Virtual 8086 - GPF too early
Virtual 8086 - GPF too early
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)
Why is this? Does the task have to be < 1 mb? (thinking of overflow in IP)
- Pype.Clicker
- 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
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.
Re:Virtual 8086 - GPF too early
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
Re:Virtual 8086 - GPF too early
I'm looking at some code for v86, trying to make it work for me. But it doesn't at all.
Segment is like 0xB6 and offset is 0x0.
Sometimes I get BOUND range exceeded exception, and sometimes bochs quits with the message "rip > cs".
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);
Sometimes I get BOUND range exceeded exception, and sometimes bochs quits with the message "rip > cs".
- Pype.Clicker
- 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
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...
Re:Virtual 8086 - GPF too early
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.
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.
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);
}
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.
- Pype.Clicker
- 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
"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 ...
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 ...
Re:Virtual 8086 - GPF too early
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*
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*
- Pype.Clicker
- 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
which is not, iirc, as easy asBI 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.
Code: Select all
pushfd
pop eax
or eax, VM_BIT
push eax
popfd
Re:Virtual 8086 - GPF too early
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.
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.