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" 30aaa1e810SAaron LI #include "pdir.h" 31aaa1e810SAaron LI #include "trap.h" 328368e25fSAaron LI 33*20b815aaSAaron LI #include <sys/bitops.h> 348368e25fSAaron LI #include <machine/reg.h> 358368e25fSAaron LI #include <machine/specialreg.h> 368368e25fSAaron LI #include <machine/frame.h> 378368e25fSAaron LI #include <machine/tss.h> 388368e25fSAaron LI #include <machine/segments.h> 398368e25fSAaron LI 408368e25fSAaron LI /* GDT offsets */ 418368e25fSAaron LI #define SMALLKERN_GDT_NUL_OFF (0 * 8) 428368e25fSAaron LI #define SMALLKERN_GDT_CS_OFF (1 * 8) 438368e25fSAaron LI #define SMALLKERN_GDT_DS_OFF (2 * 8) 448368e25fSAaron LI #define SMALLKERN_GDT_TSS_OFF (3 * 8) 458368e25fSAaron LI 46*20b815aaSAaron LI #ifdef __DragonFly__ 47*20b815aaSAaron LI #define SDT_SYS386TSS SDT_SYSTSS /* 9: system 64-bit TSS available */ 48*20b815aaSAaron LI #define SDT_SYS386IGT SDT_SYSIGT /* 14: system 64-bit interrupt gate */ 49*20b815aaSAaron LI #define APICBASE_PHYSADDR APICBASE_ADDRESS /* 0xfffff000: physical address */ 50*20b815aaSAaron LI #define sys_segment_descriptor system_segment_descriptor 51*20b815aaSAaron LI #define x86_64_tss x86_64tss 52*20b815aaSAaron LI #define __arraycount(x) nitems(x) 53*20b815aaSAaron LI #endif /* __DragonFly__ */ 54*20b815aaSAaron LI 558368e25fSAaron LI void fatal(char *msg) 568368e25fSAaron LI { 578368e25fSAaron LI print("\n"); 588368e25fSAaron LI print_ext(RED_ON_BLACK, "********** FATAL ***********\n"); 598368e25fSAaron LI print_ext(RED_ON_BLACK, msg); 608368e25fSAaron LI print("\n"); 618368e25fSAaron LI print_ext(RED_ON_BLACK, "****************************\n"); 628368e25fSAaron LI 638368e25fSAaron LI while (1); 648368e25fSAaron LI } 658368e25fSAaron LI 668368e25fSAaron LI /* -------------------------------------------------------------------------- */ 678368e25fSAaron LI 688368e25fSAaron LI struct smallframe { 698368e25fSAaron LI uint64_t sf_trapno; 708368e25fSAaron LI uint64_t sf_err; 718368e25fSAaron LI uint64_t sf_rip; 728368e25fSAaron LI uint64_t sf_cs; 738368e25fSAaron LI uint64_t sf_rflags; 748368e25fSAaron LI uint64_t sf_rsp; 758368e25fSAaron LI uint64_t sf_ss; 768368e25fSAaron LI }; 778368e25fSAaron LI 788368e25fSAaron LI static void setregion(struct region_descriptor *, void *, uint16_t); 798368e25fSAaron LI static void setgate(struct gate_descriptor *, void *, int, int, int, int); 808368e25fSAaron LI static void set_sys_segment(struct sys_segment_descriptor *, void *, 818368e25fSAaron LI size_t, int, int, int); 828368e25fSAaron LI static void set_sys_gdt(int, void *, size_t, int, int, int); 838368e25fSAaron LI static void init_tss(void); 848368e25fSAaron LI static void init_idt(void); 858368e25fSAaron LI 868368e25fSAaron LI static char *trap_type[] = { 878368e25fSAaron LI "privileged instruction fault", /* 0 T_PRIVINFLT */ 888368e25fSAaron LI "breakpoint trap", /* 1 T_BPTFLT */ 898368e25fSAaron LI "arithmetic trap", /* 2 T_ARITHTRAP */ 908368e25fSAaron LI "asynchronous system trap", /* 3 T_ASTFLT */ 918368e25fSAaron LI "protection fault", /* 4 T_PROTFLT */ 928368e25fSAaron LI "trace trap", /* 5 T_TRCTRAP */ 938368e25fSAaron LI "page fault", /* 6 T_PAGEFLT */ 948368e25fSAaron LI "alignment fault", /* 7 T_ALIGNFLT */ 958368e25fSAaron LI "integer divide fault", /* 8 T_DIVIDE */ 968368e25fSAaron LI "non-maskable interrupt", /* 9 T_NMI */ 978368e25fSAaron LI "overflow trap", /* 10 T_OFLOW */ 988368e25fSAaron LI "bounds check fault", /* 11 T_BOUND */ 998368e25fSAaron LI "FPU not available fault", /* 12 T_DNA */ 1008368e25fSAaron LI "double fault", /* 13 T_DOUBLEFLT */ 1018368e25fSAaron LI "FPU operand fetch fault", /* 14 T_FPOPFLT */ 1028368e25fSAaron LI "invalid TSS fault", /* 15 T_TSSFLT */ 1038368e25fSAaron LI "segment not present fault", /* 16 T_SEGNPFLT */ 1048368e25fSAaron LI "stack fault", /* 17 T_STKFLT */ 1058368e25fSAaron LI "machine check fault", /* 18 T_MCA */ 1068368e25fSAaron LI "SSE FP exception", /* 19 T_XMM */ 1078368e25fSAaron LI "hardware interrupt", /* 20 T_RESERVED */ 1088368e25fSAaron LI }; 109ce7051aeSAaron LI size_t trap_types = __arraycount(trap_type); 1108368e25fSAaron LI 111aaa1e810SAaron LI static uint8_t idtstore[PAGE_SIZE] __aligned(PAGE_SIZE); 112aaa1e810SAaron LI static uint8_t faultstack[PAGE_SIZE] __aligned(PAGE_SIZE); 113aaa1e810SAaron LI static struct x86_64_tss smallkern_tss; 114aaa1e810SAaron LI 1158368e25fSAaron LI static void 1168368e25fSAaron LI triple_fault(void) 1178368e25fSAaron LI { 1188368e25fSAaron LI char *p = NULL; 1198368e25fSAaron LI memset(&idtstore, 0, PAGE_SIZE); 1208368e25fSAaron LI *p = 0; 1218368e25fSAaron LI } 1228368e25fSAaron LI 1238368e25fSAaron LI /* 1248368e25fSAaron LI * Trap handler. 1258368e25fSAaron LI */ 1268368e25fSAaron LI void 1278368e25fSAaron LI trap(struct smallframe *sf) 1288368e25fSAaron LI { 1298368e25fSAaron LI uint64_t trapno = sf->sf_trapno; 1308368e25fSAaron LI static int ntrap = 0; 1318368e25fSAaron LI static float f = 0.0; 1328368e25fSAaron LI char *buf; 1338368e25fSAaron LI 1348368e25fSAaron LI f += 1.0f; 1358368e25fSAaron LI if (ntrap++ == 10) { 1368368e25fSAaron LI triple_fault(); 1378368e25fSAaron LI } 1388368e25fSAaron LI if (ntrap != (int)f) { 1398368e25fSAaron LI print_ext(RED_ON_BLACK, "!!! FPU BUG !!!\n"); 1408368e25fSAaron LI } 1418368e25fSAaron LI 1428368e25fSAaron LI if (trapno < trap_types) { 1438368e25fSAaron LI buf = trap_type[trapno]; 1448368e25fSAaron LI } else { 1458368e25fSAaron LI buf = "unknown trap"; 1468368e25fSAaron LI } 1478368e25fSAaron LI 1488368e25fSAaron LI if (trapno == T_RESERVED) { 1498368e25fSAaron LI /* Disable external interrupts. */ 1508368e25fSAaron LI lcr8(15); 1518368e25fSAaron LI } 1528368e25fSAaron LI 1538368e25fSAaron LI print("\n"); 1548368e25fSAaron LI print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n"); 1558368e25fSAaron LI print_ext(RED_ON_BLACK, buf); 1568368e25fSAaron LI print("\n"); 1578368e25fSAaron LI print_ext(RED_ON_BLACK, "****************************\n"); 1588368e25fSAaron LI 1598368e25fSAaron LI sti(); 1608368e25fSAaron LI 1618368e25fSAaron LI while (1); 1628368e25fSAaron LI } 1638368e25fSAaron LI 1648368e25fSAaron LI static void 1658368e25fSAaron LI setregion(struct region_descriptor *rd, void *base, uint16_t limit) 1668368e25fSAaron LI { 1678368e25fSAaron LI rd->rd_limit = limit; 1688368e25fSAaron LI rd->rd_base = (uint64_t)base; 1698368e25fSAaron LI } 1708368e25fSAaron LI 1718368e25fSAaron LI static void 1728368e25fSAaron LI setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl, 1738368e25fSAaron LI int sel) 1748368e25fSAaron LI { 1758368e25fSAaron LI gd->gd_looffset = (uint64_t)func & 0xffff; 1768368e25fSAaron LI gd->gd_selector = sel; 1778368e25fSAaron LI gd->gd_ist = ist; 1788368e25fSAaron LI gd->gd_type = type; 1798368e25fSAaron LI gd->gd_dpl = dpl; 1808368e25fSAaron LI gd->gd_p = 1; 1818368e25fSAaron LI gd->gd_hioffset = (uint64_t)func >> 16; 1828368e25fSAaron LI gd->gd_xx1 = 0; 183*20b815aaSAaron LI #ifdef __NetBSD__ 184*20b815aaSAaron LI gd->gd_zero = 0; 1858368e25fSAaron LI gd->gd_xx2 = 0; 1868368e25fSAaron LI gd->gd_xx3 = 0; 187*20b815aaSAaron LI #endif 1888368e25fSAaron LI } 1898368e25fSAaron LI 1908368e25fSAaron LI static void 1918368e25fSAaron LI set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit, 1928368e25fSAaron LI int type, int dpl, int gran) 1938368e25fSAaron LI { 1948368e25fSAaron LI memset(sd, 0, sizeof(*sd)); 1958368e25fSAaron LI sd->sd_lolimit = (unsigned)limit; 1968368e25fSAaron LI sd->sd_lobase = (uint64_t)base; 1978368e25fSAaron LI sd->sd_type = type; 1988368e25fSAaron LI sd->sd_dpl = dpl; 1998368e25fSAaron LI sd->sd_p = 1; 2008368e25fSAaron LI sd->sd_hilimit = (unsigned)limit >> 16; 2018368e25fSAaron LI sd->sd_gran = gran; 2028368e25fSAaron LI sd->sd_hibase = (uint64_t)base >> 24; 2038368e25fSAaron LI } 2048368e25fSAaron LI 2058368e25fSAaron LI static void 2068368e25fSAaron LI set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran) 2078368e25fSAaron LI { 2088368e25fSAaron LI struct sys_segment_descriptor sd; 2098368e25fSAaron LI 2108368e25fSAaron LI set_sys_segment(&sd, base, limit, type, dpl, gran); 2118368e25fSAaron LI 2128368e25fSAaron LI memcpy(&gdt64_start + slotoff, &sd, sizeof(sd)); 2138368e25fSAaron LI } 2148368e25fSAaron LI 2158368e25fSAaron LI static void init_tss(void) 2168368e25fSAaron LI { 2178368e25fSAaron LI memset(&smallkern_tss, 0, sizeof(smallkern_tss)); 218*20b815aaSAaron LI #ifdef __NetBSD__ 2198368e25fSAaron LI smallkern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf; 220*20b815aaSAaron LI #else /* DragonFly */ 221*20b815aaSAaron LI smallkern_tss.tss_ist1 = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf; 222*20b815aaSAaron LI #endif 2238368e25fSAaron LI 2248368e25fSAaron LI set_sys_gdt(SMALLKERN_GDT_TSS_OFF, &smallkern_tss, 2258368e25fSAaron LI sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0); 2268368e25fSAaron LI } 2278368e25fSAaron LI 2288368e25fSAaron LI static void init_idt(void) 2298368e25fSAaron LI { 2308368e25fSAaron LI struct region_descriptor region; 2318368e25fSAaron LI struct gate_descriptor *idt; 2328368e25fSAaron LI size_t i; 2338368e25fSAaron LI 2348368e25fSAaron LI idt = (struct gate_descriptor *)&idtstore; 2358368e25fSAaron LI for (i = 0; i < NCPUIDT; i++) { 2368368e25fSAaron LI setgate(&idt[i], x86_exceptions[i], 0, SDT_SYS386IGT, 2378368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 2388368e25fSAaron LI } 2398368e25fSAaron LI for (i = NCPUIDT; i < 256; i++) { 2408368e25fSAaron LI setgate(&idt[i], &Xintr, 0, SDT_SYS386IGT, 2418368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 2428368e25fSAaron LI } 2438368e25fSAaron LI 2448368e25fSAaron LI setregion(®ion, &idtstore, PAGE_SIZE - 1); 2458368e25fSAaron LI lidt(®ion); 2468368e25fSAaron LI } 2478368e25fSAaron LI 2488368e25fSAaron LI /* -------------------------------------------------------------------------- */ 2498368e25fSAaron LI 2508368e25fSAaron LI /* 2518368e25fSAaron LI * Main entry point of the kernel. 2528368e25fSAaron LI */ 2538368e25fSAaron LI void 254ce7051aeSAaron LI main(paddr_t pa_start __unused) 2558368e25fSAaron LI { 2568368e25fSAaron LI u_int descs[4]; 2578368e25fSAaron LI uint32_t *reg, val; 2588368e25fSAaron LI 2598368e25fSAaron LI print_banner(); 2608368e25fSAaron LI 2618368e25fSAaron LI /* 2628368e25fSAaron LI * Init the TSS and IDT. We mostly don't care about this, they are just 2638368e25fSAaron LI * here to properly handle traps. 2648368e25fSAaron LI */ 2658368e25fSAaron LI init_tss(); 2668368e25fSAaron LI print_state(true, "TSS created"); 2678368e25fSAaron LI init_idt(); 2688368e25fSAaron LI print_state(true, "IDT created"); 2698368e25fSAaron LI 2708368e25fSAaron LI /* Reset CR8. */ 2718368e25fSAaron LI lcr8(0); 2728368e25fSAaron LI 2738368e25fSAaron LI /* Enable FPU. */ 2748368e25fSAaron LI clts(); 2758368e25fSAaron LI 2768368e25fSAaron LI /* Enable interrupts. */ 2778368e25fSAaron LI sti(); 2788368e25fSAaron LI 2798368e25fSAaron LI /* Ensure APICBASE is correct (default). */ 2808368e25fSAaron LI if ((rdmsr(MSR_APICBASE) & APICBASE_PHYSADDR) == 0xfee00000) { 2818368e25fSAaron LI print_state(true, "APICBASE is correct"); 2828368e25fSAaron LI } else { 2838368e25fSAaron LI print_state(false, "wrong APICBASE"); 2848368e25fSAaron LI } 2858368e25fSAaron LI 2868368e25fSAaron LI /* Ensure PG_NX is disabled. */ 2878368e25fSAaron LI if (!nox_flag) { 2888368e25fSAaron LI print_state(true, "PG_NX is disabled"); 2898368e25fSAaron LI } else { 2908368e25fSAaron LI print_state(false, "PG_NX is enabled!"); 2918368e25fSAaron LI } 2928368e25fSAaron LI 2938368e25fSAaron LI /* Ensure we are on cpu120. */ 2948368e25fSAaron LI cpuid(1, 0, descs); 2958368e25fSAaron LI if (__SHIFTOUT(descs[1], CPUID_LOCAL_APIC_ID) == 120) { 2968368e25fSAaron LI print_state(true, "Running on cpu120"); 2978368e25fSAaron LI } else { 2988368e25fSAaron LI print_state(false, "Not running on cpu120!"); 2998368e25fSAaron LI } 3008368e25fSAaron LI 3018368e25fSAaron LI /* Ensure the LAPIC information matches. */ 3028368e25fSAaron LI #define LAPIC_ID 0x020 3038368e25fSAaron LI # define LAPIC_ID_MASK 0xff000000 3048368e25fSAaron LI # define LAPIC_ID_SHIFT 24 3058368e25fSAaron LI reg = (uint32_t *)lapicbase; 3068368e25fSAaron LI val = reg[LAPIC_ID/4]; 3078368e25fSAaron LI if (__SHIFTOUT(val, LAPIC_ID_MASK) == 120) { 3088368e25fSAaron LI print_state(true, "LAPIC information matches"); 3098368e25fSAaron LI } else { 3108368e25fSAaron LI print_state(false, "LAPIC information does not match!"); 3118368e25fSAaron LI } 3128368e25fSAaron LI 3138368e25fSAaron LI /* 3148368e25fSAaron LI * Will cause a #UD. 3158368e25fSAaron LI */ 3168368e25fSAaron LI vmmcall(); 3178368e25fSAaron LI } 318