]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - wimboot/wimboot-2.7.3/src/efiblock.c
1. Optimization for WIMBOOT mode.
[Ventoy.git] / wimboot / wimboot-2.7.3 / src / efiblock.c
1 /*
2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 /**
21 * @file
22 *
23 * EFI block device
24 *
25 */
26
27 #include <stddef.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include "wimboot.h"
31 #include "vdisk.h"
32 #include "efi.h"
33 #include "efipath.h"
34 #include "efiblock.h"
35
36 /** A block I/O device */
37 struct efi_block {
38 /** EFI block I/O protocol */
39 EFI_BLOCK_IO_PROTOCOL block;
40 /** Device path */
41 EFI_DEVICE_PATH_PROTOCOL *path;
42 /** Starting LBA */
43 uint64_t lba;
44 /** Name */
45 const char *name;
46 };
47
48 /**
49 * Reset block I/O protocol
50 *
51 * @v this Block I/O protocol
52 * @v extended Perform extended verification
53 * @ret efirc EFI status code
54 */
55 static EFI_STATUS EFIAPI
56 efi_reset_blocks ( EFI_BLOCK_IO_PROTOCOL *this, BOOLEAN extended ) {
57 struct efi_block *block =
58 container_of ( this, struct efi_block, block );
59 void *retaddr = __builtin_return_address ( 0 );
60
61 DBG2 ( "EFI %s %sreset -> %p\n",
62 block->name, ( extended ? "extended " : "" ), retaddr );
63 return 0;
64 }
65
66 /**
67 * Read blocks
68 *
69 * @v this Block I/O protocol
70 * @v media Media ID
71 * @v lba Starting LBA
72 * @v len Length of data
73 * @v data Data buffer
74 * @ret efirc EFI status code
75 */
76 static EFI_STATUS EFIAPI
77 efi_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this, UINT32 media, EFI_LBA lba,
78 UINTN len, VOID *data ) {
79 struct efi_block *block =
80 container_of ( this, struct efi_block, block );
81 void *retaddr = __builtin_return_address ( 0 );
82
83 DBG2 ( "EFI %s read media %08x LBA %#llx to %p+%zx -> %p\n",
84 block->name, media, lba, data, ( ( size_t ) len ), retaddr );
85 vdisk_read ( ( lba + block->lba ), ( len / VDISK_SECTOR_SIZE ), data );
86 return 0;
87 }
88
89 /**
90 * Write blocks
91 *
92 * @v this Block I/O protocol
93 * @v media Media ID
94 * @v lba Starting LBA
95 * @v len Length of data
96 * @v data Data buffer
97 * @ret efirc EFI status code
98 */
99 static EFI_STATUS EFIAPI
100 efi_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
101 UINT32 media __unused, EFI_LBA lba __unused,
102 UINTN len __unused, VOID *data __unused ) {
103 struct efi_block *block =
104 container_of ( this, struct efi_block, block );
105 void *retaddr = __builtin_return_address ( 0 );
106
107 DBG2 ( "EFI %s write media %08x LBA %#llx from %p+%zx -> %p\n",
108 block->name, media, lba, data, ( ( size_t ) len ), retaddr );
109 return EFI_WRITE_PROTECTED;
110 }
111
112 /**
113 * Flush block operations
114 *
115 * @v this Block I/O protocol
116 * @ret efirc EFI status code
117 */
118 static EFI_STATUS EFIAPI
119 efi_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this ) {
120 struct efi_block *block =
121 container_of ( this, struct efi_block, block );
122 void *retaddr = __builtin_return_address ( 0 );
123
124 DBG2 ( "EFI %s flush -> %p\n", block->name, retaddr );
125 return 0;
126 }
127
128 /** GUID used in vendor device path */
129 #define EFIBLOCK_GUID { \
130 0x1322d197, 0x15dc, 0x4a45, \
131 { 0xa6, 0xa4, 0xfa, 0x57, 0x05, 0x4e, 0xa6, 0x14 } \
132 }
133
134 /**
135 * Initialise vendor device path
136 *
137 * @v name Variable name
138 */
139 #define EFIBLOCK_DEVPATH_VENDOR_INIT( name ) { \
140 .Header = EFI_DEVPATH_INIT ( name, HARDWARE_DEVICE_PATH, \
141 HW_VENDOR_DP ), \
142 .Guid = EFIBLOCK_GUID, \
143 }
144
145 /**
146 * Initialise ATA device path
147 *
148 * @v name Variable name
149 */
150 #define EFIBLOCK_DEVPATH_ATA_INIT( name ) { \
151 .Header = EFI_DEVPATH_INIT ( name, MESSAGING_DEVICE_PATH, \
152 MSG_ATAPI_DP ), \
153 .PrimarySecondary = 0, \
154 .SlaveMaster = 0, \
155 .Lun = 0, \
156 }
157
158 /**
159 * Initialise hard disk device path
160 *
161 * @v name Variable name
162 */
163 #define EFIBLOCK_DEVPATH_HD_INIT( name ) { \
164 .Header = EFI_DEVPATH_INIT ( name, MEDIA_DEVICE_PATH, \
165 MEDIA_HARDDRIVE_DP ), \
166 .PartitionNumber = 1, \
167 .PartitionStart = VDISK_PARTITION_LBA, \
168 .PartitionSize = VDISK_PARTITION_COUNT, \
169 .Signature[0] = ( ( VDISK_MBR_SIGNATURE >> 0 ) & 0xff ), \
170 .Signature[1] = ( ( VDISK_MBR_SIGNATURE >> 8 ) & 0xff ), \
171 .Signature[2] = ( ( VDISK_MBR_SIGNATURE >> 16 ) & 0xff ), \
172 .Signature[3] = ( ( VDISK_MBR_SIGNATURE >> 24 ) & 0xff ), \
173 .MBRType = MBR_TYPE_PCAT, \
174 .SignatureType = SIGNATURE_TYPE_MBR, \
175 }
176
177 /** Virtual disk media */
178 static EFI_BLOCK_IO_MEDIA efi_vdisk_media = {
179 .MediaId = VDISK_MBR_SIGNATURE,
180 .MediaPresent = TRUE,
181 .LogicalPartition = FALSE,
182 .ReadOnly = TRUE,
183 .BlockSize = VDISK_SECTOR_SIZE,
184 .LastBlock = ( VDISK_COUNT - 1 ),
185 };
186
187 /** Virtual disk device path */
188 static struct {
189 VENDOR_DEVICE_PATH vendor;
190 ATAPI_DEVICE_PATH ata;
191 EFI_DEVICE_PATH_PROTOCOL end;
192 } __attribute__ (( packed )) efi_vdisk_path = {
193 .vendor = EFIBLOCK_DEVPATH_VENDOR_INIT ( efi_vdisk_path.vendor ),
194 .ata = EFIBLOCK_DEVPATH_ATA_INIT ( efi_vdisk_path.ata ),
195 .end = EFI_DEVPATH_END_INIT ( efi_vdisk_path.end ),
196 };
197
198 /** Virtual disk device */
199 static struct efi_block efi_vdisk = {
200 .block = {
201 .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
202 .Media = &efi_vdisk_media,
203 .Reset = efi_reset_blocks,
204 .ReadBlocks = efi_read_blocks,
205 .WriteBlocks = efi_write_blocks,
206 .FlushBlocks = efi_flush_blocks,
207 },
208 .path = &efi_vdisk_path.vendor.Header,
209 .lba = 0,
210 .name = "vdisk",
211 };
212
213 /** Virtual partition media */
214 static EFI_BLOCK_IO_MEDIA efi_vpartition_media = {
215 .MediaId = VDISK_MBR_SIGNATURE,
216 .MediaPresent = TRUE,
217 .LogicalPartition = TRUE,
218 .ReadOnly = TRUE,
219 .BlockSize = VDISK_SECTOR_SIZE,
220 .LastBlock = ( VDISK_PARTITION_COUNT - 1 ),
221 };
222
223 /** Virtual partition device path */
224 static struct {
225 VENDOR_DEVICE_PATH vendor;
226 ATAPI_DEVICE_PATH ata;
227 HARDDRIVE_DEVICE_PATH hd;
228 EFI_DEVICE_PATH_PROTOCOL end;
229 } __attribute__ (( packed )) efi_vpartition_path = {
230 .vendor = EFIBLOCK_DEVPATH_VENDOR_INIT ( efi_vpartition_path.vendor ),
231 .ata = EFIBLOCK_DEVPATH_ATA_INIT ( efi_vpartition_path.ata ),
232 .hd = EFIBLOCK_DEVPATH_HD_INIT ( efi_vpartition_path.hd ),
233 .end = EFI_DEVPATH_END_INIT ( efi_vpartition_path.end ),
234 };
235
236 /** Virtual partition device */
237 static struct efi_block efi_vpartition = {
238 .block = {
239 .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
240 .Media = &efi_vpartition_media,
241 .Reset = efi_reset_blocks,
242 .ReadBlocks = efi_read_blocks,
243 .WriteBlocks = efi_write_blocks,
244 .FlushBlocks = efi_flush_blocks,
245 },
246 .path = &efi_vpartition_path.vendor.Header,
247 .lba = VDISK_PARTITION_LBA,
248 .name = "vpartition",
249 };
250
251 /**
252 * Install block I/O protocols
253 *
254 * @ret vdisk New virtual disk handle
255 * @ret vpartition New virtual partition handle
256 */
257 void efi_install ( EFI_HANDLE *vdisk, EFI_HANDLE *vpartition ) {
258 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
259 EFI_STATUS efirc;
260
261 /* Install virtual disk */
262 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
263 vdisk,
264 &efi_block_io_protocol_guid, &efi_vdisk.block,
265 &efi_device_path_protocol_guid, efi_vdisk.path,
266 NULL ) ) != 0 ) {
267 die ( "Could not install disk block I/O protocols: %#lx\n",
268 ( ( unsigned long ) efirc ) );
269 }
270
271 /* Install virtual partition */
272 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
273 vpartition,
274 &efi_block_io_protocol_guid, &efi_vpartition.block,
275 &efi_device_path_protocol_guid, efi_vpartition.path,
276 NULL ) ) != 0 ) {
277 die ( "Could not install partition block I/O protocols: %#lx\n",
278 ( ( unsigned long ) efirc ) );
279 }
280 }
281
282 /** Boot image path */
283 static struct {
284 VENDOR_DEVICE_PATH vendor;
285 ATAPI_DEVICE_PATH ata;
286 HARDDRIVE_DEVICE_PATH hd;
287 struct {
288 EFI_DEVICE_PATH header;
289 CHAR16 name[ sizeof ( EFI_REMOVABLE_MEDIA_FILE_NAME ) /
290 sizeof ( CHAR16 ) ];
291 } __attribute__ (( packed )) file;
292 EFI_DEVICE_PATH_PROTOCOL end;
293 } __attribute__ (( packed )) efi_bootmgfw_path = {
294 .vendor = EFIBLOCK_DEVPATH_VENDOR_INIT ( efi_bootmgfw_path.vendor ),
295 .ata = EFIBLOCK_DEVPATH_ATA_INIT ( efi_bootmgfw_path.ata ),
296 .hd = EFIBLOCK_DEVPATH_HD_INIT ( efi_bootmgfw_path.hd ),
297 .file = {
298 .header = EFI_DEVPATH_INIT ( efi_bootmgfw_path.file,
299 MEDIA_DEVICE_PATH,
300 MEDIA_FILEPATH_DP ),
301 .name = EFI_REMOVABLE_MEDIA_FILE_NAME,
302 },
303 .end = EFI_DEVPATH_END_INIT ( efi_bootmgfw_path.end ),
304 };
305
306 /** Boot image path */
307 EFI_DEVICE_PATH_PROTOCOL *bootmgfw_path = &efi_bootmgfw_path.vendor.Header;