• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2012 Intel Corporation; author: H. Peter Anvin
5  *   Chandramouli Narayanan
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
10  *   Boston MA 02111-1307, USA; either version 2 of the License, or
11  *   (at your option) any later version; incorporated herein by reference.
12  *
13  * ----------------------------------------------------------------------- */
14 
15 /* Miscellaneous functions for UEFI support
16  * We assume that EFI library initialization has completed
17  * and we have access to the global EFI exported variables
18  *
19  */
20 #include "efi.h"
21 #include "fio.h"
22 
23 /* Variables that need to be exported
24  * efi_errno - maintains the errors from EFI calls to display error messages.
25  */
26 EFI_STATUS efi_errno = EFI_SUCCESS;
27 
28 /* Locals
29  * vol_root - handle to the root device for file operations
30  */
31 static EFI_FILE_HANDLE vol_root;
32 
33 /* Table of UEFI error messages to be indexed with the EFI errno
34  * Update error message list as needed
35  */
36 static CHAR16 *uefi_errmsg[] = {
37 	L"EFI_UNDEFINED",	/* should not get here */
38 	L"EFI_LOAD_ERROR",
39 	L"EFI_INVALID_PARAMETER",
40 	L"EFI_UNSUPPORTED",
41 	L"EFI_BAD_BUFFER_SIZE",
42 	L"EFI_BUFFER_TOO_SMALL",
43 	L"EFI_NOT_READY",
44 	L"EFI_DEVICE_ERROR",
45 	L"EFI_WRITE_PROTECTED",
46 	L"EFI_OUT_OF_RESOURCES",
47 	L"EFI_VOLUME_CORRUPTED",
48 	L"EFI_VOLUME_FULL",
49 	L"EFI_NO_MEDIA",
50 	L"EFI_MEDIA_CHANGED",
51 	L"EFI_NOT_FOUND",
52 	L"EFI_ACCESS_DENIED",
53 	L"EFI_NO_RESPONSE",
54 	L"EFI_NO_MAPPING",
55 	L"EFI_TIMEOUT",
56 	L"EFI_NOT_STARTED",
57 	L"EFI_ALREADY_STARTED",
58 	L"EFI_ABORTED",
59 	L"EFI_ICMP_ERROR",
60 	L"EFI_TFTP_ERROR",
61 	L"EFI_PROTOCOL_ERROR"
62 };
63 
64 static UINTN nerrs = sizeof(uefi_errmsg)/sizeof(CHAR16 *);
65 
66 
67 /* Generic write error message; there is no gnu lib api to write to StdErr
68  * For now, everything goes ConOut
69  */
efi_printerr(CHAR16 * fmt,...)70 void efi_printerr(
71     CHAR16   *fmt,
72     ...
73     )
74 {
75     va_list     args;
76     va_start (args, fmt);
77     VPrint (fmt, args);
78     va_end (args);
79 }
80 
81 /* Simple console logger of efi-specific error messages. It uses
82  * gnu-efi library Print function to do the job.
83  */
84 
efi_perror(CHAR16 * prog)85 void efi_perror(CHAR16 *prog)
86 {
87 	/* Ensure that the err number lies within range
88 	 * Beware: unsigned comparisons fail on efi, signed comparisons work
89 	 */
90 	if (EFI_ERROR(efi_errno) && (INTN)efi_errno < (INTN)nerrs)
91 		efi_printerr(L"%s: %s\n", prog, uefi_errmsg[efi_errno]);
92 }
93 
94 /* Write to UEFI ConOut */
efi_printout(CHAR16 * fmt,...)95 void efi_printout(
96     CHAR16   *fmt,
97     ...
98     )
99 {
100     va_list     args;
101     va_start (args, fmt);
102     VPrint (fmt, args);
103     va_end (args);
104 }
105 
106 /* IMPORTANT:
107  * efi_setvol_root() needs to be called from efi main.
108  * The rest of the ADV support relies on the file i/o environment
109  * setup here. In order to use the EFI file support, we need
110  * to set up the volume root. Subsequent file operations need the root to
111  * access the interface routines.
112  *
113  */
114 
efi_set_volroot(EFI_HANDLE device_handle)115 EFI_STATUS efi_set_volroot(EFI_HANDLE device_handle)
116 {
117 	vol_root = LibOpenRoot(device_handle);
118 	if (!vol_root) {
119 		return EFI_DEVICE_ERROR;
120 	}
121 	return EFI_SUCCESS;
122 }
123 
124 /* File operations using EFI runtime services */
125 
126 /* Open the file using EFI runtime service
127  * Opening a file in EFI requires a handle to the device
128  * root in order to use the interface to the file operations supported by UEFI.
129  * For now, assume device volume root handle from the loaded image
130  *
131  * Return a valid handle if open succeeded and null otherwise.
132  * UEFI returns a bogus handle on error, so return null handle on error.
133  *
134  * TODO:
135  * 1. Validate the assumption about the root device
136  * 2. Can EFI open a file with full path name specification?
137  * 3. Look into gnu-efi helper functions for dealing with device path/file path
138  * 4. Consider utilizing EFI file open attributes.
139  * 5. In EFI, file attributes can be specified only at the time of creation.
140  * How do we support the equivalent of set_attributes() and clear_attributes()
141  */
efi_open(CHAR16 * file,UINT64 mode)142 EFI_FILE_HANDLE efi_open(CHAR16 *file, UINT64 mode)
143 {
144 	/* initialize with NULL handle since EFI open returns bogus */
145 	EFI_FILE_HANDLE	fd = NULL;
146 
147 	ASSERT(vol_root);
148 
149 	/* Note that the attributes parameter is none for now */
150 	efi_errno = uefi_call_wrapper(vol_root->Open,
151 					5,
152 					vol_root,
153 					&fd,
154 					file,
155 					mode,
156 					0);
157 	return fd;
158 }
159 
160 /*
161  * read/write wrapper functions for UEFI
162  *
163  * Read or write the specified number of bytes starting at the
164  * offset specified.
165  *
166  * Returns:
167  * number of bytes read/written on success
168  * -1 on error
169  */
170 /* Wrapper function to read from a file */
efi_xpread(EFI_FILE_HANDLE fd,void * buf,size_t count,off_t offset)171 size_t efi_xpread(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
172 {
173 	ASSERT(fd);
174 	efi_errno = uefi_call_wrapper(fd->SetPosition,
175 					2,
176 				    fd,
177 				    offset);
178 	if (EFI_ERROR(efi_errno)) return -1;
179 	efi_errno = uefi_call_wrapper(fd->Read,
180 					3,
181 				    fd,
182 				    &count,
183 					buf);
184 	if (EFI_ERROR(efi_errno)) return -1;
185 	return count;
186 }
187 
188 /* Wrapper function to write */
efi_xpwrite(EFI_FILE_HANDLE fd,void * buf,size_t count,off_t offset)189 size_t efi_xpwrite(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
190 {
191 	ASSERT(fd);
192 	efi_errno = uefi_call_wrapper(fd->SetPosition,
193 					2,
194 				    fd,
195 				    offset);
196 	if (EFI_ERROR(efi_errno)) return -1;
197 	efi_errno = uefi_call_wrapper(fd->Write,
198 					3,
199 				    fd,
200 				    &count,
201 					buf);
202 	if (EFI_ERROR(efi_errno)) return -1;
203 	return count;
204 }
205 
206 /* For an open handle, return the generic file info excluding
207  * the variable-length filename in the EFI_FILE_INFO structure.
208  */
efi_fstat(EFI_FILE_HANDLE fd,EFI_FILE_INFO * st)209 int efi_fstat(EFI_FILE_HANDLE fd, EFI_FILE_INFO *st)
210 {
211 	EFI_FILE_INFO *finfo;
212 
213 	ASSERT(fd);
214 	finfo = LibFileInfo(fd);
215 	if (finfo) {
216 		uefi_call_wrapper(BS->CopyMem, 3, (VOID *)st, (VOID *)finfo, SIZE_OF_EFI_FILE_INFO);
217 		FreePool(finfo);
218 		return 0;
219 	}
220 	/* gnu-efi lib does not return EFI status; export a generic device error for now */
221 	efi_errno = EFI_DEVICE_ERROR;
222 	return -1;
223 }
224 
225 /* set/clear_attributes()
226  * 	Currently handles only VFAT filesystem
227  * TODO:
228  *    1. Assumes VFAT file system.
229  *    2. How do we support other file systems?
230  */
efi_set_attributes(EFI_FILE_HANDLE fd)231 void efi_set_attributes(EFI_FILE_HANDLE fd)
232 {
233 	EFI_FILE_INFO *finfo;
234 
235 	ASSERT(fd);
236 	finfo = LibFileInfo(fd);
237 	if (finfo) {
238 		/* Hidden+System+Readonly */
239 		finfo->Attribute = EFI_FILE_READ_ONLY|EFI_FILE_HIDDEN|EFI_FILE_SYSTEM;
240 		efi_errno = uefi_call_wrapper(fd->SetInfo,
241 					4,
242 					fd,
243 					&GenericFileInfo,
244 					finfo->Size,
245 					finfo);
246 		FreePool(finfo);
247 	} else efi_errno = EFI_NOT_FOUND;
248 }
249 
efi_clear_attributes(EFI_FILE_HANDLE fd)250 void efi_clear_attributes(EFI_FILE_HANDLE fd)
251 {
252 	EFI_FILE_INFO *finfo;
253 
254 	ASSERT(fd);
255 	finfo = LibFileInfo(fd);
256 	if (finfo) {
257 		finfo->Attribute = 0; /* no attributes */
258 		efi_errno = uefi_call_wrapper(fd->SetInfo,
259 					4,
260 					fd,
261 					&GenericFileInfo,
262 					finfo->Size,
263 					finfo);
264 		FreePool(finfo);
265 	} else efi_errno = EFI_NOT_FOUND;
266 }
267 
268 /* Implement the sync operation using the EFI Flush file operation*/
efi_sync(EFI_FILE_HANDLE fd)269 void efi_sync(EFI_FILE_HANDLE fd)
270 {
271 	ASSERT(fd);
272 	efi_errno = uefi_call_wrapper(fd->Flush, 1, fd);
273 	return;
274 }
275 
276 /* Close the file */
efi_close(EFI_FILE_HANDLE fd)277 void efi_close(EFI_FILE_HANDLE fd)
278 {
279 
280 	ASSERT(fd);
281 	efi_errno = uefi_call_wrapper(fd->Close, 1, fd);
282 	return;
283 }
284