コンテキスト (おそらく不要):
学習課題として、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>
そのため、 のアドレスをchunk
r3 に入れ、 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;
};
chunk
next
重ならないでください。
「特異点線」を の下に移動すると、next->next_free = chunk->next_free
2 つの値が交互に表示されなくなりますが、それでも奇妙*prev_list = next
です。しかし、next->next_free はまだ 0 に設定されています。