18368e25fSAaron LI /*
2*e84206a6SAaron LI * Copyright (c) 2018-2021 Maxime Villard, m00nbsd.net
3*e84206a6SAaron LI * All rights reserved.
48368e25fSAaron LI *
5*e84206a6SAaron LI * This code is part of the NVMM hypervisor.
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 *
16*e84206a6SAaron LI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*e84206a6SAaron LI * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*e84206a6SAaron LI * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*e84206a6SAaron LI * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*e84206a6SAaron LI * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*e84206a6SAaron LI * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*e84206a6SAaron LI * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*e84206a6SAaron LI * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*e84206a6SAaron LI * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*e84206a6SAaron LI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*e84206a6SAaron LI * SUCH DAMAGE.
278368e25fSAaron LI */
288368e25fSAaron LI
298368e25fSAaron LI #include "smallkern.h"
30aaa1e810SAaron LI #include "pdir.h"
31aaa1e810SAaron LI #include "trap.h"
328368e25fSAaron LI
3320b815aaSAaron 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
4620b815aaSAaron LI #ifdef __DragonFly__
4720b815aaSAaron LI #define SDT_SYS386TSS SDT_SYSTSS /* 9: system 64-bit TSS available */
4820b815aaSAaron LI #define SDT_SYS386IGT SDT_SYSIGT /* 14: system 64-bit interrupt gate */
4920b815aaSAaron LI #define APICBASE_PHYSADDR APICBASE_ADDRESS /* 0xfffff000: physical address */
5020b815aaSAaron LI #define sys_segment_descriptor system_segment_descriptor
5120b815aaSAaron LI #define x86_64_tss x86_64tss
5220b815aaSAaron LI #define __arraycount(x) nitems(x)
5320b815aaSAaron LI #endif /* __DragonFly__ */
5420b815aaSAaron LI
fatal(char * msg)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
triple_fault(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
trap(struct smallframe * sf)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;
135ce659a16SAaron LI if (ntrap++ == 6) {
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");
158ce659a16SAaron LI print("\n");
1598368e25fSAaron LI
1608368e25fSAaron LI sti();
1618368e25fSAaron LI
1628368e25fSAaron LI while (1);
1638368e25fSAaron LI }
1648368e25fSAaron LI
1658368e25fSAaron LI static void
setregion(struct region_descriptor * rd,void * base,uint16_t limit)1668368e25fSAaron LI setregion(struct region_descriptor *rd, void *base, uint16_t limit)
1678368e25fSAaron LI {
1688368e25fSAaron LI rd->rd_limit = limit;
1698368e25fSAaron LI rd->rd_base = (uint64_t)base;
1708368e25fSAaron LI }
1718368e25fSAaron LI
1728368e25fSAaron LI static void
setgate(struct gate_descriptor * gd,void * func,int ist,int type,int dpl,int sel)1738368e25fSAaron LI setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl,
1748368e25fSAaron LI int sel)
1758368e25fSAaron LI {
1768368e25fSAaron LI gd->gd_looffset = (uint64_t)func & 0xffff;
1778368e25fSAaron LI gd->gd_selector = sel;
1788368e25fSAaron LI gd->gd_ist = ist;
1798368e25fSAaron LI gd->gd_type = type;
1808368e25fSAaron LI gd->gd_dpl = dpl;
1818368e25fSAaron LI gd->gd_p = 1;
1828368e25fSAaron LI gd->gd_hioffset = (uint64_t)func >> 16;
1838368e25fSAaron LI gd->gd_xx1 = 0;
18420b815aaSAaron LI #ifdef __NetBSD__
18520b815aaSAaron LI gd->gd_zero = 0;
1868368e25fSAaron LI gd->gd_xx2 = 0;
1878368e25fSAaron LI gd->gd_xx3 = 0;
18820b815aaSAaron LI #endif
1898368e25fSAaron LI }
1908368e25fSAaron LI
1918368e25fSAaron LI static void
set_sys_segment(struct sys_segment_descriptor * sd,void * base,size_t limit,int type,int dpl,int gran)1928368e25fSAaron LI set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit,
1938368e25fSAaron LI int type, int dpl, int gran)
1948368e25fSAaron LI {
1958368e25fSAaron LI memset(sd, 0, sizeof(*sd));
1968368e25fSAaron LI sd->sd_lolimit = (unsigned)limit;
1978368e25fSAaron LI sd->sd_lobase = (uint64_t)base;
1988368e25fSAaron LI sd->sd_type = type;
1998368e25fSAaron LI sd->sd_dpl = dpl;
2008368e25fSAaron LI sd->sd_p = 1;
2018368e25fSAaron LI sd->sd_hilimit = (unsigned)limit >> 16;
2028368e25fSAaron LI sd->sd_gran = gran;
2038368e25fSAaron LI sd->sd_hibase = (uint64_t)base >> 24;
2048368e25fSAaron LI }
2058368e25fSAaron LI
2068368e25fSAaron LI static void
set_sys_gdt(int slotoff,void * base,size_t limit,int type,int dpl,int gran)2078368e25fSAaron LI set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran)
2088368e25fSAaron LI {
2098368e25fSAaron LI struct sys_segment_descriptor sd;
2108368e25fSAaron LI
2118368e25fSAaron LI set_sys_segment(&sd, base, limit, type, dpl, gran);
2128368e25fSAaron LI
2138368e25fSAaron LI memcpy(&gdt64_start + slotoff, &sd, sizeof(sd));
2148368e25fSAaron LI }
2158368e25fSAaron LI
init_tss(void)2168368e25fSAaron LI static void init_tss(void)
2178368e25fSAaron LI {
2188368e25fSAaron LI memset(&smallkern_tss, 0, sizeof(smallkern_tss));
21920b815aaSAaron LI #ifdef __NetBSD__
2208368e25fSAaron LI smallkern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf;
22120b815aaSAaron LI #else /* DragonFly */
22220b815aaSAaron LI smallkern_tss.tss_ist1 = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf;
22320b815aaSAaron LI #endif
2248368e25fSAaron LI
2258368e25fSAaron LI set_sys_gdt(SMALLKERN_GDT_TSS_OFF, &smallkern_tss,
2268368e25fSAaron LI sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
2278368e25fSAaron LI }
2288368e25fSAaron LI
init_idt(void)2298368e25fSAaron LI static void init_idt(void)
2308368e25fSAaron LI {
2318368e25fSAaron LI struct region_descriptor region;
2328368e25fSAaron LI struct gate_descriptor *idt;
2338368e25fSAaron LI size_t i;
2348368e25fSAaron LI
2358368e25fSAaron LI idt = (struct gate_descriptor *)&idtstore;
2368368e25fSAaron LI for (i = 0; i < NCPUIDT; i++) {
2378368e25fSAaron LI setgate(&idt[i], x86_exceptions[i], 0, SDT_SYS386IGT,
2388368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
2398368e25fSAaron LI }
2408368e25fSAaron LI for (i = NCPUIDT; i < 256; i++) {
2418368e25fSAaron LI setgate(&idt[i], &Xintr, 0, SDT_SYS386IGT,
2428368e25fSAaron LI SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
2438368e25fSAaron LI }
2448368e25fSAaron LI
2458368e25fSAaron LI setregion(®ion, &idtstore, PAGE_SIZE - 1);
2468368e25fSAaron LI lidt(®ion);
2478368e25fSAaron LI }
2488368e25fSAaron LI
2498368e25fSAaron LI /* -------------------------------------------------------------------------- */
2508368e25fSAaron LI
2518368e25fSAaron LI /*
2528368e25fSAaron LI * Main entry point of the kernel.
2538368e25fSAaron LI */
2548368e25fSAaron LI void
main(paddr_t pa_start __unused)255ce7051aeSAaron LI main(paddr_t pa_start __unused)
2568368e25fSAaron LI {
2578368e25fSAaron LI u_int descs[4];
2588368e25fSAaron LI uint32_t *reg, val;
2598368e25fSAaron LI
2608368e25fSAaron LI print_banner();
2618368e25fSAaron LI
2628368e25fSAaron LI /*
2638368e25fSAaron LI * Init the TSS and IDT. We mostly don't care about this, they are just
2648368e25fSAaron LI * here to properly handle traps.
2658368e25fSAaron LI */
2668368e25fSAaron LI init_tss();
2678368e25fSAaron LI print_state(true, "TSS created");
2688368e25fSAaron LI init_idt();
2698368e25fSAaron LI print_state(true, "IDT created");
2708368e25fSAaron LI
2718368e25fSAaron LI /* Reset CR8. */
2728368e25fSAaron LI lcr8(0);
2738368e25fSAaron LI
2748368e25fSAaron LI /* Enable FPU. */
2758368e25fSAaron LI clts();
2768368e25fSAaron LI
2778368e25fSAaron LI /* Enable interrupts. */
2788368e25fSAaron LI sti();
2798368e25fSAaron LI
2808368e25fSAaron LI /* Ensure APICBASE is correct (default). */
2818368e25fSAaron LI if ((rdmsr(MSR_APICBASE) & APICBASE_PHYSADDR) == 0xfee00000) {
2828368e25fSAaron LI print_state(true, "APICBASE is correct");
2838368e25fSAaron LI } else {
2848368e25fSAaron LI print_state(false, "wrong APICBASE");
2858368e25fSAaron LI }
2868368e25fSAaron LI
2878368e25fSAaron LI /* Ensure PG_NX is disabled. */
2888368e25fSAaron LI if (!nox_flag) {
2898368e25fSAaron LI print_state(true, "PG_NX is disabled");
2908368e25fSAaron LI } else {
2918368e25fSAaron LI print_state(false, "PG_NX is enabled!");
2928368e25fSAaron LI }
2938368e25fSAaron LI
2948368e25fSAaron LI /* Ensure we are on cpu120. */
2958368e25fSAaron LI cpuid(1, 0, descs);
2968368e25fSAaron LI if (__SHIFTOUT(descs[1], CPUID_LOCAL_APIC_ID) == 120) {
2978368e25fSAaron LI print_state(true, "Running on cpu120");
2988368e25fSAaron LI } else {
2998368e25fSAaron LI print_state(false, "Not running on cpu120!");
3008368e25fSAaron LI }
3018368e25fSAaron LI
3028368e25fSAaron LI /* Ensure the LAPIC information matches. */
3038368e25fSAaron LI #define LAPIC_ID 0x020
3048368e25fSAaron LI # define LAPIC_ID_MASK 0xff000000
3058368e25fSAaron LI # define LAPIC_ID_SHIFT 24
3068368e25fSAaron LI reg = (uint32_t *)lapicbase;
3078368e25fSAaron LI val = reg[LAPIC_ID/4];
3088368e25fSAaron LI if (__SHIFTOUT(val, LAPIC_ID_MASK) == 120) {
3098368e25fSAaron LI print_state(true, "LAPIC information matches");
3108368e25fSAaron LI } else {
3118368e25fSAaron LI print_state(false, "LAPIC information does not match!");
3128368e25fSAaron LI }
3138368e25fSAaron LI
3148368e25fSAaron LI /*
3158368e25fSAaron LI * Will cause a #UD.
3168368e25fSAaron LI */
3178368e25fSAaron LI vmmcall();
3188368e25fSAaron LI }
319