I have a custom embedded system with a 440GP derived CPU that places the memory starting at 0xc0000000 which requires a non-zero PPC_MEMSTART. There are a couple of places that assume PPC_MEMSTART is 0. This results in various tricky crashing during booting. Most of the problems are not accounting for PPC_MEMSTART during va/pa translations. My fixes convert these places to use pre-existing macros instead of duplicating the calculation.
The two items in head_4xx.S are critical, but I can't see a good way to link them in without an #ifdef, or maybe a CONFIG_* symbol. The alternate version of the tlb index picker will work for any platform, but is based on 'random' selection of the tlb index using the timebase rather than linear increment. I don't know if this is better, but it is an easy way to skip the problematic memory reference. Signed-off-by: Jason Gunthorpe <jgunthorpe at obsidianresearch.com> --- arch/ppc/kernel/head_4xx.S | 7 +++++++ arch/ppc/mm/4xx_mmu.c | 5 +++-- arch/ppc/mm/pgtable.c | 4 +++- include/asm-ppc/io.h | 4 ++-- include/asm-ppc/pgtable.h | 4 ++-- 5 files changed, 17 insertions(+), 7 deletions(-) applies-to: cec49fea2095ec77123684854ed519f01cf890da 1ffdbeb034cf2ad10105c28b4c9b7588084d8d9d diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S index 10c261c..4d5ccaf 100644 --- a/arch/ppc/kernel/head_4xx.S +++ b/arch/ppc/kernel/head_4xx.S @@ -771,10 +771,15 @@ tlb_4xx_index: finish_tlb_load: /* load the next available TLB index. */ +#ifdef NON_ZERO_PPC_MEMSTART + mftb r9 + andi. r9, r9, (PPC4XX_TLB_SIZE-1) +#else lwz r9, tlb_4xx_index at l(0) addi r9, r9, 1 andi. r9, r9, (PPC4XX_TLB_SIZE-1) stw r9, tlb_4xx_index at l(0) +#endif 6: /* @@ -872,6 +877,7 @@ start_here: tlbia isync /* Flush shadow TLBs */ +#ifndef NON_ZERO_PPC_MEMSTART /* set up the PTE pointers for the Abatron bdiGDB. */ lis r6, swapper_pg_dir at h @@ -881,6 +887,7 @@ start_here: stw r5, 0xf0(r0) /* Must match your Abatron config file */ tophys(r5,r5) stw r6, 0(r5) +#endif /* Now turn on the MMU for real! */ lis r4,MSR_KERNEL at h diff --git a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c index 4d006aa..253cf64 100644 --- a/arch/ppc/mm/4xx_mmu.c +++ b/arch/ppc/mm/4xx_mmu.c @@ -84,10 +84,11 @@ void __init MMU_init_hw(void) /* * Cache instruction and data space where the exception * vectors and the kernel live in real-mode. + * 512MB starting at the base physical address of the kernel. */ - mtspr(SPRN_DCCR, 0xF0000000); /* 512 MB of data space at 0x0. */ - mtspr(SPRN_ICCR, 0xF0000000); /* 512 MB of instr. space at 0x0. */ + mtspr(SPRN_DCCR, 0xF0000000 >> (PPC_MEMSTART/0x8000000)); + mtspr(SPRN_ICCR, 0xF0000000 >> (PPC_MEMSTART/0x8000000)); } #define LARGE_PAGE_SIZE_16M (1<<24) diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 6ea9185..29909ac 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -190,7 +190,9 @@ __ioremap(phys_addr_t addr, unsigned lon * Don't allow anybody to remap normal RAM that we're using. * mem_init() sets high_memory so only do the check after that. */ - if ( mem_init_done && (p < virt_to_phys(high_memory)) ) + if ( mem_init_done && + p < virt_to_phys(high_memory) && + p >= PPC_MEMSTART ) { printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p, __builtin_return_address(0)); diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h index 84ac6e2..c43f2f9 100644 --- a/include/asm-ppc/io.h +++ b/include/asm-ppc/io.h @@ -422,7 +422,7 @@ extern inline void * bus_to_virt(unsigne extern inline unsigned long virt_to_phys(volatile void * address) { #ifndef CONFIG_APUS - return (unsigned long) address - KERNELBASE; + return __pa(address); #else return iopa ((unsigned long) address); #endif @@ -431,7 +431,7 @@ extern inline unsigned long virt_to_phys extern inline void * phys_to_virt(unsigned long address) { #ifndef CONFIG_APUS - return (void *) (address + KERNELBASE); + return __va(address); #else return (void*) mm_ptov (address); #endif diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 6d1c39e..488c6e9 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -724,12 +724,12 @@ extern pgprot_t phys_mem_access_prot(str #define pmd_page_kernel(pmd) \ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) #define pmd_page(pmd) \ - (mem_map + (pmd_val(pmd) >> PAGE_SHIFT)) + pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT) #else #define pmd_page_kernel(pmd) \ ((unsigned long) (pmd_val(pmd) & PAGE_MASK)) #define pmd_page(pmd) \ - (mem_map + (__pa(pmd_val(pmd)) >> PAGE_SHIFT)) + (virt_to_page(pmd_val(pmd))) #endif /* to find an entry in a kernel page-table-directory */ --- 0.99.9k