Bootloader - ASM to C transition point
Posted: Wed Sep 17, 2014 8:07 am
Hi there,
I'm new to both OS development and these forums, but I've really enjoyed the learning experience so far. I have what I think is likely quite a simple implementation question, but I was interested as to how other people may have approached this, I get the feeling there is a better way but I've finally got something working and wanted to query the knowledgeable people on the forums about it.
So far, I've got a simple bootloader written that loads (via FAT12) a stage2 binary file, which sets up a GDT and jumps into protected mode. I've been testing via bochs and all seems OK up till this point. It dawned on me that I would now like to start writing in C as I'm much more comfortable in it than assembly, and I wanted to compile the kernel as ELF. Trouble was I didn't fancy an ELF loader in asm, so I wanted to transition from assembly into C code.
So now I have this:
Stage 1 Bootloader - 512 byte loader, parses FAT12 directory for stage2.bin, loads it at 0x0050:0x0000 and jumps to it
Stage 2 - File on FAT12 floppy, sets up GDT, enables A20 address line and protected mode.
Stage 3 - Desired to be written in C to do ELF loading of yet unwritten "kernel.bin".
It was the transition between Stage 2 and Stage 3 (please forgive my likely incorrect naming of the stages) that puzzled me. In the end what I've done is pad the stage 2 file up to a known mark, in my case 1024 bytes and then compile my C code as a flat binary and concatenate it with the stage2 file. Then, when stage2.bin is loaded from disk it includes the C portion at a known offset which I can jump to.
I tell via linker script that it's loaded at Stage2 load offset plus the 1024 byte offset (0x0500 + 1024 = 0x0900) and have stage2 jump to the end of it's section.
So stage 2 looks like:
And my linker script:
My question really is, this feels like a rather ugly hack, and that there's likely a better way, could someone share some insight into how it's normally done?
Thanks for your time,
Jon.
I'm new to both OS development and these forums, but I've really enjoyed the learning experience so far. I have what I think is likely quite a simple implementation question, but I was interested as to how other people may have approached this, I get the feeling there is a better way but I've finally got something working and wanted to query the knowledgeable people on the forums about it.
So far, I've got a simple bootloader written that loads (via FAT12) a stage2 binary file, which sets up a GDT and jumps into protected mode. I've been testing via bochs and all seems OK up till this point. It dawned on me that I would now like to start writing in C as I'm much more comfortable in it than assembly, and I wanted to compile the kernel as ELF. Trouble was I didn't fancy an ELF loader in asm, so I wanted to transition from assembly into C code.
So now I have this:
Stage 1 Bootloader - 512 byte loader, parses FAT12 directory for stage2.bin, loads it at 0x0050:0x0000 and jumps to it
Stage 2 - File on FAT12 floppy, sets up GDT, enables A20 address line and protected mode.
Stage 3 - Desired to be written in C to do ELF loading of yet unwritten "kernel.bin".
It was the transition between Stage 2 and Stage 3 (please forgive my likely incorrect naming of the stages) that puzzled me. In the end what I've done is pad the stage 2 file up to a known mark, in my case 1024 bytes and then compile my C code as a flat binary and concatenate it with the stage2 file. Then, when stage2.bin is loaded from disk it includes the C portion at a known offset which I can jump to.
I tell via linker script that it's loaded at Stage2 load offset plus the 1024 byte offset (0x0500 + 1024 = 0x0900) and have stage2 jump to the end of it's section.
So stage 2 looks like:
Code: Select all
ORG 0x500
bits 16:
.
ProtectedMode, A20 and GDT setup
.
pmode:
jmp stage2_kernel_loader
.
times 1024 - ($-$$) db 0
stage2_kernel_loader:
Code: Select all
ENTRY(kernel_main)
OUTPUT_FORMAT(binary)
SECTIONS
{
/* Stage2 is loaded at 0x0000:0x0500 and is padded to be 1024 bytes. Therefore 0x0500 + 0x400 = 0x900 */
. = 0x00000900;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
Thanks for your time,
Jon.