unsigned long decompress_kernel()

in boot/compressed/misc.c [281:370]


unsigned long decompress_kernel(unsigned int started_wide,
		unsigned int command_line,
		const unsigned int rd_start,
		const unsigned int rd_end)
{
	char *output;
	unsigned long vmlinux_addr, vmlinux_len;
	unsigned long kernel_addr, kernel_len;

#ifdef CONFIG_64BIT
	parisc_narrow_firmware = 0;
#endif

	set_firmware_width_unlocked();

	putchar('D');	/* if you get this D and no more, string storage */
			/* in $GLOBAL$ is wrong or %dp is wrong */
	puts("ecompressing Linux... ");

	/* where the final bits are stored */
	kernel_addr = KERNEL_BINARY_TEXT_START;
	kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
	if ((unsigned long) &_startcode_end > kernel_addr)
		error("Bootcode overlaps kernel code");

	/*
	 * Calculate addr to where the vmlinux ELF file shall be decompressed.
	 * Assembly code in head.S positioned the stack directly behind bss, so
	 * leave 2 MB for the stack.
	 */
	vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
	vmlinux_len = get_unaligned_le32(&output_len);
	output = (char *) vmlinux_addr;

	/*
	 * Initialize free_mem_ptr and free_mem_end_ptr.
	 */
	free_mem_ptr = vmlinux_addr + vmlinux_len;

	/* Limit memory for bootoader to 1GB */
	#define ARTIFICIAL_LIMIT (1*1024*1024*1024)
	free_mem_end_ptr = PAGE0->imm_max_mem;
	if (free_mem_end_ptr > ARTIFICIAL_LIMIT)
		free_mem_end_ptr = ARTIFICIAL_LIMIT;

#ifdef CONFIG_BLK_DEV_INITRD
	/* if we have ramdisk this is at end of memory */
	if (rd_start && rd_start < free_mem_end_ptr)
		free_mem_end_ptr = rd_start;
#endif

	if (free_mem_ptr >= free_mem_end_ptr) {
		int free_ram;
		free_ram = (free_mem_ptr >> 20) + 1;
		if (free_ram < 32)
			free_ram = 32;
		printf("\nKernel requires at least %d MB RAM.\n",
			free_ram);
		error(NULL);
	}

#ifdef DEBUG
	printf("\n");
	printf("startcode_end = %x\n", &_startcode_end);
	printf("commandline   = %x\n", command_line);
	printf("rd_start      = %x\n", rd_start);
	printf("rd_end        = %x\n", rd_end);

	printf("free_ptr      = %x\n", free_mem_ptr);
	printf("free_ptr_end  = %x\n", free_mem_end_ptr);

	printf("input_data    = %x\n", input_data);
	printf("input_len     = %x\n", input_len);
	printf("output        = %x\n", output);
	printf("output_len    = %x\n", vmlinux_len);
	printf("kernel_addr   = %x\n", kernel_addr);
	printf("kernel_len    = %x\n", kernel_len);
#endif

	__decompress(input_data, input_len, NULL, NULL,
			output, 0, NULL, error);
	parse_elf(output);

	output = (char *) kernel_addr;
	flush_data_cache(output, kernel_len);

	printf("done.\nBooting the kernel.\n");

	return (unsigned long) output;
}