Page 1 of 2
A bootsector that doesn't load the kernel :(
Posted: Sat Jul 15, 2006 12:04 am
by kenneth_phough
I have read a couple tutorials on loading kernels and tried to make my boot sector load a simple kernel but it doesn't work. I kind of have a vague idea what might be the reason but I am not sure.
First, my kernel is just the following:
Code: Select all
[bits 32]
mov byte [ds:0xB8000], 'P'
mov byte [ds:0xB8001], 0x1B
jmp $
In the bootsector I loaded the 2nd sector (the first sector after the bootsector) to 0x08:0x0000 (this is my kernel code segment).
After my bootsector loads my kernel it is supposed to enter p-mode and then jump to the kernel like this jmp 0x08:0x0000 but it causes a triple fault right after I call int 13h for reading the sectors.
I have a feeling that it could be the way I tried to put the kernel and the bootsector to gether. These are the steps I took:
1)compiled the kernel w/ nasm -f bin kernel.asm -o krn.bin
2)compiled the bootsector w/ nasm -f bin boot.asm -o boot.bin
3)cat boot.bin krn.bin > a.bin
then I tested it with bochs.
Would anyone know what might be the problem?
Thanks,
Kenneth
Posted: Sat Jul 15, 2006 3:47 am
by ComputerPsi
It could be a number of reasons. Make sure your GDT is correctly set. Make sure you are writing to the right place in memory. Also, a small bug I see is that you didn't set DS. When you transfer into protected mode completely, if you want to use a segment, you have to set it to the correct number according to the GDT. Also, in your case, make it a data segment, so that you can read and write with DS.
Hope that helps.
Posted: Sat Jul 15, 2006 7:17 am
by kenneth_phough
I changed my code so it loads at 0x10 in the kernel data segment like you advised and moved the
after loading the kernel from after entering protected mode, but it still caused a tripple fault. I haven't gone over my GDT yet but that my next step, but before that, are the following steps in the "right" order for my bootsector?
1)Enable A20
2)Load Kernel
3)Load GDT
4)Enter P-Mode
5)Jump to kernel
Also just to make sure, the first entry (the null entry) in the GDT is at 0x00 right? hence, the second entry (in my case the kernel code segment) would be at 0x08 because each entry is 8bytes long.
Thanks,
Kenneth
Posted: Sat Jul 15, 2006 6:28 pm
by ComputerPsi
Yep.. looks right so far. Don't forget to cli! (The old Interrupts aren't very good when it comes to Protected Mode) Also, when you jump, you jump to the new protected mode segment and offset.. So it would probably look something like this:
jmp 8:0
btw, don't forget to write "org" and the starting offset for your kernel.
Hope that helps.. if not, look over the GDT.
ComputerPsi
Posted: Mon Jul 17, 2006 3:11 am
by kenneth_phough
I'm still not exactly sure what the problem is but I noticed something in my GDT that might be the problem. I made sure I loaded my kernel in the write segment and set the ds to the right address and jumped to the kernel but it still didn't work, so...I looked over my GDT, re-read the intel manuals and searched online for examples/tutorials and found that from my GDT the Segment Limit 19:16 is set to 0x0F but this other person's GDT had it set to 0. I vaguely remember reading a tutorial on
www.osdever.net that this Limit has to be set to 0x0F due to something with the compiler...don't remember any more and I can't check it because
www.osdever.net is not up yet. Could this be the problem?
Thanks,
Kenneth
Posted: Mon Jul 17, 2006 3:26 am
by chase
Your limit really shoudn't matter(if its big enough) as long as you either don't access memory that isn't there or setup paging to remap to physical memory. I have some working GDT code here
http://www.osdev.org/howtos/1/loader.asm if you want to look at it. Maybe if you posted your code? As long as your GDT is setting up a flat memory model your compiler should be ok.
Posted: Mon Jul 17, 2006 3:59 am
by kenneth_phough
Your limit really shoudn't matter(if its big enough) as long as you either don't access memory that isn't there or setup paging to remap to physical memory. I have some working GDT code here
http://www.osdev.org/howtos/1/loader.asm if you want to look at it.
Yeah, I found out. Tried modifying my limit, still get the same fault
. Below are the sources.
My bootsector is @
http://www.kenax.byethost9.com/osdev/boot/bootsect.asm
and my kernel is @
http://www.kenax.byethost9.com/osdev/kernel/kern.asm
Thanks,
Kenneth
Posted: Mon Jul 17, 2006 7:52 am
by kenneth_phough
This might be random but I couldn't decide for myself. Before I go into the problem, which has to do with the bootsector, I'm going to talk a little bit on my background and why I'm trying to write my own OS.
It has been my dream to write my own OS since 7th, 8th grade, however I was never successful. I always failed to write my own bootsector. This was because I didn't have enough time to do research and development due to school work. After I finished junior high I left my old school (it went up till 12th grade) and enrolled a bording high school in williamstown, MA. I stilled dreamed of writing my own OS and when ever I had time I read bit and pieces of Intel's Manual and books on intel assembly (i was fluent in c by then). Over the summer I would practice programing in assembly and read more books on os dev, such as MMURTL v1.0. During my sophomore year I heard about something called a Junior Project. It was a project that all the juniors do towards the end of the year. Students pick a topic they are interested in and they narrow it down and right a paper on it. There is also a creative response to the paper. I immediately new that this would be a great opportunity for me to write an OS and with permission from a faculty member I started working on it over the summer. The topic is operating systems and my creative response is to write a 32-bit multitasking single-user realtime operating system. I bought more books on os dev and am reading them right now. Fortunately with help from people on the internet (we just got DSL) I was able to work my way through, especially with the help from poeple at
www.osdev.org.
I'M SORRY FOR THE LONG INTRO. DIDN'T THINK IT'LL BE THAT LONG.
My concern is that I only have approximately 3 more months and because I am struggling with my bootsector I was wondering if I should use GRUB instead. Any ideas or advice are appreciated.
Thank you very much,
Kenneth
Posted: Mon Jul 17, 2006 1:37 pm
by bubach
You'r jumping to offset 0 in your datasegment, is that really what you want? Should be 0x08 for code. But are you sure that you want to jump to offset 0? What are your segment base?
EDIT: If you'r forced to keep a diary of your work etc. it should be clear to the theachers that you are doing the best you can, and have learned much. For example that writing an OS isn't something you pull off during one summer...
Posted: Mon Jul 17, 2006 8:25 pm
by kenneth_phough
The segment bases for both code and kernel code are 0. The reason I had it jump to 0x10:0x00 was because I had my bootsect load the kernel to 0x10:0x00, my data segment (or what I think is my kernel data segment). I changed the jmp to 0x10:0x08 but now it just freezes after it enters protected mode.
EDIT: I am not forced to keep a diary but by reading the paper the teachers would understand, and my thesis advisory is a tech guy. Also, the important part is that I really enjoy doing this and I wish to continue the development of my operating system even after the project is due.
Posted: Mon Jul 17, 2006 9:23 pm
by JAAman
The segment bases for both code and kernel code are 0. The reason I had it jump to 0x10:0x00 was because I had my bootsect load the kernel to 0x10:0x00, my data segment (or what I think is my kernel data segment). I changed the jmp to 0x10:0x08 but now it just freezes after it enters protected mode.
not sure you understand segmentation...
be sure you do
0x10:0000 and 0x08:0000 are both the same address if they both have the same base
you do know that niether of these are the same as RMode 0x10:0000?
if i am wrong, and you do know where these addresses are, then your problem is simple -- your loading to absolute address 0 -- and overwriting your IDT (BIOS sets it up at bottom_of_memory for compatability with the 8088 where it was always at that address)
Posted: Tue Jul 18, 2006 6:15 am
by kenneth_phough
I think I have an idea of what segmentation it. Please correct me if I am wrong. Segmentation is where you break up the memory into chunks of address spaces. The segment address points to the base address (offset 0) of that specific segment and the offset points to the specific byte of that segment. Now the physical address is mapped by the processor through the GDT. The logical address (or far pointer) [segment:offset] is used by the processor to figure out the physical address in the memory.
In my case, I have 4 segments. The first segment is the kernel code segment which has a limit of 4GB and a base address of 0. The second segment is the kernel data/stack segment which also has 4GB limit and is 0-based. The 3rd and 4th segments are user code and user data/stack respectively, and they also have a 4GB limit and are 0-based. And because they have the same base they start from the same point so they address the same space.
Where could I find information on where I should load the kernel or if it is high up in the segment it wouldn't matter. I know linux loads their kernel at something like offset 1000 for low memory and 10000 (i think) for high.
Also another thing I want to make sure is if I load something to say 0x08:0x100 then because the segment address is set to 0x08 and 0x08 is my kernel segment it should load the stuff into memory as kernel segment.
Thanks,
Kenneth
Posted: Tue Jul 18, 2006 9:44 am
by JAAman
Also another thing I want to make sure is if I load something to say 0x08:0x100 then because the segment address is set to 0x08 and 0x08 is my kernel segment it should load the stuff into memory as kernel segment.
the only thing that matters is the absolute address that it was loaded to (the offset + base) -- if CS.base=DS.base, then loading it into DS:0, you can read/execute it at CS:0
but RMode segmentation is not the same as PMode segmentation (i assume your loading at the correct RMode segment? and not trying to load at RMode 0x8:0?
Where could I find information on where I should load the kernel or if it is high up in the segment it wouldn't matter. I know linux loads their kernel at something like offset 1000 for low memory and 10000 (i think) for high.
doesnt matter what the offset in the segment is, the question is what is the
absolute address -- if your segment base is 0, then the offset is the absolute address
if you are loading in RMode, make sure you understand how the RMode segments are mapped, and as long as the absolute memory address is the same, it shouldnt matter
absolute memory addresses: (all numbers are in hexadecimal)
Code: Select all
0-400 default IDT location (can be moved, but in RMode usually isnt overwriting this area
while interupts are enabled, will crash your computer
-- do not overwrite if you ever want to return to RMode
400-500 BDA (BIOS data area) -- dont overwrite this in RMode, and it contains possibly useful
information you may want to access later
-- do not overwrite if you ever want to return to RMode
500-600 BIOS/data area -- just treat it the same as above
600-800 the MS MBR and the MS boot sector both copy the MBR into this address (i do the same)
for identifying the active partition -- if you are booting on FDD or CD, or dont
support partitions, you can ignore this
-- this is availible space
800-7C00 this is availible space, many people place the stack at 7C00, because it is known valid
7C00-7E00 the boot sector is loaded here -- once you are in your second stage, you could reuse it
if you dont need access to anything in it (i reuse some bootsector code in my
second stage, and if your disk is FAT12/16/32 compliant, you will need access to
the BPB)
7E00-9???? this is all availible space (assuming that your system has full conventional memory
-- not a problem on newer systems)
9????-A0000 this is the extended BDA -- dont touch in RMode (the starting address is stored in
the BDA -- though i cannot remember where -- search for a "memory map BDA" should
give you one of many on the internet
A0000-C0000 part of your video memory is mapped into this area -- not realistically useable
C0000-E0000 this is reserved for ROM chips on add-in cards
E0000-F0000 this is reserved for BIOS ROM, but afaik it has never been used
F0000-10_0000 part of the BIOS code is copied into RAM at this location (and write-protected)
-- both to improve performance, and provide BIOS services in RMode
10_0000-FF??_???? this area is availible if it contains valid RAM
-- RAM does not need to be contingious, and can often be mixed with hardware,
please use e820 to detect this area
FF??_????-FFFF_FFFF this area contains some chipset stuff, CPU stuff, and the BIOS ROMs
-- if you need to know where this stuff is, or about anything beyond FFFF_FFFF
then you already know all of this
i hope this has helped you -- feel free to ask if you need further clairification
Posted: Tue Jul 18, 2006 10:52 pm
by kenneth_phough
Thank you very much. I loaded the kernel at 0x10:0x7E00 and jumped to 0x08:0x7E00 and it worked!
Also I coppied the list of address and printed it out so I can use it as reference for which address are occupied by whom.
I have 2 more questions.
I'm pretty sure that my kernel will exceed 512 B in no time. When it does exceed 512 B then I would have to find a different method of loading my kernel. Before I start looking into this, are there materials/documents I should read first? Also, do I need a filesystem (eventually yes)? Is it recomended to have one? Eventually I would like to write my own but if I need one should I use FAT?
The next question is:
in gcc, does it put an underscore infront of c functions? Last time I compiled a c sample kernel and a kernel entry with an underscore infront of the function and linked them, ld said unkown reference to _kmain. So I used a hex editor and opened the binary file of the compiled C kernel and found out that it didn't have an underscore. So I removed the underscore and it linked but didn't run.
Thanks,
Kenneth
Posted: Thu Jul 20, 2006 9:15 am
by JAAman
When it does exceed 512 B then I would have to find a different method of loading my kernel.
normally, the bootsector is used to load a second-stage bootloader, which then loads the kernel -- this second stage can be much longer than 1 sector (see below)
Also, do I need a filesystem (eventually yes)? Is it recomended to have one? Eventually I would like to write my own but if I need one should I use FAT?
i would recomend switching to use FAT12 immediately -- as it will save headaches later (FAT12 is a very simple, easy to implement FS)
when you do, you will need to rewrite your bootsector to include the BPB (located at the begining of the sector, and contains information about how to access the disk) -- because the FAT12 filesystem is so simple, it can easily be implemented in the bootsector, and then you can load the second stage from a file located in the root directory, this is the way both MS and JAAos do it -- though it is possible to load it from a specific sector (either reserved sector at the begining, or hardcode the sector numbers -- this is how linux does it -- imho, a much less elegant solution), then the second stage, loads the kernel (from a file on the disk) into memory (possiblely moving it above 1MB) and then initializes PMode, then jumps to the kernel code
also note:
that map i gave you is good for memory below 1MB, but...
before you use any memory above 1MB, you must discover how much memory you have, and where it is -- there are several BIOS functions that will do the first, but only 1 will answer the where question (which is very important) -- int15, service e820 -- look it up in the
RBIL or another reference -- all other options only give the amount of memory, not where it is located (it is allowed to have gaps, and there can be hardware mapped lower than memory, and there can be hardware mapped at the same place as memory (like it is below 1MB))