linux - ARM: Disabling MMU and updating PC -
in short, shut down mmu (and cache) operations in linux context (from inside kernel), debug purposes, run tests. clear, don't intend system still functional after that.
about setup: i'm fiddling freescale vybrid (vf610) - integrates cortex a5 - , low power modes. since i'm experimenting suspiciously local memory corruption while chip in "low power stop" mode , ddr3 in self refresh, i'm trying shift operations bit bit, , right performing suspend/resume steps without executing wfi. since before instruction run address translation, , after without (it's reset), "simulate" "manually" shutting down mmu.
(i currently have no jtag nor other debug access chip. load via mmc/tftp/nfs, , debug leds.)
what i've tried far:
/* disable icache, dcache , branch prediction */ mrc p15, 0, r6, c1, c0, 0 ldr r7, =0x1804 bic r6, r6, r7 mcr p15, 0, r6, c1, c0, 0 isb /* disable mmu , tex */ bic r7, r6, r7 isb mcr p15, 0, r6, c1, c0, 0 @ turn on mmu, i-cache, etc mrc p15, 0, r6, c0, c0, 0 @ read id reg isb dsb dmb and other variations same effect.
what observe:
before mmu block, can light led (3 assembly instructions, no branch, nothing fancy, nor access ddr, in self refresh - virtual address gpio port stored in register before that).
after mmu block, can no more, whether try physical or virtual addresses.
i think problem may related pc, retains outdated virtual address. seeing how things done elsewhere in kernel, other way round (that is, while enabling translation) :
ldr r3, =cpu_resume_after_mmu instr_sync mcr p15, 0, r0, c1, c0, 0 @ turn on mmu, i-cache, etc mrc p15, 0, r0, c0, c0, 0 @ read id reg instr_sync mov r0, r0 mov r0, r0 ret r3 @ jump virtual address endproc(cpu_resume_mmu) .popsection cpu_resume_after_mmu: (from arch/arm/kernel/sleep.s, cpu_resume_mmu)
i wonder 2 instructions delay related to, , documented. i've found nothing on subject. i've tried equivalent, without success:
adr lr, bsym(phys_block) /* disable icache, dcache , branch prediction */ mrc p15, 0, r6, c1, c0, 0 ldr r7, =0x1804 bic r6, r6, r7 mcr p15, 0, r6, c1, c0, 0 isb /* disable mmu , tex */ bic r7, r6, r7 isb mcr p15, 0, r6, c1, c0, 0 @ turn on mmu, i-cache, etc mrc p15, 0, r6, c0, c0, 0 @ read id reg isb dsb msb mov r0, r0 mov r0, r0 ret lr phys_block: blue_light loop thanks has clue or pointers!
since both jacen , dwelch kindly brought answer needed through comment (each), answer own question here sake of clarity:
the trick add identity mapping from/to page doing transition, allowing jump "physical" (though virtual) pc, disable mmu.
here final code (a bit specific, commented):
/* duplicate mapping here */ mrc p15, 0, r4, c2, c0, 0 // ttrb0 ldr r10, =0x00003fff bic r4, r10 // extract page table physical base address orr r4, #0xc0000000 // nastily "translate" virtual 1 /* * here r8 holds vf_suspend's physical address. had no way of * doing more "locally", since both physical , virtual * space code runtime-allocated. */ add lr, r8, #(phys_block-vf_suspend) // -> phys_block physical address lsr r9, lr, #20 // section_shift -> page index add r7, r4, r9, lsl #2 // pmd_order -> entry address ldr r10, =0x00000c0e // flags orr r9, r10, r9, lsl #20 // section_shift -> entry value str r9, [r7] // write entry ret lr // jump / transition virtual addressing phys_block: /* disable mmu , tex */ isb mrc p15, 0, r6, c1, c0, 0 ldr r7, =0x10000001 bic r6, r6, r7 mcr p15, 0, r6, c1, c0, 0 @ turn on mmu, i-cache, etc mrc p15, 0, r6, c0, c0, 0 @ read id reg isb dsb dmb /* disable icache, dcache , branch prediction */ mrc p15, 0, r6, c1, c0, 0 ldr r7, =0x1804 bic r6, r6, r7 mcr p15, 0, r6, c1, c0, 0 isb // done !
Comments
Post a Comment