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(®, 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, ®, 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