Virtual 8086 Mode
Posted: Tue Apr 10, 2007 9:19 am
This is my code for the creation of a task in virtual 8086 mode. Is it good?
kernel_stack is the kernel stack, esp0 in the TSS
user_stack is the user stack
esp is the stack
ss0 in the TSS is the kernel data selector
kernel_stack is the kernel stack, esp0 in the TSS
user_stack is the user stack
esp is the stack
ss0 in the TSS is the kernel data selector
Code: Select all
//Interrupt enable flag in EFLAGS register.
#define EFLAGS_IF 0x200
//I/O privilege level 0.
//Only the kernel can perform I/O operations.
#define EFLAGS_IOPL0 0x0000
#define EFLAGS_VM 0x20000
//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) )
//Make a linear address from a segment:offset address.
#define LINEAR(seg, off) ( (unsigned int)(((unsigned short)(seg) << 4) + (unsigned short)(off)) )
void new_v86_task(void *entry, void *stack_top, const char *nome)
{
asm("cli");
int i;
unsigned int *stacksetup;
struct task_t *newtask;
newtask = (struct task_t*)kmalloc(sizeof(struct task_t));
newtask->kernel_stack = (unsigned int*)kmalloc(4096);
newtask->init_kstack = newtask->kernel_stack;
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)end_task;
*stacksetup-- = SEGMENT((unsigned int)stack_top-sizeof(unsigned int)); //SS3
*stacksetup-- = OFFSET((unsigned int)(stack_top-sizeof(unsigned int))); //ESP3
*stacksetup-- = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; //EFlags
*stacksetup-- = SEGMENT((unsigned int)entry); //CS
*stacksetup-- = OFFSET((unsigned int)entry); //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-- = SEGMENT((unsigned int)entry); //DS
*stacksetup-- = SEGMENT((unsigned int)entry); //ES
*stacksetup-- = SEGMENT((unsigned int)entry); //FS
*stacksetup = SEGMENT((unsigned int)entry); //GS
newtask->esp = (unsigned int)stacksetup;
newtask->privilege = USER;
...