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 
94fed69270SToomas Soome size_t sector_size = SECTOR_SIZE;
95fed69270SToomas Soome 
964188fb37SToomas Soome static const char *
array_find_string(stringval_t * array,int match_value)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
array_widest_str(stringval_t * array)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
print_fdisk_part(struct ipart * ip,size_t nr)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
mbr_info(struct mboot * mbr)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
cmd_mbr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv __unused)2494188fb37SToomas Soome cmd_mbr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv __unused)
2504188fb37SToomas Soome {
251fed69270SToomas Soome 	struct mboot *mbr;
2524188fb37SToomas Soome 	mbr_type_t type;
2534188fb37SToomas Soome 
254fed69270SToomas 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 
262fed69270SToomas Soome 	mbr = mdb_zalloc(sector_size, UM_SLEEP | UM_GC);
263fed69270SToomas Soome 
264fed69270SToomas 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 
269fed69270SToomas Soome 	type = mbr_info(mbr);
2704188fb37SToomas Soome 
2714188fb37SToomas Soome 	/* If the magic is wrong, stop here. */
272fed69270SToomas 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:
279fed69270SToomas Soome 		if (*(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE] == 1) {
2804188fb37SToomas Soome 			struct mboot vbr;
2814188fb37SToomas Soome 			uintptr_t vbrp;
2824188fb37SToomas Soome 
283fed69270SToomas Soome 			vbrp = *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA];
284fed69270SToomas 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 *)
304fed69270SToomas 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
efi_crc32(const unsigned char * s,unsigned int len)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
print_gpe(efi_gpe_t * gpe,size_t nr,int show_guid)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
cmd_gpt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv __unused)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;
415fed69270SToomas Soome 	efi_gpt_t *altheader;
416446c407dSJohn Levon 	size_t table_size;
417fed69270SToomas 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))
430fed69270SToomas Soome 		addr = sector_size;
431446c407dSJohn Levon 
432fed69270SToomas Soome 	header = mdb_zalloc(sector_size, UM_SLEEP | UM_GC);
433fed69270SToomas 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) {
439fed69270SToomas Soome 		addr = header->efi_gpt_AlternateLBA * sector_size;
440446c407dSJohn Levon 
441fed69270SToomas 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 
447fed69270SToomas Soome 	mdb_printf("Signature: %s (%s)\n", (char *)&header->efi_gpt_Signature,
448fed69270SToomas Soome 	    strncmp((char *)&header->efi_gpt_Signature, "EFI PART", 8) == 0 ?
449446c407dSJohn Levon 	    "valid" : "invalid");
450446c407dSJohn Levon 
451fed69270SToomas Soome 	mdb_printf("Revision: %hu.%hu\n", header->efi_gpt_Revision >> 16,
452fed69270SToomas Soome 	    header->efi_gpt_Revision);
453446c407dSJohn Levon 
454fed69270SToomas Soome 	mdb_printf("HeaderSize: %u bytes\n", header->efi_gpt_HeaderSize);
455446c407dSJohn Levon 
456fed69270SToomas Soome 	if (header->efi_gpt_HeaderSize > SECTOR_SIZE) {
457446c407dSJohn Levon 		mdb_warn("invalid header size: skipping CRC\n");
458446c407dSJohn Levon 	} else {
459fed69270SToomas Soome 		orig_crc = header->efi_gpt_HeaderCRC32;
460446c407dSJohn Levon 
461fed69270SToomas Soome 		header->efi_gpt_HeaderCRC32 = 0;
462446c407dSJohn Levon 
463fed69270SToomas Soome 		crc = efi_crc32((unsigned char *)header,
464fed69270SToomas 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",
470fed69270SToomas Soome 	    header->efi_gpt_Reserved1);
471446c407dSJohn Levon 
472446c407dSJohn Levon 	mdb_printf("MyLBA: %llu (should be %llu)\n",
473fed69270SToomas Soome 	    header->efi_gpt_MyLBA, addr / sector_size);
474446c407dSJohn Levon 
475fed69270SToomas Soome 	mdb_printf("AlternateLBA: %llu\n", header->efi_gpt_AlternateLBA);
476fed69270SToomas Soome 	mdb_printf("FirstUsableLBA: %llu\n", header->efi_gpt_FirstUsableLBA);
477fed69270SToomas Soome 	mdb_printf("LastUsableLBA: %llu\n", header->efi_gpt_LastUsableLBA);
478446c407dSJohn Levon 
479fed69270SToomas Soome 	if (header->efi_gpt_MyLBA >= header->efi_gpt_FirstUsableLBA &&
480fed69270SToomas Soome 	    header->efi_gpt_MyLBA <= header->efi_gpt_LastUsableLBA) {
481446c407dSJohn Levon 		mdb_warn("MyLBA is within usable LBA range\n");
482446c407dSJohn Levon 	}
483446c407dSJohn Levon 
484fed69270SToomas Soome 	if (header->efi_gpt_AlternateLBA >= header->efi_gpt_FirstUsableLBA &&
485fed69270SToomas Soome 	    header->efi_gpt_AlternateLBA <= header->efi_gpt_LastUsableLBA) {
486446c407dSJohn Levon 		mdb_warn("AlternateLBA is within usable LBA range\n");
487446c407dSJohn Levon 	}
488446c407dSJohn Levon 
489fed69270SToomas Soome 	altheader = mdb_zalloc(sector_size, UM_SLEEP | UM_GC);
490fed69270SToomas Soome 	if (mdb_vread(altheader, sector_size,
491fed69270SToomas Soome 	    header->efi_gpt_AlternateLBA * sector_size) == -1) {
492446c407dSJohn Levon 		mdb_warn("failed to read alternate GPT header");
493446c407dSJohn Levon 	} else {
494fed69270SToomas 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",
498fed69270SToomas Soome 			    (char *)&altheader->efi_gpt_Signature);
499446c407dSJohn Levon 		}
500446c407dSJohn Levon 
501fed69270SToomas 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",
504fed69270SToomas Soome 			    header->efi_gpt_AlternateLBA * sector_size,
505fed69270SToomas Soome 			    altheader->efi_gpt_MyLBA);
506446c407dSJohn Levon 		}
507446c407dSJohn Levon 
508fed69270SToomas 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",
511fed69270SToomas Soome 			    header->efi_gpt_AlternateLBA * sector_size,
512fed69270SToomas 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 
521fed69270SToomas 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",
525fed69270SToomas Soome 	    header->efi_gpt_PartitionEntryLBA);
526446c407dSJohn Levon 
527446c407dSJohn Levon 	mdb_printf("NumberOfPartitionEntries: %u\n",
528fed69270SToomas 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 	 */
534fed69270SToomas Soome 	if (header->efi_gpt_SizeOfPartitionEntry != sizeof (efi_gpe_t)) {
535446c407dSJohn Levon 		mdb_warn("SizeOfPartitionEntry: %#x bytes "
536446c407dSJohn Levon 		    "(expected %#x bytes)\n",
537fed69270SToomas 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",
542fed69270SToomas Soome 	    header->efi_gpt_SizeOfPartitionEntry);
543446c407dSJohn Levon 
544fed69270SToomas Soome 	table_size = header->efi_gpt_SizeOfPartitionEntry *
545fed69270SToomas 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 
556fed69270SToomas Soome 	table_size = P2ROUNDUP(table_size, sector_size);
557fed69270SToomas Soome 	gpet = mdb_alloc(table_size, UM_SLEEP | UM_GC);
558446c407dSJohn Levon 
559446c407dSJohn Levon 	if (mdb_vread(gpet, table_size,
560fed69270SToomas 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 
565*5f1e4180SToomas Soome 	crc = efi_crc32((unsigned char *)gpet,
566*5f1e4180SToomas Soome 	    header->efi_gpt_SizeOfPartitionEntry *
567*5f1e4180SToomas Soome 	    header->efi_gpt_NumberOfPartitionEntries);
568446c407dSJohn Levon 
569446c407dSJohn Levon 	mdb_printf("PartitionEntryArrayCRC32: %#x (should be %#x)\n",
570fed69270SToomas Soome 	    header->efi_gpt_PartitionEntryArrayCRC32, crc);
571446c407dSJohn Levon 
572446c407dSJohn Levon 	if (show_guid) {
573446c407dSJohn Levon 		mdb_printf("\n%<u>%-4s %-19s %-37s%</u>\n",
574446c407dSJohn Levon 		    "PART", "TYPE", "GUID");
575446c407dSJohn Levon 	} else {
576446c407dSJohn Levon 		mdb_printf("\n%<u>%-4s %-19s %-13s %-13s %-8s %s%</u>\n",
577446c407dSJohn Levon 		    "PART", "TYPE", "STARTLBA", "ENDLBA", "ATTR", "NAME");
578446c407dSJohn Levon 	}
579446c407dSJohn Levon 
580fed69270SToomas Soome 	for (size_t i = 0; i < header->efi_gpt_NumberOfPartitionEntries; i++)
581446c407dSJohn Levon 		print_gpe(&gpet[i], i, show_guid);
582446c407dSJohn Levon 
583446c407dSJohn Levon 	return (DCMD_OK);
584446c407dSJohn Levon }
585446c407dSJohn Levon 
586446c407dSJohn Levon void
gpt_help(void)587446c407dSJohn Levon gpt_help(void)
588446c407dSJohn Levon {
589446c407dSJohn Levon 	mdb_printf("Display an EFI GUID Partition Table.\n\n"
590446c407dSJohn Levon 	    "-a Display the alternate GPT\n"
591446c407dSJohn Levon 	    "-g Show unique GUID for each table entry\n");
592446c407dSJohn Levon }
593446c407dSJohn Levon 
5944188fb37SToomas Soome static int
cmd_vtoc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5954188fb37SToomas Soome cmd_vtoc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5964188fb37SToomas Soome {
597fed69270SToomas Soome 	uint8_t *buf;
5984188fb37SToomas Soome 	struct dk_label *dl;
5994188fb37SToomas Soome 	struct dk_vtoc *dv;
6004188fb37SToomas Soome 	uintptr_t vaddr;
6014188fb37SToomas Soome 	int i, tag_width, cyl_width;
6024188fb37SToomas Soome 	int show_absolute = B_TRUE;
6034188fb37SToomas Soome 	int show_sectors = B_TRUE;
6044188fb37SToomas Soome 	uint32_t cyl;
6054188fb37SToomas Soome 
6064188fb37SToomas Soome 	if (mdb_getopts(argc, argv,
6074188fb37SToomas Soome 	    'c', MDB_OPT_CLRBITS, TRUE, &show_sectors,
6084188fb37SToomas Soome 	    'r', MDB_OPT_CLRBITS, TRUE, &show_absolute,
6094188fb37SToomas Soome 	    NULL) != argc)
6104188fb37SToomas Soome 		return (DCMD_USAGE);
6114188fb37SToomas Soome 
6124188fb37SToomas Soome 	if (!(flags & DCMD_ADDRSPEC))
6134188fb37SToomas Soome 		addr = 0;
6144188fb37SToomas Soome 	else
615fed69270SToomas Soome 		addr *= sector_size;
616fed69270SToomas Soome 
617fed69270SToomas Soome 	buf = mdb_zalloc(sector_size, UM_SLEEP | UM_GC);
6184188fb37SToomas Soome 
6194188fb37SToomas Soome #if defined(_SUNOS_VTOC_16)
620fed69270SToomas Soome 	if (mdb_vread(buf, sector_size, addr) == -1) {
6214188fb37SToomas Soome 		mdb_warn("failed to read VBR");
6224188fb37SToomas Soome 		return (DCMD_ERR);
6234188fb37SToomas Soome 	}
6244188fb37SToomas Soome 
6254188fb37SToomas Soome 	mdb_printf("VBR info:\n");
6264188fb37SToomas Soome 	(void) mbr_info((struct mboot *)buf);
6274188fb37SToomas Soome #endif
6284188fb37SToomas Soome 
629fed69270SToomas Soome 	vaddr = addr + DK_LABEL_LOC * sector_size;
6304188fb37SToomas Soome 
631fed69270SToomas Soome 	if (mdb_vread(buf, sector_size, vaddr) == -1) {
6324188fb37SToomas Soome 		mdb_warn("failed to read VTOC");
6334188fb37SToomas Soome 		return (DCMD_ERR);
6344188fb37SToomas Soome 	}
6354188fb37SToomas Soome 
636fed69270SToomas Soome 	dl = (struct dk_label *)buf;
6374188fb37SToomas Soome 	dv = (struct dk_vtoc *)&dl->dkl_vtoc;
6384188fb37SToomas Soome 
6394188fb37SToomas Soome 	mdb_printf("Label magic: 0x%hx (%s)\n", dl->dkl_magic,
6404188fb37SToomas Soome 	    dl->dkl_magic == DKL_MAGIC ? "valid" : "invalid");
6414188fb37SToomas Soome 	if (dl->dkl_magic != DKL_MAGIC)
6424188fb37SToomas Soome 		return (DCMD_ERR);
6434188fb37SToomas Soome 	mdb_printf("Label %s sane\n", dv->v_sanity == VTOC_SANE ?
6444188fb37SToomas Soome 	    "is" : "is not");
6454188fb37SToomas Soome 
6464188fb37SToomas Soome 	mdb_printf("Label version: %#x\n", dv->v_version);
6474188fb37SToomas Soome 	mdb_printf("Volume name = <%s>\n", dv->v_volume);
6484188fb37SToomas Soome 	mdb_printf("ASCII name  = <%s>\n", dv->v_asciilabel);
6494188fb37SToomas Soome 	mdb_printf("pcyl        = %4d\n", dl->dkl_pcyl);
6504188fb37SToomas Soome 	mdb_printf("ncyl        = %4d\n", dl->dkl_ncyl);
6514188fb37SToomas Soome 	mdb_printf("acyl        = %4d\n", dl->dkl_acyl);
6524188fb37SToomas Soome 
6534188fb37SToomas Soome #if defined(_SUNOS_VTOC_16)
6544188fb37SToomas Soome 	mdb_printf("bcyl        = %4d\n", dl->dkl_bcyl);
6554188fb37SToomas Soome #endif /* defined(_SUNOS_VTOC_16) */
6564188fb37SToomas Soome 
6574188fb37SToomas Soome 	mdb_printf("nhead       = %4d\n", dl->dkl_nhead);
6584188fb37SToomas Soome 	mdb_printf("nsect       = %4d\n", dl->dkl_nsect);
6594188fb37SToomas Soome 
6604188fb37SToomas Soome 
6614188fb37SToomas Soome 	if (!show_absolute)
6624188fb37SToomas Soome 		addr = 0;
6634188fb37SToomas Soome 	cyl = dl->dkl_nhead * dl->dkl_nsect;
6644188fb37SToomas Soome 	if (show_sectors)
6654188fb37SToomas Soome 		cyl = 1;
6664188fb37SToomas Soome 	else
667fed69270SToomas Soome 		addr /= (cyl * sector_size);
6684188fb37SToomas Soome 
6694188fb37SToomas Soome 	tag_width = array_widest_str(ptag_array);
6704188fb37SToomas Soome 
6714188fb37SToomas Soome 	cyl_width = sizeof ("CYLINDERS");
6724188fb37SToomas Soome 	for (i = 0; i < dv->v_nparts; i++) {
6734188fb37SToomas Soome 		uint32_t start, end, size;
6744188fb37SToomas Soome 		int w;
6754188fb37SToomas Soome 
6764188fb37SToomas Soome #if defined(_SUNOS_VTOC_16)
6774188fb37SToomas Soome 		start = addr + (dv->v_part[i].p_start / cyl);
6784188fb37SToomas Soome 		size = dv->v_part[i].p_size;
6794188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8)
6804188fb37SToomas Soome 		start = dl->dkl_map[i].dkl_cylno;
6814188fb37SToomas Soome 		start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */
6824188fb37SToomas Soome 		start /= cyl;
6834188fb37SToomas Soome 		start += addr;
6844188fb37SToomas Soome 		size = dl->dkl_map[i].dkl_nblk;
6854188fb37SToomas Soome #else
6864188fb37SToomas Soome #error "No VTOC format defined."
6874188fb37SToomas Soome #endif
6884188fb37SToomas Soome 		if (size == 0)
6894188fb37SToomas Soome 			end = start = 0;
6904188fb37SToomas Soome 		else
6914188fb37SToomas Soome 			end = start + size / cyl - 1;
6924188fb37SToomas Soome 
6934188fb37SToomas Soome 		w = mdb_snprintf(NULL, 0, "%u - %u", start, end);
6944188fb37SToomas Soome 		if (w > cyl_width)
6954188fb37SToomas Soome 			cyl_width = w;
6964188fb37SToomas Soome 	}
6974188fb37SToomas Soome 
6984188fb37SToomas Soome 	if (show_sectors == B_TRUE) {
6994188fb37SToomas Soome 		mdb_printf("\n%<u>%-4s %-*s %-7s %-11s %-11s %-*s "
7004188fb37SToomas Soome 		    "%-10s%</u>\n", "PART", tag_width, "TAG", "FLAG",
7014188fb37SToomas Soome 		    "STARTLBA", "ENDLBA", MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS");
7024188fb37SToomas Soome 	} else {
7034188fb37SToomas Soome 		mdb_printf("\n%<u>%-4s %-*s %-7s %-*s %-*s %-10s%</u>\n",
7044188fb37SToomas Soome 		    "PART", tag_width, "TAG", "FLAG", cyl_width, "CYLINDERS",
7054188fb37SToomas Soome 		    MDB_NICENUM_BUFLEN, "SIZE", "BLOCKS");
7064188fb37SToomas Soome 	}
7074188fb37SToomas Soome 
7084188fb37SToomas Soome 	for (i = 0; i < dv->v_nparts; i++) {
7094188fb37SToomas Soome 		uint16_t tag, flag;
7104188fb37SToomas Soome 		uint32_t start, end, size;
7114188fb37SToomas Soome 		const char *stag, *sflag;
7124188fb37SToomas Soome 		char nnum[MDB_NICENUM_BUFLEN];
7134188fb37SToomas Soome 
7144188fb37SToomas Soome #if defined(_SUNOS_VTOC_16)
7154188fb37SToomas Soome 		tag = dv->v_part[i].p_tag;
7164188fb37SToomas Soome 		flag = dv->v_part[i].p_flag;
7174188fb37SToomas Soome 		start = addr + (dv->v_part[i].p_start / cyl);
7184188fb37SToomas Soome 		size = dv->v_part[i].p_size;
7194188fb37SToomas Soome #elif defined(_SUNOS_VTOC_8)
7204188fb37SToomas Soome 		tag = dv->v_part[i].p_tag;
7214188fb37SToomas Soome 		flag = dv->v_part[i].p_flag;
7224188fb37SToomas Soome 		start = dl->dkl_map[i].dkl_cylno;
7234188fb37SToomas Soome 		start *= dl->dkl_nhead * dl->dkl_nsect; /* compute bytes */
7244188fb37SToomas Soome 		start /= cyl;
7254188fb37SToomas Soome 		start += addr;
7264188fb37SToomas Soome 		size = dl->dkl_map[i].dkl_nblk;
7274188fb37SToomas Soome #else
7284188fb37SToomas Soome #error "No VTOC format defined."
7294188fb37SToomas Soome #endif
7304188fb37SToomas Soome 		if (size == 0)
7314188fb37SToomas Soome 			end = start = 0;
7324188fb37SToomas Soome 		else
7334188fb37SToomas Soome 			end = start + size / cyl - 1;
7344188fb37SToomas Soome 
7354188fb37SToomas Soome 		stag = array_find_string(ptag_array, tag);
7364188fb37SToomas Soome 		if (stag == NULL)
7374188fb37SToomas Soome 			stag = "?";
7384188fb37SToomas Soome 		sflag = array_find_string(pflag_array, flag);
7394188fb37SToomas Soome 		if (sflag == NULL)
7404188fb37SToomas Soome 			sflag = "?";
7414188fb37SToomas Soome 
7424188fb37SToomas Soome 		mdb_printf("%-4d %-*s %-7s ", i, tag_width, stag, sflag);
743fed69270SToomas Soome 		mdb_nicenum(size * sector_size, nnum);
7444188fb37SToomas Soome 		if (show_sectors) {
7454188fb37SToomas Soome 			mdb_printf("%-11u %-11u %-*s %-10u\n", start, end,
7464188fb37SToomas Soome 			    MDB_NICENUM_BUFLEN, nnum, size);
7474188fb37SToomas Soome 		} else {
7484188fb37SToomas Soome 			char cyls[10 * 2 + 4];
7494188fb37SToomas Soome 
7504188fb37SToomas Soome 			if (size == 0) {
7514188fb37SToomas Soome 				mdb_snprintf(cyls, sizeof (cyls), "%-*u",
7524188fb37SToomas Soome 				    cyl_width, size);
7534188fb37SToomas Soome 			} else {
7544188fb37SToomas Soome 				mdb_snprintf(cyls, sizeof (cyls), "%u - %u",
7554188fb37SToomas Soome 				    start, end);
7564188fb37SToomas Soome 			}
7574188fb37SToomas Soome 			mdb_printf("%-*s %-*s %-10u\n", cyl_width, cyls,
7584188fb37SToomas Soome 			    MDB_NICENUM_BUFLEN, nnum, size);
7594188fb37SToomas Soome 		}
7604188fb37SToomas Soome 	}
7614188fb37SToomas Soome 
7624188fb37SToomas Soome 	return (DCMD_OK);
7634188fb37SToomas Soome }
7644188fb37SToomas Soome 
7654188fb37SToomas Soome void
vtoc_help(void)7664188fb37SToomas Soome vtoc_help(void)
7674188fb37SToomas Soome {
7684188fb37SToomas Soome 	mdb_printf("Display a Virtual Table of Content (VTOC).\n\n"
7694188fb37SToomas Soome 	    "-r Display relative addresses\n"
7704188fb37SToomas Soome 	    "-c Use cylinder based addressing\n");
771fed69270SToomas Soome 	mdb_printf("\nThe addr is in %u-byte disk blocks.\n", sector_size);
772fed69270SToomas Soome }
773fed69270SToomas Soome 
774fed69270SToomas Soome static int
cmd_sect(uintptr_t addr __unused,uint_t flags __unused,int argc,const mdb_arg_t * argv)775fed69270SToomas Soome cmd_sect(uintptr_t addr __unused, uint_t flags __unused, int argc,
776fed69270SToomas Soome     const mdb_arg_t *argv)
777fed69270SToomas Soome {
778fed69270SToomas Soome 	uint64_t size = SECTOR_SIZE;
779fed69270SToomas Soome 
780fed69270SToomas Soome 	if (argc < 1) {
781fed69270SToomas Soome 		mdb_printf("Current sector size is %u (%#x)\n", sector_size,
782fed69270SToomas Soome 		    sector_size);
783fed69270SToomas Soome 		return (DCMD_OK);
784fed69270SToomas Soome 	}
785fed69270SToomas Soome 
786fed69270SToomas Soome 	if (argc != 1)
787fed69270SToomas Soome 		return (DCMD_USAGE);
788fed69270SToomas Soome 
789fed69270SToomas Soome 	switch (argv[0].a_type) {
790fed69270SToomas Soome 	case MDB_TYPE_STRING:
791fed69270SToomas Soome 		size = mdb_strtoull(argv[0].a_un.a_str);
792fed69270SToomas Soome 		break;
793fed69270SToomas Soome 	case MDB_TYPE_IMMEDIATE:
794fed69270SToomas Soome 		size = argv[0].a_un.a_val;
795fed69270SToomas Soome 		break;
796fed69270SToomas Soome 	default:
797fed69270SToomas Soome 		return (DCMD_USAGE);
798fed69270SToomas Soome 	}
799fed69270SToomas Soome 
800fed69270SToomas Soome 	if (!ISP2(size)) {
801fed69270SToomas Soome 		mdb_printf("sector size must be power of 2\n");
802fed69270SToomas Soome 		return (DCMD_USAGE);
803fed69270SToomas Soome 	}
804fed69270SToomas Soome 	sector_size = size;
805fed69270SToomas Soome 	return (DCMD_OK);
806fed69270SToomas Soome }
807fed69270SToomas Soome 
808fed69270SToomas Soome void
sect_help(void)809fed69270SToomas Soome sect_help(void)
810fed69270SToomas Soome {
811fed69270SToomas Soome 	mdb_printf("Show or set sector size.\n");
8124188fb37SToomas Soome }
8134188fb37SToomas Soome 
814446c407dSJohn Levon static const mdb_dcmd_t dcmds[] = {
815446c407dSJohn Levon 	{ "mbr", NULL, "dump Master Boot Record information", cmd_mbr },
816446c407dSJohn Levon 	{ "gpt", "?[-ag]", "dump an EFI GPT", cmd_gpt, gpt_help },
8174188fb37SToomas Soome 	{ "vtoc", "?[-cr]", "dump VTOC information", cmd_vtoc, vtoc_help },
818fed69270SToomas Soome 	{ "sectorsize", NULL, "set or show sector size", cmd_sect, sect_help },
819446c407dSJohn Levon 	{ NULL }
820446c407dSJohn Levon };
821446c407dSJohn Levon 
822446c407dSJohn Levon static const mdb_modinfo_t modinfo = {
823446c407dSJohn Levon 	MDB_API_VERSION, dcmds, NULL
824446c407dSJohn Levon };
825446c407dSJohn Levon 
826446c407dSJohn Levon const mdb_modinfo_t *
_mdb_init(void)827446c407dSJohn Levon _mdb_init(void)
828446c407dSJohn Levon {
829446c407dSJohn Levon 	return (&modinfo);
830446c407dSJohn Levon }
831