small asmconv cleanups.
[minix.git] / kernel / arch / i386 / system.c
blob2154624aab504b15271938c23c29108c7435638f
1 /* system dependent functions for use inside the whole kernel. */
3 #include "../../kernel.h"
5 #include <unistd.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <ibm/cmos.h>
9 #include <ibm/bios.h>
10 #include <minix/portio.h>
11 #include <minix/cpufeature.h>
12 #include <a.out.h>
13 #include <archconst.h>
15 #include "proto.h"
16 #include "../../proc.h"
17 #include "../../debug.h"
19 #ifdef CONFIG_APIC
20 #include "apic.h"
21 #endif
23 /* set MP and NE flags to handle FPU exceptions in native mode. */
24 #define CR0_MP_NE 0x0022
25 /* set CR4.OSFXSR[bit 9] if FXSR is supported. */
26 #define CR4_OSFXSR (1L<<9)
27 /* set OSXMMEXCPT[bit 10] if we provide #XM handler. */
28 #define CR4_OSXMMEXCPT (1L<<10)
30 FORWARD _PROTOTYPE( void ser_debug, (int c));
32 PUBLIC void arch_monitor(void)
34 level0(monitor);
37 PUBLIC int cpu_has_tsc;
39 PUBLIC void arch_shutdown(int how)
41 /* Mask all interrupts, including the clock. */
42 outb( INT_CTLMASK, ~0);
44 if(minix_panicing) {
45 /* We're panicing? Then retrieve and decode currently
46 * loaded segment selectors.
48 printseg("cs: ", 1, proc_ptr, read_cs());
49 printseg("ds: ", 0, proc_ptr, read_ds());
50 if(read_ds() != read_ss()) {
51 printseg("ss: ", 0, NULL, read_ss());
55 if(how != RBT_RESET) {
56 /* return to boot monitor */
58 outb( INT_CTLMASK, 0);
59 outb( INT2_CTLMASK, 0);
61 /* Return to the boot monitor. Set
62 * the program if not already done.
64 if (how != RBT_MONITOR)
65 arch_set_params("", 1);
66 if(minix_panicing) {
67 int source, dest;
68 static char mybuffer[sizeof(params_buffer)];
69 char *lead = "echo \\n*** kernel messages:\\n";
70 int leadlen = strlen(lead);
71 strcpy(mybuffer, lead);
73 #define DECSOURCE source = (source - 1 + _KMESS_BUF_SIZE) % _KMESS_BUF_SIZE
75 dest = sizeof(mybuffer)-1;
76 mybuffer[dest--] = '\0';
78 source = kmess.km_next;
79 DECSOURCE;
81 while(dest >= leadlen) {
82 char c = kmess.km_buf[source];
83 if(c == '\n') {
84 mybuffer[dest--] = 'n';
85 mybuffer[dest] = '\\';
86 } else if(isprint(c) &&
87 c != '\'' && c != '"' &&
88 c != '\\' && c != ';') {
89 mybuffer[dest] = c;
90 } else mybuffer[dest] = ' ';
92 DECSOURCE;
93 dest--;
96 arch_set_params(mybuffer, strlen(mybuffer)+1);
98 arch_monitor();
99 } else {
100 /* Reset the system by forcing a processor shutdown. First stop
101 * the BIOS memory test by setting a soft reset flag.
103 u16_t magic = STOP_MEM_CHECK;
104 phys_copy(vir2phys(&magic), SOFT_RESET_FLAG_ADDR,
105 SOFT_RESET_FLAG_SIZE);
106 level0(reset);
110 /* address of a.out headers, set in mpx386.s */
111 phys_bytes aout;
113 PUBLIC void arch_get_aout_headers(int i, struct exec *h)
115 /* The bootstrap loader created an array of the a.out headers at
116 * absolute address 'aout'. Get one element to h.
118 phys_copy(aout + i * A_MINHDR, vir2phys(h), (phys_bytes) A_MINHDR);
121 PRIVATE void tss_init(struct tss_s * tss, void * kernel_stack, unsigned cpu)
124 * make space for process pointer and cpu id and point to the first
125 * usable word
127 tss->sp0 = ((unsigned) kernel_stack) - 2 * sizeof(void *);
128 tss->ss0 = DS_SELECTOR;
131 * set the cpu id at the top of the stack so we know on which cpu is
132 * this stak in use when we trap to kernel
134 *((reg_t *)(tss->sp0 + 1 * sizeof(reg_t))) = cpu;
137 PUBLIC void arch_init(void)
139 unsigned short cw, sw;
141 fninit();
142 sw = fnstsw();
143 fnstcw(&cw);
145 if((sw & 0xff) == 0 &&
146 (cw & 0x103f) == 0x3f) {
147 /* We have some sort of FPU, but don't check exact model.
148 * Set CR0_NE and CR0_MP to handle fpu exceptions
149 * in native mode. */
150 write_cr0(read_cr0() | CR0_MP_NE);
151 fpu_presence = 1;
152 if(_cpufeature(_CPUF_I386_FXSR)) {
153 register struct proc *rp;
154 phys_bytes aligned_fp_area;
156 /* Enable FXSR feature usage. */
157 write_cr4(read_cr4() | CR4_OSFXSR | CR4_OSXMMEXCPT);
158 osfxsr_feature = 1;
160 for (rp = BEG_PROC_ADDR; rp < END_PROC_ADDR; ++rp) {
161 /* FXSR requires 16-byte alignment of memory
162 * image, but unfortunately some old tools
163 * (probably linker) ignores ".balign 16"
164 * applied to our memory image.
165 * Thus we have to do manual alignment.
167 aligned_fp_area =
168 (phys_bytes) &rp->p_fpu_state.fpu_image;
169 if(aligned_fp_area % FPUALIGN) {
170 aligned_fp_area += FPUALIGN -
171 (aligned_fp_area % FPUALIGN);
173 rp->p_fpu_state.fpu_save_area_p =
174 (void *) aligned_fp_area;
176 } else {
177 osfxsr_feature = 0;
179 } else {
180 /* No FPU presents. */
181 fpu_presence = 0;
182 osfxsr_feature = 0;
183 return;
186 #ifdef CONFIG_APIC
188 * this is setting kernel segments to cover most of the phys memory. The
189 * value is high enough to reach local APIC nad IOAPICs before paging is
190 * turned on.
192 prot_set_kern_seg_limit(0xfff00000);
193 reload_ds();
194 #endif
196 idt_init();
198 tss_init(&tss, &k_boot_stktop, 0);
200 #if defined(CONFIG_APIC) && !defined(CONFIG_SMP)
201 if (config_no_apic) {
202 BOOT_VERBOSE(kprintf("APIC disabled, using legacy PIC\n"));
204 else if (!apic_single_cpu_init()) {
205 BOOT_VERBOSE(kprintf("APIC not present, using legacy PIC\n"));
207 #endif
211 #define COM1_BASE 0x3F8
212 #define COM1_THR (COM1_BASE + 0)
213 #define COM1_RBR (COM1_BASE + 0)
214 #define COM1_LSR (COM1_BASE + 5)
215 #define LSR_DR 0x01
216 #define LSR_THRE 0x20
218 PUBLIC void ser_putc(char c)
220 int i;
221 int lsr, thr;
223 lsr= COM1_LSR;
224 thr= COM1_THR;
225 for (i= 0; i<100000; i++)
227 if (inb( lsr) & LSR_THRE)
228 break;
230 outb( thr, c);
233 /*===========================================================================*
234 * do_ser_debug *
235 *===========================================================================*/
236 PUBLIC void do_ser_debug()
238 u8_t c, lsr;
240 lsr= inb(COM1_LSR);
241 if (!(lsr & LSR_DR))
242 return;
243 c = inb(COM1_RBR);
244 ser_debug(c);
247 PRIVATE void ser_dump_queues(void)
249 int q;
250 for(q = 0; q < NR_SCHED_QUEUES; q++) {
251 struct proc *p;
252 if(rdy_head[q])
253 printf("%2d: ", q);
254 for(p = rdy_head[q]; p; p = p->p_nextready) {
255 printf("%s / %d ", p->p_name, p->p_endpoint);
257 printf("\n");
262 PRIVATE void ser_dump_segs(void)
264 struct proc *pp;
265 for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++)
267 if (isemptyp(pp))
268 continue;
269 kprintf("%d: %s ep %d\n", proc_nr(pp), pp->p_name, pp->p_endpoint);
270 printseg("cs: ", 1, pp, pp->p_reg.cs);
271 printseg("ds: ", 0, pp, pp->p_reg.ds);
272 if(pp->p_reg.ss != pp->p_reg.ds) {
273 printseg("ss: ", 0, pp, pp->p_reg.ss);
278 PRIVATE void ser_debug(int c)
280 int u = 0;
282 serial_debug_active = 1;
283 /* Disable interrupts so that we get a consistent state. */
284 if(!intr_disabled()) { lock; u = 1; };
286 switch(c)
288 case 'Q':
289 minix_shutdown(NULL);
290 NOT_REACHABLE;
291 case '1':
292 ser_dump_proc();
293 break;
294 case '2':
295 ser_dump_queues();
296 break;
297 case '3':
298 ser_dump_segs();
299 break;
300 #if DEBUG_TRACE
301 #define TOGGLECASE(ch, flag) \
302 case ch: { \
303 if(verboseflags & flag) { \
304 verboseflags &= ~flag; \
305 printf("%s disabled\n", #flag); \
306 } else { \
307 verboseflags |= flag; \
308 printf("%s enabled\n", #flag); \
310 break; \
312 TOGGLECASE('8', VF_SCHEDULING)
313 TOGGLECASE('9', VF_PICKPROC)
314 #endif
316 serial_debug_active = 0;
317 if(u) { unlock; }
320 PRIVATE void printslot(struct proc *pp, int level)
322 struct proc *depproc = NULL;
323 int dep = NONE;
324 #define COL { int i; for(i = 0; i < level; i++) printf("> "); }
326 if(level >= NR_PROCS) {
327 kprintf("loop??\n");
328 return;
333 kprintf("%d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s misc %s",
334 proc_nr(pp), pp->p_name, pp->p_endpoint,
335 pp->p_priority, pp->p_max_priority, pp->p_user_time,
336 pp->p_sys_time, pp->p_seg.p_cr3,
337 rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags));
339 if(pp->p_rts_flags & RTS_SENDING) {
340 dep = pp->p_sendto_e;
341 kprintf(" to: ");
342 } else if(pp->p_rts_flags & RTS_RECEIVING) {
343 dep = pp->p_getfrom_e;
344 kprintf(" from: ");
347 if(dep != NONE) {
348 if(dep == ANY) {
349 kprintf(" ANY\n");
350 } else {
351 int procno;
352 if(!isokendpt(dep, &procno)) {
353 kprintf(" ??? %d\n", dep);
354 } else {
355 depproc = proc_addr(procno);
356 if(isemptyp(depproc)) {
357 kprintf(" empty slot %d???\n", procno);
358 depproc = NULL;
359 } else {
360 kprintf(" %s\n", depproc->p_name);
364 } else {
365 kprintf("\n");
369 proc_stacktrace(pp);
372 if(depproc)
373 printslot(depproc, level+1);
377 PUBLIC void ser_dump_proc()
379 struct proc *pp;
381 for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++)
383 if (isemptyp(pp))
384 continue;
385 printslot(pp, 0);
389 #if SPROFILE
391 PUBLIC int arch_init_profile_clock(u32_t freq)
393 int r;
394 /* Set CMOS timer frequency. */
395 outb(RTC_INDEX, RTC_REG_A);
396 outb(RTC_IO, RTC_A_DV_OK | freq);
397 /* Enable CMOS timer interrupts. */
398 outb(RTC_INDEX, RTC_REG_B);
399 r = inb(RTC_IO);
400 outb(RTC_INDEX, RTC_REG_B);
401 outb(RTC_IO, r | RTC_B_PIE);
402 /* Mandatory read of CMOS register to enable timer interrupts. */
403 outb(RTC_INDEX, RTC_REG_C);
404 inb(RTC_IO);
406 return CMOS_CLOCK_IRQ;
409 PUBLIC void arch_stop_profile_clock(void)
411 int r;
412 /* Disable CMOS timer interrupts. */
413 outb(RTC_INDEX, RTC_REG_B);
414 r = inb(RTC_IO);
415 outb(RTC_INDEX, RTC_REG_B);
416 outb(RTC_IO, r & ~RTC_B_PIE);
419 PUBLIC void arch_ack_profile_clock(void)
421 /* Mandatory read of CMOS register to re-enable timer interrupts. */
422 outb(RTC_INDEX, RTC_REG_C);
423 inb(RTC_IO);
426 #endif
428 #define COLOR_BASE 0xB8000L
430 PRIVATE void cons_setc(int pos, int c)
432 char ch;
434 ch= c;
435 phys_copy(vir2phys((vir_bytes)&ch), COLOR_BASE+(20*80+pos)*2, 1);
438 PRIVATE void cons_seth(int pos, int n)
440 n &= 0xf;
441 if (n < 10)
442 cons_setc(pos, '0'+n);
443 else
444 cons_setc(pos, 'A'+(n-10));
447 /* Saved by mpx386.s into these variables. */
448 u32_t params_size, params_offset, mon_ds;
450 PUBLIC int arch_get_params(char *params, int maxsize)
452 phys_copy(seg2phys(mon_ds) + params_offset, vir2phys(params),
453 MIN(maxsize, params_size));
454 params[maxsize-1] = '\0';
455 return OK;
458 PUBLIC int arch_set_params(char *params, int size)
460 if(size > params_size)
461 return E2BIG;
462 phys_copy(vir2phys(params), seg2phys(mon_ds) + params_offset, size);
463 return OK;
466 PUBLIC void arch_do_syscall(struct proc *proc)
468 /* Perform a previously postponed system call.
470 int call_nr, src_dst_e;
471 message *m_ptr;
472 long bit_map;
474 /* Get the system call parameters from their respective registers. */
475 call_nr = proc->p_reg.cx;
476 src_dst_e = proc->p_reg.retreg;
477 m_ptr = (message *) proc->p_reg.bx;
478 bit_map = proc->p_reg.dx;
480 /* sys_call() expects the given process's memory to be accessible. */
481 vm_set_cr3(proc);
483 /* Make the system call, for real this time. */
484 proc->p_reg.retreg = sys_call(call_nr, src_dst_e, m_ptr, bit_map);
487 PUBLIC struct proc * arch_finish_schedcheck(void)
489 char * stk;
490 stk = (char *)tss.sp0;
491 /* set pointer to the process to run on the stack */
492 *((reg_t *)stk) = (reg_t) proc_ptr;
493 return proc_ptr;