Minix1.5/kernel/main.c

Compare this file to the similar file:
Show the results in this format:

/* 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