具有MMU的ARM裸机:连续读取产生不同的值

时间:2013-07-31 22:15:02

标签: memory arm mmu bare-metal

上下文(可能不需要):

作为一项学习练习,我正在尝试为Raspberry Pi实施迷你“操作系统”。

我目前正在实施一个非常愚蠢的内存管理系统。我已经启用了MMU,而且我正在获取可用的kmalloc。

它已经可以从预先存在的小内核堆中分配内存块,映射到代码和数据段之后。我试图通过映射更多页面来根据需要增长它。它还必须能够生成物理上连续的块。

代码托管在Github,有一个专门针对这个问题的分支,带有调试代码。请注意,它不是一个组织良好,评论良好也不是非常聪明的代码的示例。 :)

实际问题:

在尝试调试数据中止时,我发现了一些非常奇怪的东西。

这是我的kmalloc的一段代码:

next->prev_size = chunk->size;
next->size = -1;

term_printf(term, "A chunk->next_free = 0x%x\n", chunk->next_free);
term_printf(term, "B chunk->next_free = 0x%x\n", chunk->next_free);

*prev_list = next;
next->next_free = chunk->next_free;

term_printf(term, "next_free = 0x%x, chunk 0x%x\n", next->next_free, chunk->next_free);
term_printf(term, "next_free = 0x%x, chunk 0x%x\n", next->next_free, chunk->next_free);

我跑了三次。结果如下:

# 1st
A chunk->next_free = 0x0
B chunk->next_free = 0x0
next_free = 0x0, chunk 0x0
next_free = 0x0, chunk 0x0

# 2nd
A chunk->next_free = 0xffffffff
B chunk->next_free = 0x0
next_free = 0x0, chunk 0xffffffff
next_free = 0x0, chunk 0x0

# 3rd
A chunk->next_free = 0xffffffff
B chunk->next_free = 0xffffffff
next_free = 0xffffffff, chunk 0xffffffff
next_free = 0xffffffff, chunk 0xffffffff

第一次和第三次迭代看起来正常(虽然next_free应该具有值0,但是数据中止是因为它具有0xffffffff)。但是我的代码在第二个代码中做了什么? O_o当连续四次读取时,什么样的黑色魔法可以使我的printf为chunk-> gt; next_free输出两个不同的值? O_O

数据排列良好,页面可缓存且不可缓冲(使它们不可缓存无效),无论编译器优化是打开还是关闭,我都会得到相同的结果。我尝试在那里抛出一个数据内存屏障,但实际上它没有做任何事情。我还检查了生产的组件,看起来还不错。

我认为这可能是由损坏的TLB引起的。我在每次新页面映射后发出“Invalidate unified single entry”(mcr p15,0,%[addr],c8,c7,1)。这够了吗?

我尝试使用qemu进行调试,但是在设置使用过的物理页面的位图时它会先获得数据中止,尽管这部分在Pi上工作正常。

我只是在寻找可能导致此行为的线索。如果你需要更多的上下文请问,虽然我的代码目前正在快速变化,并且有很多printf。


ETA: 前两个printf的反汇编为-O0:

c00025e4:       e51b3018        ldr     r3, [fp, #-24]
c00025e8:       e5933008        ldr     r3, [r3, #8]
c00025ec:       e59b0004        ldr     r0, [fp, #4]
c00025f0:       e59f10a0        ldr     r1, [pc, #160]  ; c0002698 <kmalloc_wilderness+0x2c0>
c00025f4:       e1a02003        mov     r2, r3
c00025f8:       eb000238        bl      c0002ee0 <term_printf>
c00025fc:       e51b3018        ldr     r3, [fp, #-24]
c0002600:       e5933008        ldr     r3, [r3, #8]
c0002604:       e59b0004        ldr     r0, [fp, #4]
c0002608:       e59f1088        ldr     r1, [pc, #140]  ; c000269c <kmalloc_wilderness+0x2c4>
c000260c:       e1a02003        mov     r2, r3
c0002610:       eb000232        bl      c0002ee0 <term_printf>

因此,它将chunk的地址放入r3,然后执行ldr以获取next_free。它在第二个原则之前再次出现。只有一个核心,DMA没有运行,所以在调用之间没有任何改变内存值。

使用-O2:

c0001c38:       e1a00006        mov     r0, r6
c0001c3c:       e59f10d8        ldr     r1, [pc, #216]  ; c0001d1c <kmalloc_wilderness+0x1b8>
c0001c40:       e5942008        ldr     r2, [r4, #8]
c0001c44:       eb000278        bl      c000262c <term_printf>
c0001c48:       e1a00006        mov     r0, r6
c0001c4c:       e59f10cc        ldr     r1, [pc, #204]  ; c0001d20 <kmalloc_wilderness+0x1bc>
c0001c50:       e5942008        ldr     r2, [r4, #8]
c0001c54:       eb000274        bl      c000262c <term_printf>

所以它仍然使用ldr获取值。这就是为什么我在两个优化级别都得到了同样的东西。


新编辑:我添加了更多的printfs,似乎奇点发生在这一点上:

next->size = -1;

在这一行之后,chunk-&gt; next_free变成了海森堡的猫。之前,它读为0。

结构定义如下:

struct kheap_chunk {
    size_t prev_size;
    size_t size; // -1 for wilderness chunk, bit 0 high if free
    struct kheap_chunk *next_free;
};

chunknext不重叠。

如果我移动next->next_free = chunk->next_free下面的“奇点线”,它会在两个值之间停止交替,但它仍然很奇怪:chunk-&gt; next_free在*prev_list = next之前为0,之后为0xffffffff。但是next-&gt; next_free仍然设置为0。

0 个答案:

没有答案