static EFI_STATUS launch_or_fallback(enum targets target, CHAR8 *cmdline) { EFI_STATUS ret; CHAR8 saved_cmdline[(cmdline ? strlena(cmdline) : 0) + 1]; if (cmdline) { CopyMem(saved_cmdline, cmdline, strlena(cmdline) + 1); FreePool(cmdline); } else saved_cmdline[0] = '\0'; do { target = em_fallback_target(target); ret = loader_ops.populate_indicators(); if (EFI_ERROR(ret)) return ret; ret = loader_ops.save_target_mode(target); if (EFI_ERROR(ret)) warning(L"Failed to save the target_mode: %r\n", ret); ret = loader_ops.load_target(target, saved_cmdline); target = fallback_target(target); } while (target != TARGET_UNKNOWN); return EFI_INVALID_PARAMETER; }
char * AsciiStrCat(char *Destination, char *Source) { UINTN dest_len = strlena((CHAR8 *)Destination); UINTN i; for (i = 0; Source[i] != '\0'; i++) Destination[dest_len + i] = Source[i]; Destination[dest_len + i] = '\0'; return Destination; }
VOID SmbiosGetPendingString ( IN SMBIOS_STRUCTURE_POINTER *Smbios, IN UINT16 StringNumber, OUT CHAR8 *Buffer ) { CHAR8 *String; if (Buffer == NULL) { PrintToken (STRING_TOKEN (STR_SMBIOSVIEW_LIBSMBIOSVIEW_NO_BUF_SPEC_WHEN_STRUCT), HiiHandle); return ; } // // Get string and copy to buffer. // Caller should provide the buffer. // String = LibGetSmbiosString (Smbios, StringNumber); if (String != NULL) { CopyMem (Buffer, String, strlena (String)); } else { Buffer = NULL; } }
/** * Open file * * @v This File handle * @ret new New file handle * @v Name File name * @v Mode File mode * @v Attributes File attributes (for newly-created files) * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New, CHAR16 *Name, UINT64 Mode, UINT64 Attributes) { EFI_STATUS Status; EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); EFI_GRUB_FILE *NewFile; // TODO: Use dynamic buffers? char path[MAX_PATH], clean_path[MAX_PATH], *dirname; INTN i, len; BOOLEAN AbsolutePath = (*Name == L'\\'); PrintInfo(L"Open(%llx%s, \"%s\")\n", (UINT64) This, IS_ROOT(File)?L" <ROOT>":L"", Name); /* Fail unless opening read-only */ if (Mode != EFI_FILE_MODE_READ) { PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name); return EFI_WRITE_PROTECTED; } /* Additional failures */ if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) { PrintInfo(L"Trying to open <ROOT>'s parent\n"); return EFI_NOT_FOUND; } /* See if we're trying to reopen current (which the EFI Shell insists on doing) */ if ((*Name == 0) || (StrCmp(Name, L".") == 0)) { PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"<ROOT>":FileName(File)); File->RefCount++; *New = This; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } /* If we have an absolute path, don't bother completing with the parent */ if (AbsolutePath) { len = 0; } else { strcpya(path, File->path); len = strlena(path); /* Add delimiter if needed */ if ((len == 0) || (path[len-1] != '/')) path[len++] = '/'; } /* Copy the rest of the path (converted to UTF-8) */ Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert path to UTF-8"); return Status; } /* Convert the delimiters */ for (i = strlena(path) - 1 ; i >= len; i--) { if (path[i] == '\\') path[i] = '/'; } /* We only want to handle with absolute paths */ clean_path[0] = '/'; /* Find out if we're dealing with root by removing the junk */ CopyPathRelative(&clean_path[1], path, MAX_PATH - 1); if (clean_path[1] == 0) { /* We're dealing with the root */ PrintInfo(L" Reopening <ROOT>\n"); *New = &File->FileSystem->RootFile->EfiFile; /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */ File->FileSystem->RootFile->DirIndex = 0; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } // TODO: eventually we should seek for already opened files and increase RefCount */ /* Allocate and initialise an instance of a file */ Status = GrubCreateFile(&NewFile, File->FileSystem); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not instantiate file"); return Status; } NewFile->path = AllocatePool(strlena(clean_path)+1); if (NewFile->path == NULL) { GrubDestroyFile(NewFile); PrintError(L"Could not instantiate path\n"); return EFI_OUT_OF_RESOURCES; } strcpya(NewFile->path, clean_path); /* Isolate the basename and dirname */ // TODO: would be nicer to have those if path.c for (i = strlena(clean_path) - 1; i >= 0; i--) { if (clean_path[i] == '/') { clean_path[i] = 0; break; } } dirname = (i <= 0) ? "/" : clean_path; NewFile->basename = &NewFile->path[i+1]; /* Find if we're working with a directory and fill the grub timestamp */ Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not get file attributes for '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } /* Finally we can call on GRUB open() if it's a regular file */ if (!NewFile->IsDir) { Status = GrubOpen(NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not open file '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } } NewFile->RefCount++; *New = &NewFile->EfiFile; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; }
/** * Read directory entry * * @v file EFI file * @v Len Length to read * @v Data Data buffer * @ret Status EFI status code */ static EFI_STATUS FileReadDir(EFI_GRUB_FILE *File, UINTN *Len, VOID *Data) { EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data; EFI_STATUS Status; /* We temporarily repurpose the FileSize as a *signed* entry index */ INT64 *Index = (INT64 *) &Info->FileSize; /* And PhysicalSize as a pointer to our filename */ CHAR8 **basename = (CHAR8 **) &Info->PhysicalSize; CHAR8 path[MAX_PATH]; EFI_GRUB_FILE *TmpFile = NULL; INTN len; /* Unless we can fit our maximum size, forget it */ if (*Len < MINIMUM_INFO_LENGTH) { *Len = MINIMUM_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } /* Populate our Info template */ ZeroMem(Data, *Len); Info->Size = *Len; *Index = File->DirIndex; strcpya(path, File->path); len = strlena(path); if (path[len-1] != '/') path[len++] = '/'; *basename = &path[len]; /* Invoke GRUB's directory listing */ Status = GrubDir(File, File->path, DirHook, Data); if (*Index >= 0) { /* No more entries */ *Len = 0; return EFI_SUCCESS; } if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Directory listing failed"); return Status; } /* Our Index/FileSize must be reset */ Info->FileSize = 0; Info->PhysicalSize = 0; /* For regular files, we still need to fill the size */ if (!(Info->Attribute & EFI_FILE_DIRECTORY)) { /* Open the file and read its size */ Status = GrubCreateFile(&TmpFile, File->FileSystem); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Unable to create temporary file"); return Status; } TmpFile->path = path; Status = GrubOpen(TmpFile); if (EFI_ERROR(Status)) { // TODO: EFI_NO_MAPPING is returned for links... PrintStatusError(Status, L"Unable to obtain the size of '%s'", Info->FileName); /* Non fatal error */ } else { Info->FileSize = GrubGetFileSize(TmpFile); Info->PhysicalSize = GrubGetFileSize(TmpFile); GrubClose(TmpFile); } GrubDestroyFile(TmpFile); } *Len = (UINTN) Info->Size; /* Advance to the next entry */ File->DirIndex++; // PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName, // (Info->Attribute&EFI_FILE_DIRECTORY)?L"<DIR>":L""); return EFI_SUCCESS; }
VOID CopyPathRelative(CHAR8 *dest, CHAR8 *src, INTN len) { CHAR8* o = dest; CHAR8* p = src; *o = '\0'; while(*p && *p == PATH_CHAR) ++p; for(; len && *p;) { src = p; p = strchra(src, PATH_CHAR); if(!p) p = src+strlena(src); /* . => skip */ if(p-src == 1 && *src == '.' ) { if(*p) src = ++p; } /* .. => pop one */ else if(p-src == 2 && *src == '.' && src[1] == '.') { if(o != dest) { CHAR8* tmp; *o = '\0'; tmp = strrchra(dest, PATH_CHAR); if(!tmp) { len += o-dest; o = dest; if(*p) ++p; } else { len += o-tmp; o = tmp; if(*p) ++p; } } else /* nothing to pop */ if(*p) ++p; } else { INTN copy; if(o != dest) { --len; *o++ = PATH_CHAR; } copy = MIN(p-src,len); CopyMem(o, src, copy); len -= copy; src += copy; o += copy; if(*p) ++p; } while(*p && *p == PATH_CHAR) ++p; } o[len?0:-1] = '\0'; }
UINTN AsciiStrSize(CHAR8 *string) { return strlena(string) + 1; }
CHAR8 * strcata(IN CHAR8 *dst,IN CHAR8 *src) { return strcpya(dst+strlena(dst), src); }
EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) { EFI_FILE_HANDLE handle; struct DosFileHeader dos; uint8_t magic[4]; struct PeFileHeader pe; UINTN len; UINTN i; EFI_STATUS err; err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL); if (EFI_ERROR(err)) return err; /* MS-DOS stub */ len = sizeof(dos); err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos); if (EFI_ERROR(err)) goto out; if (len != sizeof(dos)) { err = EFI_LOAD_ERROR; goto out; } if (CompareMem(dos.Magic, "MZ", 2) != 0) { err = EFI_LOAD_ERROR; goto out; } err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader); if (EFI_ERROR(err)) goto out; /* PE header */ len = sizeof(magic); err = uefi_call_wrapper(handle->Read, 3, handle, &len, &magic); if (EFI_ERROR(err)) goto out; if (len != sizeof(magic)) { err = EFI_LOAD_ERROR; goto out; } if (CompareMem(magic, "PE\0\0", 2) != 0) { err = EFI_LOAD_ERROR; goto out; } len = sizeof(pe); err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe); if (EFI_ERROR(err)) goto out; if (len != sizeof(pe)) { err = EFI_LOAD_ERROR; goto out; } /* PE32+ Subsystem type */ if (pe.Machine != PE_HEADER_MACHINE_X64 && pe.Machine != PE_HEADER_MACHINE_I386) { err = EFI_LOAD_ERROR; goto out; } if (pe.NumberOfSections > 96) { err = EFI_LOAD_ERROR; goto out; } /* the sections start directly after the headers */ err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader + sizeof(magic) + sizeof(pe) + pe.SizeOfOptionalHeader); if (EFI_ERROR(err)) goto out; for (i = 0; i < pe.NumberOfSections; i++) { struct PeSectionHeader sect; UINTN j; len = sizeof(sect); err = uefi_call_wrapper(handle->Read, 3, handle, &len, §); if (EFI_ERROR(err)) goto out; if (len != sizeof(sect)) { err = EFI_LOAD_ERROR; goto out; } for (j = 0; sections[j]; j++) { if (CompareMem(sect.Name, sections[j], strlena(sections[j])) != 0) continue; if (addrs) addrs[j] = (UINTN)sect.VirtualAddress; if (offsets) offsets[j] = (UINTN)sect.PointerToRawData; if (sizes) sizes[j] = (UINTN)sect.VirtualSize; } } out: uefi_call_wrapper(handle->Close, 1, handle); return err; }