Home | History | Annotate | Line # | Download | only in efiboot
efidisk.c revision 1.9
      1  1.9    manu /*	$NetBSD: efidisk.c,v 1.9 2019/12/17 01:37:52 manu Exp $	*/
      2  1.1  nonaka 
      3  1.1  nonaka /*-
      4  1.1  nonaka  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5  1.1  nonaka  * All rights reserved.
      6  1.1  nonaka  *
      7  1.1  nonaka  * Redistribution and use in source and binary forms, with or without
      8  1.1  nonaka  * modification, are permitted provided that the following conditions
      9  1.1  nonaka  * are met:
     10  1.1  nonaka  * 1. Redistributions of source code must retain the above copyright
     11  1.1  nonaka  *    notice, this list of conditions and the following disclaimer.
     12  1.1  nonaka  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  nonaka  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  nonaka  *    documentation and/or other materials provided with the distribution.
     15  1.1  nonaka  *
     16  1.1  nonaka  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17  1.1  nonaka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  1.1  nonaka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  1.1  nonaka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20  1.1  nonaka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  1.1  nonaka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  1.1  nonaka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  1.1  nonaka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  1.1  nonaka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  1.1  nonaka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  1.1  nonaka  * SUCH DAMAGE.
     27  1.1  nonaka  */
     28  1.1  nonaka 
     29  1.2  nonaka #define FSTYPENAMES	/* for sys/disklabel.h */
     30  1.2  nonaka 
     31  1.1  nonaka #include "efiboot.h"
     32  1.1  nonaka 
     33  1.8    manu #include <sys/param.h>	/* for howmany, required by <dev/raidframe/raidframevar.h> */
     34  1.2  nonaka #include <sys/disklabel.h>
     35  1.8    manu #include <sys/disklabel_gpt.h>
     36  1.2  nonaka 
     37  1.2  nonaka #include "biosdisk.h"
     38  1.2  nonaka #include "biosdisk_ll.h"
     39  1.2  nonaka #include "devopen.h"
     40  1.1  nonaka #include "efidisk.h"
     41  1.1  nonaka 
     42  1.1  nonaka static struct efidiskinfo_lh efi_disklist;
     43  1.1  nonaka static int nefidisks;
     44  1.1  nonaka 
     45  1.8    manu #define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */
     46  1.8    manu 
     47  1.8    manu #include <dev/raidframe/raidframevar.h>
     48  1.8    manu #define RF_COMPONENT_INFO_OFFSET   16384   /* from sys/dev/raidframe/rf_netbsdkintf.c */
     49  1.8    manu #define RF_COMPONENT_LABEL_VERSION     2   /* from <dev/raidframe/rf_raid.h> */
     50  1.8    manu 
     51  1.8    manu #define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */
     52  1.8    manu struct efi_raidframe {
     53  1.8    manu        int last_unit;
     54  1.8    manu        int serial;
     55  1.8    manu        const struct efidiskinfo *edi;
     56  1.8    manu        int parent_part;
     57  1.8    manu        char parent_name[MAXDEVNAME + 1];
     58  1.8    manu        daddr_t offset;
     59  1.8    manu        daddr_t size;
     60  1.8    manu };
     61  1.8    manu 
     62  1.8    manu static void
     63  1.8    manu dealloc_biosdisk_part(struct biosdisk_partition *part, int nparts)
     64  1.8    manu {
     65  1.8    manu 	int i;
     66  1.8    manu 
     67  1.8    manu 	for (i = 0; i < nparts; i++) {
     68  1.8    manu 		if (part[i].part_name != NULL) {
     69  1.8    manu 			dealloc(part[i].part_name, BIOSDISK_PART_NAME_LEN);
     70  1.8    manu 			part[i].part_name = NULL;
     71  1.8    manu 		}
     72  1.8    manu 	}
     73  1.8    manu 
     74  1.8    manu 	dealloc(part, sizeof(*part) * nparts);
     75  1.8    manu 
     76  1.8    manu 	return;
     77  1.8    manu }
     78  1.8    manu 
     79  1.1  nonaka void
     80  1.1  nonaka efi_disk_probe(void)
     81  1.1  nonaka {
     82  1.1  nonaka 	EFI_STATUS status;
     83  1.1  nonaka 	UINTN i, nhandles;
     84  1.1  nonaka 	EFI_HANDLE *handles;
     85  1.1  nonaka 	EFI_BLOCK_IO *bio;
     86  1.1  nonaka 	EFI_BLOCK_IO_MEDIA *media;
     87  1.2  nonaka 	EFI_DEVICE_PATH *dp;
     88  1.1  nonaka 	struct efidiskinfo *edi;
     89  1.2  nonaka 	int dev, depth = -1;
     90  1.1  nonaka 
     91  1.1  nonaka 	TAILQ_INIT(&efi_disklist);
     92  1.1  nonaka 
     93  1.1  nonaka 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
     94  1.1  nonaka 	    &nhandles, &handles);
     95  1.1  nonaka 	if (EFI_ERROR(status))
     96  1.7  nonaka 		return;
     97  1.1  nonaka 
     98  1.2  nonaka 	if (efi_bootdp != NULL)
     99  1.2  nonaka 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
    100  1.2  nonaka 
    101  1.2  nonaka 	/*
    102  1.2  nonaka 	 * U-Boot incorrectly represents devices with a single
    103  1.2  nonaka 	 * MEDIA_DEVICE_PATH component.  In that case include that
    104  1.2  nonaka 	 * component into the matching, otherwise we'll blindly select
    105  1.2  nonaka 	 * the first device.
    106  1.2  nonaka 	 */
    107  1.2  nonaka 	if (depth == 0)
    108  1.2  nonaka 		depth = 1;
    109  1.2  nonaka 
    110  1.1  nonaka 	for (i = 0; i < nhandles; i++) {
    111  1.1  nonaka 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
    112  1.1  nonaka 		    &BlockIoProtocol, (void **)&bio);
    113  1.1  nonaka 		if (EFI_ERROR(status))
    114  1.7  nonaka 			continue;
    115  1.1  nonaka 
    116  1.1  nonaka 		media = bio->Media;
    117  1.1  nonaka 		if (media->LogicalPartition || !media->MediaPresent)
    118  1.1  nonaka 			continue;
    119  1.1  nonaka 
    120  1.1  nonaka 		edi = alloc(sizeof(struct efidiskinfo));
    121  1.1  nonaka 		memset(edi, 0, sizeof(*edi));
    122  1.2  nonaka 		edi->type = BIOSDISK_TYPE_HD;
    123  1.1  nonaka 		edi->bio = bio;
    124  1.1  nonaka 		edi->media_id = media->MediaId;
    125  1.1  nonaka 
    126  1.2  nonaka 		if (efi_bootdp != NULL && depth > 0) {
    127  1.2  nonaka 			status = uefi_call_wrapper(BS->HandleProtocol, 3,
    128  1.2  nonaka 			    handles[i], &DevicePathProtocol, (void **)&dp);
    129  1.2  nonaka 			if (EFI_ERROR(status))
    130  1.2  nonaka 				goto next;
    131  1.2  nonaka 			if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
    132  1.2  nonaka 				edi->bootdev = true;
    133  1.2  nonaka 				TAILQ_INSERT_HEAD(&efi_disklist, edi,
    134  1.2  nonaka 				    list);
    135  1.2  nonaka 				continue;
    136  1.2  nonaka 			}
    137  1.2  nonaka 		}
    138  1.2  nonaka next:
    139  1.2  nonaka 		TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    140  1.2  nonaka 	}
    141  1.1  nonaka 
    142  1.2  nonaka 	FreePool(handles);
    143  1.1  nonaka 
    144  1.6  nonaka 	if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
    145  1.3  nonaka 		edi = TAILQ_FIRST(&efi_disklist);
    146  1.3  nonaka 		if (edi != NULL && edi->bootdev) {
    147  1.3  nonaka 			edi->type = BIOSDISK_TYPE_CD;
    148  1.3  nonaka 			TAILQ_REMOVE(&efi_disklist, edi, list);
    149  1.3  nonaka 			TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    150  1.1  nonaka 		}
    151  1.1  nonaka 	}
    152  1.1  nonaka 
    153  1.1  nonaka 	dev = 0x80;
    154  1.1  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    155  1.1  nonaka 		edi->dev = dev++;
    156  1.2  nonaka 		if (edi->type == BIOSDISK_TYPE_HD)
    157  1.2  nonaka 			nefidisks++;
    158  1.2  nonaka 		if (edi->bootdev)
    159  1.2  nonaka 			boot_biosdev = edi->dev;
    160  1.2  nonaka 	}
    161  1.2  nonaka }
    162  1.2  nonaka 
    163  1.8    manu static void
    164  1.8    manu efi_raidframe_probe(struct efi_raidframe *raidframe, int *raidframe_count,
    165  1.8    manu 		    const struct efidiskinfo *edi,
    166  1.8    manu 		    struct biosdisk_partition *part, int parent_part)
    167  1.8    manu 
    168  1.8    manu {
    169  1.8    manu 	int i = *raidframe_count;
    170  1.8    manu 	struct RF_ComponentLabel_s label;
    171  1.8    manu 
    172  1.8    manu 	if (i + 1 > RAIDFRAME_NDEV)
    173  1.8    manu 		return;
    174  1.8    manu 
    175  1.8    manu 	if (biosdisk_read_raidframe(edi->dev, part->offset, &label) != 0)
    176  1.8    manu 		return;
    177  1.8    manu 
    178  1.8    manu 	if (label.version != RF_COMPONENT_LABEL_VERSION)
    179  1.8    manu 		return;
    180  1.8    manu 
    181  1.8    manu 	raidframe[i].last_unit = label.last_unit;
    182  1.8    manu 	raidframe[i].serial = label.serial_number;
    183  1.8    manu 	raidframe[i].edi = edi;
    184  1.8    manu 	raidframe[i].parent_part = parent_part;
    185  1.8    manu 	if (part->part_name)
    186  1.8    manu 		strlcpy(raidframe[i].parent_name, part->part_name, MAXDEVNAME);
    187  1.8    manu 	else
    188  1.8    manu 		raidframe[i].parent_name[0] = '\0';
    189  1.8    manu 	raidframe[i].offset = part->offset;
    190  1.8    manu 	raidframe[i].size = label.__numBlocks;
    191  1.8    manu 
    192  1.8    manu 	(*raidframe_count)++;
    193  1.8    manu 
    194  1.8    manu 	return;
    195  1.8    manu }
    196  1.8    manu 
    197  1.8    manu 
    198  1.2  nonaka void
    199  1.2  nonaka efi_disk_show(void)
    200  1.2  nonaka {
    201  1.2  nonaka 	const struct efidiskinfo *edi;
    202  1.8    manu 	struct efi_raidframe raidframe[RAIDFRAME_NDEV];
    203  1.8    manu 	int raidframe_count = 0;
    204  1.2  nonaka 	EFI_BLOCK_IO_MEDIA *media;
    205  1.2  nonaka 	struct biosdisk_partition *part;
    206  1.2  nonaka 	uint64_t size;
    207  1.8    manu 	int i, j, nparts;
    208  1.2  nonaka 	bool first;
    209  1.2  nonaka 
    210  1.2  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    211  1.2  nonaka 		media = edi->bio->Media;
    212  1.2  nonaka 		first = true;
    213  1.2  nonaka 		printf("disk ");
    214  1.2  nonaka 		switch (edi->type) {
    215  1.2  nonaka 		case BIOSDISK_TYPE_CD:
    216  1.2  nonaka 			printf("cd0");
    217  1.2  nonaka 			printf(" mediaId %u", media->MediaId);
    218  1.2  nonaka 			if (edi->media_id != media->MediaId)
    219  1.2  nonaka 				printf("(%u)", edi->media_id);
    220  1.2  nonaka 			printf("\n");
    221  1.2  nonaka 			printf("  cd0a\n");
    222  1.2  nonaka 			break;
    223  1.2  nonaka 		case BIOSDISK_TYPE_HD:
    224  1.2  nonaka 			printf("hd%d", edi->dev & 0x7f);
    225  1.2  nonaka 			printf(" mediaId %u", media->MediaId);
    226  1.2  nonaka 			if (edi->media_id != media->MediaId)
    227  1.2  nonaka 				printf("(%u)", edi->media_id);
    228  1.2  nonaka 			printf(" size ");
    229  1.2  nonaka 			size = (media->LastBlock + 1) * media->BlockSize;
    230  1.2  nonaka 			if (size >= (10ULL * 1024 * 1024 * 1024))
    231  1.2  nonaka 				printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
    232  1.2  nonaka 			else
    233  1.2  nonaka 				printf("%"PRIu64" MB", size / (1024 * 1024));
    234  1.2  nonaka 			printf("\n");
    235  1.2  nonaka 			break;
    236  1.2  nonaka 		}
    237  1.2  nonaka 		if (edi->type != BIOSDISK_TYPE_HD)
    238  1.2  nonaka 			continue;
    239  1.2  nonaka 
    240  1.8    manu 		if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
    241  1.2  nonaka 			continue;
    242  1.2  nonaka 
    243  1.2  nonaka 		for (i = 0; i < nparts; i++) {
    244  1.2  nonaka 			if (part[i].size == 0)
    245  1.2  nonaka 				continue;
    246  1.2  nonaka 			if (part[i].fstype == FS_UNUSED)
    247  1.2  nonaka 				continue;
    248  1.8    manu 			if (part[i].fstype == FS_RAID) {
    249  1.8    manu 				efi_raidframe_probe(raidframe, &raidframe_count,
    250  1.8    manu 						    edi, &part[i], i);
    251  1.8    manu 			}
    252  1.2  nonaka 			if (first) {
    253  1.2  nonaka 				printf(" ");
    254  1.2  nonaka 				first = false;
    255  1.2  nonaka 			}
    256  1.9    manu 			if (part[i].part_name && part[i].part_name[0])
    257  1.8    manu 				printf(" NAME=%s(", part[i].part_name);
    258  1.8    manu 			else
    259  1.8    manu 				printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
    260  1.2  nonaka 			if (part[i].guid != NULL)
    261  1.2  nonaka 				printf("%s", part[i].guid->name);
    262  1.2  nonaka 			else if (part[i].fstype < FSMAXTYPES)
    263  1.2  nonaka 				printf("%s", fstypenames[part[i].fstype]);
    264  1.2  nonaka 			else
    265  1.2  nonaka 				printf("%d", part[i].fstype);
    266  1.2  nonaka 			printf(")");
    267  1.2  nonaka 		}
    268  1.2  nonaka 		if (!first)
    269  1.2  nonaka 			printf("\n");
    270  1.8    manu 		dealloc_biosdisk_part(part, nparts);
    271  1.8    manu 	}
    272  1.8    manu 
    273  1.8    manu 	for (i = 0; i < raidframe_count; i++) {
    274  1.8    manu 		size_t secsize = raidframe[i].edi->bio->Media->BlockSize;
    275  1.8    manu 		printf("raidframe raid%d serial %d in ",
    276  1.8    manu 		       raidframe[i].last_unit, raidframe[i].serial);
    277  1.8    manu 		if (raidframe[i].parent_name[0])
    278  1.8    manu 			printf("NAME=%s size ", raidframe[i].parent_name);
    279  1.8    manu 		else
    280  1.8    manu 			printf("hd%d%c size ",
    281  1.8    manu 			       raidframe[i].edi->dev & 0x7f,
    282  1.8    manu 			       raidframe[i].parent_part + 'a');
    283  1.8    manu 		if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize))
    284  1.8    manu 			printf("%"PRIu64" GB",
    285  1.8    manu 			    raidframe[i].size / (1024 * 1024 * 1024 / secsize));
    286  1.8    manu 		else
    287  1.8    manu 			printf("%"PRIu64" MB",
    288  1.8    manu 			    raidframe[i].size / (1024 * 1024 / secsize));
    289  1.8    manu 		printf("\n");
    290  1.8    manu 
    291  1.8    manu 		if (biosdisk_readpartition(raidframe[i].edi->dev,
    292  1.8    manu 		    raidframe[i].offset + RF_PROTECTED_SECTORS,
    293  1.8    manu 		    raidframe[i].size,
    294  1.8    manu 		    &part, &nparts))
    295  1.8    manu 			continue;
    296  1.8    manu 
    297  1.8    manu 		first = 1;
    298  1.8    manu 		for (j = 0; j < nparts; j++) {
    299  1.8    manu 			bool bootme = part[j].attr & GPT_ENT_ATTR_BOOTME;
    300  1.8    manu 
    301  1.8    manu 			if (part[j].size == 0)
    302  1.8    manu 				continue;
    303  1.8    manu 			if (part[j].fstype == FS_UNUSED)
    304  1.8    manu 				continue;
    305  1.8    manu 			if (part[j].fstype == FS_RAID) /* raid in raid? */
    306  1.8    manu 				continue;
    307  1.8    manu 			if (first) {
    308  1.8    manu 				printf(" ");
    309  1.8    manu 				first = 0;
    310  1.8    manu 			}
    311  1.9    manu 			if (part[j].part_name && part[j].part_name[0])
    312  1.8    manu 				printf(" NAME=%s(", part[j].part_name);
    313  1.8    manu 			else
    314  1.8    manu 				printf(" raid%d%c(",
    315  1.8    manu 				       raidframe[i].last_unit, j + 'a');
    316  1.8    manu 			if (part[j].guid != NULL)
    317  1.8    manu 				printf("%s", part[j].guid->name);
    318  1.8    manu 			else if (part[j].fstype < FSMAXTYPES)
    319  1.8    manu 				printf("%s",
    320  1.8    manu 				  fstypenames[part[j].fstype]);
    321  1.8    manu 			else
    322  1.8    manu 				printf("%d", part[j].fstype);
    323  1.8    manu 			printf("%s)", bootme ? ", bootme" : "");
    324  1.8    manu 		}
    325  1.8    manu 
    326  1.8    manu 		if (first == 0)
    327  1.8    manu 			printf("\n");
    328  1.8    manu 
    329  1.8    manu 		dealloc_biosdisk_part(part, nparts);
    330  1.1  nonaka 	}
    331  1.1  nonaka }
    332  1.1  nonaka 
    333  1.1  nonaka const struct efidiskinfo *
    334  1.1  nonaka efidisk_getinfo(int dev)
    335  1.1  nonaka {
    336  1.1  nonaka 	const struct efidiskinfo *edi;
    337  1.1  nonaka 
    338  1.1  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    339  1.1  nonaka 		if (dev == edi->dev)
    340  1.1  nonaka 			return edi;
    341  1.1  nonaka 	}
    342  1.1  nonaka 	return NULL;
    343  1.1  nonaka }
    344  1.1  nonaka 
    345  1.1  nonaka /*
    346  1.1  nonaka  * Return the number of hard disk drives.
    347  1.1  nonaka  */
    348  1.1  nonaka int
    349  1.1  nonaka get_harddrives(void)
    350  1.1  nonaka {
    351  1.1  nonaka 	return nefidisks;
    352  1.1  nonaka }
    353  1.5  nonaka 
    354  1.5  nonaka int
    355  1.5  nonaka efidisk_get_efi_system_partition(int dev, int *partition)
    356  1.5  nonaka {
    357  1.5  nonaka 	extern const struct uuid GET_efi;
    358  1.5  nonaka 	const struct efidiskinfo *edi;
    359  1.5  nonaka 	struct biosdisk_partition *part;
    360  1.5  nonaka 	int i, nparts;
    361  1.5  nonaka 
    362  1.5  nonaka 	edi = efidisk_getinfo(dev);
    363  1.5  nonaka 	if (edi == NULL)
    364  1.5  nonaka 		return ENXIO;
    365  1.5  nonaka 
    366  1.5  nonaka 	if (edi->type != BIOSDISK_TYPE_HD)
    367  1.5  nonaka 		return ENOTSUP;
    368  1.5  nonaka 
    369  1.8    manu 	if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
    370  1.5  nonaka 		return EIO;
    371  1.5  nonaka 
    372  1.5  nonaka 	for (i = 0; i < nparts; i++) {
    373  1.5  nonaka 		if (part[i].size == 0)
    374  1.5  nonaka 			continue;
    375  1.5  nonaka 		if (part[i].fstype == FS_UNUSED)
    376  1.5  nonaka 			continue;
    377  1.5  nonaka 		if (guid_is_equal(part[i].guid->guid, &GET_efi))
    378  1.5  nonaka 			break;
    379  1.5  nonaka 	}
    380  1.8    manu 	dealloc_biosdisk_part(part, nparts);
    381  1.5  nonaka 	if (i == nparts)
    382  1.5  nonaka 		return ENOENT;
    383  1.5  nonaka 
    384  1.5  nonaka 	*partition = i;
    385  1.5  nonaka 	return 0;
    386  1.5  nonaka }
    387