1 /* $NetBSD: prekern.c,v 1.14 2021/05/04 21:09:16 khorben Exp $ */
2
3 /*
4 * Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Maxime Villard.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "prekern.h"
32
33 #include <machine/reg.h>
34 #include <machine/specialreg.h>
35 #include <machine/frame.h>
36
37 #define _KERNEL
38 #include <machine/bootinfo.h>
39 #undef _KERNEL
40
41 #include <machine/tss.h>
42 #include <machine/segments.h>
43
44 int boothowto;
45 struct bootinfo bootinfo;
46
47 extern paddr_t kernpa_start, kernpa_end;
48
49 static uint8_t idtstore[PAGE_SIZE] __aligned(PAGE_SIZE);
50
51 #define IDTVEC(name) __CONCAT(X, name)
52 typedef void (vector)(void);
53 extern vector *x86_exceptions[];
54
fatal(char * msg)55 void fatal(char *msg)
56 {
57 print("\n");
58 print_ext(RED_ON_BLACK, "********** FATAL ***********\n");
59 print_ext(RED_ON_BLACK, msg);
60 print("\n");
61 print_ext(RED_ON_BLACK, "****************************\n");
62
63 while (1);
64 }
65
66 /* -------------------------------------------------------------------------- */
67
68 struct smallframe {
69 uint64_t sf_trapno;
70 uint64_t sf_err;
71 uint64_t sf_rip;
72 uint64_t sf_cs;
73 uint64_t sf_rflags;
74 uint64_t sf_rsp;
75 uint64_t sf_ss;
76 };
77
78 void trap(struct smallframe *);
79
80 static char *trap_type[] = {
81 "privileged instruction fault", /* 0 T_PRIVINFLT */
82 "breakpoint trap", /* 1 T_BPTFLT */
83 "arithmetic trap", /* 2 T_ARITHTRAP */
84 "asynchronous system trap", /* 3 T_ASTFLT */
85 "protection fault", /* 4 T_PROTFLT */
86 "trace trap", /* 5 T_TRCTRAP */
87 "page fault", /* 6 T_PAGEFLT */
88 "alignment fault", /* 7 T_ALIGNFLT */
89 "integer divide fault", /* 8 T_DIVIDE */
90 "non-maskable interrupt", /* 9 T_NMI */
91 "overflow trap", /* 10 T_OFLOW */
92 "bounds check fault", /* 11 T_BOUND */
93 "FPU not available fault", /* 12 T_DNA */
94 "double fault", /* 13 T_DOUBLEFLT */
95 "FPU operand fetch fault", /* 14 T_FPOPFLT */
96 "invalid TSS fault", /* 15 T_TSSFLT */
97 "segment not present fault", /* 16 T_SEGNPFLT */
98 "stack fault", /* 17 T_STKFLT */
99 "machine check fault", /* 18 T_MCA */
100 "SSE FP exception", /* 19 T_XMM */
101 "reserved trap", /* 20 T_RESERVED */
102 };
103 static int trap_types = __arraycount(trap_type);
104
105 /*
106 * Trap handler.
107 */
108 void
trap(struct smallframe * sf)109 trap(struct smallframe *sf)
110 {
111 uint64_t trapno = sf->sf_trapno;
112 char *buf;
113
114 if (trapno < trap_types) {
115 buf = trap_type[trapno];
116 } else {
117 buf = "unknown trap";
118 }
119
120 print("\n");
121 print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n");
122 print_ext(RED_ON_BLACK, buf);
123 print("\n");
124 print_ext(RED_ON_BLACK, "****************************\n");
125
126 while (1);
127 }
128
129 /* -------------------------------------------------------------------------- */
130
131 static void
setregion(struct region_descriptor * rd,void * base,uint16_t limit)132 setregion(struct region_descriptor *rd, void *base, uint16_t limit)
133 {
134 rd->rd_limit = limit;
135 rd->rd_base = (uint64_t)base;
136 }
137
138 static void
setgate(struct gate_descriptor * gd,void * func,int ist,int type,int dpl,int sel)139 setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl,
140 int sel)
141 {
142 gd->gd_looffset = (uint64_t)func & 0xffff;
143 gd->gd_selector = sel;
144 gd->gd_ist = ist;
145 gd->gd_type = type;
146 gd->gd_dpl = dpl;
147 gd->gd_p = 1;
148 gd->gd_hioffset = (uint64_t)func >> 16;
149 gd->gd_zero = 0;
150 gd->gd_xx1 = 0;
151 gd->gd_xx2 = 0;
152 gd->gd_xx3 = 0;
153 }
154
155 static void
init_idt(void)156 init_idt(void)
157 {
158 struct region_descriptor region;
159 struct gate_descriptor *idt;
160 size_t i;
161
162 idt = (struct gate_descriptor *)&idtstore;
163 for (i = 0; i < NCPUIDT; i++) {
164 setgate(&idt[i], x86_exceptions[i], 0, SDT_SYS386IGT,
165 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
166 }
167
168 setregion(®ion, &idtstore, PAGE_SIZE - 1);
169 lidt(®ion);
170 }
171
172 /* -------------------------------------------------------------------------- */
173
174 #define PREKERN_API_VERSION 2
175
176 struct prekern_args {
177 int version;
178 int boothowto;
179 void *bootinfo;
180 void *bootspace;
181 int esym;
182 int biosextmem;
183 int biosbasemem;
184 int cpuid_level;
185 uint32_t nox_flag;
186 uint64_t PDPpaddr;
187 vaddr_t atdevbase;
188 vaddr_t lwp0uarea;
189 paddr_t first_avail;
190 };
191
192 struct prekern_args pkargs;
193
194 static void
init_prekern_args(void)195 init_prekern_args(void)
196 {
197 extern struct bootspace bootspace;
198 extern int esym;
199 extern int biosextmem;
200 extern int biosbasemem;
201 extern int cpuid_level;
202 extern uint32_t nox_flag;
203 extern uint64_t PDPpaddr;
204 extern vaddr_t iom_base;
205 extern paddr_t stkpa;
206 extern paddr_t pa_avail;
207
208 memset(&pkargs, 0, sizeof(pkargs));
209 pkargs.version = PREKERN_API_VERSION;
210 pkargs.boothowto = boothowto;
211 pkargs.bootinfo = (void *)&bootinfo;
212 pkargs.bootspace = &bootspace;
213 pkargs.esym = esym;
214 pkargs.biosextmem = biosextmem;
215 pkargs.biosbasemem = biosbasemem;
216 pkargs.cpuid_level = cpuid_level;
217 pkargs.nox_flag = nox_flag;
218 pkargs.PDPpaddr = PDPpaddr;
219 pkargs.atdevbase = iom_base;
220 pkargs.lwp0uarea = bootspace.boot.va + (stkpa - bootspace.boot.pa);
221 pkargs.first_avail = pa_avail;
222
223 extern vaddr_t stkva;
224 stkva = pkargs.lwp0uarea + (USPACE - FRAMESIZE);
225 }
226
227 void
exec_kernel(vaddr_t ent)228 exec_kernel(vaddr_t ent)
229 {
230 int (*jumpfunc)(struct prekern_args *);
231 int ret;
232
233 /*
234 * Normally, the function does not return. If it does, it means the
235 * kernel had trouble processing the arguments, and we panic here. The
236 * return value is here for debug.
237 */
238 jumpfunc = (void *)ent;
239 ret = (*jumpfunc)(&pkargs);
240
241 if (ret == -1) {
242 fatal("kernel returned: wrong API version");
243 } else {
244 fatal("kernel returned: unknown value");
245 }
246 }
247
248 /*
249 * Main entry point of the Prekern.
250 */
251 void
init_prekern(paddr_t pa_start)252 init_prekern(paddr_t pa_start)
253 {
254 vaddr_t ent;
255
256 init_cons();
257 print_banner();
258
259 if (kernpa_start == 0 || kernpa_end == 0) {
260 fatal("init_prekern: unable to locate the kernel");
261 }
262 if (kernpa_start != (1UL << 21)) {
263 fatal("init_prekern: invalid kernpa_start");
264 }
265 if (kernpa_start % PAGE_SIZE != 0) {
266 fatal("init_prekern: kernpa_start not aligned");
267 }
268 if (kernpa_end % PAGE_SIZE != 0) {
269 fatal("init_prekern: kernpa_end not aligned");
270 }
271 if (kernpa_end <= kernpa_start) {
272 fatal("init_prekern: kernpa_end >= kernpa_start");
273 }
274
275 /*
276 * Our physical space starts after the end of the kernel.
277 */
278 if (pa_start < kernpa_end) {
279 fatal("init_prekern: physical space inside kernel");
280 }
281 mm_init(pa_start);
282
283 /*
284 * Init the IDT. We mostly don't care about this, it's just here
285 * to properly handle traps.
286 */
287 init_idt();
288
289 print_state(STATE_NORMAL, "Prekern loaded");
290
291 /*
292 * Init the PRNG.
293 */
294 prng_init();
295
296 /*
297 * Relocate the kernel.
298 */
299 mm_map_kernel();
300 elf_build_info();
301 ent = elf_kernel_reloc();
302 mm_bootspace_mprotect();
303
304 /*
305 * Build the arguments.
306 */
307 init_prekern_args();
308
309 /*
310 * Finally, jump into the kernel.
311 */
312 print_state(STATE_NORMAL, "Jumping into the kernel");
313 jump_kernel(ent);
314
315 fatal("init_prekern: unreachable!");
316 }
317