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