xref: /dflybsd-src/test/nvmm/demo/smallkern/main.c (revision e84206a6156728f25f14aa8391a556add61c2aa0)
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(&region, &idtstore, PAGE_SIZE - 1);
2468368e25fSAaron LI 	lidt(&region);
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