Re: [PATCH v2 7/8] powerpc/fsl_booke: make sure PAGE_OFFSET map to memstart_addr for relocatable kernel
flat view
From: Kevin Hao <hidden>
Date: 2013-08-04 00:50:46
On Fri, Jul 26, 2013 at 07:17:57PM -0500, Scott Wood wrote:
On 07/04/2013 07:54:13 AM, Kevin Hao wrote:quoted
@@ -1222,6 +1266,9 @@ _GLOBAL(switch_to_as1)/* * Restore to the address space 0 and also invalidate the tlb entry created * by switch_to_as1. + * r3 - the tlb entry which should be invalidated + * r4 - __pa(PAGE_OFFSET in AS0) - pa(PAGE_OFFSET in AS1) + * r5 - device tree virtual address */ _GLOBAL(restore_to_as0) mflr r0@@ -1230,7 +1277,15 @@ _GLOBAL(restore_to_as0)0: mflr r9 addi r9,r9,1f - 0b - mfmsr r7 + /* + * We may map the PAGE_OFFSET in AS0 to a different physical address, + * so we need calculate the right jump and device tree address based + * on the offset passed by r4. + */Whitespace
Fixed.
quoted
+ subf r9,r4,r9 + subf r5,r4,r5 + +2: mfmsr r7 li r8,(MSR_IS | MSR_DS) andc r7,r7,r8@@ -1249,9 +1304,19 @@ _GLOBAL(restore_to_as0)mtspr SPRN_MAS1,r9 tlbwe isync + + cmpwi r4,0 + bne 3f mtlr r0 blr + /* + * The PAGE_OFFSET will map to a different physical address, + * jump to _start to do another relocation again. + */ +3: mr r3,r5 + bl _start + /* * We put a few things here that have to be page-aligned. This stuff * goes at the beginning of the data segment, which is page-aligned.diff --git a/arch/powerpc/mm/fsl_booke_mmu.cb/arch/powerpc/mm/fsl_booke_mmu.c index 8f60ef8..dd283fd 100644--- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c@@ -224,7 +224,7 @@ void __init adjust_total_lowmem(void)i = switch_to_as1(); __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM); - restore_to_as0(i); + restore_to_as0(i, 0, 0);The device tree virtual address is zero?
No. But if the __pa(PAGE_OFFSET in AS0) is equal to __pa(PAGE_OFFSET in AS1),
that mean we don't need to do another relocation and the device tree virtual
address is useless in this case.
quoted
pr_info("Memory CAM mapping: "); for (i = 0; i < tlbcam_index - 1; i++)@@ -245,30 +245,56 @@ void setup_initial_memory_limit(phys_addr_tfirst_memblock_base, } #ifdef CONFIG_RELOCATABLE -notrace void __init relocate_init(phys_addr_t start) +int __initdata is_second_reloc; +notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start) { unsigned long base = KERNELBASE; - /* - * Relocatable kernel support based on processing of dynamic - * relocation entries. - * Compute the virt_phys_offset : - * virt_phys_offset = stext.run - kernstart_addr - * - * stext.run = (KERNELBASE & ~0xfffffff) + (kernstart_addr & 0xfffffff) - * When we relocate, we have : - * - * (kernstart_addr & 0xfffffff) = (stext.run & 0xfffffff) - * - * hence: - * virt_phys_offset = (KERNELBASE & ~0xfffffff) - - * (kernstart_addr & ~0xfffffff) - * - */ kernstart_addr = start; - start &= ~0xfffffff; - base &= ~0xfffffff; - virt_phys_offset = base - start; + if (!is_second_reloc) {Since it's at the end of a function and one side is much shorter than the other, please do: if (is_second_reloc) { virt_phys_offset = PAGE_OFFSET - memstart_addr; return; } /* the rest of the code goes here without having to indent everything */
Yes, this looks much better. Changed.
Otherwise, please use positive logic for if/else constructs.quoted
+ phys_addr_t size; + + /* + * Relocatable kernel support based on processing of dynamic + * relocation entries. Before we get the real memstart_addr, + * We will compute the virt_phys_offset like this: + * virt_phys_offset = stext.run - kernstart_addr + * + * stext.run = (KERNELBASE & ~0xfffffff) + + * (kernstart_addr & 0xfffffff) + * When we relocate, we have : + * + * (kernstart_addr & 0xfffffff) = (stext.run & 0xfffffff) + * + * hence: + * virt_phys_offset = (KERNELBASE & ~0xfffffff) - + * (kernstart_addr & ~0xfffffff) + * + */ + start &= ~0xfffffff; + base &= ~0xfffffff; + virt_phys_offset = base - start; + early_get_first_memblock_info(__va(dt_ptr), &size); + /* + * We now get the memstart_addr, then we should check if this + * address is the same as what the PAGE_OFFSET map to now. If + * not we have to change the map of PAGE_OFFSET to memstart_addr + * and do a second relocation. + */ + if (start != memstart_addr) { + unsigned long ram; + int n, offset = memstart_addr - start; + + is_second_reloc = 1; + ram = size; + n = switch_to_as1(); + map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM);Do we really need this much RAM mapped at this point?
Not really.
Why can't we continue with the same size TLB entry that we've been using, until the second relocation?
OK, I will change it to use 64M.
quoted
+ restore_to_as0(n, offset, __va(dt_ptr)); + /* We should never reach here */ + panic("Relocation error");Where is execution supposed to resume? It looks like you're expecting it to resume from _start,
Yes.
but why?
For second relocation, we need to: * do the real relocate * set the interrupt vector * zero the BSS So starting from the _start will avoid to duplicate these codes.
And where is this effect of restore_to_as0() documented?
There is a comment about this in restore_to_as0.
/*
* The PAGE_OFFSET will map to a different physical address,
* jump to _start to do another relocation again.
*/
3: mr r3,r5
bl _start
Thanks,
Kevin-Scott
Attachments
- (unnamed) [application/pgp-signature] 490 bytes