test/nvmm/demo: Various cleanups to 'smallkern'
[dragonfly.git] / test / nvmm / demo / smallkern / main.c
1 /*
2  * Copyright (c) 2018 The NetBSD Foundation, Inc. All rights reserved.
3  *
4  * This code is derived from software contributed to The NetBSD Foundation
5  * by Maxime Villard.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "smallkern.h"
30 #include "pdir.h"
31 #include "trap.h"
32
33 #include <machine/reg.h>
34 #include <machine/specialreg.h>
35 #include <machine/frame.h>
36 #include <machine/tss.h>
37 #include <machine/segments.h>
38
39 /* GDT offsets */
40 #define SMALLKERN_GDT_NUL_OFF   (0 * 8)
41 #define SMALLKERN_GDT_CS_OFF    (1 * 8)
42 #define SMALLKERN_GDT_DS_OFF    (2 * 8)
43 #define SMALLKERN_GDT_TSS_OFF   (3 * 8)
44
45 void fatal(char *msg)
46 {
47         print("\n");
48         print_ext(RED_ON_BLACK, "********** FATAL ***********\n");
49         print_ext(RED_ON_BLACK, msg);
50         print("\n");
51         print_ext(RED_ON_BLACK, "****************************\n");
52
53         while (1);
54 }
55
56 /* -------------------------------------------------------------------------- */
57
58 struct smallframe {
59         uint64_t sf_trapno;
60         uint64_t sf_err;
61         uint64_t sf_rip;
62         uint64_t sf_cs;
63         uint64_t sf_rflags;
64         uint64_t sf_rsp;
65         uint64_t sf_ss;
66 };
67
68 static void setregion(struct region_descriptor *, void *, uint16_t);
69 static void setgate(struct gate_descriptor *, void *, int, int, int, int);
70 static void set_sys_segment(struct sys_segment_descriptor *, void *,
71     size_t, int, int, int);
72 static void set_sys_gdt(int, void *, size_t, int, int, int);
73 static void init_tss(void);
74 static void init_idt(void);
75
76 static char *trap_type[] = {
77         "privileged instruction fault",         /*  0 T_PRIVINFLT */
78         "breakpoint trap",                      /*  1 T_BPTFLT */
79         "arithmetic trap",                      /*  2 T_ARITHTRAP */
80         "asynchronous system trap",             /*  3 T_ASTFLT */
81         "protection fault",                     /*  4 T_PROTFLT */
82         "trace trap",                           /*  5 T_TRCTRAP */
83         "page fault",                           /*  6 T_PAGEFLT */
84         "alignment fault",                      /*  7 T_ALIGNFLT */
85         "integer divide fault",                 /*  8 T_DIVIDE */
86         "non-maskable interrupt",               /*  9 T_NMI */
87         "overflow trap",                        /* 10 T_OFLOW */
88         "bounds check fault",                   /* 11 T_BOUND */
89         "FPU not available fault",              /* 12 T_DNA */
90         "double fault",                         /* 13 T_DOUBLEFLT */
91         "FPU operand fetch fault",              /* 14 T_FPOPFLT */
92         "invalid TSS fault",                    /* 15 T_TSSFLT */
93         "segment not present fault",            /* 16 T_SEGNPFLT */
94         "stack fault",                          /* 17 T_STKFLT */
95         "machine check fault",                  /* 18 T_MCA */
96         "SSE FP exception",                     /* 19 T_XMM */
97         "hardware interrupt",                   /* 20 T_RESERVED */
98 };
99 size_t  trap_types = __arraycount(trap_type);
100
101 static uint8_t idtstore[PAGE_SIZE] __aligned(PAGE_SIZE);
102 static uint8_t faultstack[PAGE_SIZE] __aligned(PAGE_SIZE);
103 static struct x86_64_tss smallkern_tss;
104
105 static void
106 triple_fault(void)
107 {
108         char *p = NULL;
109         memset(&idtstore, 0, PAGE_SIZE);
110         *p = 0;
111 }
112
113 /*
114  * Trap handler.
115  */
116 void
117 trap(struct smallframe *sf)
118 {
119         uint64_t trapno = sf->sf_trapno;
120         static int ntrap = 0;
121         static float f = 0.0;
122         char *buf;
123
124         f += 1.0f;
125         if (ntrap++ == 10) {
126                 triple_fault();
127         }
128         if (ntrap != (int)f) {
129                 print_ext(RED_ON_BLACK, "!!! FPU BUG !!!\n");
130         }
131
132         if (trapno < trap_types) {
133                 buf = trap_type[trapno];
134         } else {
135                 buf = "unknown trap";
136         }
137
138         if (trapno == T_RESERVED) {
139                 /* Disable external interrupts. */
140                 lcr8(15);
141         }
142
143         print("\n");
144         print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n");
145         print_ext(RED_ON_BLACK, buf);
146         print("\n");
147         print_ext(RED_ON_BLACK, "****************************\n");
148
149         sti();
150
151         while (1);
152 }
153
154 static void
155 setregion(struct region_descriptor *rd, void *base, uint16_t limit)
156 {
157         rd->rd_limit = limit;
158         rd->rd_base = (uint64_t)base;
159 }
160
161 static void
162 setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl,
163         int sel)
164 {
165         gd->gd_looffset = (uint64_t)func & 0xffff;
166         gd->gd_selector = sel;
167         gd->gd_ist = ist;
168         gd->gd_type = type;
169         gd->gd_dpl = dpl;
170         gd->gd_p = 1;
171         gd->gd_hioffset = (uint64_t)func >> 16;
172         gd->gd_zero = 0;
173         gd->gd_xx1 = 0;
174         gd->gd_xx2 = 0;
175         gd->gd_xx3 = 0;
176 }
177
178 static void
179 set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit,
180         int type, int dpl, int gran)
181 {
182         memset(sd, 0, sizeof(*sd));
183         sd->sd_lolimit = (unsigned)limit;
184         sd->sd_lobase = (uint64_t)base;
185         sd->sd_type = type;
186         sd->sd_dpl = dpl;
187         sd->sd_p = 1;
188         sd->sd_hilimit = (unsigned)limit >> 16;
189         sd->sd_gran = gran;
190         sd->sd_hibase = (uint64_t)base >> 24;
191 }
192
193 static void
194 set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran)
195 {
196         struct sys_segment_descriptor sd;
197
198         set_sys_segment(&sd, base, limit, type, dpl, gran);
199
200         memcpy(&gdt64_start + slotoff, &sd, sizeof(sd));
201 }
202
203 static void init_tss(void)
204 {
205         memset(&smallkern_tss, 0, sizeof(smallkern_tss));
206         smallkern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf;
207
208         set_sys_gdt(SMALLKERN_GDT_TSS_OFF, &smallkern_tss,
209             sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
210 }
211
212 static void init_idt(void)
213 {
214         struct region_descriptor region;
215         struct gate_descriptor *idt;
216         size_t i;
217
218         idt = (struct gate_descriptor *)&idtstore;
219         for (i = 0; i < NCPUIDT; i++) {
220                 setgate(&idt[i], x86_exceptions[i], 0, SDT_SYS386IGT,
221                     SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
222         }
223         for (i = NCPUIDT; i < 256; i++) {
224                 setgate(&idt[i], &Xintr, 0, SDT_SYS386IGT,
225                     SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
226         }
227
228         setregion(&region, &idtstore, PAGE_SIZE - 1);
229         lidt(&region);
230 }
231
232 /* -------------------------------------------------------------------------- */
233
234 /*
235  * Main entry point of the kernel.
236  */
237 void
238 main(paddr_t pa_start __unused)
239 {
240         u_int descs[4];
241         uint32_t *reg, val;
242
243         print_banner();
244
245         /*
246          * Init the TSS and IDT. We mostly don't care about this, they are just
247          * here to properly handle traps.
248          */
249         init_tss();
250         print_state(true, "TSS created");
251         init_idt();
252         print_state(true, "IDT created");
253
254         /* Reset CR8. */
255         lcr8(0);
256
257         /* Enable FPU. */
258         clts();
259
260         /* Enable interrupts. */
261         sti();
262
263         /* Ensure APICBASE is correct (default). */
264         if ((rdmsr(MSR_APICBASE) & APICBASE_PHYSADDR) == 0xfee00000) {
265                 print_state(true, "APICBASE is correct");
266         } else {
267                 print_state(false, "wrong APICBASE");
268         }
269
270         /* Ensure PG_NX is disabled. */
271         if (!nox_flag) {
272                 print_state(true, "PG_NX is disabled");
273         } else {
274                 print_state(false, "PG_NX is enabled!");
275         }
276
277         /* Ensure we are on cpu120. */
278         cpuid(1, 0, descs);
279         if (__SHIFTOUT(descs[1], CPUID_LOCAL_APIC_ID) == 120) {
280                 print_state(true, "Running on cpu120");
281         } else {
282                 print_state(false, "Not running on cpu120!");
283         }
284
285         /* Ensure the LAPIC information matches. */
286 #define LAPIC_ID                0x020
287 #       define LAPIC_ID_MASK            0xff000000
288 #       define LAPIC_ID_SHIFT           24
289         reg = (uint32_t *)lapicbase;
290         val = reg[LAPIC_ID/4];
291         if (__SHIFTOUT(val, LAPIC_ID_MASK) == 120) {
292                 print_state(true, "LAPIC information matches");
293         } else {
294                 print_state(false, "LAPIC information does not match!");
295         }
296
297         /*
298          * Will cause a #UD.
299          */
300         vmmcall();
301 }