1446c407dSJohn Levon /* 2446c407dSJohn Levon * This file and its contents are supplied under the terms of the 3446c407dSJohn Levon * Common Development and Distribution License ("CDDL"), version 1.0. 4446c407dSJohn Levon * You may only use this file in accordance with the terms of version 5446c407dSJohn Levon * 1.0 of the CDDL. 6446c407dSJohn Levon * 7446c407dSJohn Levon * A full copy of the text of the CDDL should have accompanied this 8446c407dSJohn Levon * source. A copy of the CDDL is also available via the Internet at 9446c407dSJohn Levon * http://www.illumos.org/license/CDDL. 10446c407dSJohn Levon */ 11446c407dSJohn Levon 12446c407dSJohn Levon /* 13446c407dSJohn Levon * Copyright (c) 2019, Joyent, Inc. 14446c407dSJohn Levon */ 15446c407dSJohn Levon 16446c407dSJohn Levon /* 17446c407dSJohn Levon * The on-disk elements here are all little-endian, and this code doesn't make 18446c407dSJohn Levon * any attempt to adjust for running on a big-endian system. 19446c407dSJohn Levon */ 20446c407dSJohn Levon 21446c407dSJohn Levon #include <sys/types.h> 22446c407dSJohn Levon #include <sys/crc32.h> 23446c407dSJohn Levon #include <sys/debug.h> 24446c407dSJohn Levon #include <sys/sysmacros.h> 25446c407dSJohn Levon #include <sys/dktp/fdisk.h> 26446c407dSJohn Levon #include <sys/efi_partition.h> 274188fb37SToomas Soome #include <sys/vtoc.h> 28446c407dSJohn Levon 29446c407dSJohn Levon #include <assert.h> 30446c407dSJohn Levon #include <ctype.h> 31446c407dSJohn Levon #include <uuid/uuid.h> 32446c407dSJohn Levon 33446c407dSJohn Levon #include <mdb/mdb_modapi.h> 34446c407dSJohn Levon #include <mdb/mdb_debug.h> 35446c407dSJohn Levon 36446c407dSJohn Levon #include "installboot.h" 37446c407dSJohn Levon 38446c407dSJohn Levon #ifdef _BIG_ENDIAN 39446c407dSJohn Levon #error needs porting for big-endian system 40446c407dSJohn Levon #endif 41446c407dSJohn Levon 42446c407dSJohn Levon /* See usr/src/grub/grub-0.97/stage1/stage1.h */ 43446c407dSJohn Levon #define GRUB_VERSION_OFF (0x3e) 44446c407dSJohn Levon #define GRUB_COMPAT_VERSION_MAJOR 3 45446c407dSJohn Levon #define GRUB_COMPAT_VERSION_MINOR 2 46446c407dSJohn Levon #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ 47446c407dSJohn Levon 48446c407dSJohn Levon #define LOADER_VERSION (1) 49446c407dSJohn Levon #define LOADER_JOYENT_VERSION (2) 50446c407dSJohn Levon 51446c407dSJohn Levon typedef enum { 52446c407dSJohn Levon MBR_TYPE_UNKNOWN, 53446c407dSJohn Levon MBR_TYPE_GRUB1, 54446c407dSJohn Levon MBR_TYPE_LOADER, 55446c407dSJohn Levon MBR_TYPE_LOADER_JOYENT, 56446c407dSJohn Levon } mbr_type_t; 57446c407dSJohn Levon 584188fb37SToomas Soome typedef struct stringval { 594188fb37SToomas Soome const char *sv_text; 604188fb37SToomas Soome int sv_value; 614188fb37SToomas Soome } stringval_t; 624188fb37SToomas Soome 634188fb37SToomas Soome stringval_t ptag_array[] = { 644188fb37SToomas Soome { "unassigned", V_UNASSIGNED }, 654188fb37SToomas Soome { "boot", V_BOOT }, 664188fb37SToomas Soome { "root", V_ROOT }, 674188fb37SToomas Soome { "swap", V_SWAP }, 684188fb37SToomas Soome { "usr", V_USR }, 694188fb37SToomas Soome { "backup", V_BACKUP }, 704188fb37SToomas Soome { "stand", V_STAND }, 714188fb37SToomas Soome { "var", V_VAR }, 724188fb37SToomas Soome { "home", V_HOME }, 734188fb37SToomas Soome { "alternates", V_ALTSCTR }, 744188fb37SToomas Soome { "reserved", V_RESERVED }, 754188fb37SToomas Soome { "system", V_SYSTEM }, 764188fb37SToomas Soome { "BIOS_boot", V_BIOS_BOOT }, 774188fb37SToomas Soome { "FreeBSD boot", V_FREEBSD_BOOT }, 784188fb37SToomas Soome { "FreeBSD swap", V_FREEBSD_SWAP }, 794188fb37SToomas Soome { "FreeBSD UFS", V_FREEBSD_UFS }, 804188fb37SToomas Soome { "FreeBSD ZFS", V_FREEBSD_ZFS }, 814188fb37SToomas Soome { "FreeBSD NANDFS", V_FREEBSD_NANDFS }, 824188fb37SToomas Soome 834188fb37SToomas Soome { NULL } 844188fb37SToomas Soome }; 854188fb37SToomas Soome 864188fb37SToomas Soome stringval_t pflag_array[] = { 874188fb37SToomas Soome { "wm", 0 }, 884188fb37SToomas Soome { "wu", V_UNMNT }, 894188fb37SToomas Soome { "rm", V_RONLY }, 904188fb37SToomas Soome { "ru", V_RONLY | V_UNMNT }, 914188fb37SToomas Soome { NULL } 924188fb37SToomas Soome }; 934188fb37SToomas Soome 94*fed69270SToomas Soome size_t sector_size = SECTOR_SIZE; 95*fed69270SToomas Soome 964188fb37SToomas Soome static const char * 974188fb37SToomas Soome array_find_string(stringval_t *array, int match_value) 984188fb37SToomas Soome { 994188fb37SToomas Soome for (; array->sv_text != NULL; array++) { 1004188fb37SToomas Soome if (array->sv_value == match_value) { 1014188fb37SToomas Soome return (array->sv_text); 1024188fb37SToomas Soome } 1034188fb37SToomas Soome } 1044188fb37SToomas Soome 1054188fb37SToomas Soome return (NULL); 1064188fb37SToomas Soome } 1074188fb37SToomas Soome 1084188fb37SToomas Soome static int 1094188fb37SToomas Soome array_widest_str(stringval_t *array) 1104188fb37SToomas Soome { 1114188fb37SToomas Soome int i; 1124188fb37SToomas Soome int width; 1134188fb37SToomas Soome 1144188fb37SToomas Soome width = 0; 1154188fb37SToomas Soome for (; array->sv_text != NULL; array++) { 1164188fb37SToomas Soome if ((i = strlen(array->sv_text)) > width) 1174188fb37SToomas Soome width = i; 1184188fb37SToomas Soome } 1194188fb37SToomas Soome 1204188fb37SToomas Soome return (width); 1214188fb37SToomas Soome } 1224188fb37SToomas Soome 123446c407dSJohn Levon static void 124446c407dSJohn Levon print_fdisk_part(struct ipart *ip, size_t nr) 125446c407dSJohn Levon { 126446c407dSJohn Levon char typestr[128]; 127446c407dSJohn Levon char begchs[128]; 128446c407dSJohn Levon char endchs[128]; 129446c407dSJohn Levon char *c = NULL; 130446c407dSJohn Levon 131446c407dSJohn Levon if (ip->systid == UNUSED) { 132446c407dSJohn Levon mdb_printf("%-4llu %s:%#lx\n", nr, "UNUSED", ip->systid); 133446c407dSJohn Levon return; 134446c407dSJohn Levon } 135446c407dSJohn Levon 136446c407dSJohn Levon switch (ip->systid) { 137446c407dSJohn Levon case DOSOS12: c = "DOSOS12"; break; 138446c407dSJohn Levon case PCIXOS: c = "PCIXOS"; break; 139446c407dSJohn Levon case DOSOS16: c = "DOSOS16"; break; 140446c407dSJohn Levon case EXTDOS: c = "EXTDOS"; break; 141446c407dSJohn Levon case DOSHUGE: c = "DOSHUGE"; break; 142446c407dSJohn Levon case FDISK_IFS: c = "FDISK_IFS"; break; 143446c407dSJohn Levon case FDISK_AIXBOOT: c = "FDISK_AIXBOOT"; break; 144446c407dSJohn Levon case FDISK_AIXDATA: c = "FDISK_AIXDATA"; break; 145446c407dSJohn Levon case FDISK_OS2BOOT: c = "FDISK_OS2BOOT"; break; 146446c407dSJohn Levon case FDISK_WINDOWS: c = "FDISK_WINDOWS"; break; 147446c407dSJohn Levon case FDISK_EXT_WIN: c = "FDISK_EXT_WIN"; break; 148446c407dSJohn Levon case FDISK_FAT95: c = "FDISK_FAT95"; break; 149446c407dSJohn Levon case FDISK_EXTLBA: c = "FDISK_EXTLBA"; break; 150446c407dSJohn Levon case DIAGPART: c = "DIAGPART"; break; 151446c407dSJohn Levon case FDISK_LINUX: c = "FDISK_LINUX"; break; 152446c407dSJohn Levon case FDISK_LINUXDSWAP: c = "FDISK_LINUXDSWAP"; break; 153446c407dSJohn Levon case FDISK_LINUXDNAT: c = "FDISK_LINUXDNAT"; break; 154446c407dSJohn Levon case FDISK_CPM: c = "FDISK_CPM"; break; 155446c407dSJohn Levon case DOSDATA: c = "DOSDATA"; break; 156446c407dSJohn Levon case OTHEROS: c = "OTHEROS"; break; 157446c407dSJohn Levon case UNIXOS: c = "UNIXOS"; break; 158446c407dSJohn Levon case FDISK_NOVELL2: c = "FDISK_NOVELL2"; break; 159446c407dSJohn Levon case FDISK_NOVELL3: c = "FDISK_NOVELL3"; break; 160446c407dSJohn Levon case FDISK_QNX4: c = "FDISK_QNX4"; break; 161446c407dSJohn Levon case FDISK_QNX42: c = "FDISK_QNX42"; break; 162446c407dSJohn Levon case FDISK_QNX43: c = "FDISK_QNX43"; break; 163446c407dSJohn Levon case SUNIXOS: c = "SUNIXOS"; break; 164446c407dSJohn Levon case FDISK_LINUXNAT: c = "FDISK_LINUXNAT"; break; 165446c407dSJohn Levon case FDISK_NTFSVOL1: c = "FDISK_NTFSVOL1"; break; 166446c407dSJohn Levon case FDISK_NTFSVOL2: c = "FDISK_NTFSVOL2"; break; 167446c407dSJohn Levon case FDISK_BSD: c = "FDISK_BSD"; break; 168446c407dSJohn Levon case FDISK_NEXTSTEP: c = "FDISK_NEXTSTEP"; break; 169446c407dSJohn Levon case FDISK_BSDIFS: c = "FDISK_BSDIFS"; break; 170446c407dSJohn Levon case FDISK_BSDISWAP: c = "FDISK_BSDISWAP"; break; 171446c407dSJohn Levon case X86BOOT: c = "X86BOOT"; break; 172446c407dSJohn Levon case SUNIXOS2: c = "SUNIXOS2"; break; 173446c407dSJohn Levon case EFI_PMBR: c = "EFI_PMBR"; break; 174446c407dSJohn Levon case EFI_FS: c = "EFI_FS"; break; 175446c407dSJohn Levon default: c = NULL; break; 176446c407dSJohn Levon } 177446c407dSJohn Levon 178446c407dSJohn Levon if (c != NULL) { 179446c407dSJohn Levon mdb_snprintf(typestr, sizeof (typestr), "%s:%#lx", 180446c407dSJohn Levon c, ip->systid); 181446c407dSJohn Levon } else { 182446c407dSJohn Levon mdb_snprintf(typestr, sizeof (typestr), "%#lx", ip->systid); 183446c407dSJohn Levon } 184446c407dSJohn Levon 185446c407dSJohn Levon mdb_snprintf(begchs, sizeof (begchs), "%hu/%hu/%hu", 186446c407dSJohn Levon (uint16_t)ip->begcyl | (uint16_t)(ip->begsect & ~0x3f) << 2, 187446c407dSJohn Levon (uint16_t)ip->beghead, (uint16_t)ip->begsect & 0x3f); 188446c407dSJohn Levon mdb_snprintf(endchs, sizeof (endchs), "%hu/%hu/%hu", 189446c407dSJohn Levon (uint16_t)ip->endcyl | (uint16_t)(ip->endsect & ~0x3f) << 2, 190446c407dSJohn Levon (uint16_t)ip->endhead, (uint16_t)ip->endsect & 0x3f); 191446c407dSJohn Levon 192446c407dSJohn Levon mdb_printf("%-4llu %-21s %#-7x %-11s %-11s %-10u %-9u\n", 193446c407dSJohn Levon nr, typestr, ip->bootid, begchs, endchs, ip->relsect, ip->numsect); 194446c407dSJohn Levon } 195446c407dSJohn Levon 1964188fb37SToomas Soome static mbr_type_t 1974188fb37SToomas Soome mbr_info(struct mboot *mbr) 198446c407dSJohn Levon { 199446c407dSJohn Levon mbr_type_t type = MBR_TYPE_UNKNOWN; 200446c407dSJohn Levon 2014188fb37SToomas Soome if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 202446c407dSJohn Levon type = MBR_TYPE_GRUB1; 2034188fb37SToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 204446c407dSJohn Levon type = MBR_TYPE_LOADER; 2054188fb37SToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 206446c407dSJohn Levon type = MBR_TYPE_LOADER_JOYENT; 207446c407dSJohn Levon } 208446c407dSJohn Levon 209446c407dSJohn Levon switch (type) { 210446c407dSJohn Levon case MBR_TYPE_UNKNOWN: 211446c407dSJohn Levon mdb_printf("Format: unknown\n"); 212446c407dSJohn Levon break; 213446c407dSJohn Levon case MBR_TYPE_GRUB1: 214446c407dSJohn Levon mdb_printf("Format: grub1\n"); 215446c407dSJohn Levon break; 216446c407dSJohn Levon case MBR_TYPE_LOADER: 217446c407dSJohn Levon mdb_printf("Format: loader (illumos)\n"); 218446c407dSJohn Levon break; 219446c407dSJohn Levon case MBR_TYPE_LOADER_JOYENT: 220446c407dSJohn Levon mdb_printf("Format: loader (joyent)\n"); 221446c407dSJohn Levon break; 222446c407dSJohn Levon } 223446c407dSJohn Levon 2244188fb37SToomas Soome mdb_printf("Signature: 0x%hx (%s)\n", mbr->signature, 2254188fb37SToomas Soome mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 226446c407dSJohn Levon 227446c407dSJohn Levon mdb_printf("UniqueMBRDiskSignature: %#lx\n", 2284188fb37SToomas Soome *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 229446c407dSJohn Levon 230446c407dSJohn Levon if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 231446c407dSJohn Levon char uuid[UUID_PRINTABLE_STRING_LENGTH]; 232446c407dSJohn Levon 233446c407dSJohn Levon mdb_printf("Loader STAGE1_STAGE2_LBA: %llu\n", 2344188fb37SToomas Soome *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 235446c407dSJohn Levon 236446c407dSJohn Levon mdb_printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 2374188fb37SToomas Soome *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 238446c407dSJohn Levon 2394188fb37SToomas Soome uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 240446c407dSJohn Levon uuid); 241446c407dSJohn Levon 242446c407dSJohn Levon mdb_printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 243446c407dSJohn Levon } 244446c407dSJohn Levon 2454188fb37SToomas Soome return (type); 2464188fb37SToomas Soome } 2474188fb37SToomas Soome 2484188fb37SToomas Soome static int 2494188fb37SToomas Soome cmd_mbr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) 2504188fb37SToomas Soome { 251*fed69270SToomas Soome struct mboot *mbr; 2524188fb37SToomas Soome mbr_type_t type; 2534188fb37SToomas Soome 254*fed69270SToomas Soome CTASSERT(sizeof (*mbr) == SECTOR_SIZE); 2554188fb37SToomas Soome 2564188fb37SToomas Soome if (argc != 0) 2574188fb37SToomas Soome return (DCMD_USAGE); 2584188fb37SToomas Soome 2594188fb37SToomas Soome if (!(flags & DCMD_ADDRSPEC)) 2604188fb37SToomas Soome addr = 0; 2614188fb37SToomas Soome 262*fed69270SToomas Soome mbr = mdb_zalloc(sector_size, UM_SLEEP | UM_GC); 263*fed69270SToomas Soome 264*fed69270SToomas Soome if (mdb_vread(mbr, sector_size, addr) == -1) { 2654188fb37SToomas Soome mdb_warn("failed to read MBR"); 2664188fb37SToomas Soome return (DCMD_ERR); 2674188fb37SToomas Soome } 2684188fb37SToomas Soome 269*fed69270SToomas Soome type = mbr_info(mbr); 2704188fb37SToomas Soome 2714188fb37SToomas Soome /* If the magic is wrong, stop here. */ 272*fed69270SToomas Soome if (mbr->signature != MBB_MAGIC) 2734188fb37SToomas Soome return (DCMD_ERR); 2744188fb37SToomas Soome 2754188fb37SToomas Soome /* Also print volume boot record */ 2764188fb37SToomas Soome switch (type) { 2774188fb37SToomas Soome case MBR_TYPE_LOADER: 2784188fb37SToomas Soome case MBR_TYPE_LOADER_JOYENT: 279*fed69270SToomas Soome if (*(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE] == 1) { 2804188fb37SToomas Soome struct mboot vbr; 2814188fb37SToomas Soome uintptr_t vbrp; 2824188fb37SToomas Soome 283*fed69270SToomas Soome vbrp = *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]; 284*fed69270SToomas Soome vbrp *= sector_size; 2854188fb37SToomas Soome vbrp += addr; 2864188fb37SToomas Soome if (mdb_vread(&vbr, sizeof (vbr), vbrp) == -1) { 2874188fb37SToomas Soome mdb_warn("failed to read VBR"); 2884188fb37SToomas Soome } else { 2894188fb37SToomas Soome mdb_printf("\nSTAGE1 in VBR:\n"); 2904188fb37SToomas Soome (void) mbr_info(&vbr); 2914188fb37SToomas Soome } 2924188fb37SToomas Soome } 2934188fb37SToomas Soome break; 2944188fb37SToomas Soome default: 2954188fb37SToomas Soome break; 2964188fb37SToomas Soome } 2974188fb37SToomas Soome 298446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-21s %-7s %-11s %-11s %-10s %-9s%</u>\n", 299446c407dSJohn Levon "PART", "TYPE", "ACTIVE", "STARTCHS", "ENDCHS", 300446c407dSJohn Levon "SECTOR", "NUMSECT"); 301446c407dSJohn Levon 302446c407dSJohn Levon for (size_t i = 0; i < FD_NUMPART; i++) { 303446c407dSJohn Levon struct ipart *ip = (struct ipart *) 304*fed69270SToomas Soome (mbr->parts + (sizeof (struct ipart) * i)); 305446c407dSJohn Levon print_fdisk_part(ip, i); 306446c407dSJohn Levon } 307446c407dSJohn Levon 308446c407dSJohn Levon return (DCMD_OK); 309446c407dSJohn Levon } 310446c407dSJohn Levon 311446c407dSJohn Levon static unsigned int crc32_tab[] = { CRC32_TABLE }; 312446c407dSJohn Levon 313446c407dSJohn Levon static unsigned int 314446c407dSJohn Levon efi_crc32(const unsigned char *s, unsigned int len) 315446c407dSJohn Levon { 316446c407dSJohn Levon unsigned int crc32val; 317446c407dSJohn Levon 318446c407dSJohn Levon CRC32(crc32val, s, len, -1U, crc32_tab); 319446c407dSJohn Levon 320446c407dSJohn Levon return (crc32val ^ -1U); 321446c407dSJohn Levon } 322446c407dSJohn Levon 323446c407dSJohn Levon typedef struct { 324446c407dSJohn Levon struct uuid eg_uuid; 325446c407dSJohn Levon const char *eg_name; 326446c407dSJohn Levon } efi_guid_t; 327446c407dSJohn Levon 328446c407dSJohn Levon static efi_guid_t efi_guids[] = { 329446c407dSJohn Levon { EFI_UNUSED, "EFI_UNUSED" }, 330446c407dSJohn Levon { EFI_RESV1, "EFI_RESV1" }, 331446c407dSJohn Levon { EFI_BOOT, "EFI_BOOT" }, 332446c407dSJohn Levon { EFI_ROOT, "EFI_ROOT" }, 333446c407dSJohn Levon { EFI_SWAP, "EFI_SWAP" }, 334446c407dSJohn Levon { EFI_USR, "EFI_USR" }, 335446c407dSJohn Levon { EFI_BACKUP, "EFI_BACKUP" }, 336446c407dSJohn Levon { EFI_RESV2, "EFI_RESV2" }, 337446c407dSJohn Levon { EFI_VAR, "EFI_VAR" }, 338446c407dSJohn Levon { EFI_HOME, "EFI_HOME" }, 339446c407dSJohn Levon { EFI_ALTSCTR, "EFI_ALTSCTR" }, 340446c407dSJohn Levon { EFI_RESERVED, "EFI_RESERVED" }, 341446c407dSJohn Levon { EFI_SYSTEM, "EFI_SYSTEM" }, 342446c407dSJohn Levon { EFI_LEGACY_MBR, "EFI_LEGACY_MBR" }, 343446c407dSJohn Levon { EFI_SYMC_PUB, "EFI_SYMC_PUB" }, 344446c407dSJohn Levon { EFI_SYMC_CDS, "EFI_SYMC_CDS" }, 345446c407dSJohn Levon { EFI_MSFT_RESV, "EFI_MSFT_RESV" }, 346446c407dSJohn Levon { EFI_DELL_BASIC, "EFI_DELL_BASIC" }, 347446c407dSJohn Levon { EFI_DELL_RAID, "EFI_DELL_RAID" }, 348446c407dSJohn Levon { EFI_DELL_SWAP, "EFI_DELL_SWAP" }, 349446c407dSJohn Levon { EFI_DELL_LVM, "EFI_DELL_LVM" }, 350446c407dSJohn Levon { EFI_DELL_RESV, "EFI_DELL_RESV" }, 351446c407dSJohn Levon { EFI_AAPL_BOOT, "EFI_AAPL_BOOT" }, 352446c407dSJohn Levon { EFI_AAPL_HFS, "EFI_AAPL_HFS" }, 353446c407dSJohn Levon { EFI_AAPL_UFS, "EFI_AAPL_UFS" }, 354446c407dSJohn Levon { EFI_AAPL_ZFS, "EFI_AAPL_ZFS" }, 355446c407dSJohn Levon { EFI_AAPL_APFS, "EFI_AAPL_APFS" }, 356446c407dSJohn Levon { EFI_FREEBSD_BOOT, "EFI_FREEBSD_BOOT" }, 357446c407dSJohn Levon { EFI_FREEBSD_NANDFS, "EFI_FREEBSD_NANDFS" }, 358446c407dSJohn Levon { EFI_FREEBSD_SWAP, "EFI_FREEBSD_SWAP" }, 359446c407dSJohn Levon { EFI_FREEBSD_UFS, "EFI_FREEBSD_UFS" }, 360446c407dSJohn Levon { EFI_FREEBSD_VINUM, "EFI_FREEBSD_VINUM" }, 361446c407dSJohn Levon { EFI_FREEBSD_ZFS, "EFI_FREEBSD_ZFS" }, 362446c407dSJohn Levon { EFI_BIOS_BOOT, "EFI_BIOS_BOOT" }, 363446c407dSJohn Levon }; 364446c407dSJohn Levon 365446c407dSJohn Levon static void 366446c407dSJohn Levon print_gpe(efi_gpe_t *gpe, size_t nr, int show_guid) 367446c407dSJohn Levon { 368446c407dSJohn Levon const char *type = "unknown"; 369446c407dSJohn Levon 370446c407dSJohn Levon for (size_t i = 0; i < ARRAY_SIZE(efi_guids); i++) { 371446c407dSJohn Levon if (memcmp((void *)&efi_guids[i].eg_uuid, 372446c407dSJohn Levon (void *)&gpe->efi_gpe_PartitionTypeGUID, 373446c407dSJohn Levon sizeof (efi_guids[i].eg_uuid)) == 0) { 374446c407dSJohn Levon type = efi_guids[i].eg_name; 375446c407dSJohn Levon break; 376446c407dSJohn Levon } 377446c407dSJohn Levon } 378446c407dSJohn Levon 379446c407dSJohn Levon if (strcmp(type, "EFI_UNUSED") == 0) { 380446c407dSJohn Levon mdb_printf("%-4u %-19s\n", nr, type); 381446c407dSJohn Levon return; 382446c407dSJohn Levon } 383446c407dSJohn Levon 384446c407dSJohn Levon if (show_guid) { 385446c407dSJohn Levon char guid[UUID_PRINTABLE_STRING_LENGTH]; 386446c407dSJohn Levon 387446c407dSJohn Levon uuid_unparse((uchar_t *)&gpe->efi_gpe_UniquePartitionGUID, 388446c407dSJohn Levon guid); 389446c407dSJohn Levon 390446c407dSJohn Levon mdb_printf("%-4u %-19s %s\n", nr, type, guid); 391446c407dSJohn Levon } else { 392446c407dSJohn Levon char name[EFI_PART_NAME_LEN + 1] = ""; 393446c407dSJohn Levon 394446c407dSJohn Levon /* 395446c407dSJohn Levon * Hopefully, ASCII is sufficient for any naming we care about. 396446c407dSJohn Levon */ 397446c407dSJohn Levon for (size_t i = 0; i < sizeof (name); i++) { 398446c407dSJohn Levon ushort_t wchar = gpe->efi_gpe_PartitionName[i]; 399446c407dSJohn Levon 400446c407dSJohn Levon name[i] = (char)(isascii(wchar) ? wchar : '?'); 401446c407dSJohn Levon } 402446c407dSJohn Levon 403446c407dSJohn Levon mdb_printf("%-4u %-19s %-13llu %-13llu %#-8llx %s\n", 404446c407dSJohn Levon nr, type, gpe->efi_gpe_StartingLBA, gpe->efi_gpe_EndingLBA, 405446c407dSJohn Levon gpe->efi_gpe_Attributes, name); 406446c407dSJohn Levon } 407446c407dSJohn Levon } 408446c407dSJohn Levon 409446c407dSJohn Levon static int 410446c407dSJohn Levon cmd_gpt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) 411446c407dSJohn Levon { 412446c407dSJohn Levon char uuid[UUID_PRINTABLE_STRING_LENGTH]; 413446c407dSJohn Levon int show_alternate = B_FALSE; 414446c407dSJohn Levon int show_guid = B_FALSE; 415*fed69270SToomas Soome efi_gpt_t *altheader; 416446c407dSJohn Levon size_t table_size; 417*fed69270SToomas Soome efi_gpt_t *header; 418446c407dSJohn Levon efi_gpe_t *gpet; 419446c407dSJohn Levon uint_t orig_crc; 420446c407dSJohn Levon uint_t crc; 421446c407dSJohn Levon 422446c407dSJohn Levon if (mdb_getopts(argc, argv, 423446c407dSJohn Levon 'a', MDB_OPT_SETBITS, TRUE, &show_alternate, 424446c407dSJohn Levon 'g', MDB_OPT_SETBITS, TRUE, &show_guid, 425446c407dSJohn Levon NULL) != argc) 426446c407dSJohn Levon return (DCMD_USAGE); 427446c407dSJohn Levon 428446c407dSJohn Levon /* Primary header is at LBA 1. */ 429446c407dSJohn Levon if (!(flags & DCMD_ADDRSPEC)) 430*fed69270SToomas Soome addr = sector_size; 431446c407dSJohn Levon 432*fed69270SToomas Soome header = mdb_zalloc(sector_size, UM_SLEEP | UM_GC); 433*fed69270SToomas Soome if (mdb_vread(header, sector_size, addr) == -1) { 434446c407dSJohn Levon mdb_warn("failed to read GPT header"); 435446c407dSJohn Levon return (DCMD_ERR); 436446c407dSJohn Levon } 437446c407dSJohn Levon 438446c407dSJohn Levon if (show_alternate) { 439*fed69270SToomas Soome addr = header->efi_gpt_AlternateLBA * sector_size; 440446c407dSJohn Levon 441*fed69270SToomas Soome if (mdb_vread(header, sector_size, addr) == -1) { 442446c407dSJohn Levon mdb_warn("failed to read GPT header"); 443446c407dSJohn Levon return (DCMD_ERR); 444446c407dSJohn Levon } 445446c407dSJohn Levon } 446446c407dSJohn Levon 447*fed69270SToomas Soome mdb_printf("Signature: %s (%s)\n", (char *)&header->efi_gpt_Signature, 448*fed69270SToomas Soome strncmp((char *)&header->efi_gpt_Signature, "EFI PART", 8) == 0 ? 449446c407dSJohn Levon "valid" : "invalid"); 450446c407dSJohn Levon 451*fed69270SToomas Soome mdb_printf("Revision: %hu.%hu\n", header->efi_gpt_Revision >> 16, 452*fed69270SToomas Soome header->efi_gpt_Revision); 453446c407dSJohn Levon 454*fed69270SToomas Soome mdb_printf("HeaderSize: %u bytes\n", header->efi_gpt_HeaderSize); 455446c407dSJohn Levon 456*fed69270SToomas Soome if (header->efi_gpt_HeaderSize > SECTOR_SIZE) { 457446c407dSJohn Levon mdb_warn("invalid header size: skipping CRC\n"); 458446c407dSJohn Levon } else { 459*fed69270SToomas Soome orig_crc = header->efi_gpt_HeaderCRC32; 460446c407dSJohn Levon 461*fed69270SToomas Soome header->efi_gpt_HeaderCRC32 = 0; 462446c407dSJohn Levon 463*fed69270SToomas Soome crc = efi_crc32((unsigned char *)header, 464*fed69270SToomas Soome header->efi_gpt_HeaderSize); 465446c407dSJohn Levon 466446c407dSJohn Levon mdb_printf("HeaderCRC32: %#x (should be %#x)\n", orig_crc, crc); 467446c407dSJohn Levon } 468446c407dSJohn Levon 469446c407dSJohn Levon mdb_printf("Reserved1: %#x (should be 0x0)\n", 470*fed69270SToomas Soome header->efi_gpt_Reserved1); 471446c407dSJohn Levon 472446c407dSJohn Levon mdb_printf("MyLBA: %llu (should be %llu)\n", 473*fed69270SToomas Soome header->efi_gpt_MyLBA, addr / sector_size); 474446c407dSJohn Levon 475*fed69270SToomas Soome mdb_printf("AlternateLBA: %llu\n", header->efi_gpt_AlternateLBA); 476*fed69270SToomas Soome mdb_printf("FirstUsableLBA: %llu\n", header->efi_gpt_FirstUsableLBA); 477*fed69270SToomas Soome mdb_printf("LastUsableLBA: %llu\n", header->efi_gpt_LastUsableLBA); 478446c407dSJohn Levon 479*fed69270SToomas Soome if (header->efi_gpt_MyLBA >= header->efi_gpt_FirstUsableLBA && 480*fed69270SToomas Soome header->efi_gpt_MyLBA <= header->efi_gpt_LastUsableLBA) { 481446c407dSJohn Levon mdb_warn("MyLBA is within usable LBA range\n"); 482446c407dSJohn Levon } 483446c407dSJohn Levon 484*fed69270SToomas Soome if (header->efi_gpt_AlternateLBA >= header->efi_gpt_FirstUsableLBA && 485*fed69270SToomas Soome header->efi_gpt_AlternateLBA <= header->efi_gpt_LastUsableLBA) { 486446c407dSJohn Levon mdb_warn("AlternateLBA is within usable LBA range\n"); 487446c407dSJohn Levon } 488446c407dSJohn Levon 489*fed69270SToomas Soome altheader = mdb_zalloc(sector_size, UM_SLEEP | UM_GC); 490*fed69270SToomas Soome if (mdb_vread(altheader, sector_size, 491*fed69270SToomas Soome header->efi_gpt_AlternateLBA * sector_size) == -1) { 492446c407dSJohn Levon mdb_warn("failed to read alternate GPT header"); 493446c407dSJohn Levon } else { 494*fed69270SToomas Soome if (strncmp((char *)&altheader->efi_gpt_Signature, 495446c407dSJohn Levon "EFI PART", 8) != 0) { 496446c407dSJohn Levon mdb_warn("found invalid alternate GPT header with " 497446c407dSJohn Levon "Signature: %s\n", 498*fed69270SToomas Soome (char *)&altheader->efi_gpt_Signature); 499446c407dSJohn Levon } 500446c407dSJohn Levon 501*fed69270SToomas Soome if (altheader->efi_gpt_MyLBA != header->efi_gpt_AlternateLBA) { 502446c407dSJohn Levon mdb_warn("alternate GPT header at offset %#llx has " 503446c407dSJohn Levon "invalid MyLBA %llu\n", 504*fed69270SToomas Soome header->efi_gpt_AlternateLBA * sector_size, 505*fed69270SToomas Soome altheader->efi_gpt_MyLBA); 506446c407dSJohn Levon } 507446c407dSJohn Levon 508*fed69270SToomas Soome if (altheader->efi_gpt_AlternateLBA != header->efi_gpt_MyLBA) { 509446c407dSJohn Levon mdb_warn("alternate GPT header at offset %#llx has " 510446c407dSJohn Levon "invalid AlternateLBA %llu\n", 511*fed69270SToomas Soome header->efi_gpt_AlternateLBA * sector_size, 512*fed69270SToomas Soome altheader->efi_gpt_AlternateLBA); 513446c407dSJohn Levon } 514446c407dSJohn Levon 515446c407dSJohn Levon /* 516446c407dSJohn Levon * We could go ahead and verify all the alternate checksums, 517446c407dSJohn Levon * etc. here too... 518446c407dSJohn Levon */ 519446c407dSJohn Levon } 520446c407dSJohn Levon 521*fed69270SToomas Soome uuid_unparse((uchar_t *)&header->efi_gpt_DiskGUID, uuid); 522446c407dSJohn Levon mdb_printf("DiskGUID: %s\n", uuid); 523446c407dSJohn Levon 524446c407dSJohn Levon mdb_printf("PartitionEntryLBA: %llu\n", 525*fed69270SToomas Soome header->efi_gpt_PartitionEntryLBA); 526446c407dSJohn Levon 527446c407dSJohn Levon mdb_printf("NumberOfPartitionEntries: %u\n", 528*fed69270SToomas Soome header->efi_gpt_NumberOfPartitionEntries); 529446c407dSJohn Levon 530446c407dSJohn Levon /* 531446c407dSJohn Levon * While the spec allows a different size, in practice the table 532446c407dSJohn Levon * is always packed. 533446c407dSJohn Levon */ 534*fed69270SToomas Soome if (header->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) { 535446c407dSJohn Levon mdb_warn("SizeOfPartitionEntry: %#x bytes " 536446c407dSJohn Levon "(expected %#x bytes)\n", 537*fed69270SToomas Soome header->efi_gpt_SizeOfPartitionEntry, sizeof (efi_gpe_t)); 538446c407dSJohn Levon return (DCMD_ERR); 539446c407dSJohn Levon } 540446c407dSJohn Levon 541446c407dSJohn Levon mdb_printf("SizeOfPartitionEntry: %#x bytes\n", 542*fed69270SToomas Soome header->efi_gpt_SizeOfPartitionEntry); 543446c407dSJohn Levon 544*fed69270SToomas Soome table_size = header->efi_gpt_SizeOfPartitionEntry * 545*fed69270SToomas Soome header->efi_gpt_NumberOfPartitionEntries; 546446c407dSJohn Levon 547446c407dSJohn Levon /* 548446c407dSJohn Levon * While this is a minimum reservation, it serves us ably as a 549446c407dSJohn Levon * maximum value to reasonably expect. 550446c407dSJohn Levon */ 551446c407dSJohn Levon if (table_size > EFI_MIN_ARRAY_SIZE) { 552446c407dSJohn Levon mdb_warn("Skipping GPT array of %#lx bytes.\n", table_size); 553446c407dSJohn Levon return (DCMD_ERR); 554446c407dSJohn Levon } 555446c407dSJohn Levon 556*fed69270SToomas Soome table_size = P2ROUNDUP(table_size, sector_size); 557*fed69270SToomas Soome gpet = mdb_alloc(table_size, UM_SLEEP | UM_GC); 558446c407dSJohn Levon 559446c407dSJohn Levon if (mdb_vread(gpet, table_size, 560*fed69270SToomas Soome header->efi_gpt_PartitionEntryLBA * sector_size) == -1) { 561446c407dSJohn Levon mdb_warn("couldn't read GPT array"); 562446c407dSJohn Levon return (DCMD_ERR); 563446c407dSJohn Levon } 564446c407dSJohn Levon 565446c407dSJohn Levon crc = efi_crc32((unsigned char *)gpet, table_size); 566446c407dSJohn Levon 567446c407dSJohn Levon mdb_printf("PartitionEntryArrayCRC32: %#x (should be %#x)\n", 568*fed69270SToomas Soome header->efi_gpt_PartitionEntryArrayCRC32, crc); 569446c407dSJohn Levon 570446c407dSJohn Levon if (show_guid) { 571446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-19s %-37s%</u>\n", 572446c407dSJohn Levon "PART", "TYPE", "GUID"); 573446c407dSJohn Levon } else { 574446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-19s %-13s %-13s %-8s %s%</u>\n", 575446c407dSJohn Levon "PART", "TYPE", "STARTLBA", "ENDLBA", "ATTR", "NAME"); 576446c407dSJohn Levon } 577446c407dSJohn Levon 578*fed69270SToomas Soome for (size_t i = 0; i < header->efi_gpt_NumberOfPartitionEntries; i++) 579446c407dSJohn Levon print_gpe(&gpet[i], i, show_guid); 580446c407dSJohn Levon 581446c407dSJohn Levon return (DCMD_OK); 582446c407dSJohn Levon } 583446c407dSJohn Levon 584446c407dSJohn Levon void 585446c407dSJohn Levon gpt_help(void) 586446c407dSJohn Levon { 587446c407dSJohn Levon mdb_printf("Display an EFI GUID Partition Table.\n\n" 588446c407dSJohn Levon "-a Display the alternate GPT\n" 589446c407dSJohn Levon "-g Show unique GUID for each table entry\n"); 590446c407dSJohn Levon } 591446c407dSJohn Levon 5924188fb37SToomas Soome static int 5934188fb37SToomas Soome cmd_vtoc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5944188fb37SToomas Soome { 595*fed69270SToomas Soome uint8_t *buf; 5964188fb37SToomas Soome struct dk_label *dl; 5974188fb37SToomas Soome struct dk_vtoc *dv; 5984188fb37SToomas Soome uintptr_t vaddr; 5994188fb37SToomas Soome int i, tag_width, cyl_width; 6004188fb37SToomas Soome int show_absolute = B_TRUE; 6014188fb37SToomas Soome int show_sectors = B_TRUE; 6024188fb37SToomas Soome uint32_t cyl; 6034188fb37SToomas Soome 6044188fb37SToomas Soome if (mdb_getopts(argc, argv, 6054188fb37SToomas Soome 'c', MDB_OPT_CLRBITS, TRUE, &show_sectors, 6064188fb37SToomas Soome 'r', MDB_OPT_CLRBITS, TRUE, &show_absolute, 6074188fb37SToomas Soome NULL) != argc) 6084188fb37SToomas Soome return (DCMD_USAGE); 6094188fb37SToomas Soome 6104188fb37SToomas Soome if (!(flags & DCMD_ADDRSPEC)) 6114188fb37SToomas Soome addr = 0; 6124188fb37SToomas Soome else 613*fed69270SToomas Soome addr *= sector_size; 614*fed69270SToomas Soome 615*fed69270SToomas Soome buf = mdb_zalloc(sector_size, UM_SLEEP | UM_GC); 6164188fb37SToomas Soome 6174188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 618*fed69270SToomas Soome if (mdb_vread(buf, sector_size, addr) == -1) { 6194188fb37SToomas Soome mdb_warn("failed to read VBR"); 6204188fb37SToomas Soome return (DCMD_ERR); 6214188fb37SToomas Soome } 6224188fb37SToomas Soome 6234188fb37SToomas Soome mdb_printf("VBR info:\n"); 6244188fb37SToomas Soome (void) mbr_info((struct mboot *)buf); 6254188fb37SToomas Soome #endif 6264188fb37SToomas Soome 627*fed69270SToomas Soome vaddr = addr + DK_LABEL_LOC * sector_size; 6284188fb37SToomas Soome 629*fed69270SToomas Soome if (mdb_vread(buf, sector_size, vaddr) == -1) { 6304188fb37SToomas Soome mdb_warn("failed to read VTOC"); 6314188fb37SToomas Soome return (DCMD_ERR); 6324188fb37SToomas Soome } 6334188fb37SToomas Soome 634*fed69270SToomas Soome dl = (struct dk_label *)buf; 6354188fb37SToomas Soome dv = (struct dk_vtoc *)&dl->dkl_vtoc; 6364188fb37SToomas Soome 6374188fb37SToomas Soome mdb_printf("Label magic: 0x%hx (%s)\n", dl->dkl_magic, 6384188fb37SToomas Soome dl->dkl_magic == DKL_MAGIC ? "valid" : "invalid"); 6394188fb37SToomas Soome if (dl->dkl_magic != DKL_MAGIC) 6404188fb37SToomas Soome return (DCMD_ERR); 6414188fb37SToomas Soome mdb_printf("Label %s sane\n", dv->v_sanity == VTOC_SANE ? 6424188fb37SToomas Soome "is" : "is not"); 6434188fb37SToomas Soome 6444188fb37SToomas Soome mdb_printf("Label version: %#x\n", dv->v_version); 6454188fb37SToomas Soome mdb_printf("Volume name = <%s>\n", dv->v_volume); 6464188fb37SToomas Soome mdb_printf("ASCII name = <%s>\n", dv->v_asciilabel); 6474188fb37SToomas Soome mdb_printf("pcyl = %4d\n", dl->dkl_pcyl); 6484188fb37SToomas Soome mdb_printf("ncyl = %4d\n", dl->dkl_ncyl); 6494188fb37SToomas Soome mdb_printf("acyl = %4d\n", dl->dkl_acyl); 6504188fb37SToomas Soome 6514188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 6524188fb37SToomas Soome mdb_printf("bcyl = %4d\n", dl->dkl_bcyl); 6534188fb37SToomas Soome #endif /* defined(_SUNOS_VTOC_16) */ 6544188fb37SToomas Soome 6554188fb37SToomas Soome mdb_printf("nhead = %4d\n", dl->dkl_nhead); 6564188fb37SToomas Soome mdb_printf("nsect = %4d\n", dl->dkl_nsect); 6574188fb37SToomas Soome 6584188fb37SToomas Soome 6594188fb37SToomas Soome if (!show_absolute) 6604188fb37SToomas Soome addr = 0; 6614188fb37SToomas Soome cyl = dl->dkl_nhead * dl->dkl_nsect; 6624188fb37SToomas Soome if (show_sectors) 6634188fb37SToomas Soome cyl = 1; 6644188fb37SToomas Soome else 665*fed69270SToomas Soome addr /= (cyl * sector_size); 6664188fb37SToomas Soome 6674188fb37SToomas Soome tag_width = array_widest_str(ptag_array); 6684188fb37SToomas Soome 6694188fb37SToomas Soome cyl_width = sizeof ("CYLINDERS"); 6704188fb37SToomas Soome for (i = 0; i < dv->v_nparts; i++) { 6714188fb37SToomas Soome uint32_t start, end, size; 6724188fb37SToomas Soome int w; 6734188fb37SToomas Soome 6744188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 6754188fb37SToomas Soome start = addr + (dv->v_part[i].p_start / cyl); 6764188fb37SToomas Soome size = dv->v_part[i].p_size; 6774188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8) 6784188fb37SToomas Soome start = dl->dkl_map[i].dkl_cylno; 6794188fb37SToomas Soome start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */ 6804188fb37SToomas Soome start /= cyl; 6814188fb37SToomas Soome start += addr; 6824188fb37SToomas Soome size = dl->dkl_map[i].dkl_nblk; 6834188fb37SToomas Soome #else 6844188fb37SToomas Soome #error "No VTOC format defined." 6854188fb37SToomas Soome #endif 6864188fb37SToomas Soome if (size == 0) 6874188fb37SToomas Soome end = start = 0; 6884188fb37SToomas Soome else 6894188fb37SToomas Soome end = start + size / cyl - 1; 6904188fb37SToomas Soome 6914188fb37SToomas Soome w = mdb_snprintf(NULL, 0, "%u - %u", start, end); 6924188fb37SToomas Soome if (w > cyl_width) 6934188fb37SToomas Soome cyl_width = w; 6944188fb37SToomas Soome } 6954188fb37SToomas Soome 6964188fb37SToomas Soome if (show_sectors == B_TRUE) { 6974188fb37SToomas Soome mdb_printf("\n%<u>%-4s %-*s %-7s %-11s %-11s %-*s " 6984188fb37SToomas Soome "%-10s%</u>\n", "PART", tag_width, "TAG", "FLAG", 6994188fb37SToomas Soome "STARTLBA", "ENDLBA", MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS"); 7004188fb37SToomas Soome } else { 7014188fb37SToomas Soome mdb_printf("\n%<u>%-4s %-*s %-7s %-*s %-*s %-10s%</u>\n", 7024188fb37SToomas Soome "PART", tag_width, "TAG", "FLAG", cyl_width, "CYLINDERS", 7034188fb37SToomas Soome MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS"); 7044188fb37SToomas Soome } 7054188fb37SToomas Soome 7064188fb37SToomas Soome for (i = 0; i < dv->v_nparts; i++) { 7074188fb37SToomas Soome uint16_t tag, flag; 7084188fb37SToomas Soome uint32_t start, end, size; 7094188fb37SToomas Soome const char *stag, *sflag; 7104188fb37SToomas Soome char nnum[MDB_NICENUM_BUFLEN]; 7114188fb37SToomas Soome 7124188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 7134188fb37SToomas Soome tag = dv->v_part[i].p_tag; 7144188fb37SToomas Soome flag = dv->v_part[i].p_flag; 7154188fb37SToomas Soome start = addr + (dv->v_part[i].p_start / cyl); 7164188fb37SToomas Soome size = dv->v_part[i].p_size; 7174188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8) 7184188fb37SToomas Soome tag = dv->v_part[i].p_tag; 7194188fb37SToomas Soome flag = dv->v_part[i].p_flag; 7204188fb37SToomas Soome start = dl->dkl_map[i].dkl_cylno; 7214188fb37SToomas Soome start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */ 7224188fb37SToomas Soome start /= cyl; 7234188fb37SToomas Soome start += addr; 7244188fb37SToomas Soome size = dl->dkl_map[i].dkl_nblk; 7254188fb37SToomas Soome #else 7264188fb37SToomas Soome #error "No VTOC format defined." 7274188fb37SToomas Soome #endif 7284188fb37SToomas Soome if (size == 0) 7294188fb37SToomas Soome end = start = 0; 7304188fb37SToomas Soome else 7314188fb37SToomas Soome end = start + size / cyl - 1; 7324188fb37SToomas Soome 7334188fb37SToomas Soome stag = array_find_string(ptag_array, tag); 7344188fb37SToomas Soome if (stag == NULL) 7354188fb37SToomas Soome stag = "?"; 7364188fb37SToomas Soome sflag = array_find_string(pflag_array, flag); 7374188fb37SToomas Soome if (sflag == NULL) 7384188fb37SToomas Soome sflag = "?"; 7394188fb37SToomas Soome 7404188fb37SToomas Soome mdb_printf("%-4d %-*s %-7s ", i, tag_width, stag, sflag); 741*fed69270SToomas Soome mdb_nicenum(size * sector_size, nnum); 7424188fb37SToomas Soome if (show_sectors) { 7434188fb37SToomas Soome mdb_printf("%-11u %-11u %-*s %-10u\n", start, end, 7444188fb37SToomas Soome MDB_NICENUM_BUFLEN, nnum, size); 7454188fb37SToomas Soome } else { 7464188fb37SToomas Soome char cyls[10 * 2 + 4]; 7474188fb37SToomas Soome 7484188fb37SToomas Soome if (size == 0) { 7494188fb37SToomas Soome mdb_snprintf(cyls, sizeof (cyls), "%-*u", 7504188fb37SToomas Soome cyl_width, size); 7514188fb37SToomas Soome } else { 7524188fb37SToomas Soome mdb_snprintf(cyls, sizeof (cyls), "%u - %u", 7534188fb37SToomas Soome start, end); 7544188fb37SToomas Soome } 7554188fb37SToomas Soome mdb_printf("%-*s %-*s %-10u\n", cyl_width, cyls, 7564188fb37SToomas Soome MDB_NICENUM_BUFLEN, nnum, size); 7574188fb37SToomas Soome } 7584188fb37SToomas Soome } 7594188fb37SToomas Soome 7604188fb37SToomas Soome return (DCMD_OK); 7614188fb37SToomas Soome } 7624188fb37SToomas Soome 7634188fb37SToomas Soome void 7644188fb37SToomas Soome vtoc_help(void) 7654188fb37SToomas Soome { 7664188fb37SToomas Soome mdb_printf("Display a Virtual Table of Content (VTOC).\n\n" 7674188fb37SToomas Soome "-r Display relative addresses\n" 7684188fb37SToomas Soome "-c Use cylinder based addressing\n"); 769*fed69270SToomas Soome mdb_printf("\nThe addr is in %u-byte disk blocks.\n", sector_size); 770*fed69270SToomas Soome } 771*fed69270SToomas Soome 772*fed69270SToomas Soome static int 773*fed69270SToomas Soome cmd_sect(uintptr_t addr __unused, uint_t flags __unused, int argc, 774*fed69270SToomas Soome const mdb_arg_t *argv) 775*fed69270SToomas Soome { 776*fed69270SToomas Soome uint64_t size = SECTOR_SIZE; 777*fed69270SToomas Soome 778*fed69270SToomas Soome if (argc < 1) { 779*fed69270SToomas Soome mdb_printf("Current sector size is %u (%#x)\n", sector_size, 780*fed69270SToomas Soome sector_size); 781*fed69270SToomas Soome return (DCMD_OK); 782*fed69270SToomas Soome } 783*fed69270SToomas Soome 784*fed69270SToomas Soome if (argc != 1) 785*fed69270SToomas Soome return (DCMD_USAGE); 786*fed69270SToomas Soome 787*fed69270SToomas Soome switch (argv[0].a_type) { 788*fed69270SToomas Soome case MDB_TYPE_STRING: 789*fed69270SToomas Soome size = mdb_strtoull(argv[0].a_un.a_str); 790*fed69270SToomas Soome break; 791*fed69270SToomas Soome case MDB_TYPE_IMMEDIATE: 792*fed69270SToomas Soome size = argv[0].a_un.a_val; 793*fed69270SToomas Soome break; 794*fed69270SToomas Soome default: 795*fed69270SToomas Soome return (DCMD_USAGE); 796*fed69270SToomas Soome } 797*fed69270SToomas Soome 798*fed69270SToomas Soome if (!ISP2(size)) { 799*fed69270SToomas Soome mdb_printf("sector size must be power of 2\n"); 800*fed69270SToomas Soome return (DCMD_USAGE); 801*fed69270SToomas Soome } 802*fed69270SToomas Soome sector_size = size; 803*fed69270SToomas Soome return (DCMD_OK); 804*fed69270SToomas Soome } 805*fed69270SToomas Soome 806*fed69270SToomas Soome void 807*fed69270SToomas Soome sect_help(void) 808*fed69270SToomas Soome { 809*fed69270SToomas Soome mdb_printf("Show or set sector size.\n"); 8104188fb37SToomas Soome } 8114188fb37SToomas Soome 812446c407dSJohn Levon static const mdb_dcmd_t dcmds[] = { 813446c407dSJohn Levon { "mbr", NULL, "dump Master Boot Record information", cmd_mbr }, 814446c407dSJohn Levon { "gpt", "?[-ag]", "dump an EFI GPT", cmd_gpt, gpt_help }, 8154188fb37SToomas Soome { "vtoc", "?[-cr]", "dump VTOC information", cmd_vtoc, vtoc_help }, 816*fed69270SToomas Soome { "sectorsize", NULL, "set or show sector size", cmd_sect, sect_help }, 817446c407dSJohn Levon { NULL } 818446c407dSJohn Levon }; 819446c407dSJohn Levon 820446c407dSJohn Levon static const mdb_modinfo_t modinfo = { 821446c407dSJohn Levon MDB_API_VERSION, dcmds, NULL 822446c407dSJohn Levon }; 823446c407dSJohn Levon 824446c407dSJohn Levon const mdb_modinfo_t * 825446c407dSJohn Levon _mdb_init(void) 826446c407dSJohn Levon { 827446c407dSJohn Levon return (&modinfo); 828446c407dSJohn Levon } 829