main.c revision 293802
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/10/sys/boot/i386/loader/main.c 293802 2016-01-13 01:50:02Z allanjude $"); 29 30/* 31 * MD bootstrap main() and assorted miscellaneous 32 * commands. 33 */ 34 35#include <stand.h> 36#include <stddef.h> 37#include <string.h> 38#include <machine/bootinfo.h> 39#include <machine/cpufunc.h> 40#include <machine/psl.h> 41#include <sys/reboot.h> 42 43#include "bootstrap.h" 44#include "common/bootargs.h" 45#include "libi386/libi386.h" 46#include "libi386/smbios.h" 47#include "btxv86.h" 48 49#ifdef LOADER_ZFS_SUPPORT 50#include "../zfs/libzfs.h" 51#endif 52 53CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); 54CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); 55CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); 56CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); 57 58/* Arguments passed in from the boot1/boot2 loader */ 59static struct bootargs *kargs; 60 61static u_int32_t initial_howto; 62static u_int32_t initial_bootdev; 63static struct bootinfo *initial_bootinfo; 64 65struct arch_switch archsw; /* MI/MD interface boundary */ 66 67static void extract_currdev(void); 68static int isa_inb(int port); 69static void isa_outb(int port, int value); 70void exit(int code); 71#ifdef LOADER_ZFS_SUPPORT 72static void init_zfs_bootenv(char *currdev); 73static void i386_zfs_probe(void); 74#endif 75 76/* from vers.c */ 77extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 78 79/* XXX debugging */ 80extern char end[]; 81 82static void *heap_top; 83static void *heap_bottom; 84 85int 86main(void) 87{ 88 int i; 89 90 /* Pick up arguments */ 91 kargs = (void *)__args; 92 initial_howto = kargs->howto; 93 initial_bootdev = kargs->bootdev; 94 initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; 95 96 /* Initialize the v86 register set to a known-good state. */ 97 bzero(&v86, sizeof(v86)); 98 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 99 100 /* 101 * Initialise the heap as early as possible. Once this is done, malloc() is usable. 102 */ 103 bios_getmem(); 104 105#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ 106 defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) 107 if (high_heap_size > 0) { 108 heap_top = PTOV(high_heap_base + high_heap_size); 109 heap_bottom = PTOV(high_heap_base); 110 if (high_heap_base < memtop_copyin) 111 memtop_copyin = high_heap_base; 112 } else 113#endif 114 { 115 heap_top = (void *)PTOV(bios_basemem); 116 heap_bottom = (void *)end; 117 } 118 setheap(heap_bottom, heap_top); 119 120 /* 121 * XXX Chicken-and-egg problem; we want to have console output early, but some 122 * console attributes may depend on reading from eg. the boot device, which we 123 * can't do yet. 124 * 125 * We can use printf() etc. once this is done. 126 * If the previous boot stage has requested a serial console, prefer that. 127 */ 128 bi_setboothowto(initial_howto); 129 if (initial_howto & RB_MULTIPLE) { 130 if (initial_howto & RB_SERIAL) 131 setenv("console", "comconsole vidconsole", 1); 132 else 133 setenv("console", "vidconsole comconsole", 1); 134 } else if (initial_howto & RB_SERIAL) 135 setenv("console", "comconsole", 1); 136 else if (initial_howto & RB_MUTE) 137 setenv("console", "nullconsole", 1); 138 cons_probe(); 139 140 /* 141 * Initialise the block cache 142 */ 143 bcache_init(32, 512); /* 16k cache XXX tune this */ 144 145 /* 146 * Special handling for PXE and CD booting. 147 */ 148 if (kargs->bootinfo == 0) { 149 /* 150 * We only want the PXE disk to try to init itself in the below 151 * walk through devsw if we actually booted off of PXE. 152 */ 153 if (kargs->bootflags & KARGS_FLAGS_PXE) 154 pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); 155 else if (kargs->bootflags & KARGS_FLAGS_CD) 156 bc_add(initial_bootdev); 157 } 158 159 archsw.arch_autoload = i386_autoload; 160 archsw.arch_getdev = i386_getdev; 161 archsw.arch_copyin = i386_copyin; 162 archsw.arch_copyout = i386_copyout; 163 archsw.arch_readin = i386_readin; 164 archsw.arch_isainb = isa_inb; 165 archsw.arch_isaoutb = isa_outb; 166#ifdef LOADER_ZFS_SUPPORT 167 archsw.arch_zfs_probe = i386_zfs_probe; 168#endif 169 170 /* 171 * March through the device switch probing for things. 172 */ 173 for (i = 0; devsw[i] != NULL; i++) 174 if (devsw[i]->dv_init != NULL) 175 (devsw[i]->dv_init)(); 176 printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); 177 if (initial_bootinfo != NULL) { 178 initial_bootinfo->bi_basemem = bios_basemem / 1024; 179 initial_bootinfo->bi_extmem = bios_extmem / 1024; 180 } 181 182 /* detect ACPI for future reference */ 183 biosacpi_detect(); 184 185 /* detect SMBIOS for future reference */ 186 smbios_detect(NULL); 187 188 printf("\n"); 189 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 190 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 191 192 extract_currdev(); /* set $currdev and $loaddev */ 193 setenv("LINES", "24", 1); /* optional */ 194 195 bios_getsmap(); 196 197 interact(); /* doesn't return */ 198 199 /* if we ever get here, it is an error */ 200 return (1); 201} 202 203/* 204 * Set the 'current device' by (if possible) recovering the boot device as 205 * supplied by the initial bootstrap. 206 * 207 * XXX should be extended for netbooting. 208 */ 209static void 210extract_currdev(void) 211{ 212 struct i386_devdesc new_currdev; 213#ifdef LOADER_ZFS_SUPPORT 214 char buf[20]; 215 struct zfs_boot_args *zargs; 216#endif 217 int biosdev = -1; 218 219 /* Assume we are booting from a BIOS disk by default */ 220 new_currdev.d_dev = &biosdisk; 221 222 /* new-style boot loaders such as pxeldr and cdldr */ 223 if (kargs->bootinfo == 0) { 224 if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { 225 /* we are booting from a CD with cdboot */ 226 new_currdev.d_dev = &bioscd; 227 new_currdev.d_unit = bc_bios2unit(initial_bootdev); 228 } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { 229 /* we are booting from pxeldr */ 230 new_currdev.d_dev = &pxedisk; 231 new_currdev.d_unit = 0; 232 } else { 233 /* we don't know what our boot device is */ 234 new_currdev.d_kind.biosdisk.slice = -1; 235 new_currdev.d_kind.biosdisk.partition = 0; 236 biosdev = -1; 237 } 238#ifdef LOADER_ZFS_SUPPORT 239 } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { 240 zargs = NULL; 241 /* check for new style extended argument */ 242 if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) 243 zargs = (struct zfs_boot_args *)(kargs + 1); 244 245 if (zargs != NULL && 246 zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { 247 /* sufficient data is provided */ 248 new_currdev.d_kind.zfs.pool_guid = zargs->pool; 249 new_currdev.d_kind.zfs.root_guid = zargs->root; 250 if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { 251 sprintf(buf, "%llu", zargs->primary_pool); 252 setenv("vfs.zfs.boot.primary_pool", buf, 1); 253 sprintf(buf, "%llu", zargs->primary_vdev); 254 setenv("vfs.zfs.boot.primary_vdev", buf, 1); 255 } 256 } else { 257 /* old style zfsboot block */ 258 new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; 259 new_currdev.d_kind.zfs.root_guid = 0; 260 } 261 new_currdev.d_dev = &zfs_dev; 262#endif 263 } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { 264 /* The passed-in boot device is bad */ 265 new_currdev.d_kind.biosdisk.slice = -1; 266 new_currdev.d_kind.biosdisk.partition = 0; 267 biosdev = -1; 268 } else { 269 new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; 270 new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); 271 biosdev = initial_bootinfo->bi_bios_dev; 272 273 /* 274 * If we are booted by an old bootstrap, we have to guess at the BIOS 275 * unit number. We will lose if there is more than one disk type 276 * and we are not booting from the lowest-numbered disk type 277 * (ie. SCSI when IDE also exists). 278 */ 279 if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ 280 biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ 281 } 282 new_currdev.d_type = new_currdev.d_dev->dv_type; 283 284 /* 285 * If we are booting off of a BIOS disk and we didn't succeed in determining 286 * which one we booted off of, just use disk0: as a reasonable default. 287 */ 288 if ((new_currdev.d_type == biosdisk.dv_type) && 289 ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { 290 printf("Can't work out which disk we are booting from.\n" 291 "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); 292 new_currdev.d_unit = 0; 293 } 294 295#ifdef LOADER_ZFS_SUPPORT 296 if (new_currdev.d_type == DEVT_ZFS) 297 init_zfs_bootenv(zfs_fmtdev(&new_currdev)); 298#endif 299 300 env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), 301 i386_setcurrdev, env_nounset); 302 env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, 303 env_nounset); 304} 305 306#ifdef LOADER_ZFS_SUPPORT 307static void 308init_zfs_bootenv(char *currdev) 309{ 310 char *beroot; 311 312 if (strlen(currdev) == 0) 313 return; 314 if(strncmp(currdev, "zfs:", 4) != 0) 315 return; 316 /* Remove the trailing : */ 317 currdev[strlen(currdev) - 1] = '\0'; 318 setenv("zfs_be_active", currdev, 1); 319 setenv("zfs_be_currpage", "1", 1); 320 /* Do not overwrite if already set */ 321 setenv("vfs.root.mountfrom", currdev, 0); 322 /* Forward past zfs: */ 323 currdev = strchr(currdev, ':'); 324 currdev++; 325 /* Remove the last element (current bootenv) */ 326 beroot = strrchr(currdev, '/'); 327 if (beroot != NULL) 328 beroot[0] = '\0'; 329 beroot = currdev; 330 setenv("zfs_be_root", beroot, 1); 331} 332#endif 333 334COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 335 336static int 337command_reboot(int argc, char *argv[]) 338{ 339 int i; 340 341 for (i = 0; devsw[i] != NULL; ++i) 342 if (devsw[i]->dv_cleanup != NULL) 343 (devsw[i]->dv_cleanup)(); 344 345 printf("Rebooting...\n"); 346 delay(1000000); 347 __exit(0); 348} 349 350/* provide this for panic, as it's not in the startup code */ 351void 352exit(int code) 353{ 354 __exit(code); 355} 356 357COMMAND_SET(heap, "heap", "show heap usage", command_heap); 358 359static int 360command_heap(int argc, char *argv[]) 361{ 362 mallocstats(); 363 printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, 364 sbrk(0), heap_top); 365 return(CMD_OK); 366} 367 368#ifdef LOADER_ZFS_SUPPORT 369COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", 370 command_lszfs); 371 372static int 373command_lszfs(int argc, char *argv[]) 374{ 375 int err; 376 377 if (argc != 2) { 378 command_errmsg = "wrong number of arguments"; 379 return (CMD_ERROR); 380 } 381 382 err = zfs_list(argv[1]); 383 if (err != 0) { 384 command_errmsg = strerror(err); 385 return (CMD_ERROR); 386 } 387 388 return (CMD_OK); 389} 390 391COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments", 392 command_reloadbe); 393 394static int 395command_reloadbe(int argc, char *argv[]) 396{ 397 int err; 398 char *root; 399 400 if (argc > 2) { 401 command_errmsg = "wrong number of arguments"; 402 return (CMD_ERROR); 403 } 404 405 if (argc == 2) { 406 err = zfs_bootenv(argv[1]); 407 } else { 408 root = getenv("zfs_be_root"); 409 if (root == NULL) { 410 /* There does not appear to be a ZFS pool here, exit without error */ 411 return (CMD_OK); 412 } 413 err = zfs_bootenv(getenv("zfs_be_root")); 414 } 415 416 if (err != 0) { 417 command_errmsg = strerror(err); 418 return (CMD_ERROR); 419 } 420 421 return (CMD_OK); 422} 423#endif 424 425/* ISA bus access functions for PnP. */ 426static int 427isa_inb(int port) 428{ 429 430 return (inb(port)); 431} 432 433static void 434isa_outb(int port, int value) 435{ 436 437 outb(port, value); 438} 439 440#ifdef LOADER_ZFS_SUPPORT 441static void 442i386_zfs_probe(void) 443{ 444 char devname[32]; 445 int unit; 446 447 /* 448 * Open all the disks we can find and see if we can reconstruct 449 * ZFS pools from them. 450 */ 451 for (unit = 0; unit < MAXBDDEV; unit++) { 452 if (bd_unit2bios(unit) == -1) 453 break; 454 sprintf(devname, "disk%d:", unit); 455 zfs_probe_dev(devname, NULL); 456 } 457} 458#endif 459