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