lgdt not working, mov cr0, eax causing triple fault.
Re: lgdt not working, mov cr0, eax causing triple fault.
Ok, the size of my kernel file is 38364 bytes. I don't know how correct that this is, as the kernel only contains a simple instruction for writing to the screen and to clear it (which is 1128 bytes by itself), and the "pre-kernel" is simply there to jump into the main kernel, and it comes to 89 bytes. Does the linking precess add a bunch of junk to a binary file? The linker is told to output to a binary in the configuration file passed to it.
OK, so I guess the real question of the day is... how would I load all 72 sectors of the kernel into memory using Interupt 13h. I would probably have to pass the int 13h command multiple times, with different parameters corresponding to the multiple cylinders and heads. Having multiple, fixed value disk reading functions will not be that large of a deal for now, until I implement a simple file system, because I only ever plan to use this with my own (and current) kernel.
OK, so I guess the real question of the day is... how would I load all 72 sectors of the kernel into memory using Interupt 13h. I would probably have to pass the int 13h command multiple times, with different parameters corresponding to the multiple cylinders and heads. Having multiple, fixed value disk reading functions will not be that large of a deal for now, until I implement a simple file system, because I only ever plan to use this with my own (and current) kernel.
Last edited by XeonX369 on Wed Jan 27, 2010 3:36 pm, edited 1 time in total.
Re: lgdt not working, mov cr0, eax causing triple fault.
That's a bit weird; any idea *why* it's so big? (How are you linking it? Where are your sections linked to? Looking at those might help to see where your problem is)briandknopp wrote:Ok, the size of my kernel file is 38364 bytes. I don't know how correct that this is, as the kernel only contains a simple instruction for writing to the screen and to clear it (which is 1128 bytes by itself)
Considering the size, I imagine that the start of the file isn't your executable code, so you might have hit a ton of NULs or whatever, which helpfully don't correspond to NOPs in x86)
Re: lgdt not working, mov cr0, eax causing triple fault.
The way that I call ld is as so:Selenic wrote:That's a bit weird; any idea *why* it's so big? (How are you linking it? Where are your sections linked to? Looking at those might help to see where your problem is)
Considering the size, I imagine that the start of the file isn't your executable code, so you might have hit a ton of NULs or whatever, which helpfully don't correspond to NOPs in x86)
Code: Select all
ld -nostdlib -nodefaultlibs -T ./link.ld -o ../Binaries/kernel.xix ../Binaries/prekernel.krnl ../Binaries/kernel.krnl
Yes, I am compiling my base kernel with all the -nodefault(insert name here) options.
My linker script is as so:
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(loader)
SECTIONS
{
.text 0x8200 : {
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data : {
data = .; _data = .; __data = .;
*(.data)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
- Attachments
-
- prekernel.asm
- Pre-Kernel
- (685 Bytes) Downloaded 106 times
-
- kernel.c
- Kernel
- (3.09 KiB) Downloaded 113 times
Last edited by XeonX369 on Thu Jan 28, 2010 11:41 am, edited 1 time in total.
Re: lgdt not working, mov cr0, eax causing triple fault.
OK, I tried getting the kernel into ELF format, primarily by changing the output of the pre-kernel to output to standard elf. Apparently, the old aout format just bloats the file, and I can't use binary, because I get an error message about lack of support for external files (even with an underscore in the function name).
Why does Aout bloat the file?
Why does Aout bloat the file?
Re: lgdt not working, mov cr0, eax causing triple fault.
What error do you get?
These are the commands I use to build the kernel (first compile the C file to an object file, then the ASM file to an AOUT object, and finally call the linker script):
This also seemed to be an error:
It should be (note the "x == x"; otherwise you aren't comparing but assigning a value):
Also, remember to properly set up DS, ES, FS, GS, SS, ESP, etc., before executing the kernel (at first it didn't display anything).
And I insist in that you should load your kernel at 0x100000 (a place just away from the confusion of the Real Mode space), or you will run over reserved memory if you load at 0x8200, but that's only an advice. If you ever note your kernel failing, the machine locking or whatever, take into account that it may be due to the fact that you might be overwritting reserved memory.
I'm using "GCC 3.4.6" and "ld 2.15.92.0.2, 2004-09-27".
Here I have attached the resulting object files, the kernel.bin file and modified versions of the source code, mainly for correcting the error above and changing the linker script so it links to 0x100000 instead of 0x8200.
These are the commands I use to build the kernel (first compile the C file to an object file, then the ASM file to an AOUT object, and finally call the linker script):
Code: Select all
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -c -o kernel.o kernel.c
nasm -f aout -o start.o prekernel.asm
ld -T link.ld -o kernel.bin prekernel.o kernel.o
This also seemed to be an error:
Code: Select all
for( x = 10; x = x; x++ ) { //UNRECOVERABLE LOOP
Code: Select all
for( x = 10; x == x; x++ ) { //UNRECOVERABLE LOOP
And I insist in that you should load your kernel at 0x100000 (a place just away from the confusion of the Real Mode space), or you will run over reserved memory if you load at 0x8200, but that's only an advice. If you ever note your kernel failing, the machine locking or whatever, take into account that it may be due to the fact that you might be overwritting reserved memory.
I'm using "GCC 3.4.6" and "ld 2.15.92.0.2, 2004-09-27".
Here I have attached the resulting object files, the kernel.bin file and modified versions of the source code, mainly for correcting the error above and changing the linker script so it links to 0x100000 instead of 0x8200.
- Attachments
-
- link.zip
- (3.38 KiB) Downloaded 90 times
YouTube:
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: lgdt not working, mov cr0, eax causing triple fault.
Short answer: Because it sucks and is outdated and you really should not be using it.briandknopp wrote:Why does Aout bloat the file?
Re: lgdt not working, mov cr0, eax causing triple fault.
No, that's the easy answer :).Combuster wrote:Short answer
QFT.Because it sucks and is outdated and you really should not be using it.
JAL
Re: lgdt not working, mov cr0, eax causing triple fault.
~,
The error I get:
The resulting kernel.bin file in your packaging is quite small in size, about 4KB. Whereas, if I replicate this process using your modified source files, with the specified commands, my file is quite huge. I suspect that this has something to do with the version of ld. This size difference is ridiculous.
If I use your kernel.bin with my bootloader, the problem persists with the continued triple-faulting. I guess that it wasn't the kernel, but it still appears to be in the loader. This is absolutely crazy, and I just wish I could get to the bottom of this. I suspect that it is the jmp instruction, although I just don't know why.
The error I get:
Code: Select all
prekernel.asm:27: error: binary output format does not support external references
If I use your kernel.bin with my bootloader, the problem persists with the continued triple-faulting. I guess that it wasn't the kernel, but it still appears to be in the loader. This is absolutely crazy, and I just wish I could get to the bottom of this. I suspect that it is the jmp instruction, although I just don't know why.
Combuster, I appreciate your knowledge of this situation. In this case, what sort of executable format should I be using? Elf?briandknopp wrote:
Why does Aout bloat the file?
Short answer: Because it sucks and is outdated and you really should not be using it.
Re: lgdt not working, mov cr0, eax causing triple fault.
ELF is preferred over about anything else. It is well documented, and well supported. Native GRUB support, easy to parse yourself, relatively easy to add your own segments, etc. etc.XeonX369 wrote:what sort of executable format should I be using? Elf?
JAL
Re: lgdt not working, mov cr0, eax causing triple fault.
OK, I have switched my pre-kernel file to be output to ELF. The final kernel file comes out to 7KB. So, I set my bootloader to load the 15 segments of floppy necessary for the loading of the kernel. The bootloader still does not work. It continues on to the jump instruction, and then it tripple faults.
~, I have given your bootsector and loader a try, and have found it to work. If I wanted to just use your bootsector to load my kernel, could I just substitute the "bootloader" functions and place them into the 'pre-kernel' file (eg, A20, GDT, PMode)? This would then be linked to the kernel itself. In all effect, the kernel would be loaded directly from the bootsector, with the linked pre-kernel acting as the "bootloader" that I have now.
~, I have given your bootsector and loader a try, and have found it to work. If I wanted to just use your bootsector to load my kernel, could I just substitute the "bootloader" functions and place them into the 'pre-kernel' file (eg, A20, GDT, PMode)? This would then be linked to the kernel itself. In all effect, the kernel would be loaded directly from the bootsector, with the linked pre-kernel acting as the "bootloader" that I have now.
Re: lgdt not working, mov cr0, eax causing triple fault.
The easiest way of doing things in that respect maybe would be to replicate the most important things into the second stage bootloader.
The sample bootsector tries to set up the A20 line through the keyboard controller, sets up Unreal Mode so now you are able to load the kernel above the 1MB mark (you can now reach 0x100000 and above).
I have attached a bootsector that I think is like the previous ones, and have also attached a second stage bootloader.
This bootloader tries again to enable the A20 line through several methods (keyboard controller, BIOS and Fast A20), but not without first testing if it's already enabled.
It also duplicates the small FAT12 code so now you can add other things to this bootloader before jumping to the kernel.
You must name this second stage bootloader, "LOADER.BIN" and the kernel "KERNEL.BIN" (you can change it in the source code).
Your second stage bootloader is loaded always at 8000h:0000h, so it has about 120KB of memory that you can use to gather things like the memory map, maybe some peripheral detection, some option you could implement to boot from a device other than the floppy (it is an advanced feature which is not implemented at all in this sample) and/or set up a graphics mode -- among many other things.
Your bootloader can use RAM from 80000h to 9FBFFh. If you use memory outside that region, with the current setup of loading it at 8000h:0000h, you will make a mistake.
The KERNEL.BIN file is loaded at 0x100000, and is a 32-bit protected mode image (you can reload your own GDT and other structures from your kernel to replace the ones used by the bootloader).
As you can see, both these bootsector and bootloader can now read from a FAT12 floppy since they duplicate the same FAT12 reading code and the second stage bootloader accesses the FAT12 fields located at 7C00h.
The code still needs a lot of cleanup, mainly to make the FAT12 code more ordered (it is optimized to be extremely compact, sacrificing simplicity) but it's a good start for being able to have a first and second stage bootloaders, both capable of reading the files from a standard FAT12 floppy that can be read and used under Windows.
If you wonder what's good about that, it is that as you know, 512 bytes of boot code aren't enough, so the second stage bootloader allows you to take advantage of BIOS calls, which will allow you to get many important pieces of information about your PC. If you made a 512-byte bootsector that jumped directly to a 32-bit kernel, you couldn't use the BIOS (not without heavy emulation on your own) and that would get your kernel rather lost in an unknown hardware environment.
So the configuration of memory for these programs is like this:
The DL register will be set by the bootsector to the original drive number we were booted from just before jumping to the second stage.
You need to install the bootsector to the floppy, and copy to it (preferably empty) the files LOADER.BIN and KERNEL.BIN.
The KERNEL.BIN file included is the previous one, unchanged.
This bootsector program in general is very fragile because each instruction depends greatly on the results of the previous one(s) to reduce as much as possible the waste of space and try to do an "extreme" optimization, so it isn't easy to modify it arbitrarily without a lot of care.
Maybe I should suggest that you should first fully understand FAT filesystems and all of the code presented until now, which should now be able to pass control to 2nd stage and from there to a 32-bit kernel. Otherwise, there could be a chance of like 90% that you will make many failed kernel attempts which will span a lot of time.
Using an attempt of a kernel is a inconvenient choice if you still need to find out how the hardware works, it's a very deserted environment when you have entered Protected Mode and don't have yet available any way to use the 16-bit Real Mode code of the BIOS or useable drivers. When something about your low level design considerations don't fit with the hardware setup, it will cause bugs that will require you to start from scratch (or almost).
The sample bootsector tries to set up the A20 line through the keyboard controller, sets up Unreal Mode so now you are able to load the kernel above the 1MB mark (you can now reach 0x100000 and above).
I have attached a bootsector that I think is like the previous ones, and have also attached a second stage bootloader.
This bootloader tries again to enable the A20 line through several methods (keyboard controller, BIOS and Fast A20), but not without first testing if it's already enabled.
It also duplicates the small FAT12 code so now you can add other things to this bootloader before jumping to the kernel.
You must name this second stage bootloader, "LOADER.BIN" and the kernel "KERNEL.BIN" (you can change it in the source code).
Your second stage bootloader is loaded always at 8000h:0000h, so it has about 120KB of memory that you can use to gather things like the memory map, maybe some peripheral detection, some option you could implement to boot from a device other than the floppy (it is an advanced feature which is not implemented at all in this sample) and/or set up a graphics mode -- among many other things.
Your bootloader can use RAM from 80000h to 9FBFFh. If you use memory outside that region, with the current setup of loading it at 8000h:0000h, you will make a mistake.
The KERNEL.BIN file is loaded at 0x100000, and is a 32-bit protected mode image (you can reload your own GDT and other structures from your kernel to replace the ones used by the bootloader).
As you can see, both these bootsector and bootloader can now read from a FAT12 floppy since they duplicate the same FAT12 reading code and the second stage bootloader accesses the FAT12 fields located at 7C00h.
The code still needs a lot of cleanup, mainly to make the FAT12 code more ordered (it is optimized to be extremely compact, sacrificing simplicity) but it's a good start for being able to have a first and second stage bootloaders, both capable of reading the files from a standard FAT12 floppy that can be read and used under Windows.
If you wonder what's good about that, it is that as you know, 512 bytes of boot code aren't enough, so the second stage bootloader allows you to take advantage of BIOS calls, which will allow you to get many important pieces of information about your PC. If you made a 512-byte bootsector that jumped directly to a 32-bit kernel, you couldn't use the BIOS (not without heavy emulation on your own) and that would get your kernel rather lost in an unknown hardware environment.
So the configuration of memory for these programs is like this:
Code: Select all
7C00h -- FAT12 bootsector
8000h -- FAT tables read from disk
40000h -- temporary sector-at-once buffer
80000h -- second stage bootloader
100000h -- kernel image
You need to install the bootsector to the floppy, and copy to it (preferably empty) the files LOADER.BIN and KERNEL.BIN.
The KERNEL.BIN file included is the previous one, unchanged.
This bootsector program in general is very fragile because each instruction depends greatly on the results of the previous one(s) to reduce as much as possible the waste of space and try to do an "extreme" optimization, so it isn't easy to modify it arbitrarily without a lot of care.
Maybe I should suggest that you should first fully understand FAT filesystems and all of the code presented until now, which should now be able to pass control to 2nd stage and from there to a 32-bit kernel. Otherwise, there could be a chance of like 90% that you will make many failed kernel attempts which will span a lot of time.
Using an attempt of a kernel is a inconvenient choice if you still need to find out how the hardware works, it's a very deserted environment when you have entered Protected Mode and don't have yet available any way to use the 16-bit Real Mode code of the BIOS or useable drivers. When something about your low level design considerations don't fit with the hardware setup, it will cause bugs that will require you to start from scratch (or almost).
- Attachments
-
- 2stages.zip
- (10.29 KiB) Downloaded 125 times
YouTube:
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
http://youtube.com/@AltComp126
My x86 OS/software:
https://sourceforge.net/projects/api-simple-completa/
Donate to get more food/programming resources/computers:
https://www.paypal.com/donate/?hosted_b ... QS2YTW3V64
Re: lgdt not working, mov cr0, eax causing triple fault.
I thank everyone who contributed to this thread here. I believe that my question has been answered and my problems (for now) have been solved. I will try to implement some sort of a basic FAT type file system for the disk (or maybe ext2), until I am ready to do a true build, using the files provided here. This will allow me to do some more hardware research and read more manuals, while doing kernel development of my own.
Many thanks, once again, to all who contributed.
Many thanks, once again, to all who contributed.