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$"); 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 "btxv86.h" 47 48#ifdef LOADER_ZFS_SUPPORT 49#include "../zfs/libzfs.h" 50#endif 51 52CTASSERT(sizeof(struct bootargs) == BOOTARGS_SIZE); 53CTASSERT(offsetof(struct bootargs, bootinfo) == BA_BOOTINFO); 54CTASSERT(offsetof(struct bootargs, bootflags) == BA_BOOTFLAGS); 55CTASSERT(offsetof(struct bootinfo, bi_size) == BI_SIZE); 56 57/* Arguments passed in from the boot1/boot2 loader */ 58static struct bootargs *kargs; 59 60static u_int32_t initial_howto; 61static u_int32_t initial_bootdev; 62static struct bootinfo *initial_bootinfo; 63 64struct arch_switch archsw; /* MI/MD interface boundary */ 65 66static void extract_currdev(void); 67static int isa_inb(int port); 68static void isa_outb(int port, int value); 69void exit(int code); 70#ifdef LOADER_ZFS_SUPPORT 71static void i386_zfs_probe(void); 72#endif 73 74/* from vers.c */ 75extern char bootprog_name[], bootprog_rev[], bootprog_date[], bootprog_maker[]; 76 77/* XXX debugging */ 78extern char end[]; 79 80static void *heap_top; 81static void *heap_bottom; 82 83int 84main(void) 85{ 86 int i; 87 88 /* Pick up arguments */ 89 kargs = (void *)__args; 90 initial_howto = kargs->howto; 91 initial_bootdev = kargs->bootdev; 92 initial_bootinfo = kargs->bootinfo ? (struct bootinfo *)PTOV(kargs->bootinfo) : NULL; 93 94 /* Initialize the v86 register set to a known-good state. */ 95 bzero(&v86, sizeof(v86)); 96 v86.efl = PSL_RESERVED_DEFAULT | PSL_I; 97 98 /* 99 * Initialise the heap as early as possible. Once this is done, malloc() is usable. 100 */ 101 bios_getmem(); 102 103#if defined(LOADER_BZIP2_SUPPORT) || defined(LOADER_FIREWIRE_SUPPORT) || \ 104 defined(LOADER_GPT_SUPPORT) || defined(LOADER_ZFS_SUPPORT) 105 if (high_heap_size > 0) { 106 heap_top = PTOV(high_heap_base + high_heap_size); 107 heap_bottom = PTOV(high_heap_base); 108 if (high_heap_base < memtop_copyin) 109 memtop_copyin = high_heap_base; 110 } else 111#endif 112 { 113 heap_top = (void *)PTOV(bios_basemem); 114 heap_bottom = (void *)end; 115 } 116 setheap(heap_bottom, heap_top); 117 118 /* 119 * XXX Chicken-and-egg problem; we want to have console output early, but some 120 * console attributes may depend on reading from eg. the boot device, which we 121 * can't do yet. 122 * 123 * We can use printf() etc. once this is done. 124 * If the previous boot stage has requested a serial console, prefer that. 125 */ 126 bi_setboothowto(initial_howto); 127 if (initial_howto & RB_MULTIPLE) { 128 if (initial_howto & RB_SERIAL) 129 setenv("console", "comconsole vidconsole", 1); 130 else 131 setenv("console", "vidconsole comconsole", 1); 132 } else if (initial_howto & RB_SERIAL) 133 setenv("console", "comconsole", 1); 134 else if (initial_howto & RB_MUTE) 135 setenv("console", "nullconsole", 1); 136 cons_probe(); 137 138 /* 139 * Initialise the block cache 140 */ 141 bcache_init(32, 512); /* 16k cache XXX tune this */ 142 143 /* 144 * Special handling for PXE and CD booting. 145 */ 146 if (kargs->bootinfo == 0) { 147 /* 148 * We only want the PXE disk to try to init itself in the below 149 * walk through devsw if we actually booted off of PXE. 150 */ 151 if (kargs->bootflags & KARGS_FLAGS_PXE) 152 pxe_enable(kargs->pxeinfo ? PTOV(kargs->pxeinfo) : NULL); 153 else if (kargs->bootflags & KARGS_FLAGS_CD) 154 bc_add(initial_bootdev); 155 } 156 157 archsw.arch_autoload = i386_autoload; 158 archsw.arch_getdev = i386_getdev; 159 archsw.arch_copyin = i386_copyin; 160 archsw.arch_copyout = i386_copyout; 161 archsw.arch_readin = i386_readin; 162 archsw.arch_isainb = isa_inb; 163 archsw.arch_isaoutb = isa_outb; 164#ifdef LOADER_ZFS_SUPPORT 165 archsw.arch_zfs_probe = i386_zfs_probe; 166#endif 167 168 /* 169 * March through the device switch probing for things. 170 */ 171 for (i = 0; devsw[i] != NULL; i++) 172 if (devsw[i]->dv_init != NULL) 173 (devsw[i]->dv_init)(); 174 printf("BIOS %dkB/%dkB available memory\n", bios_basemem / 1024, bios_extmem / 1024); 175 if (initial_bootinfo != NULL) { 176 initial_bootinfo->bi_basemem = bios_basemem / 1024; 177 initial_bootinfo->bi_extmem = bios_extmem / 1024; 178 } 179 180 /* detect ACPI for future reference */ 181 biosacpi_detect(); 182 183 /* detect SMBIOS for future reference */ 184 smbios_detect(); 185 186 printf("\n"); 187 printf("%s, Revision %s\n", bootprog_name, bootprog_rev); 188 printf("(%s, %s)\n", bootprog_maker, bootprog_date); 189 190 extract_currdev(); /* set $currdev and $loaddev */ 191 setenv("LINES", "24", 1); /* optional */ 192 193 bios_getsmap(); 194 195 interact(); /* doesn't return */ 196 197 /* if we ever get here, it is an error */ 198 return (1); 199} 200 201/* 202 * Set the 'current device' by (if possible) recovering the boot device as 203 * supplied by the initial bootstrap. 204 * 205 * XXX should be extended for netbooting. 206 */ 207static void 208extract_currdev(void) 209{ 210 struct i386_devdesc new_currdev; 211#ifdef LOADER_ZFS_SUPPORT 212 char buf[20]; 213 struct zfs_boot_args *zargs; 214#endif 215 int biosdev = -1; 216 217 /* Assume we are booting from a BIOS disk by default */ 218 new_currdev.d_dev = &biosdisk; 219 220 /* new-style boot loaders such as pxeldr and cdldr */ 221 if (kargs->bootinfo == 0) { 222 if ((kargs->bootflags & KARGS_FLAGS_CD) != 0) { 223 /* we are booting from a CD with cdboot */ 224 new_currdev.d_dev = &bioscd; 225 new_currdev.d_unit = bc_bios2unit(initial_bootdev); 226 } else if ((kargs->bootflags & KARGS_FLAGS_PXE) != 0) { 227 /* we are booting from pxeldr */ 228 new_currdev.d_dev = &pxedisk; 229 new_currdev.d_unit = 0; 230 } else { 231 /* we don't know what our boot device is */ 232 new_currdev.d_kind.biosdisk.slice = -1; 233 new_currdev.d_kind.biosdisk.partition = 0; 234 biosdev = -1; 235 } 236#ifdef LOADER_ZFS_SUPPORT 237 } else if ((kargs->bootflags & KARGS_FLAGS_ZFS) != 0) { 238 zargs = NULL; 239 /* check for new style extended argument */ 240 if ((kargs->bootflags & KARGS_FLAGS_EXTARG) != 0) 241 zargs = (struct zfs_boot_args *)(kargs + 1); 242 243 if (zargs != NULL && 244 zargs->size >= offsetof(struct zfs_boot_args, primary_pool)) { 245 /* sufficient data is provided */ 246 new_currdev.d_kind.zfs.pool_guid = zargs->pool; 247 new_currdev.d_kind.zfs.root_guid = zargs->root; 248 if (zargs->size >= sizeof(*zargs) && zargs->primary_vdev != 0) { 249 sprintf(buf, "%llu", zargs->primary_pool); 250 setenv("vfs.zfs.boot.primary_pool", buf, 1); 251 sprintf(buf, "%llu", zargs->primary_vdev); 252 setenv("vfs.zfs.boot.primary_vdev", buf, 1); 253 } 254 } else { 255 /* old style zfsboot block */ 256 new_currdev.d_kind.zfs.pool_guid = kargs->zfspool; 257 new_currdev.d_kind.zfs.root_guid = 0; 258 } 259 new_currdev.d_dev = &zfs_dev; 260#endif 261 } else if ((initial_bootdev & B_MAGICMASK) != B_DEVMAGIC) { 262 /* The passed-in boot device is bad */ 263 new_currdev.d_kind.biosdisk.slice = -1; 264 new_currdev.d_kind.biosdisk.partition = 0; 265 biosdev = -1; 266 } else { 267 new_currdev.d_kind.biosdisk.slice = B_SLICE(initial_bootdev) - 1; 268 new_currdev.d_kind.biosdisk.partition = B_PARTITION(initial_bootdev); 269 biosdev = initial_bootinfo->bi_bios_dev; 270 271 /* 272 * If we are booted by an old bootstrap, we have to guess at the BIOS 273 * unit number. We will lose if there is more than one disk type 274 * and we are not booting from the lowest-numbered disk type 275 * (ie. SCSI when IDE also exists). 276 */ 277 if ((biosdev == 0) && (B_TYPE(initial_bootdev) != 2)) /* biosdev doesn't match major */ 278 biosdev = 0x80 + B_UNIT(initial_bootdev); /* assume harddisk */ 279 } 280 new_currdev.d_type = new_currdev.d_dev->dv_type; 281 282 /* 283 * If we are booting off of a BIOS disk and we didn't succeed in determining 284 * which one we booted off of, just use disk0: as a reasonable default. 285 */ 286 if ((new_currdev.d_type == biosdisk.dv_type) && 287 ((new_currdev.d_unit = bd_bios2unit(biosdev)) == -1)) { 288 printf("Can't work out which disk we are booting from.\n" 289 "Guessed BIOS device 0x%x not found by probes, defaulting to disk0:\n", biosdev); 290 new_currdev.d_unit = 0; 291 } 292 293 env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), 294 i386_setcurrdev, env_nounset); 295 env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset, 296 env_nounset); 297} 298 299COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); 300 301static int 302command_reboot(int argc, char *argv[]) 303{ 304 int i; 305 306 for (i = 0; devsw[i] != NULL; ++i) 307 if (devsw[i]->dv_cleanup != NULL) 308 (devsw[i]->dv_cleanup)(); 309 310 printf("Rebooting...\n"); 311 delay(1000000); 312 __exit(0); 313} 314 315/* provide this for panic, as it's not in the startup code */ 316void 317exit(int code) 318{ 319 __exit(code); 320} 321 322COMMAND_SET(heap, "heap", "show heap usage", command_heap); 323 324static int 325command_heap(int argc, char *argv[]) 326{ 327 mallocstats(); 328 printf("heap base at %p, top at %p, upper limit at %p\n", heap_bottom, 329 sbrk(0), heap_top); 330 return(CMD_OK); 331} 332 333#ifdef LOADER_ZFS_SUPPORT 334COMMAND_SET(lszfs, "lszfs", "list child datasets of a zfs dataset", 335 command_lszfs); 336 337static int 338command_lszfs(int argc, char *argv[]) 339{ 340 int err; 341 342 if (argc != 2) { 343 command_errmsg = "wrong number of arguments"; 344 return (CMD_ERROR); 345 } 346 347 err = zfs_list(argv[1]); 348 if (err != 0) { 349 command_errmsg = strerror(err); 350 return (CMD_ERROR); 351 } 352 return (CMD_OK); 353} 354#endif 355 356/* ISA bus access functions for PnP. */ 357static int 358isa_inb(int port) 359{ 360 361 return (inb(port)); 362} 363 364static void 365isa_outb(int port, int value) 366{ 367 368 outb(port, value); 369} 370 371#ifdef LOADER_ZFS_SUPPORT 372static void 373i386_zfs_probe(void) 374{ 375 char devname[32]; 376 int unit; 377 378 /* 379 * Open all the disks we can find and see if we can reconstruct 380 * ZFS pools from them. 381 */ 382 for (unit = 0; unit < MAXBDDEV; unit++) { 383 if (bd_unit2bios(unit) == -1) 384 break; 385 sprintf(devname, "disk%d:", unit); 386 zfs_probe_dev(devname, NULL); 387 } 388} 389#endif 390