18368e25fSAaron LI /* 28368e25fSAaron LI * Copyright (c) 2018 The NetBSD Foundation, Inc. All rights reserved. 38368e25fSAaron LI * 48368e25fSAaron LI * This code is derived from software contributed to The NetBSD Foundation 58368e25fSAaron LI * by Maxime Villard. 68368e25fSAaron LI * 78368e25fSAaron LI * Redistribution and use in source and binary forms, with or without 88368e25fSAaron LI * modification, are permitted provided that the following conditions 98368e25fSAaron LI * are met: 108368e25fSAaron LI * 1. Redistributions of source code must retain the above copyright 118368e25fSAaron LI * notice, this list of conditions and the following disclaimer. 128368e25fSAaron LI * 2. Redistributions in binary form must reproduce the above copyright 138368e25fSAaron LI * notice, this list of conditions and the following disclaimer in the 148368e25fSAaron LI * documentation and/or other materials provided with the distribution. 158368e25fSAaron LI * 168368e25fSAaron LI * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 178368e25fSAaron LI * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 188368e25fSAaron LI * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 198368e25fSAaron LI * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 208368e25fSAaron LI * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 218368e25fSAaron LI * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 228368e25fSAaron LI * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 238368e25fSAaron LI * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 248368e25fSAaron LI * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 258368e25fSAaron LI * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 268368e25fSAaron LI * POSSIBILITY OF SUCH DAMAGE. 278368e25fSAaron LI */ 288368e25fSAaron LI 298368e25fSAaron LI #include "smallkern.h" 30*aaa1e810SAaron LI #include "pdir.h" 31*aaa1e810SAaron LI #include "trap.h" 328368e25fSAaron LI 338368e25fSAaron LI #include <machine/reg.h> 348368e25fSAaron LI #include <machine/specialreg.h> 358368e25fSAaron LI #include <machine/frame.h> 368368e25fSAaron LI #include <machine/tss.h> 378368e25fSAaron LI #include <machine/segments.h> 388368e25fSAaron LI 398368e25fSAaron LI /* GDT offsets */ 408368e25fSAaron LI #define SMALLKERN_GDT_NUL_OFF (0 * 8) 418368e25fSAaron LI #define SMALLKERN_GDT_CS_OFF (1 * 8) 428368e25fSAaron LI #define SMALLKERN_GDT_DS_OFF (2 * 8) 438368e25fSAaron LI #define SMALLKERN_GDT_TSS_OFF (3 * 8) 448368e25fSAaron LI 458368e25fSAaron LI void fatal(char *msg) 468368e25fSAaron LI { 478368e25fSAaron LI print("\n"); 488368e25fSAaron LI print_ext(RED_ON_BLACK, "********** FATAL ***********\n"); 498368e25fSAaron LI print_ext(RED_ON_BLACK, msg); 508368e25fSAaron LI print("\n"); 518368e25fSAaron LI print_ext(RED_ON_BLACK, "****************************\n"); 528368e25fSAaron LI 538368e25fSAaron LI while (1); 548368e25fSAaron LI } 558368e25fSAaron LI 568368e25fSAaron LI /* -------------------------------------------------------------------------- */ 578368e25fSAaron LI 588368e25fSAaron LI struct smallframe { 598368e25fSAaron LI uint64_t sf_trapno; 608368e25fSAaron LI uint64_t sf_err; 618368e25fSAaron LI uint64_t sf_rip; 628368e25fSAaron LI uint64_t sf_cs; 638368e25fSAaron LI uint64_t sf_rflags; 648368e25fSAaron LI uint64_t sf_rsp; 658368e25fSAaron LI uint64_t sf_ss; 668368e25fSAaron LI }; 678368e25fSAaron LI 688368e25fSAaron LI static void setregion(struct region_descriptor *, void *, uint16_t); 698368e25fSAaron LI static void setgate(struct gate_descriptor *, void *, int, int, int, int); 708368e25fSAaron LI static void set_sys_segment(struct sys_segment_descriptor *, void *, 718368e25fSAaron LI size_t, int, int, int); 728368e25fSAaron LI static void set_sys_gdt(int, void *, size_t, int, int, int); 738368e25fSAaron LI static void init_tss(void); 748368e25fSAaron LI static void init_idt(void); 758368e25fSAaron LI 768368e25fSAaron LI static char *trap_type[] = { 778368e25fSAaron LI "privileged instruction fault", /* 0 T_PRIVINFLT */ 788368e25fSAaron LI "breakpoint trap", /* 1 T_BPTFLT */ 798368e25fSAaron LI "arithmetic trap", /* 2 T_ARITHTRAP */ 808368e25fSAaron LI "asynchronous system trap", /* 3 T_ASTFLT */ 818368e25fSAaron LI "protection fault", /* 4 T_PROTFLT */ 828368e25fSAaron LI "trace trap", /* 5 T_TRCTRAP */ 838368e25fSAaron LI "page fault", /* 6 T_PAGEFLT */ 848368e25fSAaron LI "alignment fault", /* 7 T_ALIGNFLT */ 858368e25fSAaron LI "integer divide fault", /* 8 T_DIVIDE */ 868368e25fSAaron LI "non-maskable interrupt", /* 9 T_NMI */ 878368e25fSAaron LI "overflow trap", /* 10 T_OFLOW */ 888368e25fSAaron LI "bounds check fault", /* 11 T_BOUND */ 898368e25fSAaron LI "FPU not available fault", /* 12 T_DNA */ 908368e25fSAaron LI "double fault", /* 13 T_DOUBLEFLT */ 918368e25fSAaron LI "FPU operand fetch fault", /* 14 T_FPOPFLT */ 928368e25fSAaron LI "invalid TSS fault", /* 15 T_TSSFLT */ 938368e25fSAaron LI "segment not present fault", /* 16 T_SEGNPFLT */ 948368e25fSAaron LI "stack fault", /* 17 T_STKFLT */ 958368e25fSAaron LI "machine check fault", /* 18 T_MCA */ 968368e25fSAaron LI "SSE FP exception", /* 19 T_XMM */ 978368e25fSAaron LI "hardware interrupt", /* 20 T_RESERVED */ 988368e25fSAaron LI }; 99ce7051aeSAaron LI size_t trap_types = __arraycount(trap_type); 1008368e25fSAaron LI 101*aaa1e810SAaron LI static uint8_t idtstore[PAGE_SIZE] __aligned(PAGE_SIZE); 102*aaa1e810SAaron LI static uint8_t faultstack[PAGE_SIZE] __aligned(PAGE_SIZE); 103*aaa1e810SAaron LI static struct x86_64_tss smallkern_tss; 104*aaa1e810SAaron LI 1058368e25fSAaron LI static void 1068368e25fSAaron LI triple_fault(void) 1078368e25fSAaron LI { 1088368e25fSAaron LI char *p = NULL; 1098368e25fSAaron LI memset(&idtstore, 0, PAGE_SIZE); 1108368e25fSAaron LI *p = 0; 1118368e25fSAaron LI } 1128368e25fSAaron LI 1138368e25fSAaron LI /* 1148368e25fSAaron LI * Trap handler. 1158368e25fSAaron LI */ 1168368e25fSAaron LI void 1178368e25fSAaron LI trap(struct smallframe *sf) 1188368e25fSAaron LI { 1198368e25fSAaron LI uint64_t trapno = sf->sf_trapno; 1208368e25fSAaron LI static int ntrap = 0; 1218368e25fSAaron LI static float f = 0.0; 1228368e25fSAaron LI char *buf; 1238368e25fSAaron LI 1248368e25fSAaron LI f += 1.0f; 1258368e25fSAaron LI if (ntrap++ == 10) { 1268368e25fSAaron LI triple_fault(); 1278368e25fSAaron LI } 1288368e25fSAaron LI if (ntrap != (int)f) { 1298368e25fSAaron LI print_ext(RED_ON_BLACK, "!!! FPU BUG !!!\n"); 1308368e25fSAaron LI } 1318368e25fSAaron LI 1328368e25fSAaron LI if (trapno < trap_types) { 1338368e25fSAaron LI buf = trap_type[trapno]; 1348368e25fSAaron LI } else { 1358368e25fSAaron LI buf = "unknown trap"; 1368368e25fSAaron LI } 1378368e25fSAaron LI 1388368e25fSAaron LI if (trapno == T_RESERVED) { 1398368e25fSAaron LI /* Disable external interrupts. */ 1408368e25fSAaron LI lcr8(15); 1418368e25fSAaron LI } 1428368e25fSAaron LI 1438368e25fSAaron LI print("\n"); 1448368e25fSAaron LI print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n"); 1458368e25fSAaron LI print_ext(RED_ON_BLACK, buf); 1468368e25fSAaron LI print("\n"); 1478368e25fSAaron LI print_ext(RED_ON_BLACK, "****************************\n"); 1488368e25fSAaron LI 1498368e25fSAaron LI sti(); 1508368e25fSAaron LI 1518368e25fSAaron LI while (1); 1528368e25fSAaron LI } 1538368e25fSAaron LI 1548368e25fSAaron LI static void 1558368e25fSAaron LI setregion(struct region_descriptor *rd, void *base, uint16_t limit) 1568368e25fSAaron LI { 1578368e25fSAaron LI rd->rd_limit = limit; 1588368e25fSAaron LI rd->rd_base = (uint64_t)base; 1598368e25fSAaron LI } 1608368e25fSAaron LI 1618368e25fSAaron LI static void 1628368e25fSAaron LI setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl, 1638368e25fSAaron LI int sel) 1648368e25fSAaron LI { 1658368e25fSAaron LI gd->gd_looffset = (uint64_t)func & 0xffff; 1668368e25fSAaron LI gd->gd_selector = sel; 1678368e25fSAaron LI gd->gd_ist = ist; 1688368e25fSAaron LI gd->gd_type = type; 1698368e25fSAaron LI gd->gd_dpl = dpl; 1708368e25fSAaron LI gd->gd_p = 1; 1718368e25fSAaron LI gd->gd_hioffset = (uint64_t)func >> 16; 1728368e25fSAaron LI gd->gd_zero = 0; 1738368e25fSAaron LI gd->gd_xx1 = 0; 1748368e25fSAaron LI gd->gd_xx2 = 0; 1758368e25fSAaron LI gd->gd_xx3 = 0; 1768368e25fSAaron LI } 1778368e25fSAaron LI 1788368e25fSAaron LI static void 1798368e25fSAaron LI set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit, 1808368e25fSAaron LI int type, int dpl, int gran) 1818368e25fSAaron LI { 1828368e25fSAaron LI memset(sd, 0, sizeof(*sd)); 1838368e25fSAaron LI sd->sd_lolimit = (unsigned)limit; 1848368e25fSAaron LI sd->sd_lobase = (uint64_t)base; 1858368e25fSAaron LI sd->sd_type = type; 1868368e25fSAaron LI sd->sd_dpl = dpl; 1878368e25fSAaron LI sd->sd_p = 1; 1888368e25fSAaron LI sd->sd_hilimit = (unsigned)limit >> 16; 1898368e25fSAaron LI sd->sd_gran = gran; 1908368e25fSAaron LI sd->sd_hibase = (uint64_t)base >> 24; 1918368e25fSAaron LI } 1928368e25fSAaron LI 1938368e25fSAaron LI static void 1948368e25fSAaron LI set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran) 1958368e25fSAaron LI { 1968368e25fSAaron LI struct sys_segment_descriptor sd; 1978368e25fSAaron LI 1988368e25fSAaron LI set_sys_segment(&sd, base, limit, type, dpl, gran); 1998368e25fSAaron LI 2008368e25fSAaron LI memcpy(&gdt64_start + slotoff, &sd, sizeof(sd)); 2018368e25fSAaron LI } 2028368e25fSAaron LI 2038368e25fSAaron LI static void init_tss(void) 2048368e25fSAaron LI { 2058368e25fSAaron LI memset(&smallkern_tss, 0, sizeof(smallkern_tss)); 2068368e25fSAaron LI smallkern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf; 2078368e25fSAaron LI 2088368e25fSAaron LI set_sys_gdt(SMALLKERN_GDT_TSS_OFF, &smallkern_tss, 2098368e25fSAaron LI sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0); 2108368e25fSAaron LI } 2118368e25fSAaron LI 2128368e25fSAaron LI static void init_idt(void) 2138368e25fSAaron LI { 2148368e25fSAaron LI struct region_descriptor region; 2158368e25fSAaron LI struct gate_descriptor *idt; 2168368e25fSAaron LI size_t i; 2178368e25fSAaron LI 2188368e25fSAaron LI idt = (struct gate_descriptor *)&idtstore; 2198368e25fSAaron LI for (i = 0; i < NCPUIDT; i++) { 2208368e25fSAaron LI setgate(&idt[i], x86_exceptions[i], 0, SDT_SYS386IGT, 2218368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 2228368e25fSAaron LI } 2238368e25fSAaron LI for (i = NCPUIDT; i < 256; i++) { 2248368e25fSAaron LI setgate(&idt[i], &Xintr, 0, SDT_SYS386IGT, 2258368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 2268368e25fSAaron LI } 2278368e25fSAaron LI 2288368e25fSAaron LI setregion(®ion, &idtstore, PAGE_SIZE - 1); 2298368e25fSAaron LI lidt(®ion); 2308368e25fSAaron LI } 2318368e25fSAaron LI 2328368e25fSAaron LI /* -------------------------------------------------------------------------- */ 2338368e25fSAaron LI 2348368e25fSAaron LI /* 2358368e25fSAaron LI * Main entry point of the kernel. 2368368e25fSAaron LI */ 2378368e25fSAaron LI void 238ce7051aeSAaron LI main(paddr_t pa_start __unused) 2398368e25fSAaron LI { 2408368e25fSAaron LI u_int descs[4]; 2418368e25fSAaron LI uint32_t *reg, val; 2428368e25fSAaron LI 2438368e25fSAaron LI print_banner(); 2448368e25fSAaron LI 2458368e25fSAaron LI /* 2468368e25fSAaron LI * Init the TSS and IDT. We mostly don't care about this, they are just 2478368e25fSAaron LI * here to properly handle traps. 2488368e25fSAaron LI */ 2498368e25fSAaron LI init_tss(); 2508368e25fSAaron LI print_state(true, "TSS created"); 2518368e25fSAaron LI init_idt(); 2528368e25fSAaron LI print_state(true, "IDT created"); 2538368e25fSAaron LI 2548368e25fSAaron LI /* Reset CR8. */ 2558368e25fSAaron LI lcr8(0); 2568368e25fSAaron LI 2578368e25fSAaron LI /* Enable FPU. */ 2588368e25fSAaron LI clts(); 2598368e25fSAaron LI 2608368e25fSAaron LI /* Enable interrupts. */ 2618368e25fSAaron LI sti(); 2628368e25fSAaron LI 2638368e25fSAaron LI /* Ensure APICBASE is correct (default). */ 2648368e25fSAaron LI if ((rdmsr(MSR_APICBASE) & APICBASE_PHYSADDR) == 0xfee00000) { 2658368e25fSAaron LI print_state(true, "APICBASE is correct"); 2668368e25fSAaron LI } else { 2678368e25fSAaron LI print_state(false, "wrong APICBASE"); 2688368e25fSAaron LI } 2698368e25fSAaron LI 2708368e25fSAaron LI /* Ensure PG_NX is disabled. */ 2718368e25fSAaron LI if (!nox_flag) { 2728368e25fSAaron LI print_state(true, "PG_NX is disabled"); 2738368e25fSAaron LI } else { 2748368e25fSAaron LI print_state(false, "PG_NX is enabled!"); 2758368e25fSAaron LI } 2768368e25fSAaron LI 2778368e25fSAaron LI /* Ensure we are on cpu120. */ 2788368e25fSAaron LI cpuid(1, 0, descs); 2798368e25fSAaron LI if (__SHIFTOUT(descs[1], CPUID_LOCAL_APIC_ID) == 120) { 2808368e25fSAaron LI print_state(true, "Running on cpu120"); 2818368e25fSAaron LI } else { 2828368e25fSAaron LI print_state(false, "Not running on cpu120!"); 2838368e25fSAaron LI } 2848368e25fSAaron LI 2858368e25fSAaron LI /* Ensure the LAPIC information matches. */ 2868368e25fSAaron LI #define LAPIC_ID 0x020 2878368e25fSAaron LI # define LAPIC_ID_MASK 0xff000000 2888368e25fSAaron LI # define LAPIC_ID_SHIFT 24 2898368e25fSAaron LI reg = (uint32_t *)lapicbase; 2908368e25fSAaron LI val = reg[LAPIC_ID/4]; 2918368e25fSAaron LI if (__SHIFTOUT(val, LAPIC_ID_MASK) == 120) { 2928368e25fSAaron LI print_state(true, "LAPIC information matches"); 2938368e25fSAaron LI } else { 2948368e25fSAaron LI print_state(false, "LAPIC information does not match!"); 2958368e25fSAaron LI } 2968368e25fSAaron LI 2978368e25fSAaron LI /* 2988368e25fSAaron LI * Will cause a #UD. 2998368e25fSAaron LI */ 3008368e25fSAaron LI vmmcall(); 3018368e25fSAaron LI } 302