ラズベリーパイ用のおもちゃのOSを絞り、MMUをセットアップしようとしています。仮想メモリを 3G:1G に分割したいので、実行時にコードを 0x8000 にロードしながら、コードを 0xC0008000 にリンクする必要があると思います。(0x8000 は、Linux 用にビルドされているため、現在のブートローダーがカーネルを見つけると予想するアドレスです)。
objdump をいじってみるとうまくセットアップできていると思いますが、うまくいきません。qemu でデバッグした後、ブートローダーが私のコードをまったく見つけられないと思います。
0x8000 でリンクおよびロードされている独自のセクションに開始コードを移動すると、カーネルが正常に起動するため、問題はリンクスクリプトにあると思います。
スクリプトと最小限のコードを抽出しました。次のように、
$ cat kernel.ld
ENTRY(_start)
SECTIONS
{
/* must == KERNLINK */
. = 0xC0008000;
.text : AT(0x8000) {
*(.text)
}
.bss : {
*(.bss)
}
.data : {
*(.data)
}
.rodata : {
*(.rodata)
}
}
-
$ cat source/entry.S
#include "mem.h"
.globl _start
_start = V2P(entry)
.globl entry
entry:
loop$:
b loop$
(「b loop$」は、相対ブランチを使用する代わりに「b·c0008000」として生成されるため、機能しません。しかし、その部分は気にしないでください。問題は、エントリに到達しないことです)。
$ cat source/mem.h
#define KERNLOAD 0x8000
#define KERNBASE 0xC0000000
#define KERNLINK (KERNBASE+KERNLOAD)
#define V2P(va) ((va) - KERNBASE)
これらは、3 つのソース ファイルのみです。Makefile には興味深いものは何もないはずですが、make からの出力は次のとおりです。
$ make
arm-none-eabi-gcc -g -Wall -c -o build/entry.o source/entry.S
arm-none-eabi-ld --no-undefined -T kernel.ld build/entry.o -Map kernel.map -o build/output.elf
arm-none-eabi-objcopy build/output.elf -O binary kernel.img
そしてobjdump、
$ arm-none-eabi-objdump -h build/output.elf
build/output.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000004 c0008000 00008000 00008000 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .ARM.attributes 00000014 00000000 00000000 00008004 2**0
CONTENTS, READONLY
2 .debug_line 0000003c 00000000 00000000 00008018 2**0
CONTENTS, READONLY, DEBUGGING
3 .debug_info 00000054 00000000 00000000 00008054 2**0
CONTENTS, READONLY, DEBUGGING
4 .debug_abbrev 00000014 00000000 00000000 000080a8 2**0
CONTENTS, READONLY, DEBUGGING
5 .debug_aranges 00000020 00000000 00000000 000080c0 2**3
CONTENTS, READONLY, DEBUGGING
明らかでありながら貴重な詳細を見落としていると思い始めています。
====更新====
以下の私自身の回答で述べたように、混乱はqemuでのデバッグによって引き起こされます。ブレークポイントは、仮想アドレスによって設定されます。MMU が有効になっておらず、物理アドレスで実行しているときに gdb が仮想アドレスを考慮しているため、「b エントリ」は機能しません。
したがって、MMU を有効にする前に、「b *0x8000」を使用する必要があります。これにより、正しくヒットするブレークポイントが設定されます。ただし、GDB にはデバッグ情報が表示されない (のようなソース コードがない) ため、まだ混乱しているよう0x00008004 in ?? ()
です。「objdump -D」によって生成されたリストがあるので、それは大きな問題ではありません。
MMU を有効にして main に分岐すると、gdb は完全に機能します。重要なのは、絶対分岐を使用して仮想アドレスにジャンプすることです。b/bl
相対ジャンプを発行します。だから私は使用しますldr pc =main
。bx
も動作します。