Virtual 8086 - GPF too early

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
mr. x2

Virtual 8086 - GPF too early

Post by mr. x2 »

I'm trying to setup a v86 task, but I have a problem: I get a general protection fault too early. I get it even without doing any priviledged tasks like int, like when i "mov ax, 0xBA".
Why is this? Does the task have to be < 1 mb? (thinking of overflow in IP)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Virtual 8086 - GPF too early

Post by Pype.Clicker »

a V86 task will indeed require your eIP and eSP pointers to be shrinked on 16 bits... segments will be used as in realmode, so don't expect any base in GDT to affect the 1MB extreme barrier of V86.
Tim

Re:Virtual 8086 - GPF too early

Post by Tim »

As Pype says, all protected-mode segmentation is bypassed in V86 mode. So:
  • You can only use memory in the bottom 1MB of the address space
  • All code runs in ring 3, so if you're using paging, make sure the bottom 1MB is accessible from user mode
See here for more details.
mr. x2

Re:Virtual 8086 - GPF too early

Post by mr. x2 »

I'm looking at some code for v86, trying to make it work for me. But it doesn't at all.

Code: Select all

void InitTask(uint8 _num, void *_task) {
        uint32 iESP = 0;
        asm("mov %%esp, %0":"=r"(iESP));

        uint16 iSegment = (uint32)_task >> 4;//FP_SEG(0x10000);//(uint32)_task >> 4;
        uint16 iOffset = (uint32)_task & 0xF; //FP_OFF(0x10000); //;(uint32)_task & 0xF;

        kprintf("SEG: 0x%X OFF: 0x%X\n", iSegment, iOffset);
        kprintf("PAGE OFFSET: 0x%X\n", (uint32)_task - (uint32)_task & 0xFFFFF000);

        g_Tasks[_num].backlink = 0;
        g_Tasks[_num].esp0 = malloc(0x2000) + 0x2000;
        g_Tasks[_num].ss0 = 0x10;
        g_Tasks[_num].esp1 = 0x0;
        g_Tasks[_num].ss1 = 0x0;
        g_Tasks[_num].esp2 = 0x0;
        g_Tasks[_num].ss2 = 0x0;
        g_Tasks[_num].cr3 = palloc();
        g_Tasks[_num].eip = iOffset;
        g_Tasks[_num].eflags = 2|EFLAGS_V86;
        g_Tasks[_num].eax = 0x0;
        g_Tasks[_num].ebx = 0x0;
        g_Tasks[_num].ecx = 0x0;
        g_Tasks[_num].edx = 0x0;
        g_Tasks[_num].esp = 0x1000;
        g_Tasks[_num].ebp = 0x1000;
        g_Tasks[_num].cs = iSegment; 
        g_Tasks[_num].ss = 0x1000;
        g_Tasks[_num].iomapbase = sizeof(tss_seg)-8192;
        InitializePaging(g_Tasks[_num].cr3);
        //vmmMapPage(g_Tasks[_num].cr3, 0x10000, (uint32)_task & 0xFFFFF000);

Segment is like 0xB6 and offset is 0x0.
Sometimes I get BOUND range exceeded exception, and sometimes bochs quits with the message "rip > cs".
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Virtual 8086 - GPF too early

Post by Pype.Clicker »

and what do you have at 0xb60 for code ? if only zeroes stands there, IP will increment until it eventually breaks the 64K segment limit...
mr. x2

Re:Virtual 8086 - GPF too early

Post by mr. x2 »

Oh well, I can't make it work! :(
It works perfectly without the VM bit set, but when I enable it I get a GPF on a 0x53 instruction.

Code: Select all

void InitTask(uint8 _num, void *_task) {
        uint32 iESP = 0;
        asm("mov %%esp, %0":"=r"(iESP));

        g_Tasks[_num].esp = 0x90000;
        g_Tasks[_num].ss0 = 0x10;
        g_Tasks[_num].esp0 = iESP;
        g_Tasks[_num].es = 0x10;
        g_Tasks[_num].cs = 0x8;
        g_Tasks[_num].ss = 0x10;
        g_Tasks[_num].ds = 0x10;
        g_Tasks[_num].fs = 0x10;
        g_Tasks[_num].gs = 0x10;
        g_Tasks[_num].cr3 = 0x90000;
        g_Tasks[_num].eip = 0x10000;//_task;
        g_Tasks[_num].eflags = 0x0002|EFLAGS_V86;//|0x40000;
        g_Tasks[_num].trace = 0;
        g_Tasks[_num].iomapbase = sizeof(tss_seg);

        InitializePaging(0x90000);
        vmmMapPage(0x90000, 0x10000, _task);

        kprintf("TASK: 0x%X MAPPED: 0x%X\n", g_Tasks[_num].eip, PagePhysical(g_Tasks[_num].eip));
        EnablePaging(1);
}
EFLAGS_V86 is 0x20000.

I've tried to set CS to FP_SEG(_task), SS to FP_SEG(0x9000), EIP to FP_OFF(_task) etc, but it still doesn't work. :(
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Virtual 8086 - GPF too early

Post by Pype.Clicker »

"on 53 instruction" ??

you mean opcode 0x53, which is "push bp" ?

I don't remember exactly what is the best way to switch into V86 mode. I would suggest you study both Tim's tutorial and TRAN's "start32" code to see how a VM monitor can be set up.

Maybe having the tss describing a task in kernel-pmode first (which will then 'return' from a VM-called interrupt could work better than trying to have a VM state defined right in the TSS ...
BI lazy

Re:Virtual 8086 - GPF too early

Post by BI lazy »

switching to vm86-mode is done simply by putting the proper eflags value into eflags - i.e. vm86 flag is set: cpu operates in vm86 mode.

So, setting the *damn* thing up is as simple as setting up any other process, provided you have the vm86-handler at hands - for resolving the GPF's if running in vm86.

Do you have a vm86 context frame at hands? in vm86 the registers ds,es,fs,gs (or similar) are popped onto to the ring0 stack upon interruption too (be it exception be it irq), and pushed from it upon iret to any vm86 process.

to set it up: have the proper values stored in eip/cs,ring3-ss,ring3-esp. (i.e. esp converted to real mode adress. eip converted to real mode adress). They both need to reside inside the first 1 mb of memory. Do the according mapping in your page table for the vm86 process. Best is 1:1 mapping for this region (because of the IVT and the location of the bios) and careful usage of vm86 processes. Have it trap into a pagefault to do the proper process loading and setting up of the adress space. That's how I do it.

Fill in the stack frame for the vm86 process and enqueue the TCB to the CPU. If the necessary framework is already present, it works like a charm.

look at www.distantvoices.org. Download the source of blueillusion. There are some files regarding processes, interrupts and paging with english translations inside. You may take them as reference for setting up a vm86 process.

Gosh, I'm tired... *yawn*
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Virtual 8086 - GPF too early

Post by Pype.Clicker »

BI lazy wrote: switching to vm86-mode is done simply by putting the proper eflags value into eflags - i.e. vm86 flag is set: cpu operates in vm86 mode.
which is not, iirc, as easy as

Code: Select all

    pushfd
    pop eax
    or eax, VM_BIT
    push eax
    popfd
PM/VM switch may only occur when switching protection level.
BI lazy

Re:Virtual 8086 - GPF too early

Post by BI lazy »

Thanks, Pype, for pointing that one out.

putting the proper eflags values at place is usually done upon IRET, IIRC.

But as I 've said, I am a tad tired, and what one says is not always what one means ... *gnarfl*

Well ... it is always relative what one calls easy *gg* With easy in this context I've meant writing eflags at task switch.
Post Reply