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 * We also currently assume a 512-byte sized logical block. 21446c407dSJohn Levon */ 22446c407dSJohn Levon 23446c407dSJohn Levon #include <sys/types.h> 24446c407dSJohn Levon #include <sys/crc32.h> 25446c407dSJohn Levon #include <sys/debug.h> 26446c407dSJohn Levon #include <sys/sysmacros.h> 27446c407dSJohn Levon #include <sys/dktp/fdisk.h> 28446c407dSJohn Levon #include <sys/efi_partition.h> 29*4188fb37SToomas Soome #include <sys/vtoc.h> 30446c407dSJohn Levon 31446c407dSJohn Levon #include <assert.h> 32446c407dSJohn Levon #include <ctype.h> 33446c407dSJohn Levon #include <uuid/uuid.h> 34446c407dSJohn Levon 35446c407dSJohn Levon #include <mdb/mdb_modapi.h> 36446c407dSJohn Levon #include <mdb/mdb_debug.h> 37446c407dSJohn Levon 38446c407dSJohn Levon #include "installboot.h" 39446c407dSJohn Levon 40446c407dSJohn Levon #ifdef _BIG_ENDIAN 41446c407dSJohn Levon #error needs porting for big-endian system 42446c407dSJohn Levon #endif 43446c407dSJohn Levon 44446c407dSJohn Levon /* See usr/src/grub/grub-0.97/stage1/stage1.h */ 45446c407dSJohn Levon #define GRUB_VERSION_OFF (0x3e) 46446c407dSJohn Levon #define GRUB_COMPAT_VERSION_MAJOR 3 47446c407dSJohn Levon #define GRUB_COMPAT_VERSION_MINOR 2 48446c407dSJohn Levon #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ 49446c407dSJohn Levon 50446c407dSJohn Levon #define LOADER_VERSION (1) 51446c407dSJohn Levon #define LOADER_JOYENT_VERSION (2) 52446c407dSJohn Levon 53446c407dSJohn Levon typedef enum { 54446c407dSJohn Levon MBR_TYPE_UNKNOWN, 55446c407dSJohn Levon MBR_TYPE_GRUB1, 56446c407dSJohn Levon MBR_TYPE_LOADER, 57446c407dSJohn Levon MBR_TYPE_LOADER_JOYENT, 58446c407dSJohn Levon } mbr_type_t; 59446c407dSJohn Levon 60*4188fb37SToomas Soome typedef struct stringval { 61*4188fb37SToomas Soome const char *sv_text; 62*4188fb37SToomas Soome int sv_value; 63*4188fb37SToomas Soome } stringval_t; 64*4188fb37SToomas Soome 65*4188fb37SToomas Soome stringval_t ptag_array[] = { 66*4188fb37SToomas Soome { "unassigned", V_UNASSIGNED }, 67*4188fb37SToomas Soome { "boot", V_BOOT }, 68*4188fb37SToomas Soome { "root", V_ROOT }, 69*4188fb37SToomas Soome { "swap", V_SWAP }, 70*4188fb37SToomas Soome { "usr", V_USR }, 71*4188fb37SToomas Soome { "backup", V_BACKUP }, 72*4188fb37SToomas Soome { "stand", V_STAND }, 73*4188fb37SToomas Soome { "var", V_VAR }, 74*4188fb37SToomas Soome { "home", V_HOME }, 75*4188fb37SToomas Soome { "alternates", V_ALTSCTR }, 76*4188fb37SToomas Soome { "reserved", V_RESERVED }, 77*4188fb37SToomas Soome { "system", V_SYSTEM }, 78*4188fb37SToomas Soome { "BIOS_boot", V_BIOS_BOOT }, 79*4188fb37SToomas Soome { "FreeBSD boot", V_FREEBSD_BOOT }, 80*4188fb37SToomas Soome { "FreeBSD swap", V_FREEBSD_SWAP }, 81*4188fb37SToomas Soome { "FreeBSD UFS", V_FREEBSD_UFS }, 82*4188fb37SToomas Soome { "FreeBSD ZFS", V_FREEBSD_ZFS }, 83*4188fb37SToomas Soome { "FreeBSD NANDFS", V_FREEBSD_NANDFS }, 84*4188fb37SToomas Soome 85*4188fb37SToomas Soome { NULL } 86*4188fb37SToomas Soome }; 87*4188fb37SToomas Soome 88*4188fb37SToomas Soome stringval_t pflag_array[] = { 89*4188fb37SToomas Soome { "wm", 0 }, 90*4188fb37SToomas Soome { "wu", V_UNMNT }, 91*4188fb37SToomas Soome { "rm", V_RONLY }, 92*4188fb37SToomas Soome { "ru", V_RONLY | V_UNMNT }, 93*4188fb37SToomas Soome { NULL } 94*4188fb37SToomas Soome }; 95*4188fb37SToomas Soome 96*4188fb37SToomas Soome static const char * 97*4188fb37SToomas Soome array_find_string(stringval_t *array, int match_value) 98*4188fb37SToomas Soome { 99*4188fb37SToomas Soome for (; array->sv_text != NULL; array++) { 100*4188fb37SToomas Soome if (array->sv_value == match_value) { 101*4188fb37SToomas Soome return (array->sv_text); 102*4188fb37SToomas Soome } 103*4188fb37SToomas Soome } 104*4188fb37SToomas Soome 105*4188fb37SToomas Soome return (NULL); 106*4188fb37SToomas Soome } 107*4188fb37SToomas Soome 108*4188fb37SToomas Soome static int 109*4188fb37SToomas Soome array_widest_str(stringval_t *array) 110*4188fb37SToomas Soome { 111*4188fb37SToomas Soome int i; 112*4188fb37SToomas Soome int width; 113*4188fb37SToomas Soome 114*4188fb37SToomas Soome width = 0; 115*4188fb37SToomas Soome for (; array->sv_text != NULL; array++) { 116*4188fb37SToomas Soome if ((i = strlen(array->sv_text)) > width) 117*4188fb37SToomas Soome width = i; 118*4188fb37SToomas Soome } 119*4188fb37SToomas Soome 120*4188fb37SToomas Soome return (width); 121*4188fb37SToomas Soome } 122*4188fb37SToomas 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 196*4188fb37SToomas Soome static mbr_type_t 197*4188fb37SToomas Soome mbr_info(struct mboot *mbr) 198446c407dSJohn Levon { 199446c407dSJohn Levon mbr_type_t type = MBR_TYPE_UNKNOWN; 200446c407dSJohn Levon 201*4188fb37SToomas Soome if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 202446c407dSJohn Levon type = MBR_TYPE_GRUB1; 203*4188fb37SToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 204446c407dSJohn Levon type = MBR_TYPE_LOADER; 205*4188fb37SToomas 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 224*4188fb37SToomas Soome mdb_printf("Signature: 0x%hx (%s)\n", mbr->signature, 225*4188fb37SToomas Soome mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 226446c407dSJohn Levon 227446c407dSJohn Levon mdb_printf("UniqueMBRDiskSignature: %#lx\n", 228*4188fb37SToomas 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", 234*4188fb37SToomas Soome *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 235446c407dSJohn Levon 236446c407dSJohn Levon mdb_printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 237*4188fb37SToomas Soome *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 238446c407dSJohn Levon 239*4188fb37SToomas 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 245*4188fb37SToomas Soome return (type); 246*4188fb37SToomas Soome } 247*4188fb37SToomas Soome 248*4188fb37SToomas Soome static int 249*4188fb37SToomas Soome cmd_mbr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) 250*4188fb37SToomas Soome { 251*4188fb37SToomas Soome struct mboot mbr; 252*4188fb37SToomas Soome mbr_type_t type; 253*4188fb37SToomas Soome 254*4188fb37SToomas Soome CTASSERT(sizeof (mbr) == SECTOR_SIZE); 255*4188fb37SToomas Soome 256*4188fb37SToomas Soome if (argc != 0) 257*4188fb37SToomas Soome return (DCMD_USAGE); 258*4188fb37SToomas Soome 259*4188fb37SToomas Soome if (!(flags & DCMD_ADDRSPEC)) 260*4188fb37SToomas Soome addr = 0; 261*4188fb37SToomas Soome 262*4188fb37SToomas Soome if (mdb_vread(&mbr, sizeof (mbr), addr) == -1) { 263*4188fb37SToomas Soome mdb_warn("failed to read MBR"); 264*4188fb37SToomas Soome return (DCMD_ERR); 265*4188fb37SToomas Soome } 266*4188fb37SToomas Soome 267*4188fb37SToomas Soome type = mbr_info(&mbr); 268*4188fb37SToomas Soome 269*4188fb37SToomas Soome /* If the magic is wrong, stop here. */ 270*4188fb37SToomas Soome if (mbr.signature != MBB_MAGIC) 271*4188fb37SToomas Soome return (DCMD_ERR); 272*4188fb37SToomas Soome 273*4188fb37SToomas Soome /* Also print volume boot record */ 274*4188fb37SToomas Soome switch (type) { 275*4188fb37SToomas Soome case MBR_TYPE_LOADER: 276*4188fb37SToomas Soome case MBR_TYPE_LOADER_JOYENT: 277*4188fb37SToomas Soome if (*(uint16_t *)&mbr.bootinst[STAGE1_STAGE2_SIZE] == 1) { 278*4188fb37SToomas Soome struct mboot vbr; 279*4188fb37SToomas Soome uintptr_t vbrp; 280*4188fb37SToomas Soome 281*4188fb37SToomas Soome vbrp = *(uint64_t *)&mbr.bootinst[STAGE1_STAGE2_LBA]; 282*4188fb37SToomas Soome vbrp *= SECTOR_SIZE; 283*4188fb37SToomas Soome vbrp += addr; 284*4188fb37SToomas Soome if (mdb_vread(&vbr, sizeof (vbr), vbrp) == -1) { 285*4188fb37SToomas Soome mdb_warn("failed to read VBR"); 286*4188fb37SToomas Soome } else { 287*4188fb37SToomas Soome mdb_printf("\nSTAGE1 in VBR:\n"); 288*4188fb37SToomas Soome (void) mbr_info(&vbr); 289*4188fb37SToomas Soome } 290*4188fb37SToomas Soome } 291*4188fb37SToomas Soome break; 292*4188fb37SToomas Soome default: 293*4188fb37SToomas Soome break; 294*4188fb37SToomas Soome } 295*4188fb37SToomas Soome 296446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-21s %-7s %-11s %-11s %-10s %-9s%</u>\n", 297446c407dSJohn Levon "PART", "TYPE", "ACTIVE", "STARTCHS", "ENDCHS", 298446c407dSJohn Levon "SECTOR", "NUMSECT"); 299446c407dSJohn Levon 300446c407dSJohn Levon for (size_t i = 0; i < FD_NUMPART; i++) { 301446c407dSJohn Levon struct ipart *ip = (struct ipart *) 302446c407dSJohn Levon (mbr.parts + (sizeof (struct ipart) * i)); 303446c407dSJohn Levon print_fdisk_part(ip, i); 304446c407dSJohn Levon } 305446c407dSJohn Levon 306446c407dSJohn Levon return (DCMD_OK); 307446c407dSJohn Levon } 308446c407dSJohn Levon 309446c407dSJohn Levon static unsigned int crc32_tab[] = { CRC32_TABLE }; 310446c407dSJohn Levon 311446c407dSJohn Levon static unsigned int 312446c407dSJohn Levon efi_crc32(const unsigned char *s, unsigned int len) 313446c407dSJohn Levon { 314446c407dSJohn Levon unsigned int crc32val; 315446c407dSJohn Levon 316446c407dSJohn Levon CRC32(crc32val, s, len, -1U, crc32_tab); 317446c407dSJohn Levon 318446c407dSJohn Levon return (crc32val ^ -1U); 319446c407dSJohn Levon } 320446c407dSJohn Levon 321446c407dSJohn Levon typedef struct { 322446c407dSJohn Levon struct uuid eg_uuid; 323446c407dSJohn Levon const char *eg_name; 324446c407dSJohn Levon } efi_guid_t; 325446c407dSJohn Levon 326446c407dSJohn Levon static efi_guid_t efi_guids[] = { 327446c407dSJohn Levon { EFI_UNUSED, "EFI_UNUSED" }, 328446c407dSJohn Levon { EFI_RESV1, "EFI_RESV1" }, 329446c407dSJohn Levon { EFI_BOOT, "EFI_BOOT" }, 330446c407dSJohn Levon { EFI_ROOT, "EFI_ROOT" }, 331446c407dSJohn Levon { EFI_SWAP, "EFI_SWAP" }, 332446c407dSJohn Levon { EFI_USR, "EFI_USR" }, 333446c407dSJohn Levon { EFI_BACKUP, "EFI_BACKUP" }, 334446c407dSJohn Levon { EFI_RESV2, "EFI_RESV2" }, 335446c407dSJohn Levon { EFI_VAR, "EFI_VAR" }, 336446c407dSJohn Levon { EFI_HOME, "EFI_HOME" }, 337446c407dSJohn Levon { EFI_ALTSCTR, "EFI_ALTSCTR" }, 338446c407dSJohn Levon { EFI_RESERVED, "EFI_RESERVED" }, 339446c407dSJohn Levon { EFI_SYSTEM, "EFI_SYSTEM" }, 340446c407dSJohn Levon { EFI_LEGACY_MBR, "EFI_LEGACY_MBR" }, 341446c407dSJohn Levon { EFI_SYMC_PUB, "EFI_SYMC_PUB" }, 342446c407dSJohn Levon { EFI_SYMC_CDS, "EFI_SYMC_CDS" }, 343446c407dSJohn Levon { EFI_MSFT_RESV, "EFI_MSFT_RESV" }, 344446c407dSJohn Levon { EFI_DELL_BASIC, "EFI_DELL_BASIC" }, 345446c407dSJohn Levon { EFI_DELL_RAID, "EFI_DELL_RAID" }, 346446c407dSJohn Levon { EFI_DELL_SWAP, "EFI_DELL_SWAP" }, 347446c407dSJohn Levon { EFI_DELL_LVM, "EFI_DELL_LVM" }, 348446c407dSJohn Levon { EFI_DELL_RESV, "EFI_DELL_RESV" }, 349446c407dSJohn Levon { EFI_AAPL_BOOT, "EFI_AAPL_BOOT" }, 350446c407dSJohn Levon { EFI_AAPL_HFS, "EFI_AAPL_HFS" }, 351446c407dSJohn Levon { EFI_AAPL_UFS, "EFI_AAPL_UFS" }, 352446c407dSJohn Levon { EFI_AAPL_ZFS, "EFI_AAPL_ZFS" }, 353446c407dSJohn Levon { EFI_AAPL_APFS, "EFI_AAPL_APFS" }, 354446c407dSJohn Levon { EFI_FREEBSD_BOOT, "EFI_FREEBSD_BOOT" }, 355446c407dSJohn Levon { EFI_FREEBSD_NANDFS, "EFI_FREEBSD_NANDFS" }, 356446c407dSJohn Levon { EFI_FREEBSD_SWAP, "EFI_FREEBSD_SWAP" }, 357446c407dSJohn Levon { EFI_FREEBSD_UFS, "EFI_FREEBSD_UFS" }, 358446c407dSJohn Levon { EFI_FREEBSD_VINUM, "EFI_FREEBSD_VINUM" }, 359446c407dSJohn Levon { EFI_FREEBSD_ZFS, "EFI_FREEBSD_ZFS" }, 360446c407dSJohn Levon { EFI_BIOS_BOOT, "EFI_BIOS_BOOT" }, 361446c407dSJohn Levon }; 362446c407dSJohn Levon 363446c407dSJohn Levon static void 364446c407dSJohn Levon print_gpe(efi_gpe_t *gpe, size_t nr, int show_guid) 365446c407dSJohn Levon { 366446c407dSJohn Levon const char *type = "unknown"; 367446c407dSJohn Levon 368446c407dSJohn Levon for (size_t i = 0; i < ARRAY_SIZE(efi_guids); i++) { 369446c407dSJohn Levon if (memcmp((void *)&efi_guids[i].eg_uuid, 370446c407dSJohn Levon (void *)&gpe->efi_gpe_PartitionTypeGUID, 371446c407dSJohn Levon sizeof (efi_guids[i].eg_uuid)) == 0) { 372446c407dSJohn Levon type = efi_guids[i].eg_name; 373446c407dSJohn Levon break; 374446c407dSJohn Levon } 375446c407dSJohn Levon } 376446c407dSJohn Levon 377446c407dSJohn Levon if (strcmp(type, "EFI_UNUSED") == 0) { 378446c407dSJohn Levon mdb_printf("%-4u %-19s\n", nr, type); 379446c407dSJohn Levon return; 380446c407dSJohn Levon } 381446c407dSJohn Levon 382446c407dSJohn Levon if (show_guid) { 383446c407dSJohn Levon char guid[UUID_PRINTABLE_STRING_LENGTH]; 384446c407dSJohn Levon 385446c407dSJohn Levon uuid_unparse((uchar_t *)&gpe->efi_gpe_UniquePartitionGUID, 386446c407dSJohn Levon guid); 387446c407dSJohn Levon 388446c407dSJohn Levon mdb_printf("%-4u %-19s %s\n", nr, type, guid); 389446c407dSJohn Levon } else { 390446c407dSJohn Levon char name[EFI_PART_NAME_LEN + 1] = ""; 391446c407dSJohn Levon 392446c407dSJohn Levon /* 393446c407dSJohn Levon * Hopefully, ASCII is sufficient for any naming we care about. 394446c407dSJohn Levon */ 395446c407dSJohn Levon for (size_t i = 0; i < sizeof (name); i++) { 396446c407dSJohn Levon ushort_t wchar = gpe->efi_gpe_PartitionName[i]; 397446c407dSJohn Levon 398446c407dSJohn Levon name[i] = (char)(isascii(wchar) ? wchar : '?'); 399446c407dSJohn Levon } 400446c407dSJohn Levon 401446c407dSJohn Levon mdb_printf("%-4u %-19s %-13llu %-13llu %#-8llx %s\n", 402446c407dSJohn Levon nr, type, gpe->efi_gpe_StartingLBA, gpe->efi_gpe_EndingLBA, 403446c407dSJohn Levon gpe->efi_gpe_Attributes, name); 404446c407dSJohn Levon } 405446c407dSJohn Levon } 406446c407dSJohn Levon 407446c407dSJohn Levon static int 408446c407dSJohn Levon cmd_gpt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused) 409446c407dSJohn Levon { 410446c407dSJohn Levon char uuid[UUID_PRINTABLE_STRING_LENGTH]; 411446c407dSJohn Levon int show_alternate = B_FALSE; 412446c407dSJohn Levon int show_guid = B_FALSE; 413446c407dSJohn Levon efi_gpt_t altheader; 414446c407dSJohn Levon size_t table_size; 415446c407dSJohn Levon efi_gpt_t header; 416446c407dSJohn Levon efi_gpe_t *gpet; 417446c407dSJohn Levon uint_t orig_crc; 418446c407dSJohn Levon uint_t crc; 419446c407dSJohn Levon 420446c407dSJohn Levon if (mdb_getopts(argc, argv, 421446c407dSJohn Levon 'a', MDB_OPT_SETBITS, TRUE, &show_alternate, 422446c407dSJohn Levon 'g', MDB_OPT_SETBITS, TRUE, &show_guid, 423446c407dSJohn Levon NULL) != argc) 424446c407dSJohn Levon return (DCMD_USAGE); 425446c407dSJohn Levon 426446c407dSJohn Levon /* Primary header is at LBA 1. */ 427446c407dSJohn Levon if (!(flags & DCMD_ADDRSPEC)) 428446c407dSJohn Levon addr = SECTOR_SIZE; 429446c407dSJohn Levon 430446c407dSJohn Levon if (mdb_vread(&header, sizeof (header), addr) == -1) { 431446c407dSJohn Levon mdb_warn("failed to read GPT header"); 432446c407dSJohn Levon return (DCMD_ERR); 433446c407dSJohn Levon } 434446c407dSJohn Levon 435446c407dSJohn Levon if (show_alternate) { 436446c407dSJohn Levon addr = header.efi_gpt_AlternateLBA * SECTOR_SIZE; 437446c407dSJohn Levon 438446c407dSJohn Levon if (mdb_vread(&header, sizeof (header), addr) == -1) { 439446c407dSJohn Levon mdb_warn("failed to read GPT header"); 440446c407dSJohn Levon return (DCMD_ERR); 441446c407dSJohn Levon } 442446c407dSJohn Levon } 443446c407dSJohn Levon 444446c407dSJohn Levon mdb_printf("Signature: %s (%s)\n", (char *)&header.efi_gpt_Signature, 445446c407dSJohn Levon strncmp((char *)&header.efi_gpt_Signature, "EFI PART", 8) == 0 ? 446446c407dSJohn Levon "valid" : "invalid"); 447446c407dSJohn Levon 448446c407dSJohn Levon mdb_printf("Revision: %hu.%hu\n", header.efi_gpt_Revision >> 16, 449446c407dSJohn Levon header.efi_gpt_Revision); 450446c407dSJohn Levon 451446c407dSJohn Levon mdb_printf("HeaderSize: %u bytes\n", header.efi_gpt_HeaderSize); 452446c407dSJohn Levon 453446c407dSJohn Levon if (header.efi_gpt_HeaderSize > SECTOR_SIZE) { 454446c407dSJohn Levon mdb_warn("invalid header size: skipping CRC\n"); 455446c407dSJohn Levon } else { 456446c407dSJohn Levon orig_crc = header.efi_gpt_HeaderCRC32; 457446c407dSJohn Levon 458446c407dSJohn Levon header.efi_gpt_HeaderCRC32 = 0; 459446c407dSJohn Levon 460446c407dSJohn Levon crc = efi_crc32((unsigned char *)&header, 461446c407dSJohn Levon header.efi_gpt_HeaderSize); 462446c407dSJohn Levon 463446c407dSJohn Levon mdb_printf("HeaderCRC32: %#x (should be %#x)\n", orig_crc, crc); 464446c407dSJohn Levon } 465446c407dSJohn Levon 466446c407dSJohn Levon mdb_printf("Reserved1: %#x (should be 0x0)\n", 467446c407dSJohn Levon header.efi_gpt_Reserved1); 468446c407dSJohn Levon 469446c407dSJohn Levon mdb_printf("MyLBA: %llu (should be %llu)\n", 470446c407dSJohn Levon header.efi_gpt_MyLBA, addr / SECTOR_SIZE); 471446c407dSJohn Levon 472446c407dSJohn Levon mdb_printf("AlternateLBA: %llu\n", header.efi_gpt_AlternateLBA); 473446c407dSJohn Levon mdb_printf("FirstUsableLBA: %llu\n", header.efi_gpt_FirstUsableLBA); 474446c407dSJohn Levon mdb_printf("LastUsableLBA: %llu\n", header.efi_gpt_LastUsableLBA); 475446c407dSJohn Levon 476446c407dSJohn Levon if (header.efi_gpt_MyLBA >= header.efi_gpt_FirstUsableLBA && 477446c407dSJohn Levon header.efi_gpt_MyLBA <= header.efi_gpt_LastUsableLBA) { 478446c407dSJohn Levon mdb_warn("MyLBA is within usable LBA range\n"); 479446c407dSJohn Levon } 480446c407dSJohn Levon 481446c407dSJohn Levon if (header.efi_gpt_AlternateLBA >= header.efi_gpt_FirstUsableLBA && 482446c407dSJohn Levon header.efi_gpt_AlternateLBA <= header.efi_gpt_LastUsableLBA) { 483446c407dSJohn Levon mdb_warn("AlternateLBA is within usable LBA range\n"); 484446c407dSJohn Levon } 485446c407dSJohn Levon 486446c407dSJohn Levon if (mdb_vread(&altheader, sizeof (altheader), 487446c407dSJohn Levon header.efi_gpt_AlternateLBA * SECTOR_SIZE) == -1) { 488446c407dSJohn Levon mdb_warn("failed to read alternate GPT header"); 489446c407dSJohn Levon } else { 490446c407dSJohn Levon if (strncmp((char *)&altheader.efi_gpt_Signature, 491446c407dSJohn Levon "EFI PART", 8) != 0) { 492446c407dSJohn Levon mdb_warn("found invalid alternate GPT header with " 493446c407dSJohn Levon "Signature: %s\n", 494446c407dSJohn Levon (char *)&altheader.efi_gpt_Signature); 495446c407dSJohn Levon } 496446c407dSJohn Levon 497446c407dSJohn Levon if (altheader.efi_gpt_MyLBA != header.efi_gpt_AlternateLBA) { 498446c407dSJohn Levon mdb_warn("alternate GPT header at offset %#llx has " 499446c407dSJohn Levon "invalid MyLBA %llu\n", 500446c407dSJohn Levon header.efi_gpt_AlternateLBA * SECTOR_SIZE, 501446c407dSJohn Levon altheader.efi_gpt_MyLBA); 502446c407dSJohn Levon } 503446c407dSJohn Levon 504446c407dSJohn Levon if (altheader.efi_gpt_AlternateLBA != header.efi_gpt_MyLBA) { 505446c407dSJohn Levon mdb_warn("alternate GPT header at offset %#llx has " 506446c407dSJohn Levon "invalid AlternateLBA %llu\n", 507446c407dSJohn Levon header.efi_gpt_AlternateLBA * SECTOR_SIZE, 508446c407dSJohn Levon altheader.efi_gpt_AlternateLBA); 509446c407dSJohn Levon } 510446c407dSJohn Levon 511446c407dSJohn Levon /* 512446c407dSJohn Levon * We could go ahead and verify all the alternate checksums, 513446c407dSJohn Levon * etc. here too... 514446c407dSJohn Levon */ 515446c407dSJohn Levon } 516446c407dSJohn Levon 517446c407dSJohn Levon uuid_unparse((uchar_t *)&header.efi_gpt_DiskGUID, uuid); 518446c407dSJohn Levon mdb_printf("DiskGUID: %s\n", uuid); 519446c407dSJohn Levon 520446c407dSJohn Levon mdb_printf("PartitionEntryLBA: %llu\n", 521446c407dSJohn Levon header.efi_gpt_PartitionEntryLBA); 522446c407dSJohn Levon 523446c407dSJohn Levon mdb_printf("NumberOfPartitionEntries: %u\n", 524446c407dSJohn Levon header.efi_gpt_NumberOfPartitionEntries); 525446c407dSJohn Levon 526446c407dSJohn Levon /* 527446c407dSJohn Levon * While the spec allows a different size, in practice the table 528446c407dSJohn Levon * is always packed. 529446c407dSJohn Levon */ 530446c407dSJohn Levon if (header.efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) { 531446c407dSJohn Levon mdb_warn("SizeOfPartitionEntry: %#x bytes " 532446c407dSJohn Levon "(expected %#x bytes)\n", 533446c407dSJohn Levon header.efi_gpt_SizeOfPartitionEntry, sizeof (efi_gpe_t)); 534446c407dSJohn Levon return (DCMD_ERR); 535446c407dSJohn Levon } 536446c407dSJohn Levon 537446c407dSJohn Levon mdb_printf("SizeOfPartitionEntry: %#x bytes\n", 538446c407dSJohn Levon header.efi_gpt_SizeOfPartitionEntry); 539446c407dSJohn Levon 540446c407dSJohn Levon table_size = header.efi_gpt_SizeOfPartitionEntry * 541446c407dSJohn Levon header.efi_gpt_NumberOfPartitionEntries; 542446c407dSJohn Levon 543446c407dSJohn Levon /* 544446c407dSJohn Levon * While this is a minimum reservation, it serves us ably as a 545446c407dSJohn Levon * maximum value to reasonably expect. 546446c407dSJohn Levon */ 547446c407dSJohn Levon if (table_size > EFI_MIN_ARRAY_SIZE) { 548446c407dSJohn Levon mdb_warn("Skipping GPT array of %#lx bytes.\n", table_size); 549446c407dSJohn Levon return (DCMD_ERR); 550446c407dSJohn Levon } 551446c407dSJohn Levon 552446c407dSJohn Levon gpet = mdb_alloc(header.efi_gpt_SizeOfPartitionEntry * 553446c407dSJohn Levon header.efi_gpt_NumberOfPartitionEntries, UM_SLEEP | UM_GC); 554446c407dSJohn Levon 555446c407dSJohn Levon if (mdb_vread(gpet, table_size, 556446c407dSJohn Levon header.efi_gpt_PartitionEntryLBA * SECTOR_SIZE) == -1) { 557446c407dSJohn Levon mdb_warn("couldn't read GPT array"); 558446c407dSJohn Levon return (DCMD_ERR); 559446c407dSJohn Levon } 560446c407dSJohn Levon 561446c407dSJohn Levon crc = efi_crc32((unsigned char *)gpet, table_size); 562446c407dSJohn Levon 563446c407dSJohn Levon mdb_printf("PartitionEntryArrayCRC32: %#x (should be %#x)\n", 564446c407dSJohn Levon header.efi_gpt_PartitionEntryArrayCRC32, crc); 565446c407dSJohn Levon 566446c407dSJohn Levon if (show_guid) { 567446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-19s %-37s%</u>\n", 568446c407dSJohn Levon "PART", "TYPE", "GUID"); 569446c407dSJohn Levon } else { 570446c407dSJohn Levon mdb_printf("\n%<u>%-4s %-19s %-13s %-13s %-8s %s%</u>\n", 571446c407dSJohn Levon "PART", "TYPE", "STARTLBA", "ENDLBA", "ATTR", "NAME"); 572446c407dSJohn Levon } 573446c407dSJohn Levon 574446c407dSJohn Levon for (size_t i = 0; i < header.efi_gpt_NumberOfPartitionEntries; i++) 575446c407dSJohn Levon print_gpe(&gpet[i], i, show_guid); 576446c407dSJohn Levon 577446c407dSJohn Levon return (DCMD_OK); 578446c407dSJohn Levon } 579446c407dSJohn Levon 580446c407dSJohn Levon void 581446c407dSJohn Levon gpt_help(void) 582446c407dSJohn Levon { 583446c407dSJohn Levon mdb_printf("Display an EFI GUID Partition Table.\n\n" 584446c407dSJohn Levon "-a Display the alternate GPT\n" 585446c407dSJohn Levon "-g Show unique GUID for each table entry\n"); 586446c407dSJohn Levon } 587446c407dSJohn Levon 588*4188fb37SToomas Soome static int 589*4188fb37SToomas Soome cmd_vtoc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 590*4188fb37SToomas Soome { 591*4188fb37SToomas Soome uint8_t buf[SECTOR_SIZE]; 592*4188fb37SToomas Soome struct dk_label *dl; 593*4188fb37SToomas Soome struct dk_vtoc *dv; 594*4188fb37SToomas Soome uintptr_t vaddr; 595*4188fb37SToomas Soome int i, tag_width, cyl_width; 596*4188fb37SToomas Soome int show_absolute = B_TRUE; 597*4188fb37SToomas Soome int show_sectors = B_TRUE; 598*4188fb37SToomas Soome uint32_t cyl; 599*4188fb37SToomas Soome 600*4188fb37SToomas Soome if (mdb_getopts(argc, argv, 601*4188fb37SToomas Soome 'c', MDB_OPT_CLRBITS, TRUE, &show_sectors, 602*4188fb37SToomas Soome 'r', MDB_OPT_CLRBITS, TRUE, &show_absolute, 603*4188fb37SToomas Soome NULL) != argc) 604*4188fb37SToomas Soome return (DCMD_USAGE); 605*4188fb37SToomas Soome 606*4188fb37SToomas Soome if (!(flags & DCMD_ADDRSPEC)) 607*4188fb37SToomas Soome addr = 0; 608*4188fb37SToomas Soome else 609*4188fb37SToomas Soome addr *= SECTOR_SIZE; 610*4188fb37SToomas Soome 611*4188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 612*4188fb37SToomas Soome if (mdb_vread(&buf, sizeof (buf), addr) == -1) { 613*4188fb37SToomas Soome mdb_warn("failed to read VBR"); 614*4188fb37SToomas Soome return (DCMD_ERR); 615*4188fb37SToomas Soome } 616*4188fb37SToomas Soome 617*4188fb37SToomas Soome mdb_printf("VBR info:\n"); 618*4188fb37SToomas Soome (void) mbr_info((struct mboot *)buf); 619*4188fb37SToomas Soome #endif 620*4188fb37SToomas Soome 621*4188fb37SToomas Soome vaddr = addr + DK_LABEL_LOC * SECTOR_SIZE; 622*4188fb37SToomas Soome 623*4188fb37SToomas Soome if (mdb_vread(&buf, sizeof (buf), vaddr) == -1) { 624*4188fb37SToomas Soome mdb_warn("failed to read VTOC"); 625*4188fb37SToomas Soome return (DCMD_ERR); 626*4188fb37SToomas Soome } 627*4188fb37SToomas Soome 628*4188fb37SToomas Soome dl = (struct dk_label *)&buf; 629*4188fb37SToomas Soome dv = (struct dk_vtoc *)&dl->dkl_vtoc; 630*4188fb37SToomas Soome 631*4188fb37SToomas Soome mdb_printf("Label magic: 0x%hx (%s)\n", dl->dkl_magic, 632*4188fb37SToomas Soome dl->dkl_magic == DKL_MAGIC ? "valid" : "invalid"); 633*4188fb37SToomas Soome if (dl->dkl_magic != DKL_MAGIC) 634*4188fb37SToomas Soome return (DCMD_ERR); 635*4188fb37SToomas Soome mdb_printf("Label %s sane\n", dv->v_sanity == VTOC_SANE ? 636*4188fb37SToomas Soome "is" : "is not"); 637*4188fb37SToomas Soome 638*4188fb37SToomas Soome mdb_printf("Label version: %#x\n", dv->v_version); 639*4188fb37SToomas Soome mdb_printf("Volume name = <%s>\n", dv->v_volume); 640*4188fb37SToomas Soome mdb_printf("ASCII name = <%s>\n", dv->v_asciilabel); 641*4188fb37SToomas Soome mdb_printf("pcyl = %4d\n", dl->dkl_pcyl); 642*4188fb37SToomas Soome mdb_printf("ncyl = %4d\n", dl->dkl_ncyl); 643*4188fb37SToomas Soome mdb_printf("acyl = %4d\n", dl->dkl_acyl); 644*4188fb37SToomas Soome 645*4188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 646*4188fb37SToomas Soome mdb_printf("bcyl = %4d\n", dl->dkl_bcyl); 647*4188fb37SToomas Soome #endif /* defined(_SUNOS_VTOC_16) */ 648*4188fb37SToomas Soome 649*4188fb37SToomas Soome mdb_printf("nhead = %4d\n", dl->dkl_nhead); 650*4188fb37SToomas Soome mdb_printf("nsect = %4d\n", dl->dkl_nsect); 651*4188fb37SToomas Soome 652*4188fb37SToomas Soome 653*4188fb37SToomas Soome if (!show_absolute) 654*4188fb37SToomas Soome addr = 0; 655*4188fb37SToomas Soome cyl = dl->dkl_nhead * dl->dkl_nsect; 656*4188fb37SToomas Soome if (show_sectors) 657*4188fb37SToomas Soome cyl = 1; 658*4188fb37SToomas Soome else 659*4188fb37SToomas Soome addr /= (cyl * SECTOR_SIZE); 660*4188fb37SToomas Soome 661*4188fb37SToomas Soome tag_width = array_widest_str(ptag_array); 662*4188fb37SToomas Soome 663*4188fb37SToomas Soome cyl_width = sizeof ("CYLINDERS"); 664*4188fb37SToomas Soome for (i = 0; i < dv->v_nparts; i++) { 665*4188fb37SToomas Soome uint32_t start, end, size; 666*4188fb37SToomas Soome int w; 667*4188fb37SToomas Soome 668*4188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 669*4188fb37SToomas Soome start = addr + (dv->v_part[i].p_start / cyl); 670*4188fb37SToomas Soome size = dv->v_part[i].p_size; 671*4188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8) 672*4188fb37SToomas Soome start = dl->dkl_map[i].dkl_cylno; 673*4188fb37SToomas Soome start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */ 674*4188fb37SToomas Soome start /= cyl; 675*4188fb37SToomas Soome start += addr; 676*4188fb37SToomas Soome size = dl->dkl_map[i].dkl_nblk; 677*4188fb37SToomas Soome #else 678*4188fb37SToomas Soome #error "No VTOC format defined." 679*4188fb37SToomas Soome #endif 680*4188fb37SToomas Soome if (size == 0) 681*4188fb37SToomas Soome end = start = 0; 682*4188fb37SToomas Soome else 683*4188fb37SToomas Soome end = start + size / cyl - 1; 684*4188fb37SToomas Soome 685*4188fb37SToomas Soome w = mdb_snprintf(NULL, 0, "%u - %u", start, end); 686*4188fb37SToomas Soome if (w > cyl_width) 687*4188fb37SToomas Soome cyl_width = w; 688*4188fb37SToomas Soome } 689*4188fb37SToomas Soome 690*4188fb37SToomas Soome if (show_sectors == B_TRUE) { 691*4188fb37SToomas Soome mdb_printf("\n%<u>%-4s %-*s %-7s %-11s %-11s %-*s " 692*4188fb37SToomas Soome "%-10s%</u>\n", "PART", tag_width, "TAG", "FLAG", 693*4188fb37SToomas Soome "STARTLBA", "ENDLBA", MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS"); 694*4188fb37SToomas Soome } else { 695*4188fb37SToomas Soome mdb_printf("\n%<u>%-4s %-*s %-7s %-*s %-*s %-10s%</u>\n", 696*4188fb37SToomas Soome "PART", tag_width, "TAG", "FLAG", cyl_width, "CYLINDERS", 697*4188fb37SToomas Soome MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS"); 698*4188fb37SToomas Soome } 699*4188fb37SToomas Soome 700*4188fb37SToomas Soome for (i = 0; i < dv->v_nparts; i++) { 701*4188fb37SToomas Soome uint16_t tag, flag; 702*4188fb37SToomas Soome uint32_t start, end, size; 703*4188fb37SToomas Soome const char *stag, *sflag; 704*4188fb37SToomas Soome char nnum[MDB_NICENUM_BUFLEN]; 705*4188fb37SToomas Soome 706*4188fb37SToomas Soome #if defined(_SUNOS_VTOC_16) 707*4188fb37SToomas Soome tag = dv->v_part[i].p_tag; 708*4188fb37SToomas Soome flag = dv->v_part[i].p_flag; 709*4188fb37SToomas Soome start = addr + (dv->v_part[i].p_start / cyl); 710*4188fb37SToomas Soome size = dv->v_part[i].p_size; 711*4188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8) 712*4188fb37SToomas Soome tag = dv->v_part[i].p_tag; 713*4188fb37SToomas Soome flag = dv->v_part[i].p_flag; 714*4188fb37SToomas Soome start = dl->dkl_map[i].dkl_cylno; 715*4188fb37SToomas Soome start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */ 716*4188fb37SToomas Soome start /= cyl; 717*4188fb37SToomas Soome start += addr; 718*4188fb37SToomas Soome size = dl->dkl_map[i].dkl_nblk; 719*4188fb37SToomas Soome #else 720*4188fb37SToomas Soome #error "No VTOC format defined." 721*4188fb37SToomas Soome #endif 722*4188fb37SToomas Soome if (size == 0) 723*4188fb37SToomas Soome end = start = 0; 724*4188fb37SToomas Soome else 725*4188fb37SToomas Soome end = start + size / cyl - 1; 726*4188fb37SToomas Soome 727*4188fb37SToomas Soome stag = array_find_string(ptag_array, tag); 728*4188fb37SToomas Soome if (stag == NULL) 729*4188fb37SToomas Soome stag = "?"; 730*4188fb37SToomas Soome sflag = array_find_string(pflag_array, flag); 731*4188fb37SToomas Soome if (sflag == NULL) 732*4188fb37SToomas Soome sflag = "?"; 733*4188fb37SToomas Soome 734*4188fb37SToomas Soome mdb_printf("%-4d %-*s %-7s ", i, tag_width, stag, sflag); 735*4188fb37SToomas Soome mdb_nicenum(size * SECTOR_SIZE, nnum); 736*4188fb37SToomas Soome if (show_sectors) { 737*4188fb37SToomas Soome mdb_printf("%-11u %-11u %-*s %-10u\n", start, end, 738*4188fb37SToomas Soome MDB_NICENUM_BUFLEN, nnum, size); 739*4188fb37SToomas Soome } else { 740*4188fb37SToomas Soome char cyls[10 * 2 + 4]; 741*4188fb37SToomas Soome 742*4188fb37SToomas Soome if (size == 0) { 743*4188fb37SToomas Soome mdb_snprintf(cyls, sizeof (cyls), "%-*u", 744*4188fb37SToomas Soome cyl_width, size); 745*4188fb37SToomas Soome } else { 746*4188fb37SToomas Soome mdb_snprintf(cyls, sizeof (cyls), "%u - %u", 747*4188fb37SToomas Soome start, end); 748*4188fb37SToomas Soome } 749*4188fb37SToomas Soome mdb_printf("%-*s %-*s %-10u\n", cyl_width, cyls, 750*4188fb37SToomas Soome MDB_NICENUM_BUFLEN, nnum, size); 751*4188fb37SToomas Soome } 752*4188fb37SToomas Soome } 753*4188fb37SToomas Soome 754*4188fb37SToomas Soome return (DCMD_OK); 755*4188fb37SToomas Soome } 756*4188fb37SToomas Soome 757*4188fb37SToomas Soome void 758*4188fb37SToomas Soome vtoc_help(void) 759*4188fb37SToomas Soome { 760*4188fb37SToomas Soome mdb_printf("Display a Virtual Table of Content (VTOC).\n\n" 761*4188fb37SToomas Soome "-r Display relative addresses\n" 762*4188fb37SToomas Soome "-c Use cylinder based addressing\n"); 763*4188fb37SToomas Soome mdb_printf("\nThe addr is in 512-byte disk blocks.\n"); 764*4188fb37SToomas Soome } 765*4188fb37SToomas Soome 766446c407dSJohn Levon static const mdb_dcmd_t dcmds[] = { 767446c407dSJohn Levon { "mbr", NULL, "dump Master Boot Record information", cmd_mbr }, 768446c407dSJohn Levon { "gpt", "?[-ag]", "dump an EFI GPT", cmd_gpt, gpt_help }, 769*4188fb37SToomas Soome { "vtoc", "?[-cr]", "dump VTOC information", cmd_vtoc, vtoc_help }, 770446c407dSJohn Levon { NULL } 771446c407dSJohn Levon }; 772446c407dSJohn Levon 773446c407dSJohn Levon static const mdb_modinfo_t modinfo = { 774446c407dSJohn Levon MDB_API_VERSION, dcmds, NULL 775446c407dSJohn Levon }; 776446c407dSJohn Levon 777446c407dSJohn Levon const mdb_modinfo_t * 778446c407dSJohn Levon _mdb_init(void) 779446c407dSJohn Levon { 780446c407dSJohn Levon return (&modinfo); 781446c407dSJohn Levon } 782