2 * Copyright (c) 2018 The NetBSD Foundation, Inc. All rights reserved.
4 * This code is derived from software contributed to The NetBSD Foundation
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include "smallkern.h"
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>
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)
48 print_ext(RED_ON_BLACK, "********** FATAL ***********\n");
49 print_ext(RED_ON_BLACK, msg);
51 print_ext(RED_ON_BLACK, "****************************\n");
56 /* -------------------------------------------------------------------------- */
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);
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 */
99 size_t trap_types = __arraycount(trap_type);
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;
109 memset(&idtstore, 0, PAGE_SIZE);
117 trap(struct smallframe *sf)
119 uint64_t trapno = sf->sf_trapno;
120 static int ntrap = 0;
121 static float f = 0.0;
128 if (ntrap != (int)f) {
129 print_ext(RED_ON_BLACK, "!!! FPU BUG !!!\n");
132 if (trapno < trap_types) {
133 buf = trap_type[trapno];
135 buf = "unknown trap";
138 if (trapno == T_RESERVED) {
139 /* Disable external interrupts. */
144 print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n");
145 print_ext(RED_ON_BLACK, buf);
147 print_ext(RED_ON_BLACK, "****************************\n");
155 setregion(struct region_descriptor *rd, void *base, uint16_t limit)
157 rd->rd_limit = limit;
158 rd->rd_base = (uint64_t)base;
162 setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl,
165 gd->gd_looffset = (uint64_t)func & 0xffff;
166 gd->gd_selector = sel;
171 gd->gd_hioffset = (uint64_t)func >> 16;
179 set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit,
180 int type, int dpl, int gran)
182 memset(sd, 0, sizeof(*sd));
183 sd->sd_lolimit = (unsigned)limit;
184 sd->sd_lobase = (uint64_t)base;
188 sd->sd_hilimit = (unsigned)limit >> 16;
190 sd->sd_hibase = (uint64_t)base >> 24;
194 set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran)
196 struct sys_segment_descriptor sd;
198 set_sys_segment(&sd, base, limit, type, dpl, gran);
200 memcpy(&gdt64_start + slotoff, &sd, sizeof(sd));
203 static void init_tss(void)
205 memset(&smallkern_tss, 0, sizeof(smallkern_tss));
206 smallkern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf;
208 set_sys_gdt(SMALLKERN_GDT_TSS_OFF, &smallkern_tss,
209 sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
212 static void init_idt(void)
214 struct region_descriptor region;
215 struct gate_descriptor *idt;
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));
223 for (i = NCPUIDT; i < 256; i++) {
224 setgate(&idt[i], &Xintr, 0, SDT_SYS386IGT,
225 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
228 setregion(®ion, &idtstore, PAGE_SIZE - 1);
232 /* -------------------------------------------------------------------------- */
235 * Main entry point of the kernel.
238 main(paddr_t pa_start __unused)
246 * Init the TSS and IDT. We mostly don't care about this, they are just
247 * here to properly handle traps.
250 print_state(true, "TSS created");
252 print_state(true, "IDT created");
260 /* Enable interrupts. */
263 /* Ensure APICBASE is correct (default). */
264 if ((rdmsr(MSR_APICBASE) & APICBASE_PHYSADDR) == 0xfee00000) {
265 print_state(true, "APICBASE is correct");
267 print_state(false, "wrong APICBASE");
270 /* Ensure PG_NX is disabled. */
272 print_state(true, "PG_NX is disabled");
274 print_state(false, "PG_NX is enabled!");
277 /* Ensure we are on cpu120. */
279 if (__SHIFTOUT(descs[1], CPUID_LOCAL_APIC_ID) == 120) {
280 print_state(true, "Running on cpu120");
282 print_state(false, "Not running on cpu120!");
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");
294 print_state(false, "LAPIC information does not match!");