Enter to V86, perform BIOS Interrupt and return back to PM

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.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Enter to V86, perform BIOS Interrupt and return back to PM

Post by MrLolthe1st »

So, i'm have a, may be, very dumb question: how to enter to V86, perform BIOS Interrupt and return back to PM?
I'm wrote that code(In kernel) to enter to a v86:

Code: Select all

		mov $_lo1, %ebx #Save return address to ebx
		pushf
		orl  $131072, (%esp)#Turn on VM flag
		movl	$0x0, %eax 
		pushl	%eax #Segment 0	
		mov		$0x8400, %eax #Offset 0x8400
		pushl	%eax 
		mov 24(%esp), %eax #Some arg to eax
		iret				#Go to V86
		_lo1:				
And now i'm trying to run that code(it executes, but on int 10h it fails)

Code: Select all

mov dx,0
mov ss,dx
mov sp, 0x8C00
mov dx, ax
mov ax, 0x4f02
int 10h ;Crashes here
;How to retrun back?
Thanks,
Aleksandr
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

Some hits:
Try to jmp $ before int 0x10 in QEMU and see if you are really running v86 mode and if your registers are all correct using builtin monitor.
Check if your IVT is mapped to virtual address 0 and is not trashed (happens easily if you have some uncaught NULL pointer dereferences).
The way I return from v86 mode is I use int 0xFE instruction and catch it in the v86 monitor as a special interrupt.

I assume you have proper v86 monitor (the emulation layer for privileged 16 bit instructions) in place.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

Yes, i'm checked with bochs, i'm working in v86, and registers have right values. But, i'm never corrupt the IVT, because i'm run that code from kernel start(for easily debug).
<bochs:9> xp /1w 0x40
[bochs]:
0x0000000000000040 <bogus+ 0>: 0xc0000152
<bochs:10> s
Next at t=1597216600
(0) [0x000000008403] 0000:8403 (unk. ctxt): mov ss, bx ; 8ed3
<bochs:11> s
Next at t=1597216601
(0) [0x000000008405] 0000:8405 (unk. ctxt): mov sp, 0x8c00 ; bc008c
<bochs:12> s
Next at t=1597216602
(0) [0x000000008408] 0000:8408 (unk. ctxt): mov dx, ax ; 89c2
<bochs:13> s
Next at t=1597216603
(0) [0x00000000840a] 0000:840a (unk. ctxt): mov ax, 0x4f02 ; b8024f
<bochs:14> s
Next at t=1597216604
(0) [0x00000000840d] 0000:840d (unk. ctxt): int 0x10 ; cd10
<bochs:15> s
01597216604e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
01597216604e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
01597216604i[CPU0 ] CPU is in v8086 mode (active)
01597216604i[CPU0 ] CS.mode = 16 bit
01597216604i[CPU0 ] SS.mode = 16 bit
01597216604i[CPU0 ] EFER = 0x00000000
01597216604i[CPU0 ] | EAX=00004f02 EBX=00000000 ECX=00000000 EDX=0000010f
...
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

01597216604e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
01597216604e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
Looks like your v86 int instruction emulation is not in place or is not working. You get general protection fault at int 0x10 instruction (which is correct). And after that you get double fault. And then, I assume, triple fault (which means machine reset).
The way v86 monitor works is that you are supposed to catch that first GPF and emulate that instruction.

EDIT:
Here you can see how you can do that. That's some standalone code I've sent to another user as an EXAMPLE (he didn't understand that piece I think ;) and just blindly copypasted all of it into his kernel).
EDIT2:
Code in previous link had a nasty bug.
download/file.php?id=3874
Last edited by pvc on Mon Dec 24, 2018 11:10 am, edited 1 time in total.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

What is a monitor? I've saw that: https://wiki.osdev.org/Virtual_Monitor, but understood nothing.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

V86 Monitor is a piece of code that emulates 16 bit, otherwise privileged, instructions.
For example:
You can't execute hlt instruction in 32 bit userland protected mode. It will generate GPF. But let's say you want hlt instruction to be available in userland so you catch an exception it generates and subtitute it with, let's say, current thread suspend code. The same applies to V86 since it's just 16 bit userland code. If you want to use int instruction you have to catch GPF it generates and emulate that instruction in your kernel.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

But for what i'm need to emulate it? I'm want to execute BIOS interrupt. How i can catch GPFs?
quirck
Member
Member
Posts: 42
Joined: Sun Nov 23, 2008 5:56 am
Location: Russia, Saint-Petersburg

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by quirck »

Emulation is needed so that the real-mode code is executed in controlled manner, so that you can decide, for example, whether you allow it to perform i/o, etc.

If you don't want to bother with v8086 monitor, maybe just returning to real mode, calling the int, and returning back to pm would be easier?
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

quirck, скинь ВК/телегу :)
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

GPFs are just interrupts. Interrupts with number 13 to be exact.
About instruction emulation.
Some instructions can be considered unsafe. Some may lead to inconsistency in hardware (like in and out). These have to be emulated. Imagine that your multitasking OS is waiting for an interrupt from HDD and some other thread executes cli instruction and crashes just because. What will happen?
.
.
.
HDD driver will never receive that interrupt. And the system will freeze.
That's why some instructions need to be emulated.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

So, i'm set handler for 13th interrupt, what next? What that handler must do(i'm won't use v86 for other tasks, only for change videomode)?
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

Good. Then you need to know what instruction caused the exception. For that you need to get faulting instruction EIP. From that you can get the instruction which caused the fault.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

But when fault throws, what i'm need to do, in example, on interrupt?
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by pvc »

That's really OS dependent thing.

in my example the code for instruction 'int n' was:

Code: Select all

else if(opcode == 0xCD)
    { // int n
        byte intNo = peekb(state->CS, ++state->IP);
        if(intNo == 0xFE)
        { // special interrupt
            //memcpy(state, &vm86CPUState, sizeof(MachineState));
            size_t size = sizeof(MachineState);
            byte *dst = (byte *)state;
            byte *src = (byte *)&vm86CPUState;
            while(size--) *dst++ = *src++;
            return true;
        }
        pushw(state, state->FLAGS);
        state->EFLAGS &= ~((1 << 8) | (1 << 9) | (1 << 18));
        pushw(state, state->CS);
        pushw(state, ++state->IP);
        state->CS = peekw(0x0000, 4 * intNo + 2);
        state->IP = peekw(0x0000, 4 * intNo);
        return true;
    }
I have no idea how your interrupt stack frame looks like. That's one thing YOU have to resolve.
MrLolthe1st
Member
Member
Posts: 90
Joined: Sat Sep 24, 2016 12:06 am

Re: Enter to V86, perform BIOS Interrupt and return back to

Post by MrLolthe1st »

Ok. So, i've set GPF handler, but when i'm trying to call 'int 10h', GPF hadn't executed, qemu says:
(qemu) qemu: fatal: invalid tss type
Post Reply