v86 question - invoking BIOS

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
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

v86 question - invoking BIOS

Post by neon »

Hey everyone,

I cannot seem to find out what the problem is here, or where to begin looking anymore on this problem, and hope someone else may have some ideas at what the problem may be.

I am setting up v86 mode in my bootloader. This is the v86 task:

Code: Select all

bits 16

V86_Mode:

	sti

	mov	al, 'A'
	mov	ah, 0eh
	int	10h			; print 'A'

	int	0x80	;	terminate process-return to previous task

	jmp	$
Okay... The important line is INT 0x10. This is to be invoking BIOS INT 0x10 through my GPF handler.

The above v86 task is executing at ring 3. When the INT 0x10 instruction is executed, the processor executes my GPF handler nicely, and enters back in pmode.

...Except still at ring 3.

What can cause this? Why would the processor execute my pmode GPF handler at ring 3 still? Is it not supposed to switch back to ring 0?

---

Now for problem number 2...

I cannot seem to be able to execute the BIOS interrupt handler. I have the IVT index, but cannot execute it from that location. Anything I try, it will either GPF, Double fault, or triple fault. :( Other times, of course, jumping off to la-la land.

It never attempts to execute the handler.

I have checked with the intel manuals. Assuming the first problem is an actual problem, I wonder if these two are linked.

As I have tried so many things to invoke the BIOS interrupt through the IVT, I have had countless of different Bochs log errors. As such, it would not be of much use here to post it. I am basically looking for either an example, stack frame setup, anything that can help in invoking the BIOS interrupt from the GPF handler / v86 monitor.

I am looking for more suggestions here on possible places to look that may cause these problems. I am all out of ideas :/

Thanks for any suggestions. ;)
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post by AJ »

For problem 1, have you checked your GPF code segment entry for RPL? Otherwise, I'm not sure there.

For problem 2, presumably you are treating the IVT entry as a 16 bit sg:offset pair rather than trying to jump directly to the IVT itself. Another reason that it would be faulting is that the interrupt handler you have jumped to immediately attempts a) A privileged instruction such as in/out, or b) Is located somewhere that is not paged in or c) it is paged in but the page table entry does not have the correct privilege level.

Have you tried enabling VME in CR4? That may be an easier way to deal with it.

Cheers,
Adam
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

Hello,
For problem 1, have you checked your GPF code segment entry for RPL? Otherwise, I'm not sure there.
Can you please elaborate what you mean here?
For problem 2, presumably you are treating the IVT entry as a 16 bit sg:offset pair rather than trying to jump directly to the IVT itself.
Correct.
Another reason that it would be faulting is that the interrupt handler you have jumped to immediately attempts a) A privileged instruction such as in/out
I check for privileged instructions within the GPF handler (Except for in/out right now. I should probably check for those as well to take the possibility out.)
or b) Is located somewhere that is not paged in or c) it is paged in but the page table entry does not have the correct privilege level.
While I do plan on enabling paging, it is not enabled atm, so none of these apply.
Have you tried enabling VME in CR4? That may be an easier way to deal with it.
I have not. I have been thinking about it, though. According to the manuals, they were introduced in the Pentium, so if I enable this I lose compatibility with older processors.

Thanks for your suggestions so far :)
User avatar
Combuster
Member
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:

Post by Combuster »

Any exception in v8086 mode will call the exception handler like anything else. If it doesn't work, you probably have some fields off.

For comparison
The GPF entry in the IDT should be a trap gate, holding the ring 0 CS and the EIP of the exception handler. The privilege part of CS should be 0, the DPL of the IDT entry must be 0 as well to prevent software interrupts causing an "GPF" where the error code suddenly is missing. You should also have a TSS with SS0 and ESP0 set with correct values, again the RPL for SS must 0.

In any case, you may want to try the bochs debugger and request the GDT and IDT info immediately before executing the int 10. If you have something messed up you'll find out soon enough this way, otherwise please post it here (including CPU state before and after the INT instruction)

You may want to try calling INT 0x(gpf index) from the kernel to see what that does.

VME support is not present on all CPUs, and even worse, several emulators pretend they support it while they don't. In general, it does make a lot of things a lot easier.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

Hello again,

Upon close inspection of my v86 monitor / GPF handler, I made two little mistakes when handling the seg:offset address within the IVT, its all fixed now, and seems to be executing the BIOS interrupt. - according to the debugger. *runs to the stupidest mistake thread* ;) )

I seem to have just ran into a stack issue (A iret instruction in Bochs brings it to address 0 - argh.)
The GPF entry in the IDT should be a trap gate, holding the ring 0 CS and the EIP of the exception handler.
Okay, that makes things much clearer.

I am going to try out your suggestion, and post any updates here as I run into them.

Thanks again :D
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

Okay, this is a little update:

It seems to be executing the INT handler fine right now (Sort of, see below.) It executes it, and returns from it fine (Again, sort of.)

There are two current problems:

When the BIOS INT handler is executed, absolutely nothing seems to happen (It should display a character - please see the code in my first post.)

When the handler returns, it returns back to this part of the GPF handler:

Code: Select all

.v86done:

	mov		ax, 0x10			; set data segments to data selector offset (0x10)
	mov		ds, ax
	mov		ss, ax
	mov		es, ax
	mov		fs, ax
	mov		gs, ax
	mov		esp, 90000h			; stack begins from 90000h

	mov	ecx, 0x0ff0

	cli
	hlt		
This is great, as .v86_done can now go back to the v86 task after the INT instruction. This is from my GPF handler.

As soon as the HLT instruction executes, it GPFs again because it is still running at ring3, instead of ring 0 (Please see above posts for more detail here.)

The cli+hlt instructions are temporary while I get the GPF handler working.

I should be able to fix the second problem (Ring3 issue.), But am a little worried about why the BIOS interrupt handler does absolutely nothing.

An interesting note: When the HLT instruction is executed, it executes my GPF again, which checks for HLT and stops here:

Code: Select all

.v86_halt:

	mov		eax, 0xA000
	cli
	hlt
...Still running at ring 3. Except this HLT seems to actually halt the system, even though its at ring 3... :/

Code: Select all

00000989281i[CPU  ] HLT(): CPL!=0
00000990322i[CPU  ] WARNING: HLT instruction with IF=0!
-1106528796p[WGUI ] >>PANIC<< POWER button turned off.
-1106528796i[SYS  ] Last time is 1196039587
-1106528796i[CPU  ] protected mode
-1106528796i[CPU  ] CS.d_b = 32 bit
-1106528796i[CPU  ] SS.d_b = 32 bit
-1106528796i[CPU  ] | EAX=0000a000  EBX=2a2a2af4  ECX=00000ff0  EDX=00001860
-1106528796i[CPU  ] | ESP=00006fd8  EBP=00013202  ESI=00001000  EDI=00001c8b
-1106528796i[CPU  ] | IOPL=3 NV UP DI PL ZR NA PE NC
-1106528796i[CPU  ] | SEG selector     base    limit G D
-1106528796i[CPU  ] | SEG sltr(index|ti|rpl)     base    limit G D
-1106528796i[CPU  ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
-1106528796i[CPU  ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
-1106528796i[CPU  ] |  FS:0000( 0002| 0|  3) 00000100 0000ffff 0 0
-1106528796i[CPU  ] |  GS:0000( 0002| 0|  3) 00000100 0000ffff 0 0
-1106528796i[CPU  ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
-1106528796i[CPU  ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
-1106528796i[CPU  ] | EIP=000017ce (000017ce)
-1106528796i[CPU  ] | CR0=0x60000011 CR1=0x00000000 CR2=0x00000000
-1106528796i[CPU  ] | CR3=0x00000000 CR4=0x00000000
Here, you can see that EAX=0xA000, which was set when .v86_halt was executed (The second GPF call.)

We can also see ECX=0x0FF0, set from .v86done, so we know the BIOS INT handler is returning fine.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

In any case, you may want to try the bochs debugger and request the GDT and IDT info immediately before executing the int 10.
Cant do that yet. I can return after invoking the BIOS handler routine, but cannot IRET from the v86 monitor as it causes a GPF again. Hence, I cannot leave the GPF / v86 monitor.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

Im stumped :/

The following code runs at ring3, v86 mode:

Code: Select all

bits 16

V86_Mode:

	cli
	hlt
The HLT instruction calls my GPF handler in protected mode fine, but STILL runs at ring 3!?

I have all IDT entries follow the same setup:

Code: Select all

%rep 256										; The IDT has 256 descriptors
	istruc idt_entry
		at idt_entry.m_baseLow,		dw 0
		at idt_entry.m_selector,	dw 0x8		; GDT Code selecter offset = 0x8
		at idt_entry.m_reserved,	db 0
		at idt_entry.m_flags,		db 010001111b ; trap gate, 32bit descriptor,ring0, segment present
		at idt_entry.m_baseHi,		dw 0
	iend
%endrep
I use another routine, IDT_SetGate to fill in the base low and high addresses. All interrupt descriptors use the same flags and code selector.

Im thinking my TSS is some how missed up - Although I do not see how (I can execute pmode tasks just fine with my ...err... "task manager".)

Does anyone see what might be wrong?
You may want to try calling INT 0x(gpf index) from the kernel to see what that does.
I tried calling my INT 0x80 from pmode (Ring 0)...It stayed at ring 0 within the handler.

I then tried it within my v86 task running at ring 3...It stayed at ring 3 within the handler. (!?)

Any more suggestions are greatly appreciated :)
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

You know what? I have a feeling something may be wrong with my task managing setup. I dont know for sure, though.

I am going to put this thread on hold for now (Although suggestions are always welcome) while I take a closer look.

Thanks for the suggestions so far.
User avatar
Combuster
Member
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:

Post by Combuster »

neon wrote:
In any case, you may want to try the bochs debugger and request the GDT and IDT info immediately before executing the int 10.
Cant do that yet. I can return after invoking the BIOS handler routine, but cannot IRET from the v86 monitor as it causes a GPF again. Hence, I cannot leave the GPF / v86 monitor.
I was referring to the state when the next instruction in the stream would be int 0x10 (without regard as to what it does when it tries to execute it)

In fact, try single-stepping through the execution using bochs to trace what actually happens.

The GPF exception is classified as a fault - that means the return address points to the instruction causing the fault. If you try to IRET you'll be back to square one and you get the same GPF again. Instead you have to increment the return address manually. The GPF exception also has an error code pushed which you'll need removed.

Also, you have IOPL set to 3 - that means unprivileged code can do pretty much whatever it likes, including enabling and disabling interrupts, uncontrolled port IO and a lot of other potential badnesses. Consider setting it to 0 to eliminate that possibility.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

In fact, try single-stepping through the execution using bochs to trace what actually happens.
I've done that so many times prior to, and after posting this thread :)
The GPF exception is classified as a fault - that means the return address points to the instruction causing the fault. If you try to IRET you'll be back to square one and you get the same GPF again.
I know about that. Except thats not what is happening.

Because the GPF handler itself is - for some still unkown reason - being called and executed at Ring 3, it cannot execute a IRET instruction at all, as it is a privledge instruction. Hence, it immeditaley goes back to the beginning of the GPF handler. - It never returns because it cannot execute IRET in ring 3.

I verifed this with single-stepping.

Thanks for your reply.
User avatar
Combuster
Member
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:

Post by Combuster »

Could you post a link to a floppy image and/or source tarball? (and the address where the V8086 task is actually loaded to quickly get to the checks I want to do)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Post by neon »

Sorry I dont have access to it right now :(

I *think* I may know the problem though. I am currently verifing some things from the intel manuals to be sure.

I am going to also set the IOPL to 0.

Ill keep you all updated if I find anything :)
Post Reply