Skip to content

Commit 1b7898e

Browse files
oohalmpe
authored andcommitted
powerpc/boot: Use the pre-boot decompression API
Currently the powerpc boot wrapper has its own wrapper around zlib to handle decompressing gzipped kernels. The kernel decompressor library functions now provide a generic interface that can be used in the pre-boot environment. This allows boot wrappers to easily support different compression algorithms. This patch converts the wrapper to use this new API, but does not add support for using new algorithms. Signed-off-by: Oliver O'Halloran <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 22750d9 commit 1b7898e

File tree

4 files changed

+190
-25
lines changed

4 files changed

+190
-25
lines changed

arch/powerpc/boot/Makefile

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,28 @@ $(obj)/treeboot-currituck.o: BOOTCFLAGS += -mcpu=405
6363
$(obj)/treeboot-akebono.o: BOOTCFLAGS += -mcpu=405
6464
$(obj)/virtex405-head.o: BOOTAFLAGS += -mcpu=405
6565

66-
# the kernel's version of zlib pulls in a lot of other kernel headers
67-
# which we don't provide inside the wrapper.
66+
# The pre-boot decompressors pull in a lot of kernel headers and other source
67+
# files. This creates a bit of a dependency headache since we need to copy
68+
# these files into the build dir, fix up any includes and ensure that dependent
69+
# files are copied in the right order.
70+
71+
# these need to be seperate variables because they are copied out of different
72+
# directories in the kernel tree. Sure you COULd merge them, but it's a
73+
# cure-is-worse-than-disease situation.
74+
zlib-decomp-$(CONFIG_KERNEL_GZIP) := decompress_inflate.c
6875
zlib-$(CONFIG_KERNEL_GZIP) := inffast.c inflate.c inftrees.c
6976
zlibheader-$(CONFIG_KERNEL_GZIP) := inffast.h inffixed.h inflate.h inftrees.h infutil.h
7077
zliblinuxheader-$(CONFIG_KERNEL_GZIP) := zlib.h zconf.h zutil.h
7178

72-
$(addprefix $(obj)/,$(zlib-y) cuboot-c2k.o gunzip_util.o main.o): \
79+
$(addprefix $(obj)/, decompress.o): \
80+
$(addprefix $(obj)/,$(zlib-decomp-y))
81+
82+
$(addprefix $(obj)/, $(zlib-decomp-y)): \
83+
$(addprefix $(obj)/,$(zliblinuxheader-y)) \
84+
$(addprefix $(obj)/,$(zlibheader-y)) \
85+
$(addprefix $(obj)/,$(zlib-y))
86+
87+
$(addprefix $(obj)/,$(zlib-y)): \
7388
$(addprefix $(obj)/,$(zliblinuxheader-y)) \
7489
$(addprefix $(obj)/,$(zlibheader-y))
7590

@@ -79,10 +94,10 @@ libfdtheader := fdt.h libfdt.h libfdt_internal.h
7994
$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
8095
$(addprefix $(obj)/,$(libfdtheader))
8196

82-
src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
97+
src-wlib-y := string.S crt0.S crtsavres.S stdio.c decompress.c main.c \
8398
$(libfdt) libfdt-wrapper.c \
8499
ns16550.c serial.c simple_alloc.c div64.S util.S \
85-
gunzip_util.c elf_util.c $(zlib-y) devtree.c stdlib.c \
100+
elf_util.c $(zlib-y) devtree.c stdlib.c \
86101
oflib.c ofconsole.c cuboot.c mpsc.c cpm-serial.c \
87102
uartlite.c mpc52xx-psc.c opal.c opal-calls.S
88103
src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
@@ -143,6 +158,9 @@ $(addprefix $(obj)/,$(zlibheader-y)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
143158
$(addprefix $(obj)/,$(zliblinuxheader-y)): $(obj)/%: $(srctree)/include/linux/%
144159
$(call cmd,copy_kern_src)
145160

161+
$(addprefix $(obj)/,$(zlib-decomp-y)): $(obj)/%: $(srctree)/lib/%
162+
$(call cmd,copy_kern_src)
163+
146164
quiet_cmd_copy_libfdt = COPY $@
147165
cmd_copy_libfdt = cp $< $@
148166

@@ -160,7 +178,7 @@ $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds : $(obj)/%: $(srctree)/$(src)/%.S
160178
$(Q)cp $< $@
161179

162180
clean-files := $(zlib-) $(zlibheader-) $(zliblinuxheader-) \
163-
$(libfdt) $(libfdtheader) \
181+
$(zlib-decomp-) $(libfdt) $(libfdtheader) \
164182
empty.c zImage.coff.lds zImage.ps3.lds zImage.lds
165183

166184
quiet_cmd_bootcc = BOOTCC $@
@@ -410,8 +428,8 @@ clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \
410428
zImage.maple simpleImage.* otheros.bld *.dtb
411429

412430
# clean up files cached by wrapper
413-
clean-kernel := vmlinux.strip vmlinux.bin
414-
clean-kernel += $(addsuffix .gz,$(clean-kernel))
431+
clean-kernel-base := vmlinux.strip vmlinux.bin
432+
clean-kernel := $(addsuffix .gz,$(clean-kernel-base))
415433
# If not absolute clean-files are relative to $(obj).
416434
clean-files += $(addprefix $(objtree)/, $(clean-kernel))
417435

arch/powerpc/boot/decompress.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Wrapper around the kernel's pre-boot decompression library.
3+
*
4+
* Copyright (C) IBM Corporation 2016.
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU General Public License
8+
* as published by the Free Software Foundation; either version
9+
* 2 of the License, or (at your option) any later version.
10+
*/
11+
12+
#include "elf.h"
13+
#include "page.h"
14+
#include "string.h"
15+
#include "stdio.h"
16+
#include "ops.h"
17+
#include "reg.h"
18+
#include "types.h"
19+
20+
/*
21+
* The decompressor_*.c files play #ifdef games so they can be used in both
22+
* pre-boot and regular kernel code. We need these definitions to make the
23+
* includes work.
24+
*/
25+
26+
#define STATIC static
27+
#define INIT
28+
#define __always_inline inline
29+
30+
/*
31+
* The build process will copy the required zlib source files and headers
32+
* out of lib/ and "fix" the includes so they do not pull in other kernel
33+
* headers.
34+
*/
35+
36+
#ifdef CONFIG_KERNEL_GZIP
37+
# include "decompress_inflate.c"
38+
#endif
39+
40+
/* globals for tracking the state of the decompression */
41+
static unsigned long decompressed_bytes;
42+
static unsigned long limit;
43+
static unsigned long skip;
44+
static char *output_buffer;
45+
46+
/*
47+
* flush() is called by __decompress() when the decompressor's scratch buffer is
48+
* full.
49+
*/
50+
static long flush(void *v, unsigned long buffer_size)
51+
{
52+
unsigned long end = decompressed_bytes + buffer_size;
53+
unsigned long size = buffer_size;
54+
unsigned long offset = 0;
55+
char *in = v;
56+
char *out;
57+
58+
/*
59+
* if we hit our decompression limit, we need to fake an error to abort
60+
* the in-progress decompression.
61+
*/
62+
if (decompressed_bytes >= limit)
63+
return -1;
64+
65+
/* skip this entire block */
66+
if (end <= skip) {
67+
decompressed_bytes += buffer_size;
68+
return buffer_size;
69+
}
70+
71+
/* skip some data at the start, but keep the rest of the block */
72+
if (decompressed_bytes < skip && end > skip) {
73+
offset = skip - decompressed_bytes;
74+
75+
in += offset;
76+
size -= offset;
77+
decompressed_bytes += offset;
78+
}
79+
80+
out = &output_buffer[decompressed_bytes - skip];
81+
size = min(decompressed_bytes + size, limit) - decompressed_bytes;
82+
83+
memcpy(out, in, size);
84+
decompressed_bytes += size;
85+
86+
return buffer_size;
87+
}
88+
89+
static void print_err(char *s)
90+
{
91+
/* suppress the "error" when we terminate the decompressor */
92+
if (decompressed_bytes >= limit)
93+
return;
94+
95+
printf("Decompression error: '%s'\n\r", s);
96+
}
97+
98+
/**
99+
* partial_decompress - decompresses part or all of a compressed buffer
100+
* @inbuf: input buffer
101+
* @input_size: length of the input buffer
102+
* @outbuf: input buffer
103+
* @output_size: length of the input buffer
104+
* @skip number of output bytes to ignore
105+
*
106+
* This function takes compressed data from inbuf, decompresses and write it to
107+
* outbuf. Once output_size bytes are written to the output buffer, or the
108+
* stream is exhausted the function will return the number of bytes that were
109+
* decompressed. Otherwise it will return whatever error code the decompressor
110+
* reported (NB: This is specific to each decompressor type).
111+
*
112+
* The skip functionality is mainly there so the program and discover
113+
* the size of the compressed image so that it can ask firmware (if present)
114+
* for an appropriately sized buffer.
115+
*/
116+
long partial_decompress(void *inbuf, unsigned long input_size,
117+
void *outbuf, unsigned long output_size, unsigned long _skip)
118+
{
119+
int ret;
120+
121+
/*
122+
* The skipped bytes needs to be included in the size of data we want
123+
* to decompress.
124+
*/
125+
output_size += _skip;
126+
127+
decompressed_bytes = 0;
128+
output_buffer = outbuf;
129+
limit = output_size;
130+
skip = _skip;
131+
132+
ret = __decompress(inbuf, input_size, NULL, flush, outbuf,
133+
output_size, NULL, print_err);
134+
135+
/*
136+
* If decompression was aborted due to an actual error rather than
137+
* a fake error that we used to abort, then we should report it.
138+
*/
139+
if (decompressed_bytes < limit)
140+
return ret;
141+
142+
return decompressed_bytes - skip;
143+
}

arch/powerpc/boot/main.c

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
#include "string.h"
1616
#include "stdio.h"
1717
#include "ops.h"
18-
#include "gunzip_util.h"
1918
#include "reg.h"
2019

21-
static struct gunzip_state gzstate;
22-
2320
struct addr_range {
2421
void *addr;
2522
unsigned long size;
@@ -30,15 +27,14 @@ struct addr_range {
3027
static struct addr_range prep_kernel(void)
3128
{
3229
char elfheader[256];
33-
void *vmlinuz_addr = _vmlinux_start;
30+
unsigned char *vmlinuz_addr = (unsigned char *)_vmlinux_start;
3431
unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
3532
void *addr = 0;
3633
struct elf_info ei;
37-
int len;
34+
long len;
3835

39-
/* gunzip the ELF header of the kernel */
40-
gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
41-
gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
36+
partial_decompress(vmlinuz_addr, vmlinuz_size,
37+
elfheader, sizeof(elfheader), 0);
4238

4339
if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
4440
fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
@@ -51,7 +47,7 @@ static struct addr_range prep_kernel(void)
5147
* the kernel bss must be claimed (it will be zero'd by the
5248
* kernel itself)
5349
*/
54-
printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize);
50+
printf("Allocating 0x%lx bytes for kernel...\n\r", ei.memsize);
5551

5652
if (platform_ops.vmlinux_alloc) {
5753
addr = platform_ops.vmlinux_alloc(ei.memsize);
@@ -71,16 +67,21 @@ static struct addr_range prep_kernel(void)
7167
"device tree\n\r");
7268
}
7369

74-
/* Finally, gunzip the kernel */
75-
printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
70+
/* Finally, decompress the kernel */
71+
printf("Decompressing (0x%p <- 0x%p:0x%p)...\n\r", addr,
7672
vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
77-
/* discard up to the actual load data */
78-
gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
79-
len = gunzip_finish(&gzstate, addr, ei.loadsize);
73+
74+
len = partial_decompress(vmlinuz_addr, vmlinuz_size,
75+
addr, ei.loadsize, ei.elfoffset);
76+
77+
if (len < 0)
78+
fatal("Decompression failed with error code %ld\n\r", len);
79+
8080
if (len != ei.loadsize)
81-
fatal("ran out of data! only got 0x%x of 0x%lx bytes.\n\r",
82-
len, ei.loadsize);
83-
printf("done 0x%x bytes\n\r", len);
81+
fatal("Decompression error: got 0x%lx bytes, expected 0x%lx.\n\r",
82+
len, ei.loadsize);
83+
84+
printf("Done! Decompressed 0x%lx bytes\n\r", len);
8485

8586
flush_cache(addr, ei.loadsize);
8687

arch/powerpc/boot/ops.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,7 @@ int __ilog2_u32(u32 n)
260260
return 31 - bit;
261261
}
262262

263+
long partial_decompress(void *inbuf, unsigned long input_size, void *outbuf,
264+
unsigned long output_size, unsigned long skip);
265+
263266
#endif /* _PPC_BOOT_OPS_H_ */

0 commit comments

Comments
 (0)