Index: sys/powerpc/booke/pmap.c =================================================================== --- sys/powerpc/booke/pmap.c (revision 361836) +++ sys/powerpc/booke/pmap.c (working copy) @@ -78,6 +78,7 @@ #include "opt_ddb.h" #include "opt_kstack_pages.h" +#include "opt_platform.h" #include #include @@ -112,6 +113,7 @@ #include #include +#include #include #include #include @@ -640,6 +642,12 @@ vm_paddr_t kstack0_phys; vm_offset_t kstack0; void *dpcpu; +#ifdef FDT + phandle_t chosen; + ssize_t size; + pcell_t cell[2]; + uint64_t initrd_end; +#endif debugf("mmu_booke_bootstrap: entered\n"); @@ -665,6 +673,31 @@ * kernsize is the size of the kernel that is actually mapped. */ data_start = round_page(kernelend); + + /* + * Qemu workaround: + * + * Using an initrd will cause qemu to load the initrd a bit above + * the kernel. + * As we don't have proper region handling here yet, check if + * an initrd is in use, and if so, bump data_start to be past the + * initrd so they don't conflict. + * + * Note: This is rather wasteful. + */ +#ifdef FDT + initrd_end = 0; + chosen = OF_finddevice("/chosen"); + size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell)); + if (size == 4) + initrd_end = cell[0]; + else if (size == 8) + initrd_end = (uint64_t)cell[0] << 32 | cell[1]; + + if (initrd_end && ((VM_MIN_KERNEL_ADDRESS + initrd_end) > data_start)) + data_start = round_page(VM_MIN_KERNEL_ADDRESS + initrd_end + PAGE_SIZE); +#endif + data_end = data_start; /* Allocate the dynamic per-cpu area. */ Index: sys/powerpc/powerpc/machdep.c =================================================================== --- sys/powerpc/powerpc/machdep.c (revision 361836) +++ sys/powerpc/powerpc/machdep.c (working copy) @@ -547,7 +547,8 @@ vm_paddr_t start, end; pcell_t cell[2]; ssize_t size; - u_char *kernelimg; + u_char *kernelimg; /* Temporary map */ + u_char *kernelimg_final; /* Final location */ int i; @@ -556,6 +557,7 @@ Elf_Shdr *shdr; vm_offset_t ksym_start, ksym_sz, kstr_start, kstr_sz; + vm_offset_t ksym_start_final, kstr_start_final; if (!hw_direct_map) return; @@ -587,27 +589,48 @@ if (!(end - start > 0)) return; - kernelimg = (u_char *) PHYS_TO_DMAP(start); - + kernelimg_final = (u_char *) PHYS_TO_DMAP(start); +#ifdef AIM + kernelimg = kernelimg_final; +#else /* BOOKE */ + kernelimg = (u_char *)pmap_early_io_map(start, PAGE_SIZE); +#endif ehdr = (Elf_Ehdr *)kernelimg; - if (!IS_ELF(*ehdr)) + if (!IS_ELF(*ehdr)) { +#ifdef BOOKE + pmap_early_io_unmap(start, PAGE_SIZE); +#endif return; + } +#ifdef BOOKE + pmap_early_io_unmap(start, PAGE_SIZE); + kernelimg = (u_char *)pmap_early_io_map(start, (end - start)); +#endif + phdr = (Elf_Phdr *)(kernelimg + ehdr->e_phoff); shdr = (Elf_Shdr *)(kernelimg + ehdr->e_shoff); ksym_start = 0; ksym_sz = 0; + ksym_start_final = 0; kstr_start = 0; kstr_sz = 0; + kstr_start_final = 0; for (i = 0; i < ehdr->e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { ksym_start = (vm_offset_t)(kernelimg + shdr[i].sh_offset); + ksym_start_final = (vm_offset_t) + (kernelimg_final + shdr[i].sh_offset); ksym_sz = (vm_offset_t)(shdr[i].sh_size); kstr_start = (vm_offset_t)(kernelimg + shdr[shdr[i].sh_link].sh_offset); + kstr_start_final = (vm_offset_t) + (kernelimg_final + + shdr[shdr[i].sh_link].sh_offset); + kstr_sz = (vm_offset_t) (shdr[shdr[i].sh_link].sh_size); } @@ -618,11 +641,15 @@ displace_symbol_table(ksym_start, ksym_sz, (__startkernel - KERNBASE)); - ksymtab = ksym_start; + ksymtab = ksym_start_final; ksymtab_size = ksym_sz; - kstrtab = kstr_start; + kstrtab = kstr_start_final; } +#ifdef BOOKE + pmap_early_io_unmap(start, (end - start)); +#endif + }; #endif