From 64e2fae2c4ed0a8490ef11904770ece6900b88f4 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 26 Aug 2025 12:36:23 -0700 Subject: [PATCH 1/5] [lib][uefi] Fix memory leak in load_pe_file --- lib/uefi/include/uefi/system_table.h | 2 +- lib/uefi/uefi.cpp | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/uefi/include/uefi/system_table.h b/lib/uefi/include/uefi/system_table.h index 3141c903e8..cbadd3e86d 100644 --- a/lib/uefi/include/uefi/system_table.h +++ b/lib/uefi/include/uefi/system_table.h @@ -38,7 +38,7 @@ typedef struct { typedef struct EfiSystemTable { EfiTableHeader header; - uint16_t* firmware_vendor; + const char16_t* firmware_vendor; uint32_t firmware_revision; EfiHandle console_in_handle; void* con_in; diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index 5927b1cbae..5b6358f83e 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -35,6 +35,7 @@ #include "boot_service_provider.h" #include "charset.h" #include "configuration_table.h" +#include "debug_support.h" #include "defer.h" #include "memory_protocols.h" #include "pe.h" @@ -43,7 +44,6 @@ #include "switch_stack.h" #include "text_protocol.h" #include "uefi_platform.h" -#include "debug_support.h" #include "variable_mem.h" namespace { @@ -55,8 +55,7 @@ constexpr auto EFI_SYSTEM_TABLE_SIGNATURE = using EfiEntry = int (*)(void *, struct EfiSystemTable *); -template -void fill(T *data, size_t skip, uint8_t begin = 0) { +template void fill(T *data, size_t skip, uint8_t begin = 0) { auto ptr = reinterpret_cast(data); for (size_t i = 0; i < sizeof(T); i++) { if (i < skip) { @@ -66,7 +65,7 @@ void fill(T *data, size_t skip, uint8_t begin = 0) { } } -static char16_t firmwareVendor[] = u"Little Kernel"; +const char16_t firmwareVendor[] = u"Little Kernel"; int load_sections_and_execute(bdev_t *dev, const IMAGE_NT_HEADERS64 *pe_header) { @@ -123,7 +122,7 @@ int load_sections_and_execute(bdev_t *dev, fill(&boot_service, 0); setup_runtime_service_table(&runtime_service); setup_boot_service_table(&boot_service); - table.firmware_vendor = reinterpret_cast(firmwareVendor); + table.firmware_vendor = reinterpret_cast(firmwareVendor); table.runtime_services = &runtime_service; table.boot_services = &boot_service; table.header.signature = EFI_SYSTEM_TABLE_SIGNATURE; @@ -180,10 +179,7 @@ int cmd_uefi_set_variable(int argc, const console_cmd_args *argv) { EfiGuid guid = EFI_GLOBAL_VARIABLE_GUID; char16_t buffer[128]; utf8_to_utf16(buffer, argv[1].str, sizeof(buffer) / sizeof(buffer[0])); - efi_set_variable(buffer, - &guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS, - argv[2].str, + efi_set_variable(buffer, &guid, EFI_VARIABLE_BOOTSERVICE_ACCESS, argv[2].str, strlen(argv[2].str)); return 0; } @@ -199,7 +195,7 @@ STATIC_COMMAND("uefi_set_var", "set UEFI variable", &cmd_uefi_set_variable) STATIC_COMMAND("uefi_list_var", "list UEFI variable", &cmd_uefi_list_variable) STATIC_COMMAND_END(uefi); -} // namespace +} // namespace int load_pe_file(const char *blkdev) { bdev_t *dev = bio_open(blkdev); @@ -215,8 +211,17 @@ int load_pe_file(const char *blkdev) { lk_time_t t = current_time(); uint8_t *address = static_cast(malloc(kBlocKSize)); + if (address == nullptr) { + printf("failed to allocate %zu bytes memory for PE header\n", kBlocKSize); + return -1; + } + DEFER { free(address); }; ssize_t err = bio_read(dev, static_cast(address), 0, kBlocKSize); t = current_time() - t; + if (err < 0) { + printf("error reading PE header from block device %s: %zd\n", blkdev, err); + return -1; + } dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); From dda8a4a3bd7b88e7feb7fc1b3ee76ed89d8f5161 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 26 Aug 2025 12:57:29 -0700 Subject: [PATCH 2/5] [lib][uefi] Use LK standard error codes for uefi.cpp --- lib/uefi/uefi.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index 5b6358f83e..71ff2d9cf4 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -77,13 +77,13 @@ int load_sections_and_execute(bdev_t *dev, file_header->SizeOfOptionalHeader); if (sections <= 0) { printf("This PE file does not have any sections, unsupported.\n"); - return -8; + return ERR_BAD_STATE; } for (size_t i = 0; i < sections; i++) { if (section_header[i].NumberOfRelocations != 0) { printf("Section %s requires relocation, which is not supported.\n", section_header[i].Name); - return -6; + return ERR_NOT_SUPPORTED; } } setup_heap(); @@ -91,11 +91,14 @@ int load_sections_and_execute(bdev_t *dev, const auto &last_section = section_header[sections - 1]; const auto virtual_size = ROUNDUP( last_section.VirtualAddress + last_section.Misc.VirtualSize, PAGE_SIZE); + // For casting ImageBase to optional_header + // NOLINTBEGIN(performance-no-int-to-ptr) const auto image_base = reinterpret_cast( alloc_page(reinterpret_cast(optional_header->ImageBase), virtual_size, 21 /* Kernel requires 2MB alignment */)); + // NOLINTEND(performance-no-int-to-ptr) if (image_base == nullptr) { - return -7; + return ERR_NO_MEMORY; } memset(image_base, 0, virtual_size); DEFER { free_pages(image_base, virtual_size / PAGE_SIZE); }; @@ -165,7 +168,7 @@ int load_sections_and_execute(bdev_t *dev, int cmd_uefi_load(int argc, const console_cmd_args *argv) { if (argc != 2) { printf("Usage: %s \n", argv[0].str); - return 1; + return ERR_INVALID_ARGS; } load_pe_file(argv[1].str); return 0; @@ -174,7 +177,7 @@ int cmd_uefi_load(int argc, const console_cmd_args *argv) { int cmd_uefi_set_variable(int argc, const console_cmd_args *argv) { if (argc != 3) { printf("Usage: %s \n", argv[0].str); - return 1; + return ERR_INVALID_ARGS; } EfiGuid guid = EFI_GLOBAL_VARIABLE_GUID; char16_t buffer[128]; @@ -201,7 +204,7 @@ 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; + return ERR_IO; } DEFER { bio_close(dev); @@ -213,14 +216,14 @@ int load_pe_file(const char *blkdev) { uint8_t *address = static_cast(malloc(kBlocKSize)); if (address == nullptr) { printf("failed to allocate %zu bytes memory for PE header\n", kBlocKSize); - return -1; + return ERR_NO_MEMORY; } DEFER { free(address); }; ssize_t err = bio_read(dev, static_cast(address), 0, kBlocKSize); t = current_time() - t; if (err < 0) { printf("error reading PE header from block device %s: %zd\n", blkdev, err); - return -1; + return ERR_IO; } dprintf(INFO, "bio_read returns %d, took %u msecs (%d bytes/sec)\n", (int)err, (uint)t, (uint32_t)((uint64_t)err * 1000 / t)); @@ -228,19 +231,19 @@ int load_pe_file(const char *blkdev) { const auto dos_header = reinterpret_cast(address); if (!dos_header->CheckMagic()) { printf("DOS Magic check failed %x\n", dos_header->e_magic); - return -2; + return ERR_BAD_STATE; } if (dos_header->e_lfanew > kBlocKSize - sizeof(IMAGE_FILE_HEADER)) { printf( "Invalid PE header offset %d exceeds maximum read size of %zu - %zu\n", dos_header->e_lfanew, kBlocKSize, sizeof(IMAGE_FILE_HEADER)); - return -3; + return ERR_BAD_STATE; } 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; + return ERR_BAD_STATE; } printf("PE header machine type: %x\n", static_cast(file_header->Machine)); @@ -250,7 +253,7 @@ int load_pe_file(const char *blkdev) { sizeof(IMAGE_OPTIONAL_HEADER64::DataDirectory)) { printf("Unexpected size of optional header %d, expected %zu\n", file_header->SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER64)); - return -5; + return ERR_BAD_STATE; } const auto optional_header = &pe_header->OptionalHeader; if (optional_header->Subsystem != SubsystemType::EFIApplication) { From 0b3ab1df2e4a852f52ab67c96abe3918f02c6310 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 26 Aug 2025 13:07:57 -0700 Subject: [PATCH 3/5] [lib][uefi] Add error checking for certain functions --- lib/uefi/boot_service_provider.cpp | 9 ++++++--- lib/uefi/pe.h | 1 + lib/uefi/uefi.cpp | 24 +++++++++++++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/uefi/boot_service_provider.cpp b/lib/uefi/boot_service_provider.cpp index c5b435a55e..4861ef76e8 100644 --- a/lib/uefi/boot_service_provider.cpp +++ b/lib/uefi/boot_service_provider.cpp @@ -54,8 +54,11 @@ EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { printf("handle_protocol(%p, LOADED_IMAGE_PROTOCOL_GUID, %p);\n", handle, intf); - const auto loaded_image = static_cast( - uefi_malloc(sizeof(EfiLoadedImageProtocol))); + const auto loaded_image = static_cast( + uefi_malloc(sizeof(EFI_LOADED_IMAGE_PROTOCOL))); + if (!loaded_image) { + return EFI_STATUS_OUT_OF_RESOURCES; + } *loaded_image = {}; loaded_image->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; loaded_image->parent_handle = nullptr; @@ -70,7 +73,7 @@ EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, } else if (guid_eq(protocol, LINUX_EFI_LOADED_IMAGE_FIXED_GUID)) { printf("handle_protocol(%p, LINUX_EFI_LOADED_IMAGE_FIXED_GUID, %p);\n", handle, intf); - return EFI_STATUS_SUCCESS; + return EFI_STATUS_UNSUPPORTED; } else { printf("handle_protocol(%p, %p, %p);\n", handle, protocol, intf); } diff --git a/lib/uefi/pe.h b/lib/uefi/pe.h index 882d499c70..c5a4477567 100644 --- a/lib/uefi/pe.h +++ b/lib/uefi/pe.h @@ -63,6 +63,7 @@ struct IMAGE_DOS_HEADER { // DOS .EXE header u16 e_res2[10]; // Reserved words u32 e_lfanew; // File address of new exe header + // ASCII "PE\x0\x0" constexpr bool CheckMagic() const { return LE32(e_magic) == 0x5A4D; } IMAGE_NT_HEADERS64 *GetPEHeader() { auto address = reinterpret_cast(this); diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index 71ff2d9cf4..4073d519c6 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -51,8 +51,6 @@ namespace { constexpr auto EFI_SYSTEM_TABLE_SIGNATURE = static_cast(0x5453595320494249ULL); -// ASCII "PE\x0\x0" - using EfiEntry = int (*)(void *, struct EfiSystemTable *); template void fill(T *data, size_t skip, uint8_t begin = 0) { @@ -102,12 +100,22 @@ int load_sections_and_execute(bdev_t *dev, } memset(image_base, 0, virtual_size); DEFER { free_pages(image_base, virtual_size / PAGE_SIZE); }; - bio_read(dev, image_base, 0, section_header[0].PointerToRawData); + ssize_t bytes_reads = + bio_read(dev, image_base, 0, section_header[0].PointerToRawData); + if (bytes_reads != section_header[0].SizeOfRawData) { + printf("Failed to read section %s\n", section_header[0].Name); + return ERR_IO; + } for (size_t i = 0; i < sections; i++) { const auto §ion = section_header[i]; - bio_read(dev, image_base + section.VirtualAddress, section.PointerToRawData, - section.SizeOfRawData); + ssize_t bytes_read = + bio_read(dev, image_base + section.VirtualAddress, + section.PointerToRawData, section.SizeOfRawData); + if (bytes_read != section.SizeOfRawData) { + printf("Failed to read section %s %zu\n", section.Name, bytes_read); + return ERR_IO; + } } printf("Relocating image from 0x%llx to %p\n", optional_header->ImageBase, image_base); @@ -245,8 +253,10 @@ int load_pe_file(const char *blkdev) { printf("COFF Magic check failed %x\n", LE32(file_header->Signature)); return ERR_BAD_STATE; } - printf("PE header machine type: %x\n", - static_cast(file_header->Machine)); + if (file_header->Machine != ArchitectureType::ARM64) { + printf("Unsupported PE header machine type: %x\n", + static_cast(file_header->Machine)); + } if (file_header->SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER64) || file_header->SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER64) - From 4050f187a37e521b79f988b92d193baf1012a77b Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 3 Sep 2025 11:01:08 -0700 Subject: [PATCH 4/5] [lib][uefi] Use utf16 charset functions --- .clang-format | 2 +- lib/uefi/charset.cpp | 8 +++--- lib/uefi/charset.h | 8 ++++-- lib/uefi/runtime_service_provider.cpp | 41 +++++++++++---------------- 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/.clang-format b/.clang-format index b9985ef26c..e536d29815 100644 --- a/.clang-format +++ b/.clang-format @@ -11,4 +11,4 @@ ColumnLimit: 0 IndentCaseLabels: true IndentGotoLabels: false AlignConsecutiveMacros: - Enabled: true \ No newline at end of file + Enabled: true diff --git a/lib/uefi/charset.cpp b/lib/uefi/charset.cpp index 6996a3e183..f16f7afe12 100644 --- a/lib/uefi/charset.cpp +++ b/lib/uefi/charset.cpp @@ -46,14 +46,14 @@ int utf16_strcmp(const char16_t *s1, const char16_t *s2) { * This function converts utf-8 string to utf-16 string. However * it only supports us-ascii input right now. */ -int utf8_to_utf16(char16_t *dest, const char *src, size_t size) { +size_t utf8_to_utf16(char16_t *dest, const char *src, size_t size) { size_t i = 0; for (; i < size - 1 && *src; i++, src++) { dest[i] = *src; } dest[i] = 0; - return 0; + return i; } /** @@ -62,12 +62,12 @@ int utf8_to_utf16(char16_t *dest, const char *src, size_t size) { * This function converts utf-16 string to utf-8 string. However * it only supports us-ascii output right now. */ -int utf16_to_utf8(char *dest, const char16_t *src, size_t size) { +size_t utf16_to_utf8(char *dest, const char16_t *src, size_t size) { size_t i = 0; for (; i < size - 1 && *src; i++, src++) { dest[i] = *src; } dest[i] = 0; - return 0; + return i; } diff --git a/lib/uefi/charset.h b/lib/uefi/charset.h index 3154c90fb0..f7ee214c4f 100644 --- a/lib/uefi/charset.h +++ b/lib/uefi/charset.h @@ -22,7 +22,11 @@ size_t utf16_strlen(const char16_t *str); int utf16_strcmp(const char16_t *s1, const char16_t *s2); -int utf8_to_utf16(char16_t *dest, const char *src, size_t size); -int utf16_to_utf8(char *dest, const char16_t *src, size_t size); +static inline int utf16_strcmp(const uint16_t *s1, const char16_t *s2) { + return utf16_strcmp(reinterpret_cast(s1), s2); +} +// Return number of characters converted, including the null terminator +size_t utf8_to_utf16(char16_t *dest, const char *src, size_t size); +size_t utf16_to_utf8(char *dest, const char16_t *src, size_t size); #endif diff --git a/lib/uefi/runtime_service_provider.cpp b/lib/uefi/runtime_service_provider.cpp index 23585798b4..c4b8e372bb 100644 --- a/lib/uefi/runtime_service_provider.cpp +++ b/lib/uefi/runtime_service_provider.cpp @@ -22,29 +22,20 @@ #include #include +#include "charset.h" #include "variable_mem.h" namespace { -constexpr auto &&kSecureBoot = "SecureBoot"; +EFI_STATUS GetVariable(const uint16_t *VariableName, const EfiGuid *VendorGuid, + uint32_t *Attributes, size_t *DataSize, void *Data) { -EfiStatus GetVariable(const uint16_t* VariableName, const EfiGuid* VendorGuid, - uint32_t* Attributes, size_t* DataSize, void* Data) { if (!VariableName || !VendorGuid || !DataSize) { return EFI_STATUS_INVALID_PARAMETER; } - char buffer[512]; - size_t i = 0; - while (VariableName[i] && i < sizeof(buffer)) { - size_t j = 0; - for (j = 0; j < sizeof(buffer) - 1 && VariableName[i + j]; j++) { - buffer[j] = VariableName[i + j]; - } - i += j; - } - buffer[i] = 0; - if (strncmp(buffer, kSecureBoot, sizeof(kSecureBoot)) == 0 || strcmp(buffer, "SetupMode") == 0) { + if (utf16_strcmp(VariableName, u"SecureBoot") == 0 && + utf16_strcmp(VariableName, u"SetupMode") == 0) { if (DataSize) { *DataSize = 1; } @@ -56,7 +47,9 @@ EfiStatus GetVariable(const uint16_t* VariableName, const EfiGuid* VendorGuid, char *data_in_mem; size_t data_in_mem_size; - if (efi_get_variable(reinterpret_cast(VariableName), VendorGuid, Attributes, &data_in_mem, &data_in_mem_size) == EFI_STATUS_SUCCESS) { + if (efi_get_variable(reinterpret_cast(VariableName), + VendorGuid, Attributes, &data_in_mem, + &data_in_mem_size) == EFI_STATUS_SUCCESS) { if (*DataSize == 0 && !Data) { *DataSize = data_in_mem_size; return EFI_STATUS_BUFFER_TOO_SMALL; @@ -68,6 +61,9 @@ EfiStatus GetVariable(const uint16_t* VariableName, const EfiGuid* VendorGuid, memcpy(Data, data_in_mem, data_in_mem_size); return EFI_STATUS_SUCCESS; } + char buffer[512]; + utf16_to_utf8(buffer, reinterpret_cast(VariableName), + sizeof(buffer)); printf("%s(%s) is unsupported\n", __FUNCTION__, buffer); return EFI_STATUS_UNSUPPORTED; @@ -89,25 +85,22 @@ EfiStatus SetVariable(const uint16_t* VariableName, const EfiGuid* VendorGuid, /* Only allow setting non-volatile variables */ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { efi_set_variable(reinterpret_cast(VariableName), - VendorGuid, - Attributes, - reinterpret_cast(Data), - DataSize); + VendorGuid, Attributes, + reinterpret_cast(Data), DataSize); return EFI_STATUS_SUCCESS; } printf("%s: Only non-volatile is supported. Attributes = 0x%x\n", - __FUNCTION__, - Attributes); + __FUNCTION__, Attributes); return EFI_STATUS_UNSUPPORTED; } -void ResetSystem(EfiResetType ResetType, EfiStatus ResetStatus, size_t DataSize, - void* ResetData) { +void ResetSystem(EFI_RESET_TYPE ResetType, EFI_STATUS ResetStatus, + size_t DataSize, void *ResetData) { platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET); } -} // namespace +} // namespace void setup_runtime_service_table(EfiRuntimeService *service) { service->get_variable = GetVariable; From f1520271c0f72254ba1fb2c5a54c60dafa56e2c1 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 3 Sep 2025 15:36:35 -0700 Subject: [PATCH 5/5] [lib][uefi] Remove THUMB mode relocation, added aarch64 specific relocation --- lib/uefi/pe.h | 1 + lib/uefi/relocation.cpp | 127 +++++++--------------------------------- 2 files changed, 23 insertions(+), 105 deletions(-) diff --git a/lib/uefi/pe.h b/lib/uefi/pe.h index c5a4477567..562a388113 100644 --- a/lib/uefi/pe.h +++ b/lib/uefi/pe.h @@ -285,6 +285,7 @@ static constexpr size_t EFI_IMAGE_REL_BASED_HIGHADJ = 4; static constexpr size_t EFI_IMAGE_REL_BASED_MIPS_JMPADDR = 5; static constexpr size_t EFI_IMAGE_REL_BASED_ARM_MOV32A = 5; static constexpr size_t EFI_IMAGE_REL_BASED_ARM_MOV32T = 7; +static constexpr size_t EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA = 8; static constexpr size_t EFI_IMAGE_REL_BASED_IA64_IMM64 = 9; static constexpr size_t EFI_IMAGE_REL_BASED_MIPS_JMPADDR16 = 9; static constexpr size_t EFI_IMAGE_REL_BASED_DIR64 = 10; diff --git a/lib/uefi/relocation.cpp b/lib/uefi/relocation.cpp index 49e2907d0f..7cb52aae8c 100644 --- a/lib/uefi/relocation.cpp +++ b/lib/uefi/relocation.cpp @@ -7,102 +7,6 @@ #include "pe.h" -namespace { - -constexpr size_t BIT26 = 1 << 26; -constexpr size_t BIT11 = 1 << 11; -constexpr size_t BIT10 = 1 << 10; - -/** - Pass in a pointer to an ARM MOVT or MOVW immediate instruciton and - return the immediate data encoded in the instruction. - - @param Instruction Pointer to ARM MOVT or MOVW immediate instruction - - @return Immediate address encoded in the instruction - -**/ -uint16_t ThumbMovtImmediateAddress(const uint16_t *Instruction) { - uint32_t Movt{}; - uint16_t Address{}; - - // Thumb2 is two 16-bit instructions working together. Not a single 32-bit - // instruction Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000 - Movt = (*Instruction << 16) | (*(Instruction + 1)); - - // imm16 = imm4:i:imm3:imm8 - // imm4 -> Bit19:Bit16 - // i -> Bit26 - // imm3 -> Bit14:Bit12 - // imm8 -> Bit7:Bit0 - Address = static_cast(Movt & 0x000000ff); // imm8 - Address |= static_cast((Movt >> 4) & 0x0000f700); // imm4 imm3 - Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i - return Address; -} - -/** - Pass in a pointer to an ARM MOVW/MOVT instruciton pair and - return the immediate data encoded in the two` instruction. - - @param Instructions Pointer to ARM MOVW/MOVT insturction pair - - @return Immediate address encoded in the instructions - -**/ -uint32_t ThumbMovwMovtImmediateAddress(uint16_t *Instructions) { - uint16_t *Word{}; - uint16_t *Top{}; - - Word = Instructions; // MOVW - Top = Word + 2; // MOVT - - return (ThumbMovtImmediateAddress(Top) << 16) + - ThumbMovtImmediateAddress(Word); -} - -/** - Update an ARM MOVT or MOVW immediate instruction immediate data. - - @param Instruction Pointer to ARM MOVT or MOVW immediate instruction - @param Address New addres to patch into the instruction -**/ -void ThumbMovtImmediatePatch(uint16_t *Instruction, uint16_t Address) { - uint16_t Patch{}; - - // First 16-bit chunk of instruciton - Patch = ((Address >> 12) & 0x000f); // imm4 - Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i - // Mask out instruction bits and or in address - *(Instruction) = (*Instruction & ~0x040f) | Patch; - - // Second 16-bit chunk of instruction - Patch = Address & 0x000000ff; // imm8 - Patch |= ((Address << 4) & 0x00007000); // imm3 - // Mask out instruction bits and or in address - Instruction++; - *Instruction = (*Instruction & ~0x70ff) | Patch; -} - -/** - Update an ARM MOVW/MOVT immediate instruction instruction pair. - - @param Instructions Pointer to ARM MOVW/MOVT instruction pair - @param Address New addres to patch into the instructions -**/ -void ThumbMovwMovtImmediatePatch(uint16_t *Instructions, uint32_t Address) { - uint16_t *Word{}; - uint16_t *Top{}; - - Word = Instructions; // MOVW - Top = Word + 2; // MOVT - - ThumbMovtImmediatePatch(Word, static_cast(Address & 0xffff)); - ThumbMovtImmediatePatch(Top, static_cast(Address >> 16)); -} - -} // namespace - int relocate_image(char *image) { const auto dos_header = reinterpret_cast(image); const auto pe_header = dos_header->GetPEHeader(); @@ -141,7 +45,6 @@ int relocate_image(char *image) { auto Fixup16 = reinterpret_cast(Fixup); auto Fixup32 = reinterpret_cast(Fixup); auto Fixup64 = reinterpret_cast(Fixup); - uint32_t FixupVal = 0; switch ((*Reloc) >> 12) { case EFI_IMAGE_REL_BASED_ABSOLUTE: break; @@ -167,18 +70,32 @@ int relocate_image(char *image) { *Fixup64 = *Fixup64 + static_cast(Adjust); break; - case EFI_IMAGE_REL_BASED_ARM_MOV32T: - FixupVal = ThumbMovwMovtImmediateAddress(Fixup16) + - static_cast(Adjust); - ThumbMovwMovtImmediatePatch(Fixup16, FixupVal); - - break; - case EFI_IMAGE_REL_BASED_ARM_MOV32A: printf("Unsupported relocation type: EFI_IMAGE_REL_BASED_ARM_MOV32A\n"); // break omitted - ARM instruction encoding not implemented break; - + case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA: { + // The next four instructions are used to load a 64 bit address, + // relocate all of them + uint64_t Value = + (*Fixup32 & 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5 + (*(Fixup32 + 1) & 0x3ffc00) >> 10; // ori 12bits from bit10 + uint64_t Tmp1 = *(Fixup32 + 2) & 0x1ffffe0; // lu32i.d 20bits from bit5 + uint64_t Tmp2 = *(Fixup32 + 3) & 0x3ffc00; // lu52i.d 12bits from bit10 + Value = Value | (Tmp1 << 27) | (Tmp2 << 42); + Value += Adjust; + + *Fixup32 = (*Fixup32 & ~0x1ffffe0) | (((Value >> 12) & 0xfffff) << 5); + + Fixup += sizeof(uint32_t); + *Fixup32 = (*Fixup32 & ~0x3ffc00) | ((Value & 0xfff) << 10); + + Fixup += sizeof(uint32_t); + *Fixup32 = (*Fixup32 & ~0x1ffffe0) | (((Value >> 32) & 0xfffff) << 5); + + Fixup += sizeof(uint32_t); + *Fixup32 = (*Fixup32 & ~0x3ffc00) | (((Value >> 52) & 0xfff) << 10); + } default: printf("Unsupported relocation type: %d\n", (*Reloc) >> 12); return -1;