Browse Source

[efi] Expose downloaded images via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL

Expose iPXE's images as a UEFI file system, allowing the booted image
to access all images downloaded by iPXE.

This functionality is complementary to the custom iPXE download
protocol.  The iPXE download protocol allows a booted image to utilise
iPXE to download arbitrary URIs, but requires the booted image to
specifically support the custom iPXE download protocol.  The new
functionality limits the booted image to accessing only files that
were already downloaded by iPXE (e.g. as part of a script), but can
work with any generic UEFI image (e.g. the UEFI shell).  Both
protocols are provided simultaneously, and are attached to the SNP
device handle.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
fc87adb46c

+ 139
- 92
src/image/efi_image.c View File

21
 
21
 
22
 #include <errno.h>
22
 #include <errno.h>
23
 #include <stdlib.h>
23
 #include <stdlib.h>
24
+#include <wchar.h>
24
 #include <ipxe/efi/efi.h>
25
 #include <ipxe/efi/efi.h>
26
+#include <ipxe/efi/efi_snp.h>
27
+#include <ipxe/efi/efi_download.h>
28
+#include <ipxe/efi/efi_file.h>
29
+#include <ipxe/efi/efi_driver.h>
30
+#include <ipxe/efi/efi_strings.h>
25
 #include <ipxe/image.h>
31
 #include <ipxe/image.h>
26
 #include <ipxe/init.h>
32
 #include <ipxe/init.h>
27
 #include <ipxe/features.h>
33
 #include <ipxe/features.h>
34
 	EFI_LOADED_IMAGE_PROTOCOL_GUID;
40
 	EFI_LOADED_IMAGE_PROTOCOL_GUID;
35
 
41
 
36
 /**
42
 /**
37
- * Create a Unicode command line for the image
43
+ * Create device path for image
44
+ *
45
+ * @v image		EFI image
46
+ * @v parent		Parent device path
47
+ * @ret path		Device path, or NULL on failure
48
+ *
49
+ * The caller must eventually free() the device path.
50
+ */
51
+static EFI_DEVICE_PATH_PROTOCOL * efi_image_path ( struct image *image,
52
+						   EFI_DEVICE_PATH *parent ) {
53
+	EFI_DEVICE_PATH_PROTOCOL *path;
54
+	FILEPATH_DEVICE_PATH *filepath;
55
+	EFI_DEVICE_PATH_PROTOCOL *end;
56
+	size_t name_len;
57
+	size_t prefix_len;
58
+	size_t filepath_len;
59
+	size_t len;
60
+
61
+	/* Calculate device path lengths */
62
+	end = efi_devpath_end ( parent );
63
+	prefix_len = ( ( void * ) end - ( void * ) parent );
64
+	name_len = strlen ( image->name );
65
+	filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH +
66
+			 ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
67
+	len = ( prefix_len + filepath_len + sizeof ( *end ) );
68
+
69
+	/* Allocate device path */
70
+	path = zalloc ( len );
71
+	if ( ! path )
72
+		return NULL;
73
+
74
+	/* Construct device path */
75
+	memcpy ( path, parent, prefix_len );
76
+	filepath = ( ( ( void * ) path ) + prefix_len );
77
+	filepath->Header.Type = MEDIA_DEVICE_PATH;
78
+	filepath->Header.SubType = MEDIA_FILEPATH_DP;
79
+	filepath->Header.Length[0] = ( filepath_len & 0xff );
80
+	filepath->Header.Length[1] = ( filepath_len >> 8 );
81
+	efi_snprintf ( filepath->PathName, ( name_len + 1 /* NUL */ ),
82
+		       "%s", image->name );
83
+	end = ( ( ( void * ) filepath ) + filepath_len );
84
+	end->Type = END_DEVICE_PATH_TYPE;
85
+	end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
86
+	end->Length[0] = sizeof ( *end );
87
+
88
+	return path;
89
+}
90
+
91
+/**
92
+ * Create command line for image
38
  *
93
  *
39
  * @v image             EFI image
94
  * @v image             EFI image
40
- * @v devpath_out       Device path to pass to image (output)
41
- * @v cmdline_out       Unicode command line (output)
42
- * @v cmdline_len_out   Length of command line in bytes (output)
43
- * @ret rc              Return status code
95
+ * @ret cmdline		Command line, or NULL on failure
44
  */
96
  */
45
-static int efi_image_make_cmdline ( struct image *image,
46
-				    EFI_DEVICE_PATH **devpath_out,
47
-				    VOID **cmdline_out,
48
-				    UINT32 *cmdline_len_out ) {
49
-	char *uri;
50
-	size_t uri_len;
51
-	FILEPATH_DEVICE_PATH *devpath;
52
-	EFI_DEVICE_PATH *endpath;
53
-	size_t devpath_len;
54
-	CHAR16 *cmdline;
55
-	UINT32 cmdline_len;
56
-	size_t args_len = 0;
57
-	UINT32 i;
58
-
59
-	/* Get the URI string of the image */
60
-	uri_len = unparse_uri ( NULL, 0, image->uri, URI_ALL ) + 1;
61
-
62
-	/* Compute final command line length */
63
-	if ( image->cmdline ) {
64
-		args_len = strlen ( image->cmdline ) + 1;
65
-	}
66
-	cmdline_len = args_len + uri_len;
97
+static wchar_t * efi_image_cmdline ( struct image *image ) {
98
+	wchar_t *cmdline;
99
+	size_t len;
67
 
100
 
68
-	/* Allocate space for the uri, final command line and device path */
69
-	cmdline = malloc ( cmdline_len * sizeof ( CHAR16 ) + uri_len
70
-			   + SIZE_OF_FILEPATH_DEVICE_PATH
71
-			   + uri_len * sizeof ( CHAR16 )
72
-			   + sizeof ( EFI_DEVICE_PATH ) );
101
+	len = ( strlen ( image->name ) +
102
+		( image->cmdline ?
103
+		  ( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) );
104
+	cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
73
 	if ( ! cmdline )
105
 	if ( ! cmdline )
74
-		return -ENOMEM;
75
-	uri = (char *) ( cmdline + cmdline_len );
76
-	devpath = (FILEPATH_DEVICE_PATH *) ( uri + uri_len );
77
-	endpath = (EFI_DEVICE_PATH *) ( (char *) devpath
78
-					+ SIZE_OF_FILEPATH_DEVICE_PATH
79
-					+ uri_len * sizeof ( CHAR16 ) );
80
-
81
-	/* Build the iPXE device path */
82
-	devpath->Header.Type = MEDIA_DEVICE_PATH;
83
-	devpath->Header.SubType = MEDIA_FILEPATH_DP;
84
-	devpath_len = SIZE_OF_FILEPATH_DEVICE_PATH
85
-			+ uri_len * sizeof ( CHAR16 );
86
-	devpath->Header.Length[0] = devpath_len & 0xFF;
87
-	devpath->Header.Length[1] = devpath_len >> 8;
88
-	endpath->Type = END_DEVICE_PATH_TYPE;
89
-	endpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
90
-	endpath->Length[0] = 4;
91
-	endpath->Length[1] = 0;
92
-	unparse_uri ( uri, uri_len, image->uri, URI_ALL );
93
-
94
-	/* Convert to Unicode */
95
-	for ( i = 0 ; i < uri_len ; i++ ) {
96
-		cmdline[i] = uri[i];
97
-		devpath->PathName[i] = uri[i];
98
-	}
99
-	if ( image->cmdline ) {
100
-		cmdline[uri_len - 1] = ' ';
101
-	}
102
-	for ( i = 0 ; i < args_len ; i++ ) {
103
-		cmdline[i + uri_len] = image->cmdline[i];
104
-	}
105
-
106
-	*devpath_out = &devpath->Header;
107
-	*cmdline_out = cmdline;
108
-	*cmdline_len_out = cmdline_len * sizeof ( CHAR16 );
109
-	return 0;
106
+		return NULL;
107
+	efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s",
108
+		       image->name,
109
+		       ( image->cmdline ? " " : "" ),
110
+		       ( image->cmdline ? image->cmdline : "" ) );
111
+	return cmdline;
110
 }
112
 }
111
 
113
 
112
 /**
114
 /**
117
  */
119
  */
118
 static int efi_image_exec ( struct image *image ) {
120
 static int efi_image_exec ( struct image *image ) {
119
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
121
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
122
+	struct efi_snp_device *snpdev;
123
+	EFI_DEVICE_PATH_PROTOCOL *path;
120
 	union {
124
 	union {
121
 		EFI_LOADED_IMAGE_PROTOCOL *image;
125
 		EFI_LOADED_IMAGE_PROTOCOL *image;
122
 		void *interface;
126
 		void *interface;
123
 	} loaded;
127
 	} loaded;
124
 	EFI_HANDLE handle;
128
 	EFI_HANDLE handle;
125
-	EFI_HANDLE device_handle = NULL;
126
-	UINTN exit_data_size;
127
-	CHAR16 *exit_data;
129
+	wchar_t *cmdline;
128
 	EFI_STATUS efirc;
130
 	EFI_STATUS efirc;
129
 	int rc;
131
 	int rc;
130
 
132
 
133
+	/* Find an appropriate device handle to use */
134
+	snpdev = last_opened_snpdev();
135
+	if ( ! snpdev ) {
136
+		DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
137
+		       image );
138
+		rc = -ENODEV;
139
+		goto err_no_snpdev;
140
+	}
141
+
142
+	/* Install file I/O protocols */
143
+	if ( ( rc = efi_file_install ( &snpdev->handle ) ) != 0 ) {
144
+		DBGC ( image, "EFIIMAGE %p could not install file protocol: "
145
+		       "%s\n", image, strerror ( rc ) );
146
+		goto err_file_install;
147
+	}
148
+
149
+	/* Install iPXE download protocol */
150
+	if ( ( rc = efi_download_install ( &snpdev->handle ) ) != 0 ) {
151
+		DBGC ( image, "EFIIMAGE %p could not install iPXE download "
152
+		       "protocol: %s\n", image, strerror ( rc ) );
153
+		goto err_download_install;
154
+	}
155
+
156
+	/* Create device path for image */
157
+	path = efi_image_path ( image, &snpdev->path );
158
+	if ( ! path ) {
159
+		DBGC ( image, "EFIIMAGE %p could not create device path\n",
160
+		       image );
161
+		rc = -ENOMEM;
162
+		goto err_image_path;
163
+	}
164
+
165
+	/* Create command line for image */
166
+	cmdline = efi_image_cmdline ( image );
167
+	if ( ! cmdline ) {
168
+		DBGC ( image, "EFIIMAGE %p could not create command line\n",
169
+		       image );
170
+		rc = -ENOMEM;
171
+		goto err_cmdline;
172
+	}
173
+
131
 	/* Attempt loading image */
174
 	/* Attempt loading image */
132
-	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, NULL,
175
+	if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path,
133
 				       user_to_virt ( image->data, 0 ),
176
 				       user_to_virt ( image->data, 0 ),
134
 				       image->len, &handle ) ) != 0 ) {
177
 				       image->len, &handle ) ) != 0 ) {
135
 		/* Not an EFI image */
178
 		/* Not an EFI image */
149
 		goto err_open_protocol;
192
 		goto err_open_protocol;
150
 	}
193
 	}
151
 
194
 
152
-	/* Pass an iPXE download protocol to the image */
153
-	if ( ( rc = efi_download_install ( &device_handle ) ) != 0 ) {
154
-		DBGC ( image, "EFIIMAGE %p could not install iPXE download "
155
-		       "protocol: %s\n", image, strerror ( rc ) );
156
-		goto err_download_install;
157
-	}
158
-	loaded.image->DeviceHandle = device_handle;
159
-	loaded.image->ParentHandle = efi_loaded_image;
160
-	if ( ( rc = efi_image_make_cmdline ( image, &loaded.image->FilePath,
161
-				       &loaded.image->LoadOptions,
162
-				       &loaded.image->LoadOptionsSize ) ) != 0 )
163
-		goto err_make_cmdline;
195
+	/* Sanity checks */
196
+	assert ( loaded.image->ParentHandle == efi_image_handle );
197
+	assert ( loaded.image->DeviceHandle == snpdev->handle );
198
+	assert ( loaded.image->LoadOptionsSize == 0 );
199
+	assert ( loaded.image->LoadOptions == NULL );
200
+
201
+	/* Set command line */
202
+	loaded.image->LoadOptions = cmdline;
203
+	loaded.image->LoadOptionsSize =
204
+		( ( wcslen ( cmdline ) + 1 /* NUL */ ) * sizeof ( wchar_t ) );
164
 
205
 
165
 	/* Start the image */
206
 	/* Start the image */
166
-	if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
167
-					&exit_data ) ) != 0 ) {
207
+	if ( ( efirc = bs->StartImage ( handle, 0, NULL ) ) != 0 ) {
168
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
208
 		DBGC ( image, "EFIIMAGE %p returned with status %s\n",
169
 		       image, efi_strerror ( efirc ) );
209
 		       image, efi_strerror ( efirc ) );
170
 		rc = EFIRC_TO_RC ( efirc );
210
 		rc = EFIRC_TO_RC ( efirc );
175
 	rc = 0;
215
 	rc = 0;
176
 
216
 
177
  err_start_image:
217
  err_start_image:
178
-	free ( loaded.image->LoadOptions );
179
- err_make_cmdline:
180
-	efi_download_uninstall ( device_handle );
181
- err_download_install:
182
  err_open_protocol:
218
  err_open_protocol:
183
 	/* Unload the image.  We can't leave it loaded, because we
219
 	/* Unload the image.  We can't leave it loaded, because we
184
 	 * have no "unload" operation.
220
 	 * have no "unload" operation.
185
 	 */
221
 	 */
186
-	bs->UnloadImage ( handle );
222
+	if ( ( efirc = bs->UnloadImage ( handle ) ) != 0 ) {
223
+		DBGC ( image, "EFIIMAGE %p could not unload: %s\n",
224
+		       image, efi_strerror ( efirc ) );
225
+	}
187
  err_load_image:
226
  err_load_image:
188
-
227
+	free ( cmdline );
228
+ err_cmdline:
229
+	free ( path );
230
+ err_image_path:
231
+	efi_download_uninstall ( snpdev->handle );
232
+ err_download_install:
233
+	efi_file_uninstall ( snpdev->handle );
234
+ err_file_install:
235
+ err_no_snpdev:
189
 	return rc;
236
 	return rc;
190
 }
237
 }
191
 
238
 

+ 73
- 0
src/include/ipxe/efi/Guid/FileInfo.h View File

1
+/** @file
2
+  Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.SetInfo()
3
+  and EFI_FILE_PROTOCOL.GetInfo() to set or get generic file information.
4
+  This GUID is defined in UEFI specification.
5
+
6
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
7
+This program and the accompanying materials are licensed and made available under
8
+the terms and conditions of the BSD License that accompanies this distribution.
9
+The full text of the license may be found at
10
+http://opensource.org/licenses/bsd-license.php.
11
+
12
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+
15
+**/
16
+
17
+#ifndef __FILE_INFO_H__
18
+#define __FILE_INFO_H__
19
+
20
+FILE_LICENCE ( BSD3 );
21
+
22
+#define EFI_FILE_INFO_ID \
23
+  { \
24
+    0x9576e92, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
25
+  }
26
+
27
+typedef struct {
28
+  ///
29
+  /// The size of the EFI_FILE_INFO structure, including the Null-terminated FileName string.
30
+  ///
31
+  UINT64    Size;
32
+  ///
33
+  /// The size of the file in bytes.
34
+  ///
35
+  UINT64    FileSize;
36
+  ///
37
+  /// PhysicalSize The amount of physical space the file consumes on the file system volume.
38
+  ///
39
+  UINT64    PhysicalSize;
40
+  ///
41
+  /// The time the file was created.
42
+  ///
43
+  EFI_TIME  CreateTime;
44
+  ///
45
+  /// The time when the file was last accessed.
46
+  ///
47
+  EFI_TIME  LastAccessTime;
48
+  ///
49
+  /// The time when the file's contents were last modified.
50
+  ///
51
+  EFI_TIME  ModificationTime;
52
+  ///
53
+  /// The attribute bits for the file.
54
+  ///
55
+  UINT64    Attribute;
56
+  ///
57
+  /// The Null-terminated name of the file.
58
+  ///
59
+  CHAR16    FileName[1];
60
+} EFI_FILE_INFO;
61
+
62
+///
63
+/// The FileName field of the EFI_FILE_INFO data structure is variable length.
64
+/// Whenever code needs to know the size of the EFI_FILE_INFO data structure, it needs to
65
+/// be the size of the data structure without the FileName field.  The following macro
66
+/// computes this size correctly no matter how big the FileName array is declared.
67
+/// This is required to make the EFI_FILE_INFO data structure ANSI compilant.
68
+///
69
+#define SIZE_OF_EFI_FILE_INFO OFFSET_OF (EFI_FILE_INFO, FileName)
70
+
71
+extern EFI_GUID gEfiFileInfoGuid;
72
+
73
+#endif

+ 65
- 0
src/include/ipxe/efi/Guid/FileSystemInfo.h View File

1
+/** @file
2
+  Provides a GUID and a data structure that can be used with EFI_FILE_PROTOCOL.GetInfo()
3
+  or EFI_FILE_PROTOCOL.SetInfo() to get or set information about the system's volume.
4
+  This GUID is defined in UEFI specification.
5
+
6
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
7
+This program and the accompanying materials are licensed and made available under
8
+the terms and conditions of the BSD License that accompanies this distribution.
9
+The full text of the license may be found at
10
+http://opensource.org/licenses/bsd-license.php.
11
+
12
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
+
15
+**/
16
+
17
+#ifndef __FILE_SYSTEM_INFO_H__
18
+#define __FILE_SYSTEM_INFO_H__
19
+
20
+FILE_LICENCE ( BSD3 );
21
+
22
+#define EFI_FILE_SYSTEM_INFO_ID \
23
+  { \
24
+    0x9576e93, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
25
+  }
26
+
27
+typedef struct {
28
+  ///
29
+  /// The size of the EFI_FILE_SYSTEM_INFO structure, including the Null-terminated VolumeLabel string.
30
+  ///
31
+  UINT64  Size;
32
+  ///
33
+  /// TRUE if the volume only supports read access.
34
+  ///
35
+  BOOLEAN ReadOnly;
36
+  ///
37
+  /// The number of bytes managed by the file system.
38
+  ///
39
+  UINT64  VolumeSize;
40
+  ///
41
+  /// The number of available bytes for use by the file system.
42
+  ///
43
+  UINT64  FreeSpace;
44
+  ///
45
+  /// The nominal block size by which files are typically grown.
46
+  ///
47
+  UINT32  BlockSize;
48
+  ///
49
+  /// The Null-terminated string that is the volume's label.
50
+  ///
51
+  CHAR16  VolumeLabel[1];
52
+} EFI_FILE_SYSTEM_INFO;
53
+
54
+///
55
+/// The VolumeLabel field of the EFI_FILE_SYSTEM_INFO data structure is variable length.
56
+/// Whenever code needs to know the size of the EFI_FILE_SYSTEM_INFO data structure, it needs
57
+/// to be the size of the data structure without the VolumeLable field.  The following macro
58
+/// computes this size correctly no matter how big the VolumeLable array is declared.
59
+/// This is required to make the EFI_FILE_SYSTEM_INFO data structure ANSI compilant.
60
+///
61
+#define SIZE_OF_EFI_FILE_SYSTEM_INFO  OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)
62
+
63
+extern EFI_GUID gEfiFileSystemInfoGuid;
64
+
65
+#endif

+ 243
- 0
src/include/ipxe/efi/Protocol/BlockIo.h View File

1
+/** @file
2
+  Block IO protocol as defined in the UEFI 2.0 specification.
3
+
4
+  The Block IO protocol is used to abstract block devices like hard drives,
5
+  DVD-ROMs and floppy drives.
6
+
7
+  Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
8
+  This program and the accompanying materials
9
+  are licensed and made available under the terms and conditions of the BSD License
10
+  which accompanies this distribution.  The full text of the license may be found at
11
+  http://opensource.org/licenses/bsd-license.php
12
+
13
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
+
16
+**/
17
+
18
+#ifndef __BLOCK_IO_H__
19
+#define __BLOCK_IO_H__
20
+
21
+FILE_LICENCE ( BSD3 );
22
+
23
+#define EFI_BLOCK_IO_PROTOCOL_GUID \
24
+  { \
25
+    0x964e5b21, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
26
+  }
27
+
28
+typedef struct _EFI_BLOCK_IO_PROTOCOL  EFI_BLOCK_IO_PROTOCOL;
29
+
30
+///
31
+/// Protocol GUID name defined in EFI1.1.
32
+///
33
+#define BLOCK_IO_PROTOCOL       EFI_BLOCK_IO_PROTOCOL_GUID
34
+
35
+///
36
+/// Protocol defined in EFI1.1.
37
+///
38
+typedef EFI_BLOCK_IO_PROTOCOL   EFI_BLOCK_IO;
39
+
40
+/**
41
+  Reset the Block Device.
42
+
43
+  @param  This                 Indicates a pointer to the calling context.
44
+  @param  ExtendedVerification Driver may perform diagnostics on reset.
45
+
46
+  @retval EFI_SUCCESS          The device was reset.
47
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
48
+                               not be reset.
49
+
50
+**/
51
+typedef
52
+EFI_STATUS
53
+(EFIAPI *EFI_BLOCK_RESET)(
54
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
55
+  IN BOOLEAN                        ExtendedVerification
56
+  );
57
+
58
+/**
59
+  Read BufferSize bytes from Lba into Buffer.
60
+
61
+  @param  This       Indicates a pointer to the calling context.
62
+  @param  MediaId    Id of the media, changes every time the media is replaced.
63
+  @param  Lba        The starting Logical Block Address to read from
64
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
65
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is
66
+                     responsible for either having implicit or explicit ownership of the buffer.
67
+
68
+  @retval EFI_SUCCESS           The data was read correctly from the device.
69
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
70
+  @retval EFI_NO_MEDIA          There is no media in the device.
71
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
72
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
73
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
74
+                                or the buffer is not on proper alignment.
75
+
76
+**/
77
+typedef
78
+EFI_STATUS
79
+(EFIAPI *EFI_BLOCK_READ)(
80
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
81
+  IN UINT32                         MediaId,
82
+  IN EFI_LBA                        Lba,
83
+  IN UINTN                          BufferSize,
84
+  OUT VOID                          *Buffer
85
+  );
86
+
87
+/**
88
+  Write BufferSize bytes from Lba into Buffer.
89
+
90
+  @param  This       Indicates a pointer to the calling context.
91
+  @param  MediaId    The media ID that the write request is for.
92
+  @param  Lba        The starting logical block address to be written. The caller is
93
+                     responsible for writing to only legitimate locations.
94
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.
95
+  @param  Buffer     A pointer to the source buffer for the data.
96
+
97
+  @retval EFI_SUCCESS           The data was written correctly to the device.
98
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.
99
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
100
+  @retval EFI_NO_MEDIA          There is no media in the device.
101
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
102
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
103
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
104
+                                or the buffer is not on proper alignment.
105
+
106
+**/
107
+typedef
108
+EFI_STATUS
109
+(EFIAPI *EFI_BLOCK_WRITE)(
110
+  IN EFI_BLOCK_IO_PROTOCOL          *This,
111
+  IN UINT32                         MediaId,
112
+  IN EFI_LBA                        Lba,
113
+  IN UINTN                          BufferSize,
114
+  IN VOID                           *Buffer
115
+  );
116
+
117
+/**
118
+  Flush the Block Device.
119
+
120
+  @param  This              Indicates a pointer to the calling context.
121
+
122
+  @retval EFI_SUCCESS       All outstanding data was written to the device
123
+  @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
124
+  @retval EFI_NO_MEDIA      There is no media in the device.
125
+
126
+**/
127
+typedef
128
+EFI_STATUS
129
+(EFIAPI *EFI_BLOCK_FLUSH)(
130
+  IN EFI_BLOCK_IO_PROTOCOL  *This
131
+  );
132
+
133
+/**
134
+  Block IO read only mode data and updated only via members of BlockIO
135
+**/
136
+typedef struct {
137
+  ///
138
+  /// The curent media Id. If the media changes, this value is changed.
139
+  ///
140
+  UINT32  MediaId;
141
+
142
+  ///
143
+  /// TRUE if the media is removable; otherwise, FALSE.
144
+  ///
145
+  BOOLEAN RemovableMedia;
146
+
147
+  ///
148
+  /// TRUE if there is a media currently present in the device;
149
+  /// othersise, FALSE. THis field shows the media present status
150
+  /// as of the most recent ReadBlocks() or WriteBlocks() call.
151
+  ///
152
+  BOOLEAN MediaPresent;
153
+
154
+  ///
155
+  /// TRUE if LBA 0 is the first block of a partition; otherwise
156
+  /// FALSE. For media with only one partition this would be TRUE.
157
+  ///
158
+  BOOLEAN LogicalPartition;
159
+
160
+  ///
161
+  /// TRUE if the media is marked read-only otherwise, FALSE.
162
+  /// This field shows the read-only status as of the most recent WriteBlocks () call.
163
+  ///
164
+  BOOLEAN ReadOnly;
165
+
166
+  ///
167
+  /// TRUE if the WriteBlock () function caches write data.
168
+  ///
169
+  BOOLEAN WriteCaching;
170
+
171
+  ///
172
+  /// The intrinsic block size of the device. If the media changes, then
173
+  /// this field is updated.
174
+  ///
175
+  UINT32  BlockSize;
176
+
177
+  ///
178
+  /// Supplies the alignment requirement for any buffer to read or write block(s).
179
+  ///
180
+  UINT32  IoAlign;
181
+
182
+  ///
183
+  /// The last logical block address on the device.
184
+  /// If the media changes, then this field is updated.
185
+  ///
186
+  EFI_LBA LastBlock;
187
+
188
+  ///
189
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
190
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the first LBA is aligned to
191
+  /// a physical block boundary.
192
+  ///
193
+  EFI_LBA LowestAlignedLba;
194
+
195
+  ///
196
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
197
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION2. Returns the number of logical blocks
198
+  /// per physical block.
199
+  ///
200
+  UINT32 LogicalBlocksPerPhysicalBlock;
201
+
202
+  ///
203
+  /// Only present if EFI_BLOCK_IO_PROTOCOL.Revision is greater than or equal to
204
+  /// EFI_BLOCK_IO_PROTOCOL_REVISION3. Returns the optimal transfer length
205
+  /// granularity as a number of logical blocks.
206
+  ///
207
+  UINT32 OptimalTransferLengthGranularity;
208
+} EFI_BLOCK_IO_MEDIA;
209
+
210
+#define EFI_BLOCK_IO_PROTOCOL_REVISION  0x00010000
211
+#define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001
212
+#define EFI_BLOCK_IO_PROTOCOL_REVISION3 0x00020031
213
+
214
+///
215
+/// Revision defined in EFI1.1.
216
+///
217
+#define EFI_BLOCK_IO_INTERFACE_REVISION   EFI_BLOCK_IO_PROTOCOL_REVISION
218
+
219
+///
220
+///  This protocol provides control over block devices.
221
+///
222
+struct _EFI_BLOCK_IO_PROTOCOL {
223
+  ///
224
+  /// The revision to which the block IO interface adheres. All future
225
+  /// revisions must be backwards compatible. If a future version is not
226
+  /// back wards compatible, it is not the same GUID.
227
+  ///
228
+  UINT64              Revision;
229
+  ///
230
+  /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
231
+  ///
232
+  EFI_BLOCK_IO_MEDIA  *Media;
233
+
234
+  EFI_BLOCK_RESET     Reset;
235
+  EFI_BLOCK_READ      ReadBlocks;
236
+  EFI_BLOCK_WRITE     WriteBlocks;
237
+  EFI_BLOCK_FLUSH     FlushBlocks;
238
+
239
+};
240
+
241
+extern EFI_GUID gEfiBlockIoProtocolGuid;
242
+
243
+#endif

+ 403
- 0
src/include/ipxe/efi/Protocol/SimpleFileSystem.h View File

1
+/** @file
2
+  SimpleFileSystem protocol as defined in the UEFI 2.0 specification.
3
+
4
+  The SimpleFileSystem protocol is the programmatic access to the FAT (12,16,32)
5
+  file system specified in UEFI 2.0. It can also be used to abstract a file
6
+  system other than FAT.
7
+
8
+  UEFI 2.0 can boot from any valid EFI image contained in a SimpleFileSystem.
9
+
10
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
11
+This program and the accompanying materials are licensed and made available under
12
+the terms and conditions of the BSD License that accompanies this distribution.
13
+The full text of the license may be found at
14
+http://opensource.org/licenses/bsd-license.php.
15
+
16
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18
+
19
+**/
20
+
21
+#ifndef __SIMPLE_FILE_SYSTEM_H__
22
+#define __SIMPLE_FILE_SYSTEM_H__
23
+
24
+FILE_LICENCE ( BSD3 );
25
+
26
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
27
+  { \
28
+    0x964e5b22, 0x6459, 0x11d2, {0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b } \
29
+  }
30
+
31
+typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
32
+
33
+typedef struct _EFI_FILE_PROTOCOL         EFI_FILE_PROTOCOL;
34
+typedef struct _EFI_FILE_PROTOCOL         *EFI_FILE_HANDLE;
35
+
36
+///
37
+/// Protocol GUID name defined in EFI1.1.
38
+///
39
+#define SIMPLE_FILE_SYSTEM_PROTOCOL       EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
40
+
41
+///
42
+/// Protocol name defined in EFI1.1.
43
+///
44
+typedef EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   EFI_FILE_IO_INTERFACE;
45
+typedef EFI_FILE_PROTOCOL                 EFI_FILE;
46
+
47
+/**
48
+  Open the root directory on a volume.
49
+
50
+  @param  This A pointer to the volume to open the root directory.
51
+  @param  Root A pointer to the location to return the opened file handle for the
52
+               root directory.
53
+
54
+  @retval EFI_SUCCESS          The device was opened.
55
+  @retval EFI_UNSUPPORTED      This volume does not support the requested file system type.
56
+  @retval EFI_NO_MEDIA         The device has no medium.
57
+  @retval EFI_DEVICE_ERROR     The device reported an error.
58
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
59
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
60
+  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
61
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
62
+                               longer supported. Any existing file handles for this volume are
63
+                               no longer valid. To access the files on the new medium, the
64
+                               volume must be reopened with OpenVolume().
65
+
66
+**/
67
+typedef
68
+EFI_STATUS
69
+(EFIAPI *EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME)(
70
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    *This,
71
+  OUT EFI_FILE_PROTOCOL                 **Root
72
+  );
73
+
74
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION  0x00010000
75
+
76
+///
77
+/// Revision defined in EFI1.1
78
+///
79
+#define EFI_FILE_IO_INTERFACE_REVISION  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
80
+
81
+struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
82
+  ///
83
+  /// The version of the EFI_SIMPLE_FILE_SYSTEM_PROTOCOL. The version
84
+  /// specified by this specification is 0x00010000. All future revisions
85
+  /// must be backwards compatible.
86
+  ///
87
+  UINT64                                      Revision;
88
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_OPEN_VOLUME OpenVolume;
89
+};
90
+
91
+/**
92
+  Opens a new file relative to the source file's location.
93
+
94
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
95
+                     handle to the source location. This would typically be an open
96
+                     handle to a directory.
97
+  @param  NewHandle  A pointer to the location to return the opened handle for the new
98
+                     file.
99
+  @param  FileName   The Null-terminated string of the name of the file to be opened.
100
+                     The file name may contain the following path modifiers: "\", ".",
101
+                     and "..".
102
+  @param  OpenMode   The mode to open the file. The only valid combinations that the
103
+                     file may be opened with are: Read, Read/Write, or Create/Read/Write.
104
+  @param  Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the
105
+                     attribute bits for the newly created file.
106
+
107
+  @retval EFI_SUCCESS          The file was opened.
108
+  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
109
+  @retval EFI_NO_MEDIA         The device has no medium.
110
+  @retval EFI_MEDIA_CHANGED    The device has a different medium in it or the medium is no
111
+                               longer supported.
112
+  @retval EFI_DEVICE_ERROR     The device reported an error.
113
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
114
+  @retval EFI_WRITE_PROTECTED  An attempt was made to create a file, or open a file for write
115
+                               when the media is write-protected.
116
+  @retval EFI_ACCESS_DENIED    The service denied access to the file.
117
+  @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
118
+  @retval EFI_VOLUME_FULL      The volume is full.
119
+
120
+**/
121
+typedef
122
+EFI_STATUS
123
+(EFIAPI *EFI_FILE_OPEN)(
124
+  IN EFI_FILE_PROTOCOL        *This,
125
+  OUT EFI_FILE_PROTOCOL       **NewHandle,
126
+  IN CHAR16                   *FileName,
127
+  IN UINT64                   OpenMode,
128
+  IN UINT64                   Attributes
129
+  );
130
+
131
+//
132
+// Open modes
133
+//
134
+#define EFI_FILE_MODE_READ    0x0000000000000001ULL
135
+#define EFI_FILE_MODE_WRITE   0x0000000000000002ULL
136
+#define EFI_FILE_MODE_CREATE  0x8000000000000000ULL
137
+
138
+//
139
+// File attributes
140
+//
141
+#define EFI_FILE_READ_ONLY  0x0000000000000001ULL
142
+#define EFI_FILE_HIDDEN     0x0000000000000002ULL
143
+#define EFI_FILE_SYSTEM     0x0000000000000004ULL
144
+#define EFI_FILE_RESERVED   0x0000000000000008ULL
145
+#define EFI_FILE_DIRECTORY  0x0000000000000010ULL
146
+#define EFI_FILE_ARCHIVE    0x0000000000000020ULL
147
+#define EFI_FILE_VALID_ATTR 0x0000000000000037ULL
148
+
149
+/**
150
+  Closes a specified file handle.
151
+
152
+  @param  This          A pointer to the EFI_FILE_PROTOCOL instance that is the file
153
+                        handle to close.
154
+
155
+  @retval EFI_SUCCESS   The file was closed.
156
+
157
+**/
158
+typedef
159
+EFI_STATUS
160
+(EFIAPI *EFI_FILE_CLOSE)(
161
+  IN EFI_FILE_PROTOCOL  *This
162
+  );
163
+
164
+/**
165
+  Close and delete the file handle.
166
+
167
+  @param  This                     A pointer to the EFI_FILE_PROTOCOL instance that is the
168
+                                   handle to the file to delete.
169
+
170
+  @retval EFI_SUCCESS              The file was closed and deleted, and the handle was closed.
171
+  @retval EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
172
+
173
+**/
174
+typedef
175
+EFI_STATUS
176
+(EFIAPI *EFI_FILE_DELETE)(
177
+  IN EFI_FILE_PROTOCOL  *This
178
+  );
179
+
180
+/**
181
+  Reads data from a file.
182
+
183
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
184
+                     handle to read data from.
185
+  @param  BufferSize On input, the size of the Buffer. On output, the amount of data
186
+                     returned in Buffer. In both cases, the size is measured in bytes.
187
+  @param  Buffer     The buffer into which the data is read.
188
+
189
+  @retval EFI_SUCCESS          Data was read.
190
+  @retval EFI_NO_MEDIA         The device has no medium.
191
+  @retval EFI_DEVICE_ERROR     The device reported an error.
192
+  @retval EFI_DEVICE_ERROR     An attempt was made to read from a deleted file.
193
+  @retval EFI_DEVICE_ERROR     On entry, the current file position is beyond the end of the file.
194
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
195
+  @retval EFI_BUFFER_TO_SMALL  The BufferSize is too small to read the current directory
196
+                               entry. BufferSize has been updated with the size
197
+                               needed to complete the request.
198
+
199
+**/
200
+typedef
201
+EFI_STATUS
202
+(EFIAPI *EFI_FILE_READ)(
203
+  IN EFI_FILE_PROTOCOL        *This,
204
+  IN OUT UINTN                *BufferSize,
205
+  OUT VOID                    *Buffer
206
+  );
207
+
208
+/**
209
+  Writes data to a file.
210
+
211
+  @param  This       A pointer to the EFI_FILE_PROTOCOL instance that is the file
212
+                     handle to write data to.
213
+  @param  BufferSize On input, the size of the Buffer. On output, the amount of data
214
+                     actually written. In both cases, the size is measured in bytes.
215
+  @param  Buffer     The buffer of data to write.
216
+
217
+  @retval EFI_SUCCESS          Data was written.
218
+  @retval EFI_UNSUPPORTED      Writes to open directory files are not supported.
219
+  @retval EFI_NO_MEDIA         The device has no medium.
220
+  @retval EFI_DEVICE_ERROR     The device reported an error.
221
+  @retval EFI_DEVICE_ERROR     An attempt was made to write to a deleted file.
222
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
223
+  @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
224
+  @retval EFI_ACCESS_DENIED    The file was opened read only.
225
+  @retval EFI_VOLUME_FULL      The volume is full.
226
+
227
+**/
228
+typedef
229
+EFI_STATUS
230
+(EFIAPI *EFI_FILE_WRITE)(
231
+  IN EFI_FILE_PROTOCOL        *This,
232
+  IN OUT UINTN                *BufferSize,
233
+  IN VOID                     *Buffer
234
+  );
235
+
236
+/**
237
+  Sets a file's current position.
238
+
239
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the
240
+                          file handle to set the requested position on.
241
+  @param  Position        The byte position from the start of the file to set.
242
+
243
+  @retval EFI_SUCCESS      The position was set.
244
+  @retval EFI_UNSUPPORTED  The seek request for nonzero is not valid on open
245
+                           directories.
246
+  @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file.
247
+
248
+**/
249
+typedef
250
+EFI_STATUS
251
+(EFIAPI *EFI_FILE_SET_POSITION)(
252
+  IN EFI_FILE_PROTOCOL        *This,
253
+  IN UINT64                   Position
254
+  );
255
+
256
+/**
257
+  Returns a file's current position.
258
+
259
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
260
+                          handle to get the current position on.
261
+  @param  Position        The address to return the file's current position value.
262
+
263
+  @retval EFI_SUCCESS      The position was returned.
264
+  @retval EFI_UNSUPPORTED  The request is not valid on open directories.
265
+  @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file.
266
+
267
+**/
268
+typedef
269
+EFI_STATUS
270
+(EFIAPI *EFI_FILE_GET_POSITION)(
271
+  IN EFI_FILE_PROTOCOL        *This,
272
+  OUT UINT64                  *Position
273
+  );
274
+
275
+/**
276
+  Returns information about a file.
277
+
278
+  @param  This            A pointer to the EFI_FILE_PROTOCOL instance that is the file
279
+                          handle the requested information is for.
280
+  @param  InformationType The type identifier for the information being requested.
281
+  @param  BufferSize      On input, the size of Buffer. On output, the amount of data
282
+                          returned in Buffer. In both cases, the size is measured in bytes.
283
+  @param  Buffer          A pointer to the data buffer to return. The buffer's type is
284
+                          indicated by InformationType.
285
+
286
+  @retval EFI_SUCCESS          The information was returned.
287
+  @retval EFI_UNSUPPORTED      The InformationType is not known.
288
+  @retval EFI_NO_MEDIA         The device has no medium.
289
+  @retval EFI_DEVICE_ERROR     The device reported an error.
290
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
291
+  @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry.
292
+                               BufferSize has been updated with the size needed to complete
293
+                               the request.
294
+**/
295
+typedef
296
+EFI_STATUS
297
+(EFIAPI *EFI_FILE_GET_INFO)(
298
+  IN EFI_FILE_PROTOCOL        *This,
299
+  IN EFI_GUID                 *InformationType,
300
+  IN OUT UINTN                *BufferSize,
301
+  OUT VOID                    *Buffer
302
+  );
303
+
304
+/**
305
+  Sets information about a file.
306
+
307
+  @param  File            A pointer to the EFI_FILE_PROTOCOL instance that is the file
308
+                          handle the information is for.
309
+  @param  InformationType The type identifier for the information being set.
310
+  @param  BufferSize      The size, in bytes, of Buffer.
311
+  @param  Buffer          A pointer to the data buffer to write. The buffer's type is
312
+                          indicated by InformationType.
313
+
314
+  @retval EFI_SUCCESS          The information was set.
315
+  @retval EFI_UNSUPPORTED      The InformationType is not known.
316
+  @retval EFI_NO_MEDIA         The device has no medium.
317
+  @retval EFI_DEVICE_ERROR     The device reported an error.
318
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
319
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_INFO_ID and the media is
320
+                               read-only.
321
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_PROTOCOL_SYSTEM_INFO_ID
322
+                               and the media is read only.
323
+  @retval EFI_WRITE_PROTECTED  InformationType is EFI_FILE_SYSTEM_VOLUME_LABEL_ID
324
+                               and the media is read-only.
325
+  @retval EFI_ACCESS_DENIED    An attempt is made to change the name of a file to a
326
+                               file that is already present.
327
+  @retval EFI_ACCESS_DENIED    An attempt is being made to change the EFI_FILE_DIRECTORY
328
+                               Attribute.
329
+  @retval EFI_ACCESS_DENIED    An attempt is being made to change the size of a directory.
330
+  @retval EFI_ACCESS_DENIED    InformationType is EFI_FILE_INFO_ID and the file was opened
331
+                               read-only and an attempt is being made to modify a field
332
+                               other than Attribute.
333
+  @retval EFI_VOLUME_FULL      The volume is full.
334
+  @retval EFI_BAD_BUFFER_SIZE  BufferSize is smaller than the size of the type indicated
335
+                               by InformationType.
336
+
337
+**/
338
+typedef
339
+EFI_STATUS
340
+(EFIAPI *EFI_FILE_SET_INFO)(
341
+  IN EFI_FILE_PROTOCOL        *This,
342
+  IN EFI_GUID                 *InformationType,
343
+  IN UINTN                    BufferSize,
344
+  IN VOID                     *Buffer
345
+  );
346
+
347
+/**
348
+  Flushes all modified data associated with a file to a device.
349
+
350
+  @param  This A pointer to the EFI_FILE_PROTOCOL instance that is the file
351
+               handle to flush.
352
+
353
+  @retval EFI_SUCCESS          The data was flushed.
354
+  @retval EFI_NO_MEDIA         The device has no medium.
355
+  @retval EFI_DEVICE_ERROR     The device reported an error.
356
+  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
357
+  @retval EFI_WRITE_PROTECTED  The file or medium is write-protected.
358
+  @retval EFI_ACCESS_DENIED    The file was opened read-only.
359
+  @retval EFI_VOLUME_FULL      The volume is full.
360
+
361
+**/
362
+typedef
363
+EFI_STATUS
364
+(EFIAPI *EFI_FILE_FLUSH)(
365
+  IN EFI_FILE_PROTOCOL  *This
366
+  );
367
+
368
+#define EFI_FILE_PROTOCOL_REVISION   0x00010000
369
+//
370
+// Revision defined in EFI1.1.
371
+//
372
+#define EFI_FILE_REVISION   EFI_FILE_PROTOCOL_REVISION
373
+
374
+///
375
+/// The EFI_FILE_PROTOCOL provides file IO access to supported file systems.
376
+/// An EFI_FILE_PROTOCOL provides access to a file's or directory's contents,
377
+/// and is also a reference to a location in the directory tree of the file system
378
+/// in which the file resides. With any given file handle, other files may be opened
379
+/// relative to this file's location, yielding new file handles.
380
+///
381
+struct _EFI_FILE_PROTOCOL {
382
+  ///
383
+  /// The version of the EFI_FILE_PROTOCOL interface. The version specified
384
+  /// by this specification is 0x00010000. Future versions are required
385
+  /// to be backward compatible to version 1.0.
386
+  ///
387
+  UINT64                Revision;
388
+  EFI_FILE_OPEN         Open;
389
+  EFI_FILE_CLOSE        Close;
390
+  EFI_FILE_DELETE       Delete;
391
+  EFI_FILE_READ         Read;
392
+  EFI_FILE_WRITE        Write;
393
+  EFI_FILE_GET_POSITION GetPosition;
394
+  EFI_FILE_SET_POSITION SetPosition;
395
+  EFI_FILE_GET_INFO     GetInfo;
396
+  EFI_FILE_SET_INFO     SetInfo;
397
+  EFI_FILE_FLUSH        Flush;
398
+};
399
+
400
+
401
+extern EFI_GUID gEfiSimpleFileSystemProtocolGuid;
402
+
403
+#endif

+ 0
- 2
src/include/ipxe/efi/efi.h View File

142
 extern const char * efi_strerror ( EFI_STATUS efirc );
142
 extern const char * efi_strerror ( EFI_STATUS efirc );
143
 extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
143
 extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
144
 			     EFI_SYSTEM_TABLE *systab );
144
 			     EFI_SYSTEM_TABLE *systab );
145
-extern int efi_download_install ( EFI_HANDLE *device_handle );
146
-extern void efi_download_uninstall ( EFI_HANDLE device_handle );
147
 
145
 
148
 #endif /* _IPXE_EFI_H */
146
 #endif /* _IPXE_EFI_H */

src/include/ipxe/efi/ipxe_download.h → src/include/ipxe/efi/efi_download.h View File

151
     0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \
151
     0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \
152
   }
152
   }
153
 
153
 
154
+extern int efi_download_install ( EFI_HANDLE *device );
155
+extern void efi_download_uninstall ( EFI_HANDLE device );
156
+
154
 #endif /* _IPXE_DOWNLOAD_H */
157
 #endif /* _IPXE_DOWNLOAD_H */

+ 13
- 0
src/include/ipxe/efi/efi_file.h View File

1
+#ifndef _IPXE_EFI_FILE_H
2
+#define _IPXE_EFI_FILE_H
3
+
4
+/** @file
5
+ *
6
+ * EFI file protocols
7
+ *
8
+ */
9
+
10
+extern int efi_file_install ( EFI_HANDLE *handle );
11
+extern void efi_file_uninstall ( EFI_HANDLE handle );
12
+
13
+#endif /* _IPXE_EFI_FILE_H */

+ 13
- 21
src/interface/efi/efi_download.c View File

25
 #include <ipxe/iobuf.h>
25
 #include <ipxe/iobuf.h>
26
 #include <ipxe/xfer.h>
26
 #include <ipxe/xfer.h>
27
 #include <ipxe/efi/efi.h>
27
 #include <ipxe/efi/efi.h>
28
-#include <ipxe/efi/ipxe_download.h>
28
+#include <ipxe/efi/efi_download.h>
29
 
29
 
30
 /** iPXE download protocol GUID */
30
 /** iPXE download protocol GUID */
31
 static EFI_GUID ipxe_download_protocol_guid
31
 static EFI_GUID ipxe_download_protocol_guid
187
 };
187
 };
188
 
188
 
189
 /**
189
 /**
190
- * Create a new device handle with a iPXE download protocol attached to it.
190
+ * Install iPXE download protocol
191
  *
191
  *
192
- * @v device_handle	Newly created device handle (output)
192
+ * @v handle		EFI handle
193
  * @ret rc		Return status code
193
  * @ret rc		Return status code
194
  */
194
  */
195
-int efi_download_install ( EFI_HANDLE *device_handle ) {
195
+int efi_download_install ( EFI_HANDLE *handle ) {
196
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
196
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
197
 	EFI_STATUS efirc;
197
 	EFI_STATUS efirc;
198
-	EFI_HANDLE handle = NULL;
199
-	if (efi_loaded_image->DeviceHandle) { /* TODO: ensure handle is the NIC (maybe efi_image has a better way to indicate the handle doing SNP?) */
200
-		handle = efi_loaded_image->DeviceHandle;
201
-	}
202
 
198
 
203
-	DBG ( "Installing ipxe protocol interface (%p)... ",
204
-	      &ipxe_download_protocol_interface );
205
 	efirc = bs->InstallMultipleProtocolInterfaces (
199
 	efirc = bs->InstallMultipleProtocolInterfaces (
206
-			&handle,
200
+			handle,
207
 			&ipxe_download_protocol_guid,
201
 			&ipxe_download_protocol_guid,
208
 			&ipxe_download_protocol_interface,
202
 			&ipxe_download_protocol_interface,
209
 			NULL );
203
 			NULL );
210
 	if ( efirc ) {
204
 	if ( efirc ) {
211
-		DBG ( "failed (%s)\n", efi_strerror ( efirc ) );
205
+		DBG ( "Could not install download protocol: %s\n",
206
+		      efi_strerror ( efirc ) );
212
 		return EFIRC_TO_RC ( efirc );
207
 		return EFIRC_TO_RC ( efirc );
213
 	}
208
 	}
214
 
209
 
215
-	DBG ( "success (%p)\n", handle );
216
-	*device_handle = handle;
217
 	return 0;
210
 	return 0;
218
 }
211
 }
219
 
212
 
220
 /**
213
 /**
221
- * Remove the iPXE download protocol from the given handle, and if nothing
222
- * else is attached, destroy the handle.
214
+ * Uninstall iPXE download protocol
223
  *
215
  *
224
- * @v device_handle	EFI device handle to remove from
216
+ * @v handle		EFI handle
225
  */
217
  */
226
-void efi_download_uninstall ( EFI_HANDLE device_handle ) {
218
+void efi_download_uninstall ( EFI_HANDLE handle ) {
227
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
219
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
228
 
220
 
229
 	bs->UninstallMultipleProtocolInterfaces (
221
 	bs->UninstallMultipleProtocolInterfaces (
230
-			device_handle,
231
-			ipxe_download_protocol_guid,
232
-			ipxe_download_protocol_interface );
222
+			handle,
223
+			&ipxe_download_protocol_guid,
224
+			&ipxe_download_protocol_interface, NULL );
233
 }
225
 }

+ 594
- 0
src/interface/efi/efi_file.c View File

1
+/*
2
+ * Copyright (C) 2013 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 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
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+/**
23
+ * @file
24
+ *
25
+ * EFI file protocols
26
+ *
27
+ */
28
+
29
+#include <stddef.h>
30
+#include <stdlib.h>
31
+#include <stdio.h>
32
+#include <string.h>
33
+#include <wchar.h>
34
+#include <ipxe/image.h>
35
+#include <ipxe/efi/efi.h>
36
+#include <ipxe/efi/Protocol/SimpleFileSystem.h>
37
+#include <ipxe/efi/Protocol/BlockIo.h>
38
+#include <ipxe/efi/Guid/FileInfo.h>
39
+#include <ipxe/efi/Guid/FileSystemInfo.h>
40
+#include <ipxe/efi/efi_strings.h>
41
+#include <ipxe/efi/efi_file.h>
42
+
43
+/** EFI simple file system protocol GUID */
44
+static EFI_GUID efi_simple_file_system_protocol_guid
45
+	= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
46
+
47
+/** EFI file information GUID */
48
+static EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID;
49
+
50
+/** EFI file system information GUID */
51
+static EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID;
52
+
53
+/** EFI block I/O protocol GUID */
54
+static EFI_GUID efi_block_io_protocol_guid
55
+	= EFI_BLOCK_IO_PROTOCOL_GUID;
56
+
57
+/** EFI media ID */
58
+#define EFI_MEDIA_ID_MAGIC 0x69505845
59
+
60
+/** An image exposed as an EFI file */
61
+struct efi_file {
62
+	/** EFI file protocol */
63
+	EFI_FILE_PROTOCOL file;
64
+	/** Image */
65
+	struct image *image;
66
+	/** Current file position */
67
+	size_t pos;
68
+};
69
+
70
+static struct efi_file efi_file_root;
71
+
72
+/**
73
+ * Get EFI file name (for debugging)
74
+ *
75
+ * @v file		EFI file
76
+ * @ret name		Name
77
+ */
78
+static const char * efi_file_name ( struct efi_file *file ) {
79
+
80
+	return ( file->image ? file->image->name : "<root>" );
81
+}
82
+
83
+/**
84
+ * Open file
85
+ *
86
+ * @v this		EFI file
87
+ * @ret new		New EFI file
88
+ * @v wname		Filename
89
+ * @v mode		File mode
90
+ * @v attributes	File attributes (for newly-created files)
91
+ * @ret efirc		EFI status code
92
+ */
93
+static EFI_STATUS EFIAPI
94
+efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
95
+		CHAR16 *wname, UINT64 mode __unused,
96
+		UINT64 attributes __unused ) {
97
+	struct efi_file *file = container_of ( this, struct efi_file, file );
98
+	char name[ wcslen ( wname ) + 1 /* NUL */ ];
99
+	struct efi_file *new_file;
100
+	struct image *image;
101
+
102
+	/* Initial '\' indicates opening from the root directory */
103
+	while ( *wname == L'\\' ) {
104
+		file = &efi_file_root;
105
+		wname++;
106
+	}
107
+
108
+	/* Allow root directory itself to be opened */
109
+	if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
110
+		*new = &efi_file_root.file;
111
+		return 0;
112
+	}
113
+
114
+	/* Fail unless opening from the root */
115
+	if ( file->image ) {
116
+		DBGC ( file, "EFIFILE %s is not a directory\n",
117
+		       efi_file_name ( file ) );
118
+		return EFI_NOT_FOUND;
119
+	}
120
+
121
+	/* Identify image */
122
+	snprintf ( name, sizeof ( name ), "%ls", wname );
123
+	image = find_image ( name );
124
+	if ( ! image ) {
125
+		DBGC ( file, "EFIFILE \"%s\" does not exist\n", name );
126
+		return EFI_NOT_FOUND;
127
+	}
128
+
129
+	/* Fail unless opening read-only */
130
+	if ( mode != EFI_FILE_MODE_READ ) {
131
+		DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
132
+		       image->name, mode );
133
+		return EFI_WRITE_PROTECTED;
134
+	}
135
+
136
+	/* Allocate and initialise file */
137
+	new_file = zalloc ( sizeof ( *new_file ) );
138
+	memcpy ( &new_file->file, &efi_file_root.file,
139
+		 sizeof ( new_file->file ) );
140
+	new_file->image = image_get ( image );
141
+	*new = &new_file->file;
142
+	DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
143
+
144
+	return 0;
145
+}
146
+
147
+/**
148
+ * Close file
149
+ *
150
+ * @v this		EFI file
151
+ * @ret efirc		EFI status code
152
+ */
153
+static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
154
+	struct efi_file *file = container_of ( this, struct efi_file, file );
155
+
156
+	/* Do nothing if this is the root */
157
+	if ( ! file->image )
158
+		return 0;
159
+
160
+	/* Close file */
161
+	DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
162
+	image_put ( file->image );
163
+	free ( file );
164
+
165
+	return 0;
166
+}
167
+
168
+/**
169
+ * Close and delete file
170
+ *
171
+ * @v this		EFI file
172
+ * @ret efirc		EFI status code
173
+ */
174
+static EFI_STATUS EFIAPI efi_file_delete ( EFI_FILE_PROTOCOL *this ) {
175
+	struct efi_file *file = container_of ( this, struct efi_file, file );
176
+
177
+	DBGC ( file, "EFIFILE %s cannot be deleted\n", efi_file_name ( file ) );
178
+
179
+	/* Close file */
180
+	efi_file_close ( this );
181
+
182
+	/* Warn of failure to delete */
183
+	return EFI_WARN_DELETE_FAILURE;
184
+}
185
+
186
+/**
187
+ * Return variable-length data structure
188
+ *
189
+ * @v base		Base data structure (starting with UINT64)
190
+ * @v base_len		Length of base data structure
191
+ * @v name		Name to append to base data structure
192
+ * @v len		Length of data buffer
193
+ * @v data		Data buffer
194
+ * @ret efirc		EFI status code
195
+ */
196
+static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
197
+				    const char *name, UINTN *len, VOID *data ) {
198
+	size_t name_len;
199
+
200
+	/* Calculate structure length */
201
+	name_len = strlen ( name );
202
+	*base = ( base_len + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) );
203
+	if ( *len < *base ) {
204
+		*len = *base;
205
+		return EFI_BUFFER_TOO_SMALL;
206
+	}
207
+
208
+	/* Copy data to buffer */
209
+	*len = *base;
210
+	memcpy ( data, base, base_len );
211
+	efi_snprintf ( ( data + base_len ), ( name_len + 1 /* NUL */ ),
212
+		       "%s", name );
213
+
214
+	return 0;
215
+}
216
+
217
+/**
218
+ * Return file information structure
219
+ *
220
+ * @v image		Image, or NULL for the root directory
221
+ * @v len		Length of data buffer
222
+ * @v data		Data buffer
223
+ * @ret efirc		EFI status code
224
+ */
225
+static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
226
+				  VOID *data ) {
227
+	EFI_FILE_INFO info;
228
+	const char *name;
229
+
230
+	/* Populate file information */
231
+	memset ( &info, 0, sizeof ( info ) );
232
+	if ( image ) {
233
+		info.FileSize = image->len;
234
+		info.PhysicalSize = image->len;
235
+		info.Attribute = EFI_FILE_READ_ONLY;
236
+		name = image->name;
237
+	} else {
238
+		info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
239
+		name = "";
240
+	}
241
+
242
+	return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
243
+				 len, data );
244
+}
245
+
246
+/**
247
+ * Read directory entry
248
+ *
249
+ * @v file		EFI file
250
+ * @v len		Length to read
251
+ * @v data		Data buffer
252
+ * @ret efirc		EFI status code
253
+ */
254
+static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
255
+				      VOID *data ) {
256
+	EFI_STATUS efirc;
257
+	struct image *image;
258
+	unsigned int index;
259
+
260
+	/* Construct directory entry at current position */
261
+	index = file->pos;
262
+	for_each_image ( image ) {
263
+		if ( index-- == 0 ) {
264
+			efirc = efi_file_info ( image, len, data );
265
+			if ( efirc == 0 )
266
+				file->pos++;
267
+			return efirc;
268
+		}
269
+	}
270
+
271
+	/* No more entries */
272
+	*len = 0;
273
+	return 0;
274
+}
275
+
276
+/**
277
+ * Read from file
278
+ *
279
+ * @v this		EFI file
280
+ * @v len		Length to read
281
+ * @v data		Data buffer
282
+ * @ret efirc		EFI status code
283
+ */
284
+static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
285
+					 UINTN *len, VOID *data ) {
286
+	struct efi_file *file = container_of ( this, struct efi_file, file );
287
+	size_t remaining;
288
+
289
+	/* If this is the root directory, then construct a directory entry */
290
+	if ( ! file->image )
291
+		return efi_file_read_dir ( file, len, data );
292
+
293
+	/* Read from the file */
294
+	remaining = ( file->image->len - file->pos );
295
+	if ( *len > remaining )
296
+		*len = remaining;
297
+	DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
298
+	       efi_file_name ( file ), file->pos,
299
+	       ( ( size_t ) ( file->pos + *len ) ) );
300
+	copy_from_user ( data, file->image->data, file->pos, *len );
301
+	file->pos += *len;
302
+	return 0;
303
+}
304
+
305
+/**
306
+ * Write to file
307
+ *
308
+ * @v this		EFI file
309
+ * @v len		Length to write
310
+ * @v data		Data buffer
311
+ * @ret efirc		EFI status code
312
+ */
313
+static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
314
+					  UINTN *len, VOID *data __unused ) {
315
+	struct efi_file *file = container_of ( this, struct efi_file, file );
316
+
317
+	DBGC ( file, "EFIFILE %s cannot write [%#08zx, %#08zx)\n",
318
+	       efi_file_name ( file ), file->pos,
319
+	       ( ( size_t ) ( file->pos + *len ) ) );
320
+	return EFI_WRITE_PROTECTED;
321
+}
322
+
323
+/**
324
+ * Set file position
325
+ *
326
+ * @v this		EFI file
327
+ * @v position		New file position
328
+ * @ret efirc		EFI status code
329
+ */
330
+static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
331
+						 UINT64 position ) {
332
+	struct efi_file *file = container_of ( this, struct efi_file, file );
333
+
334
+	/* If this is the root directory, reset to the start */
335
+	if ( ! file->image ) {
336
+		DBGC ( file, "EFIFILE root directory rewound\n" );
337
+		file->pos = 0;
338
+		return 0;
339
+	}
340
+
341
+	/* Check for the magic end-of-file value */
342
+	if ( position == 0xffffffffffffffffULL )
343
+		position = file->image->len;
344
+
345
+	/* Fail if we attempt to seek past the end of the file (since
346
+	 * we do not support writes).
347
+	 */
348
+	if ( position > file->image->len ) {
349
+		DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
350
+		       efi_file_name ( file ), position, file->image->len );
351
+		return EFI_UNSUPPORTED;
352
+	}
353
+
354
+	/* Set position */
355
+	file->pos = position;
356
+	DBGC ( file, "EFIFILE %s position set to %#08zx\n",
357
+	       efi_file_name ( file ), file->pos );
358
+
359
+	return 0;
360
+}
361
+
362
+/**
363
+ * Get file position
364
+ *
365
+ * @v this		EFI file
366
+ * @ret position	New file position
367
+ * @ret efirc		EFI status code
368
+ */
369
+static EFI_STATUS EFIAPI efi_file_get_position ( EFI_FILE_PROTOCOL *this,
370
+						 UINT64 *position ) {
371
+	struct efi_file *file = container_of ( this, struct efi_file, file );
372
+
373
+	*position = file->pos;
374
+	return 0;
375
+}
376
+
377
+/**
378
+ * Get file information
379
+ *
380
+ * @v this		EFI file
381
+ * @v type		Type of information
382
+ * @v len		Buffer size
383
+ * @v data		Buffer
384
+ * @ret efirc		EFI status code
385
+ */
386
+static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
387
+					     EFI_GUID *type,
388
+					     UINTN *len, VOID *data ) {
389
+	struct efi_file *file = container_of ( this, struct efi_file, file );
390
+	EFI_FILE_SYSTEM_INFO fsinfo;
391
+	struct image *image;
392
+
393
+	/* Determine information to return */
394
+	if ( memcmp ( type, &efi_file_info_id, sizeof ( *type ) ) == 0 ) {
395
+
396
+		/* Get file information */
397
+		DBGC ( file, "EFIFILE %s get file information\n",
398
+		       efi_file_name ( file ) );
399
+		return efi_file_info ( file->image, len, data );
400
+
401
+	} else if ( memcmp ( type, &efi_file_system_info_id,
402
+			     sizeof ( *type ) ) == 0 ) {
403
+
404
+		/* Get file system information */
405
+		DBGC ( file, "EFIFILE %s get file system information\n",
406
+		       efi_file_name ( file ) );
407
+		memset ( &fsinfo, 0, sizeof ( fsinfo ) );
408
+		fsinfo.ReadOnly = 1;
409
+		for_each_image ( image )
410
+			fsinfo.VolumeSize += image->len;
411
+		return efi_file_varlen ( &fsinfo.Size,
412
+					 SIZE_OF_EFI_FILE_SYSTEM_INFO, "iPXE",
413
+					 len, data );
414
+	} else {
415
+
416
+		DBGC ( file, "EFIFILE %s cannot get information of type %s\n",
417
+		       efi_file_name ( file ),
418
+		       uuid_ntoa ( ( union uuid * ) type ) );
419
+		return EFI_UNSUPPORTED;
420
+	}
421
+}
422
+
423
+/**
424
+ * Set file information
425
+ *
426
+ * @v this		EFI file
427
+ * @v type		Type of information
428
+ * @v len		Buffer size
429
+ * @v data		Buffer
430
+ * @ret efirc		EFI status code
431
+ */
432
+static EFI_STATUS EFIAPI
433
+efi_file_set_info ( EFI_FILE_PROTOCOL *this, EFI_GUID *type,
434
+		    UINTN len __unused, VOID *data __unused ) {
435
+	struct efi_file *file = container_of ( this, struct efi_file, file );
436
+
437
+	DBGC ( file, "EFIFILE %s cannot set information of type %s\n",
438
+	       efi_file_name ( file ), uuid_ntoa ( ( union uuid * ) type ) );
439
+	return EFI_WRITE_PROTECTED;
440
+}
441
+
442
+/**
443
+ * Flush file modified data
444
+ *
445
+ * @v this		EFI file
446
+ * @v type		Type of information
447
+ * @v len		Buffer size
448
+ * @v data		Buffer
449
+ * @ret efirc		EFI status code
450
+ */
451
+static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
452
+	struct efi_file *file = container_of ( this, struct efi_file, file );
453
+
454
+	DBGC ( file, "EFIFILE %s flushed\n", efi_file_name ( file ) );
455
+	return 0;
456
+}
457
+
458
+/** Root directory */
459
+static struct efi_file efi_file_root = {
460
+	.file = {
461
+		.Revision = EFI_FILE_PROTOCOL_REVISION,
462
+		.Open = efi_file_open,
463
+		.Close = efi_file_close,
464
+		.Delete = efi_file_delete,
465
+		.Read = efi_file_read,
466
+		.Write = efi_file_write,
467
+		.GetPosition = efi_file_get_position,
468
+		.SetPosition = efi_file_set_position,
469
+		.GetInfo = efi_file_get_info,
470
+		.SetInfo = efi_file_set_info,
471
+		.Flush = efi_file_flush,
472
+	},
473
+	.image = NULL,
474
+};
475
+
476
+/**
477
+ * Open root directory
478
+ *
479
+ * @v filesystem	EFI simple file system
480
+ * @ret file		EFI file handle
481
+ * @ret efirc		EFI status code
482
+ */
483
+static EFI_STATUS EFIAPI
484
+efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
485
+		       EFI_FILE_PROTOCOL **file ) {
486
+
487
+	*file = &efi_file_root.file;
488
+	return 0;
489
+}
490
+
491
+/** EFI simple file system protocol */
492
+static EFI_SIMPLE_FILE_SYSTEM_PROTOCOL efi_simple_file_system_protocol = {
493
+	.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
494
+	.OpenVolume = efi_file_open_volume,
495
+};
496
+
497
+/** Dummy block I/O reset */
498
+static EFI_STATUS EFIAPI
499
+efi_block_io_reset ( EFI_BLOCK_IO_PROTOCOL *this __unused,
500
+		     BOOLEAN extended __unused ) {
501
+	return 0;
502
+}
503
+
504
+/** Dummy block I/O read */
505
+static EFI_STATUS EFIAPI
506
+efi_block_io_read_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
507
+			   UINT32 MediaId __unused, EFI_LBA lba __unused,
508
+			   UINTN len __unused, VOID *data __unused ) {
509
+	return EFI_DEVICE_ERROR;
510
+}
511
+
512
+/** Dummy block I/O write */
513
+static EFI_STATUS EFIAPI
514
+efi_block_io_write_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused,
515
+			    UINT32 MediaId __unused, EFI_LBA lba __unused,
516
+			    UINTN len __unused, VOID *data __unused ) {
517
+	return EFI_DEVICE_ERROR;
518
+}
519
+
520
+/** Dummy block I/O flush */
521
+static EFI_STATUS EFIAPI
522
+efi_block_io_flush_blocks ( EFI_BLOCK_IO_PROTOCOL *this __unused ) {
523
+	return 0;
524
+}
525
+
526
+/** Dummy block I/O media */
527
+static EFI_BLOCK_IO_MEDIA efi_block_io_media = {
528
+	.MediaId = EFI_MEDIA_ID_MAGIC,
529
+	.MediaPresent = 1,
530
+	.ReadOnly = 1,
531
+	.BlockSize = 1,
532
+};
533
+
534
+/** Dummy EFI block I/O protocol */
535
+static EFI_BLOCK_IO_PROTOCOL efi_block_io_protocol = {
536
+	.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION,
537
+	.Media = &efi_block_io_media,
538
+	.Reset = efi_block_io_reset,
539
+	.ReadBlocks = efi_block_io_read_blocks,
540
+	.WriteBlocks = efi_block_io_write_blocks,
541
+	.FlushBlocks = efi_block_io_flush_blocks,
542
+};
543
+
544
+/**
545
+ * Install EFI simple file system protocol
546
+ *
547
+ * @v handle		EFI handle
548
+ * @ret rc		Return status code
549
+ */
550
+int efi_file_install ( EFI_HANDLE *handle ) {
551
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
552
+	EFI_STATUS efirc;
553
+
554
+	/* Install the simple file system protocol and the block I/O
555
+	 * protocol.  We don't have a block device, but large parts of
556
+	 * the EDK2 codebase make the assumption that file systems are
557
+	 * normally attached to block devices, and so we create a
558
+	 * dummy block device on the same handle just to keep things
559
+	 * looking normal.
560
+	 */
561
+	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
562
+			handle,
563
+			&efi_block_io_protocol_guid,
564
+			&efi_block_io_protocol,
565
+			&efi_simple_file_system_protocol_guid,
566
+			&efi_simple_file_system_protocol, NULL ) ) != 0 ) {
567
+		DBGC ( handle, "Could not install simple file system protocol: "
568
+		       "%s\n", efi_strerror ( efirc ) );
569
+		return EFIRC_TO_RC ( efirc );
570
+	}
571
+
572
+	return 0;
573
+}
574
+
575
+/**
576
+ * Uninstall EFI simple file system protocol
577
+ *
578
+ * @v handle		EFI handle
579
+ */
580
+void efi_file_uninstall ( EFI_HANDLE handle ) {
581
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
582
+
583
+	/* We must install the file system protocol first, since
584
+	 * otherwise the EDK2 code will attempt to helpfully uninstall
585
+	 * it when the block I/O protocol is uninstalled, leading to a
586
+	 * system lock-up.
587
+	 */
588
+	bs->UninstallMultipleProtocolInterfaces (
589
+			handle,
590
+			&efi_simple_file_system_protocol_guid,
591
+			&efi_simple_file_system_protocol,
592
+			&efi_block_io_protocol_guid,
593
+			&efi_block_io_protocol, NULL );
594
+}

Loading…
Cancel
Save