xref: /netbsd-src/sys/arch/amd64/stand/prekern/prekern.c (revision dadf0eef45c0862a0008b5e5b75d17ad81495ef6)
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(&region, &idtstore, PAGE_SIZE - 1);
169 	lidt(&region);
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