/* This file contains the main program of MINIX. The routine main() * initializes the system and starts the ball rolling by setting up the proc * table, interrupt vectors, and scheduling each task to run to initialize * itself. * * The entries into this file are: * main: MINIX main program * panic: abort MINIX due to a fatal error */ #include "kernel.h" #include <signal.h> #include <minix/callnr.h> #include <minix/com.h> #include "proc.h" #define SAFETY 32 /* safety margin for stack overflow (bytes) */ #define CMASK4 0x9E /* mask for Planar Control Register */ #define HIGH_INT 17 /* limit of the interrupt vectors */ FORWARD void set_vec(); #if !INTEL_32BITS PRIVATE void (*int_vec[HIGH_INT])() = { int00, int01, int02, int03, int04, int05, int06, int07, int08, int09, int10, int11, int12, int13, int14, int15, int16, }; #endif /*===========================================================================* * main * *===========================================================================*/ PUBLIC void main() { /* Start the ball rolling. */ register struct proc *rp; register int t; int sizeindex; phys_clicks base_click; phys_clicks text_base; vir_clicks text_clicks; vir_clicks data_clicks; phys_bytes phys_b; int stack_size; reg_t ktsb; /* kernel task stack base */ /* Interrupts are disabled here. * They are reenabled when INIT_PSW is loaded by the first restart(). */ /* Call the stage 2 assembler hooks to finish machine/mode-specific inits. * The 2 stages are needed to handle modes switches, especially 16->32 bits. */ mpx_2hook(); klib_2hook(); /* Clear the process table. * Set up mappings for proc_addr() and proc_number() macros. */ for (rp = BEG_PROC_ADDR, t = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++t) { rp->p_flags = P_SLOT_FREE; rp->p_nr = t; /* proc number from ptr */ (pproc_addr + NR_TASKS)[t] = rp; /* proc ptr from number */ } #if (CHIP == INTEL) /* Finish off initialization of tables for protected mode. */ if (protected_mode) ldt_init(); #endif /* Set up proc table entries for tasks and servers. Be very careful about * sp, since in real mode the 3 words prior to it will be clobbered when * the kernel pushes pc, cs, and psw onto the USER's stack when starting * the user the first time. If an interrupt happens before the user loads * a better stack pointer, these 3 words will be used to save the state, * and the interrupt handler will use another 3, and a debugger trap will * use another 3 or 4, and an "impossible" non-maskable interrupt may use * more! This means that with INIT_SP == 0x1C, user programs must leave * the memory between 0x0008 and 0x001B free. FS currently violates this * by using the word at 0x0008. */ base_click = code_base >> CLICK_SHIFT; /* base for tasks */ /* Align stack base suitably. */ ktsb = ((reg_t) t_stack + (ALIGNMENT - 1)) & ~((reg_t) ALIGNMENT - 1); for (rp = BEG_PROC_ADDR, t = -NR_TASKS; rp <= BEG_USER_ADDR; ++rp, ++t) { if (t < 0) { stack_size = tasktab[t+NR_TASKS].stksize; rp->p_splimit = ktsb + SAFETY; ktsb += stack_size; rp->p_reg.sp = ktsb; text_base = base_click; /* tasks are all in the kernel */ sizeindex = 0; /* and use the full kernel sizes */ } else { rp->p_splimit = rp->p_reg.sp = INIT_SP; sizeindex = 2 * t + 2; /* MM, FS, INIT have their own sizes */ } rp->p_reg.pc = (reg_t) tasktab[t + NR_TASKS].initial_pc; rp->p_reg.psw = istaskp(rp) ? INIT_TASK_PSW : INIT_PSW; text_clicks = sizes[sizeindex]; data_clicks = sizes[sizeindex + 1]; rp->p_map[T].mem_phys = text_base; rp->p_map[T].mem_len = text_clicks; rp->p_map[D].mem_phys = text_base + text_clicks; rp->p_map[D].mem_len = data_clicks; rp->p_map[S].mem_phys = text_base + text_clicks + data_clicks; rp->p_map[S].mem_vir = data_clicks; /* empty - stack is in data */ text_base += text_clicks + data_clicks; /* ready for next, if server */ if (!isidlehardware(t)) lock_ready(rp); /* IDLE, HARDWARE neveready */ rp->p_flags = 0; #if (CHIP == INTEL) alloc_segments(rp); #endif } /* Interpret memory sizes. */ mem_init(); /* Save the old interrupt vectors. */ phys_b = umap(cproc_addr(HARDWARE), D, (vir_bytes) vec_table, VECTOR_BYTES); phys_copy(0L, phys_b, (long) VECTOR_BYTES); /* save all the vectors */ #if !INTEL_32BITS /* For protected mode, the interrupt vectors have already been set up by * prot_init() (with a different vector table). * So this block of code does nothing useful in protected mode. * It is not worth skipping, except for 32-bit mode where it would be too * much trouble to set up the unused functions in int_vec[]. * The low-memory vector table was saved mainly for *wini.c to peek at. */ /* Set up the new interrupt vectors. */ for (t = 0; t < HIGH_INT; t++) set_vec(t, int_vec[t], base_click); for (t = HIGH_INT; t < 256; t++) set_vec(t, trp, base_click); set_vec(SYS_VECTOR, s_call, base_click); set_vec(CLOCK_VECTOR, clock_int, base_click); set_vec(KEYBOARD_VECTOR, tty_int, base_click); set_vec(SECONDARY_VECTOR, secondary_int, base_click); set_vec(RS232_VECTOR, rs232_int, base_click); set_vec(FLOPPY_VECTOR, disk_int, base_click); set_vec(PRINTER_VECTOR, lpr_int, base_click); #if AM_KERNEL #if !NONET set_vec(ETHER_VECTOR, eth_int, base_click); /* overwrites RS232 port 2 */ #endif #endif if (pc_at) { set_vec(AT_WINI_VECTOR, wini_int, base_click); } else set_vec(XT_WINI_VECTOR, wini_int, base_click); if (ps) set_vec(PS_KEYB_VECTOR, tty_int, base_click); #endif /* !INTEL_32BITS */ /* Put a ptr to proc table in a known place so it can be found in /dev/mem */ set_vec( (code_base - 4)/4, (void (*)()) proc, (phys_clicks) 0); bill_ptr = cproc_addr(IDLE); /* it has to point somewhere */ lock_pick_proc(); /* Finish initializing 8259 (needs machine type). */ init_8259(IRQ0_VECTOR, IRQ8_VECTOR); /* Unmask second interrupt controller on AT's. * Don't use enable_irq(), because it unlocks interrupts. */ if (pc_at) out_byte(INT_CTLMASK, ~(1 << (CASCADE_IRQ & 0x07))); /* Set planar control registers on PS's. Fix this. CMASK4 is magic and * probably ought to be set by the individual drivers. */ if (ps) { port_65 = in_byte(PCR); /* save Planar Control Register */ out_byte(PCR, CMASK4); /* set Planar Control Register */ } /* Now go to the assembly code to start running the current process. */ restart(); } /*===========================================================================* * panic * *===========================================================================*/ PUBLIC void panic(s,n) char *s; int n; { /* The system has run aground of a fatal error. Terminate execution. * If the panic originated in MM or FS, the string will be empty and the * file system already syncked. If the panic originates in the kernel, we are * kind of stuck. */ if (*s != 0) { printf("\r\nKernel panic: %s",s); if (n != NO_NUM) printf(" %d", n); printf("\r\n"); } if (db_exists) { db_enabled = TRUE; db(); } wreboot(); } #if (CHIP == INTEL) /*===========================================================================* * set_vec * *===========================================================================*/ PRIVATE void set_vec(vec_nr, addr, base_click) int vec_nr; /* which vector */ void (*addr)(); /* where to start */ phys_clicks base_click; /* click where kernel sits in memory */ { /* Set up an interrupt vector. */ u16_t vec[2]; phys_bytes phys_b; /* Build the vector in the array 'vec'. */ vec[0] = (unsigned) addr; vec[1] = (unsigned) click_to_hclick(base_click); /* Copy the vector into place. */ phys_b = umap(cproc_addr(HARDWARE), D, (vir_bytes) vec, 4); phys_copy(phys_b, (phys_bytes) vec_nr*4, (phys_bytes) 4); } #endif /*===========================================================================* * networking * *===========================================================================*/ #if !AM_KERNEL /* These routines are dummies. They are only needed when networking is * disabled. They are called in mpx88.s and klib88.s. */ PUBLIC void eth_stp() {} /* stop the ethernet upon reboot */ PUBLIC void dp8390_int(){} /* Ethernet interrupt */ #endif