-
Notifications
You must be signed in to change notification settings - Fork 644
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Thids adds a uefi_load <block dev name> command, which will parse the PE header and do some basic validation checks. Bug: 294283461 Test: uefi_load virtio0 Change-Id: I97393652526bda5be1b995e59647e239c64d31d6
- Loading branch information
1 parent
4e9edd2
commit c750ed0
Showing
6 changed files
with
349 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#ifndef __DEFER_HEADER_ | ||
#define __DEFER_HEADER_ | ||
|
||
// Macro for running a block of code before function exits. | ||
// Example: | ||
// DEFER { | ||
// fclose(hc); | ||
// hc = nullptr; | ||
// }; | ||
// It works by creating a new local variable struct holding the lambda, the | ||
// destructor of that struct will invoke the lambda. | ||
|
||
// ScopeGuard ensures that the specified functor is executed no matter how the | ||
// current scope exits. | ||
template <typename F> class ScopeGuard { | ||
public: | ||
constexpr ScopeGuard(F &&f) : f_(static_cast<F &&>(f)) {} | ||
constexpr ScopeGuard(ScopeGuard &&that) noexcept | ||
: f_(that.f_), active_(that.active_) { | ||
that.active_ = false; | ||
} | ||
|
||
template <typename Functor> | ||
constexpr ScopeGuard(ScopeGuard<Functor> &&that) | ||
: f_(that.f_), active_(that.active_) { | ||
that.active_ = false; | ||
} | ||
|
||
~ScopeGuard() { f_(); } | ||
|
||
ScopeGuard() = delete; | ||
ScopeGuard(const ScopeGuard &) = delete; | ||
void operator=(const ScopeGuard &) = delete; | ||
void operator=(ScopeGuard &&that) = delete; | ||
|
||
private: | ||
template <typename Functor> friend class ScopeGuard; | ||
F f_; | ||
bool active_ = true; | ||
}; | ||
|
||
constexpr struct { | ||
template <typename F> constexpr auto operator<<(F &&f) const noexcept { | ||
return ScopeGuard<F>(static_cast<F &&>(f)); | ||
} | ||
} deferrer; | ||
|
||
#define TOKENPASTE1(x, y) x##y | ||
#define TOKENPASTE2(x, y) TOKENPASTE1(x, y) | ||
#define DEFER \ | ||
auto TOKENPASTE2(_deferred_lambda_call, __COUNTER__) = deferrer \ | ||
<< [&]() mutable | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#ifndef __PE_HEADER_ | ||
#define __PE_HEADER_ | ||
|
||
#include <endian.h> | ||
#include <sys/types.h> | ||
|
||
static constexpr size_t IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; | ||
static constexpr size_t IMAGE_SIZEOF_SHORT_NAME = 8; | ||
|
||
static constexpr uint32_t kPEHeader = 0x4550; | ||
struct IMAGE_NT_HEADERS64; | ||
|
||
struct IMAGE_DOS_HEADER { // DOS .EXE header | ||
u16 e_magic; // Magic number | ||
u16 e_cblp; // Bytes on last page of file | ||
u16 e_cp; // Pages in file | ||
u16 e_crlc; // Relocations | ||
u16 e_cparhdr; // Size of header in paragraphs | ||
u16 e_minalloc; // Minimum extra paragraphs needed | ||
u16 e_maxalloc; // Maximum extra paragraphs needed | ||
u16 e_ss; // Initial (relative) SS value | ||
u16 e_sp; // Initial SP value | ||
u16 e_csum; // Checksum | ||
u16 e_ip; // Initial IP value | ||
u16 e_cs; // Initial (relative) CS value | ||
u16 e_lfarlc; // File address of relocation table | ||
u16 e_ovno; // Overlay number | ||
u16 e_res[4]; // Reserved words | ||
u16 e_oemid; // OEM identifier (for e_oeminfo) | ||
u16 e_oeminfo; // OEM information; e_oemid specific | ||
u16 e_res2[10]; // Reserved words | ||
u32 e_lfanew; // File address of new exe header | ||
|
||
constexpr bool CheckMagic() const { return LE32(e_magic) == 0x5A4D; } | ||
IMAGE_NT_HEADERS64 *GetPEHeader() { | ||
auto address = reinterpret_cast<char *>(this); | ||
const auto pe_header = | ||
reinterpret_cast<IMAGE_NT_HEADERS64 *>(address + e_lfanew); | ||
return pe_header; | ||
} | ||
const IMAGE_NT_HEADERS64 *GetPEHeader() const { | ||
auto address = reinterpret_cast<const char *>(this); | ||
const auto pe_header = | ||
reinterpret_cast<const IMAGE_NT_HEADERS64 *>(address + e_lfanew); | ||
return pe_header; | ||
} | ||
} __attribute__((packed)); | ||
|
||
enum class ArchitectureType : u16 { | ||
Unknown = 0x00, | ||
ALPHAAXPOld = 0x183, | ||
ALPHAAXP = 0x184, | ||
ALPHAAXP64Bit = 0x284, | ||
AM33 = 0x1D3, | ||
AMD64 = 0x8664, | ||
ARM = 0x1C0, | ||
ARM64 = 0xAA64, | ||
ARMNT = 0x1C4, | ||
CLRPureMSIL = 0xC0EE, | ||
EBC = 0xEBC, | ||
I386 = 0x14C, | ||
I860 = 0x14D, | ||
IA64 = 0x200, | ||
LOONGARCH32 = 0x6232, | ||
LOONGARCH64 = 0x6264, | ||
M32R = 0x9041, | ||
MIPS16 = 0x266, | ||
MIPSFPU = 0x366, | ||
MIPSFPU16 = 0x466, | ||
MOTOROLA68000 = 0x268, | ||
POWERPC = 0x1F0, | ||
POWERPCFP = 0x1F1, | ||
POWERPC64 = 0x1F2, | ||
R3000 = 0x162, | ||
R4000 = 0x166, | ||
R10000 = 0x168, | ||
RISCV32 = 0x5032, | ||
RISCV64 = 0x5064, | ||
RISCV128 = 0x5128, | ||
SH3 = 0x1A2, | ||
SH3DSP = 0x1A3, | ||
SH4 = 0x1A6, | ||
SH5 = 0x1A8, | ||
THUMB = 0x1C2, | ||
WCEMIPSV2 = 0x169 | ||
}; | ||
|
||
struct IMAGE_FILE_HEADER { | ||
u32 Signature; | ||
ArchitectureType Machine; | ||
u16 NumberOfSections; | ||
u32 TimeDateStamp; | ||
u32 PointerToSymbolTable; | ||
u32 NumberOfSymbols; | ||
u16 SizeOfOptionalHeader; | ||
u16 Characteristics; | ||
} __attribute__((packed)); | ||
|
||
struct IMAGE_DATA_DIRECTORY { | ||
u32 VirtualAddress; | ||
u32 Size; | ||
} __attribute__((packed)); | ||
|
||
enum SubsystemType : u16 { | ||
Unknown = 0x00, | ||
Native = 0x01, | ||
WindowsGUI = 0x02, | ||
WindowsCUI = 0x03, | ||
OS2CUI = 0x05, | ||
POSIXCUI = 0x07, | ||
Windows9xNative = 0x08, | ||
WindowsCEGUI = 0x09, | ||
EFIApplication = 0x0A, | ||
EFIBootServiceDriver = 0x0B, | ||
EFIRuntimeDriver = 0x0C, | ||
EFIROM = 0x0D, | ||
Xbox = 0x0E, | ||
WindowsBootApplication = 0x10 | ||
}; | ||
|
||
constexpr const char *ToString(SubsystemType type) { | ||
switch (type) { | ||
case Native: | ||
return "Native"; | ||
case WindowsGUI: | ||
return "WindowsGUI"; | ||
case WindowsCUI: | ||
return "WindowsCUI"; | ||
case OS2CUI: | ||
return "OS2CUI"; | ||
case POSIXCUI: | ||
return "POSIXCUI"; | ||
case Windows9xNative: | ||
return "Windows9xNative"; | ||
case WindowsCEGUI: | ||
return "WindowsCEGUI"; | ||
case EFIApplication: | ||
return "EFIApplication"; | ||
case EFIBootServiceDriver: | ||
return "EFIBootServiceDriver"; | ||
case EFIRuntimeDriver: | ||
return "EFIRuntimeDriver"; | ||
case EFIROM: | ||
return "EFIROM"; | ||
case Xbox: | ||
return "Xbox"; | ||
case WindowsBootApplication: | ||
return "WindowsBootApplication"; | ||
default: | ||
return "Unknown"; | ||
} | ||
} | ||
|
||
struct IMAGE_OPTIONAL_HEADER64 { | ||
u16 Magic; | ||
u8 MajorLinkerVersion; | ||
u8 MinorLinkerVersion; | ||
u32 SizeOfCode; | ||
u32 SizeOfInitializedData; | ||
u32 SizeOfUninitializedData; | ||
u32 AddressOfEntryPoint; | ||
u32 BaseOfCode; | ||
u64 ImageBase; | ||
u32 SectionAlignment; | ||
u32 FileAlignment; | ||
u16 MajorOperatingSystemVersion; | ||
u16 MinorOperatingSystemVersion; | ||
u16 MajorImageVersion; | ||
u16 MinorImageVersion; | ||
u16 MajorSubsystemVersion; | ||
u16 MinorSubsystemVersion; | ||
u32 Win32VersionValue; | ||
u32 SizeOfImage; | ||
u32 SizeOfHeaders; | ||
u32 CheckSum; | ||
SubsystemType Subsystem; | ||
u16 DllCharacteristics; | ||
u64 SizeOfStackReserve; | ||
u64 SizeOfStackCommit; | ||
u64 SizeOfHeapReserve; | ||
u64 SizeOfHeapCommit; | ||
u32 LoaderFlags; | ||
u32 NumberOfRvaAndSizes; | ||
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; | ||
} __attribute__((packed)); | ||
|
||
struct IMAGE_SECTION_HEADER { | ||
char Name[IMAGE_SIZEOF_SHORT_NAME]; | ||
union { | ||
u32 PhysicalAddress; | ||
u32 VirtualSize; | ||
} Misc; | ||
u32 VirtualAddress; | ||
u32 SizeOfRawData; | ||
u32 PointerToRawData; | ||
u32 PointerToRelocations; | ||
u32 PointerToLinenumbers; | ||
u16 NumberOfRelocations; | ||
u16 NumberOfLinenumbers; | ||
u32 Characteristics; | ||
} __attribute__((packed)); | ||
|
||
struct IMAGE_NT_HEADERS64 { | ||
IMAGE_FILE_HEADER FileHeader; | ||
IMAGE_OPTIONAL_HEADER64 OptionalHeader; | ||
} __attribute__((packed)); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
LOCAL_DIR := $(GET_LOCAL_DIR) | ||
|
||
MODULE := $(LOCAL_DIR) | ||
|
||
MODULE_SRCS += \ | ||
$(LOCAL_DIR)/uefi.cpp \ | ||
|
||
include make/module.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#include "defer.h" | ||
#include "pe.h" | ||
|
||
#include <lib/bio.h> | ||
#include <lib/heap.h> | ||
#include <lk/console_cmd.h> | ||
#include <lk/debug.h> | ||
#include <lk/err.h> | ||
#include <lk/trace.h> | ||
#include <platform.h> | ||
#include <string.h> | ||
|
||
// ASCII "PE\x0\x0" | ||
static constexpr uint32_t kPEHeader = 0x4550; | ||
|
||
int load_pe_file(const char *blkdev) { | ||
bdev_t *dev = bio_open(blkdev); | ||
if (!dev) { | ||
printf("error opening block device %s\n", blkdev); | ||
return -1; | ||
} | ||
DEFER { bio_close(dev); }; | ||
constexpr size_t kBlocKSize = 4096; | ||
|
||
lk_time_t t = current_time(); | ||
uint8_t *address = (uint8_t *)malloc(kBlocKSize); | ||
ssize_t err = bio_read(dev, (void *)address, 0, kBlocKSize); | ||
t = current_time() - t; | ||
dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, | ||
(uint)t, (uint32_t)((uint64_t)err * 1000 / t)); | ||
|
||
const auto dos_header = reinterpret_cast<const IMAGE_DOS_HEADER *>(address); | ||
if (!dos_header->CheckMagic()) { | ||
printf("DOS Magic check failed %x\n", dos_header->e_magic); | ||
return -2; | ||
} | ||
if (dos_header->e_lfanew > kBlocKSize - sizeof(IMAGE_FILE_HEADER)) { | ||
printf("Invalid PE header offset %d exceeds maximum read size of %u - %u\n", | ||
dos_header->e_lfanew, kBlocKSize, sizeof(IMAGE_FILE_HEADER)); | ||
return -3; | ||
} | ||
const auto pe_header = dos_header->GetPEHeader(); | ||
const auto file_header = &pe_header->FileHeader; | ||
if (LE32(file_header->Signature) != kPEHeader) { | ||
printf("COFF Magic check failed %x\n", LE32(file_header->Signature)); | ||
return -4; | ||
} | ||
printf("PE header machine type: %x\n", | ||
static_cast<int>(file_header->Machine)); | ||
if (file_header->SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64)) { | ||
printf("Unexpected size of optional header %d, expected %d\n", | ||
file_header->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER64)); | ||
return -5; | ||
} | ||
const auto optional_header = &pe_header->OptionalHeader; | ||
if (optional_header->Subsystem != SubsystemType::EFIApplication) { | ||
printf("Unsupported Subsystem type: %d %s\n", optional_header->Subsystem, | ||
ToString(optional_header->Subsystem)); | ||
} | ||
printf("Valid UEFI application found.\n"); | ||
|
||
return 0; | ||
} | ||
|
||
int cmd_uefi_load(int argc, const console_cmd_args *argv) { | ||
if (argc != 2) { | ||
printf("Usage: %s <name of block device to load from>\n", argv[0].str); | ||
return 1; | ||
} | ||
load_pe_file(argv[1].str); | ||
return 0; | ||
} | ||
|
||
STATIC_COMMAND_START | ||
STATIC_COMMAND("uefi_load", "load UEFI application and run it", &cmd_uefi_load) | ||
STATIC_COMMAND_END(uefi); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters