Home | History | Annotate | Line # | Download | only in efiboot
efidisk.c revision 1.6
      1  1.6  nonaka /*	$NetBSD: efidisk.c,v 1.6 2018/04/11 10:32:09 nonaka 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.2  nonaka #include <sys/disklabel.h>
     34  1.2  nonaka 
     35  1.2  nonaka #include "biosdisk.h"
     36  1.2  nonaka #include "biosdisk_ll.h"
     37  1.2  nonaka #include "devopen.h"
     38  1.1  nonaka #include "efidisk.h"
     39  1.1  nonaka 
     40  1.1  nonaka static struct efidiskinfo_lh efi_disklist;
     41  1.1  nonaka static int nefidisks;
     42  1.1  nonaka 
     43  1.1  nonaka void
     44  1.1  nonaka efi_disk_probe(void)
     45  1.1  nonaka {
     46  1.1  nonaka 	EFI_STATUS status;
     47  1.1  nonaka 	UINTN i, nhandles;
     48  1.1  nonaka 	EFI_HANDLE *handles;
     49  1.1  nonaka 	EFI_BLOCK_IO *bio;
     50  1.1  nonaka 	EFI_BLOCK_IO_MEDIA *media;
     51  1.2  nonaka 	EFI_DEVICE_PATH *dp;
     52  1.1  nonaka 	struct efidiskinfo *edi;
     53  1.2  nonaka 	int dev, depth = -1;
     54  1.1  nonaka 
     55  1.1  nonaka 	TAILQ_INIT(&efi_disklist);
     56  1.1  nonaka 
     57  1.1  nonaka 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
     58  1.1  nonaka 	    &nhandles, &handles);
     59  1.1  nonaka 	if (EFI_ERROR(status))
     60  1.4  nonaka 		panic("LocateHandle(BlockIoProtocol): %" PRIxMAX,
     61  1.4  nonaka 		    (uintmax_t)status);
     62  1.1  nonaka 
     63  1.2  nonaka 	if (efi_bootdp != NULL)
     64  1.2  nonaka 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
     65  1.2  nonaka 
     66  1.2  nonaka 	/*
     67  1.2  nonaka 	 * U-Boot incorrectly represents devices with a single
     68  1.2  nonaka 	 * MEDIA_DEVICE_PATH component.  In that case include that
     69  1.2  nonaka 	 * component into the matching, otherwise we'll blindly select
     70  1.2  nonaka 	 * the first device.
     71  1.2  nonaka 	 */
     72  1.2  nonaka 	if (depth == 0)
     73  1.2  nonaka 		depth = 1;
     74  1.2  nonaka 
     75  1.1  nonaka 	for (i = 0; i < nhandles; i++) {
     76  1.1  nonaka 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
     77  1.1  nonaka 		    &BlockIoProtocol, (void **)&bio);
     78  1.1  nonaka 		if (EFI_ERROR(status))
     79  1.4  nonaka 			panic("HandleProtocol(BlockIoProtocol): %" PRIxMAX,
     80  1.4  nonaka 			    (uintmax_t)status);
     81  1.1  nonaka 
     82  1.1  nonaka 		media = bio->Media;
     83  1.1  nonaka 		if (media->LogicalPartition || !media->MediaPresent)
     84  1.1  nonaka 			continue;
     85  1.1  nonaka 
     86  1.1  nonaka 		edi = alloc(sizeof(struct efidiskinfo));
     87  1.1  nonaka 		memset(edi, 0, sizeof(*edi));
     88  1.2  nonaka 		edi->type = BIOSDISK_TYPE_HD;
     89  1.1  nonaka 		edi->bio = bio;
     90  1.1  nonaka 		edi->media_id = media->MediaId;
     91  1.1  nonaka 
     92  1.2  nonaka 		if (efi_bootdp != NULL && depth > 0) {
     93  1.2  nonaka 			status = uefi_call_wrapper(BS->HandleProtocol, 3,
     94  1.2  nonaka 			    handles[i], &DevicePathProtocol, (void **)&dp);
     95  1.2  nonaka 			if (EFI_ERROR(status))
     96  1.2  nonaka 				goto next;
     97  1.2  nonaka 			if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
     98  1.2  nonaka 				edi->bootdev = true;
     99  1.2  nonaka 				TAILQ_INSERT_HEAD(&efi_disklist, edi,
    100  1.2  nonaka 				    list);
    101  1.2  nonaka 				continue;
    102  1.2  nonaka 			}
    103  1.2  nonaka 		}
    104  1.2  nonaka next:
    105  1.2  nonaka 		TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    106  1.2  nonaka 	}
    107  1.1  nonaka 
    108  1.2  nonaka 	FreePool(handles);
    109  1.1  nonaka 
    110  1.6  nonaka 	if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
    111  1.3  nonaka 		edi = TAILQ_FIRST(&efi_disklist);
    112  1.3  nonaka 		if (edi != NULL && edi->bootdev) {
    113  1.3  nonaka 			edi->type = BIOSDISK_TYPE_CD;
    114  1.3  nonaka 			TAILQ_REMOVE(&efi_disklist, edi, list);
    115  1.3  nonaka 			TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    116  1.1  nonaka 		}
    117  1.1  nonaka 	}
    118  1.1  nonaka 
    119  1.1  nonaka 	dev = 0x80;
    120  1.1  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    121  1.1  nonaka 		edi->dev = dev++;
    122  1.2  nonaka 		if (edi->type == BIOSDISK_TYPE_HD)
    123  1.2  nonaka 			nefidisks++;
    124  1.2  nonaka 		if (edi->bootdev)
    125  1.2  nonaka 			boot_biosdev = edi->dev;
    126  1.2  nonaka 	}
    127  1.2  nonaka }
    128  1.2  nonaka 
    129  1.2  nonaka void
    130  1.2  nonaka efi_disk_show(void)
    131  1.2  nonaka {
    132  1.2  nonaka 	const struct efidiskinfo *edi;
    133  1.2  nonaka 	EFI_BLOCK_IO_MEDIA *media;
    134  1.2  nonaka 	struct biosdisk_partition *part;
    135  1.2  nonaka 	uint64_t size;
    136  1.2  nonaka 	int i, nparts;
    137  1.2  nonaka 	bool first;
    138  1.2  nonaka 
    139  1.2  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    140  1.2  nonaka 		media = edi->bio->Media;
    141  1.2  nonaka 		first = true;
    142  1.2  nonaka 		printf("disk ");
    143  1.2  nonaka 		switch (edi->type) {
    144  1.2  nonaka 		case BIOSDISK_TYPE_CD:
    145  1.2  nonaka 			printf("cd0");
    146  1.2  nonaka 			printf(" mediaId %u", media->MediaId);
    147  1.2  nonaka 			if (edi->media_id != media->MediaId)
    148  1.2  nonaka 				printf("(%u)", edi->media_id);
    149  1.2  nonaka 			printf("\n");
    150  1.2  nonaka 			printf("  cd0a\n");
    151  1.2  nonaka 			break;
    152  1.2  nonaka 		case BIOSDISK_TYPE_HD:
    153  1.2  nonaka 			printf("hd%d", edi->dev & 0x7f);
    154  1.2  nonaka 			printf(" mediaId %u", media->MediaId);
    155  1.2  nonaka 			if (edi->media_id != media->MediaId)
    156  1.2  nonaka 				printf("(%u)", edi->media_id);
    157  1.2  nonaka 			printf(" size ");
    158  1.2  nonaka 			size = (media->LastBlock + 1) * media->BlockSize;
    159  1.2  nonaka 			if (size >= (10ULL * 1024 * 1024 * 1024))
    160  1.2  nonaka 				printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
    161  1.2  nonaka 			else
    162  1.2  nonaka 				printf("%"PRIu64" MB", size / (1024 * 1024));
    163  1.2  nonaka 			printf("\n");
    164  1.2  nonaka 			break;
    165  1.2  nonaka 		}
    166  1.2  nonaka 		if (edi->type != BIOSDISK_TYPE_HD)
    167  1.2  nonaka 			continue;
    168  1.2  nonaka 
    169  1.2  nonaka 		if (biosdisk_readpartition(edi->dev, &part, &nparts))
    170  1.2  nonaka 			continue;
    171  1.2  nonaka 
    172  1.2  nonaka 		for (i = 0; i < nparts; i++) {
    173  1.2  nonaka 			if (part[i].size == 0)
    174  1.2  nonaka 				continue;
    175  1.2  nonaka 			if (part[i].fstype == FS_UNUSED)
    176  1.2  nonaka 				continue;
    177  1.2  nonaka 			if (first) {
    178  1.2  nonaka 				printf(" ");
    179  1.2  nonaka 				first = false;
    180  1.2  nonaka 			}
    181  1.2  nonaka 			printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
    182  1.2  nonaka 			if (part[i].guid != NULL)
    183  1.2  nonaka 				printf("%s", part[i].guid->name);
    184  1.2  nonaka 			else if (part[i].fstype < FSMAXTYPES)
    185  1.2  nonaka 				printf("%s", fstypenames[part[i].fstype]);
    186  1.2  nonaka 			else
    187  1.2  nonaka 				printf("%d", part[i].fstype);
    188  1.2  nonaka 			printf(")");
    189  1.2  nonaka 		}
    190  1.2  nonaka 		if (!first)
    191  1.2  nonaka 			printf("\n");
    192  1.2  nonaka 		dealloc(part, sizeof(*part) * nparts);
    193  1.1  nonaka 	}
    194  1.1  nonaka }
    195  1.1  nonaka 
    196  1.1  nonaka const struct efidiskinfo *
    197  1.1  nonaka efidisk_getinfo(int dev)
    198  1.1  nonaka {
    199  1.1  nonaka 	const struct efidiskinfo *edi;
    200  1.1  nonaka 
    201  1.1  nonaka 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    202  1.1  nonaka 		if (dev == edi->dev)
    203  1.1  nonaka 			return edi;
    204  1.1  nonaka 	}
    205  1.1  nonaka 	return NULL;
    206  1.1  nonaka }
    207  1.1  nonaka 
    208  1.1  nonaka /*
    209  1.1  nonaka  * Return the number of hard disk drives.
    210  1.1  nonaka  */
    211  1.1  nonaka int
    212  1.1  nonaka get_harddrives(void)
    213  1.1  nonaka {
    214  1.1  nonaka 	return nefidisks;
    215  1.1  nonaka }
    216  1.5  nonaka 
    217  1.5  nonaka int
    218  1.5  nonaka efidisk_get_efi_system_partition(int dev, int *partition)
    219  1.5  nonaka {
    220  1.5  nonaka 	extern const struct uuid GET_efi;
    221  1.5  nonaka 	const struct efidiskinfo *edi;
    222  1.5  nonaka 	struct biosdisk_partition *part;
    223  1.5  nonaka 	int i, nparts;
    224  1.5  nonaka 
    225  1.5  nonaka 	edi = efidisk_getinfo(dev);
    226  1.5  nonaka 	if (edi == NULL)
    227  1.5  nonaka 		return ENXIO;
    228  1.5  nonaka 
    229  1.5  nonaka 	if (edi->type != BIOSDISK_TYPE_HD)
    230  1.5  nonaka 		return ENOTSUP;
    231  1.5  nonaka 
    232  1.5  nonaka 	if (biosdisk_readpartition(edi->dev, &part, &nparts))
    233  1.5  nonaka 		return EIO;
    234  1.5  nonaka 
    235  1.5  nonaka 	for (i = 0; i < nparts; i++) {
    236  1.5  nonaka 		if (part[i].size == 0)
    237  1.5  nonaka 			continue;
    238  1.5  nonaka 		if (part[i].fstype == FS_UNUSED)
    239  1.5  nonaka 			continue;
    240  1.5  nonaka 		if (guid_is_equal(part[i].guid->guid, &GET_efi))
    241  1.5  nonaka 			break;
    242  1.5  nonaka 	}
    243  1.5  nonaka 	dealloc(part, sizeof(*part) * nparts);
    244  1.5  nonaka 	if (i == nparts)
    245  1.5  nonaka 		return ENOENT;
    246  1.5  nonaka 
    247  1.5  nonaka 	*partition = i;
    248  1.5  nonaka 	return 0;
    249  1.5  nonaka }
    250