JessyV wrote:Thanks to you for replying, I must confess that I first thought my question was stubborn
.
My loading scheme iss in fact to have the bootloader from 0x7C00 to 0x7E00, as the BIOS loads it. It would then load a larger 16-Bits program (that I call pre-kernel or Kernel.16), which would make all the necessary initializations (Video modes and other BIOS calls) which didn't feet at all in the 512 bytes limit of the bootloader. at 0x6000 so it can be very large while not overwritting the original bootloader, as it shares some of it's routines to avoid code repetition. Then, it would load the definitive, 32-Bits kernel at 0x9000 and pass it control.
What I do for a second stage is to have a "pre-kernel" image that spans as much memory as it needs. Now the clever part is that the boot code checks for every sector it copies, that it isn't in the way of the boot code (if(pointer==
0x7B00)pointer=0x7F00;else copy_next_sector();) and if so it skips copying it and advances beyond it. Meanwhile, in the "pre-kernel" image, I assume that the base address is simply
0x500 and when it reaches the address that would correspond to the boot code in memory, I just pad it with 0 (anyway the boot code will take care not to overwrite itself with this 1024-byte block, just add 0x200 to 0x500 until you reach 0x7B00 and then the need to skip 0x7D00 at the middle of the boot code and finally to 0x7F00, beyond the boot code, becomes more clear).
With that tiny precaution I could probably load an image all the way from
0x500 to
0x9FBFF if I needed to
--see how 0x500-0x7BFF/0x7DFF, 0x7E00-0x7FFFF and 0x80000-0x9FBFF-- are in reality a contiguous block of memory, with just 1 KB of padding (but the assembling/compilation becomes just a little more difficult because you need to check that the first part spans just before the boot code, and then 1024 bytes of padding, and then the rest of the code up to a valid address).
Once you figure out how to build such a skeleton, then reimplementing it becomes very easy (it could take you a while; if you want more specific information, which can require the use of extern or global keywords for C/Assembler, and probably a LD script, unless you are comfortable with manually tracking the structure of the binary, or help about it, just ask).
And I wouldn't mind repeating routines in the second stage and in the kernel. It is normal/standard, and it is better to have all useful functions that make sense, of the second stage in the kernel itself (it allows for the kernel to be really autonomous).
JessyV wrote:The pre-kernel should not, however, overwritten then as my OS will return to it times by times using virtual 8086 mode to, for example, change the video mode or other BIOS things. This is the reason for which it should be so big
Sorry, I just didn't notice the existance of the Memory Map page
There's no need to worry since it's very basic stuff.
I think it is OK to design a kernel in this way if it allows you to learn in the first milestone. BIOS services in Protected Mode are almost useful only for setting VESA modes (standard VGA modes can be programmed in the kernel because they are very well known).
Just don't forget to better use code emulation (look for
x86emu in the wiki for source code of this type, although it's not so basic) or virtual 8086 mode from your kernel instead of returning to Real Mode for some future milestone.
I would only use code emulation because virtual 8086 mode doesn't work for 64-bit Long Mode, from what I have learned.
You could have a similar functionality in the kernel, reimplementing specific software interrupts or using an "exports table" that other rudimentary binaries can be "linked" to the kernel, which in turn could internally have the kernel emulate the BIOS code you need.