00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <const.h>
00012 #include <string.h>
00013
00014 #include <arch/i386.h>
00015 #include <arch/interrupt.h>
00016 #include <arch/mem.h>
00017 #include <arch/paging.h>
00018
00019 #include <kernel/console.h>
00020 #include <kernel/kmalloc.h>
00021 #include <kernel/queue.h>
00022 #include <kernel/kernel_map.h>
00023 #include <kernel/task.h>
00024
00025 #include <arch/v86.h>
00026
00027
00028
00029 extern int new_pid();
00030 extern queue_t *ready_queue;
00031 extern task_t *curr_task;
00032
00033
00034 #define V86_TASK_STACK_START 0x90000
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 task_t *create_v86_process(void *address, void *buffer, size_t size, char *v86name)
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
00063 new_task = kmemalign(PAGE_SIZE, sizeof(task_t));
00064 if (!new_task)
00065 {
00066
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
00077 pl0_stack = kmalloc(STACK_SIZE);
00078 if (!pl0_stack)
00079 {
00080
00081 set_color(LIGHT_RED);
00082 kprintf("\n\rOut of virtual memory!!! Cannot create v86task [%s].", v86name);
00083 set_color(DEFAULT_COLOR);
00084
00085 kfree((void *)new_task);
00086
00087 sched_leave_critical_region();
00088 return(NULL);
00089 }
00090
00091 memset(pl0_stack, 0, STACK_SIZE);
00092
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
00097 new_task->tss_sel = setup_GDT_entry(sizeof(tss_IO_t), (dword)&(new_task->tss), TSS_SEG, 0);
00098
00099
00100 PDBR = (dword *)get_temp_page();
00101 if ( PDBR == NULL )
00102 {
00103
00104 set_color(LIGHT_RED);
00105 kprintf("\n\rOut of physical memory!!! Cannot create v86task [%s].", v86name);
00106 set_color(DEFAULT_COLOR);
00107
00108 kfree((void *)(new_task->pl0_stack-STACK_SIZE));
00109 kfree((void *)new_task);
00110
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
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
00124 PDBR[1023] = PDBR_frame | P_PRESENT | P_WRITE;
00125
00126
00127 free_temp_page(PDBR, FALSE);
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 __asm__ __volatile__ ("movl %%cr3, %0" : "=r"(cr3) : );
00141 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(PDBR_frame));
00142
00143
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
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
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
00154
00155
00156
00157
00158
00159
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
00164 if (address != buffer)
00165 {
00166 memcpy(address, buffer, size);
00167 }
00168
00169
00170 __asm__ __volatile__ ("movl %0, %%cr3" : : "r"(cr3));
00171
00172
00173 new_task->tss.cr3 = PDBR_frame;
00174
00175
00176 new_task->tss.io_map_addr = sizeof(tss_t);
00177
00178
00179
00180 new_task->tss.ds = new_task->tss.es =
00181 new_task->tss.fs = new_task->tss.gs = SEGMENT((dword)address);
00182
00183
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
00189
00190 new_task->tss.eflags = EFLAGS_IOPL0 | EFLAGS_VM | EFLAGS_IF | 0x02;
00191
00192
00193
00194 new_task->tss.ldtr = 0;
00195
00196
00197
00198 new_task->tss.trace = 0;
00199
00200
00201 new_task->tss.cs = SEGMENT((dword)address);
00202 new_task->tss.eip = OFFSET((dword)address);
00203
00204
00205 new_task->pid = new_pid();
00206
00207
00208
00209 strncpy(new_task->name, v86name, sizeof(new_task->name)-2);
00210
00211
00212 new_task->type = PROCESS_T;
00213
00214
00215 new_task->father = curr_task;
00216
00217
00218 new_task->state = READY;
00219 add_queue(&ready_queue, new_task);
00220
00221 sched_leave_critical_region();
00222
00223 return (new_task);
00224 }
00225
00226
00227
00228
00229
00230 void v86_monitor()
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:
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:
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:
00258 if (ip[1]==MINIRIGHI_INT)
00259
00260 auto_kill( 1 );
00261 else
00262 {
00263 if (ip[1]==DOS_INT)
00264 {
00265
00266
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:
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:
00291 context->eflags = (context->eflags & (~EFLAGS_IF));
00292 context->ip = (word)(context->ip + 1);
00293 return;
00294
00295 case 0xFB:
00296 context->eflags = (context->eflags | EFLAGS_IF);
00297 context->ip = (word)(context->ip + 1);
00298 return;
00299
00300 case 0xF4:
00301
00302
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
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 }