1

コンテキスト (おそらく不要):

学習課題として、Raspberry Pi 用のミニ「OS」を実装しようとしています。

私は現在、非常に馬鹿げたメモリ管理システムを実装しています。既に 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);

私はそれを3回実行します。結果は次のとおりです。

# 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

1 回目と 3 回目の反復は正常に見えます (ただし、next_free の値は 0 であるはずですが、0xffffffff であるため、データの中止が発生します)。しかし、私のコードは 2 番目に何をしているのでしょうか? O_o 連続して 4 回読み取られたときに、printf が chunk->next_free に対して 2 つの異なる値を出力するようにするには、どのような黒い魔術が必要ですか? O_o

データは適切に整列されており、ページはキャッシュ可能かつバッファリング不可 (キャッシュ不可にしても意味がありません) であり、コンパイラーの最適化がオンでもオフでも同じ結果が得られます。そこにデータメモリバリアを投げてみましたが、実際には何もしません。作成したアセンブリも確認しましたが、問題ないようです。

TLBの破損が原因である可能性があると思いました。新しいページをマッピングするたびに、「統一された単一のエントリを無効にする」(mcr p15, 0, %[addr], c8, c7, 1) を発行しています。それは十分ですか?

qemu でデバッグを試みましたが、使用済み物理ページのビットマップを設定するとデータが異常終了しますが、この部分は Pi では問題なく動作します。

この動作の原因についての手がかりを探しているだけです。より多くのコンテキストが必要な場合は、質問してください。ただし、私のコードは今のところ急速に変化し、多くの printf が乱雑になっています。


ETA: 最初の 2 つの 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>

そのため、 のアドレスをchunkr3 に入れ、 a を実行してldrを取得しますnext_free。2 番目の prinf の前にもう一度実行します。コアは 1 つしかなく、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->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_free2 つの値が交互に表示されなくなりますが、それでも奇妙*prev_list = nextです。しかし、next->next_free はまだ 0 に設定されています。

4

0 に答える 0