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