2 * Definitions and wrapper functions for kernel decompressor
4 * (C) 2017 Helge Deller <deller@gmx.de>
7 #include <linux/uaccess.h>
9 #include <asm/unaligned.h>
19 #define memmove memmove
20 #define memzero(s, n) memset((s), 0, (n))
22 #define malloc malloc_gzip
23 #define free free_gzip
25 /* Symbols defined by linker scripts */
26 extern char input_data
[];
28 /* output_len is inserted by the linker possibly at an unaligned address */
29 extern __le32 output_len
__aligned(1);
30 extern char _text
, _end
;
31 extern char _bss
, _ebss
;
32 extern char _startcode_end
;
33 extern void startup_continue(void *entry
, unsigned long cmdline
,
34 unsigned long rd_start
, unsigned long rd_end
) __noreturn
;
36 void error(char *m
) __noreturn
;
38 static unsigned long free_mem_ptr
;
39 static unsigned long free_mem_end_ptr
;
41 #ifdef CONFIG_KERNEL_GZIP
42 #include "../../../../lib/decompress_inflate.c"
45 #ifdef CONFIG_KERNEL_BZIP2
46 #include "../../../../lib/decompress_bunzip2.c"
49 #ifdef CONFIG_KERNEL_LZ4
50 #include "../../../../lib/decompress_unlz4.c"
53 #ifdef CONFIG_KERNEL_LZMA
54 #include "../../../../lib/decompress_unlzma.c"
57 #ifdef CONFIG_KERNEL_LZO
58 #include "../../../../lib/decompress_unlzo.c"
61 #ifdef CONFIG_KERNEL_XZ
62 #include "../../../../lib/decompress_unxz.c"
65 void *memmove(void *dest
, const void *src
, size_t n
)
82 void *memset(void *s
, int c
, size_t count
)
91 void *memcpy(void *d
, const void *s
, size_t len
)
93 char *dest
= (char *)d
;
94 const char *source
= (const char *)s
;
101 size_t strlen(const char *s
)
105 for (sc
= s
; *sc
!= '\0'; ++sc
)
110 char *strchr(const char *s
, int c
)
120 int puts(const char *s
)
122 const char *nuline
= s
;
124 while ((nuline
= strchr(s
, '\n')) != NULL
) {
126 pdc_iodc_print(s
, nuline
- s
);
127 pdc_iodc_print("\r\n", 2);
131 pdc_iodc_print(s
, strlen(s
));
136 static int putchar(int c
)
146 void __noreturn
error(char *x
)
149 puts("\n -- System halted\n");
150 while (1) /* wait forever */
154 static int print_num(unsigned long num
, int base
)
156 const char hex
[] = "0123456789abcdef";
158 int i
= sizeof(str
)-1;
162 str
[i
--] = hex
[num
% base
];
175 int printf(const char *fmt
, ...)
191 print_num(va_arg(args
, unsigned long),
192 fmt
[i
] == 'x' ? 16:10);
200 /* helper functions for libgcc */
207 void *malloc(size_t size
)
209 return malloc_gzip(size
);
215 return free_gzip(ptr
);
219 static void flush_data_cache(char *start
, unsigned long length
)
221 char *end
= start
+ length
;
224 asm volatile("fdc 0(%0)" : : "r" (start
));
225 asm volatile("fic 0(%%sr0,%0)" : : "r" (start
));
227 } while (start
< end
);
228 asm volatile("fdc 0(%0)" : : "r" (end
));
233 static void parse_elf(void *output
)
237 Elf64_Phdr
*phdrs
, *phdr
;
240 Elf32_Phdr
*phdrs
, *phdr
;
245 memcpy(&ehdr
, output
, sizeof(ehdr
));
246 if (ehdr
.e_ident
[EI_MAG0
] != ELFMAG0
||
247 ehdr
.e_ident
[EI_MAG1
] != ELFMAG1
||
248 ehdr
.e_ident
[EI_MAG2
] != ELFMAG2
||
249 ehdr
.e_ident
[EI_MAG3
] != ELFMAG3
) {
250 error("Kernel is not a valid ELF file");
255 printf("Parsing ELF... ");
258 phdrs
= malloc(sizeof(*phdrs
) * ehdr
.e_phnum
);
260 error("Failed to allocate space for phdrs");
262 memcpy(phdrs
, output
+ ehdr
.e_phoff
, sizeof(*phdrs
) * ehdr
.e_phnum
);
264 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
267 switch (phdr
->p_type
) {
269 dest
= (void *)((unsigned long) phdr
->p_paddr
&
270 (__PAGE_OFFSET_DEFAULT
-1));
271 memmove(dest
, output
+ phdr
->p_offset
, phdr
->p_filesz
);
281 unsigned long decompress_kernel(unsigned int started_wide
,
282 unsigned int command_line
,
283 const unsigned int rd_start
,
284 const unsigned int rd_end
)
287 unsigned long vmlinux_addr
, vmlinux_len
;
288 unsigned long kernel_addr
, kernel_len
;
291 parisc_narrow_firmware
= 0;
294 set_firmware_width_unlocked();
296 putchar('D'); /* if you get this D and no more, string storage */
297 /* in $GLOBAL$ is wrong or %dp is wrong */
298 puts("ecompressing Linux... ");
300 /* where the final bits are stored */
301 kernel_addr
= KERNEL_BINARY_TEXT_START
;
302 kernel_len
= __pa(SZ_end
) - __pa(SZparisc_kernel_start
);
303 if ((unsigned long) &_startcode_end
> kernel_addr
)
304 error("Bootcode overlaps kernel code");
307 * Calculate addr to where the vmlinux ELF file shall be decompressed.
308 * Assembly code in head.S positioned the stack directly behind bss, so
309 * leave 2 MB for the stack.
311 vmlinux_addr
= (unsigned long) &_ebss
+ 2*1024*1024;
312 vmlinux_len
= get_unaligned_le32(&output_len
);
313 output
= (char *) vmlinux_addr
;
316 * Initialize free_mem_ptr and free_mem_end_ptr.
318 free_mem_ptr
= vmlinux_addr
+ vmlinux_len
;
320 /* Limit memory for bootoader to 1GB */
321 #define ARTIFICIAL_LIMIT (1*1024*1024*1024)
322 free_mem_end_ptr
= PAGE0
->imm_max_mem
;
323 if (free_mem_end_ptr
> ARTIFICIAL_LIMIT
)
324 free_mem_end_ptr
= ARTIFICIAL_LIMIT
;
326 #ifdef CONFIG_BLK_DEV_INITRD
327 /* if we have ramdisk this is at end of memory */
328 if (rd_start
&& rd_start
< free_mem_end_ptr
)
329 free_mem_end_ptr
= rd_start
;
332 if (free_mem_ptr
>= free_mem_end_ptr
) {
334 free_ram
= (free_mem_ptr
>> 20) + 1;
337 printf("\nKernel requires at least %d MB RAM.\n",
344 printf("startcode_end = %x\n", &_startcode_end
);
345 printf("commandline = %x\n", command_line
);
346 printf("rd_start = %x\n", rd_start
);
347 printf("rd_end = %x\n", rd_end
);
349 printf("free_ptr = %x\n", free_mem_ptr
);
350 printf("free_ptr_end = %x\n", free_mem_end_ptr
);
352 printf("input_data = %x\n", input_data
);
353 printf("input_len = %x\n", input_len
);
354 printf("output = %x\n", output
);
355 printf("output_len = %x\n", vmlinux_len
);
356 printf("kernel_addr = %x\n", kernel_addr
);
357 printf("kernel_len = %x\n", kernel_len
);
360 __decompress(input_data
, input_len
, NULL
, NULL
,
361 output
, 0, NULL
, error
);
364 output
= (char *) kernel_addr
;
365 flush_data_cache(output
, kernel_len
);
367 printf("done.\nBooting the kernel.\n");
369 return (unsigned long) output
;