Calling bios interrupts from protected mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
walling

Calling bios interrupts from protected mode

Post 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
Dex4u

Re:Calling bios interrupts from protected mode

Post 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.
walling

Re:Calling bios interrupts from protected mode

Post 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?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Calling bios interrupts from protected mode

Post 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
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.
walling

Re:Calling bios interrupts from protected mode

Post 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
pradeep

Re:Calling bios interrupts from protected mode

Post 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.
Dex4u

Re:Calling bios interrupts from protected mode

Post 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.
walling

Re:Calling bios interrupts from protected mode

Post 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
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:Calling bios interrupts from protected mode

Post 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
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.
walling

Re:Calling bios interrupts from protected mode

Post 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
Post Reply