Home | History | Annotate | Line # | Download | only in efiboot
efidisk.c revision 1.4
      1 /*	$NetBSD: efidisk.c,v 1.4 2018/03/27 14:15:05 nonaka Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #define FSTYPENAMES	/* for sys/disklabel.h */
     30 
     31 #include "efiboot.h"
     32 
     33 #include <sys/disklabel.h>
     34 
     35 #include "biosdisk.h"
     36 #include "biosdisk_ll.h"
     37 #include "devopen.h"
     38 #include "efidisk.h"
     39 
     40 static struct efidiskinfo_lh efi_disklist;
     41 static int nefidisks;
     42 
     43 void
     44 efi_disk_probe(void)
     45 {
     46 	EFI_STATUS status;
     47 	UINTN i, nhandles;
     48 	EFI_HANDLE *handles;
     49 	EFI_BLOCK_IO *bio;
     50 	EFI_BLOCK_IO_MEDIA *media;
     51 	EFI_DEVICE_PATH *dp;
     52 	struct efidiskinfo *edi;
     53 	int dev, depth = -1;
     54 
     55 	TAILQ_INIT(&efi_disklist);
     56 
     57 	status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
     58 	    &nhandles, &handles);
     59 	if (EFI_ERROR(status))
     60 		panic("LocateHandle(BlockIoProtocol): %" PRIxMAX,
     61 		    (uintmax_t)status);
     62 
     63 	if (efi_bootdp != NULL)
     64 		depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
     65 
     66 	/*
     67 	 * U-Boot incorrectly represents devices with a single
     68 	 * MEDIA_DEVICE_PATH component.  In that case include that
     69 	 * component into the matching, otherwise we'll blindly select
     70 	 * the first device.
     71 	 */
     72 	if (depth == 0)
     73 		depth = 1;
     74 
     75 	for (i = 0; i < nhandles; i++) {
     76 		status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
     77 		    &BlockIoProtocol, (void **)&bio);
     78 		if (EFI_ERROR(status))
     79 			panic("HandleProtocol(BlockIoProtocol): %" PRIxMAX,
     80 			    (uintmax_t)status);
     81 
     82 		media = bio->Media;
     83 		if (media->LogicalPartition || !media->MediaPresent)
     84 			continue;
     85 
     86 		edi = alloc(sizeof(struct efidiskinfo));
     87 		memset(edi, 0, sizeof(*edi));
     88 		edi->type = BIOSDISK_TYPE_HD;
     89 		edi->bio = bio;
     90 		edi->media_id = media->MediaId;
     91 
     92 		if (efi_bootdp != NULL && depth > 0) {
     93 			status = uefi_call_wrapper(BS->HandleProtocol, 3,
     94 			    handles[i], &DevicePathProtocol, (void **)&dp);
     95 			if (EFI_ERROR(status))
     96 				goto next;
     97 			if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
     98 				edi->bootdev = true;
     99 				TAILQ_INSERT_HEAD(&efi_disklist, edi,
    100 				    list);
    101 				continue;
    102 			}
    103 		}
    104 next:
    105 		TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    106 	}
    107 
    108 	FreePool(handles);
    109 
    110 	if (efi_bootdp_type == BIOSDISK_TYPE_CD) {
    111 		edi = TAILQ_FIRST(&efi_disklist);
    112 		if (edi != NULL && edi->bootdev) {
    113 			edi->type = BIOSDISK_TYPE_CD;
    114 			TAILQ_REMOVE(&efi_disklist, edi, list);
    115 			TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
    116 		}
    117 	}
    118 
    119 	dev = 0x80;
    120 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    121 		edi->dev = dev++;
    122 		if (edi->type == BIOSDISK_TYPE_HD)
    123 			nefidisks++;
    124 		if (edi->bootdev)
    125 			boot_biosdev = edi->dev;
    126 	}
    127 }
    128 
    129 void
    130 efi_disk_show(void)
    131 {
    132 	const struct efidiskinfo *edi;
    133 	EFI_BLOCK_IO_MEDIA *media;
    134 	struct biosdisk_partition *part;
    135 	uint64_t size;
    136 	int i, nparts;
    137 	bool first;
    138 
    139 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    140 		media = edi->bio->Media;
    141 		first = true;
    142 		printf("disk ");
    143 		switch (edi->type) {
    144 		case BIOSDISK_TYPE_CD:
    145 			printf("cd0");
    146 			printf(" mediaId %u", media->MediaId);
    147 			if (edi->media_id != media->MediaId)
    148 				printf("(%u)", edi->media_id);
    149 			printf("\n");
    150 			printf("  cd0a\n");
    151 			break;
    152 		case BIOSDISK_TYPE_HD:
    153 			printf("hd%d", edi->dev & 0x7f);
    154 			printf(" mediaId %u", media->MediaId);
    155 			if (edi->media_id != media->MediaId)
    156 				printf("(%u)", edi->media_id);
    157 			printf(" size ");
    158 			size = (media->LastBlock + 1) * media->BlockSize;
    159 			if (size >= (10ULL * 1024 * 1024 * 1024))
    160 				printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
    161 			else
    162 				printf("%"PRIu64" MB", size / (1024 * 1024));
    163 			printf("\n");
    164 			break;
    165 		}
    166 		if (edi->type != BIOSDISK_TYPE_HD)
    167 			continue;
    168 
    169 		if (biosdisk_readpartition(edi->dev, &part, &nparts))
    170 			continue;
    171 
    172 		for (i = 0; i < nparts; i++) {
    173 			if (part[i].size == 0)
    174 				continue;
    175 			if (part[i].fstype == FS_UNUSED)
    176 				continue;
    177 			if (first) {
    178 				printf(" ");
    179 				first = false;
    180 			}
    181 			printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
    182 			if (part[i].guid != NULL)
    183 				printf("%s", part[i].guid->name);
    184 			else if (part[i].fstype < FSMAXTYPES)
    185 				printf("%s", fstypenames[part[i].fstype]);
    186 			else
    187 				printf("%d", part[i].fstype);
    188 			printf(")");
    189 		}
    190 		if (!first)
    191 			printf("\n");
    192 		dealloc(part, sizeof(*part) * nparts);
    193 	}
    194 }
    195 
    196 const struct efidiskinfo *
    197 efidisk_getinfo(int dev)
    198 {
    199 	const struct efidiskinfo *edi;
    200 
    201 	TAILQ_FOREACH(edi, &efi_disklist, list) {
    202 		if (dev == edi->dev)
    203 			return edi;
    204 	}
    205 	return NULL;
    206 }
    207 
    208 /*
    209  * Return the number of hard disk drives.
    210  */
    211 int
    212 get_harddrives(void)
    213 {
    214 	return nefidisks;
    215 }
    216