1 /* 2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 * 58 * $FreeBSD: src/sys/boot/i386/loader/main.c,v 1.28 2003/08/25 23:28:32 obrien Exp $ 59 */ 60 61 /* 62 * MD bootstrap main() and assorted miscellaneous 63 * commands. 64 */ 65 66 #include <stand.h> 67 #include <string.h> 68 #include <machine/bootinfo.h> 69 #include <machine/psl.h> 70 #include <sys/reboot.h> 71 72 #include "bootstrap.h" 73 #include "libi386/libi386.h" 74 #include "libi386/smbios.h" 75 #include "btxv86.h" 76 77 #define KARGS_FLAGS_CD 0x1 78 #define KARGS_FLAGS_PXE 0x2 79 80 /* Arguments passed in from the boot1/boot2 loader */ 81 static struct 82 { 83 u_int32_t howto; 84 u_int32_t bootdev; 85 u_int32_t bootflags; 86 u_int32_t pxeinfo; 87 u_int32_t res2; 88 u_int32_t bootinfo; 89 } *kargs; 90 91 static u_int32_t initial_howto; 92 static u_int32_t initial_bootdev; 93 static struct bootinfo *initial_bootinfo; 94 95 struct arch_switch archsw; /* MI/MD interface boundary */ 96 97 static void extract_currdev(void); 98 static int isa_inb(int port); 99 static void isa_outb(int port, int value); 100 void exit(int code); 101 102 /* from vers.c */ 103 extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 104 105 /* XXX debugging */ 106 extern char _end[]; 107 108 #define COMCONSOLE_DEBUG 109 #ifdef COMCONSOLE_DEBUG 110 111 static void 112 WDEBUG_INIT(void) 113 { 114 isa_outb(0x3f8+3, 0x83); /* DLAB + 8N1 */ 115 isa_outb(0x3f8+0, (115200 / 115200) & 0xFF); 116 isa_outb(0x3f8+1, (115200 / 115200) >> 8); 117 isa_outb(0x3f8+3, 0x03); /* 8N1 */ 118 isa_outb(0x3f8+4, 0x03); /* RTS+DTR */ 119 isa_outb(0x3f8+2, 0x01); /* FIFO_ENABLE */ 120 } 121 122 static void 123 WDEBUG(char c) 124 { 125 isa_outb(0x3f8, c); 126 } 127 128 #else 129 130 #define WDEBUG(x) 131 #define WDEBUG_INIT() 132 133 #endif 134 135 int 136 main(void) 137 { 138 char *memend; 139 int i; 140 141 WDEBUG_INIT(); 142 WDEBUG('X'); 143 144 /* Pick up arguments */ 145 kargs = (void *)__args; 146 initial_howto = kargs->howto; 147 initial_bootdev = kargs->bootdev; 148 initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; 149 150 #ifdef COMCONSOLE_DEBUG 151 printf("args at %p initial_howto = %08x bootdev = %08x bootinfo = %p\n", 152 kargs, initial_howto, initial_bootdev, initial_bootinfo); 153 #endif 154 155 /* Initialize the v86 register set to a known-good state. */ 156 bzero(&v86, sizeof(v86)); 157 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 158 159 160 /* 161 * Initialize the heap as early as possible. Once this is done, 162 * malloc() is usable. 163 * 164 * Don't include our stack in the heap. If the stack is in low 165 * user memory use {end,bios_basemem}. If the stack is in high 166 * user memory but not extended memory then don't let the heap 167 * overlap the stack. If the stack is in extended memory limit 168 * the heap to bios_basemem. 169 * 170 * Be sure to use the virtual bios_basemem address rather then 171 * the physical bios_basemem address or we may overwrite BIOS 172 * data. 173 */ 174 bios_getmem(); 175 memend = (char *)&memend - 0x8000; /* space for stack (16K) */ 176 memend = (char *)((uintptr_t)memend & ~(uintptr_t)(0x1000 - 1)); 177 178 /* 179 * Steal the heap from high memory. bios_basemem no longer has 180 * enough space, last failure was the gunzip code for initrd.img 181 * needing > ~32KB of temporary buffer space and we ran out. again. 182 * 183 * High memory reserves at least ~1MB for the loader. 184 */ 185 #if 0 186 if (memend < (char *)_end) { 187 setheap((void *)_end, PTOV(bios_basemem)); 188 } else { 189 if (memend > (char *)PTOV(bios_basemem)) 190 memend = (char *)PTOV(bios_basemem); 191 setheap((void *)_end, memend); 192 } 193 #endif 194 setheap((void *)heapbase, (void *)memtop); 195 196 /* 197 * XXX Chicken-and-egg problem; we want to have console output early, 198 * but some console attributes may depend on reading from eg. the boot 199 * device, which we can't do yet. 200 * 201 * We can use printf() etc. once this is done. The previous boot stage 202 * might have requested a video or serial preference, in which case we 203 * set it. If neither is specified or both are specified we leave the 204 * console environment variable alone, defaulting to dual boot. 205 */ 206 if (initial_howto & RB_MUTE) { 207 setenv("console", "nullconsole", 1); 208 } else if ((initial_howto & (RB_VIDEO|RB_SERIAL)) != (RB_VIDEO|RB_SERIAL)) { 209 if (initial_howto & RB_VIDEO) 210 setenv("console", "vidconsole", 1); 211 if (initial_howto & RB_SERIAL) 212 setenv("console", "comconsole", 1); 213 } 214 cons_probe(); 215 216 /* 217 * Initialise the block cache 218 */ 219 bcache_init(32, 512); /* 16k cache XXX tune this */ 220 221 /* 222 * Special handling for PXE and CD booting. 223 */ 224 if (kargs->bootinfo == 0) { 225 /* 226 * We only want the PXE disk to try to init itself in the below 227 * walk through devsw if we actually booted off of PXE. 228 */ 229 if (kargs->bootflags & KARGS_FLAGS_PXE) 230 pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); 231 else if (kargs->bootflags & KARGS_FLAGS_CD) 232 bc_add(initial_bootdev); 233 } 234 235 /* 236 * March through the device switch probing for things. 237 */ 238 for (i = 0; devsw[i] != NULL; i++) { 239 WDEBUG('M' + i); 240 if (devsw[i]->dv_init != NULL) 241 (devsw[i]->dv_init)(); 242 WDEBUG('M' + i); 243 } 244 printf("BIOS %dkB/%dkB available memory\n", 245 bios_basemem / 1024, bios_extmem / 1024); 246 if (initial_bootinfo != NULL) { 247 initial_bootinfo->bi_basemem = bios_basemem / 1024; 248 initial_bootinfo->bi_extmem = bios_extmem / 1024; 249 } 250 251 /* detect ACPI for future reference */ 252 biosacpi_detect(); 253 254 /* detect SMBIOS for future reference */ 255 smbios_detect(NULL); 256 257 /* enable EHCI */ 258 setenv("ehci_load", "YES", 1); 259 260 /* enable XHCI */ 261 setenv("xhci_load", "YES", 1); 262 263 printf("\n"); 264 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 265 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 266 267 extract_currdev(); /* set $currdev and $loaddev */ 268 setenv("LINES", "24", 1); /* optional */ 269 270 bios_getsmap(); 271 272 archsw.arch_autoload = i386_autoload; 273 archsw.arch_getdev = i386_getdev; 274 archsw.arch_copyin = i386_copyin; 275 archsw.arch_copyout = i386_copyout; 276 archsw.arch_readin = i386_readin; 277 archsw.arch_isainb = isa_inb; 278 archsw.arch_isaoutb = isa_outb; 279 280 interact(); /* doesn't return */ 281 282 /* if we ever get here, it is an error */ 283 return (1); 284 } 285 286 /* 287 * Set the 'current device' by (if possible) recovering the boot device as 288 * supplied by the initial bootstrap. 289 * 290 * XXX should be extended for netbooting. 291 */ 292 static void 293 extract_currdev(void) 294 { 295 struct i386_devdesc new_currdev; 296 int biosdev = -1; 297 298 /* Assume we are booting from a BIOS disk by default */ 299 new_currdev.d_dev = &biosdisk; 300 301 /* new-style boot loaders such as pxeldr and cdldr */ 302 if (kargs->bootinfo == 0) { 303 if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { 304 /* we are booting from a CD with cdboot */ 305 new_currdev.d_dev = &bioscd; 306 new_currdev.d_kind.bioscd.unit = bc_bios2unit(initial_bootdev); 307 } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { 308 /* we are booting from pxeldr */ 309 new_currdev.d_dev = &pxedisk; 310 new_currdev.d_kind.netif.unit = 0; 311 } else { 312 /* we don't know what our boot device is */ 313 new_currdev.d_kind.biosdisk.slice = -1; 314 new_currdev.d_kind.biosdisk.partition = 0; 315 biosdev = -1; 316 } 317 } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { 318 /* The passed-in boot device is bad */ 319 new_currdev.d_kind.biosdisk.slice = -1; 320 new_currdev.d_kind.biosdisk.partition = 0; 321 biosdev = -1; 322 } else { 323 new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; 324 new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); 325 biosdev = initial_bootinfo->bi_bios_dev; 326 327 /* 328 * If we are booted by an old bootstrap, we have to guess at the BIOS 329 * unit number. We will loose if there is more than one disk type 330 * and we are not booting from the lowest-numbered disk type 331 * (ie. SCSI when IDE also exists). 332 */ 333 if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ 334 biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ 335 } 336 new_currdev.d_type = new_currdev.d_dev->dv_type; 337 338 /* 339 * If we are booting off of a BIOS disk and we didn't succeed in determining 340 * which one we booted off of, just use disk0: as a reasonable default. 341 */ 342 if ((new_currdev.d_type == biosdisk.dv_type) && 343 ((new_currdev.d_kind.biosdisk.unit = bd_bios2unit(biosdev)) == -1)) { 344 printf("Can't work out which disk we are booting from.\n" 345 "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); 346 new_currdev.d_kind.biosdisk.unit = 0; 347 } 348 env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), 349 i386_setcurrdev, env_nounset); 350 env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, 351 env_nounset); 352 } 353 354 COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 355 356 static int 357 command_reboot(int argc, char *argv[]) 358 { 359 int i; 360 361 for (i = 0; devsw[i] != NULL; ++i) 362 if (devsw[i]->dv_cleanup != NULL) 363 (devsw[i]->dv_cleanup)(); 364 365 printf("Rebooting...\n"); 366 delay(1000000); 367 __exit(0); 368 } 369 370 /* provide this for panic, as it's not in the startup code */ 371 void 372 exit(int code) 373 { 374 __exit(code); 375 } 376 377 COMMAND_SET(heap, "heap", "show heap usage", command_heap); 378 379 static int 380 command_heap(int argc, char *argv[]) 381 { 382 char *base; 383 size_t bytes; 384 385 mallocstats(); 386 base = getheap(&bytes); 387 printf("heap %p-%p (%d)\n", base, base + bytes, (int)bytes); 388 printf("stack at %p\n", &argc); 389 return(CMD_OK); 390 } 391 392 /* ISA bus access functions for PnP, derived from <machine/cpufunc.h> */ 393 static int 394 isa_inb(int port) 395 { 396 u_char data; 397 398 if (__builtin_constant_p(port) && 399 (((port) & 0xffff) < 0x100) && 400 ((port) < 0x10000)) { 401 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 402 } else { 403 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 404 } 405 return(data); 406 } 407 408 static void 409 isa_outb(int port, int value) 410 { 411 u_char al = value; 412 413 if (__builtin_constant_p(port) && 414 (((port) & 0xffff) < 0x100) && 415 ((port) < 0x10000)) { 416 __asm __volatile("outb %0,%1" : : "a" (al), "id" ((u_short)(port))); 417 } else { 418 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 419 } 420 } 421 422