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 :D

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