xref: /minix3/minix/kernel/arch/i386/arch_system.c (revision cfd712b4245f67a5631cc14e950ce43b18455602)
1433d6423SLionel Sambuc /* system dependent functions for use inside the whole kernel. */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include "kernel/kernel.h"
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc #include <unistd.h>
6433d6423SLionel Sambuc #include <ctype.h>
7433d6423SLionel Sambuc #include <string.h>
8433d6423SLionel Sambuc #include <machine/cmos.h>
9433d6423SLionel Sambuc #include <machine/bios.h>
10433d6423SLionel Sambuc #include <machine/cpu.h>
11433d6423SLionel Sambuc #include <minix/portio.h>
12433d6423SLionel Sambuc #include <minix/cpufeature.h>
13433d6423SLionel Sambuc #include <assert.h>
14433d6423SLionel Sambuc #include <signal.h>
15433d6423SLionel Sambuc #include <machine/vm.h>
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #include <minix/u64.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include "archconst.h"
20433d6423SLionel Sambuc #include "arch_proto.h"
21433d6423SLionel Sambuc #include "serial.h"
22433d6423SLionel Sambuc #include "oxpcie.h"
23433d6423SLionel Sambuc #include <machine/multiboot.h>
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc #include "glo.h"
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc #ifdef USE_APIC
28433d6423SLionel Sambuc #include "apic.h"
29433d6423SLionel Sambuc #endif
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc #ifdef USE_ACPI
32433d6423SLionel Sambuc #include "acpi.h"
33433d6423SLionel Sambuc #endif
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc static int osfxsr_feature; /* FXSAVE/FXRSTOR instructions support (SSEx) */
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc /* set MP and NE flags to handle FPU exceptions in native mode. */
38433d6423SLionel Sambuc #define CR0_MP_NE	0x0022
39433d6423SLionel Sambuc /* set CR4.OSFXSR[bit 9] if FXSR is supported. */
40433d6423SLionel Sambuc #define CR4_OSFXSR	(1L<<9)
41433d6423SLionel Sambuc /* set OSXMMEXCPT[bit 10] if we provide #XM handler. */
42433d6423SLionel Sambuc #define CR4_OSXMMEXCPT	(1L<<10)
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc void * k_stacks;
45433d6423SLionel Sambuc 
46433d6423SLionel Sambuc static void ser_debug(int c);
47433d6423SLionel Sambuc static void ser_dump_vfs(void);
48433d6423SLionel Sambuc 
49433d6423SLionel Sambuc #ifdef CONFIG_SMP
50433d6423SLionel Sambuc static void ser_dump_proc_cpu(void);
51433d6423SLionel Sambuc #endif
52433d6423SLionel Sambuc #if !CONFIG_OXPCIE
53433d6423SLionel Sambuc static void ser_init(void);
54433d6423SLionel Sambuc #endif
55433d6423SLionel Sambuc 
56433d6423SLionel Sambuc void fpu_init(void)
57433d6423SLionel Sambuc {
58433d6423SLionel Sambuc 	unsigned short cw, sw;
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 	fninit();
61433d6423SLionel Sambuc 	sw = fnstsw();
62433d6423SLionel Sambuc 	fnstcw(&cw);
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 	if((sw & 0xff) == 0 &&
65433d6423SLionel Sambuc 	   (cw & 0x103f) == 0x3f) {
66433d6423SLionel Sambuc 		/* We have some sort of FPU, but don't check exact model.
67433d6423SLionel Sambuc 		 * Set CR0_NE and CR0_MP to handle fpu exceptions
68433d6423SLionel Sambuc 		 * in native mode. */
69433d6423SLionel Sambuc 		write_cr0(read_cr0() | CR0_MP_NE);
70433d6423SLionel Sambuc 		get_cpulocal_var(fpu_presence) = 1;
71433d6423SLionel Sambuc 		if(_cpufeature(_CPUF_I386_FXSR)) {
72433d6423SLionel Sambuc 			u32_t cr4 = read_cr4() | CR4_OSFXSR; /* Enable FXSR. */
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 			/* OSXMMEXCPT if supported
75433d6423SLionel Sambuc 			 * FXSR feature can be available without SSE
76433d6423SLionel Sambuc 			 */
77433d6423SLionel Sambuc 			if(_cpufeature(_CPUF_I386_SSE))
78433d6423SLionel Sambuc 				cr4 |= CR4_OSXMMEXCPT;
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 			write_cr4(cr4);
81433d6423SLionel Sambuc 			osfxsr_feature = 1;
82433d6423SLionel Sambuc 		} else {
83433d6423SLionel Sambuc 			osfxsr_feature = 0;
84433d6423SLionel Sambuc 		}
85433d6423SLionel Sambuc 	} else {
86433d6423SLionel Sambuc 		/* No FPU presents. */
87433d6423SLionel Sambuc 		get_cpulocal_var(fpu_presence) = 0;
88433d6423SLionel Sambuc                 osfxsr_feature = 0;
89433d6423SLionel Sambuc                 return;
90433d6423SLionel Sambuc         }
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc 
93433d6423SLionel Sambuc void save_local_fpu(struct proc *pr, int retain)
94433d6423SLionel Sambuc {
95433d6423SLionel Sambuc 	char *state = pr->p_seg.fpu_state;
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	/* Save process FPU context. If the 'retain' flag is set, keep the FPU
98433d6423SLionel Sambuc 	 * state as is. If the flag is not set, the state is undefined upon
99433d6423SLionel Sambuc 	 * return, and the caller is responsible for reloading a proper state.
100433d6423SLionel Sambuc 	 */
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc 	if(!is_fpu())
103433d6423SLionel Sambuc 		return;
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc 	assert(state);
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc 	if(osfxsr_feature) {
108433d6423SLionel Sambuc 		fxsave(state);
109433d6423SLionel Sambuc 	} else {
110433d6423SLionel Sambuc 		fnsave(state);
111433d6423SLionel Sambuc 		if (retain)
112433d6423SLionel Sambuc 			(void) frstor(state);
113433d6423SLionel Sambuc 	}
114433d6423SLionel Sambuc }
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc void save_fpu(struct proc *pr)
117433d6423SLionel Sambuc {
118433d6423SLionel Sambuc #ifdef CONFIG_SMP
119433d6423SLionel Sambuc 	if (cpuid != pr->p_cpu) {
120433d6423SLionel Sambuc 		int stopped;
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc 		/* remember if the process was already stopped */
123433d6423SLionel Sambuc 		stopped = RTS_ISSET(pr, RTS_PROC_STOP);
124433d6423SLionel Sambuc 
125433d6423SLionel Sambuc 		/* stop the remote process and force its context to be saved */
126433d6423SLionel Sambuc 		smp_schedule_stop_proc_save_ctx(pr);
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 		/*
129433d6423SLionel Sambuc 		 * If the process wasn't stopped let the process run again. The
130433d6423SLionel Sambuc 		 * process is kept block by the fact that the kernel cannot run
131433d6423SLionel Sambuc 		 * on its cpu
132433d6423SLionel Sambuc 		 */
133433d6423SLionel Sambuc 		if (!stopped)
134433d6423SLionel Sambuc 			RTS_UNSET(pr, RTS_PROC_STOP);
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 		return;
137433d6423SLionel Sambuc 	}
138433d6423SLionel Sambuc #endif
139433d6423SLionel Sambuc 
140433d6423SLionel Sambuc 	if (get_cpulocal_var(fpu_owner) == pr) {
141433d6423SLionel Sambuc 		disable_fpu_exception();
142433d6423SLionel Sambuc 		save_local_fpu(pr, TRUE /*retain*/);
143433d6423SLionel Sambuc 	}
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc /* reserve a chunk of memory for fpu state; every one has to
147433d6423SLionel Sambuc  * be FPUALIGN-aligned.
148433d6423SLionel Sambuc  */
149433d6423SLionel Sambuc static char fpu_state[NR_PROCS][FPU_XFP_SIZE] __aligned(FPUALIGN);
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc void arch_proc_reset(struct proc *pr)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc 	char *v = NULL;
154433d6423SLionel Sambuc 	struct stackframe_s reg;
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc 	assert(pr->p_nr < NR_PROCS);
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc 	if(pr->p_nr >= 0) {
159433d6423SLionel Sambuc 		v = fpu_state[pr->p_nr];
160433d6423SLionel Sambuc 		/* verify alignment */
161433d6423SLionel Sambuc 		assert(!((vir_bytes)v % FPUALIGN));
162433d6423SLionel Sambuc 		/* initialize state */
163433d6423SLionel Sambuc 		memset(v, 0, FPU_XFP_SIZE);
164433d6423SLionel Sambuc 	}
165433d6423SLionel Sambuc 
166433d6423SLionel Sambuc 	/* Clear process state. */
167433d6423SLionel Sambuc         memset(&reg, 0, sizeof(pr->p_reg));
168433d6423SLionel Sambuc         if(iskerneln(pr->p_nr))
169433d6423SLionel Sambuc         	reg.psw = INIT_TASK_PSW;
170433d6423SLionel Sambuc         else
171433d6423SLionel Sambuc         	reg.psw = INIT_PSW;
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc 	pr->p_seg.fpu_state = v;
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc 	/* Initialize the fundamentals that are (initially) the same for all
176433d6423SLionel Sambuc 	 * processes - the segment selectors it gets to use.
177433d6423SLionel Sambuc 	 */
178433d6423SLionel Sambuc 	pr->p_reg.cs = USER_CS_SELECTOR;
179433d6423SLionel Sambuc 	pr->p_reg.gs =
180433d6423SLionel Sambuc 	pr->p_reg.fs =
181433d6423SLionel Sambuc 	pr->p_reg.ss =
182433d6423SLionel Sambuc 	pr->p_reg.es =
183433d6423SLionel Sambuc 	pr->p_reg.ds = USER_DS_SELECTOR;
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc 	/* set full context and make sure it gets restored */
186433d6423SLionel Sambuc 	arch_proc_setcontext(pr, &reg, 0, KTS_FULLCONTEXT);
187433d6423SLionel Sambuc }
188433d6423SLionel Sambuc 
189433d6423SLionel Sambuc void arch_set_secondary_ipc_return(struct proc *p, u32_t val)
190433d6423SLionel Sambuc {
191433d6423SLionel Sambuc 	p->p_reg.bx = val;
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc int restore_fpu(struct proc *pr)
195433d6423SLionel Sambuc {
196433d6423SLionel Sambuc 	int failed;
197433d6423SLionel Sambuc 	char *state = pr->p_seg.fpu_state;
198433d6423SLionel Sambuc 
199433d6423SLionel Sambuc 	assert(state);
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	if(!proc_used_fpu(pr)) {
202433d6423SLionel Sambuc 		fninit();
203433d6423SLionel Sambuc 		pr->p_misc_flags |= MF_FPU_INITIALIZED;
204433d6423SLionel Sambuc 	} else {
205433d6423SLionel Sambuc 		if(osfxsr_feature) {
206433d6423SLionel Sambuc 			failed = fxrstor(state);
207433d6423SLionel Sambuc 		} else {
208433d6423SLionel Sambuc 			failed = frstor(state);
209433d6423SLionel Sambuc 		}
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc 		if (failed) return EINVAL;
212433d6423SLionel Sambuc 	}
213433d6423SLionel Sambuc 
214433d6423SLionel Sambuc 	return OK;
215433d6423SLionel Sambuc }
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc void cpu_identify(void)
218433d6423SLionel Sambuc {
219433d6423SLionel Sambuc 	u32_t eax, ebx, ecx, edx;
220433d6423SLionel Sambuc 	unsigned cpu = cpuid;
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	eax = 0;
223433d6423SLionel Sambuc 	_cpuid(&eax, &ebx, &ecx, &edx);
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	if (ebx == INTEL_CPUID_GEN_EBX && ecx == INTEL_CPUID_GEN_ECX &&
226433d6423SLionel Sambuc 			edx == INTEL_CPUID_GEN_EDX) {
227433d6423SLionel Sambuc 		cpu_info[cpu].vendor = CPU_VENDOR_INTEL;
228433d6423SLionel Sambuc 	} else if (ebx == AMD_CPUID_GEN_EBX && ecx == AMD_CPUID_GEN_ECX &&
229433d6423SLionel Sambuc 			edx == AMD_CPUID_GEN_EDX) {
230433d6423SLionel Sambuc 		cpu_info[cpu].vendor = CPU_VENDOR_AMD;
231433d6423SLionel Sambuc 	} else
232433d6423SLionel Sambuc 		cpu_info[cpu].vendor = CPU_VENDOR_UNKNOWN;
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc 	if (eax == 0)
235433d6423SLionel Sambuc 		return;
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 	eax = 1;
238433d6423SLionel Sambuc 	_cpuid(&eax, &ebx, &ecx, &edx);
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 	cpu_info[cpu].family = (eax >> 8) & 0xf;
241433d6423SLionel Sambuc 	if (cpu_info[cpu].family == 0xf)
242433d6423SLionel Sambuc 		cpu_info[cpu].family += (eax >> 20) & 0xff;
243433d6423SLionel Sambuc 	cpu_info[cpu].model = (eax >> 4) & 0xf;
244433d6423SLionel Sambuc 	if (cpu_info[cpu].model == 0xf || cpu_info[cpu].model == 0x6)
245433d6423SLionel Sambuc 		cpu_info[cpu].model += ((eax >> 16) & 0xf) << 4 ;
246433d6423SLionel Sambuc 	cpu_info[cpu].stepping = eax & 0xf;
247433d6423SLionel Sambuc 	cpu_info[cpu].flags[0] = ecx;
248433d6423SLionel Sambuc 	cpu_info[cpu].flags[1] = edx;
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc void arch_init(void)
252433d6423SLionel Sambuc {
253433d6423SLionel Sambuc 	k_stacks = (void*) &k_stacks_start;
254433d6423SLionel Sambuc 	assert(!((vir_bytes) k_stacks % K_STACK_SIZE));
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc #ifndef CONFIG_SMP
257433d6423SLionel Sambuc 	/*
258433d6423SLionel Sambuc 	 * use stack 0 and cpu id 0 on a single processor machine, SMP
259433d6423SLionel Sambuc 	 * configuration does this in smp_init() for all cpus at once
260433d6423SLionel Sambuc 	 */
261433d6423SLionel Sambuc 	tss_init(0, get_k_stack_top(0));
262433d6423SLionel Sambuc #endif
263433d6423SLionel Sambuc 
264433d6423SLionel Sambuc #if !CONFIG_OXPCIE
265433d6423SLionel Sambuc 	ser_init();
266433d6423SLionel Sambuc #endif
267433d6423SLionel Sambuc 
268433d6423SLionel Sambuc #ifdef USE_ACPI
269433d6423SLionel Sambuc 	acpi_init();
270433d6423SLionel Sambuc #endif
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc #if defined(USE_APIC) && !defined(CONFIG_SMP)
273433d6423SLionel Sambuc 	if (config_no_apic) {
274da9af514SLionel Sambuc 		DEBUGBASIC(("APIC disabled, using legacy PIC\n"));
275433d6423SLionel Sambuc 	}
276433d6423SLionel Sambuc 	else if (!apic_single_cpu_init()) {
277da9af514SLionel Sambuc 		DEBUGBASIC(("APIC not present, using legacy PIC\n"));
278433d6423SLionel Sambuc 	}
279433d6423SLionel Sambuc #endif
280433d6423SLionel Sambuc 
281433d6423SLionel Sambuc 	/* Reserve some BIOS ranges */
282433d6423SLionel Sambuc 	cut_memmap(&kinfo, BIOS_MEM_BEGIN, BIOS_MEM_END);
283433d6423SLionel Sambuc 	cut_memmap(&kinfo, BASE_MEM_TOP, UPPER_MEM_END);
284433d6423SLionel Sambuc }
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc /*===========================================================================*
287433d6423SLionel Sambuc  *				do_ser_debug				     *
288433d6423SLionel Sambuc  *===========================================================================*/
2896077d1adSDr. Florian Grätz void do_ser_debug(void)
290433d6423SLionel Sambuc {
291433d6423SLionel Sambuc 	u8_t c, lsr;
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc #if CONFIG_OXPCIE
294433d6423SLionel Sambuc 	{
295433d6423SLionel Sambuc 		int oxin;
296433d6423SLionel Sambuc 		if((oxin = oxpcie_in()) >= 0)
297433d6423SLionel Sambuc 		ser_debug(oxin);
298433d6423SLionel Sambuc 	}
299433d6423SLionel Sambuc #endif
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 	lsr= inb(COM1_LSR);
302433d6423SLionel Sambuc 	if (!(lsr & LSR_DR))
303433d6423SLionel Sambuc 		return;
304433d6423SLionel Sambuc 	c = inb(COM1_RBR);
305433d6423SLionel Sambuc 	ser_debug(c);
306433d6423SLionel Sambuc }
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc static void ser_dump_queue_cpu(unsigned cpu)
309433d6423SLionel Sambuc {
310433d6423SLionel Sambuc 	int q;
311433d6423SLionel Sambuc 	struct proc ** rdy_head;
312433d6423SLionel Sambuc 
313433d6423SLionel Sambuc 	rdy_head = get_cpu_var(cpu, run_q_head);
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc 	for(q = 0; q < NR_SCHED_QUEUES; q++) {
316433d6423SLionel Sambuc 		struct proc *p;
317433d6423SLionel Sambuc 		if(rdy_head[q])	 {
318433d6423SLionel Sambuc 			printf("%2d: ", q);
319433d6423SLionel Sambuc 			for(p = rdy_head[q]; p; p = p->p_nextready) {
320433d6423SLionel Sambuc 				printf("%s / %d  ", p->p_name, p->p_endpoint);
321433d6423SLionel Sambuc 			}
322433d6423SLionel Sambuc 			printf("\n");
323433d6423SLionel Sambuc 		}
324433d6423SLionel Sambuc 	}
325433d6423SLionel Sambuc }
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc static void ser_dump_queues(void)
328433d6423SLionel Sambuc {
329433d6423SLionel Sambuc #ifdef CONFIG_SMP
330433d6423SLionel Sambuc 	unsigned cpu;
331433d6423SLionel Sambuc 
332433d6423SLionel Sambuc 	printf("--- run queues ---\n");
333433d6423SLionel Sambuc 	for (cpu = 0; cpu < ncpus; cpu++) {
334433d6423SLionel Sambuc 		printf("CPU %d :\n", cpu);
335433d6423SLionel Sambuc 		ser_dump_queue_cpu(cpu);
336433d6423SLionel Sambuc 	}
337433d6423SLionel Sambuc #else
338433d6423SLionel Sambuc 	ser_dump_queue_cpu(0);
339433d6423SLionel Sambuc #endif
340433d6423SLionel Sambuc }
341433d6423SLionel Sambuc 
342433d6423SLionel Sambuc #ifdef CONFIG_SMP
343433d6423SLionel Sambuc static void dump_bkl_usage(void)
344433d6423SLionel Sambuc {
345433d6423SLionel Sambuc 	unsigned cpu;
346433d6423SLionel Sambuc 
347433d6423SLionel Sambuc 	printf("--- BKL usage ---\n");
348433d6423SLionel Sambuc 	for (cpu = 0; cpu < ncpus; cpu++) {
349433d6423SLionel Sambuc 		printf("cpu %3d kernel ticks 0x%x%08x bkl ticks 0x%x%08x succ %d tries %d\n", cpu,
350433d6423SLionel Sambuc 				ex64hi(kernel_ticks[cpu]),
351433d6423SLionel Sambuc 				ex64lo(kernel_ticks[cpu]),
352433d6423SLionel Sambuc 				ex64hi(bkl_ticks[cpu]),
353433d6423SLionel Sambuc 				ex64lo(bkl_ticks[cpu]),
354433d6423SLionel Sambuc 				bkl_succ[cpu], bkl_tries[cpu]);
355433d6423SLionel Sambuc 	}
356433d6423SLionel Sambuc }
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc static void reset_bkl_usage(void)
359433d6423SLionel Sambuc {
360433d6423SLionel Sambuc 	memset(kernel_ticks, 0, sizeof(kernel_ticks));
361433d6423SLionel Sambuc 	memset(bkl_ticks, 0, sizeof(bkl_ticks));
362433d6423SLionel Sambuc 	memset(bkl_tries, 0, sizeof(bkl_tries));
363433d6423SLionel Sambuc 	memset(bkl_succ, 0, sizeof(bkl_succ));
364433d6423SLionel Sambuc }
365433d6423SLionel Sambuc #endif
366433d6423SLionel Sambuc 
367433d6423SLionel Sambuc static void ser_debug(const int c)
368433d6423SLionel Sambuc {
369433d6423SLionel Sambuc 	serial_debug_active = 1;
370433d6423SLionel Sambuc 
371433d6423SLionel Sambuc 	switch(c)
372433d6423SLionel Sambuc 	{
373433d6423SLionel Sambuc 	case 'Q':
374*cfd712b4SDavid van Moolenbroek 		minix_shutdown(0);
375433d6423SLionel Sambuc 		NOT_REACHABLE;
376433d6423SLionel Sambuc #ifdef CONFIG_SMP
377433d6423SLionel Sambuc 	case 'B':
378433d6423SLionel Sambuc 		dump_bkl_usage();
379433d6423SLionel Sambuc 		break;
380433d6423SLionel Sambuc 	case 'b':
381433d6423SLionel Sambuc 		reset_bkl_usage();
382433d6423SLionel Sambuc 		break;
383433d6423SLionel Sambuc #endif
384433d6423SLionel Sambuc 	case '1':
385433d6423SLionel Sambuc 		ser_dump_proc();
386433d6423SLionel Sambuc 		break;
387433d6423SLionel Sambuc 	case '2':
388433d6423SLionel Sambuc 		ser_dump_queues();
389433d6423SLionel Sambuc 		break;
390433d6423SLionel Sambuc #ifdef CONFIG_SMP
391433d6423SLionel Sambuc 	case '4':
392433d6423SLionel Sambuc 		ser_dump_proc_cpu();
393433d6423SLionel Sambuc 		break;
394433d6423SLionel Sambuc #endif
395433d6423SLionel Sambuc 	case '5':
396433d6423SLionel Sambuc 		ser_dump_vfs();
397433d6423SLionel Sambuc 		break;
398433d6423SLionel Sambuc #if DEBUG_TRACE
399433d6423SLionel Sambuc #define TOGGLECASE(ch, flag)				\
400433d6423SLionel Sambuc 	case ch: {					\
401433d6423SLionel Sambuc 		if(verboseflags & flag)	{		\
402433d6423SLionel Sambuc 			verboseflags &= ~flag;		\
403433d6423SLionel Sambuc 			printf("%s disabled\n", #flag);	\
404433d6423SLionel Sambuc 		} else {				\
405433d6423SLionel Sambuc 			verboseflags |= flag;		\
406433d6423SLionel Sambuc 			printf("%s enabled\n", #flag);	\
407433d6423SLionel Sambuc 		}					\
408433d6423SLionel Sambuc 		break;					\
409433d6423SLionel Sambuc 		}
410433d6423SLionel Sambuc 	TOGGLECASE('8', VF_SCHEDULING)
411433d6423SLionel Sambuc 	TOGGLECASE('9', VF_PICKPROC)
412433d6423SLionel Sambuc #endif
413433d6423SLionel Sambuc #ifdef USE_APIC
414433d6423SLionel Sambuc 	case 'I':
415433d6423SLionel Sambuc 		dump_apic_irq_state();
416433d6423SLionel Sambuc 		break;
417433d6423SLionel Sambuc #endif
418433d6423SLionel Sambuc 	}
419433d6423SLionel Sambuc 	serial_debug_active = 0;
420433d6423SLionel Sambuc }
421433d6423SLionel Sambuc 
422433d6423SLionel Sambuc #if DEBUG_SERIAL
423433d6423SLionel Sambuc 
4246077d1adSDr. Florian Grätz static void ser_dump_vfs(void)
425433d6423SLionel Sambuc {
426433d6423SLionel Sambuc 	/* Notify VFS it has to generate stack traces. Kernel can't do that as
427433d6423SLionel Sambuc 	 * it's not aware of user space threads.
428433d6423SLionel Sambuc 	 */
429433d6423SLionel Sambuc 	mini_notify(proc_addr(KERNEL), VFS_PROC_NR);
430433d6423SLionel Sambuc }
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc #ifdef CONFIG_SMP
433433d6423SLionel Sambuc static void ser_dump_proc_cpu(void)
434433d6423SLionel Sambuc {
435433d6423SLionel Sambuc 	struct proc *pp;
436433d6423SLionel Sambuc 	unsigned cpu;
437433d6423SLionel Sambuc 
438433d6423SLionel Sambuc 	for (cpu = 0; cpu < ncpus; cpu++) {
439433d6423SLionel Sambuc 		printf("CPU %d processes : \n", cpu);
440433d6423SLionel Sambuc 		for (pp= BEG_USER_ADDR; pp < END_PROC_ADDR; pp++) {
441433d6423SLionel Sambuc 			if (isemptyp(pp) || pp->p_cpu != cpu)
442433d6423SLionel Sambuc 				continue;
443433d6423SLionel Sambuc 			print_proc(pp);
444433d6423SLionel Sambuc 		}
445433d6423SLionel Sambuc 	}
446433d6423SLionel Sambuc }
447433d6423SLionel Sambuc #endif
448433d6423SLionel Sambuc 
449433d6423SLionel Sambuc #endif /* DEBUG_SERIAL */
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc #if SPROFILE
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc int arch_init_profile_clock(const u32_t freq)
454433d6423SLionel Sambuc {
455433d6423SLionel Sambuc   int r;
456433d6423SLionel Sambuc   /* Set CMOS timer frequency. */
457433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_A);
458433d6423SLionel Sambuc   outb(RTC_IO, RTC_A_DV_OK | freq);
459433d6423SLionel Sambuc   /* Enable CMOS timer interrupts. */
460433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_B);
461433d6423SLionel Sambuc   r = inb(RTC_IO);
462433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_B);
463433d6423SLionel Sambuc   outb(RTC_IO, r | RTC_B_PIE);
464433d6423SLionel Sambuc   /* Mandatory read of CMOS register to enable timer interrupts. */
465433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_C);
466433d6423SLionel Sambuc   inb(RTC_IO);
467433d6423SLionel Sambuc 
468433d6423SLionel Sambuc   return CMOS_CLOCK_IRQ;
469433d6423SLionel Sambuc }
470433d6423SLionel Sambuc 
471433d6423SLionel Sambuc void arch_stop_profile_clock(void)
472433d6423SLionel Sambuc {
473433d6423SLionel Sambuc   int r;
474433d6423SLionel Sambuc   /* Disable CMOS timer interrupts. */
475433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_B);
476433d6423SLionel Sambuc   r = inb(RTC_IO);
477433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_B);
478433d6423SLionel Sambuc   outb(RTC_IO, r & ~RTC_B_PIE);
479433d6423SLionel Sambuc }
480433d6423SLionel Sambuc 
481433d6423SLionel Sambuc void arch_ack_profile_clock(void)
482433d6423SLionel Sambuc {
483433d6423SLionel Sambuc   /* Mandatory read of CMOS register to re-enable timer interrupts. */
484433d6423SLionel Sambuc   outb(RTC_INDEX, RTC_REG_C);
485433d6423SLionel Sambuc   inb(RTC_IO);
486433d6423SLionel Sambuc }
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc #endif
489433d6423SLionel Sambuc 
490433d6423SLionel Sambuc void arch_do_syscall(struct proc *proc)
491433d6423SLionel Sambuc {
492433d6423SLionel Sambuc   /* do_ipc assumes that it's running because of the current process */
493433d6423SLionel Sambuc   assert(proc == get_cpulocal_var(proc_ptr));
494433d6423SLionel Sambuc   /* Make the system call, for real this time. */
495433d6423SLionel Sambuc   assert(proc->p_misc_flags & MF_SC_DEFER);
496433d6423SLionel Sambuc   proc->p_reg.retreg =
497433d6423SLionel Sambuc 	  do_ipc(proc->p_defer.r1, proc->p_defer.r2, proc->p_defer.r3);
498433d6423SLionel Sambuc }
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc struct proc * arch_finish_switch_to_user(void)
501433d6423SLionel Sambuc {
502433d6423SLionel Sambuc 	char * stk;
503433d6423SLionel Sambuc 	struct proc * p;
504433d6423SLionel Sambuc 
505433d6423SLionel Sambuc #ifdef CONFIG_SMP
506433d6423SLionel Sambuc 	stk = (char *)tss[cpuid].sp0;
507433d6423SLionel Sambuc #else
508433d6423SLionel Sambuc 	stk = (char *)tss[0].sp0;
509433d6423SLionel Sambuc #endif
510433d6423SLionel Sambuc 	/* set pointer to the process to run on the stack */
511433d6423SLionel Sambuc 	p = get_cpulocal_var(proc_ptr);
512433d6423SLionel Sambuc 	*((reg_t *)stk) = (reg_t) p;
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc 	/* make sure IF is on in FLAGS so that interrupts won't be disabled
515433d6423SLionel Sambuc 	 * once p's context is restored.
516433d6423SLionel Sambuc 	 */
517433d6423SLionel Sambuc         p->p_reg.psw |= IF_MASK;
518433d6423SLionel Sambuc 
519433d6423SLionel Sambuc 	/* Set TRACEBIT state properly. */
520433d6423SLionel Sambuc 	if(p->p_misc_flags & MF_STEP)
521433d6423SLionel Sambuc         	p->p_reg.psw |= TRACEBIT;
522433d6423SLionel Sambuc 	else
523433d6423SLionel Sambuc         	p->p_reg.psw &= ~TRACEBIT;
524433d6423SLionel Sambuc 
525433d6423SLionel Sambuc 	return p;
526433d6423SLionel Sambuc }
527433d6423SLionel Sambuc 
528433d6423SLionel Sambuc void arch_proc_setcontext(struct proc *p, struct stackframe_s *state,
529433d6423SLionel Sambuc 	int isuser, int trap_style)
530433d6423SLionel Sambuc {
531433d6423SLionel Sambuc 	if(isuser) {
532433d6423SLionel Sambuc 		/* Restore user bits of psw from sc, maintain system bits
533433d6423SLionel Sambuc 		 * from proc.
534433d6423SLionel Sambuc 		 */
535433d6423SLionel Sambuc 		state->psw  =  (state->psw & X86_FLAGS_USER) |
536433d6423SLionel Sambuc 			(p->p_reg.psw & ~X86_FLAGS_USER);
537433d6423SLionel Sambuc 	}
538433d6423SLionel Sambuc 
539433d6423SLionel Sambuc 	/* someone wants to totally re-initialize process state */
540433d6423SLionel Sambuc 	assert(sizeof(p->p_reg) == sizeof(*state));
541433d6423SLionel Sambuc 	if(state != &p->p_reg) {
542433d6423SLionel Sambuc 		memcpy(&p->p_reg, state, sizeof(*state));
543433d6423SLionel Sambuc 	}
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc 	/* further code is instructed to not touch the context
546433d6423SLionel Sambuc 	 * any more
547433d6423SLionel Sambuc 	 */
548433d6423SLionel Sambuc 	p->p_misc_flags |= MF_CONTEXT_SET;
549433d6423SLionel Sambuc 
550433d6423SLionel Sambuc 	/* on x86 this requires returning using iret (KTS_INT)
551433d6423SLionel Sambuc 	 * so that the full context is restored instead of relying on
552433d6423SLionel Sambuc 	 * the userspace doing it (as it would do on SYSEXIT).
553433d6423SLionel Sambuc 	 * as ESP and EIP are also reset, userspace won't try to
554433d6423SLionel Sambuc 	 * restore bogus context after returning.
555433d6423SLionel Sambuc 	 *
556433d6423SLionel Sambuc 	 * if the process is not blocked, or the kernel will ignore
557433d6423SLionel Sambuc 	 * our trap style, we needn't panic but things will probably
558433d6423SLionel Sambuc 	 * not go well for the process (restored context will be ignored)
559433d6423SLionel Sambuc 	 * and the situation should be debugged.
560433d6423SLionel Sambuc 	 */
561433d6423SLionel Sambuc 	if(!(p->p_rts_flags)) {
562433d6423SLionel Sambuc 		printf("WARNINIG: setting full context of runnable process\n");
563433d6423SLionel Sambuc 		print_proc(p);
564433d6423SLionel Sambuc 		util_stacktrace();
565433d6423SLionel Sambuc 	}
566433d6423SLionel Sambuc 	if(p->p_seg.p_kern_trap_style == KTS_NONE)
567433d6423SLionel Sambuc 		printf("WARNINIG: setting full context of out-of-kernel process\n");
568433d6423SLionel Sambuc 	p->p_seg.p_kern_trap_style = trap_style;
569433d6423SLionel Sambuc }
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc void restore_user_context(struct proc *p)
572433d6423SLionel Sambuc {
573433d6423SLionel Sambuc 	int trap_style = p->p_seg.p_kern_trap_style;
574433d6423SLionel Sambuc #if 0
575433d6423SLionel Sambuc #define TYPES 10
576433d6423SLionel Sambuc 	static int restores[TYPES], n = 0;
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc 	if(trap_style >= 0 && trap_style < TYPES)
579433d6423SLionel Sambuc 		restores[trap_style]++;
580433d6423SLionel Sambuc 
581433d6423SLionel Sambuc 	if(!(n++ % 500000)) {
582433d6423SLionel Sambuc 		int t;
583433d6423SLionel Sambuc 		for(t = 0; t < TYPES; t++)
584433d6423SLionel Sambuc 			if(restores[t])
585433d6423SLionel Sambuc 				printf("%d: %d   ", t, restores[t]);
586433d6423SLionel Sambuc 		printf("\n");
587433d6423SLionel Sambuc 	}
588433d6423SLionel Sambuc #endif
589433d6423SLionel Sambuc 
590433d6423SLionel Sambuc 	p->p_seg.p_kern_trap_style = KTS_NONE;
591433d6423SLionel Sambuc 
592433d6423SLionel Sambuc 	if(trap_style == KTS_SYSENTER) {
593433d6423SLionel Sambuc 		restore_user_context_sysenter(p);
594433d6423SLionel Sambuc 		NOT_REACHABLE;
595433d6423SLionel Sambuc         }
596433d6423SLionel Sambuc 
597433d6423SLionel Sambuc 	if(trap_style == KTS_SYSCALL) {
598433d6423SLionel Sambuc 		restore_user_context_syscall(p);
599433d6423SLionel Sambuc 		NOT_REACHABLE;
600433d6423SLionel Sambuc 	}
601433d6423SLionel Sambuc 
602433d6423SLionel Sambuc         switch(trap_style) {
603433d6423SLionel Sambuc                 case KTS_NONE:
604433d6423SLionel Sambuc                         panic("no entry trap style known");
605433d6423SLionel Sambuc                 case KTS_INT_HARD:
606433d6423SLionel Sambuc                 case KTS_INT_UM:
607433d6423SLionel Sambuc                 case KTS_FULLCONTEXT:
608433d6423SLionel Sambuc                 case KTS_INT_ORIG:
609433d6423SLionel Sambuc 			restore_user_context_int(p);
610433d6423SLionel Sambuc 			NOT_REACHABLE;
611433d6423SLionel Sambuc                 default:
612433d6423SLionel Sambuc                         panic("unknown trap style recorded");
613433d6423SLionel Sambuc                         NOT_REACHABLE;
614433d6423SLionel Sambuc         }
615433d6423SLionel Sambuc 
616433d6423SLionel Sambuc         NOT_REACHABLE;
617433d6423SLionel Sambuc }
618433d6423SLionel Sambuc 
619433d6423SLionel Sambuc void fpu_sigcontext(struct proc *pr, struct sigframe_sigcontext *fr, struct sigcontext *sc)
620433d6423SLionel Sambuc {
621433d6423SLionel Sambuc 	int fp_error;
622433d6423SLionel Sambuc 
623433d6423SLionel Sambuc 	if (osfxsr_feature) {
624433d6423SLionel Sambuc 		fp_error = sc->sc_fpu_state.xfp_regs.fp_status &
625433d6423SLionel Sambuc 			~sc->sc_fpu_state.xfp_regs.fp_control;
626433d6423SLionel Sambuc 	} else {
627433d6423SLionel Sambuc 		fp_error = sc->sc_fpu_state.fpu_regs.fp_status &
628433d6423SLionel Sambuc 			~sc->sc_fpu_state.fpu_regs.fp_control;
629433d6423SLionel Sambuc 	}
630433d6423SLionel Sambuc 
631433d6423SLionel Sambuc 	if (fp_error & 0x001) {      /* Invalid op */
632433d6423SLionel Sambuc 		/*
633433d6423SLionel Sambuc 		 * swd & 0x240 == 0x040: Stack Underflow
634433d6423SLionel Sambuc 		 * swd & 0x240 == 0x240: Stack Overflow
635433d6423SLionel Sambuc 		 * User must clear the SF bit (0x40) if set
636433d6423SLionel Sambuc 		 */
637433d6423SLionel Sambuc 		fr->sf_code = FPE_FLTINV;
638433d6423SLionel Sambuc 	} else if (fp_error & 0x004) {
639433d6423SLionel Sambuc 		fr->sf_code = FPE_FLTDIV; /* Divide by Zero */
640433d6423SLionel Sambuc 	} else if (fp_error & 0x008) {
641433d6423SLionel Sambuc 		fr->sf_code = FPE_FLTOVF; /* Overflow */
642433d6423SLionel Sambuc 	} else if (fp_error & 0x012) {
643433d6423SLionel Sambuc 		fr->sf_code = FPE_FLTUND; /* Denormal, Underflow */
644433d6423SLionel Sambuc 	} else if (fp_error & 0x020) {
645433d6423SLionel Sambuc 		fr->sf_code = FPE_FLTRES; /* Precision */
646433d6423SLionel Sambuc 	} else {
647433d6423SLionel Sambuc 		fr->sf_code = 0;  /* XXX - probably should be used for FPE_INTOVF or
648433d6423SLionel Sambuc 				  * FPE_INTDIV */
649433d6423SLionel Sambuc 	}
650433d6423SLionel Sambuc }
651433d6423SLionel Sambuc 
652433d6423SLionel Sambuc reg_t arch_get_sp(struct proc *p) { return p->p_reg.sp; }
653433d6423SLionel Sambuc 
654433d6423SLionel Sambuc #if !CONFIG_OXPCIE
655433d6423SLionel Sambuc static void ser_init(void)
656433d6423SLionel Sambuc {
657433d6423SLionel Sambuc 	unsigned char lcr;
658433d6423SLionel Sambuc 	unsigned divisor;
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc 	/* keep BIOS settings if cttybaud is not set */
661433d6423SLionel Sambuc 	if (kinfo.serial_debug_baud <= 0) return;
662433d6423SLionel Sambuc 
663433d6423SLionel Sambuc 	/* set DLAB to make baud accessible */
664433d6423SLionel Sambuc 	lcr = LCR_8BIT | LCR_1STOP | LCR_NPAR;
665433d6423SLionel Sambuc 	outb(COM1_LCR, lcr | LCR_DLAB);
666433d6423SLionel Sambuc 
667433d6423SLionel Sambuc 	/* set baud rate */
668433d6423SLionel Sambuc 	divisor = UART_BASE_FREQ / kinfo.serial_debug_baud;
669433d6423SLionel Sambuc 	if (divisor < 1) divisor = 1;
670433d6423SLionel Sambuc 	if (divisor > 65535) divisor = 65535;
671433d6423SLionel Sambuc 
672433d6423SLionel Sambuc 	outb(COM1_DLL, divisor & 0xff);
673433d6423SLionel Sambuc 	outb(COM1_DLM, (divisor >> 8) & 0xff);
674433d6423SLionel Sambuc 
675433d6423SLionel Sambuc 	/* clear DLAB */
676433d6423SLionel Sambuc 	outb(COM1_LCR, lcr);
677433d6423SLionel Sambuc }
678433d6423SLionel Sambuc #endif
679