Memory ARM裸金属与MMU:连续读取产生不同的值

Memory ARM裸金属与MMU:连续读取产生不同的值,memory,arm,mmu,bare-metal,Memory,Arm,Mmu,Bare Metal,上下文(可能不需要): 作为一个学习练习,我正在尝试为Raspberry Pi实现一个迷你“操作系统” 我目前正在实施一个非常愚蠢的内存管理系统。我已经启用了MMU,并且正在获得一个可用的kmalloc 它已经可以从预先存在的小内核堆中分配内存块,映射到代码和数据段之后。我正试图通过映射更多的页面来让它根据需要增长。它还必须能够产生物理上连续的块 代码托管在,有一个分支专门讨论这个问题,其中包含调试代码。请注意,这不是一个组织良好、注释良好或非常聪明的代码示例。:) 实际问题: 在尝试调试数据中

上下文(可能不需要):

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

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

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

代码托管在,有一个分支专门讨论这个问题,其中包含调试代码。请注意,这不是一个组织良好、注释良好或非常聪明的代码示例。:)

实际问题:

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

这是我的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,但是数据中止发生,因为它的值为0xFFFFFF)。但是我的代码在第二个过程中做了什么?O_O什么样的黑色魔法可以让我的printf在连续读取四次时为chunk->next_自由输出两个不同的值?欧欧欧

数据对齐良好,页面可缓存且不可缓冲(使其不可缓存没有帮助),无论编译器优化是打开还是关闭,我都会得到相同的结果。我试着在那里设置一个数据存储屏障,但实际上它什么也没做。我还检查了生产的组件,看起来还可以

我认为这可能是由损坏的TLB引起的。在每个新的页面映射之后,我将发布“使统一单条目无效”(mcr p15,0,%[addr],c8,c7,1)。够了吗

我试着用qemu进行调试,但是在设置使用过的物理页面的位图时,它得到了一个数据中止,尽管这部分在Pi上运行良好

我只是在寻找导致这种行为的线索。如果您需要更多的上下文,请询问,尽管我的代码目前正在快速变化,并且有很多printf


预计到达时间: 对于前两个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>
因此,它仍然使用
ldr
获取值。这就是为什么我在两个优化级别上得到相同的结果


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

next->size = -1;
在这一行之后,chunk->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;
};
chunk
next
不重叠


如果我将“奇点线”移动到
next->next\u free=chunk->next\u free
下面,它会停止在两个值之间交替,但仍然很奇怪:chunk->next\u free在
*prev\u list=next
之前为0,之后为0xffffffff。但是next->next\u free仍然设置为0。

您提到的
term\u printf
是在汇编中编写的。你确定它遵守了你的C编译器所期望的调用约定吗?是的,我广泛地使用过它,并且它从来没有显示出任何问题。我使用的是arm-none-eabi-gcc。您已经反汇编并检查了对term_printf的调用,以知道编译器正在获取正确的东西吗?同样,您尝试了不同的优化级别,以查看这是否会影响行为?是的。我编辑了我的问题我又调查了一些。请参阅问题的第三部分(我在源代码中添加了前面的几行)。
struct kheap_chunk {
    size_t prev_size;
    size_t size; // -1 for wilderness chunk, bit 0 high if free
    struct kheap_chunk *next_free;
};