diff options
Diffstat (limited to 'arch/mips/kernel/setup.c')
-rw-r--r-- | arch/mips/kernel/setup.c | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8f6e89697cc..89440a0d852 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -145,13 +145,12 @@ static int __init rd_start_early(char *p) unsigned long start = memparse(p, &p); #ifdef CONFIG_64BIT - /* HACK: Guess if the sign extension was forgotten */ - if (start > 0x0000000080000000 && start < 0x00000000ffffffff) - start |= 0xffffffff00000000UL; + /* Guess if the sign extension was forgotten by bootloader */ + if (start < XKPHYS) + start = (int)start; #endif initrd_start = start; initrd_end += start; - return 0; } early_param("rd_start", rd_start_early); @@ -159,41 +158,64 @@ early_param("rd_start", rd_start_early); static int __init rd_size_early(char *p) { initrd_end += memparse(p, &p); - return 0; } early_param("rd_size", rd_size_early); +/* it returns the next free pfn after initrd */ static unsigned long __init init_initrd(void) { - unsigned long tmp, end, size; + unsigned long end; u32 *initrd_header; - ROOT_DEV = Root_RAM0; - /* * Board specific code or command line parser should have * already set up initrd_start and initrd_end. In these cases * perfom sanity checks and use them if all looks good. */ - size = initrd_end - initrd_start; - if (initrd_end == 0 || size == 0) { - initrd_start = 0; - initrd_end = 0; - } else - return initrd_end; - - end = (unsigned long)&_end; - tmp = PAGE_ALIGN(end) - sizeof(u32) * 2; - if (tmp < end) - tmp += PAGE_SIZE; - - initrd_header = (u32 *)tmp; - if (initrd_header[0] == 0x494E5244) { - initrd_start = (unsigned long)&initrd_header[2]; - initrd_end = initrd_start + initrd_header[1]; + if (initrd_start && initrd_end > initrd_start) + goto sanitize; + + /* + * See if initrd has been added to the kernel image by + * arch/mips/boot/addinitrd.c. In that case a header is + * prepended to initrd and is made up by 8 bytes. The fisrt + * word is a magic number and the second one is the size of + * initrd. Initrd start must be page aligned in any cases. + */ + initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8; + if (initrd_header[0] != 0x494E5244) + goto disable; + initrd_start = (unsigned long)(initrd_header + 2); + initrd_end = initrd_start + initrd_header[1]; + +sanitize: + if (initrd_start & ~PAGE_MASK) { + printk(KERN_ERR "initrd start must be page aligned\n"); + goto disable; } - return initrd_end; + if (initrd_start < PAGE_OFFSET) { + printk(KERN_ERR "initrd start < PAGE_OFFSET\n"); + goto disable; + } + + /* + * Sanitize initrd addresses. For example firmware + * can't guess if they need to pass them through + * 64-bits values if the kernel has been built in pure + * 32-bit. We need also to switch from KSEG0 to XKPHYS + * addresses now, so the code can now safely use __pa(). + */ + end = __pa(initrd_end); + initrd_end = (unsigned long)__va(end); + initrd_start = (unsigned long)__va(__pa(initrd_start)); + + ROOT_DEV = Root_RAM0; + return PFN_UP(end); +disable: + initrd_start = 0; + initrd_end = 0; + return 0; } static void __init finalize_initrd(void) @@ -204,12 +226,12 @@ static void __init finalize_initrd(void) printk(KERN_INFO "Initrd not found or empty"); goto disable; } - if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) { + if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) { printk("Initrd extends beyond end of memory"); goto disable; } - reserve_bootmem(CPHYSADDR(initrd_start), size); + reserve_bootmem(__pa(initrd_start), size); initrd_below_start_ok = 1; printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n", @@ -259,8 +281,7 @@ static void __init bootmem_init(void) * not selected. Once that done we can determine the low bound * of usable memory. */ - reserved_end = init_initrd(); - reserved_end = PFN_UP(CPHYSADDR(max(reserved_end, (unsigned long)&_end))); + reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end))); /* * Find the highest page frame number we have available. @@ -432,10 +453,10 @@ static void __init resource_init(void) if (UNCAC_BASE != IO_BASE) return; - code_resource.start = virt_to_phys(&_text); - code_resource.end = virt_to_phys(&_etext) - 1; - data_resource.start = virt_to_phys(&_etext); - data_resource.end = virt_to_phys(&_edata) - 1; + code_resource.start = __pa_symbol(&_text); + code_resource.end = __pa_symbol(&_etext) - 1; + data_resource.start = __pa_symbol(&_etext); + data_resource.end = __pa_symbol(&_edata) - 1; /* * Request address space for all standard RAM. |