14a5d661aSToomas Soome /*- 24a5d661aSToomas Soome * Copyright (c) 1998 Robert Nordier 34a5d661aSToomas Soome * All rights reserved. 44a5d661aSToomas Soome * 54a5d661aSToomas Soome * Redistribution and use in source and binary forms are freely 64a5d661aSToomas Soome * permitted provided that the above copyright notice and this 74a5d661aSToomas Soome * paragraph and the following disclaimer are duplicated in all 84a5d661aSToomas Soome * such forms. 94a5d661aSToomas Soome * 104a5d661aSToomas Soome * This software is provided "AS IS" and without any express or 114a5d661aSToomas Soome * implied warranties, including, without limitation, the implied 124a5d661aSToomas Soome * warranties of merchantability and fitness for a particular 134a5d661aSToomas Soome * purpose. 144a5d661aSToomas Soome */ 154a5d661aSToomas Soome 164a5d661aSToomas Soome #include <sys/cdefs.h> 174a5d661aSToomas Soome #include <stand.h> 184a5d661aSToomas Soome 194a5d661aSToomas Soome #include <sys/param.h> 204a5d661aSToomas Soome #include <sys/errno.h> 214a5d661aSToomas Soome #include <sys/diskmbr.h> 224a5d661aSToomas Soome #include <sys/vtoc.h> 234a5d661aSToomas Soome #include <sys/disk.h> 244a5d661aSToomas Soome #include <sys/reboot.h> 254a5d661aSToomas Soome #include <sys/queue.h> 264a5d661aSToomas Soome #include <multiboot.h> 274a5d661aSToomas Soome 284a5d661aSToomas Soome #include <machine/bootinfo.h> 294a5d661aSToomas Soome #include <machine/elf.h> 304a5d661aSToomas Soome #include <machine/pc/bios.h> 314a5d661aSToomas Soome 324a5d661aSToomas Soome #include <stdarg.h> 334a5d661aSToomas Soome #include <stddef.h> 344a5d661aSToomas Soome 354a5d661aSToomas Soome #include <a.out.h> 364a5d661aSToomas Soome #include "bootstrap.h" 374a5d661aSToomas Soome #include "libi386.h" 384a5d661aSToomas Soome #include <btxv86.h> 394a5d661aSToomas Soome 404a5d661aSToomas Soome #include "lib.h" 414a5d661aSToomas Soome #include "rbx.h" 424a5d661aSToomas Soome #include "cons.h" 434a5d661aSToomas Soome #include "bootargs.h" 444a5d661aSToomas Soome #include "disk.h" 454a5d661aSToomas Soome #include "part.h" 464a5d661aSToomas Soome #include "paths.h" 474a5d661aSToomas Soome 484a5d661aSToomas Soome #include "libzfs.h" 494a5d661aSToomas Soome 504a5d661aSToomas Soome #define ARGS 0x900 514a5d661aSToomas Soome #define NOPT 14 524a5d661aSToomas Soome #define NDEV 3 534a5d661aSToomas Soome 544a5d661aSToomas Soome #define BIOS_NUMDRIVES 0x475 554a5d661aSToomas Soome #define DRV_HARD 0x80 564a5d661aSToomas Soome #define DRV_MASK 0x7f 574a5d661aSToomas Soome 584a5d661aSToomas Soome #define TYPE_AD 0 594a5d661aSToomas Soome #define TYPE_DA 1 604a5d661aSToomas Soome #define TYPE_MAXHARD TYPE_DA 614a5d661aSToomas Soome #define TYPE_FD 2 624a5d661aSToomas Soome 634a5d661aSToomas Soome extern uint32_t _end; 644a5d661aSToomas Soome 654a5d661aSToomas Soome /* 664a5d661aSToomas Soome * Fake multiboot header to provide versioning and to pass 674a5d661aSToomas Soome * partition start LBA. Partition is either GPT partition or 684a5d661aSToomas Soome * VTOC slice. 694a5d661aSToomas Soome */ 704a5d661aSToomas Soome extern const struct multiboot_header mb_header; 714a5d661aSToomas Soome extern uint64_t start_sector; 724a5d661aSToomas Soome 734a5d661aSToomas Soome static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */ 744a5d661aSToomas Soome static const unsigned char flags[NOPT] = { 754a5d661aSToomas Soome RBX_DUAL, 764a5d661aSToomas Soome RBX_SERIAL, 774a5d661aSToomas Soome RBX_ASKNAME, 784a5d661aSToomas Soome RBX_CDROM, 794a5d661aSToomas Soome RBX_CONFIG, 804a5d661aSToomas Soome RBX_KDB, 814a5d661aSToomas Soome RBX_GDB, 824a5d661aSToomas Soome RBX_MUTE, 834a5d661aSToomas Soome RBX_NOINTR, 844a5d661aSToomas Soome RBX_PAUSE, 854a5d661aSToomas Soome RBX_QUIET, 864a5d661aSToomas Soome RBX_DFLTROOT, 874a5d661aSToomas Soome RBX_SINGLE, 884a5d661aSToomas Soome RBX_VERBOSE 894a5d661aSToomas Soome }; 904a5d661aSToomas Soome uint32_t opts; 914a5d661aSToomas Soome 924a5d661aSToomas Soome static const unsigned char dev_maj[NDEV] = {30, 4, 2}; 934a5d661aSToomas Soome 944a5d661aSToomas Soome static struct i386_devdesc *bdev; 954a5d661aSToomas Soome static char cmd[512]; 964a5d661aSToomas Soome static char cmddup[512]; 974a5d661aSToomas Soome static char kname[1024]; 984a5d661aSToomas Soome static int comspeed = SIOSPD; 994a5d661aSToomas Soome static struct bootinfo bootinfo; 1004a5d661aSToomas Soome static uint32_t bootdev; 1014a5d661aSToomas Soome static struct zfs_boot_args zfsargs; 1024a5d661aSToomas Soome 1034a5d661aSToomas Soome extern vm_offset_t high_heap_base; 1044a5d661aSToomas Soome extern uint32_t bios_basemem, bios_extmem, high_heap_size; 1054a5d661aSToomas Soome 1064a5d661aSToomas Soome static char *heap_top; 1074a5d661aSToomas Soome static char *heap_bottom; 1084a5d661aSToomas Soome 1094a5d661aSToomas Soome static void i386_zfs_probe(void); 1104a5d661aSToomas Soome void exit(int); 1114a5d661aSToomas Soome static void load(void); 1124a5d661aSToomas Soome static int parse_cmd(void); 1134a5d661aSToomas Soome 1144a5d661aSToomas Soome struct arch_switch archsw; /* MI/MD interface boundary */ 1154a5d661aSToomas Soome static char boot_devname[2 * ZFS_MAXNAMELEN + 8]; /* disk or pool:dataset */ 1164a5d661aSToomas Soome 1174a5d661aSToomas Soome struct devsw *devsw[] = { 1184a5d661aSToomas Soome &biosdisk, 1194a5d661aSToomas Soome &zfs_dev, 1204a5d661aSToomas Soome NULL 1214a5d661aSToomas Soome }; 1224a5d661aSToomas Soome 1234a5d661aSToomas Soome struct fs_ops *file_system[] = { 1244a5d661aSToomas Soome &zfs_fsops, 1254a5d661aSToomas Soome &ufs_fsops, 1264a5d661aSToomas Soome &dosfs_fsops, 1274a5d661aSToomas Soome NULL 1284a5d661aSToomas Soome }; 1294a5d661aSToomas Soome 1304a5d661aSToomas Soome int 1314a5d661aSToomas Soome main(void) 1324a5d661aSToomas Soome { 133b406476aSToomas Soome int auto_boot, i, fd; 1344a5d661aSToomas Soome struct disk_devdesc devdesc; 1354a5d661aSToomas Soome 1364a5d661aSToomas Soome bios_getmem(); 1374a5d661aSToomas Soome 1384a5d661aSToomas Soome if (high_heap_size > 0) { 1394a5d661aSToomas Soome heap_top = PTOV(high_heap_base + high_heap_size); 1404a5d661aSToomas Soome heap_bottom = PTOV(high_heap_base); 1414a5d661aSToomas Soome } else { 1424a5d661aSToomas Soome heap_bottom = (char *) 1434a5d661aSToomas Soome (roundup2(__base + (int32_t)&_end, 0x10000) - __base); 1444a5d661aSToomas Soome heap_top = (char *) PTOV(bios_basemem); 1454a5d661aSToomas Soome } 1464a5d661aSToomas Soome setheap(heap_bottom, heap_top); 1474a5d661aSToomas Soome 1484a5d661aSToomas Soome /* 1494a5d661aSToomas Soome * Initialise the block cache. Set the upper limit. 1504a5d661aSToomas Soome */ 1514a5d661aSToomas Soome bcache_init(32768, 512); 1524a5d661aSToomas Soome 1534a5d661aSToomas Soome archsw.arch_autoload = NULL; 1544a5d661aSToomas Soome archsw.arch_getdev = i386_getdev; 1554a5d661aSToomas Soome archsw.arch_copyin = NULL; 1564a5d661aSToomas Soome archsw.arch_copyout = NULL; 1574a5d661aSToomas Soome archsw.arch_readin = NULL; 1584a5d661aSToomas Soome archsw.arch_isainb = NULL; 1594a5d661aSToomas Soome archsw.arch_isaoutb = NULL; 1604a5d661aSToomas Soome archsw.arch_zfs_probe = i386_zfs_probe; 1614a5d661aSToomas Soome 1624a5d661aSToomas Soome bootinfo.bi_version = BOOTINFO_VERSION; 1634a5d661aSToomas Soome bootinfo.bi_size = sizeof(bootinfo); 1644a5d661aSToomas Soome bootinfo.bi_basemem = bios_basemem / 1024; 1654a5d661aSToomas Soome bootinfo.bi_extmem = bios_extmem / 1024; 1664a5d661aSToomas Soome bootinfo.bi_memsizes_valid++; 1674a5d661aSToomas Soome bootinfo.bi_bios_dev = *(uint8_t *)PTOV(ARGS); 1684a5d661aSToomas Soome 169b406476aSToomas Soome /* Set up fall back device name. */ 170b406476aSToomas Soome snprintf(boot_devname, sizeof (boot_devname), "disk%d:", 171b406476aSToomas Soome bd_bios2unit(bootinfo.bi_bios_dev)); 172b406476aSToomas Soome 173b406476aSToomas Soome for (i = 0; devsw[i] != NULL; i++) 174b406476aSToomas Soome if (devsw[i]->dv_init != NULL) 175b406476aSToomas Soome (devsw[i]->dv_init)(); 1764a5d661aSToomas Soome 1774a5d661aSToomas Soome disk_parsedev(&devdesc, boot_devname+4, NULL); 1784a5d661aSToomas Soome 1794a5d661aSToomas Soome bootdev = MAKEBOOTDEV(dev_maj[devdesc.d_type], devdesc.d_slice + 1, 1804a5d661aSToomas Soome devdesc.d_unit, devdesc.d_partition >= 0? devdesc.d_partition:0xff); 1814a5d661aSToomas Soome 1824a5d661aSToomas Soome /* 1834a5d661aSToomas Soome * zfs_fmtdev() can be called only after dv_init 1844a5d661aSToomas Soome */ 1854a5d661aSToomas Soome if (bdev != NULL && bdev->d_type == DEVT_ZFS) { 1864a5d661aSToomas Soome /* set up proper device name string for ZFS */ 187b406476aSToomas Soome strncpy(boot_devname, zfs_fmtdev(bdev), sizeof (boot_devname)); 1884a5d661aSToomas Soome } 1894a5d661aSToomas Soome 1904a5d661aSToomas Soome /* now make sure we have bdev on all cases */ 1914a5d661aSToomas Soome if (bdev != NULL) 1924a5d661aSToomas Soome free(bdev); 1934a5d661aSToomas Soome i386_getdev((void **)&bdev, boot_devname, NULL); 1944a5d661aSToomas Soome 1954a5d661aSToomas Soome env_setenv("currdev", EV_VOLATILE, boot_devname, i386_setcurrdev, 1964a5d661aSToomas Soome env_nounset); 1974a5d661aSToomas Soome 1984a5d661aSToomas Soome /* Process configuration file */ 1994a5d661aSToomas Soome setenv("LINES", "24", 1); 2004a5d661aSToomas Soome auto_boot = 1; 2014a5d661aSToomas Soome 2024a5d661aSToomas Soome fd = open(PATH_CONFIG, O_RDONLY); 2034a5d661aSToomas Soome if (fd == -1) 2044a5d661aSToomas Soome fd = open(PATH_DOTCONFIG, O_RDONLY); 2054a5d661aSToomas Soome 2064a5d661aSToomas Soome if (fd != -1) { 2074a5d661aSToomas Soome read(fd, cmd, sizeof(cmd)); 2084a5d661aSToomas Soome close(fd); 2094a5d661aSToomas Soome } 2104a5d661aSToomas Soome 2114a5d661aSToomas Soome if (*cmd) { 2124a5d661aSToomas Soome /* 2134a5d661aSToomas Soome * Note that parse_cmd() is destructive to cmd[] and we also want 2144a5d661aSToomas Soome * to honor RBX_QUIET option that could be present in cmd[]. 2154a5d661aSToomas Soome */ 2164a5d661aSToomas Soome memcpy(cmddup, cmd, sizeof(cmd)); 2174a5d661aSToomas Soome if (parse_cmd()) 2184a5d661aSToomas Soome auto_boot = 0; 2194a5d661aSToomas Soome if (!OPT_CHECK(RBX_QUIET)) 2204a5d661aSToomas Soome printf("%s: %s\n", PATH_CONFIG, cmddup); 2214a5d661aSToomas Soome /* Do not process this command twice */ 2224a5d661aSToomas Soome *cmd = 0; 2234a5d661aSToomas Soome } 2244a5d661aSToomas Soome 2254a5d661aSToomas Soome /* 2264a5d661aSToomas Soome * Try to exec stage 3 boot loader. If interrupted by a keypress, 2274a5d661aSToomas Soome * or in case of failure, switch off auto boot. 2284a5d661aSToomas Soome */ 2294a5d661aSToomas Soome 2304a5d661aSToomas Soome if (auto_boot && !*kname) { 2314a5d661aSToomas Soome memcpy(kname, PATH_LOADER_ZFS, sizeof(PATH_LOADER_ZFS)); 2324a5d661aSToomas Soome if (!keyhit(3)) { 2334a5d661aSToomas Soome load(); 2344a5d661aSToomas Soome auto_boot = 0; 2354a5d661aSToomas Soome } 2364a5d661aSToomas Soome } 2374a5d661aSToomas Soome 2384a5d661aSToomas Soome /* Present the user with the boot2 prompt. */ 2394a5d661aSToomas Soome 2404a5d661aSToomas Soome for (;;) { 2414a5d661aSToomas Soome if (!auto_boot || !OPT_CHECK(RBX_QUIET)) { 2424a5d661aSToomas Soome printf("\nillumos/x86 boot\n"); 2434a5d661aSToomas Soome printf("Default: %s%s\nboot: ", boot_devname, kname); 2444a5d661aSToomas Soome } 2454a5d661aSToomas Soome if (ioctrl & IO_SERIAL) 2464a5d661aSToomas Soome sio_flush(); 2474a5d661aSToomas Soome if (!auto_boot || keyhit(5)) 2484a5d661aSToomas Soome getstr(cmd, sizeof(cmd)); 2494a5d661aSToomas Soome else if (!auto_boot || !OPT_CHECK(RBX_QUIET)) 2504a5d661aSToomas Soome putchar('\n'); 2514a5d661aSToomas Soome auto_boot = 0; 2524a5d661aSToomas Soome if (parse_cmd()) 2534a5d661aSToomas Soome putchar('\a'); 2544a5d661aSToomas Soome else 2554a5d661aSToomas Soome load(); 2564a5d661aSToomas Soome } 2574a5d661aSToomas Soome } 2584a5d661aSToomas Soome 2594a5d661aSToomas Soome /* XXX - Needed for btxld to link the boot2 binary; do not remove. */ 2604a5d661aSToomas Soome void 2614a5d661aSToomas Soome exit(int x) 2624a5d661aSToomas Soome { 2634a5d661aSToomas Soome } 2644a5d661aSToomas Soome 2654a5d661aSToomas Soome static void 2664a5d661aSToomas Soome load(void) 2674a5d661aSToomas Soome { 2684a5d661aSToomas Soome union { 2694a5d661aSToomas Soome struct exec ex; 2704a5d661aSToomas Soome Elf32_Ehdr eh; 2714a5d661aSToomas Soome } hdr; 2724a5d661aSToomas Soome static Elf32_Phdr ep[2]; 2734a5d661aSToomas Soome static Elf32_Shdr es[2]; 2744a5d661aSToomas Soome caddr_t p; 2754a5d661aSToomas Soome uint32_t addr, x; 2764a5d661aSToomas Soome int fd, fmt, i, j; 2774a5d661aSToomas Soome 2784a5d661aSToomas Soome if ((fd = open(kname, O_RDONLY)) == -1) { 2794a5d661aSToomas Soome printf("\nCan't find %s\n", kname); 2804a5d661aSToomas Soome return; 2814a5d661aSToomas Soome } 2824a5d661aSToomas Soome if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { 2834a5d661aSToomas Soome close(fd); 2844a5d661aSToomas Soome return; 2854a5d661aSToomas Soome } 2864a5d661aSToomas Soome if (N_GETMAGIC(hdr.ex) == ZMAGIC) 2874a5d661aSToomas Soome fmt = 0; 2884a5d661aSToomas Soome else if (IS_ELF(hdr.eh)) 2894a5d661aSToomas Soome fmt = 1; 2904a5d661aSToomas Soome else { 2914a5d661aSToomas Soome printf("Invalid %s\n", "format"); 2924a5d661aSToomas Soome close(fd); 2934a5d661aSToomas Soome return; 2944a5d661aSToomas Soome } 2954a5d661aSToomas Soome if (fmt == 0) { 2964a5d661aSToomas Soome addr = hdr.ex.a_entry & 0xffffff; 2974a5d661aSToomas Soome p = PTOV(addr); 2984a5d661aSToomas Soome lseek(fd, PAGE_SIZE, SEEK_SET); 2994a5d661aSToomas Soome if (read(fd, p, hdr.ex.a_text) != hdr.ex.a_text) { 3004a5d661aSToomas Soome close(fd); 3014a5d661aSToomas Soome return; 3024a5d661aSToomas Soome } 3034a5d661aSToomas Soome p += roundup2(hdr.ex.a_text, PAGE_SIZE); 3044a5d661aSToomas Soome if (read(fd, p, hdr.ex.a_data) != hdr.ex.a_data) { 3054a5d661aSToomas Soome close(fd); 3064a5d661aSToomas Soome return; 3074a5d661aSToomas Soome } 3084a5d661aSToomas Soome p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); 3094a5d661aSToomas Soome bootinfo.bi_symtab = VTOP(p); 3104a5d661aSToomas Soome memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); 3114a5d661aSToomas Soome p += sizeof(hdr.ex.a_syms); 3124a5d661aSToomas Soome if (hdr.ex.a_syms) { 3134a5d661aSToomas Soome if (read(fd, p, hdr.ex.a_syms) != hdr.ex.a_syms) { 3144a5d661aSToomas Soome close(fd); 3154a5d661aSToomas Soome return; 3164a5d661aSToomas Soome } 3174a5d661aSToomas Soome p += hdr.ex.a_syms; 3184a5d661aSToomas Soome if (read(fd, p, sizeof(int)) != sizeof(int)) { 3194a5d661aSToomas Soome close(fd); 3204a5d661aSToomas Soome return; 3214a5d661aSToomas Soome } 3224a5d661aSToomas Soome x = *(uint32_t *)p; 3234a5d661aSToomas Soome p += sizeof(int); 3244a5d661aSToomas Soome x -= sizeof(int); 3254a5d661aSToomas Soome if (read(fd, p, x) != x) { 3264a5d661aSToomas Soome close(fd); 3274a5d661aSToomas Soome return; 3284a5d661aSToomas Soome } 3294a5d661aSToomas Soome p += x; 3304a5d661aSToomas Soome } 3314a5d661aSToomas Soome } else { 3324a5d661aSToomas Soome lseek(fd, hdr.eh.e_phoff, SEEK_SET); 3334a5d661aSToomas Soome for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { 3344a5d661aSToomas Soome if (read(fd, ep + j, sizeof(ep[0])) != sizeof(ep[0])) { 3354a5d661aSToomas Soome close(fd); 3364a5d661aSToomas Soome return; 3374a5d661aSToomas Soome } 3384a5d661aSToomas Soome if (ep[j].p_type == PT_LOAD) 3394a5d661aSToomas Soome j++; 3404a5d661aSToomas Soome } 3414a5d661aSToomas Soome for (i = 0; i < 2; i++) { 3424a5d661aSToomas Soome p = PTOV(ep[i].p_paddr & 0xffffff); 3434a5d661aSToomas Soome lseek(fd, ep[i].p_offset, SEEK_SET); 3444a5d661aSToomas Soome if (read(fd, p, ep[i].p_filesz) != ep[i].p_filesz) { 3454a5d661aSToomas Soome close(fd); 3464a5d661aSToomas Soome return; 3474a5d661aSToomas Soome } 3484a5d661aSToomas Soome } 3494a5d661aSToomas Soome p += roundup2(ep[1].p_memsz, PAGE_SIZE); 3504a5d661aSToomas Soome bootinfo.bi_symtab = VTOP(p); 3514a5d661aSToomas Soome if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { 3524a5d661aSToomas Soome lseek(fd, hdr.eh.e_shoff + sizeof(es[0]) * (hdr.eh.e_shstrndx + 1), 3534a5d661aSToomas Soome SEEK_SET); 3544a5d661aSToomas Soome if (read(fd, &es, sizeof(es)) != sizeof(es)) { 3554a5d661aSToomas Soome close(fd); 3564a5d661aSToomas Soome return; 3574a5d661aSToomas Soome } 3584a5d661aSToomas Soome for (i = 0; i < 2; i++) { 3594a5d661aSToomas Soome memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 3604a5d661aSToomas Soome p += sizeof(es[i].sh_size); 3614a5d661aSToomas Soome lseek(fd, es[i].sh_offset, SEEK_SET); 3624a5d661aSToomas Soome if (read(fd, p, es[i].sh_size) != es[i].sh_size) { 3634a5d661aSToomas Soome close(fd); 3644a5d661aSToomas Soome return; 3654a5d661aSToomas Soome } 3664a5d661aSToomas Soome p += es[i].sh_size; 3674a5d661aSToomas Soome } 3684a5d661aSToomas Soome } 3694a5d661aSToomas Soome addr = hdr.eh.e_entry & 0xffffff; 3704a5d661aSToomas Soome } 3714a5d661aSToomas Soome close(fd); 3724a5d661aSToomas Soome 3734a5d661aSToomas Soome bootinfo.bi_esymtab = VTOP(p); 3744a5d661aSToomas Soome bootinfo.bi_kernelname = VTOP(kname); 3754a5d661aSToomas Soome 3764a5d661aSToomas Soome if (bdev->d_type == DEVT_ZFS) { 3774a5d661aSToomas Soome zfsargs.size = sizeof(zfsargs); 3784a5d661aSToomas Soome zfsargs.pool = bdev->d_kind.zfs.pool_guid; 3794a5d661aSToomas Soome zfsargs.root = bdev->d_kind.zfs.root_guid; 3804a5d661aSToomas Soome __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 3814a5d661aSToomas Soome bootdev, 3824a5d661aSToomas Soome KARGS_FLAGS_ZFS | KARGS_FLAGS_EXTARG, 3834a5d661aSToomas Soome (uint32_t) bdev->d_kind.zfs.pool_guid, 3844a5d661aSToomas Soome (uint32_t) (bdev->d_kind.zfs.pool_guid >> 32), 3854a5d661aSToomas Soome VTOP(&bootinfo), 3864a5d661aSToomas Soome zfsargs); 3874a5d661aSToomas Soome } else 3884a5d661aSToomas Soome __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), 3894a5d661aSToomas Soome bootdev, 0, 0, 0, VTOP(&bootinfo)); 3904a5d661aSToomas Soome } 3914a5d661aSToomas Soome 3924a5d661aSToomas Soome static int 3934a5d661aSToomas Soome mount_root(char *arg) 3944a5d661aSToomas Soome { 3954a5d661aSToomas Soome char *root; 3964a5d661aSToomas Soome struct i386_devdesc *ddesc; 3974a5d661aSToomas Soome uint8_t part; 3984a5d661aSToomas Soome 3994a5d661aSToomas Soome root = malloc(strlen(arg) + 2); 4004a5d661aSToomas Soome if (root == NULL) 4014a5d661aSToomas Soome return (1); 4024a5d661aSToomas Soome sprintf(root, "%s:", arg); 4034a5d661aSToomas Soome if (i386_getdev((void **)&ddesc, root, NULL)) { 4044a5d661aSToomas Soome free(root); 4054a5d661aSToomas Soome return (1); 4064a5d661aSToomas Soome } 4074a5d661aSToomas Soome 4084a5d661aSToomas Soome /* we should have new device descriptor, free old and replace it. */ 4094a5d661aSToomas Soome if (bdev != NULL) 4104a5d661aSToomas Soome free(bdev); 4114a5d661aSToomas Soome bdev = ddesc; 4124a5d661aSToomas Soome if (bdev->d_type == DEVT_DISK) { 4134a5d661aSToomas Soome if (bdev->d_kind.biosdisk.partition == -1) 4144a5d661aSToomas Soome part = 0xff; 4154a5d661aSToomas Soome else 4164a5d661aSToomas Soome part = bdev->d_kind.biosdisk.partition; 4174a5d661aSToomas Soome bootdev = MAKEBOOTDEV(dev_maj[bdev->d_type], 4184a5d661aSToomas Soome bdev->d_kind.biosdisk.slice + 1, 4194a5d661aSToomas Soome bdev->d_unit, part); 4204a5d661aSToomas Soome bootinfo.bi_bios_dev = bd_unit2bios(bdev->d_unit); 4214a5d661aSToomas Soome } 4224a5d661aSToomas Soome setenv("currdev", root, 1); 4234a5d661aSToomas Soome free(root); 4244a5d661aSToomas Soome return (0); 4254a5d661aSToomas Soome } 4264a5d661aSToomas Soome 4274a5d661aSToomas Soome static void 4284a5d661aSToomas Soome fs_list(char *arg) 4294a5d661aSToomas Soome { 4304a5d661aSToomas Soome int fd; 4314a5d661aSToomas Soome struct dirent *d; 4324a5d661aSToomas Soome char line[80]; 4334a5d661aSToomas Soome 4344a5d661aSToomas Soome fd = open(arg, O_RDONLY); 4354a5d661aSToomas Soome if (fd < 0) 4364a5d661aSToomas Soome return; 4374a5d661aSToomas Soome pager_open(); 4384a5d661aSToomas Soome while ((d = readdirfd(fd)) != NULL) { 4394a5d661aSToomas Soome sprintf(line, "%s\n", d->d_name); 4404a5d661aSToomas Soome if (pager_output(line)) 4414a5d661aSToomas Soome break; 4424a5d661aSToomas Soome } 4434a5d661aSToomas Soome pager_close(); 4444a5d661aSToomas Soome close(fd); 4454a5d661aSToomas Soome } 4464a5d661aSToomas Soome 4474a5d661aSToomas Soome static int 4484a5d661aSToomas Soome parse_cmd(void) 4494a5d661aSToomas Soome { 4504a5d661aSToomas Soome char *arg = cmd; 4514a5d661aSToomas Soome char *ep, *p, *q; 4524a5d661aSToomas Soome const char *cp; 4534a5d661aSToomas Soome char line[80]; 4544a5d661aSToomas Soome int c, i, j; 4554a5d661aSToomas Soome 4564a5d661aSToomas Soome while ((c = *arg++)) { 4574a5d661aSToomas Soome if (c == ' ' || c == '\t' || c == '\n') 4584a5d661aSToomas Soome continue; 4594a5d661aSToomas Soome for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); 4604a5d661aSToomas Soome ep = p; 4614a5d661aSToomas Soome if (*p) 4624a5d661aSToomas Soome *p++ = 0; 4634a5d661aSToomas Soome if (c == '-') { 4644a5d661aSToomas Soome while ((c = *arg++)) { 4654a5d661aSToomas Soome if (c == 'P') { 4664a5d661aSToomas Soome if (*(uint8_t *)PTOV(0x496) & 0x10) { 4674a5d661aSToomas Soome cp = "yes"; 4684a5d661aSToomas Soome } else { 4694a5d661aSToomas Soome opts |= OPT_SET(RBX_DUAL) | OPT_SET(RBX_SERIAL); 4704a5d661aSToomas Soome cp = "no"; 4714a5d661aSToomas Soome } 4724a5d661aSToomas Soome printf("Keyboard: %s\n", cp); 4734a5d661aSToomas Soome continue; 4744a5d661aSToomas Soome } else if (c == 'S') { 4754a5d661aSToomas Soome j = 0; 4764a5d661aSToomas Soome while ((unsigned int)(i = *arg++ - '0') <= 9) 4774a5d661aSToomas Soome j = j * 10 + i; 4784a5d661aSToomas Soome if (j > 0 && i == -'0') { 4794a5d661aSToomas Soome comspeed = j; 4804a5d661aSToomas Soome break; 4814a5d661aSToomas Soome } 4824a5d661aSToomas Soome /* Fall through to error below ('S' not in optstr[]). */ 4834a5d661aSToomas Soome } 4844a5d661aSToomas Soome for (i = 0; c != optstr[i]; i++) 4854a5d661aSToomas Soome if (i == NOPT - 1) 4864a5d661aSToomas Soome return -1; 4874a5d661aSToomas Soome opts ^= OPT_SET(flags[i]); 4884a5d661aSToomas Soome } 4894a5d661aSToomas Soome ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) : 4904a5d661aSToomas Soome OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD; 4914a5d661aSToomas Soome if (ioctrl & IO_SERIAL) { 4924a5d661aSToomas Soome if (sio_init(115200 / comspeed) != 0) 4934a5d661aSToomas Soome ioctrl &= ~IO_SERIAL; 4944a5d661aSToomas Soome } 4954a5d661aSToomas Soome } if (c == '?') { 4964a5d661aSToomas Soome printf("\n"); 4974a5d661aSToomas Soome fs_list(arg); 4984a5d661aSToomas Soome zfs_list(arg); 4994a5d661aSToomas Soome return -1; 5004a5d661aSToomas Soome } else { 5014a5d661aSToomas Soome arg--; 5024a5d661aSToomas Soome 5034a5d661aSToomas Soome /* 5044a5d661aSToomas Soome * Report pool status if the comment is 'status'. Lets 5054a5d661aSToomas Soome * hope no-one wants to load /status as a kernel. 5064a5d661aSToomas Soome */ 5074a5d661aSToomas Soome if (!strcmp(arg, "status")) { 5084a5d661aSToomas Soome pager_open(); 5094a5d661aSToomas Soome for (i = 0; devsw[i] != NULL; i++) { 5104a5d661aSToomas Soome if (devsw[i]->dv_print != NULL) { 5114a5d661aSToomas Soome if (devsw[i]->dv_print(1)) 5124a5d661aSToomas Soome break; 5134a5d661aSToomas Soome } else { 5144a5d661aSToomas Soome sprintf(line, "%s: (unknown)\n", devsw[i]->dv_name); 5154a5d661aSToomas Soome if (pager_output(line)) 5164a5d661aSToomas Soome break; 5174a5d661aSToomas Soome } 5184a5d661aSToomas Soome } 5194a5d661aSToomas Soome pager_close(); 5204a5d661aSToomas Soome return -1; 5214a5d661aSToomas Soome } 5224a5d661aSToomas Soome 5234a5d661aSToomas Soome /* 5244a5d661aSToomas Soome * If there is a colon, switch pools. 5254a5d661aSToomas Soome */ 5264a5d661aSToomas Soome if (strncmp(arg, "zfs:", 4) == 0) 5274a5d661aSToomas Soome q = strchr(arg + 4, ':'); 5284a5d661aSToomas Soome else 5294a5d661aSToomas Soome q = strchr(arg, ':'); 5304a5d661aSToomas Soome if (q) { 5314a5d661aSToomas Soome *q++ = '\0'; 5324a5d661aSToomas Soome if (mount_root(arg) != 0) 5334a5d661aSToomas Soome return -1; 5344a5d661aSToomas Soome arg = q; 5354a5d661aSToomas Soome } 5364a5d661aSToomas Soome if ((i = ep - arg)) { 5374a5d661aSToomas Soome if ((size_t)i >= sizeof(kname)) 5384a5d661aSToomas Soome return -1; 5394a5d661aSToomas Soome memcpy(kname, arg, i + 1); 5404a5d661aSToomas Soome } 5414a5d661aSToomas Soome } 5424a5d661aSToomas Soome arg = p; 5434a5d661aSToomas Soome } 5444a5d661aSToomas Soome return 0; 5454a5d661aSToomas Soome } 5464a5d661aSToomas Soome 547b406476aSToomas Soome /* 548b406476aSToomas Soome * probe arguments for partition iterator (see below) 549b406476aSToomas Soome */ 550b406476aSToomas Soome struct probe_args { 551b406476aSToomas Soome int fd; 552b406476aSToomas Soome char *devname; 553b406476aSToomas Soome u_int secsz; 554b406476aSToomas Soome uint64_t offset; 555b406476aSToomas Soome }; 556b406476aSToomas Soome 557b406476aSToomas Soome /* 558b406476aSToomas Soome * simple wrapper around read() to avoid using device specific 559b406476aSToomas Soome * strategy() directly. 560b406476aSToomas Soome */ 561b406476aSToomas Soome static int 562b406476aSToomas Soome parttblread(void *arg, void *buf, size_t blocks, uint64_t offset) 563b406476aSToomas Soome { 564b406476aSToomas Soome struct probe_args *ppa = arg; 565b406476aSToomas Soome size_t size = ppa->secsz * blocks; 566b406476aSToomas Soome 567b406476aSToomas Soome lseek(ppa->fd, offset * ppa->secsz, SEEK_SET); 568b406476aSToomas Soome if (read(ppa->fd, buf, size) == size) 569b406476aSToomas Soome return (0); 570b406476aSToomas Soome return (EIO); 571b406476aSToomas Soome } 572b406476aSToomas Soome 573b406476aSToomas Soome /* 574b406476aSToomas Soome * scan partition entries to find boot partition starting at start_sector. 575b406476aSToomas Soome * in case of MBR partition type PART_SOLARIS2, read VTOC and recurse. 576b406476aSToomas Soome */ 577b406476aSToomas Soome static int 578b406476aSToomas Soome probe_partition(void *arg, const char *partname, 579b406476aSToomas Soome const struct ptable_entry *part) 580b406476aSToomas Soome { 581b406476aSToomas Soome struct probe_args pa, *ppa = arg; 582b406476aSToomas Soome struct ptable *table; 583b406476aSToomas Soome uint64_t *pool_guid_ptr = NULL; 584b406476aSToomas Soome uint64_t pool_guid = 0; 585b406476aSToomas Soome char devname[32]; 586b406476aSToomas Soome int len, ret = 0; 587b406476aSToomas Soome 588b406476aSToomas Soome len = strlen(ppa->devname); 589b406476aSToomas Soome if (len > sizeof (devname)) 590b406476aSToomas Soome len = sizeof (devname); 591b406476aSToomas Soome 592b406476aSToomas Soome strncpy(devname, ppa->devname, len - 1); 593b406476aSToomas Soome devname[len - 1] = '\0'; 594b406476aSToomas Soome snprintf(devname, sizeof (devname), "%s%s:", devname, partname); 595b406476aSToomas Soome 596b406476aSToomas Soome /* filter out partitions *not* used by zfs */ 597b406476aSToomas Soome switch (part->type) { 598b406476aSToomas Soome case PART_RESERVED: /* efi reserverd */ 599b406476aSToomas Soome case PART_VTOC_BOOT: /* vtoc boot area */ 600b406476aSToomas Soome case PART_VTOC_SWAP: 601b406476aSToomas Soome return (ret); 602b406476aSToomas Soome default: 603b406476aSToomas Soome break; 604b406476aSToomas Soome } 605b406476aSToomas Soome 606b406476aSToomas Soome if (part->type == PART_SOLARIS2) { 607b406476aSToomas Soome pa.offset = part->start; 608b406476aSToomas Soome pa.fd = open(devname, O_RDONLY); 609b406476aSToomas Soome if (pa.fd == -1) 610b406476aSToomas Soome return (ret); 611b406476aSToomas Soome pa.devname = devname; 612b406476aSToomas Soome pa.secsz = ppa->secsz; 613b406476aSToomas Soome table = ptable_open(&pa, part->end - part->start + 1, 614b406476aSToomas Soome ppa->secsz, parttblread); 615b406476aSToomas Soome if (table != NULL) { 616b406476aSToomas Soome ret = ptable_iterate(table, &pa, probe_partition); 617b406476aSToomas Soome ptable_close(table); 618b406476aSToomas Soome } 619b406476aSToomas Soome close(pa.fd); 620b406476aSToomas Soome return (ret); 621b406476aSToomas Soome } 622b406476aSToomas Soome 623b406476aSToomas Soome if (ppa->offset + part->start == start_sector) { 624b406476aSToomas Soome /* Ask zfs_probe_dev to provide guid. */ 625b406476aSToomas Soome pool_guid_ptr = &pool_guid; 626b406476aSToomas Soome /* Set up boot device name for non-zfs case. */ 627b406476aSToomas Soome strncpy(boot_devname, devname, sizeof (boot_devname)); 628b406476aSToomas Soome } 629b406476aSToomas Soome 630b406476aSToomas Soome ret = zfs_probe_dev(devname, pool_guid_ptr); 631b406476aSToomas Soome if (pool_guid != 0 && bdev == NULL) { 632b406476aSToomas Soome bdev = malloc(sizeof (struct i386_devdesc)); 633b406476aSToomas Soome bzero(bdev, sizeof (struct i386_devdesc)); 634b406476aSToomas Soome bdev->d_type = DEVT_ZFS; 635b406476aSToomas Soome bdev->d_dev = &zfs_dev; 636b406476aSToomas Soome bdev->d_kind.zfs.pool_guid = pool_guid; 637b406476aSToomas Soome 638b406476aSToomas Soome /* 639b406476aSToomas Soome * We can not set up zfs boot device name yet, as the 640b406476aSToomas Soome * zfs dv_init() is not completed. We will set boot_devname 641b406476aSToomas Soome * in main, after devsw setup. 642b406476aSToomas Soome */ 643b406476aSToomas Soome } 644b406476aSToomas Soome 645b406476aSToomas Soome return (0); 646b406476aSToomas Soome } 647b406476aSToomas Soome 648b406476aSToomas Soome /* 649b406476aSToomas Soome * open partition table on disk and scan partition entries to find 650b406476aSToomas Soome * boot partition starting at start_sector (recorded by installboot). 651b406476aSToomas Soome */ 652b406476aSToomas Soome static int 653b406476aSToomas Soome probe_disk(char *devname) 654b406476aSToomas Soome { 655b406476aSToomas Soome struct ptable *table; 656b406476aSToomas Soome struct probe_args pa; 657b406476aSToomas Soome uint64_t mediasz; 658b406476aSToomas Soome int ret; 659b406476aSToomas Soome 660b406476aSToomas Soome pa.offset = 0; 661b406476aSToomas Soome pa.devname = devname; 662b406476aSToomas Soome pa.fd = open(devname, O_RDONLY); 663b406476aSToomas Soome if (pa.fd == -1) { 664b406476aSToomas Soome return (ENXIO); 665b406476aSToomas Soome } 666b406476aSToomas Soome 667b406476aSToomas Soome ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); 668b406476aSToomas Soome if (ret == 0) 669b406476aSToomas Soome ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); 670b406476aSToomas Soome if (ret == 0) { 671b406476aSToomas Soome table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, 672b406476aSToomas Soome parttblread); 673b406476aSToomas Soome if (table != NULL) { 674b406476aSToomas Soome ret = ptable_iterate(table, &pa, probe_partition); 675b406476aSToomas Soome ptable_close(table); 676b406476aSToomas Soome } 677b406476aSToomas Soome } 678b406476aSToomas Soome close(pa.fd); 679b406476aSToomas Soome return (ret); 680b406476aSToomas Soome } 681b406476aSToomas Soome 682b406476aSToomas Soome /* 683b406476aSToomas Soome * Probe all disks to discover ZFS pools. The idea is to walk all possible 684b406476aSToomas Soome * disk devices, however, we also need to identify possible boot pool. 685b406476aSToomas Soome * For boot pool detection we have boot disk passed us from BIOS, recorded 686b406476aSToomas Soome * in bootinfo.bi_bios_dev, and start_sector LBA recorded by installboot. 687b406476aSToomas Soome * 688b406476aSToomas Soome * To detect boot pool, we can not use generic zfs_probe_dev() on boot disk, 689b406476aSToomas Soome * but we need to walk partitions, as we have no way to pass start_sector 690b406476aSToomas Soome * to zfs_probe_dev(). Note we do need to detect the partition correcponding 691b406476aSToomas Soome * to non-zfs case, so here we can set boot_devname for both cases. 692b406476aSToomas Soome */ 6934a5d661aSToomas Soome static void 6944a5d661aSToomas Soome i386_zfs_probe(void) 6954a5d661aSToomas Soome { 6964a5d661aSToomas Soome char devname[32]; 697b406476aSToomas Soome int boot_unit, unit; 698b406476aSToomas Soome 699b406476aSToomas Soome /* Translate bios dev to our unit number. */ 700b406476aSToomas Soome boot_unit = bd_bios2unit(bootinfo.bi_bios_dev); 7014a5d661aSToomas Soome 7024a5d661aSToomas Soome /* 7034a5d661aSToomas Soome * Open all the disks we can find and see if we can reconstruct 704b406476aSToomas Soome * ZFS pools from them. 7054a5d661aSToomas Soome */ 7064a5d661aSToomas Soome for (unit = 0; unit < MAXBDDEV; unit++) { 7074a5d661aSToomas Soome if (bd_unit2bios(unit) == -1) 7084a5d661aSToomas Soome break; 709b406476aSToomas Soome 7104a5d661aSToomas Soome sprintf(devname, "disk%d:", unit); 711b406476aSToomas Soome /* If this is not boot disk, use generic probe. */ 712b406476aSToomas Soome if (unit != boot_unit) 7134a5d661aSToomas Soome zfs_probe_dev(devname, NULL); 714b406476aSToomas Soome else 715b406476aSToomas Soome probe_disk(devname); 7164a5d661aSToomas Soome } 7174a5d661aSToomas Soome } 718*9ab3b382SToomas Soome 719*9ab3b382SToomas Soome uint64_t 720*9ab3b382SToomas Soome ldi_get_size(void *priv) 721*9ab3b382SToomas Soome { 722*9ab3b382SToomas Soome int fd = (uintptr_t) priv; 723*9ab3b382SToomas Soome uint64_t size; 724*9ab3b382SToomas Soome 725*9ab3b382SToomas Soome ioctl(fd, DIOCGMEDIASIZE, &size); 726*9ab3b382SToomas Soome return (size); 727*9ab3b382SToomas Soome } 728