I want make tiny OS for ARM system. I have this bootloader:
.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:
And Here kernel:
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);
}
I wrote make file for compiling:
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
I use command for runing qemu subsystem:
qemu-system-arm -M versatilepb -m 128M -kernel "C:/Users/Ukraine/Documents/FlowyOS/bootloader.bin" -initrd "C:/Users/Ukraine/Documents/FlowyOS/kernel.img" -d int
And i have 'error' cuz in wm i did not see hello world
text:
Any ides what can be wrong and how to fix it?
strap.s
.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
/* memmap */
MEMORY
{
ram : ORIGIN = 0x00000000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
build
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
Inspect
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
To run as a bin need the entry point up front.
One way to run is
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.bin
It will spew out
01234567012345670123456701234567012345670...
To stop/exit ctrl-a then x
Or
qemu-system-arm -M versatilepb -m 128M -kernel notmain.bin
Then ctrl-alt-3 (Linux of course, if Windows I don't know how, but it's possible) to get to the serial console.
That was position independent without trying. Let's see what is going on with the address space.
.globl GETPC
GETPC:
mov r0,pc
bx lr
hexstring(GETPC());
gives 0x10054 (different binary not shown). So 0x10000 based (not 0x8000 on my machine today).
So can try this
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
and run the elf file
qemu-system-arm -M versatilepb -m 128M -nographic -kernel notmain.elf
And that works fine.
void notmain ( void )
{
const char *msg = "Hello, ARM world!\n";
char *uart = (char *)0x101f1000; // UART base address for ARM
while (*msg) {
*uart = *msg++;
}
}
A number of reasons why this should not work for language reasons, but...
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 points to the uart, r2 points at the string.
It created an .rodata section even though I did not specify one.
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
Hello, ARM world!
QEMU: Terminated
You want a volatile for the uart pointer, or other solutions. Want to have control over the linker script.
The -Ttext 0x8000 is going to take a/the stock/default linker script and basically hack it up with changing where .text lives. You will want to just control the whole link and not do this, you can see how trivial linker scripts can be despite almost everyone grossly over complicating theirs.
If I take my binary that prints numbers out and do this
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x0002000, LENGTH = 32K
}
SECTIONS
{
.text : { *(.text*) } > ram
.bss : { *(.text*) } > ram
}
Telling the linker to put the entry point into the binary (other than a default of the first thing in the memory image). And run with the elf.
00002054
And your 0x8000 and other kernel elf images would do this as well, just to force the entry point...
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
So it is really using the entry point not simply executing from the start.
It may be that you simply are not looking at the console output screen. Without seeing a disassembly/dump of your binary, it is difficult to tell why yours is not working. Want to boot something bare-metal, disassembly and dumping the binary is examined before even trying to run.