1 /* This file contains the main program of MINIX as well as its shutdown code.
2 * The routine main() initializes the system and starts the ball rolling by
3 * setting up the process table, interrupt vectors, and scheduling each task
4 * to run to initialize itself.
5 * The routine shutdown() does the opposite and brings down MINIX.
7 * The entries into this file are:
8 * main: MINIX main program
9 * prepare_shutdown: prepare to take MINIX down
16 #include <minix/callnr.h>
17 #include <minix/com.h>
18 #include <minix/endpoint.h>
21 /* Prototype declarations for PRIVATE functions. */
22 FORWARD
_PROTOTYPE( void announce
, (void));
23 FORWARD
_PROTOTYPE( void shutdown
, (timer_t
*));
25 /*===========================================================================*
27 *===========================================================================*/
30 /* Start the ball rolling. */
31 struct boot_image
*ip
; /* boot image pointer */
32 register struct proc
*rp
; /* process pointer */
33 register struct priv
*sp
; /* privilege structure pointer */
35 int hdrindex
; /* index to array of a.out headers */
36 phys_clicks text_base
;
37 vir_clicks text_clicks
, data_clicks
, st_clicks
;
38 reg_t ktsb
; /* kernel task stack base */
39 struct exec e_hdr
; /* for a copy of an a.out header */
41 /* Clear the process table. Anounce each slot as empty and set up mappings
42 * for proc_addr() and proc_nr() macros. Do the same for the table with
43 * privilege structures for the system processes.
45 for (rp
= BEG_PROC_ADDR
, i
= -NR_TASKS
; rp
< END_PROC_ADDR
; ++rp
, ++i
) {
46 rp
->p_rts_flags
= SLOT_FREE
; /* initialize free slot */
47 rp
->p_nr
= i
; /* proc number from ptr */
48 rp
->p_endpoint
= _ENDPOINT(0, rp
->p_nr
); /* generation no. 0 */
49 (pproc_addr
+ NR_TASKS
)[i
] = rp
; /* proc ptr from number */
51 for (sp
= BEG_PRIV_ADDR
, i
= 0; sp
< END_PRIV_ADDR
; ++sp
, ++i
) {
52 sp
->s_proc_nr
= NONE
; /* initialize as free */
53 sp
->s_id
= i
; /* priv structure index */
54 ppriv_addr
[i
] = sp
; /* priv ptr from number */
57 /* Set up proc table entries for processes in boot image. The stacks of the
58 * kernel tasks are initialized to an array in data space. The stacks
59 * of the servers have been added to the data segment by the monitor, so
60 * the stack pointer is set to the end of the data segment. All the
61 * processes are in low memory on the 8086. On the 386 only the kernel
62 * is in low memory, the rest is loaded in extended memory.
66 ktsb
= (reg_t
) t_stack
;
68 for (i
=0; i
< NR_BOOT_PROCS
; ++i
) {
71 ip
= &image
[i
]; /* process' attributes */
72 rp
= proc_addr(ip
->proc_nr
); /* get process pointer */
73 ip
->endpoint
= rp
->p_endpoint
; /* ipc endpoint */
74 rp
->p_max_priority
= ip
->priority
; /* max scheduling priority */
75 rp
->p_priority
= ip
->priority
; /* current priority */
76 rp
->p_quantum_size
= ip
->quantum
; /* quantum size in ticks */
77 rp
->p_ticks_left
= ip
->quantum
; /* current credit */
78 strncpy(rp
->p_name
, ip
->proc_name
, P_NAME_LEN
); /* set process name */
79 (void) get_priv(rp
, (ip
->flags
& SYS_PROC
)); /* assign structure */
80 priv(rp
)->s_flags
= ip
->flags
; /* process flags */
81 priv(rp
)->s_trap_mask
= ip
->trap_mask
; /* allowed traps */
83 /* Initialize call mask bitmap from unordered set.
84 * A single SYS_ALL_CALLS is a special case - it
85 * means all calls are allowed.
87 if(ip
->nr_k_calls
== 1 && ip
->k_calls
[0] == SYS_ALL_CALLS
)
88 fv
= ~0; /* fill call mask */
90 fv
= 0; /* clear call mask */
92 for(ci
= 0; ci
< CALL_MASK_SIZE
; ci
++) /* fill or clear call mask */
93 priv(rp
)->s_k_call_mask
[ci
] = fv
;
94 if(!fv
) /* not all full? enter calls bit by bit */
95 for(ci
= 0; ci
< ip
->nr_k_calls
; ci
++)
96 SET_BIT(priv(rp
)->s_k_call_mask
,
97 ip
->k_calls
[ci
]-KERNEL_CALL
);
99 priv(rp
)->s_ipc_to
.chunk
[0] = ip
->ipc_to
; /* restrict targets */
100 if (iskerneln(proc_nr(rp
))) { /* part of the kernel? */
101 if (ip
->stksize
> 0) { /* HARDWARE stack size is 0 */
102 rp
->p_priv
->s_stack_guard
= (reg_t
*) ktsb
;
103 *rp
->p_priv
->s_stack_guard
= STACK_GUARD
;
105 ktsb
+= ip
->stksize
; /* point to high end of stack */
106 rp
->p_reg
.sp
= ktsb
; /* this task's initial stack ptr */
107 hdrindex
= 0; /* all use the first a.out header */
109 hdrindex
= 1 + i
-NR_TASKS
; /* servers, drivers, INIT */
112 /* The bootstrap loader created an array of the a.out headers at
113 * absolute address 'aout'. Get one element to e_hdr.
115 phys_copy(aout
+ hdrindex
* A_MINHDR
, vir2phys(&e_hdr
),
116 (phys_bytes
) A_MINHDR
);
117 /* Convert addresses to clicks and build process memory map */
118 text_base
= e_hdr
.a_syms
>> CLICK_SHIFT
;
119 text_clicks
= (e_hdr
.a_text
+ CLICK_SIZE
-1) >> CLICK_SHIFT
;
120 data_clicks
= (e_hdr
.a_data
+e_hdr
.a_bss
+ CLICK_SIZE
-1) >> CLICK_SHIFT
;
121 st_clicks
= (e_hdr
.a_total
+ CLICK_SIZE
-1) >> CLICK_SHIFT
;
122 if (!(e_hdr
.a_flags
& A_SEP
))
124 data_clicks
= (e_hdr
.a_text
+e_hdr
.a_data
+e_hdr
.a_bss
+
125 CLICK_SIZE
-1) >> CLICK_SHIFT
;
126 text_clicks
= 0; /* common I&D */
128 rp
->p_memmap
[T
].mem_phys
= text_base
;
129 rp
->p_memmap
[T
].mem_len
= text_clicks
;
130 rp
->p_memmap
[D
].mem_phys
= text_base
+ text_clicks
;
131 rp
->p_memmap
[D
].mem_len
= data_clicks
;
132 rp
->p_memmap
[S
].mem_phys
= text_base
+ text_clicks
+ st_clicks
;
133 rp
->p_memmap
[S
].mem_vir
= st_clicks
;
134 rp
->p_memmap
[S
].mem_len
= 0;
136 /* Set initial register values. The processor status word for tasks
137 * is different from that of other processes because tasks can
138 * access I/O; this is not allowed to less-privileged processes
140 rp
->p_reg
.pc
= (reg_t
) ip
->initial_pc
;
141 rp
->p_reg
.psw
= (iskernelp(rp
)) ? INIT_TASK_PSW
: INIT_PSW
;
143 /* Initialize the server stack pointer. Take it down one word
144 * to give crtso.s something to use as "argc".
146 if (isusern(proc_nr(rp
))) { /* user-space process? */
147 rp
->p_reg
.sp
= (rp
->p_memmap
[S
].mem_vir
+
148 rp
->p_memmap
[S
].mem_len
) << CLICK_SHIFT
;
149 rp
->p_reg
.sp
-= sizeof(reg_t
);
152 /* Set ready. The HARDWARE task is never ready. */
153 if (rp
->p_nr
== HARDWARE
) RTS_LOCK_SET(rp
, NO_PRIORITY
);
154 RTS_LOCK_UNSET(rp
, SLOT_FREE
); /* remove SLOT_FREE and schedule */
156 /* Code and data segments must be allocated in protected mode. */
161 sprofiling
= 0; /* we're not profiling until instructed to */
162 #endif /* SPROFILE */
164 cprof_procs_no
= 0; /* init nr of hash table slots used */
165 #endif /* CPROFILE */
167 /* MINIX is now ready. All boot image processes are on the ready queue.
168 * Return to the assembly code to start running the current process.
170 bill_ptr
= proc_addr(IDLE
); /* it has to point somewhere */
171 announce(); /* print MINIX startup banner */
175 /*===========================================================================*
177 *===========================================================================*/
178 PRIVATE
void announce(void)
180 /* Display the MINIX startup banner. */
181 kprintf("\nMINIX %s.%s. "
183 "(" _SVN_REVISION
")\n"
185 "Copyright 2006, Vrije Universiteit, Amsterdam, The Netherlands\n",
186 OS_RELEASE
, OS_VERSION
);
189 /*===========================================================================*
191 *===========================================================================*/
192 PUBLIC
void prepare_shutdown(how
)
195 /* This function prepares to shutdown MINIX. */
196 static timer_t shutdown_timer
;
197 register struct proc
*rp
;
200 /* Send a signal to all system processes that are still alive to inform
201 * them that the MINIX kernel is shutting down. A proper shutdown sequence
202 * should be implemented by a user-space server. This mechanism is useful
203 * as a backup in case of system panics, so that system processes can still
204 * run their shutdown code, e.g, to synchronize the FS or to let the TTY
205 * switch to the first console.
208 kprintf("Sending SIGKSTOP to system processes ...\n");
209 for (rp
=BEG_PROC_ADDR
; rp
<END_PROC_ADDR
; rp
++) {
210 if (!isemptyp(rp
) && (priv(rp
)->s_flags
& SYS_PROC
) && !iskernelp(rp
))
211 send_sig(proc_nr(rp
), SIGKSTOP
);
215 /* Continue after 1 second, to give processes a chance to get scheduled to
216 * do shutdown work. Set a watchog timer to call shutdown(). The timer
217 * argument passes the shutdown status.
219 kprintf("MINIX will now be shut down ...\n");
220 tmr_arg(&shutdown_timer
)->ta_int
= how
;
221 set_timer(&shutdown_timer
, get_uptime() + HZ
, shutdown
);
224 /*===========================================================================*
226 *===========================================================================*/
227 PRIVATE
void shutdown(tp
)
230 /* This function is called from prepare_shutdown or stop_sequence to bring
231 * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the
232 * monitor), RBT_MONITOR (execute given code), RBT_RESET (hard reset).
234 intr_init(INTS_ORIG
);
236 arch_shutdown(tmr_arg(tp
)->ta_int
);