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