Home | History | Annotate | Download | only in efi
      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  */
     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 
     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 */
     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 
    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  */
    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 */
    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 */
    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  */
    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  */
    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 
    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*/
    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 */
    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