Xosdev chapter 1
Xosdev Chapter 1 [The Bootloader]
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There are two things required to get a basic bootsector running: keep the bootsector at
This is often a big step to understand and code, unless you steal someone else's code.
[ADD KBD BIT INFO TABLE HERE] Steps to take: 1-disable interrupts 2-wait for the kbd controller to clear (if bit 1[00000001] is set that means input port isn't open) 3-write to kbd controller to set A20 gate 4-tell kbd conroller you want to write to output port 5-wait agin for kbd to clear 6-get status value and OR it by 2(bit 2[00000010] is A20 gate bit) 7-write new data to data port 8-write 'nop' to kbd 9-wait for kbd to clear 10-enable interrupts There ya go, 10 easy steps :) If you need any help on this, just check out the provided example code. Moving on.
This step is by far the easiest of them all. All you do is set the proper values
after all of the register are set, you can call interrupt 13h.
Two things that are a must to jump in to your 32-bit kernel are a piece O' pie to setup.
In Asm: mov ax,0x100 mov ss,ax mov sp,0x200 You may need to know that the stack counts down, toward 0, so sp = 0x200 means that the stack is 512 bytes long. SS = memory segment of stack and SP = pointer/offset/size of stack. Next we have the GDT(Note:you may have heard of some people loading the IDT in the bootsector. We will not do this because there is no visible advantage to doing it now). The GDT(Global Descriptor Table) is a table with structures for memory setup. Each GDT entry contains the following:
Limit: This is the limit address of the Pmode Segment (ie-0xFFFFF) Base: This is the base address of the Pmode Segment (ie-0x0) Type: This conatins the type of Segment it is (ie-code/data/writable/readable/stack/ring3..0) Flags: Another set of options like 32bit or 16bit
Present: Tells whther Segment is present or not DPL: Descriptor Privilege Levevl (ring3..0) Segment Type: Tells what kind of segment it is (ie-System=1) C/D: Tells whether segment is code or data segment Expand-Down: Tells whether segment expands up or down in memory Write: Is the segment writable or read-only? Accessed: Every time the segment is accessed this bit is set Once you have at least a code and data segment, alls you need to do is load the data with a pointer. The GDTR(GDT register) holds this data. You can load the data to it with a special command, but first, let me show you exactly what the data looks like. In Asm: GDTR: GDTsize DW 0x10 ; limit GDTbase DD 0x50 ; base address This means that our GDT will begin at 0x500 and span 0x10 bytes. After that, you load it with this command: In Asm: lgdt[GDTR] Then you're all ready to enter Pmode and jump into your kernel code. Remember that this is only the temperary GDT. One thing, the GDT is special in that it requires a null entry before all others. This 'null' entry is simple to create: In Asm: NULL_SEL DD 0 DD 0 Ok, one MORE thing, another name for a GDT entry is a selector. This is because it selects memory, in plainest terms :)
Another very easy, short, and simple step in the bootloader. All you need to do is change a bit in cr3(control register 3). Take a look at the steps. Enabling Pmode: 1-get cr0's current value 2-OR it by 1(bit 1[00000001] is the Pmode bit) 3-save new data to cr3 Hey, hey! "It's Easy as A B C,1 2 3". This will allow protection levels for your OS. Ring 0 is the highest level and ring 3 is the lowest. Think of it this way, the lower the ring, the less bull-crap the cpu gives you about hardware access. The most significant effect of Pmode is that it allows you to access up to a whopping 4GB of memory. That's a whole 4,294,967,296 bytes!!! I know I won't have that much RAM till one of two things ocurr: For me to have >=4GB RAM: 1-1GB chips are up for wholesale 2-Bill Gates adopts me
Ahh, the most exciting moment in OSdev, seeing your hard work workin' for you. In this section I will only briefly discuss how to jump into the kernel. It is up to you to study the provided code and to understand it(it is well commented, I coded it myself). After enabling pmode and loading the GDTR, jump into the kernel at the address where you loaded it at. For example, if I loaded it to 0x5000 linear I would use my Code Selector from the GDT to jump to it. In Asm: jmp CODESEL:0x5000 In Asm(usually CODESEL=0x08): jmp 0x08:0x5000 That doesn't mean segment 0x08, because in Pmode it means the offset to the selector in the GDT. This will not be enough to load a kernel. Read on to the next chapter where it is explained more.There is still a linker script that has to be used to load all code correctly. Then we need code that calls the kernel function: In Asm: [bits 32] ; 32bit code here [global start] ; start is a global function [extern _k_main] ; this is the kernel function start: call _k_main ; jump to k_main() in kernel.c hlt ; halt the cpu It is probably a better idea to read the next chapter and see how it is done there. Comment out the asm jmp command for now. That way it only loads "nothing" and doesn't try to run it. And there ya go. If all goes as planned you will have a very simple 32bit Pmode kernel loaded up(well, at least a simple 32bit bootloader). :)
What fun would it be to have a bootloader with just code? Let's run this bad boy and see how 'bad' you did :) First things first: get the bootloader assembly file and save it as, oh say, boot.asm. Now run this command in windows. In Win: nasm -f bin boot.asm There really is no difference between linux and windows, just get nasm for linux (or whatever other supported platform) and compile boot.asm with the same parameters. This command will output a binary file call 'boot' usually without a 'bin' extension. If you want a 'bin' extension just do this: In Win: nasm -f bin boot.asm -o boot.bin By the way, '-f' = format and '-o' = output. Ok, now take that file and use something like rawrite or similar and write it to sector 1 of the floppy. Stick that bad boy into a real PC and hope it boots right :) It would be a good idea to have some kind of output to make sure it works like the source example has. If you want to use bochs to run the binary file, then look at the example source code. It is easier to explain by example than for me to try to explain it to you. Also, read the bochs' readme file. That always helps :) |