Я отжимаю игрушку ОС для моей малины pi и пытаюсь настроить MMU. Я хочу разделить виртуальную память между 3G: 1G, поэтому я думаю, что мой код должен быть связан с 0xC0008000, а при выполнении - 0x8000. (0x8000 - это адрес, который текущие загрузчики ожидают найти ядро - поскольку они созданы для Linux).linkscript - другой адрес ссылки и адрес загрузки
Я думаю, что все настроено нормально, выкапывая с помощью 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 петля $» не будет работать, так как он генерируется, как «б · c0008000» вместо того, чтобы использовать относительную ветвь Но не возражаю, что часть. , проблема в том, что он никогда не доходит до входа).
$ cat source/mem.h
#define KERNLOAD 0x8000
#define KERNBASE 0xC0000000
#define KERNLINK (KERNBASE+KERNLOAD)
#define V2P(va) ((va) - KERNBASE)
Это только три исходных файла. Там не должно быть ничего интересного в Makefile, но на выходе из косметики есть
$ 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 включен и мы переходим на главную, gdb работает отлично. Суть заключается в том, чтобы перейти к виртуальному адресу, используя абсолютную ветвь. b/bl
выдаст относительные прыжки. Поэтому я использую ldr pc =main
. bx
работает тоже.
Смотрите: [Gnu ld дает неожиданный груз] (http://stackoverflow.com/questions/14453996/gnu-linker-map-file-giving-unexpected-load-addresses). Я думаю, вы используете путаницу 'load'. Обычно у вас есть ПЗУ и вы хотите скопировать раздел в ОЗУ. 'LOAD' помещает его в двоичный файл. Он не заставляет код работать по этому адресу. Вам нужно написать относительный код 'PC' для части загрузки. –
Кажется, проблема qemu. – jsz
Возможно, вы должны поместить свой * bootstrap * не-MMU-код в отдельный раздел. Например, '. = 0x8000; .boot: {boot.o (.text)} '. Я также воспользовался секцией сценария ['memory' linker] (http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_16.html) и, возможно, назвал разделы вашей памяти 'phys' и' virt'. Используйте 'AT', чтобы сказать, что адрес загрузки находится на * 0x8000 *. –