Page 1 of 2
Setting a stack for a V86 task
Posted: Mon Jul 16, 2007 7:45 am
by Jeko
I must set a stack for a V86 task.
For normal tasks I have this code:
Code: Select all
newtask->kernel_stack = (unsigned int*)kmalloc(4096);
newtask->kernel_stack += 4096;
stacksetup = newtask->kernel_stack;
*stacksetup--;
newtask->user_stack = (unsigned int*)kmalloc(4096);
newtask->user_stack += 4096;
*newtask->user_stack--;
*newtask->user_stack = (unsigned int)end_task2;
*stacksetup-- = USER_DATA_SEL | 3; //SS3
*stacksetup-- = (unsigned int)newtask->user_stack; //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_IF | 0x02; //EFlags
*stacksetup-- = USER_CODE_SEL | 3; //CS
*stacksetup-- = (unsigned int)func; //EIP
*stacksetup-- = 0; //EAX
*stacksetup-- = 0; //ECX
*stacksetup-- = 0; //EDX
*stacksetup-- = 0; //EBX
*stacksetup-- = 0; //ESP
*stacksetup-- = 0; //EBP
*stacksetup-- = 0; //ESI
*stacksetup-- = 0; //EDI
*stacksetup-- = USER_DATA_SEL | 3; //DS
*stacksetup-- = USER_DATA_SEL | 3; //ES
*stacksetup-- = USER_DATA_SEL | 3; //FS
*stacksetup = USER_DATA_SEL | 3; //GS
newtask->esp = (unsigned int)stacksetup;
How can I do for V86 tasks?
Posted: Mon Jul 16, 2007 8:20 pm
by frank
I don't know exactly how multitasking code is set up so the only thing that I can do is to tell you the layout of the stack the cpu expects when you are issuing that iret to get into VM86 mode. NOTE: All values are DWORD aligned.
Code: Select all
Virtual mode GS
Virtual mode FS
Virtual mode DS
Virtual mode ES
Virtual mode SS
Virtual mode ESP
Virtual mode EFLAGS
Virtual mode CS
Virtual mode EIP <- Kernel mode esp should point to this value
All of the virtual mode values need to be valid real mode values. Don't try using segment descriptors for the segment registers. EIP and ESP also need to be less than equal to 0xFFFF.
Posted: Tue Jul 17, 2007 2:16 am
by Jeko
I wrote this code, but this doesn't work. The PC doesn't go to virtual mode. When a GPF occur, eflags value is 0x10002. The VM86 eflag isn't set.
Code: Select all
//Get the segment from the far pointer \p fp.
#define FP_SEG(fp) (((unsigned int)fp) >> 16)
//Get the offset from the far pointer \p fp.
#define FP_OFF(fp) (((unsigned int)fp) & 0xffff)
newtask->kernel_stack = (unsigned int*)kmalloc(4096);
newtask->kernel_stack += 4096;
stacksetup = newtask->kernel_stack;
*stacksetup--;
newtask->user_stack = (unsigned int*)kmalloc(4096);
newtask->init_ustack = newtask->user_stack;
newtask->user_stack += 4096;
*newtask->user_stack--;
*newtask->user_stack = (unsigned int)endv;
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)newtask->user_stack); //SS3
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)newtask->user_stack); //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; //EFlags = 0x20202
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //CS
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)func); //EIP
*stacksetup-- = 0; //EDI
*stacksetup-- = 0; //ESI
*stacksetup-- = 0; //EBP
*stacksetup-- = 0; //Offset
*stacksetup-- = 0; //EBX
*stacksetup-- = 0; //EDX
*stacksetup-- = 0; //ECX
*stacksetup-- = 0; //EAX
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //DS
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //ES
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //FS
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //GS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_DS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_ES
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_FS
*stacksetup = (unsigned short)FP_SEG((unsigned int)func); //V_GS
newtask->esp = (unsigned int)stacksetup;
Where is the error?
Posted: Tue Jul 17, 2007 3:35 am
by pcmattman
Try:
Code: Select all
//Get the segment from the far pointer \p fp.
#define FP_SEG(fp) (((unsigned int)fp) >> 16)
//Get the offset from the far pointer \p fp.
#define FP_OFF(fp) (((unsigned int)fp) & 0xffff)
newtask->kernel_stack = (unsigned int*)kmalloc(4096);
newtask->kernel_stack += 4096;
stacksetup = newtask->kernel_stack;
*stacksetup--;
newtask->user_stack = (unsigned int*)kmalloc(4096);
newtask->init_ustack = newtask->user_stack;
newtask->user_stack += 4096;
*newtask->user_stack--;
*newtask->user_stack = (unsigned int)endv;
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_DS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_ES
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_FS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_GS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)newtask->user_stack); //SS3
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)newtask->user_stack); //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; //EFlags = 0x20202
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //CS
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)func); //EIP
*stacksetup-- = 0; //EDI
*stacksetup-- = 0; //ESI
*stacksetup-- = 0; //EBP
*stacksetup-- = 0; //Offset
*stacksetup-- = 0; //EBX
*stacksetup-- = 0; //EDX
*stacksetup-- = 0; //ECX
*stacksetup-- = 0; //EAX
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //DS
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //ES
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //FS
*stacksetup = (unsigned short)USER_DATA_SEL | 3; //GS
newtask->esp = (unsigned int)stacksetup;
Good luck
Re: Setting a stack for a V86 task
Posted: Tue Jul 17, 2007 4:43 am
by TomTom
MarkOS wrote:
Code: Select all
*stacksetup--;
...
*newtask->user_stack--;
I hope you know that these lines of code are equivalent to:
Code: Select all
stacksetup--;
...
newtask->user_stack--;
Posted: Tue Jul 17, 2007 6:27 am
by Jeko
pcmattman wrote:Try:
Code: Select all
//Get the segment from the far pointer \p fp.
#define FP_SEG(fp) (((unsigned int)fp) >> 16)
//Get the offset from the far pointer \p fp.
#define FP_OFF(fp) (((unsigned int)fp) & 0xffff)
newtask->kernel_stack = (unsigned int*)kmalloc(4096);
newtask->kernel_stack += 4096;
stacksetup = newtask->kernel_stack;
*stacksetup--;
newtask->user_stack = (unsigned int*)kmalloc(4096);
newtask->init_ustack = newtask->user_stack;
newtask->user_stack += 4096;
*newtask->user_stack--;
*newtask->user_stack = (unsigned int)endv;
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_DS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_ES
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_FS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //V_GS
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)newtask->user_stack); //SS3
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)newtask->user_stack); //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; //EFlags = 0x20202
*stacksetup-- = (unsigned short)FP_SEG((unsigned int)func); //CS
*stacksetup-- = (unsigned short)FP_OFF((unsigned int)func); //EIP
*stacksetup-- = 0; //EDI
*stacksetup-- = 0; //ESI
*stacksetup-- = 0; //EBP
*stacksetup-- = 0; //Offset
*stacksetup-- = 0; //EBX
*stacksetup-- = 0; //EDX
*stacksetup-- = 0; //ECX
*stacksetup-- = 0; //EAX
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //DS
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //ES
*stacksetup-- = (unsigned short)USER_DATA_SEL | 3; //FS
*stacksetup = (unsigned short)USER_DATA_SEL | 3; //GS
newtask->esp = (unsigned int)stacksetup;
This code doesn't work. Bochs give me these messages:
[CPU0 ] LOCK prefix unallowed (op1=0x53, attr=0x0, mod=0x0, nnn=0)
Many: [CPU0 ] seg[DS]->selector.value = 0000
And after:
[XGUI ] >>PANIC<< POWER button turned off.
[SYS ] Last time is 1184672850
[XGUI ] Exit.
[CPU0 ] protected mode
[CPU0 ] CS.d_b = 32 bit
[CPU0 ] SS.d_b = 32 bit
[CPU0 ] | EAX=000f0320 EBX=00000023 ECX=00000023 EDX=00000023
[CPU0 ] | ESP=000f0310 EBP=00000023 ESI=00000023 EDI=00000023
[CPU0 ] | IOPL=0 NV UP DI PL NZ NA PO NC
[CPU0 ] | SEG selector base limit G D
[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
[CPU0 ] | DS:0000( 0004| 0| 3) 00000030 0000ffff 0 0
[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
[CPU0 ] | ES:0000( 0004| 0| 3) 00000030 0000ffff 0 0
[CPU0 ] | FS:0000( 0004| 0| 3) 00000030 0000ffff 0 0
[CPU0 ] | GS:0000( 0004| 0| 3) 00000030 0000ffff 0 0
[CPU0 ] | EIP=0001bc1f (0001bc1f)
[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
[CPU0 ] | CR3=0x00000000 CR4=0x00000200
Then the stack isn't good.
Another thing:
#define FP_SEG(fp) (((unsigned int)fp) >> 16)
may be:
#define FP_SEG(fp) ((unsigned short)(((unsigned int)(linear) & 0xFFFF0000) >> 4))
For TomTom:
that has nothing to do with it
Posted: Tue Jul 17, 2007 8:56 am
by frank
Well lock prefix unallowed is a good sign you are jumping to bogus memory. Keep in mind that VM86 mode can only execute code that is below the 1mb mark.
The new version of FP_SEG, the one from the last post, is the correct one.
Posted: Wed Jul 18, 2007 11:53 am
by Jeko
frank wrote:Well lock prefix unallowed is a good sign you are jumping to bogus memory. Keep in mind that VM86 mode can only execute code that is below the 1mb mark.
The new version of FP_SEG, the one from the last post, is the correct one.
the code is below the 1mb mark.
with the new version of FP_SEG, the error still remains.
I'm sure that the error is in the setting of the stack. But which is the error?
Posted: Wed Jul 18, 2007 12:21 pm
by frank
Are you still getting a lock prefix unallowed error or is it simply a general protection fault? A general protection fault is used to tell the kernel that the vm86 task is executing code that needs to be emulated. Instructions such as out in iret int pushf and popf are all supposed to be handled in the general protection fault handler.
EDIT: Can you post the code that is supposed to be executed in VM86 mode?
Posted: Thu Jul 19, 2007 8:19 am
by Jeko
frank wrote:Are you still getting a lock prefix unallowed error or is it simply a general protection fault? A general protection fault is used to tell the kernel that the vm86 task is executing code that needs to be emulated. Instructions such as out in iret int pushf and popf are all supposed to be handled in the general protection fault handler.
EDIT: Can you post the code that is supposed to be executed in VM86 mode?
It's still a lock prefix unallowed
Posted: Fri Jul 20, 2007 4:02 am
by Jeko
This is the 16 bit code:
Code: Select all
[bits 16]
[section .text]
[global _i386PowerOff]
_i386PowerOff:
mov ax,5304h ; disconnect interface
sub bx,bx
int 15h
mov ax,5301h ; connect real mode interface
sub bx,bx
int 15h
mov ax,5308h ; enable power management
mov bx,1
mov cx,bx
int 15h
mov ax,530Dh ; enable device power management
mov bx,1
mov cx,bx
int 15h
mov ax,530Fh ; engage power management
mov bx,1
mov cx,bx
int 15h
mov ax,530Eh ; driver version
sub bx,bx
mov cx,102h
int 15h
mov ax,5307h ; set power state
mov bx,1
mov cx,3
int 15h
int 80h
[global _i386PowerOffEnd]
_i386PowerOffEnd:
These are the bytes:
Code: Select all
unsigned char poweroff[67] = {
0xB8,0x04,0x53,0x29,0xDB,0xCD,0x15,0xB8,0x01,0x53,
0x29,0xDB,0xCD,0x15,0xB8,0x08,0x53,0xBB,0x01,0x00,
0x89,0xD9,0xCD,0x15,0xB8,0x0D,0x53,0xBB,0x01,0x00,
0x89,0xD9,0xCD,0x15,0xB8,0x0F,0x53,0xBB,0x01,0x00,
0x89,0xD9,0xCD,0x15,0xB8,0x0E,0x53,0x29,0xDB,0xB9,
0x02,0x01,0xCD,0x15,0xB8,0x07,0x53,0xBB,0x01,0x00,
0xB9,0x03,0x00,0xCD,0x15,0xCD,0x80 };
Posted: Fri Jul 20, 2007 6:06 am
by frank
Maybe you should try a simple jmp $ for now to eliminate the possibility that something in the VM86 code is causing it.
Posted: Sat Jul 21, 2007 10:13 am
by Jeko
I changed my code. Now it is:
Code: Select all
//Extract the segment part of a linear address.
#define SEGMENT(linear) ((unsigned short)(((unsigned int)(linear) & 0xFFFF0000) >> 4))
//Extract the offset part of a linear address.
#define OFFSET(linear) ((unsigned short)((unsigned int)(linear) & 0xFFFF))
newtask->kernel_stack = (unsigned int*)0x500;
newtask->init_kstack = newtask->kernel_stack;
newtask->kernel_stack += 1024; //1024 ints are 4096 bytes.
stacksetup = newtask->kernel_stack;
*stacksetup--;
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)func); //V_DS
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)func); //V_ES
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)func); //V_FS
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)func); //V_GS
newtask->user_stack = (unsigned int*)0x1500;
newtask->init_ustack = newtask->user_stack;
//Forse devo togliere la linea seguente
newtask->user_stack += 1024;
*newtask->user_stack--;
*newtask->user_stack = (unsigned int)endv;
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)newtask->user_stack); //SS3
*stacksetup-- = (unsigned short)OFFSET((unsigned int)newtask->user_stack); //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; //EFlags
*stacksetup-- = (unsigned short)SEGMENT((unsigned int)func); //CS
*stacksetup-- = (unsigned short)OFFSET((unsigned int)func); //EIP
*stacksetup-- = 0; //EDI
*stacksetup-- = 0; //ESI
*stacksetup-- = 0; //EBP
*stacksetup-- = 0; //Offset
*stacksetup-- = 0; //EBX
*stacksetup-- = 0; //EDX
*stacksetup-- = 0; //ECX
*stacksetup-- = 0; //EAX
*stacksetup-- = USER_DATA_SEL | 3; //DS
*stacksetup-- = USER_DATA_SEL | 3; //ES
*stacksetup-- = USER_DATA_SEL | 3; //FS
*stacksetup = USER_DATA_SEL | 3; //GS
newtask->esp = (unsigned int)stacksetup;
newtask->privilege = USER_PRIVILEGE;
This is the handler for irqs and exceptions:
Code: Select all
pusha
pushl %ds
pushl %es
pushl %fs
pushl %gs
movl %esp, %eax
pushl %eax
call irqortrap
popl %eax
mov %eax, %esp
popl %gs
popl %fs
popl %es
popl %ds
popa
iret
This code is used in task scheduling:
Code: Select all
if(cur_task->privilege == USER_PRIVILEGE)
scheduler_tss->esp0 = (unsigned int)cur_task->kernel_stack;
scheduler_tss->ss0 = KERNEL_DATA_SEL;
*stack = cur_task->esp;
This is the tss setting code (I've an only TSS):
Code: Select all
tss = (struct tss_t*)kmalloc(sizeof(struct tss_t));
memset((void*)scheduler_tss, 0x00, sizeof(struct tss_t));
gdt_add_entry(KERNEL_TSS_SEL, (unsigned int)tss, sizeof(struct tss_t)-1, 0x89, 0x00);
ltr(KERNEL_TSS_SEL);
tss->ss0 = KERNEL_DATA_SEL;
tss->io_map_base = 104;
int i;
for(i=0; i<(8192/32);i++)
tss->bitmap_io_perm[i] = 0xFFFFFFFF;
The lock prefix unallowed there is no more.
Now bochs give me only this error:
Many: [CPU0 ] seg[DS]->selector.value = 0000
If the code is only "jmp $", bochs give me these errors:
Many: [CPU0 ] seg[DS]->selector.value = 0000
[CPU0 ] can_push(): expand-up: esp < N
[CPU0 ] PUSHAD(): stack doesn't have enough room!
[CPU0 ] can_push(): expand-up: esp < N
[CPU0 ] can_push(): expand-up: esp < N
[CPU0 ] exception(): 3rd (12) exception with no resolution, shutdown status is 00h, resetting
Posted: Tue Jul 24, 2007 4:34 am
by Jeko
I'm very confused!
I can''t find any error!
Where is it?
Posted: Tue Jul 24, 2007 5:38 am
by digo_rp
process->kstack = (dword)&process->pl0_stacK+stack_size;
p = (dword)0x1fff8;
*--p = r->gs; /* gs */
*--p = r->fs; /* fs */
*--p = r->ds; /* ds */
*--p = r->es; /* es */
*--p = r->cs; /* ss */
*--p = 0xfff8; /* esp */
*--p = 0x20000L; /* eflags */
*--p = r->cs; /* cs */
*--p = r->eip; /* eip */
*--p = r->eax; /* eax */
*--p = r->ecx; /* ecx */
*--p = r->edx; /* edx */
*--p = r->ebx; /* ebx */
*--p = 0; /* nullesp*/
*--p = r->ebp; /* ebp */
*--p = r->esi; /* esi */
*--p = r->edi; /* edi */
*--p = 0x10; /* gs */
*--p = 0x10; /* fs */
*--p = 0x10; /* es */
*--p = 0x10; /* ds */
process->ustack = (dword)p;
_irq00:
pusha
push ds
push es
push fs
push gs
mov eax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
push esp
mov eax, _TaskSwitch
call eax
add esp, 4
mov esp, eax
mov eax, cr0
or eax, 0x8 ; Set TS flag to use x87.fxsave with
mov cr0, eax ; device not available
pop gs
pop fs
pop es
pop ds
mov al, 0x20
out 0x20, al
popa
iret