简而言之,为了调试的目的,我想关闭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/

10-11 19:10