ARM:禁用 MMU 并更新 PC [英] ARM: Disabling MMU and updating PC

查看:29
本文介绍了ARM:禁用 MMU 并更新 PC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简而言之,我想关闭 Linux 上下文中的所有 MMU(和缓存)操作(从内核内部),用于调试目的,只是为了运行一些测试.明确地说,我不打算在那之后我的系统仍然可以运行.

关于我的设置:我目前正在摆弄集成了 Cortex A5 的 Freescale Vybrid (VF610) 及其低功耗模式.由于我正在尝试一些可疑的本地内存损坏,而芯片处于低功率停止"模式并且我的 DDR3 处于自我刷新状态,因此我正在尝试一点一点地改变操作,现在在不实际执行 WFI 的情况下执行所有挂起/恢复步骤.因为在这条指令之前我运行地址转换,之后没有(它本质上是一个重置),我想通过手动"关闭 MMU 来模拟".

(我目前对我的芯片没有 JTAG 或任何其他调试访问权限.我通过 MMC/TFTP/NFS 加载它,并使用 LED 对其进行调试.)

到目前为止我尝试过的:

/* 禁用 Icache、Dcache 和分支预测 */mrc p15, 0, r6, c1, c0, 0ldr r7,=0x1804bic r6, r6, r7mcr p15, 0, r6, c1, c0, 0为B/* 禁用 MMU 和 TEX */bic r7, r6, r7为Bmcr p15, 0, r6, c1, c0, 0 @ 打开 MMU、I-cache 等mrc p15, 0, r6, c0, c0, 0 @ 读取 id reg为B双星数据库

以及其他具有相同效果的变体.

我观察到的:

在 MMU 模块之前,我可以点亮一个 LED(3 条汇编指令,没有分支,没有什么花哨的,也没有任何对我的 DDR 的访问,它已经在自我刷新 - GPIO 端口的虚拟地址存储在寄存器中在那之前).

在 MMU 块之后,我无法再尝试使用物理地址或虚拟地址.

我认为问题可能与我的电脑有关,它保留了一个过时的虚拟地址.查看内核中其他地方的工作方式,但反过来(即启用翻译时):

 ldr r3, =cpu_resume_after_mmu指令同步mcr p15, 0, r0, c1, c0, 0 @ 打开 MMU、I-cache 等mrc p15, 0, r0, c0, c0, 0 @ 读取 id reg指令同步移动 r0, r0移动 r0, r0ret r3 @ 跳转到虚拟地址ENDPROC(cpu_resume_mmu).popsectioncpu_resume_after_mmu:

(来自 arch/arm/kernel/sleep.S, cpu_resume_mmu)

我想知道这 2 条指令延迟与什么有关,以及记录在哪里.我在这个主题上什么也没找到.我尝试过类似的东西,但没有成功:

 adr lr, BSYM(phys_block)/* 禁用 Icache、Dcache 和分支预测 */mrc p15, 0, r6, c1, c0, 0ldr r7,=0x1804bic r6, r6, r7mcr p15, 0, r6, c1, c0, 0为B/* 禁用 MMU 和 TEX */bic r7, r6, r7为Bmcr p15, 0, r6, c1, c0, 0 @ 打开 MMU、I-cache 等mrc p15, 0, r6, c0, c0, 0 @ 读取 id reg为B双星msb移动 r0, r0移动 r0, r0回复物理块:蓝光环形

感谢任何有线索或指点的人!

解决方案

由于 Jacen 和 dwelch 都通过评论(每个)好心地提供了我需要的答案,为了清楚起见,我将在这里回答我自己的问题:

诀窍是简单地添加一个从/到执行转换的页面的身份映射,允许我们使用物理"(尽管实际上是虚拟的)PC 跳转到它,然后禁用 MMU.

这是最终代码(有点具体,但已注释):

/* 复制到这里的映射 */mrc p15, 0, r4, c2, c0, 0//得到 TTRB0ldr r10,=0x00003fffbic r4, r10//提取页表物理基地址orr r4, #0xc0000000//急切地将它翻译"为虚拟的/** 这里 r8 保存 vf_suspend 的物理地址.我没有办法* 更本地"地做这件事,因为物理和虚拟* 我的代码空间是运行时分配的.*/添加 lr, r8, #(phys_block-vf_suspend)//->phys_block 物理地址lsr r9, lr, #20//SECTION_SHIFT ->页面索引添加 r7, r4, r9, lsl #2//PMD_ORDER ->入口地址ldr r10, =0x00000c0e//标志orr r9, r10, r9, lsl #20//SECTION_SHIFT ->入场价值str r9, [r7]//写入条目ret lr//跳转/转换到虚拟寻址物理块:/* 禁用 MMU 和 TEX */为Bmrc p15, 0, r6, c1, c0, 0ldr r7,=0x10000001bic r6, r6, r7mcr p15, 0, r6, c1, c0, 0 @ 打开 MMU、I-cache 等mrc p15, 0, r6, c0, c0, 0 @ 读取 id reg为B双星数据库/* 禁用 Icache、Dcache 和分支预测 */mrc p15, 0, r6, c1, c0, 0ldr r7,=0x1804bic r6, r6, r7mcr p15, 0, r6, c1, c0, 0为B//完毕 !

In short, I would like to shut down all MMU (and cache) operations in a Linux context (from inside the Kernel), for debug purposes, just to run some tests. To be perfectly clear, I don't intend that my system still be functional after that.

About my setup: I'm currently fiddling with a Freescale Vybrid (VF610) - which integrates a Cortex A5 - and its low power modes. Since I'm experimenting some suspiciously local memory corruption while the chip is in "Low Power Stop" mode and my DDR3 in self refresh, I'm trying to shift the operations bit by bit, and right now performing all the suspend/resume steps without actually executing the WFI. Since before this instruction I run with address translation, and after that without (it's essentially a reset), I would like to "simulate" that by "manually" shutting down the MMU.

(I currently have no JTAG nor any other debug access to my chip. I load it via MMC/TFTP/NFS, and debug it with LEDs.)

What I've tried so far:

    /* 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

and other variations to the same effect.

What I observe:

Before the MMU block, I can light a LED (3 assembly instructions, no branch, nothing fancy, nor any access to my DDR, which is already in self refresh - the virtual address for the GPIO port is stored in a register before that).

After the MMU block, I can no more, whether I try with physical or virtual addresses.

I think the problem may be related to my PC, which retains an outdated virtual address. Seeing how things are done elsewhere in the kernel, but the 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 to virtual address
ENDPROC(cpu_resume_mmu)
    .popsection
cpu_resume_after_mmu:

(from arch/arm/kernel/sleep.S, cpu_resume_mmu)

I wonder to what this 2 instructions delay is related to, and where it is documented. I've found nothing on the subject. I've tried something equivalent, without success:

    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

Thanks to anyone who has a clue or some pointers!

解决方案

Since both Jacen and dwelch kindly brought the answer I needed through a comment (each), I will answer my own question here for the sake of clarity:

The trick was simply to add an identity mapping from/to the page doing the transition, allowing us to jump to it with a "physical" (though actually virtual) PC, then disable MMU.

Here is the final code (a bit specific, but commented):

    /* 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 !

这篇关于ARM:禁用 MMU 并更新 PC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆