2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
36 /** A block I/O device */
38 /** EFI block I/O protocol */
39 EFI_BLOCK_IO_PROTOCOL block
;
41 EFI_DEVICE_PATH_PROTOCOL
*path
;
49 * Reset block I/O protocol
51 * @v this Block I/O protocol
52 * @v extended Perform extended verification
53 * @ret efirc EFI status code
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 );
61 DBG2 ( "EFI %s %sreset -> %p\n",
62 block
->name
, ( extended
? "extended " : "" ), retaddr
);
69 * @v this Block I/O protocol
72 * @v len Length of data
74 * @ret efirc EFI status code
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 );
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
);
92 * @v this Block I/O protocol
95 * @v len Length of data
97 * @ret efirc EFI status code
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 );
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
;
113 * Flush block operations
115 * @v this Block I/O protocol
116 * @ret efirc EFI status code
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 );
124 DBG2 ( "EFI %s flush -> %p\n", block
->name
, retaddr
);
128 /** GUID used in vendor device path */
129 #define EFIBLOCK_GUID { \
130 0x1322d197, 0x15dc, 0x4a45, \
131 { 0xa6, 0xa4, 0xfa, 0x57, 0x05, 0x4e, 0xa6, 0x14 } \
135 * Initialise vendor device path
137 * @v name Variable name
139 #define EFIBLOCK_DEVPATH_VENDOR_INIT( name ) { \
140 .Header = EFI_DEVPATH_INIT ( name, HARDWARE_DEVICE_PATH, \
142 .Guid = EFIBLOCK_GUID, \
146 * Initialise ATA device path
148 * @v name Variable name
150 #define EFIBLOCK_DEVPATH_ATA_INIT( name ) { \
151 .Header = EFI_DEVPATH_INIT ( name, MESSAGING_DEVICE_PATH, \
153 .PrimarySecondary = 0, \
159 * Initialise hard disk device path
161 * @v name Variable name
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, \
177 /** Virtual disk media */
178 static EFI_BLOCK_IO_MEDIA efi_vdisk_media
= {
179 .MediaId
= VDISK_MBR_SIGNATURE
,
180 .MediaPresent
= TRUE
,
181 .LogicalPartition
= FALSE
,
183 .BlockSize
= VDISK_SECTOR_SIZE
,
184 .LastBlock
= ( VDISK_COUNT
- 1 ),
187 /** Virtual disk device path */
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
),
198 /** Virtual disk device */
199 static struct efi_block efi_vdisk
= {
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
,
208 .path
= &efi_vdisk_path
.vendor
.Header
,
213 /** Virtual partition media */
214 static EFI_BLOCK_IO_MEDIA efi_vpartition_media
= {
215 .MediaId
= VDISK_MBR_SIGNATURE
,
216 .MediaPresent
= TRUE
,
217 .LogicalPartition
= TRUE
,
219 .BlockSize
= VDISK_SECTOR_SIZE
,
220 .LastBlock
= ( VDISK_PARTITION_COUNT
- 1 ),
223 /** Virtual partition device path */
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
),
236 /** Virtual partition device */
237 static struct efi_block efi_vpartition
= {
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
,
246 .path
= &efi_vpartition_path
.vendor
.Header
,
247 .lba
= VDISK_PARTITION_LBA
,
248 .name
= "vpartition",
252 * Install block I/O protocols
254 * @ret vdisk New virtual disk handle
255 * @ret vpartition New virtual partition handle
257 void efi_install ( EFI_HANDLE
*vdisk
, EFI_HANDLE
*vpartition
) {
258 EFI_BOOT_SERVICES
*bs
= efi_systab
->BootServices
;
261 /* Install virtual disk */
262 if ( ( efirc
= bs
->InstallMultipleProtocolInterfaces (
264 &efi_block_io_protocol_guid
, &efi_vdisk
.block
,
265 &efi_device_path_protocol_guid
, efi_vdisk
.path
,
267 die ( "Could not install disk block I/O protocols: %#lx\n",
268 ( ( unsigned long ) efirc
) );
271 /* Install virtual partition */
272 if ( ( efirc
= bs
->InstallMultipleProtocolInterfaces (
274 &efi_block_io_protocol_guid
, &efi_vpartition
.block
,
275 &efi_device_path_protocol_guid
, efi_vpartition
.path
,
277 die ( "Could not install partition block I/O protocols: %#lx\n",
278 ( ( unsigned long ) efirc
) );
282 /** Boot image path */
284 VENDOR_DEVICE_PATH vendor
;
285 ATAPI_DEVICE_PATH ata
;
286 HARDDRIVE_DEVICE_PATH hd
;
288 EFI_DEVICE_PATH header
;
289 CHAR16 name
[ sizeof ( EFI_REMOVABLE_MEDIA_FILE_NAME
) /
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
),
298 .header
= EFI_DEVPATH_INIT ( efi_bootmgfw_path
.file
,
301 .name
= EFI_REMOVABLE_MEDIA_FILE_NAME
,
303 .end
= EFI_DEVPATH_END_INIT ( efi_bootmgfw_path
.end
),
306 /** Boot image path */
307 EFI_DEVICE_PATH_PROTOCOL
*bootmgfw_path
= &efi_bootmgfw_path
.vendor
.Header
;