Page 1 of 1
Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 8:35 am
by walling
Hi everybody,
I'm new on this forum, but it looks great, so I hope you'll help me on this.
I was developing a bootloader, but recently I lost all my code by an accident, so I'm starting all over. Bad luck! Now I want to find out if there's better ways I could do it, than my last attempt. It worked just fine, but maybe it's not the best approach I used.
It's about calling bios interrupts from protected mode and return with the result to protected mode. I did it this way:
- Jumped into protected mode at first, enabled A20, and all that.
- Whenever pmode code would call realmode code it put the realmode segment and offset on the stack and called the PRP-bridge.
- The PRP-bridge (prot-to-real-to-prot) jumped to real mode, took the far pointer off the stack and called the realmode code, which performed some actions like calling an interrupt, and returned. Now it jumped back to protected mode, and returned to the caller.
- It's worth to mention that the pmode and rmode code shared the same stack, which was located so they both could access it.
It is just about the same way GRUB does it, and it works fine, but it might not be the only solution. Fx. can I call BIOS interrupts, when I am in 16-bit protected mode. Then I don't have to jump all the way into real mode.
What solution do you guys out there use?
- Walling
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 9:24 am
by Dex4u
I set the base of the code and data descriptors to DS * 16. Which is computed at run-time, this make switching to RM and back easier.
NOTE: My kernel is loaded as a mz exe with the cs & ds set the same.
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 9:53 am
by walling
Dex4u wrote:
I set the base of the code and data descriptors to DS * 16. Which is computed at run-time, this make switching to RM and back easier.
What do you mean by settings the base and data descriptors. Do you do it in the real mode code? Or what do you mean actually?
It's not difficult to get the linker to insert the correct address. In the new version I thought I'll do something like this:
Code: Select all
extern my_real_mode_code_address ; recieve from linker
extern prp_bridge ; recieve from linker
push dword some_parameter
push dword my_real_mode_code_address
call prp_bridge
add esp, 8
Dex4u wrote:
NOTE: My kernel is loaded as a mz exe with the cs & ds set the same.
Does it run in pmode?
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 10:12 am
by Brendan
Hi,
walling wrote:What solution do you guys out there use?
I do everything I need to in real mode before I bother switching to protected mode or long mode.
To make it "nice" I set one of the segment registers with a 4 GB limit so that I can easily access anything below 4 GB in real mode. See
this topic for an explanation..
walling wrote:Dex4u wrote:
NOTE: My kernel is loaded as a mz exe with the cs & ds set the same.
Does it run in pmode?
I would assume that because Dex4u's code is loaded as a mz exe (a DOS/Windows executable), that its impossible to know where it will be loaded in memory beforehand. In this case he can't pre-calculate the base addresses for protected mode segments in the GDT and needs to do this dynamically to avoid hassles (Dex4u, please correct me if I'm wrong!).
This would, as Dex4u said "make switching to RM and back easier". This also answers your last question - it does use protected mode (but switches back to real mode when it needs to like yours did).
Cheers,
Brendan
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 10:37 am
by walling
Brendan wrote:
I do everything I need to in real mode before I bother switching to protected mode or long mode.
I don't think I could do that. There's many tasks that I have to do, when my bootloader have been loaded. Like chainloading another OS, nothing I can do beforehand.
Brendan wrote:
To make it "nice" I set one of the segment registers with a 4 GB limit so that I can easily access anything below 4 GB in real mode. See
this topic for an explanation..
I thought it always was segment*0x10+offset in real mode...? There's a difference between 16-bit pmode and real mode, isn't it? But I don't know how big a difference it is.
Brendan wrote:
I would assume that because Dex4u's code is loaded as a mz exe (a DOS/Windows executable), that its impossible to know where it will be loaded in memory beforehand. In this case he can't pre-calculate the base addresses for protected mode segments in the GDT and needs to do this dynamically to avoid hassles (Dex4u, please correct me if I'm wrong!).
This would, as Dex4u said "make switching to RM and back easier". This also answers your last question - it does use protected mode (but switches back to real mode when it needs to like yours did).
Ok, now I get it. I don't think it's the occasion with my bootloader, since I know all the addresses at link-time.
Cheers,
- Walling
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 12:09 pm
by pradeep
16bit pmode, i.e unreal mode in unreal mode you can access all the available RAM depending on the GDT entry. Unreal mode is much useful, and Giese's material are quite useful for learning pmode stuff.
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 2:04 pm
by Dex4u
Here is a demo i make the switch to realmode and back to pmode, for switch graphic modes etc.
The demo set up for pmode, switchers to pmode prints a message in text mode, switch to realmode, switch to vesa 640x480 24bpp, goes back to pmode fades the screen, waits 10 seconds and goes to real mode set text mode and back to pmode and so on.
It comes with asm source code.
http://www.dex4u.com/DemoVesa.zip
PS: Yes my OS is pmode with a full set of drivers and function, the demo is a simple demo of how my OS works.
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 6:20 pm
by walling
Thanks for all your answers up till now.
I have just recoded a lot of my lost code, which includes the prot-to-real-mechanism. I might code it to go to unreal mode instead of real real mode, but I haven't had to use it yet.
I call my real mode functions this way now (it's a little smarter than with the code I lost):
Code: Select all
extern realmode_code_address
extern real_getchar
extern prp_bridge
mov [realmode_code_address], dword real_getchar
call prp_bridge
It might seem strange to do it this way, but it enables me to easily create C wrapper functions, like this:
Code: Select all
_getchar:
mov [realmode_code_address], dword real_getchar
jmp prp_bridge
And since the pmode and rmode code share the same stack it's easy to call from C with parameters as well.
I'm now going to rewrite the C++ support code I also lost..
Cheers,
- Walling
Re:Calling bios interrupts from protected mode
Posted: Sun Nov 27, 2005 8:50 pm
by Brendan
Hi,
walling wrote:Brendan wrote:I do everything I need to in real mode before I bother switching to protected mode or long mode.
I don't think I could do that. There's many tasks that I have to do, when my bootloader have been loaded. Like chainloading another OS, nothing I can do beforehand.
When do you enable protected mode and why? A lot of people are "enthusiastic" about getting into protected mode and do it much earlier than they could.
walling wrote:Brendan wrote:
To make it "nice" I set one of the segment registers with a 4 GB limit so that I can easily access anything below 4 GB in real mode. See
this topic for an explanation..
I thought it always was segment*0x10+offset in real mode...? There's a difference between 16-bit pmode and real mode, isn't it? But I don't know how big a difference it is.
The "segment*0x10" part can always be used to find the base address of a segment in real mode, but this tells you nothing about the segment's limit. Usually in real mode all segments have a 64 KB limit, so if you try "mov al,[dword 0x12345678]" you'll get a general protection fault. For "unreal mode" you set the segment limit to 4 GB so that "mov al,[dword 0x12345678]" will work. In this case "segment*0x10+offset" still applies, but the offset can be 65536 or larger.
16-bit protected mode should never be confused with real mode or "unreal mode". They are entirely different (16-bit protected mode is true protected mode, where "segment*0x10+offset" does not apply, an IDT is used instead of an IVT, etc).
Cheers,
Brendan
Re:Calling bios interrupts from protected mode
Posted: Tue Nov 29, 2005 6:45 am
by walling
Brendan wrote:
When do you enable protected mode and why? A lot of people are "enthusiastic" about getting into protected mode and do it much earlier than they could.
My idea is to build a 2-stage bootloader. Stage1 (contained in the MBR) is pure assembler and pure real mode. It will use bios interrupts to load Stage2 into memory and jump to it.
The Stage2 actually contains an A and a B part. The A part will enable the A20 gate and enable protected mode right away, it contains a gunzip module written in 32-bit assembler, which will unzip the B part and jump to it. The B part is almost written in pure C++ and compiled as an relocatable object file, which contains linker information.
I think protected mode throughout Stage2 is the best solution, since I can write my gunzip module in 32-bit assembler. I'll prefer that, but I realize I could write it in 16-bit real mode assembler and enable protected mode just before I jump to my C++ code. I think it's easier this way.
Brendan wrote:
The "segment*0x10" part can always be used to find the base address of a segment in real mode, but this tells you nothing about the segment's limit. Usually in real mode all segments have a 64 KB limit, so if you try "mov al,[dword 0x12345678]" you'll get a general protection fault. For "unreal mode" you set the segment limit to 4 GB so that "mov al,[dword 0x12345678]" will work. In this case "segment*0x10+offset" still applies, but the offset can be 65536 or larger.
16-bit protected mode should never be confused with real mode or "unreal mode". They are entirely different (16-bit protected mode is true protected mode, where "segment*0x10+offset" does not apply, an IDT is used instead of an IVT, etc).
Thanks a lot for that clearification!
Cheers,
- Walling