Multiboot question
Multiboot question
Hey everyone,
Do you think it is fine for a multiboot compliant boot loader to pass additional data to the loaded module/kernel for specific types of kernels? Just curious what others think
Do you think it is fine for a multiboot compliant boot loader to pass additional data to the loaded module/kernel for specific types of kernels? Just curious what others think
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
- AndrewAPrice
- Member
- Posts: 2299
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: Multiboot question
Sure! Just make sure it's documented or else no one will use it! But don't they anyway? I've passed like VESA modes into Linux and the path of Initrd and the like..
My OS is Perception.
-
- Member
- Posts: 524
- Joined: Sun Nov 09, 2008 2:55 am
- Location: Pennsylvania, USA
Re: Multiboot question
Multiboot is kind of limited, so this would be a great idea. If you just put everything after the defined multiboot fields (and provide some way of testing if the your extended version of the spec is being used) there shouldn't be any problem with legacy software.
Re: Multiboot question
I would advise against it, unless it's data that your OS doesn't actually require (then why are you passing it?). Or at least put something in there for people to detect which version (yours or standard) is currently installed. If your OS requires more information than the multi-boot spec gives you, then it's not multi-boot compliant. Example, if a user installs a multi-boot loader, then your OS without installing your own multi-boot loader, your kernel will be missing information that it is expecting to be there. You would (best case) detect the missing information and fill it in with generic information, and continue booting. Else, you need to warn the user that the OS will not operate correctly, worst case, assume it's there and crash since all the info is incorrect.
Also, your multi-boot loader must be able to recognize a file that is standard multi-boot compliant vs. extended. Otherwise, if your custom information is larger than a standard multi-boot header, you will overwrite part of the kernel while filling in the info! So you need two forms of error checking (one kernel side and one loader side) to determine if an old version is being run (for either). If the standard multi-boot spec is being followed in the kernel, you can only fill out that information (nothing extra). A better idea, would to simply add another structure, and fill it in if it's found, otherwise just fill in the multi-boot header. Then the kernel can see if the info has been updated, if not just refer to the standard multi-boot header (or throw error message). I don't see why you are even trying to use the multi-boot "standard" if you're doing something non-standards compliant, it goes around the entire reason to have a standard. I do not use the multi-boot standard for my OS because it's not easily extended for future hardware.
Also, your multi-boot loader must be able to recognize a file that is standard multi-boot compliant vs. extended. Otherwise, if your custom information is larger than a standard multi-boot header, you will overwrite part of the kernel while filling in the info! So you need two forms of error checking (one kernel side and one loader side) to determine if an old version is being run (for either). If the standard multi-boot spec is being followed in the kernel, you can only fill out that information (nothing extra). A better idea, would to simply add another structure, and fill it in if it's found, otherwise just fill in the multi-boot header. Then the kernel can see if the info has been updated, if not just refer to the standard multi-boot header (or throw error message). I don't see why you are even trying to use the multi-boot "standard" if you're doing something non-standards compliant, it goes around the entire reason to have a standard. I do not use the multi-boot standard for my OS because it's not easily extended for future hardware.
Re: Multiboot question
Hi,
If it's something that can be provided when the OS is installed then load it as a module (e.g. some sort of boot script). If it's something that needs to be detected during boot then you could either extend the multi-boot information structure to include it (and have compatibility problems), or do what I always do - switch back to real mode as soon as your code is running so you can do things properly (with no compatibility problems).
If you do plan on extending GRUB and/or the multi-boot specification, remember that "GRUB legacy" has been mostly frozen by the official developers (AFAIK they want everyone to shift to "GRUB 2" one day). Because of this you could end up forking GRUB (or perhaps waiting several more years for "GRUB 2" to be canceled due to lack of progress)...
Cheers,
Brendan
What sort of information?neon wrote:Do you think it is fine for a multiboot compliant boot loader to pass additional data to the loaded module/kernel for specific types of kernels? Just curious what others think
If it's something that can be provided when the OS is installed then load it as a module (e.g. some sort of boot script). If it's something that needs to be detected during boot then you could either extend the multi-boot information structure to include it (and have compatibility problems), or do what I always do - switch back to real mode as soon as your code is running so you can do things properly (with no compatibility problems).
If you do plan on extending GRUB and/or the multi-boot specification, remember that "GRUB legacy" has been mostly frozen by the official developers (AFAIK they want everyone to shift to "GRUB 2" one day). Because of this you could end up forking GRUB (or perhaps waiting several more years for "GRUB 2" to be canceled due to lack of progress)...
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Multiboot question
That was my original problem, actually. Basically there was no nice way for me to return to real mode because my systems image base is at 64k. Entering rmode limits CS to 0xffff (1 byte less then 64K) so a gpf would occur. I was originally thinking of passing my bootloaders rmode<>pmode routine (bad, I know.)Brendan wrote:or do what I always do - switch back to real mode as soon as your code is running so you can do things properly (with no compatibility problems).
While my compiler does not allow me to rebase the image less then 64K, I have came up with a nice solution: I took my bootloaders relocate() routine and, upon entry of the program, the program will relocate itself to 0x1000 and continue execution from there which creates a nice environment for real mode code.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Re: Multiboot question
Hi,
I'm currently using "CS:IP = 0xFFFF:0x0010" where my code is mostly all 16-bit, and a separate piece of code (which switches to protected mode eventually) is loaded as a module. My code is a little different though - there's native boot loaders (floppy, CD, PXE/network) that all load certain files into memory and start a "common PC-BIOS" module (while in real mode), and then there's the GRUB thing which needs to emulate the native boot loaders.
IMHO actually relocating the code shouldn't be necessary - it's usually enough to use the segment register's base address instead. For example, set CS/DS/ES/SS to 0xFFFF in real mode, and create GDT entries with "base = 0x000FFFF0" for protected mode. The only hassle here is that you'd need to convert physical addresses. For example, the video card's display memory might be at 0x000A0000, and you'd need to do "video_address = (0x000A0000) - 0x000FFFF0" (using 32-bit unsigned arithmetic) to convert it into an address suitable for your segment registers (so that 0x000A0000 becomes "DS:0xFFFA0010").
Of course you could do the same without changing your image base - use CS/DS/ES/SS = 0xFF00 (where the real mode address "0xFF00:0x1000" is the physical address "0x00100000") and then create GDT entries with "base = 0x000FF000".
Cheers,
Brendan
I'd assume you'd be able to change your code so that your image base isn't at 64 KiB...neon wrote:That was my original problem, actually. Basically there was no nice way for me to return to real mode because my systems image base is at 64k.Brendan wrote:or do what I always do - switch back to real mode as soon as your code is running so you can do things properly (with no compatibility problems).
No. In real mode, if CS is set to 0xFFFF then you'd be able to access from 0xFFFF:0x0000 to 0xFFFF:0xFFFF without getting a general protection fault because the offset is always below the segment limit. This works out to physical addresses 0x000FFFF0 to 0x0010FFEF.neon wrote:Entering rmode limits CS to 0xffff (1 byte less then 64K) so a gpf would occur. I was originally thinking of passing my bootloaders rmode<>pmode routine (bad, I know.)
I'm currently using "CS:IP = 0xFFFF:0x0010" where my code is mostly all 16-bit, and a separate piece of code (which switches to protected mode eventually) is loaded as a module. My code is a little different though - there's native boot loaders (floppy, CD, PXE/network) that all load certain files into memory and start a "common PC-BIOS" module (while in real mode), and then there's the GRUB thing which needs to emulate the native boot loaders.
The problem here is that you don't know what you're overwriting at 0x1000 (for e.g. you could be trashing the multi-boot information structure).neon wrote:While my compiler does not allow me to rebase the image less then 64K, I have came up with a nice solution: I took my bootloaders relocate() routine and, upon entry of the program, the program will relocate itself to 0x1000 and continue execution from there which creates a nice environment for real mode code.
IMHO actually relocating the code shouldn't be necessary - it's usually enough to use the segment register's base address instead. For example, set CS/DS/ES/SS to 0xFFFF in real mode, and create GDT entries with "base = 0x000FFFF0" for protected mode. The only hassle here is that you'd need to convert physical addresses. For example, the video card's display memory might be at 0x000A0000, and you'd need to do "video_address = (0x000A0000) - 0x000FFFF0" (using 32-bit unsigned arithmetic) to convert it into an address suitable for your segment registers (so that 0x000A0000 becomes "DS:0xFFFA0010").
Of course you could do the same without changing your image base - use CS/DS/ES/SS = 0xFF00 (where the real mode address "0xFF00:0x1000" is the physical address "0x00100000") and then create GDT entries with "base = 0x000FF000".
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Multiboot question
Thats what I thought. Except its Bochs that is causing the gpf for that reason (cs:eip > limit) which is set to 0xffff whenever I enter real mode regardless of how my gdt entry flags are set up.No. In real mode, if CS is set to 0xFFFF then you'd be able to access from 0xFFFF:0x0000 to 0xFFFF:0xFFFF without getting a general protection fault because the offset is always below the segment limit. This works out to physical addresses 0x000FFFF0 to 0x0010FFEF.
...Although I have not tried that. Im going to give that a try when I get back from work and see what happens.Of course you could do the same without changing your image base - use CS/DS/ES/SS = 0xFF00 (where the real mode address "0xFF00:0x1000" is the physical address "0x00100000") and then create GDT entries with "base = 0x000FF000".
Thanks for your suggestions
Re: Multiboot question
May want to check if A20 is enabled or disabled, it will behave differently depending. If it's disabled, it will wrap around, if it's enabled, it will not wrap around, may just be a bochs warning saying that it's being wrapped since A20 wasn't enabled.
Re: Multiboot question
A20 is enabled in the bootloader.
Nontheless, thanks to Brendan, I think I know where the problem is at. Ill post back if it works or not
Nontheless, thanks to Brendan, I think I know where the problem is at. Ill post back if it works or not
Re: Multiboot question
I got it working I am now jumping to 0x1000:.rmode - 0x10000, where 0x10000 is the image base (64k), and .rmode is the linear address of the beginning of the real mode code. 0x1000:.rmode - 0x10000 == .rmode linear address.
Granted, I still have to finish the function but at least this problem is fixed
Thanks for your help
Granted, I still have to finish the function but at least this problem is fixed
Thanks for your help
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}