openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

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