我想为ARM系统制作微型操作系统。我有这个引导加载程序:
.global _start
.text
_start:
/* Set up the stack */
ldr sp, =stack_top
/* Call the kernel entry point */
bl kernel_entry
/* Infinite loop */
hang:
b hang
.bss
.space 1024
stack_top:
这里内核:
void kernel_entry(void) {
const char *msg = "Hello, ARM world!\n";
char *uart = (char *)0x101f1000; // UART base address for ARM
while (*msg) {
*uart = *msg++;
}
while (1);
}
我写了make文件来编译:
all: bootloader.bin
bootloader.bin: bootloader.elf
arm-none-eabi-objcopy -O binary bootloader.elf bootloader.bin
bootloader.elf: bootloader.o kernel.o
arm-none-eabi-ld -Ttext 0x8000 -o bootloader.elf bootloader.o kernel.o
kernel.o: kernel.c
arm-none-eabi-gcc -ffreestanding -nostdlib -c -o kernel.o kernel.c
bootloader.o: bootloader.s
arm-none-eabi-as -o bootloader.o bootloader.s
run: bootloader.bin kernel.img
./run.sh
clean:
rm -f *.o *.elf *.bin
我使用命令来运行 qemu 子系统:
qemu-system-arm -M genericpb -m 128M -kernel "C:/Users/Ukraine/Documents/FlowyOS/bootloader.bin" -initrd "C:/Users/Ukraine/Documents/FlowyOS/kernel.img" - d 整数
我有“错误”,因为在 wm 中我没有看到
hello world
文本:
有什么可能是错误的以及如何修复它吗?
带子
.globl _start
_start:
mov sp,#0x20000
bl notmain
hang:
b hang
.globl PUT32
PUT32:
str r1,[r0]
bx lr
notmain.c
void PUT32 ( unsigned int, unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;;ra++)
{
ra&=7;
PUT32(0x101f1000,0x30+ra);
}
return(0);
}
内存映射
/* memmap */
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
构建
arm-none-eabi-as --warn --fatal-warnings -march=armv5t strap.s -o strap.o
arm-none-eabi-gcc -c -Wall -O2 -nostdlib -nostartfiles -ffreestanding -march=armv5t notmain.c -o notmain.o
arm-none-eabi-ld strap.o notmain.o -T memmap -o notmain.elf
arm-none-eabi-objdump -D notmain.elf > notmain.list
arm-none-eabi-objcopy notmain.elf -O binary notmain.bin
检查
00000000 <_start>:
0: e3a0d802 mov sp, #131072 ; 0x20000
4: eb000002 bl 14 <notmain>
00000008 <hang>:
8: eafffffe b 8 <hang>
0000000c <PUT32>:
c: e5801000 str r1, [r0]
10: e12fff1e bx lr
00000014 <notmain>:
14: e92d4070 push {r4, r5, r6, lr}
18: e3a04000 mov r4, #0
1c: e59f5014 ldr r5, [pc, #20] ; 38 <notmain+0x24>
20: e2044007 and r4, r4, #7
24: e2841030 add r1, r4, #48 ; 0x30
28: e1a00005 mov r0, r5
2c: ebfffff6 bl c <PUT32>
30: e2844001 add r4, r4, #1
34: eafffff9 b 20 <notmain+0xc>
38: 101f1000 andsne r1, pc, r0
要作为垃圾箱运行,需要前面的入口点。
跑步的一种方法是
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.bin
会喷出来
01234567012345670123456701234567012345670...
停止/退出 ctrl-a 然后 x
或者
qemu-system-arm -M versatilepb -m 128M -kernel notmain.bin
然后 ctrl-alt-3 (当然是 Linux,如果是 Windows 我不知道怎么做,但可能)进入串行控制台。
这就是立场独立,无需尝试。 让我们看看地址空间发生了什么。
.globl GETPC
GETPC:
mov r0,pc
bx lr
hexstring(GETPC());
给出 0x10054(未显示不同的二进制文件)。 所以基于 0x10000(今天我的机器上不是 0x8000)。
所以可以试试这个
MEMORY
{
ram : ORIGIN = 0x00010000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
Disassembly of section .text:
00010000 <_start>:
10000: e3a0d802 mov sp, #131072 ; 0x20000
10004: eb000002 bl 10014 <notmain>
00010008 <hang>:
10008: eafffffe b 10008 <hang>
0001000c <PUT32>:
1000c: e5801000 str r1, [r0]
10010: e12fff1e bx lr
00010014 <notmain>:
10014: e92d4070 push {r4, r5, r6, lr}
10018: e3a04000 mov r4, #0
1001c: e59f5014 ldr r5, [pc, #20] ; 10038 <notmain+0x24>
10020: e2044007 and r4, r4, #7
10024: e2841030 add r1, r4, #48 ; 0x30
10028: e1a00005 mov r0, r5
1002c: ebfffff6 bl 1000c <PUT32>
10030: e2844001 add r4, r4, #1
10034: eafffff9 b 10020 <notmain+0xc>
10038: 101f1000 andsne r1, pc, r0
并运行 elf 文件
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.elf
效果很好。
void notmain ( void )
{
const char *msg = "Hello, ARM world!\n";
char *uart = (char *)0x101f1000; // UART base address for ARM
while (*msg) {
*uart = *msg++;
}
}
由于语言原因,这不应该起作用的原因有很多,但是......
00010014 <notmain>:
10014: e3a03048 mov r3, #72 ; 0x48
10018: e59f2014 ldr r2, [pc, #20] ; 10034 <notmain+0x20>
1001c: e59f1014 ldr r1, [pc, #20] ; 10038 <notmain+0x24>
10020: e5c13000 strb r3, [r1]
10024: e5f23001 ldrb r3, [r2, #1]!
10028: e3530000 cmp r3, #0
1002c: 1afffffb bne 10020 <notmain+0xc>
10030: e12fff1e bx lr
10034: 0001003c andeq r0, r1, ip, lsr r0
10038: 101f1000 andsne r1, pc, r0
r1 指向串口,r2 指向字符串。
它创建了一个 .rodata 部分,即使我没有指定。
Disassembly of section .rodata.str1.4:
0001003c <.rodata.str1.4>:
1003c: 6c6c6548 cfstr64vs mvdx6, [ip], #-288 ; 0xfffffee0
10040: 41202c6f ; <UNDEFINED> instruction: 0x41202c6f
10044: 77204d52 ; <UNDEFINED> instruction: 0x77204d52
10048: 646c726f strbtvs r7, [ip], #-623 ; 0xfffffd91
1004c: Address 0x000000000001004c is out of bounds.
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.elf
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
Hello, ARM world!
QEMU: Terminated
您需要一个用于 uart 指针的易失性,或其他解决方案。 想要控制链接描述文件。
-Ttext 0x8000 将采用一个/常用/默认链接器脚本,并基本上通过更改 .text 所在的位置来修改它。 您将只想控制整个链接而不是这样做,您可以看到链接器脚本是多么微不足道,尽管几乎每个人都严重过度复杂化了他们的链接器脚本。
如果我使用打印数字的二进制文件并执行此操作
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x0002000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
告诉链接器将入口点放入二进制文件中(而不是内存映像中第一个内容的默认值)。 和小精灵一起奔跑。
00002054
你的 0x8000 和其他内核精灵图像也会这样做,只是为了强制进入点......
b .
b .
b .
b .
b .
.globl _start
_start:
reset:
mov sp,#0x10000
bl notmain
hang:
b hang
Disassembly of section .text:
00002000 <_start-0x14>:
2000: eafffffe b 2000 <_start-0x14>
2004: eafffffe b 2004 <_start-0x10>
2008: eafffffe b 2008 <_start-0xc>
200c: eafffffe b 200c <_start-0x8>
2010: eafffffe b 2010 <_start-0x4>
00002014 <_start>:
2014: e3a0d801 mov sp, #65536 ; 0x10000
2018: eb000026 bl 20b8 <notmain>
0000201c <hang>:
201c: eafffffe b 201c <hang>
00002020 <GETPC>:
2020: e1a0000f mov r0, pc
2024: e12fff1e bx lr
00002028
所以它实际上是在使用入口点,而不是简单地从头开始执行。
您可能根本没有查看控制台输出屏幕。 如果没有看到二进制文件的反汇编/转储,很难判断为什么你的二进制文件不起作用。 想要启动裸机,请在尝试运行之前检查反汇编和转储二进制文件。