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 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 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 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 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 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 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 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 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