我正在 ARM 上進行裸機開發,并在 QEMU 上模擬 Raspi 3。下面是我的最小匯編代碼:
.section ".text.boot"
.global _start
_start:
1: wfe
b 1b
下面是我的聯結器腳本:
SECTIONS
{
. = 0x80000;
.text : {*(.text.boot)}
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}
下面是我的 Makefile :
CC = /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin/aarch64-none-elf
CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostartfiles -nostdlib -g
all: clean kernel8.img
start.o: start.S
${CC}-gcc $(CFLAGS) -c start.S -o start.o
kernel8.img: start.o
${CC}-ld -nostdlib start.o -T link.ld -o kernel8.elf
${CC}-objcopy -O binary kernel8.elf kernel8.img
clean:
rm kernel8.elf kernel8.img *.o >/dev/null 2>/dev/null || true
現在從一個終端,我正在加載我的kernel8.elf如下:
$ /opt/qemu-6.2.0/build/qemu-system-aarch64 -M raspi3b -kernel kernel8.elf -display none -S -s
從另一個終端,我連接我的 gdb :
$ /opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin/aarch64-none-elf-gdb ./kernel8.elf -ex 'target remote localhost:1234' -ex 'break *0x80000' -ex 'continue'
(gdb) info threads
Id Target Id Frame
1 Thread 1.1 (CPU#0 [running]) _start () at start.S:6
2 Thread 1.2 (CPU#1 [running]) _start () at start.S:5
* 3 Thread 1.3 (CPU#2 [running]) _start () at start.S:5
4 Thread 1.4 (CPU#3 [running]) _start () at start.S:5
在這種情況下,我的核心沒問題,因為所有 4 個核心都在運行我的匯編代碼。在continue核心隨機命中斷點時,這是完美的。
但是,如果我使用kernel8.img(objcopy binary output) 而不是kernel8.elf,我會看到只有核心 1 正在運行我的程式集,但其他 3 個核心似乎被卡住了。在continue唯一的核心1反復命中斷點每次。
(gdb) info threads
Id Target Id Frame
* 1 Thread 1.1 (CPU#0 [running]) _start () at start.S:5
2 Thread 1.2 (CPU#1 [running]) 0x0000000000000300 in ?? ()
3 Thread 1.3 (CPU#2 [running]) 0x0000000000000300 in ?? ()
4 Thread 1.4 (CPU#3 [running]) 0x0000000000000300 in ?? ()
我想set scheduler-locking on和continue其他3個核心,但他們似乎被卡住。
為什么kernel8.img不作業kernel8.elf?我希望所有 ARM 內核在重置時都運行相同的代碼,(就像kernel8.elf發生在kernel8.img.
uj5u.com熱心網友回復:
QEMU -kernel 選項根據它是否是 ELF 檔案來以不同的方式處理它加載的檔案。
如果它是 ELF 檔案,則根據 ELF 檔案所說的加載方式加載它,并從 ELF 入口點執行開始。如果不是 ELF 檔案,則假定它是 Linux 內核,并以 Linux 內核的引導協議要求的方式啟動。
特別是對于多核板,如果 -kernel 獲得一個 ELF 檔案,它會在入口點一次啟動所有內核。如果它得到一個非 ELF 檔案,那么它將執行該硬體應該為加載 Linux 內核所做的任何事情。對于 raspi3b,這意味著模擬“輔助核心處于回圈中等待主核心通過寫入“郵箱”地址來釋放它們的韌體行為。這是您在 gdb 中看到的行為——核心的 0x300 地址1-3 位于“回圈等待中的旋轉”代碼中。
通常,除非您的來賓代碼是 Linux 內核或希望以與 Linux 內核相同的方式引導,否則不要使用 -kernel 選項來加載它。-kernel 特別是“嘗試做 Linux 內核想要的事情”,而且它也往往有很多遺留的“這對某人來說似乎是一件有用的事情”的行為,這些行為因板與板或不同的客戶 CPU 架構而異。如果您想要完全手動控制“裸機”作業,“通用加載器”是加載 ELF 檔案的好方法。
有關加載訪客代碼的各種 QEMU 選項的更多資訊,請參閱此答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/406276.html
標籤:
