Page 1 of 1

Bootloader - ASM to C transition point

Posted: Wed Sep 17, 2014 8:07 am
by MrJonParr
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:

Code: Select all

ORG 0x500
bits 16:
.
ProtectedMode, A20 and GDT setup
.
pmode:
jmp stage2_kernel_loader
.
times 1024 - ($-$$) db 0
stage2_kernel_loader:
And my linker script:

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) }
}
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.

Re: Bootloader - ASM to C transition point

Posted: Wed Sep 17, 2014 9:43 am
by embryo
MrJonParr wrote:My question really is, this feels like a rather ugly hack, and that there's likely a better way
The main problem is - what do you mean using word "better"? Should it be "architecturally excellent"? Or the goal is to get best possible loading speed? Or whatever else?

One more point - if it does the job then may be there is no value in rewriting the code?

Re: Bootloader - ASM to C transition point

Posted: Wed Sep 17, 2014 10:18 am
by MrJonParr
embryo wrote:
MrJonParr wrote:My question really is, this feels like a rather ugly hack, and that there's likely a better way
The main problem is - what do you mean using word "better"? Should it be "architecturally excellent"? Or the goal is to get best possible loading speed? Or whatever else?

One more point - if it does the job then may be there is no value in rewriting the code?
I see your point, I think I was simply looking for other peoples approaches as I had difficulty in finding them and this was all I could figure out. I don't know how it compares.

Certainly the goal was not speed or performance, I would much prefer a cleaner design at this stage to ensure my understanding is solid.

Re: Bootloader - ASM to C transition point

Posted: Wed Sep 17, 2014 10:55 am
by PearOs
Correct me if I'm wrong..

But technically you don't have to use an ELF outputted file for your Kernel code. Just use a raw binary format, that way you can copy it to memory and just jump to its memory location given the binary is setup properly. People typically use ELF file format for programs and libraries, but at your stage in development, just use a raw binary version.

Correct me if I'm wrong, I don't write code in C, so I don't have all the knowledge on C operating system development.

Cheers and good luck!

- Matt

Re: Bootloader - ASM to C transition point

Posted: Wed Sep 17, 2014 2:18 pm
by MrJonParr
I think you're right about the ELF, I won't worry about it until I must. I'll use raw binaries until I require otherwise.

Jon

Re: Bootloader - ASM to C transition point

Posted: Thu Sep 18, 2014 3:58 am
by embryo
MrJonParr wrote:I would much prefer a cleaner design at this stage to ensure my understanding is solid.
Next question is - why there is the staged bootloader approach? If it were possible to load everything required in one step then I suppose all mainstream OSes would use such method. But there are many constraints that prevent us from completing the task with as little efforts as just one simple step. So the main problem here is the constraints. And the clean design can show us in simple terms all the information required to circumvent the constraints. Any other kind of design will not be clear, just because it doesn't show us full picture (is the picture clear if some parts are still hidden?).

So, next we need to figure out the constraints and create our best ever design with the goal of a clean picture in mind.

The constraints are (state 1):
  • 512 byte boot sector code limit (for floppies, for hdd it's even worse)
  • ancient processor mode we met when the boot process starts
  • lack of information about the hardware we are going to boot on
To free ourself from the constraints we need (state 2):
  • all required code to be in memory and at a proper address(es)
  • the environment should be as the code expects
  • the hardware information should be still available in full details
Now it is clean that the bootloader should somehow transform the state 1 into the state 2. From here starts a programmer contest in inventing the transformation procedure. But if the goal is to have really clear design then the contest should include another thing - some measure of "clearness" the design has. And the measure is often very specific for a particular person. It means that if you have some good understanding of your boot process then you can call it "the clear design". All the humanity has invented so far to help you in assessing the "clearness" is just a high level picture of staged bootloader. Everything else is a discussion subject. So, if you have some stages in your boot process and still see it as "clear", then it can be assessed as a clear design (at least by you).

One more point about clearness can be as such - pay as much attention to the careful treatment of every detail as possible. It is tedious and time consuming, but the result will be really solid and "bullet proof" that is really required if we consider hardware diversity, lack of documentation and some "dirty" solutions that are used by BIOS and hardware vendors. But this is the area where I can not help a lot just because I understand that some people (like Brendan on this forum) have much more experience and patience to deal with tricky hardware problems.