我正在为我的覆盆子pi拧一个玩具操作系统并试图设置MMU。我想在3G:1G之间拆分虚拟内存,所以我认为我的代码应该在0xC0008000处链接,而在执行时加载到0x8000。 (0x8000是当前引导加载程序期望找到内核的地址 - 因为它们是为linux构建的。)
我认为通过使用objdump来解决所有问题,但是它不起作用。在使用qemu进行一些调试后,我认为引导加载程序根本找不到我的代码。
我认为问题在于我的linkscript,因为如果我将起始代码移动到它自己的部分,并且链接并加载到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)
这是唯一的三个源文件。 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中的调试引起的。断点由虚拟地址设置。 “b entry”不起作用,因为gdb正在考虑虚拟地址,而MMU尚未启用且我们正在按物理地址运行。
因此,在启用MMU之前,我们必须使用“b * 0x8000”。这会设置一个正确命中的断点。 GDB似乎仍然很困惑,因为它没有显示任何调试信息(没有源代码,如0x00008004 in ?? ()
)。这不是一个大问题,因为我有“objdump -D”产生的列表。
启用MMU后我们分支到main,gdb完美运行。关键是使用绝对分支跳转到虚拟地址。 b/bl
会发出相对跳跃。所以我使用ldr pc =main
。 bx
也有效。
答案 0 :(得分:1)
终于解决了......
代码和linkscript没有问题。只是调试似乎不适用于我使用的qemu。当VMA == LMA时它确实有效,但在这种情况下内核已经运行并且qemu不知道它。或者,断点丢失并且从未被gdb捕获。
无论如何,通过重新开始并逐个添加位,我让它在我的rpi(真实硬件)上工作,然后它也适用于qemu(gdb仍然不会捕获断点)。
所以我的问题应该是如何使用qemu / gdb调试这样的场景。
(我的原始问题是通过将“域”权限更改为“管理员”而不是使用“客户端”来解决的。是的,我知道这可能是暂时的,我应该在其他地方设置变量。)