Functions | |||||||||||
task_t * | create_v86_process (void *address, void *buffer, size_t size, char *v86name) | ||||||||||
Create a new virtual-8086 mode process.
| |||||||||||
void | v86_monitor () | ||||||||||
The virtual-8086 monitor. |
|
Create a new virtual-8086 mode process.
This routine initializes a new v86-task structure, copies the content of the buffer to the entry point address and then add the new task to the ready queue. Definition at line 52 of file v86.c.
00053 { 00054 extern dword K_PDBR[PAGE_SIZE/sizeof(dword)]; 00055 task_t *new_task; 00056 byte *pl0_stack; 00057 dword *PDBR; 00058 dword cr3, PDBR_frame, i; 00059 00060 sched_enter_critical_region(); 00061 00062 // --- Create the task structure --- // 00063 new_task = kmemalign(PAGE_SIZE, sizeof(task_t)); 00064 if (!new_task) 00065 { 00066 // Out of virtual memory!!! // 00067 set_color(LIGHT_RED); 00068 kprintf("\n\rOut of virtual memory!!! Cannot create v86task [%s].", v86name); 00069 set_color(DEFAULT_COLOR); 00070 00071 sched_leave_critical_region(); 00072 return(NULL); 00073 } 00074 memset(new_task, 0, sizeof(task_t)); 00075 00076 // --- Create the pl0-stack --- // 00077 pl0_stack = kmalloc(STACK_SIZE); 00078 if (!pl0_stack) 00079 { 00080 // Out of virtual memory!!! // 00081 set_color(LIGHT_RED); 00082 kprintf("\n\rOut of virtual memory!!! Cannot create v86task [%s].", v86name); 00083 set_color(DEFAULT_COLOR); 00084 // Free the previous allocated space // 00085 kfree((void *)new_task); 00086 00087 sched_leave_critical_region(); 00088 return(NULL); 00089 } 00090 // Null the stack to enforce the page mapping // 00091 memset(pl0_stack, 0, STACK_SIZE); 00092 // Setup the pl0-stack // 00093 new_task->tss.ss0 = KERNEL_STACK; 00094 new_task->tss.esp0 = new_task->pl0_stack = (dword)(pl0_stack+STACK_SIZE-sizeof(uint32_t)); 00095 00096 // --- Setup the TSS --- // 00097 new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0); 00098 00099 // --- Create the virtual space of the task ------------------- // 00100 PDBR = (dword *)get_temp_page(); 00101 if ( PDBR == NULL ) 00102 { 00103 // Out of memory!!! Free the previous allocated memory. // 00104 set_color(LIGHT_RED); 00105 kprintf("\n\rOut of physical memory!!! Cannot create v86task [%s].", v86name); 00106 set_color(DEFAULT_COLOR); 00107 // Free the previous allocated space // 00108 kfree((void *)(new_task->pl0_stack-STACK_SIZE)); 00109 kfree((void *)new_task); 00110 // Destroy the TSS // 00111 remove_GDT_entry(new_task->tss_sel); 00112 00113 sched_leave_critical_region(); 00114 return(NULL); 00115 } 00116 PDBR_frame = vir_to_phys( (dword)PDBR ); 00117 00118 // Initialize PDBR // 00119 memset(PDBR, 0, PAGE_SIZE); 00120 for (i=K_VIR_START/(PAGE_SIZE*1024); i<1024; i++) 00121 PDBR[i] = K_PDBR[i]; 00122 00123 // Map page directory into itself // 00124 PDBR[1023] = PDBR_frame | P_PRESENT | P_WRITE; 00125 00126 // Unmap the temporary page, without free the physical frame // 00127 free_temp_page(PDBR, FALSE); 00128 00129 // Temporary switch to the new address space // 00130 // // 00131 // QUESTION: cr3 is in the stack... if I switch into the new // 00132 // address space can I ever see the old cr3 value??? // 00133 // // 00134 // RE: Yes, but only if cr3 is stored into a register... // 00135 // And if the value should be stored into the stack, here we // 00136 // are at CPL0, so we're using the 0-privileged stack, so, // 00137 // since the 0-privileged stack space is shared between every // 00138 // task and also the kernel, we're ever able to see the stored // 00139 // cr3 value... // 00140 __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(cr3) : ); 00141 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR_frame)); 00142 00143 // Map the IVT (Interrupt Vector Table) // 00144 for (i=BIOS_IVT_START; i<BIOS_IVT_END; i+=PAGE_SIZE) 00145 map_page(i, i, P_PRESENT | P_WRITE | P_USER); 00146 // Map the VIDEO BUFFER // 00147 for (i=VIDEO_BUF_START; i<VIDEO_BUF_END; i+=PAGE_SIZE) 00148 map_page(i, i, P_PRESENT | P_WRITE | P_USER); 00149 // Map the BIOS ROM memory // 00150 for (i=BIOS_ROM_START; i<BIOS_ROM_END; i+=PAGE_SIZE) 00151 map_page(i, i, P_PRESENT | P_WRITE | P_USER); 00152 00153 // --- Create the user space --- // 00154 00155 // Create the stack // 00156 00157 // It is not necessary to null the stack to enforce page // 00158 // mapping, because V86-mode tasks run permanently at CPL3. // 00159 // So a stack-fault is managed like a normal page-fault. // 00160 new_task->tss.ss = SEGMENT((dword)V86_TASK_STACK_START-sizeof(uint32_t)); 00161 new_task->tss.esp = OFFSET((dword)(V86_TASK_STACK_START-sizeof(uint32_t))); 00162 00163 // Map the user code and data // 00164 if (address != buffer) 00165 { 00166 memcpy(address, buffer, size); 00167 } 00168 00169 // Restore the old address space // 00170 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(cr3)); 00171 00172 // Setup the v86 task PDBR // 00173 new_task->tss.cr3 = PDBR_frame; 00174 00175 // Setup the IO port mapping // 00176 new_task->tss.io_map_addr = sizeof(tss_t); 00177 // for (i=0; i<8192; i++) new_task->tss.io_map[i] = 0; 00178 00179 // Initialize segment registers // 00180 new_task->tss.ds = new_task->tss.es = 00181 new_task->tss.fs = new_task->tss.gs = SEGMENT((dword)address); 00182 00183 // Initialize general purpose registers // 00184 new_task->tss.eax = new_task->tss.ebx = 00185 new_task->tss.ecx = new_task->tss.edx = 00186 new_task->tss.esi = new_task->tss.edi = 0; 00187 00188 // Virtual 8086 mode task - IOPL = 0 // 00189 // IOPL < 3 => all IOPL-sensitive instructions trap to the kernel with a GPF // 00190 new_task->tss.eflags = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02; 00191 00192 // Initialize LDTR (Local Descriptor Table Register) // 00193 // No LDTs for now... 00194 new_task->tss.ldtr = 0; 00195 00196 // Initialize debug trap // 00197 // If set to 1 the processor generate a debug exception when a task switch to this task occurs... 00198 new_task->tss.trace = 0; 00199 00200 // Setup program counter // 00201 new_task->tss.cs = SEGMENT((dword)address); 00202 new_task->tss.eip = OFFSET((dword)address); 00203 00204 // --- Get a pid --- // 00205 new_task->pid = new_pid(); 00206 00207 // --- Store the name --- // 00208 // The last character must be ever '\0' (end of string) // 00209 strncpy(new_task->name, v86name, sizeof(new_task->name)-2); 00210 00211 // --- Set the type --- // 00212 new_task->type = PROCESS_T; 00213 00214 // --- Set the parent process --- // 00215 new_task->father = curr_task; 00216 00217 // --- Insert the task into the ready queue --- // 00218 new_task->state = READY; 00219 add_queue(&ready_queue, new_task); 00220 00221 sched_leave_critical_region(); 00222 00223 return (new_task); 00224 } |
|
The virtual-8086 monitor.
Definition at line 230 of file v86.c.
00231 { 00232 v86_context *context = (v86_context *)(curr_task->pl0_stack-sizeof(v86_context)); 00233 byte *ip; 00234 word *stack, *ivt; 00235 00236 ip = (byte *) LINEAR(context->cs, context->ip); 00237 stack = (word *) LINEAR(context->ss, context->sp); 00238 ivt = (word *) BIOS_IVT_START; 00239 00240 while(TRUE) 00241 { 00242 switch (ip[0]) 00243 { 00244 case 0x9C: // PUSHF // 00245 context->sp = ((context->sp & 0xFFFF) - 2) & 0xFFFF; 00246 stack--; 00247 stack[0] = (word) context->eflags; 00248 context->ip = (word)(context->ip + 1); 00249 return; 00250 00251 case 0x9D: // POPF // 00252 context->eflags = stack[0] | EFLAGS_VM; 00253 context->sp = ((context->sp & 0xFFFF) + 2) & 0xFFFF; 00254 context->ip = (word)(context->ip + 1); 00255 return; 00256 00257 case 0xCD: // INT n // 00258 if (ip[1]==MINIRIGHI_INT) 00259 // Exit to system (syscalls are reserved for 32-bit tasks!!!) // 00260 auto_kill( 1 ); 00261 else 00262 { 00263 if (ip[1]==DOS_INT) 00264 { 00265 // Emulate DOS 0x20 interrupt... not yet implemented! // 00266 // If you like to do it... here are the source... good luck! :) 00267 kprintf("\n\rV86 monitor -> INT 0x20 emulation not yet implemented @CS=%#06x,IP=%#06x", 00268 context->cs, context->ip); 00269 kprintf("\n\rKilling task: [%s] (%i)\n\r", get_pname(), get_pid()); 00270 auto_kill( 1 ); 00271 } 00272 stack -= 3; 00273 context->sp = ((context->sp & 0xFFFF) - 6) & 0xFFFF; 00274 stack[0] = (word) (context->ip + 2); 00275 stack[1] = (word) context->cs; 00276 stack[2] = (word) context->eflags; 00277 00278 context->cs = ivt[ip[1] * 2 + 1]; 00279 context->ip = ivt[ip[1] * 2]; 00280 return; 00281 } 00282 00283 case 0xCF: // IRET // 00284 context->ip = stack[0]; 00285 context->cs = stack[1]; 00286 context->eflags = stack[2] | EFLAGS_VM; 00287 context->sp = ((context->sp & 0xFFFF) + 6) & 0xFFFF; 00288 return; 00289 00290 case 0xFA: // CLI // 00291 context->eflags = (context->eflags & (~EFLAGS_IF)); 00292 context->ip = (word)(context->ip + 1); 00293 return; 00294 00295 case 0xFB: // STI // 00296 context->eflags = (context->eflags | EFLAGS_IF); 00297 context->ip = (word)(context->ip + 1); 00298 return; 00299 00300 case 0xF4: // HLT // 00301 // If interrupts are disabled the current task // 00302 // wants to disable the CPU, so kill this task! // 00303 if ((context->eflags & EFLAGS_IF) != EFLAGS_IF) 00304 { 00305 kprintf("\n\rAttempt to disable the CPU."); 00306 kprintf("\n\rKilling task: [%s] (%i)\n\r", get_pname(), get_pid()); 00307 auto_kill( 1 ); 00308 } 00309 // Wait for an interrupt // 00310 context->ip = (word)(context->ip + 1); 00311 enable(); 00312 __asm__("hlt"); 00313 return; 00314 00315 default: 00316 kprintf("\n\rV86 monitor -> %#04x Unknown instruction@CS=%#06x,IP=%#06x", 00317 ip[0], context->cs, context->ip); 00318 context->ip = (word)(context->ip + 1); 00319 kprintf("\n\rKilling task: [%s] (%i)\n\r", get_pname(), get_pid()); 00320 auto_kill( 1 ); 00321 return; 00322 } 00323 } 00324 } |