diff options
Diffstat (limited to 'arch/s390/boot/compressed/misc.c')
-rw-r--r-- | arch/s390/boot/compressed/misc.c | 35 |
1 files changed, 19 insertions, 16 deletions
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index fa95041fa9f6..33ca29333e18 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c | |||
@@ -141,31 +141,34 @@ static void check_ipl_parmblock(void *start, unsigned long size) | |||
141 | 141 | ||
142 | unsigned long decompress_kernel(void) | 142 | unsigned long decompress_kernel(void) |
143 | { | 143 | { |
144 | unsigned long output_addr; | 144 | void *output, *kernel_end; |
145 | unsigned char *output; | ||
146 | 145 | ||
147 | output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL; | 146 | output = (void *) ALIGN((unsigned long) &_end + HEAP_SIZE, PAGE_SIZE); |
148 | check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start); | 147 | kernel_end = output + SZ__bss_start; |
149 | memset(&_bss, 0, &_ebss - &_bss); | 148 | check_ipl_parmblock((void *) 0, (unsigned long) kernel_end); |
150 | free_mem_ptr = (unsigned long)&_end; | ||
151 | free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; | ||
152 | output = (unsigned char *) output_addr; | ||
153 | 149 | ||
154 | #ifdef CONFIG_BLK_DEV_INITRD | 150 | #ifdef CONFIG_BLK_DEV_INITRD |
155 | /* | 151 | /* |
156 | * Move the initrd right behind the end of the decompressed | 152 | * Move the initrd right behind the end of the decompressed |
157 | * kernel image. | 153 | * kernel image. This also prevents initrd corruption caused by |
154 | * bss clearing since kernel_end will always be located behind the | ||
155 | * current bss section.. | ||
158 | */ | 156 | */ |
159 | if (INITRD_START && INITRD_SIZE && | 157 | if (INITRD_START && INITRD_SIZE && kernel_end > (void *) INITRD_START) { |
160 | INITRD_START < (unsigned long) output + SZ__bss_start) { | 158 | check_ipl_parmblock(kernel_end, INITRD_SIZE); |
161 | check_ipl_parmblock(output + SZ__bss_start, | 159 | memmove(kernel_end, (void *) INITRD_START, INITRD_SIZE); |
162 | INITRD_START + INITRD_SIZE); | 160 | INITRD_START = (unsigned long) kernel_end; |
163 | memmove(output + SZ__bss_start, | ||
164 | (void *) INITRD_START, INITRD_SIZE); | ||
165 | INITRD_START = (unsigned long) output + SZ__bss_start; | ||
166 | } | 161 | } |
167 | #endif | 162 | #endif |
168 | 163 | ||
164 | /* | ||
165 | * Clear bss section. free_mem_ptr and free_mem_end_ptr need to be | ||
166 | * initialized afterwards since they reside in bss. | ||
167 | */ | ||
168 | memset(&_bss, 0, &_ebss - &_bss); | ||
169 | free_mem_ptr = (unsigned long) &_end; | ||
170 | free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; | ||
171 | |||
169 | puts("Uncompressing Linux... "); | 172 | puts("Uncompressing Linux... "); |
170 | __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); | 173 | __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); |
171 | puts("Ok, booting the kernel.\n"); | 174 | puts("Ok, booting the kernel.\n"); |