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