1: /* This file contains the main program of MINIX. The routine main() 2: * initializes the system and starts the ball rolling by setting up the proc 3: * table, interrupt vectors, and scheduling each task to run to initialize 4: * itself. 5: * 6: * The entries into this file are: 7: * main: MINIX main program 8: * panic: abort MINIX due to a fatal error 9: */ 10: 11: #include "kernel.h" 12: #include <signal.h> 13: #include <unistd.h> 14: #include <a.out.h> 15: #include <minix/callnr.h> 16: #include <minix/com.h> 17: #include "proc.h" 18: 19: 20: /*===========================================================================* 21: * main * 22: *===========================================================================*/ 23: PUBLIC void main() 24: { 25: /* Start the ball rolling. */ 26: 27: register struct proc *rp; 28: register int t; 29: int hdrindex; 30: phys_clicks text_base; 31: vir_clicks text_clicks; 32: vir_clicks data_clicks; 33: reg_t ktsb; /* kernel task stack base */ 34: struct memory *memp; 35: struct tasktab *ttp; 36: struct exec e_hdr; 37: 38: /* Initialize the interrupt controller. */ 39: intr_init(1); 40: 41: /* Interpret memory sizes. */ 42: mem_init(); 43: 44: /* Clear the process table. 45: * Set up mappings for proc_addr() and proc_number() macros. 46: */ 47: for (rp = BEG_PROC_ADDR, t = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++t) { 48: rp->p_nr = t; /* proc number from ptr */ 49: (pproc_addr + NR_TASKS)[t] = rp; /* proc ptr from number */ 50: } 51: 52: /* Resolve driver selections in the task table. */ 53: mapdrivers(); 54: 55: /* Set up proc table entries for tasks and servers. The stacks of the 56: * kernel tasks are initialized to an array in data space. The stacks 57: * of the servers have been added to the data segment by the monitor, so 58: * the stack pointer is set to the end of the data segment. All the 59: * processes are in low memory on the 8086. On the 386 only the kernel 60: * is in low memory, the rest is loaded in extended memory. 61: */ 62: 63: /* Task stacks. */ 64: ktsb = (reg_t) t_stack; 65: 66: for (t = -NR_TASKS; t <= LOW_USER; ++t) { 67: rp = proc_addr(t); /* t's process slot */ 68: ttp = &tasktab[t + NR_TASKS]; /* t's task attributes */ 69: strcpy(rp->p_name, ttp->name); 70: if (t < 0) { 71: if (ttp->stksize > 0) { 72: rp->p_stguard = (reg_t *) ktsb; 73: *rp->p_stguard = STACK_GUARD; 74: } 75: ktsb += ttp->stksize; 76: rp->p_reg.sp = ktsb; 77: text_base = code_base >> CLICK_SHIFT; 78: /* tasks are all in the kernel */ 79: hdrindex = 0; /* and use the first a.out header */ 80: rp->p_priority = PPRI_TASK; 81: } else { 82: hdrindex = 1 + t; /* MM, FS, INIT follow the kernel */ 83: rp->p_priority = t < LOW_USER ? PPRI_SERVER : PPRI_USER; 84: } 85: 86: /* The bootstrap loader has created an array of the a.out headers at 87: * absolute address 'aout'. 88: */ 89: phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr), 90: (phys_bytes) A_MINHDR); 91: text_base = e_hdr.a_syms >> CLICK_SHIFT; 92: text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT; 93: if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* Common I&D */ 94: data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT; 95: rp->p_map[T].mem_phys = text_base; 96: rp->p_map[T].mem_len = text_clicks; 97: rp->p_map[D].mem_phys = text_base + text_clicks; 98: rp->p_map[D].mem_len = data_clicks; 99: rp->p_map[S].mem_phys = text_base + text_clicks + data_clicks; 100: rp->p_map[S].mem_vir = data_clicks; /* empty - stack is in data */ 101: 102: /* Remove server memory from the free memory list. The boot monitor 103: * promises to put processes at the start of memory chunks. 104: */ 105: for (memp = mem; memp < &mem[NR_MEMS]; memp++) { 106: if (memp->base == text_base) { 107: memp->base += text_clicks + data_clicks; 108: memp->size -= text_clicks + data_clicks; 109: } 110: } 111: 112: /* Set initial register values. */ 113: rp->p_reg.pc = (reg_t) ttp->initial_pc; 114: rp->p_reg.psw = istaskp(rp) ? INIT_TASK_PSW : INIT_PSW; 115: 116: if (t >= 0) { 117: /* Initialize the server stack pointer. Take it down one word 118: * to give crtso.s something to use as "argc". 119: */ 120: rp->p_reg.sp = (rp->p_map[S].mem_vir + 121: rp->p_map[S].mem_len) << CLICK_SHIFT; 122: rp->p_reg.sp -= sizeof(reg_t); 123: } 124: 125: if (!isidlehardware(t)) lock_ready(rp); /* IDLE, HARDWARE neveready */ 126: rp->p_flags = 0; 127: 128: alloc_segments(rp); 129: } 130: 131: proc[NR_TASKS+INIT_PROC_NR].p_pid = 1;/* INIT of course has pid 1 */ 132: bill_ptr = proc_addr(IDLE); /* it has to point somewhere */ 133: proc_addr(IDLE)->p_priority = PPRI_IDLE; 134: lock_pick_proc(); 135: 136: /* Now go to the assembly code to start running the current process. */ 137: restart(); 138: } 139: 140: 141: /*===========================================================================* 142: * panic * 143: *===========================================================================*/ 144: PUBLIC void panic(s,n) 145: _CONST char *s; 146: int n; 147: { 148: /* The system has run aground of a fatal error. Terminate execution. 149: * If the panic originated in MM or FS, the string will be empty and the 150: * file system already syncked. If the panic originates in the kernel, we are 151: * kind of stuck. 152: */ 153: 154: if (s != NULL) { 155: printf("\nKernel panic: %s",s); 156: if (n != NO_NUM) printf(" %d", n); 157: printf("\n"); 158: } 159: wreboot(RBT_PANIC); 160: }