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