kernel.c (11752B)
1 /* Copyright 1998-1999, Brian J. Swetland. All rights reserved. 2 ** Distributed under the terms of the OpenBLT License 3 */ 4 5 #include <blt/os.h> 6 #include "kernel.h" 7 #include "memory.h" 8 #include "boot.h" 9 #include "port.h" 10 11 #include <i386/io.h> 12 #include <string.h> 13 #include "resource.h" 14 #include "aspace.h" 15 #include "task.h" 16 #include "smp.h" 17 #include "team.h" 18 #include "pager.h" 19 20 void DEBUGGER(void); 21 22 void restore_idt(void); 23 void init_idt(char *idt); 24 25 void _context_switch(uint32 *old_stack, uint32 new_stack, uint32 pdbr); 26 27 aspace_t *flat = NULL; 28 boot_dir *bdir = NULL; 29 30 char *idt; 31 char *gdt; 32 char *gdt2; 33 char *toppage; 34 task_t *current; 35 task_t *kernel; 36 uint32 gdt2len; 37 uint32 entry_ebp; 38 uint32 _cr3; 39 task_t *idle_task; 40 int live_tasks = 0; 41 42 resource_t *run_queue, *timer_queue, *reaper_queue; 43 team_t *kernel_team = NULL; 44 int reaper_sem; 45 46 uint32 memsize; /* pages */ 47 uint32 memtotal; 48 49 static int uberportnum = 0, uberareanum = 0; 50 51 void destroy_kspace(void) 52 { 53 /* memory_status();*/ 54 55 asm("mov %0, %%cr3"::"r" (_cr3)); /* insure we're in kernel map */ 56 restore_idt(); 57 58 i386lgdt((uint32)gdt2,gdt2len); 59 asm ("mov %0, %%esp; ret": :"r" (entry_ebp + 4)); 60 } 61 62 void panic(char *reason) 63 { 64 kprintf(""); 65 kprintf("PANIC: %s",reason); 66 DEBUGGER(); 67 asm("hlt"); 68 } 69 70 void idler(void) 71 { 72 for(;;){ 73 asm("hlt"); 74 } 75 } 76 77 void reaper(void) 78 { 79 task_t *task; 80 81 asm("cli"); /* XXX race condition? */ 82 for(;;){ 83 sem_acquire(reaper_sem); 84 task = rsrc_dequeue(reaper_queue); 85 // kprintf("reaper reclaiming thread #%d (%s)",task->rsrc.id,task->rsrc.name); 86 task_destroy(task); 87 } 88 89 } 90 91 static aspace_t _flat; 92 static TSS *ktss; 93 94 void init_kspace(int membottom) 95 { 96 uint32 *raw; 97 98 /* there's an existing aspace at vaddr 0x803FD000 that was initialized 99 by the 2nd stage loader */ 100 raw = (uint32 *) 0x803FD000; 101 flat = &_flat; 102 flat->pdir = raw; 103 flat->ptab = &raw[1024]; 104 flat->high = &raw[2048]; 105 memtotal = memsize; 106 107 memsize -= 3; /* three pages already in use */ 108 109 memory_init(membottom, memsize); 110 111 112 toppage = (char *) kgetpages(3); /* kernel startup stack */ 113 gdt = (char *) kgetpages(1); 114 rsrc_init(kgetpages(6),4096*6); 115 116 117 kernel = (task_t *) kmalloc(task_t); 118 ktss = (TSS *) kgetpages(1); 119 kernel->flags = tKERNEL; 120 kernel->rsrc.id = 0; 121 kernel->rsrc.owner = NULL; 122 list_init(&kernel->rsrc.rights); 123 list_init(&kernel->rsrc.queue); 124 current = kernel; 125 126 init_idt(idt = kgetpages(1)); /* init the new idt, save the old */ 127 gdt2 = (void *) i386sgdt(&gdt2len); /* save the old gdt */ 128 129 i386SetSegment(gdt + SEL_KCODE, /* #01 - 32bit DPL0 CODE */ 130 0, 0xFFFFF, 131 i386rPRESENT | i386rDPL0 | i386rCODE, 132 i386g4K | i386g32BIT); 133 134 i386SetSegment(gdt + SEL_KDATA, /* #02 - 32bit DPL0 DATA */ 135 0, 0xFFFFF, 136 i386rPRESENT | i386rDPL0 | i386rDATA, 137 i386g4K | i386g32BIT); 138 139 i386SetSegment(gdt + SEL_KDATA2, /* #02 - 32bit DPL0 DATA */ 140 0, 0xFFFFF, 141 i386rPRESENT | i386rDPL0 | i386rDATA, 142 i386g4K | i386g32BIT); 143 144 i386SetSegment(gdt + SEL_UCODE, /* #03 - 32bit DPL3 CODE */ 145 0, 0xFFFFF, 146 i386rPRESENT | i386rDPL3 | i386rCODE, 147 i386g4K | i386g32BIT); 148 149 i386SetSegment(gdt + SEL_UDATA, /* #04 - 32bit DPL3 DATA */ 150 0, 0xFFFFF, 151 i386rPRESENT | i386rDPL3 | i386rDATA, 152 i386g4K | i386g32BIT); 153 154 i386SetSegment(gdt + SEL_KTSS, /* #05 - DPL0 TSS (Kernel) */ 155 (uint32) ktss, 104, 156 i386rPRESENT | i386rDPL0 | i386rTSS, 157 0); 158 159 i386lgdt((uint32) gdt, 1024/8); 160 161 asm("mov %%cr3, %0":"=r" (_cr3)); 162 163 /* setup the kernel TSS to insure that it's happy */ 164 ktss->cs = SEL_KCODE; 165 ktss->ds = ktss->es = ktss->ss = ktss->fs = ktss->gs = SEL_KDATA; 166 ktss->ldts = ktss->debugtrap = ktss->iomapbase = 0; 167 ktss->cr3 = _cr3; 168 ktss->ss0 = SEL_KDATA; 169 ktss->esp1 = ktss->esp2 = ktss->ss1 = ktss->ss2 = 0; 170 i386ltr(SEL_KTSS); 171 } 172 173 /* current is running -- we want to throw it on the run queue and 174 transfer control to the preemptee */ 175 void preempt(task_t *task, int status) 176 { 177 uint32 *savestack = &(current->esp); 178 179 /* current thread MUST be running, requeue it */ 180 if(current != idle_task) rsrc_enqueue(run_queue, current); 181 182 TCHKMAGIC(task); 183 if(task == (task_t *)tDEAD) panic("The dead have returned!"); 184 185 /* transfer control to the preemtee -- it had better not be on any queues */ 186 current = task; 187 current->status = status; 188 current->flags = tRUNNING; 189 current->scount++; 190 ktss->esp0 = current->esp0; 191 if(*savestack != current->esp){ 192 _context_switch(savestack, current->esp, current->cr3); 193 } 194 } 195 196 void swtch(void) 197 { 198 /* current == running thread */ 199 uint32 *savestack = &(current->esp); 200 201 /* fast path for the case of only one running thread */ 202 if(!run_queue->queue.count && (current->flags == tRUNNING)) return; 203 204 if(current->flags == tRUNNING) { 205 if(current != idle_task) rsrc_enqueue(run_queue, current); 206 } 207 208 /* get the next candidate */ 209 current = rsrc_dequeue(run_queue); 210 211 if(!current) { 212 if(live_tasks){ 213 current = idle_task; 214 } else { 215 kprintf(""); 216 kprintf("No runnable tasks. Exiting."); 217 destroy_kspace(); 218 } 219 } 220 221 if(current->flags == tDEAD) panic("The dead have returned!"); 222 TCHKMAGIC(current); 223 224 current->flags = tRUNNING; 225 current->scount++; 226 ktss->esp0 = current->esp0; 227 if(*savestack != current->esp){ 228 _context_switch(savestack, current->esp, current->cr3); 229 } 230 } 231 232 task_t *new_thread(team_t *team, uint32 ip, int kernelspace) 233 { 234 task_t *t; 235 int stack; 236 void *addr; 237 int i; 238 239 /* xxx this should be cleaner -- have a flag to area_create perhaps */ 240 for(i=1023;i>0;i--){ 241 if(!team->aspace->ptab[i]) break; 242 } 243 stack = area_create(team->aspace, 4096, i*4096, &addr, 0); 244 if(!stack) panic("cannot create a stack area. eek"); 245 246 t = task_create(team, ip, i*4096+4092, kernelspace); 247 t->ustack = (void *) (i << 12); 248 t->stack_area = rsrc_find(RSRC_AREA,stack); 249 rsrc_bind(&t->rsrc, RSRC_TASK, team); 250 t->flags = tREADY; 251 if(!kernelspace) { 252 rsrc_enqueue(run_queue, t); 253 live_tasks++; 254 } 255 256 return t; 257 } 258 259 int brk(uint32 addr) 260 { 261 aspace_t *a = current->rsrc.owner->aspace; 262 area_t *area = rsrc_find_area(current->rsrc.owner->heap_id); 263 264 if(area){ 265 // kprintf("brk addr %x thid %d",addr,current->rsrc.id); 266 return area_resize(a,current->rsrc.owner->heap_id, 267 0x1000 + ((addr - area->virt_addr) & 0xFFFFF000)); 268 } 269 return ERR_MEMORY; 270 } 271 272 /* 273 0 = directory 274 1 = bootstrap 275 2 = kernel 276 */ 277 278 279 void go_kernel(void) 280 { 281 task_t *t; 282 int i,len; 283 void *ptr,*phys; 284 port_t *uberport; 285 area_t *uberarea; 286 team_t *team; 287 288 for (i = 0, len = 1; (bdir->bd_entry[i].be_type != BE_TYPE_NONE); i++){ 289 len += bdir->bd_entry[i].be_size; 290 } 291 len *= 0x1000; 292 293 uberport = rsrc_find_port(uberportnum = port_create(0,"uberport")); 294 uberarea = rsrc_find_area(uberareanum = area_create_uber(len, 295 (void *) 0x100000)); 296 kprintf("uberport allocated with rid = %d",uberportnum); 297 kprintf("uberarea allocated with rid = %d",uberareanum); 298 299 kernel_team = team_create(); 300 rsrc_set_name(&kernel_team->rsrc, "kernel team"); 301 302 run_queue = rsrc_find_queue(queue_create("run queue",kernel_team)); 303 reaper_queue = rsrc_find_queue(queue_create("reaper queue",kernel_team)); 304 timer_queue = rsrc_find_queue(queue_create("timer queue",kernel_team)); 305 rsrc_set_owner(&uberarea->rsrc,kernel_team); 306 rsrc_set_owner(&uberport->rsrc,kernel_team); 307 308 for(i=3;bdir->bd_entry[i].be_type;i++){ 309 if(bdir->bd_entry[i].be_type != BE_TYPE_CODE) continue; 310 311 team = team_create(); 312 t = new_thread(team, 0x1074 /*bdir->bd_entry[i].be_code_ventr*/, 0); 313 current = t; 314 315 phys = (void *) (bdir->bd_entry[i].be_offset*0x1000 + 0x100000); 316 team->text_area = area_create(team->aspace,bdir->bd_entry[i].be_size*0x1000, 317 0x1000, &phys, AREA_PHYSMAP); 318 team->heap_id = area_create(team->aspace,0x2000,0x1000 + bdir->bd_entry[i].be_size* 319 0x1000, &ptr, 0); 320 321 /* make the thread own it's address space */ 322 /* rsrc_set_owner(&a->rsrc, t); */ 323 324 if (!strcmp (bdir->bd_entry[i].be_name, "namer")) { 325 rsrc_set_owner(&uberport->rsrc, team); 326 } 327 328 rsrc_set_name(&t->rsrc,bdir->bd_entry[i].be_name); 329 rsrc_set_name(&team->rsrc,bdir->bd_entry[i].be_name); 330 331 kprintf("task %X @ 0x%x, size = 0x%x (%s)",t->rsrc.id, 332 bdir->bd_entry[i].be_offset*4096+0x100000, 333 bdir->bd_entry[i].be_size*4096, 334 t->rsrc.name); 335 } 336 337 kprintf("creating idler..."); 338 idle_task = new_thread(kernel_team, (int) idler, 1); 339 rsrc_set_name((resource_t*)idle_task,"idler"); 340 341 kprintf("creating grim reaper..."); 342 current = new_thread(kernel_team, (int) reaper, 1); 343 rsrc_set_name((resource_t*)current,"grim reaper"); 344 reaper_sem = sem_create(0,"death toll"); 345 rsrc_enqueue(run_queue, current); 346 live_tasks++; 347 348 kprintf("creating pager..."); 349 current = pager_task = new_thread(kernel_team, (int) pager, 1); 350 rsrc_set_name((resource_t*)current,"pager"); 351 pager_port_no = port_create(0,"pager port"); 352 pager_sem_no = sem_create(0, "pager sem"); 353 rsrc_enqueue(run_queue, current); 354 live_tasks++; 355 356 rsrc_set_name((resource_t*)kernel,"kernel"); 357 358 #ifdef __SMP__ 359 smp_init (); 360 #endif 361 362 // DEBUGGER(); 363 kprintf("starting scheduler..."); 364 365 #ifdef __SMP__ 366 if (smp_configured) 367 { 368 smp_final_setup (); 369 kprintf ("smp: signaling other processors"); 370 smp_begin (); 371 } 372 #endif 373 374 /* 375 * when the new vm stuffas are done, we can at this point discard any 376 * complete pages in the .text.init and .data.init sections of the kernel 377 * by zeroing them and adding them to the free physical page pool. 378 */ 379 380 current = kernel; 381 current->flags = tDEAD; 382 current->waiting_on = NULL; 383 swtch(); 384 385 kprintf("panic: returned from scheduler?"); 386 asm("hlt"); 387 } 388 389 struct _kinfo 390 { 391 uint32 memsize; 392 uint32 entry_ebp; 393 boot_dir *bd; 394 unsigned char *params; 395 } *kinfo = (struct _kinfo *) 0x80000000; 396 397 const static char *copyright1 = 398 "OpenBLT Release I (built "__DATE__ ", " __TIME__ ")"; 399 const static char *copyright2 = 400 " Copyright (c) 1998-2000 The OpenBLT Dev. Team. All rights reserved."; 401 402 void kmain(void) 403 { 404 int n,len; 405 memsize = ((kinfo->memsize) / 4096) & ~0xff; 406 entry_ebp = kinfo->entry_ebp; 407 bdir = kinfo->bd; 408 409 for (n = 0, len = 1; (bdir->bd_entry[n].be_type != BE_TYPE_NONE); n++) 410 len += bdir->bd_entry[n].be_size; 411 412 init_timer(); 413 init_kspace(256 + len + 16); /* bottom of kernel memory */ 414 415 kprintf_init(); 416 #ifdef SERIAL 417 dprintf_init(); 418 #endif 419 420 kprintf(""); 421 kprintf (copyright1); 422 kprintf (copyright2); 423 kprintf(""); 424 #ifdef DPRINTF 425 dprintf (""); 426 dprintf (copyright1); 427 dprintf (copyright2); 428 dprintf (""); 429 kprintf ("serial port is in dprintf mode"); 430 dprintf ("serial port is in dprintf mode"); 431 dprintf (""); 432 #endif 433 434 kprintf("system memory 0x%x",memsize*4096); 435 436 n = ((uint32) toppage) + 4080; 437 asm("mov %0, %%esp"::"r" (n) ); 438 439 n = SEL_UDATA | 3; 440 asm("pushl %0; popl %%ds"::"r" (n)); 441 asm("pushl %0; popl %%es"::"r" (n)); 442 asm("pushl %0; popl %%fs"::"r" (n)); 443 asm("pushl %0; popl %%gs"::"r" (n)); 444 445 kprintf("kernel space initialized"); 446 go_kernel(); 447 } 448