简而言之,为了调试的目的,我想关闭linux上下文中的所有mmu(和缓存)操作(从内核内部),以便运行一些测试。为了清楚起见,我不打算在那之后我的系统还能正常工作。
关于我的设置:我目前正在摆弄一个飞思卡尔vybrid(vf610)——它集成了一个cortex a5——及其低功耗模式。当芯片处于“低功耗停止”模式,而我的DDR3处于自刷新模式时,由于我正在尝试一些可疑的本地内存损坏,所以我试图一点一点地改变操作,现在执行所有的挂起/恢复步骤,而不实际执行WFI。因为在这条指令之前,我运行的是地址转换,而在那之后没有(本质上是一个重置),我想通过“手动”关闭mmu来“模拟”。
(我目前没有JTAG或任何其他调试访问我的芯片。我通过mmc/tftp/nfs加载它,然后用led调试它。)
到目前为止我所做的:
/* disable the Icache, Dcache and 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 the MMU and 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
以及其他效果相同的变体。
我观察到:
在mmu块之前,我可以点亮一个led(3个汇编指令,没有分支,没有花哨的东西,也没有对我的ddr的任何访问,ddr已经在自刷新中了-gpio端口的虚拟地址在此之前存储在一个寄存器中)。
在mmu块之后,我再也不能使用物理地址或虚拟地址了。
我想问题可能与我的电脑有关,它保留了一个过时的虚拟地址。查看内核中其他地方的操作方式,但另一方面(即在启用翻译时):
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 to virtual address
ENDPROC(cpu_resume_mmu)
.popsection
cpu_resume_after_mmu:
(来自arch/arm/kernel/sleep.s,cpu_resume_mmu)
我想知道这两个指令延迟与什么有关,以及它是在哪里记录的。关于这个问题我什么也没发现。我也尝试过类似的方法,但没有成功:
adr lr, BSYM(phys_block)
/* disable the Icache, Dcache and 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 the MMU and 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
感谢任何有线索或线索的人!
最佳答案
由于杰森和德韦尔奇都友好地通过评论(每一条)提出了我需要的答案,为了清楚起见,我将在这里回答我自己的问题:
诀窍很简单,就是添加一个从/到页面的身份映射来进行转换,允许我们使用“物理”(虽然实际上是虚拟)PC跳到它,然后禁用MMU。
以下是最终代码(有点具体,但有注释):
/* Duplicate mapping to here */
mrc p15, 0, r4, c2, c0, 0 // Get TTRB0
ldr r10, =0x00003fff
bic r4, r10 // Extract page table physical base address
orr r4, #0xc0000000 // Nastily "translate" it to the virtual one
/*
* Here r8 holds vf_suspend's physical address. I had no way of
* doing this more "locally", since both physical and virtual
* space for my code are 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 to virtual addressing
phys_block:
/* disable the MMU and 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 the Icache, Dcache and 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 !
关于linux - ARM:禁用MMU和更新PC,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30843270/