prekern.c revision 1.3 1 /* $NetBSD: prekern.c,v 1.3 2017/10/29 11:28:30 maxv Exp $ */
2
3 /*
4 * Copyright (c) 2017 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 extern uint64_t *gdt64_start;
50 uint8_t idtstore[PAGE_SIZE];
51 uint8_t faultstack[PAGE_SIZE];
52 struct x86_64_tss prekern_tss;
53
54 /* GDT offsets */
55 #define PREKERN_GDT_NUL_OFF (0 * 8)
56 #define PREKERN_GDT_CS_OFF (1 * 8)
57 #define PREKERN_GDT_DS_OFF (2 * 8)
58 #define PREKERN_GDT_TSS_OFF (3 * 8)
59
60 #define IDTVEC(name) __CONCAT(X, name)
61 typedef void (vector)(void);
62 extern vector *IDTVEC(exceptions)[];
63
64 void fatal(char *msg)
65 {
66 print("\n");
67 print_ext(RED_ON_BLACK, "********** FATAL ***********\n");
68 print_ext(RED_ON_BLACK, msg);
69 print("\n");
70 print_ext(RED_ON_BLACK, "****************************\n");
71
72 while (1);
73 }
74
75 /* -------------------------------------------------------------------------- */
76
77 struct smallframe {
78 uint64_t sf_trapno;
79 uint64_t sf_err;
80 uint64_t sf_rip;
81 uint64_t sf_cs;
82 uint64_t sf_rflags;
83 uint64_t sf_rsp;
84 uint64_t sf_ss;
85 };
86
87 static void setregion(struct region_descriptor *, void *, uint16_t);
88 static void setgate(struct gate_descriptor *, void *, int, int, int, int);
89 static void set_sys_segment(struct sys_segment_descriptor *, void *,
90 size_t, int, int, int);
91 static void set_sys_gdt(int, void *, size_t, int, int, int);
92 static void init_tss();
93 static void init_idt();
94
95 void trap(struct smallframe *);
96
97 static char *trap_type[] = {
98 "privileged instruction fault", /* 0 T_PRIVINFLT */
99 "breakpoint trap", /* 1 T_BPTFLT */
100 "arithmetic trap", /* 2 T_ARITHTRAP */
101 "asynchronous system trap", /* 3 T_ASTFLT */
102 "protection fault", /* 4 T_PROTFLT */
103 "trace trap", /* 5 T_TRCTRAP */
104 "page fault", /* 6 T_PAGEFLT */
105 "alignment fault", /* 7 T_ALIGNFLT */
106 "integer divide fault", /* 8 T_DIVIDE */
107 "non-maskable interrupt", /* 9 T_NMI */
108 "overflow trap", /* 10 T_OFLOW */
109 "bounds check fault", /* 11 T_BOUND */
110 "FPU not available fault", /* 12 T_DNA */
111 "double fault", /* 13 T_DOUBLEFLT */
112 "FPU operand fetch fault", /* 14 T_FPOPFLT */
113 "invalid TSS fault", /* 15 T_TSSFLT */
114 "segment not present fault", /* 16 T_SEGNPFLT */
115 "stack fault", /* 17 T_STKFLT */
116 "machine check fault", /* 18 T_MCA */
117 "SSE FP exception", /* 19 T_XMM */
118 "reserved trap", /* 20 T_RESERVED */
119 };
120 int trap_types = __arraycount(trap_type);
121
122 /*
123 * Trap handler.
124 */
125 void
126 trap(struct smallframe *sf)
127 {
128 uint64_t trapno = sf->sf_trapno;
129 char *buf;
130
131 if (trapno < trap_types) {
132 buf = trap_type[trapno];
133 } else {
134 buf = "unknown trap";
135 }
136
137 print("\n");
138 print_ext(RED_ON_BLACK, "****** FAULT OCCURRED ******\n");
139 print_ext(RED_ON_BLACK, buf);
140 print("\n");
141 print_ext(RED_ON_BLACK, "****************************\n");
142
143 while (1);
144 }
145
146 static void
147 setregion(struct region_descriptor *rd, void *base, uint16_t limit)
148 {
149 rd->rd_limit = limit;
150 rd->rd_base = (uint64_t)base;
151 }
152
153 static void
154 setgate(struct gate_descriptor *gd, void *func, int ist, int type, int dpl,
155 int sel)
156 {
157 gd->gd_looffset = (uint64_t)func & 0xffff;
158 gd->gd_selector = sel;
159 gd->gd_ist = ist;
160 gd->gd_type = type;
161 gd->gd_dpl = dpl;
162 gd->gd_p = 1;
163 gd->gd_hioffset = (uint64_t)func >> 16;
164 gd->gd_zero = 0;
165 gd->gd_xx1 = 0;
166 gd->gd_xx2 = 0;
167 gd->gd_xx3 = 0;
168 }
169
170 static void
171 set_sys_segment(struct sys_segment_descriptor *sd, void *base, size_t limit,
172 int type, int dpl, int gran)
173 {
174 memset(sd, 0, sizeof(*sd));
175 sd->sd_lolimit = (unsigned)limit;
176 sd->sd_lobase = (uint64_t)base;
177 sd->sd_type = type;
178 sd->sd_dpl = dpl;
179 sd->sd_p = 1;
180 sd->sd_hilimit = (unsigned)limit >> 16;
181 sd->sd_gran = gran;
182 sd->sd_hibase = (uint64_t)base >> 24;
183 }
184
185 static void
186 set_sys_gdt(int slotoff, void *base, size_t limit, int type, int dpl, int gran)
187 {
188 struct sys_segment_descriptor sd;
189
190 set_sys_segment(&sd, base, limit, type, dpl, gran);
191
192 memcpy(&gdt64_start + slotoff, &sd, sizeof(sd));
193 }
194
195 static void init_tss()
196 {
197 memset(&prekern_tss, 0, sizeof(prekern_tss));
198 prekern_tss.tss_ist[0] = (uintptr_t)(&faultstack[PAGE_SIZE-1]) & ~0xf;
199
200 set_sys_gdt(PREKERN_GDT_TSS_OFF, &prekern_tss,
201 sizeof(struct x86_64_tss) - 1, SDT_SYS386TSS, SEL_KPL, 0);
202 }
203
204 static void init_idt()
205 {
206 struct region_descriptor region;
207 struct gate_descriptor *idt;
208 size_t i;
209
210 idt = (struct gate_descriptor *)&idtstore;
211 for (i = 0; i < NCPUIDT; i++) {
212 setgate(&idt[i], IDTVEC(exceptions)[i], 0, SDT_SYS386IGT,
213 SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
214 }
215
216 setregion(®ion, &idtstore, PAGE_SIZE - 1);
217 lidt(®ion);
218 }
219
220 /* -------------------------------------------------------------------------- */
221
222 struct prekern_args {
223 int boothowto;
224 void *bootinfo;
225 void *bootspace;
226 int esym;
227 int biosextmem;
228 int biosbasemem;
229 int cpuid_level;
230 uint32_t nox_flag;
231 uint64_t PDPpaddr;
232 vaddr_t atdevbase;
233 vaddr_t lwp0uarea;
234 paddr_t first_avail;
235 };
236
237 struct prekern_args pkargs;
238
239 static void
240 init_prekern_args()
241 {
242 extern struct bootspace bootspace;
243 extern int esym;
244 extern int biosextmem;
245 extern int biosbasemem;
246 extern int cpuid_level;
247 extern uint32_t nox_flag;
248 extern uint64_t PDPpaddr;
249 extern vaddr_t iom_base;
250 extern paddr_t stkpa;
251 extern paddr_t pa_avail;
252
253 memset(&pkargs, 0, sizeof(pkargs));
254 pkargs.boothowto = boothowto;
255 pkargs.bootinfo = (void *)&bootinfo;
256 pkargs.bootspace = &bootspace;
257 pkargs.esym = esym;
258 pkargs.biosextmem = biosextmem;
259 pkargs.biosbasemem = biosbasemem;
260 pkargs.cpuid_level = cpuid_level;
261 pkargs.nox_flag = nox_flag;
262 pkargs.PDPpaddr = PDPpaddr;
263 pkargs.atdevbase = iom_base;
264 pkargs.lwp0uarea = bootspace.boot.va + (stkpa - bootspace.boot.pa);
265 pkargs.first_avail = pa_avail;
266
267 extern vaddr_t stkva;
268 stkva = pkargs.lwp0uarea + (USPACE - FRAMESIZE);
269 }
270
271 void
272 exec_kernel(vaddr_t ent)
273 {
274 int (*jumpfunc)(struct prekern_args *);
275 int ret;
276
277 /*
278 * Normally, the function does not return. If it does, it means the
279 * kernel had trouble processing the arguments, and we panic here. The
280 * return value is here for debug.
281 */
282 jumpfunc = (void *)ent;
283 ret = (*jumpfunc)(&pkargs);
284
285 if (ret == -1) {
286 fatal("kernel returned -1");
287 } else {
288 fatal("kernel returned unknown value");
289 }
290 }
291
292 /*
293 * Main entry point of the Prekern.
294 */
295 void
296 init_prekern(paddr_t pa_start)
297 {
298 vaddr_t ent;
299
300 init_cons();
301 print_banner();
302
303 if (kernpa_start == 0 || kernpa_end == 0) {
304 fatal("init_prekern: unable to locate the kernel");
305 }
306 if (kernpa_start != (1UL << 21)) {
307 fatal("init_prekern: invalid kernpa_start");
308 }
309 if (kernpa_start % PAGE_SIZE != 0) {
310 fatal("init_prekern: kernpa_start not aligned");
311 }
312 if (kernpa_end % PAGE_SIZE != 0) {
313 fatal("init_prekern: kernpa_end not aligned");
314 }
315 if (kernpa_end <= kernpa_start) {
316 fatal("init_prekern: kernpa_end >= kernpa_start");
317 }
318
319 /*
320 * Our physical space starts after the end of the kernel.
321 */
322 if (pa_start < kernpa_end) {
323 fatal("init_prekern: physical space inside kernel");
324 }
325 mm_init(pa_start);
326
327 /*
328 * Init the TSS and IDT. We mostly don't care about this, they are just
329 * here to properly handle traps.
330 */
331 init_tss();
332 init_idt();
333
334 print_state(true, "Prekern loaded");
335
336 /*
337 * Relocate the kernel.
338 */
339 mm_map_kernel();
340 ent = elf_kernel_reloc();
341
342 /*
343 * Build the arguments.
344 */
345 init_prekern_args();
346
347 /*
348 * Finally, jump into the kernel.
349 */
350 print_state(true, "Jumping into the kernel");
351 jump_kernel(ent);
352
353 fatal("init_prekern: unreachable!");
354 }
355
356