Setting a stack for a V86 task

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.
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Setting a stack for a V86 task

Post 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?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post 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.
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post 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
TomTom
Posts: 23
Joined: Tue May 01, 2007 2:03 am
Location: USA

Re: Setting a stack for a V86 task

Post 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--;
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post 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.
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post 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?
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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 };
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Maybe you should try a simple jmp $ for now to eliminate the possibility that something in the VM86 code is causing it.
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post 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
User avatar
Jeko
Member
Member
Posts: 500
Joined: Fri Mar 17, 2006 12:00 am
Location: Napoli, Italy

Post by Jeko »

I'm very confused!
I can''t find any error!

Where is it?
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Post 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
Post Reply