diff options
author | John Levon <john.levon@joyent.com> | 2019-04-01 10:05:45 +0000 |
---|---|---|
committer | John Levon <john.levon@joyent.com> | 2019-04-08 08:43:36 +0000 |
commit | fa83485c3551a3fd3848f1535acb98b30c6595a2 (patch) | |
tree | d1ab84da58bdbfaf128c634c000feebb17422123 /usr/src | |
parent | 9a8207fa35a4a0b13b30000d6ead058c47c0ccc3 (diff) | |
download | illumos-joyent-fa83485c3551a3fd3848f1535acb98b30c6595a2.tar.gz |
OS-7260 SmartOS should support booting with loader
OS-7271 proto.boot should include loader instead of grub
OS-7332 RICHMOND-16 mitigation ensnares stock loaders
OS-7584 MDB module for disk labelling would be useful
OS-7585 Need workaround to EFI boot on AMI BIOS
OS-7595 Triton-specific extensions to Loader
Portions contributed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
25 files changed, 1088 insertions, 120 deletions
diff --git a/usr/src/boot/sys/boot/common/console.c b/usr/src/boot/sys/boot/common/console.c index b84dfe0018..923ab5e5ab 100644 --- a/usr/src/boot/sys/boot/common/console.c +++ b/usr/src/boot/sys/boot/common/console.c @@ -23,7 +23,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - +/* + * Copyright (c) 2019, Joyent, Inc. + */ #include <sys/cdefs.h> #include <stand.h> @@ -281,15 +283,6 @@ cons_change(const char *string) active++; continue; } - - if (active != 0) { - /* - * If no consoles have initialised we wouldn't - * see this. - */ - printf("console %s failed to initialize\n", - consoles[cons]->c_name); - } } } diff --git a/usr/src/boot/sys/boot/forth/Makefile.inc b/usr/src/boot/sys/boot/forth/Makefile.inc index eb2576bd64..09ac830835 100644 --- a/usr/src/boot/sys/boot/forth/Makefile.inc +++ b/usr/src/boot/sys/boot/forth/Makefile.inc @@ -4,6 +4,7 @@ FORTH = beastie.4th FORTH += beadm.4th FORTH += brand.4th FORTH += brand-illumos.4th +FORTH += brand-smartos.4th FORTH += check-password.4th FORTH += color.4th FORTH += delay.4th @@ -17,6 +18,7 @@ FORTH += logo-fbsdbw.4th FORTH += logo-illumos.4th FORTH += logo-orb.4th FORTH += logo-orbbw.4th +FORTH += logo-smartos.4th FORTH += menu.4th FORTH += menu-commands.4th FORTH += menusets.4th diff --git a/usr/src/boot/sys/boot/forth/brand-smartos.4th b/usr/src/boot/sys/boot/forth/brand-smartos.4th new file mode 100644 index 0000000000..ec3c6a0782 --- /dev/null +++ b/usr/src/boot/sys/boot/forth/brand-smartos.4th @@ -0,0 +1,35 @@ +\ +\ This file and its contents are supplied under the terms of the +\ Common Development and Distribution License ("CDDL"), version 1.0. +\ You may only use this file in accordance with the terms of version +\ 1.0 of the CDDL. +\ +\ A full copy of the text of the CDDL should have accompanied this +\ source. A copy of the CDDL is also available via the Internet at +\ http://www.illumos.org/license/CDDL. +\ + +\ +\ Copyright 2019 Joyent, Inc. +\ + +2 brandX ! 1 brandY ! \ Initialize brand placement defaults + +: brand+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: brand ( x y -- ) \ "joyent" [wide] logo in B/W (7 rows x 42 columns) + + s" # " brand+ + s" # #### # # ###### # # ##### " brand+ + s" # # # # # # ## # # " brand+ + s" # # # # ##### # # # # " brand+ + s" # # # # # # # # # # " brand+ + s" # # # # # # # ## # " brand+ + s" ##### #### # ###### # # # TM" brand+ + + 2drop +; diff --git a/usr/src/boot/sys/boot/forth/loader.4th b/usr/src/boot/sys/boot/forth/loader.4th index 92c742c472..27188079f9 100644 --- a/usr/src/boot/sys/boot/forth/loader.4th +++ b/usr/src/boot/sys/boot/forth/loader.4th @@ -596,6 +596,24 @@ only forth definitions also support-functions then ; +create pathname 1024 chars allot + +: set-platform ( c-addr u -- ) + 2dup + pathname place + s" /platform/i86pc/kernel/amd64/unix" pathname append + pathname count s" bootfile" setenv + pathname count erase + 2dup + pathname place + s" /platform/i86pc/amd64/boot_archive" pathname append + pathname count s" boot_archive" set-module-path + pathname count erase + pathname place + s" /platform/i86pc/amd64/boot_archive.hash" pathname append + pathname count s" boot_archive.hash" set-module-path +; + \ Words to be used inside configuration files : retry false ; \ For use in load error commands diff --git a/usr/src/boot/sys/boot/forth/logo-smartos.4th b/usr/src/boot/sys/boot/forth/logo-smartos.4th new file mode 100644 index 0000000000..9641a4fd81 --- /dev/null +++ b/usr/src/boot/sys/boot/forth/logo-smartos.4th @@ -0,0 +1,41 @@ +\ +\ This file and its contents are supplied under the terms of the +\ Common Development and Distribution License ("CDDL"), version 1.0. +\ You may only use this file in accordance with the terms of version +\ 1.0 of the CDDL. +\ +\ A full copy of the text of the CDDL should have accompanied this +\ source. A copy of the CDDL is also available via the Internet at +\ http://www.illumos.org/license/CDDL. +\ + +\ +\ Copyright 2019 Joyent, Inc. +\ + +52 logoX ! 11 logoY ! \ Initialize logo placement defaults + +: logo+ ( x y c-addr/u -- x y' ) + 2swap 2dup at-xy 2swap \ position the cursor + [char] @ escc! \ replace @ with Esc + type \ print to the screen + 1+ \ increase y for next time we're called +; + +: logo ( x y -- ) \ color Illumos logo + + 0 0 0 0 0 s" /boot/illumos.png" fb-putimage if 2drop exit then + + s" @[31m--@[0;31m+--@[1;31m*@[0;33m--@[1;33m*" logo+ + s" @[31m|@[1m\@[0m @[31m|\ |@[33m\ @[1m|\" logo+ + s" @[31m| @[1m\@[0;31m|@[37m @[31m\| @[33m\@[1m| \" logo+ + s" @[31m+--@[1;31m*@[31m--+@[0;33m--@[1;33m*@[33m--@[33m*" logo+ + s" |@[31m\ |\ |\ @[33m|@[1m\ |" logo+ + s" | @[31m\| \| \@[33m| @[1m\|" logo+ + s" @[1m*@[0m--+@[31m--+@[33m--+@[1m--+" logo+ + s" @[1m \ |@[0;34m\ |\ |@[1m\ |" logo+ + s" @[1m \| @[0;34m\| \| @[1m\|" logo+ + s" @[1m *--+@[0;34m--@[1;34m*@[34m--@[34m*" logo+ + + 2drop +; diff --git a/usr/src/boot/sys/boot/forth/menu-commands.4th b/usr/src/boot/sys/boot/forth/menu-commands.4th index d9d3dba411..c72868188c 100644 --- a/usr/src/boot/sys/boot/forth/menu-commands.4th +++ b/usr/src/boot/sys/boot/forth/menu-commands.4th @@ -24,6 +24,7 @@ \ \ Copyright 2015 Toomas Soome <tsoome@me.com> \ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. +\ Copyright (c) 2019 Joyent, Inc. marker task-menu-commands.4th @@ -46,6 +47,43 @@ variable debug_state also menu-namespace also menu-command-helpers +\ PATH_MAX + 6 +create chaincmd 1030 chars allot + +\ +\ Rollback to previous platform image. +\ Used by Joyent Triton +\ +: rollback_boot ( N -- NOTREACHED ) + dup + s" prev-platform" getenv s" bootfile" setenv + s" prev-archive" getenv s" boot_archive" set-module-path + s" prev-hash" getenv s" boot_archive.hash" set-module-path + 0 boot ( state -- ) +; + +\ +\ Boot from ipxe kernel +\ Used by Joyent Triton when booted in BIOS/CSM mode +\ +: ipxe_boot ( N -- NOTREACHED ) + dup + s" ipxe-bootfile" getenv s" bootfile" setenv + s" ipxe-archive" getenv s" boot_archive" set-module-path + s" boot_archive.hash" disable-module + 0 boot ( state -- ) +; + +\ +\ Chainload the ipxe EFI binary +\ Used by Joyent Triton when booted in UEFI mode +\ +: ipxe_chainload ( N -- NOTREACHED ) + s" chain " chaincmd place + s" ipxe-efi" getenv chaincmd append + chaincmd count evaluate +; + \ \ Boot \ @@ -319,6 +357,53 @@ also menu-namespace also menu-command-helpers ; \ +\ Disaster Recovery boot +\ + +: rescue_enabled? ( -- flag ) + s" noimport" getenv -1 <> dup if + swap drop ( c-addr flag -- flag ) + then +; + +: rescue_enable ( -- ) + s" set noimport=true" evaluate + s" smartos" getenv? if + s" set standalone=true" evaluate + s" set smartos=false" evaluate + then +; + +: rescue_disable ( -- ) + s" noimport" unsetenv + s" standalone" unsetenv + s" smartos" getenv? if + s" set smartos=true" evaluate + then +; + +: init_rescue ( N -- N ) + rescue_enabled? if + toggle_menuitem ( n -- n ) + then +; + +: toggle_rescue ( N -- N TRUE ) + toggle_menuitem + menu-redraw + + \ Now we're going to make the change effective + + dup toggle_stateN @ 0= if + rescue_disable + else + rescue_enable + then + + TRUE \ loop menu again +; + +\ \ Escape to Prompt \ diff --git a/usr/src/boot/sys/boot/forth/menu.4th b/usr/src/boot/sys/boot/forth/menu.4th index efdd51b6a8..814445fac8 100644 --- a/usr/src/boot/sys/boot/forth/menu.4th +++ b/usr/src/boot/sys/boot/forth/menu.4th @@ -3,6 +3,7 @@ \ Copyright (c) 2006-2015 Devin Teske <dteske@FreeBSD.org> \ Copyright 2019 OmniOS Community Edition (OmniOSce) Association. \ All rights reserved. +\ Copyright 2019 Joyent, Inc. \ \ Redistribution and use in source and binary forms, with or without \ modification, are permitted provided that the following conditions @@ -463,20 +464,20 @@ also menu-infrastructure definitions : osconsole-captions ( N -- ) \ first entry - dup s" Os[C]onsole.. text" rot 48 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole.. ^[32;7mtext^[m" rot 48 ansi_caption[x][y] setenv + dup s" OS [C]onsole.......... text" rot 48 menu_caption[x][y] setenv + dup s" OS ^[1mC^[monsole........... ^[32;7mtext^[m" rot 48 ansi_caption[x][y] setenv - dup s" Os[C]onsole.. ttya" rot 49 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole.. ^[34;1mttya^[m" rot 49 ansi_caption[x][y] setenv + dup s" OS [C]onsole.......... ttya" rot 49 menu_caption[x][y] setenv + dup s" OS ^[1mC^[monsole........... ^[34;1mttya^[m" rot 49 ansi_caption[x][y] setenv - dup s" Os[C]onsole.. ttyb" rot 50 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole.. ^[34;1mttyb^[m" rot 50 ansi_caption[x][y] setenv + dup s" OS [C]onsole.......... ttyb" rot 50 menu_caption[x][y] setenv + dup s" OS ^[1mC^[monsole........... ^[34;1mttyb^[m" rot 50 ansi_caption[x][y] setenv - dup s" Os[C]onsole.. ttyc" rot 51 menu_caption[x][y] setenv - dup s" Os^[1mC^[monsole.. ^[34;1mttyc^[m" rot 51 ansi_caption[x][y] setenv + dup s" OS [C]onsole.......... ttyc" rot 51 menu_caption[x][y] setenv + dup s" OS ^[1mC^[monsole........... ^[34;1mttyc^[m" rot 51 ansi_caption[x][y] setenv - dup s" Os[C]onsole.. ttyd" rot 52 menu_caption[x][y] setenv - s" Os^[1mC^[monsole.. ^[34;1mttyd^[m" rot 52 ansi_caption[x][y] setenv + dup s" OS [C]onsole.......... ttyd" rot 52 menu_caption[x][y] setenv + s" OS ^[1mC^[monsole........... ^[34;1mttyd^[m" rot 52 ansi_caption[x][y] setenv ; \ This function creates the list of menu items. This function is called by the @@ -486,7 +487,7 @@ also menu-infrastructure definitions \ Print the frame caption at (x,y) s" loader_menu_title" getenv dup -1 = if - drop s" Welcome to illumos" + drop s" Welcome to SmartOS" then TRUE ( use default alignment ) s" loader_menu_title_align" getenv dup -1 <> if @@ -748,7 +749,18 @@ also menu-infrastructure definitions dup 9 > if drop 9 then dup 0 < if drop 0 then - s" Autoboot in N seconds. [Space] to pause" ( n -- n c-addr/u ) + \ getenv? leaves -1 on stack if the env var exists. Thus if both + \ headnode and ipxe exist then the sum of what will be left on the + \ stack should be -2. + s" headnode" getenv? s" ipxe" getenv? + -2 = if + s" ipxe" getenv s" true" compare 0= if + s" Autoboot in N seconds from PXE. [Space] to pause" ( n -- n c-addr/u ) + else + s" Autoboot in N seconds from the USB Key. [Space] to pause" ( n -- n c-addr/u ) + then + else + s" Autoboot in N seconds. [Space] to pause" ( n -- n c-addr/u ) + then 2 pick 0> if rot 48 + -rot ( n c-addr/u -- n' c-addr/u ) \ convert to ASCII diff --git a/usr/src/boot/sys/boot/forth/support.4th b/usr/src/boot/sys/boot/forth/support.4th index 31420929d9..8ea4d3812c 100644 --- a/usr/src/boot/sys/boot/forth/support.4th +++ b/usr/src/boot/sys/boot/forth/support.4th @@ -226,6 +226,21 @@ create last_module_option sizeof module.next allot 0 last_module_option ! then ; +\ Place string into an allocated buffer +\ +\ e.g +\ create mystring 32 chars allot +\ s" Burning down " mystring place +\ +: place over over >r >r char+ swap chars move r> r> c! ; + +\ Append string +\ +\ e.g. +\ s" the house!" mystring append +\ +: append over over >r >r count chars + swap chars move r> r> dup >r c@ + r> c! ; + \ Returns TRUE if the framebuffer is active, FALSE otherwise : framebuffer? ( -- flag ) \ Use the screen-height variable as a proxy for framebuffer diff --git a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c b/usr/src/boot/sys/boot/i386/libi386/i386_copy.c index b697b43143..562c66b37c 100644 --- a/usr/src/boot/sys/boot/i386/libi386/i386_copy.c +++ b/usr/src/boot/sys/boot/i386/libi386/i386_copy.c @@ -24,6 +24,10 @@ * SUCH DAMAGE. */ +/* + * Copyright (c) 2019, Joyent, Inc. + */ + #include <sys/cdefs.h> /* @@ -93,6 +97,8 @@ smap_find(struct bios_smap *smap, int smaplen, vm_offset_t addr, size_t size) return (0); } +#define SAFE_LOAD_BASE 0xc800000 + /* * Find usable address for loading. The address for the kernel is fixed, as * it is determined by kernel linker map (dboot PT_LOAD address). @@ -116,8 +122,13 @@ i386_loadaddr(u_int type, void *data, vm_offset_t addr) if (type == LOAD_KERN) return (addr); + /* + * Nothing is yet loaded. We shouldn't get to a module with a load + * address of zero still, and the kernel loads at its own multiboot + * address, so we don't need to make any adjustments here. + */ if (addr == 0) - return (addr); /* nothing to do */ + return (0); if (type == LOAD_ELF) return (0); /* not supported */ @@ -146,12 +157,19 @@ i386_loadaddr(u_int type, void *data, vm_offset_t addr) /* Start from the end of the kernel. */ mfp = fp; do { + + if (mfp == NULL) { off = roundup2(addr + 1, MULTIBOOT_MOD_ALIGN); } else { off = roundup2(mfp->f_addr + mfp->f_size + 1, MULTIBOOT_MOD_ALIGN); } + + /* RICHMOND-16 work around. */ + if (off < SAFE_LOAD_BASE) + off = SAFE_LOAD_BASE; + off = smap_find(smap, smaplen, off, size); off = addr_verify(fp, off, size); if (off != 0) diff --git a/usr/src/boot/sys/boot/i386/loader/loader.rc b/usr/src/boot/sys/boot/i386/loader/loader.rc index 32f6bf8043..298b54b2c8 100644 --- a/usr/src/boot/sys/boot/i386/loader/loader.rc +++ b/usr/src/boot/sys/boot/i386/loader/loader.rc @@ -2,6 +2,12 @@ \ \ Includes additional commands include /boot/forth/loader.4th + +\ For SmartOS, override the default color scheme back to the more traditional +\ black background and white foreground. +set tem.fg_color=white +set tem.bg_color=black + try-include /boot/loader.rc.local \ Reads and processes loader.conf variables diff --git a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s b/usr/src/boot/sys/boot/i386/pmbr/pmbr.s index 46088cc78c..e5f059e88b 100644 --- a/usr/src/boot/sys/boot/i386/pmbr/pmbr.s +++ b/usr/src/boot/sys/boot/i386/pmbr/pmbr.s @@ -31,10 +31,12 @@ # # Partly from: src/sys/boot/i386/mbr/mbr.s 1.7 +# Copyright (c) 2019, Joyent, Inc. + # A 512 byte PMBR boot manager to read a boot program and run it. # The embedded MBR is set up for PMBR and default bootblock sector # is hardcoded to 256 and size 1. The actual values are supposed to be -# updated by installboot. +# updated by installboot (and smartos-live's format_image). .set LOAD,0x7c00 # Load address .set EXEC,0x600 # Execution address diff --git a/usr/src/cmd/mdb/common/modules/disk_label/disk_label.c b/usr/src/cmd/mdb/common/modules/disk_label/disk_label.c new file mode 100644 index 0000000000..05d71e4f5a --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/disk_label/disk_label.c @@ -0,0 +1,501 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright (c) 2019, Joyent, Inc. + */ + +/* + * The on-disk elements here are all little-endian, and this code doesn't make + * any attempt to adjust for running on a big-endian system. + * + * We also currently assume a 512-byte sized logical block. + */ + +#include <sys/types.h> +#include <sys/crc32.h> +#include <sys/debug.h> +#include <sys/sysmacros.h> +#include <sys/dktp/fdisk.h> +#include <sys/efi_partition.h> + +#include <assert.h> +#include <ctype.h> +#include <uuid/uuid.h> + +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_debug.h> + +#include "installboot.h" + +#ifdef _BIG_ENDIAN +#error needs porting for big-endian system +#endif + +/* See usr/src/grub/grub-0.97/stage1/stage1.h */ +#define GRUB_VERSION_OFF (0x3e) +#define GRUB_COMPAT_VERSION_MAJOR 3 +#define GRUB_COMPAT_VERSION_MINOR 2 +#define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ + +#define LOADER_VERSION (1) +#define LOADER_JOYENT_VERSION (2) + +typedef enum { + MBR_TYPE_UNKNOWN, + MBR_TYPE_GRUB1, + MBR_TYPE_LOADER, + MBR_TYPE_LOADER_JOYENT, +} mbr_type_t; + +static void +print_fdisk_part(struct ipart *ip, size_t nr) +{ + char typestr[128]; + char begchs[128]; + char endchs[128]; + char *c = NULL; + + if (ip->systid == UNUSED) { + mdb_printf("%-4llu %s:%#lx\n", nr, "UNUSED", ip->systid); + return; + } + + switch (ip->systid) { + case DOSOS12: c = "DOSOS12"; break; + case PCIXOS: c = "PCIXOS"; break; + case DOSOS16: c = "DOSOS16"; break; + case EXTDOS: c = "EXTDOS"; break; + case DOSHUGE: c = "DOSHUGE"; break; + case FDISK_IFS: c = "FDISK_IFS"; break; + case FDISK_AIXBOOT: c = "FDISK_AIXBOOT"; break; + case FDISK_AIXDATA: c = "FDISK_AIXDATA"; break; + case FDISK_OS2BOOT: c = "FDISK_OS2BOOT"; break; + case FDISK_WINDOWS: c = "FDISK_WINDOWS"; break; + case FDISK_EXT_WIN: c = "FDISK_EXT_WIN"; break; + case FDISK_FAT95: c = "FDISK_FAT95"; break; + case FDISK_EXTLBA: c = "FDISK_EXTLBA"; break; + case DIAGPART: c = "DIAGPART"; break; + case FDISK_LINUX: c = "FDISK_LINUX"; break; + case FDISK_LINUXDSWAP: c = "FDISK_LINUXDSWAP"; break; + case FDISK_LINUXDNAT: c = "FDISK_LINUXDNAT"; break; + case FDISK_CPM: c = "FDISK_CPM"; break; + case DOSDATA: c = "DOSDATA"; break; + case OTHEROS: c = "OTHEROS"; break; + case UNIXOS: c = "UNIXOS"; break; + case FDISK_NOVELL2: c = "FDISK_NOVELL2"; break; + case FDISK_NOVELL3: c = "FDISK_NOVELL3"; break; + case FDISK_QNX4: c = "FDISK_QNX4"; break; + case FDISK_QNX42: c = "FDISK_QNX42"; break; + case FDISK_QNX43: c = "FDISK_QNX43"; break; + case SUNIXOS: c = "SUNIXOS"; break; + case FDISK_LINUXNAT: c = "FDISK_LINUXNAT"; break; + case FDISK_NTFSVOL1: c = "FDISK_NTFSVOL1"; break; + case FDISK_NTFSVOL2: c = "FDISK_NTFSVOL2"; break; + case FDISK_BSD: c = "FDISK_BSD"; break; + case FDISK_NEXTSTEP: c = "FDISK_NEXTSTEP"; break; + case FDISK_BSDIFS: c = "FDISK_BSDIFS"; break; + case FDISK_BSDISWAP: c = "FDISK_BSDISWAP"; break; + case X86BOOT: c = "X86BOOT"; break; + case SUNIXOS2: c = "SUNIXOS2"; break; + case EFI_PMBR: c = "EFI_PMBR"; break; + case EFI_FS: c = "EFI_FS"; break; + default: c = NULL; break; + } + + if (c != NULL) { + mdb_snprintf(typestr, sizeof (typestr), "%s:%#lx", + c, ip->systid); + } else { + mdb_snprintf(typestr, sizeof (typestr), "%#lx", ip->systid); + } + + mdb_snprintf(begchs, sizeof (begchs), "%hu/%hu/%hu", + (uint16_t)ip->begcyl | (uint16_t)(ip->begsect & ~0x3f) << 2, + (uint16_t)ip->beghead, (uint16_t)ip->begsect & 0x3f); + mdb_snprintf(endchs, sizeof (endchs), "%hu/%hu/%hu", + (uint16_t)ip->endcyl | (uint16_t)(ip->endsect & ~0x3f) << 2, + (uint16_t)ip->endhead, (uint16_t)ip->endsect & 0x3f); + + mdb_printf("%-4llu %-21s %#-7x %-11s %-11s %-10u %-9u\n", + nr, typestr, ip->bootid, begchs, endchs, ip->relsect, ip->numsect); +} + +static int +cmd_mbr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) +{ + struct mboot mbr; + mbr_type_t type = MBR_TYPE_UNKNOWN; + + CTASSERT(sizeof (mbr) == SECTOR_SIZE); + + if (argc != 0) + return (DCMD_USAGE); + + if (!(flags & DCMD_ADDRSPEC)) + addr = 0; + + if (mdb_vread(&mbr, sizeof (mbr), addr) == -1) { + mdb_warn("failed to read MBR"); + return (DCMD_ERR); + } + + if (*((uint16_t *)&mbr.bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { + type = MBR_TYPE_GRUB1; + } else if (mbr.bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { + type = MBR_TYPE_LOADER; + } else if (mbr.bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { + type = MBR_TYPE_LOADER_JOYENT; + } + + switch (type) { + case MBR_TYPE_UNKNOWN: + mdb_printf("Format: unknown\n"); + break; + case MBR_TYPE_GRUB1: + mdb_printf("Format: grub1\n"); + break; + case MBR_TYPE_LOADER: + mdb_printf("Format: loader (illumos)\n"); + break; + case MBR_TYPE_LOADER_JOYENT: + mdb_printf("Format: loader (joyent)\n"); + break; + } + + mdb_printf("Signature: 0x%hx (%s)\n", mbr.signature, + mbr.signature == MBB_MAGIC ? "valid" : "invalid"); + + mdb_printf("UniqueMBRDiskSignature: %#lx\n", + *(uint32_t *)&mbr.bootinst[STAGE1_SIG]); + + if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { + char uuid[UUID_PRINTABLE_STRING_LENGTH]; + + mdb_printf("Loader STAGE1_STAGE2_LBA: %llu\n", + *(uint64_t *)&mbr.bootinst[STAGE1_STAGE2_LBA]); + + mdb_printf("Loader STAGE1_STAGE2_SIZE: %hu\n", + *(uint16_t *)&mbr.bootinst[STAGE1_STAGE2_SIZE]); + + uuid_unparse((uchar_t *)&mbr.bootinst[STAGE1_STAGE2_UUID], + uuid); + + mdb_printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); + } + + mdb_printf("\n%<u>%-4s %-21s %-7s %-11s %-11s %-10s %-9s%</u>\n", + "PART", "TYPE", "ACTIVE", "STARTCHS", "ENDCHS", + "SECTOR", "NUMSECT"); + + for (size_t i = 0; i < FD_NUMPART; i++) { + struct ipart *ip = (struct ipart *) + (mbr.parts + (sizeof (struct ipart) * i)); + print_fdisk_part(ip, i); + } + + return (DCMD_OK); +} + +static unsigned int crc32_tab[] = { CRC32_TABLE }; + +static unsigned int +efi_crc32(const unsigned char *s, unsigned int len) +{ + unsigned int crc32val; + + CRC32(crc32val, s, len, -1U, crc32_tab); + + return (crc32val ^ -1U); +} + +typedef struct { + struct uuid eg_uuid; + const char *eg_name; +} efi_guid_t; + +static efi_guid_t efi_guids[] = { + { EFI_UNUSED, "EFI_UNUSED" }, + { EFI_RESV1, "EFI_RESV1" }, + { EFI_BOOT, "EFI_BOOT" }, + { EFI_ROOT, "EFI_ROOT" }, + { EFI_SWAP, "EFI_SWAP" }, + { EFI_USR, "EFI_USR" }, + { EFI_BACKUP, "EFI_BACKUP" }, + { EFI_RESV2, "EFI_RESV2" }, + { EFI_VAR, "EFI_VAR" }, + { EFI_HOME, "EFI_HOME" }, + { EFI_ALTSCTR, "EFI_ALTSCTR" }, + { EFI_RESERVED, "EFI_RESERVED" }, + { EFI_SYSTEM, "EFI_SYSTEM" }, + { EFI_LEGACY_MBR, "EFI_LEGACY_MBR" }, + { EFI_SYMC_PUB, "EFI_SYMC_PUB" }, + { EFI_SYMC_CDS, "EFI_SYMC_CDS" }, + { EFI_MSFT_RESV, "EFI_MSFT_RESV" }, + { EFI_DELL_BASIC, "EFI_DELL_BASIC" }, + { EFI_DELL_RAID, "EFI_DELL_RAID" }, + { EFI_DELL_SWAP, "EFI_DELL_SWAP" }, + { EFI_DELL_LVM, "EFI_DELL_LVM" }, + { EFI_DELL_RESV, "EFI_DELL_RESV" }, + { EFI_AAPL_BOOT, "EFI_AAPL_BOOT" }, + { EFI_AAPL_HFS, "EFI_AAPL_HFS" }, + { EFI_AAPL_UFS, "EFI_AAPL_UFS" }, + { EFI_AAPL_ZFS, "EFI_AAPL_ZFS" }, + { EFI_AAPL_APFS, "EFI_AAPL_APFS" }, + { EFI_FREEBSD_BOOT, "EFI_FREEBSD_BOOT" }, + { EFI_FREEBSD_NANDFS, "EFI_FREEBSD_NANDFS" }, + { EFI_FREEBSD_SWAP, "EFI_FREEBSD_SWAP" }, + { EFI_FREEBSD_UFS, "EFI_FREEBSD_UFS" }, + { EFI_FREEBSD_VINUM, "EFI_FREEBSD_VINUM" }, + { EFI_FREEBSD_ZFS, "EFI_FREEBSD_ZFS" }, + { EFI_BIOS_BOOT, "EFI_BIOS_BOOT" }, +}; + +static void +print_gpe(efi_gpe_t *gpe, size_t nr, int show_guid) +{ + const char *type = "unknown"; + + for (size_t i = 0; i < ARRAY_SIZE(efi_guids); i++) { + if (memcmp((void *)&efi_guids[i].eg_uuid, + (void *)&gpe->efi_gpe_PartitionTypeGUID, + sizeof (efi_guids[i].eg_uuid)) == 0) { + type = efi_guids[i].eg_name; + break; + } + } + + if (strcmp(type, "EFI_UNUSED") == 0) { + mdb_printf("%-4u %-19s\n", nr, type); + return; + } + + if (show_guid) { + char guid[UUID_PRINTABLE_STRING_LENGTH]; + + uuid_unparse((uchar_t *)&gpe->efi_gpe_UniquePartitionGUID, + guid); + + mdb_printf("%-4u %-19s %s\n", nr, type, guid); + } else { + char name[EFI_PART_NAME_LEN + 1] = ""; + + /* + * Hopefully, ASCII is sufficient for any naming we care about. + */ + for (size_t i = 0; i < sizeof (name); i++) { + ushort_t wchar = gpe->efi_gpe_PartitionName[i]; + + name[i] = (char)(isascii(wchar) ? wchar : '?'); + } + + mdb_printf("%-4u %-19s %-13llu %-13llu %#-8llx %s\n", + nr, type, gpe->efi_gpe_StartingLBA, gpe->efi_gpe_EndingLBA, + gpe->efi_gpe_Attributes, name); + } +} + +static int +cmd_gpt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) +{ + char uuid[UUID_PRINTABLE_STRING_LENGTH]; + int show_alternate = B_FALSE; + int show_guid = B_FALSE; + efi_gpt_t altheader; + size_t table_size; + efi_gpt_t header; + efi_gpe_t *gpet; + uint_t orig_crc; + uint_t crc; + + if (mdb_getopts(argc, argv, + 'a', MDB_OPT_SETBITS, TRUE, &show_alternate, + 'g', MDB_OPT_SETBITS, TRUE, &show_guid, + NULL) != argc) + return (DCMD_USAGE); + + /* Primary header is at LBA 1. */ + if (!(flags & DCMD_ADDRSPEC)) + addr = SECTOR_SIZE; + + if (mdb_vread(&header, sizeof (header), addr) == -1) { + mdb_warn("failed to read GPT header"); + return (DCMD_ERR); + } + + if (show_alternate) { + addr = header.efi_gpt_AlternateLBA * SECTOR_SIZE; + + if (mdb_vread(&header, sizeof (header), addr) == -1) { + mdb_warn("failed to read GPT header"); + return (DCMD_ERR); + } + } + + mdb_printf("Signature: %s (%s)\n", (char *)&header.efi_gpt_Signature, + strncmp((char *)&header.efi_gpt_Signature, "EFI PART", 8) == 0 ? + "valid" : "invalid"); + + mdb_printf("Revision: %hu.%hu\n", header.efi_gpt_Revision >> 16, + header.efi_gpt_Revision); + + mdb_printf("HeaderSize: %u bytes\n", header.efi_gpt_HeaderSize); + + if (header.efi_gpt_HeaderSize > SECTOR_SIZE) { + mdb_warn("invalid header size: skipping CRC\n"); + } else { + orig_crc = header.efi_gpt_HeaderCRC32; + + header.efi_gpt_HeaderCRC32 = 0; + + crc = efi_crc32((unsigned char *)&header, + header.efi_gpt_HeaderSize); + + mdb_printf("HeaderCRC32: %#x (should be %#x)\n", orig_crc, crc); + } + + mdb_printf("Reserved1: %#x (should be 0x0)\n", + header.efi_gpt_Reserved1); + + mdb_printf("MyLBA: %llu (should be %llu)\n", + header.efi_gpt_MyLBA, addr / SECTOR_SIZE); + + mdb_printf("AlternateLBA: %llu\n", header.efi_gpt_AlternateLBA); + mdb_printf("FirstUsableLBA: %llu\n", header.efi_gpt_FirstUsableLBA); + mdb_printf("LastUsableLBA: %llu\n", header.efi_gpt_LastUsableLBA); + + if (header.efi_gpt_MyLBA >= header.efi_gpt_FirstUsableLBA && + header.efi_gpt_MyLBA <= header.efi_gpt_LastUsableLBA) { + mdb_warn("MyLBA is within usable LBA range\n"); + } + + if (header.efi_gpt_AlternateLBA >= header.efi_gpt_FirstUsableLBA && + header.efi_gpt_AlternateLBA <= header.efi_gpt_LastUsableLBA) { + mdb_warn("AlternateLBA is within usable LBA range\n"); + } + + if (mdb_vread(&altheader, sizeof (altheader), + header.efi_gpt_AlternateLBA * SECTOR_SIZE) == -1) { + mdb_warn("failed to read alternate GPT header"); + } else { + if (strncmp((char *)&altheader.efi_gpt_Signature, + "EFI PART", 8) != 0) { + mdb_warn("found invalid alternate GPT header with " + "Signature: %s\n", + (char *)&altheader.efi_gpt_Signature); + } + + if (altheader.efi_gpt_MyLBA != header.efi_gpt_AlternateLBA) { + mdb_warn("alternate GPT header at offset %#llx has " + "invalid MyLBA %llu\n", + header.efi_gpt_AlternateLBA * SECTOR_SIZE, + altheader.efi_gpt_MyLBA); + } + + if (altheader.efi_gpt_AlternateLBA != header.efi_gpt_MyLBA) { + mdb_warn("alternate GPT header at offset %#llx has " + "invalid AlternateLBA %llu\n", + header.efi_gpt_AlternateLBA * SECTOR_SIZE, + altheader.efi_gpt_AlternateLBA); + } + + /* + * We could go ahead and verify all the alternate checksums, + * etc. here too... + */ + } + + uuid_unparse((uchar_t *)&header.efi_gpt_DiskGUID, uuid); + mdb_printf("DiskGUID: %s\n", uuid); + + mdb_printf("PartitionEntryLBA: %llu\n", + header.efi_gpt_PartitionEntryLBA); + + mdb_printf("NumberOfPartitionEntries: %u\n", + header.efi_gpt_NumberOfPartitionEntries); + + /* + * While the spec allows a different size, in practice the table + * is always packed. + */ + if (header.efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) { + mdb_warn("SizeOfPartitionEntry: %#x bytes " + "(expected %#x bytes)\n", + header.efi_gpt_SizeOfPartitionEntry, sizeof (efi_gpe_t)); + return (DCMD_ERR); + } + + mdb_printf("SizeOfPartitionEntry: %#x bytes\n", + header.efi_gpt_SizeOfPartitionEntry); + + table_size = header.efi_gpt_SizeOfPartitionEntry * + header.efi_gpt_NumberOfPartitionEntries; + + /* + * While this is a minimum reservation, it serves us ably as a + * maximum value to reasonably expect. + */ + if (table_size > EFI_MIN_ARRAY_SIZE) { + mdb_warn("Skipping GPT array of %#lx bytes.\n", table_size); + return (DCMD_ERR); + } + + gpet = mdb_alloc(header.efi_gpt_SizeOfPartitionEntry * + header.efi_gpt_NumberOfPartitionEntries, UM_SLEEP | UM_GC); + + if (mdb_vread(gpet, table_size, + header.efi_gpt_PartitionEntryLBA * SECTOR_SIZE) == -1) { + mdb_warn("couldn't read GPT array"); + return (DCMD_ERR); + } + + crc = efi_crc32((unsigned char *)gpet, table_size); + + mdb_printf("PartitionEntryArrayCRC32: %#x (should be %#x)\n", + header.efi_gpt_PartitionEntryArrayCRC32, crc); + + if (show_guid) { + mdb_printf("\n%<u>%-4s %-19s %-37s%</u>\n", + "PART", "TYPE", "GUID"); + } else { + mdb_printf("\n%<u>%-4s %-19s %-13s %-13s %-8s %s%</u>\n", + "PART", "TYPE", "STARTLBA", "ENDLBA", "ATTR", "NAME"); + } + + for (size_t i = 0; i < header.efi_gpt_NumberOfPartitionEntries; i++) + print_gpe(&gpet[i], i, show_guid); + + return (DCMD_OK); +} + +void +gpt_help(void) +{ + mdb_printf("Display an EFI GUID Partition Table.\n\n" + "-a Display the alternate GPT\n" + "-g Show unique GUID for each table entry\n"); +} + +static const mdb_dcmd_t dcmds[] = { + { "mbr", NULL, "dump Master Boot Record information", cmd_mbr }, + { "gpt", "?[-ag]", "dump an EFI GPT", cmd_gpt, gpt_help }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { + MDB_API_VERSION, dcmds, NULL +}; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +} diff --git a/usr/src/cmd/mdb/intel/amd64/Makefile b/usr/src/cmd/mdb/intel/amd64/Makefile index f7bc890fb5..6ddc6b59d5 100644 --- a/usr/src/cmd/mdb/intel/amd64/Makefile +++ b/usr/src/cmd/mdb/intel/amd64/Makefile @@ -21,12 +21,13 @@ # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. -# Copyright 2018 Joyent, Inc. +# Copyright 2019 Joyent, Inc. # include ../../Makefile.common -MODULES = $(COMMON_MODULES_PROC) $(COMMON_MODULES_KVM) uhci +MODULES = $(COMMON_MODULES_PROC) $(COMMON_MODULES_KVM) +MODULES += disk_label uhci SUBDIRS = mdb mdb_ks kmdb libstandctf libstand .WAIT $(MODULES) diff --git a/usr/src/cmd/mdb/intel/amd64/disk_label/Makefile b/usr/src/cmd/mdb/intel/amd64/disk_label/Makefile new file mode 100644 index 0000000000..7b084ac28c --- /dev/null +++ b/usr/src/cmd/mdb/intel/amd64/disk_label/Makefile @@ -0,0 +1,28 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# Copyright (c) 2019, Joyent, Inc. +# + +MODULE = disk_label.so +MDBTGT = raw + +MODSRCS = disk_label.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module + +MODSRCS_DIR = ../../../common/modules/disk_label + +CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/cmd/boot/installboot/i386 + +LDLIBS += -luuid diff --git a/usr/src/cmd/mdb/intel/ia32/Makefile b/usr/src/cmd/mdb/intel/ia32/Makefile index f90ef4f824..cb544a52d2 100644 --- a/usr/src/cmd/mdb/intel/ia32/Makefile +++ b/usr/src/cmd/mdb/intel/ia32/Makefile @@ -22,10 +22,13 @@ # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # +# Copyright (c) 2019, Joyent, Inc. +# include ../../Makefile.common MODULES = $(COMMON_MODULES_PROC) $(COMMON_MODULES_PROC_32BIT) +MODULES += disk_label SUBDIRS = mdb .WAIT $(MODULES) diff --git a/usr/src/cmd/mdb/intel/ia32/disk_label/Makefile b/usr/src/cmd/mdb/intel/ia32/disk_label/Makefile new file mode 100644 index 0000000000..a50f3613da --- /dev/null +++ b/usr/src/cmd/mdb/intel/ia32/disk_label/Makefile @@ -0,0 +1,27 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# +# Copyright (c) 2019, Joyent, Inc. +# + +MODULE = disk_label.so +MDBTGT = raw + +MODSRCS = disk_label.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module + +MODSRCS_DIR = ../../../common/modules/disk_label + +CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/cmd/boot/installboot/i386 + +LDLIBS += -luuid diff --git a/usr/src/lib/libefi/common/crc32_efi.c b/usr/src/lib/libefi/common/crc32_efi.c index 1dba28ad72..73039f1478 100644 --- a/usr/src/lib/libefi/common/crc32_efi.c +++ b/usr/src/lib/libefi/common/crc32_efi.c @@ -23,8 +23,9 @@ * Copyright 2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" +/* + * Copyright (c) 2019, Joyent, Inc. + */ #include <sys/crc32.h> diff --git a/usr/src/lib/libefi/common/rdwr_efi.c b/usr/src/lib/libefi/common/rdwr_efi.c index e0d866e3c4..6aaaba7b92 100644 --- a/usr/src/lib/libefi/common/rdwr_efi.c +++ b/usr/src/lib/libefi/common/rdwr_efi.c @@ -24,7 +24,7 @@ * Copyright 2015 Nexenta Systems, Inc. All rights reserved. * Copyright 2014 Toomas Soome <tsoome@me.com> * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. - * Copyright (c) 2018, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #include <stdio.h> @@ -132,12 +132,98 @@ int efi_debug = 0; extern unsigned int efi_crc32(const unsigned char *, unsigned int); static int efi_read(int, struct dk_gpt *); +/* + * In normal operation, libefi just passes everything down to the kernel driver + * (and - usually - cmlb), as that code needs to react to any partitioning + * changes by changing device nodes under /dev/?dsk/ and the like. + * + * However, if we are running against an un-labeled lofi device on an older + * version of illumos, these ioctl()s aren't emulated. This can be a problem if + * we're in a non-global zone, which doesn't support labeled lofi, and our + * kernel is downrev. + * + * In this case, we'll simply emulate the ioctl()s that libefi actually needs, + * except those for efi_type(). They basically boil down to simple reads and + * writes, though this does skip a bunch of error checking. + * + * As a final wrinkle, rather than rely on an updated libefi, smartos-live's + * format_image tool directly builds and uses this source. + */ +static int +do_ioctl(int fd, int cmd, void *arg) +{ + struct dk_cinfo cinfo; + struct dk_minfo minfo; + dk_efi_t *efi = arg; + int saved_errno; + size_t len; + int error; + + error = ioctl(fd, cmd, arg); + + saved_errno = errno; + + if (error != -1 || errno != ENOTTY || + ioctl(fd, DKIOCINFO, (caddr_t)&cinfo) != 0 || + strcmp(cinfo.dki_cname, "lofi") != 0 || + ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&minfo) != 0) { + errno = saved_errno; + return (error); + } + + switch (cmd) { + case DKIOCGMBOOT: + len = (size_t)pread(fd, arg, minfo.dki_lbsize, 0); + error = (len == minfo.dki_lbsize) ? 0 : -1; + break; + + case DKIOCSMBOOT: + len = (size_t)pwrite(fd, arg, minfo.dki_lbsize, 0); + error = (len == minfo.dki_lbsize) ? 0 : -1; + break; + + case DKIOCGETEFI: + len = (size_t)pread(fd, (caddr_t)(uintptr_t)efi->dki_data_64, + efi->dki_length, efi->dki_lba * minfo.dki_lbsize); + error = (len == efi->dki_length) ? 0 : -1; + break; + + case DKIOCSETEFI: + len = (size_t)pwrite(fd, (caddr_t)(uintptr_t)efi->dki_data_64, + efi->dki_length, efi->dki_lba * minfo.dki_lbsize); + error = (len == efi->dki_length) ? 0 : -1; + break; + + default: + errno = saved_errno; + break; + } + + if (error == 0) + errno = 0; + + return (error); +} + +static int +efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) +{ + void *data = dk_ioc->dki_data; + int error; + + dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data; + error = do_ioctl(fd, cmd, (void *)dk_ioc); + dk_ioc->dki_data = data; + + return (error); +} + static int read_disk_info(int fd, diskaddr_t *capacity, uint_t *lbsize) { struct dk_minfo disk_info; - if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) + if ((do_ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) return (errno); *capacity = disk_info.dki_capacity; *lbsize = disk_info.dki_lbsize; @@ -183,6 +269,7 @@ efi_alloc_and_init(int fd, uint32_t nparts, struct dk_gpt **vtoc) "the maximum number of partitions supported is %lu\n", MAX_PARTS); } + errno = EINVAL; return (-1); } @@ -233,7 +320,7 @@ efi_alloc_and_read(int fd, struct dk_gpt **vtoc) if ((mbr = calloc(1, lbsize)) == NULL) return (VT_ERROR); - if ((ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) { + if ((do_ioctl(fd, DKIOCGMBOOT, (caddr_t)mbr)) == -1) { free(mbr); return (VT_ERROR); } @@ -292,19 +379,6 @@ efi_alloc_and_read(int fd, struct dk_gpt **vtoc) } static int -efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) -{ - void *data = dk_ioc->dki_data; - int error; - - dk_ioc->dki_data_64 = (uint64_t)(uintptr_t)data; - error = ioctl(fd, cmd, (void *)dk_ioc); - dk_ioc->dki_data = data; - - return (error); -} - -static int check_label(int fd, dk_efi_t *dk_ioc) { efi_gpt_t *efi; @@ -341,9 +415,8 @@ check_label(int fd, dk_efi_t *dk_ioc) if (efi_debug) (void) fprintf(stderr, "Bad EFI CRC: 0x%x != 0x%x\n", - crc, - LE_32(efi_crc32((unsigned char *)efi, - sizeof (struct efi_gpt)))); + crc, LE_32(efi_crc32((unsigned char *)efi, + LE_32(efi->efi_gpt_HeaderSize)))); return (VT_EINVAL); } @@ -368,7 +441,7 @@ efi_read(int fd, struct dk_gpt *vtoc) /* * get the partition number for this file descriptor. */ - if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { + if (do_ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { if (efi_debug) { (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno); } @@ -392,7 +465,7 @@ efi_read(int fd, struct dk_gpt *vtoc) } /* get the LBA size */ - if (ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) { + if (do_ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) == -1) { if (efi_debug) { (void) fprintf(stderr, "assuming LBA 512 bytes %d\n", @@ -715,7 +788,7 @@ write_pmbr(int fd, struct dk_gpt *vtoc) hardware_workarounds(&slot, &active); len = (vtoc->efi_lbasize == 0) ? sizeof (mb) : vtoc->efi_lbasize; - buf = calloc(len, 1); + buf = calloc(1, len); /* * Preserve any boot code and disk signature if the first block is @@ -741,10 +814,10 @@ write_pmbr(int fd, struct dk_gpt *vtoc) cp = (uchar_t *)&mb.parts[slot * sizeof (struct ipart)]; /* bootable or not */ *cp++ = active ? ACTIVE : NOTACTIVE; - /* beginning CHS; 0xffffff if not representable */ - *cp++ = 0xff; - *cp++ = 0xff; - *cp++ = 0xff; + /* beginning CHS; same as starting LBA (but one-based) */ + *cp++ = 0x0; + *cp++ = 0x2; + *cp++ = 0x0; /* OS type */ *cp++ = EFI_PMBR; /* ending CHS; 0xffffff if not representable */ @@ -985,7 +1058,7 @@ efi_write(int fd, struct dk_gpt *vtoc) int nblocks; diskaddr_t lba_backup_gpt_hdr; - if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { + if (do_ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { if (efi_debug) (void) fprintf(stderr, "DKIOCINFO errno 0x%x\n", errno); switch (errno) { @@ -1029,7 +1102,7 @@ efi_write(int fd, struct dk_gpt *vtoc) /* stuff user's input into EFI struct */ efi->efi_gpt_Signature = LE_64(EFI_SIGNATURE); efi->efi_gpt_Revision = LE_32(vtoc->efi_version); /* 0x02000100 */ - efi->efi_gpt_HeaderSize = LE_32(sizeof (struct efi_gpt)); + efi->efi_gpt_HeaderSize = LE_32(EFI_HEADER_SIZE); efi->efi_gpt_Reserved1 = 0; efi->efi_gpt_MyLBA = LE_64(1ULL); efi->efi_gpt_AlternateLBA = LE_64(lba_backup_gpt_hdr); @@ -1094,8 +1167,8 @@ efi_write(int fd, struct dk_gpt *vtoc) efi->efi_gpt_PartitionEntryArrayCRC32 = LE_32(efi_crc32((unsigned char *)efi_parts, vtoc->efi_nparts * (int)sizeof (struct efi_gpe))); - efi->efi_gpt_HeaderCRC32 = - LE_32(efi_crc32((unsigned char *)efi, sizeof (struct efi_gpt))); + efi->efi_gpt_HeaderCRC32 = LE_32(efi_crc32((unsigned char *)efi, + EFI_HEADER_SIZE)); if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { free(dk_ioc.dki_data); @@ -1142,8 +1215,7 @@ efi_write(int fd, struct dk_gpt *vtoc) efi->efi_gpt_PartitionEntryLBA = LE_64(vtoc->efi_last_u_lba + 1); efi->efi_gpt_HeaderCRC32 = 0; efi->efi_gpt_HeaderCRC32 = - LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data, - sizeof (struct efi_gpt))); + LE_32(efi_crc32((unsigned char *)dk_ioc.dki_data, EFI_HEADER_SIZE)); if (efi_ioctl(fd, DKIOCSETEFI, &dk_ioc) == -1) { if (efi_debug) { @@ -1170,6 +1242,8 @@ efi_free(struct dk_gpt *ptr) * Input: File descriptor * Output: 1 if disk has an EFI label, or > 2TB with no VTOC or legacy MBR. * Otherwise 0. + * + * This always returns 0 for an un-labeled lofi device. */ int efi_type(int fd) diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c index 196c98c602..33bac61d21 100644 --- a/usr/src/uts/common/fs/zfs/zvol.c +++ b/usr/src/uts/common/fs/zfs/zvol.c @@ -26,7 +26,7 @@ * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2012, 2017 by Delphix. All rights reserved. * Copyright (c) 2014 Integros [integros.com] - * Copyright 2018 Joyent, Inc. + * Copyright (c) 2019, Joyent, Inc. */ /* @@ -1622,7 +1622,7 @@ zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs) gpt.efi_gpt_Signature = LE_64(EFI_SIGNATURE); gpt.efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT); - gpt.efi_gpt_HeaderSize = LE_32(sizeof (gpt)); + gpt.efi_gpt_HeaderSize = LE_32(EFI_HEADER_SIZE); gpt.efi_gpt_MyLBA = LE_64(1ULL); gpt.efi_gpt_FirstUsableLBA = LE_64(34ULL); gpt.efi_gpt_LastUsableLBA = LE_64((vs >> bs) - 1); @@ -1632,7 +1632,7 @@ zvol_getefi(void *arg, int flag, uint64_t vs, uint8_t bs) LE_32(sizeof (efi_gpe_t)); CRC32(crc, &gpe, sizeof (gpe), -1U, crc32_table); gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); - CRC32(crc, &gpt, sizeof (gpt), -1U, crc32_table); + CRC32(crc, &gpt, EFI_HEADER_SIZE, -1U, crc32_table); gpt.efi_gpt_HeaderCRC32 = LE_32(~crc); if (ddi_copyout(&gpt, ptr, MIN(sizeof (gpt), length), flag)) diff --git a/usr/src/uts/common/io/cmlb.c b/usr/src/uts/common/io/cmlb.c index 17eca53288..417010c8e9 100644 --- a/usr/src/uts/common/io/cmlb.c +++ b/usr/src/uts/common/io/cmlb.c @@ -24,6 +24,7 @@ * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2016 Toomas Soome <tsoome@me.com> + * Copyright (c) 2019, Joyent, Inc. */ /* @@ -2747,7 +2748,7 @@ cmlb_validate_efi(efi_gpt_t *labp) { if (labp->efi_gpt_Signature != EFI_SIGNATURE) return (EINVAL); - /* at least 96 bytes in this version of the spec. */ + /* at least 92 bytes in this version of the spec. */ if (sizeof (efi_gpt_t) - sizeof (labp->efi_gpt_Reserved2) > labp->efi_gpt_HeaderSize) return (EINVAL); diff --git a/usr/src/uts/common/io/lofi.c b/usr/src/uts/common/io/lofi.c index e8d82a6688..5032452543 100644 --- a/usr/src/uts/common/io/lofi.c +++ b/usr/src/uts/common/io/lofi.c @@ -168,6 +168,8 @@ #include <sys/scsi/scsi.h> /* for DTYPE_DIRECT */ #include <sys/scsi/impl/uscsi.h> #include <sys/sysevent/dev.h> +#include <sys/efi_partition.h> +#include <sys/note.h> #include <LzmaDec.h> #define NBLOCKS_PROP_NAME "Nblocks" @@ -1741,26 +1743,58 @@ lofi_strategy(struct buf *bp) return (0); } -/*ARGSUSED2*/ static int lofi_read(dev_t dev, struct uio *uio, struct cred *credp) { + _NOTE(ARGUNUSED(credp)); + if (getminor(dev) == 0) return (EINVAL); UIO_CHECK(uio); return (physio(lofi_strategy, NULL, dev, B_READ, minphys, uio)); } -/*ARGSUSED2*/ static int lofi_write(dev_t dev, struct uio *uio, struct cred *credp) { + _NOTE(ARGUNUSED(credp)); + if (getminor(dev) == 0) return (EINVAL); UIO_CHECK(uio); return (physio(lofi_strategy, NULL, dev, B_WRITE, minphys, uio)); } +static int +lofi_urw(struct lofi_state *lsp, uint16_t fmode, diskaddr_t off, size_t size, + intptr_t arg, int flag, cred_t *credp) +{ + struct uio uio; + iovec_t iov; + + /* + * 1024 * 1024 apes cmlb_tg_max_efi_xfer as a reasonable max. + */ + if (size == 0 || size > 1024 * 1024 || + (size % (1 << lsp->ls_lbshift)) != 0) + return (EINVAL); + + iov.iov_base = (void *)arg; + iov.iov_len = size; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_loffset = off; + uio.uio_segflg = (flag & FKIOCTL) ? UIO_SYSSPACE : UIO_USERSPACE; + uio.uio_llimit = MAXOFFSET_T; + uio.uio_resid = size; + uio.uio_fmode = fmode; + uio.uio_extflg = 0; + + return (fmode == FREAD ? + lofi_read(lsp->ls_dev, &uio, credp) : + lofi_write(lsp->ls_dev, &uio, credp)); +} + /*ARGSUSED2*/ static int lofi_aread(dev_t dev, struct aio_req *aio, struct cred *credp) @@ -3185,10 +3219,11 @@ static int lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp) { - int error; + int error; enum dkio_state dkstate; struct lofi_state *lsp; - int id; + dk_efi_t user_efi; + int id; id = LOFI_MINOR2ID(getminor(dev)); @@ -3438,6 +3473,35 @@ lofi_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, #endif /* _MULTI_DATAMODEL */ return (0); } + + case DKIOCGMBOOT: + return (lofi_urw(lsp, FREAD, 0, 1 << lsp->ls_lbshift, + arg, flag, credp)); + + case DKIOCSMBOOT: + return (lofi_urw(lsp, FWRITE, 0, 1 << lsp->ls_lbshift, + arg, flag, credp)); + + case DKIOCGETEFI: + if (ddi_copyin((void *)arg, &user_efi, + sizeof (dk_efi_t), flag) != 0) + return (EFAULT); + + return (lofi_urw(lsp, FREAD, + user_efi.dki_lba * (1 << lsp->ls_lbshift), + user_efi.dki_length, (intptr_t)user_efi.dki_data, + flag, credp)); + + case DKIOCSETEFI: + if (ddi_copyin((void *)arg, &user_efi, + sizeof (dk_efi_t), flag) != 0) + return (EFAULT); + + return (lofi_urw(lsp, FWRITE, + user_efi.dki_lba * (1 << lsp->ls_lbshift), + user_efi.dki_length, (intptr_t)user_efi.dki_data, + flag, credp)); + default: #ifdef DEBUG cmn_err(CE_WARN, "lofi_ioctl: %d is not implemented\n", cmd); diff --git a/usr/src/uts/common/sys/efi_partition.h b/usr/src/uts/common/sys/efi_partition.h index 5fa101cbb7..065f65f802 100644 --- a/usr/src/uts/common/sys/efi_partition.h +++ b/usr/src/uts/common/sys/efi_partition.h @@ -22,12 +22,14 @@ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright 2014 Toomas Soome <tsoome@me.com> + * Copyright (c) 2019, Joyent, Inc. */ #ifndef _SYS_EFI_PARTITION_H #define _SYS_EFI_PARTITION_H #include <sys/uuid.h> +#include <sys/stddef.h> #ifdef __cplusplus extern "C" { @@ -46,6 +48,16 @@ extern "C" { #define EFI_SIGNATURE 0x5452415020494645ULL +/* + * Although the EFI spec is clear that sizeof (efi_gpt_t) is a valid value + * (512), at least one EFI system (AMI v4.6.4.1) incorrectly expects this to be + * exactly the size of the structure defined in the spec, that is, 92. + * + * As the reserved section is never used, the modified value works fine + * everywhere else. + */ +#define EFI_HEADER_SIZE (offsetof(efi_gpt_t, efi_gpt_Reserved2)) + /* EFI Guid Partition Table Header -- little endian on-disk format */ typedef struct efi_gpt { uint64_t efi_gpt_Signature; @@ -222,7 +234,7 @@ typedef struct dk_efi { diskaddr_t dki_lba; /* starting block */ len_t dki_length; /* length in bytes */ union { - efi_gpt_t *_dki_data; + efi_gpt_t *_dki_data; uint64_t _dki_data_64; } dki_un; #define dki_data dki_un._dki_data diff --git a/usr/src/uts/i86pc/dboot/dboot_startkern.c b/usr/src/uts/i86pc/dboot/dboot_startkern.c index dd9fef27fb..74e3504d11 100644 --- a/usr/src/uts/i86pc/dboot/dboot_startkern.c +++ b/usr/src/uts/i86pc/dboot/dboot_startkern.c @@ -23,7 +23,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2018 Joyent, Inc. All rights reserved. + * Copyright 2019 Joyent, Inc. All rights reserved. */ @@ -76,15 +76,6 @@ extern int have_cpuid(void); #define SHA1_ASCII_LENGTH (SHA1_DIGEST_LENGTH * 2) /* - * Region of memory that may be corrupted by external actors. This can go away - * once the firmware bug RICHMOND-16 is fixed and all systems with the bug are - * upgraded. - */ -#define CORRUPT_REGION_START 0xc700000 -#define CORRUPT_REGION_SIZE 0x100000 -#define CORRUPT_REGION_END (CORRUPT_REGION_START + CORRUPT_REGION_SIZE) - -/* * This file contains code that runs to transition us from either a multiboot * compliant loader (32 bit non-paging) or a XPV domain loader to * regular kernel execution. Its task is to setup the kernel memory image @@ -1469,6 +1460,80 @@ dboot_process_modules(void) check_images(); } +#define CORRUPT_REGION_START 0xc700000 +#define CORRUPT_REGION_SIZE 0x100000 +#define CORRUPT_REGION_END (CORRUPT_REGION_START + CORRUPT_REGION_SIZE) + +static void +dboot_add_memlist(uint64_t start, uint64_t end) +{ + if (end > max_mem) + max_mem = end; + + /* + * Well, this is sad. On some systems, there is a region of memory that + * can be corrupted until some number of seconds after we have booted. + * And the BIOS doesn't tell us that this memory is unsafe to use. And + * we don't know how long it's dangerous. So we'll chop out this range + * from any memory list that would otherwise be usable. Note that any + * system of this type will give us the new-style (0x40) memlist, so we + * need not fix up the other path below. + * + * However, if we're boot-loaded from something that doesn't have a + * RICHMOND-16 workaround (which on many systems is just fine), it could + * actually use this region for the boot modules; if we remove it from + * the memlist, we'll keel over when trying to access the region. + * + * So, if we see that a module intersects the region, we presume it's + * OK. + */ + + if (find_boot_prop("disable-RICHMOND-16") != NULL) + goto out; + + for (uint32_t i = 0; i < bi->bi_module_cnt; i++) { + native_ptr_t mod_start = modules[i].bm_addr; + native_ptr_t mod_end = modules[i].bm_addr + modules[i].bm_size; + + if (mod_start < CORRUPT_REGION_END && + mod_end >= CORRUPT_REGION_START) { + if (prom_debug) { + dboot_printf("disabling RICHMOND-16 workaround " + "due to module #%u: " + "name %s addr %lx size %lx\n", + i, (char *)(uintptr_t)modules[i].bm_name, + (ulong_t)modules[i].bm_addr, + (ulong_t)modules[i].bm_size); + } + goto out; + } + } + + if (start < CORRUPT_REGION_START && end > CORRUPT_REGION_START) { + memlists[memlists_used].addr = start; + memlists[memlists_used].size = + CORRUPT_REGION_START - start; + ++memlists_used; + if (end > CORRUPT_REGION_END) + start = CORRUPT_REGION_END; + else + return; + } + + if (start >= CORRUPT_REGION_START && start < CORRUPT_REGION_END) { + if (end <= CORRUPT_REGION_END) + return; + start = CORRUPT_REGION_END; + } + +out: + memlists[memlists_used].addr = start; + memlists[memlists_used].size = end - start; + ++memlists_used; + if (memlists_used > MAX_MEMLIST) + dboot_panic("too many memlists"); +} + /* * We then build the phys_install memlist from the multiboot information. */ @@ -1512,45 +1577,7 @@ dboot_process_mmap(void) */ switch (type) { case 1: - if (end > max_mem) - max_mem = end; - - /* - * Well, this is sad. One some systems, there - * is a region of memory that can be corrupted - * until some number of seconds after we have - * booted. And the BIOS doesn't tell us that - * this memory is unsafe to use. And we don't - * know how long it's dangerous. So we'll - * chop out this range from any memory list - * that would otherwise be usable. Note that - * any system of this type will give us the - * new-style (0x40) memlist, so we need not - * fix up the other path below. - */ - if (start < CORRUPT_REGION_START && - end > CORRUPT_REGION_START) { - memlists[memlists_used].addr = start; - memlists[memlists_used].size = - CORRUPT_REGION_START - start; - ++memlists_used; - if (end > CORRUPT_REGION_END) - start = CORRUPT_REGION_END; - else - continue; - } - if (start >= CORRUPT_REGION_START && - start < CORRUPT_REGION_END) { - if (end <= CORRUPT_REGION_END) - continue; - start = CORRUPT_REGION_END; - } - - memlists[memlists_used].addr = start; - memlists[memlists_used].size = end - start; - ++memlists_used; - if (memlists_used > MAX_MEMLIST) - dboot_panic("too many memlists"); + dboot_add_memlist(start, end); break; case 2: rsvdmemlists[rsvdmemlists_used].addr = start; diff --git a/usr/src/uts/i86pc/os/fakebop.c b/usr/src/uts/i86pc/os/fakebop.c index 8ba2e74681..60982a49fc 100644 --- a/usr/src/uts/i86pc/os/fakebop.c +++ b/usr/src/uts/i86pc/os/fakebop.c @@ -2017,6 +2017,7 @@ bop_trap(ulong_t *tfp) bop_printf(NULL, "flags register 0x%lx\n", tf->flags_reg); bop_printf(NULL, "return %%rsp 0x%lx\n", tf->stk_ptr); bop_printf(NULL, "return %%ss 0x%lx\n", tf->stk_seg & 0xffff); + bop_printf(NULL, "%%cr2 0x%lx\n", getcr2()); /* grab %[er]bp pushed by our code from the stack */ fakeframe.old_frame = (bop_frame_t *)*(tfp - 3); diff --git a/usr/src/uts/sun4v/io/vds.c b/usr/src/uts/sun4v/io/vds.c index dee390142b..15d263a1b9 100644 --- a/usr/src/uts/sun4v/io/vds.c +++ b/usr/src/uts/sun4v/io/vds.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Joyent, Inc. */ /* @@ -5832,7 +5833,7 @@ vd_setup_partition_efi(vd_t *vd) gpt->efi_gpt_Signature = LE_64(EFI_SIGNATURE); gpt->efi_gpt_Revision = LE_32(EFI_VERSION_CURRENT); - gpt->efi_gpt_HeaderSize = LE_32(sizeof (efi_gpt_t)); + gpt->efi_gpt_HeaderSize = LE_32(EFI_HEADER_SIZE); gpt->efi_gpt_FirstUsableLBA = LE_64(first_u_lba); gpt->efi_gpt_PartitionEntryLBA = LE_64(2ULL); gpt->efi_gpt_SizeOfPartitionEntry = LE_32(sizeof (efi_gpe_t)); @@ -5869,7 +5870,7 @@ vd_setup_partition_efi(vd_t *vd) CRC32(crc, gpe, sizeof (efi_gpe_t) * VD_MAXPART, -1U, crc32_table); gpt->efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); - CRC32(crc, gpt, sizeof (efi_gpt_t), -1U, crc32_table); + CRC32(crc, gpt, EFI_HEADER_SIZE, -1U, crc32_table); gpt->efi_gpt_HeaderCRC32 = LE_32(~crc); return (0); |