diff --git a/lib/uefi/boot_service_provider.cpp b/lib/uefi/boot_service_provider.cpp index ddeb41fa..38f92af4 100644 --- a/lib/uefi/boot_service_provider.cpp +++ b/lib/uefi/boot_service_provider.cpp @@ -21,13 +21,14 @@ #include "arch/defines.h" #include "boot_service.h" -#include "defer.h" #include "lib/bio.h" -#include "libfdt.h" #include "protocols/block_io_protocol.h" #include "protocols/dt_fixup_protocol.h" #include "protocols/gbl_efi_os_configuration_protocol.h" #include "protocols/loaded_image_protocol.h" +#include "uefi_platform.h" + +#include #include "switch_stack.h" #include "types.h" @@ -164,11 +165,6 @@ EfiStatus install_configuration_table(const EfiGuid *guid, void *table) { return UNSUPPORTED; } -EfiStatus exit_boot_services(EfiHandle image_handle, size_t map_key) { - printf("%s is called\n", __FUNCTION__); - return SUCCESS; -} - void copy_mem(void *dest, const void *src, size_t len) { memcpy(dest, src, len); } @@ -179,74 +175,6 @@ EfiTpl raise_tpl(EfiTpl new_tpl) { return APPLICATION; } -EFI_STATUS efi_dt_fixup(struct EfiDtFixupProtocol *self, void *fdt, - size_t *buffer_size, uint32_t flags) { - auto offset = fdt_subnode_offset(fdt, 0, "chosen"); - if (offset < 0) { - printf("Failed to find chosen node %d\n", offset); - return SUCCESS; - } - int length = 0; - auto prop = fdt_get_property(fdt, offset, "bootargs", &length); - - if (prop == nullptr) { - printf("Failed to find chosen/bootargs prop\n"); - return SUCCESS; - } - char *new_prop_data = reinterpret_cast(malloc(length)); - DEFER { - free(new_prop_data); - new_prop_data = nullptr; - }; - auto prop_length = strnlen(prop->data, length); - static constexpr auto &&to_add = - "console=ttyAMA0 earlycon=pl011,mmio32,0x9000000 "; - memset(new_prop_data, 0, length); - memcpy(new_prop_data, to_add, sizeof(to_add) - 1); - memcpy(new_prop_data + sizeof(to_add) - 1, prop->data, prop_length); - auto ret = fdt_setprop(fdt, offset, "bootargs", new_prop_data, length); - - printf("chosen/bootargs: %d %d \"%s\"\n", ret, length, new_prop_data); - - return SUCCESS; -} - -// Generates fixups for the kernel command line built by GBL. -EfiStatus fixup_kernel_commandline(struct GblEfiOsConfigurationProtocol *self, - const char *command_line, char *fixup, - size_t *fixup_buffer_size) { - printf("%s(%p, \"%s\")\n", __FUNCTION__, self, command_line); - *fixup_buffer_size = 0; - return SUCCESS; -} - -// Generates fixups for the bootconfig built by GBL. -EfiStatus fixup_bootconfig(struct GblEfiOsConfigurationProtocol *self, - const char *bootconfig, size_t size, char *fixup, - size_t *fixup_buffer_size) { - printf("%s(%p, %s, %lu, %lu)\n", __FUNCTION__, self, bootconfig, size, - *fixup_buffer_size); - constexpr auto &&to_add = "\nandroidboot.fstab_suffix=cf.f2fs." - "hctr2\nandroidboot.boot_devices=4010000000.pcie"; - const auto final_len = sizeof(to_add); - if (final_len > *fixup_buffer_size) { - *fixup_buffer_size = final_len; - return OUT_OF_RESOURCES; - } - *fixup_buffer_size = final_len; - memcpy(fixup, to_add, final_len); - - return SUCCESS; -} - -// Selects which device trees and overlays to use from those loaded by GBL. -EfiStatus select_device_trees(struct GblEfiOsConfigurationProtocol *self, - GblEfiVerifiedDeviceTree *device_trees, - size_t num_device_trees) { - printf("%s(%p, %p %lu)\n", __FUNCTION__, self, device_trees, - num_device_trees); - return UNSUPPORTED; -} EfiStatus open_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf, EfiHandle agent_handle, EfiHandle controller_handle, @@ -291,7 +219,7 @@ EfiStatus open_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf, } fixup->revision = EFI_DT_FIXUP_PROTOCOL_REVISION; fixup->fixup = efi_dt_fixup; - *intf = reinterpret_cast(fixup); + *intf = reinterpret_cast(fixup); } return SUCCESS; } else if (guid_eq(protocol, EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID)) { @@ -309,7 +237,7 @@ EfiStatus open_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf, config->fixup_bootconfig = fixup_bootconfig; config->fixup_kernel_commandline = fixup_kernel_commandline; config->select_device_trees = select_device_trees; - *intf = reinterpret_cast(config); + *intf = reinterpret_cast(config); return SUCCESS; } printf("%s is unsupported 0x%x 0x%x 0x%x 0x%llx\n", __FUNCTION__, diff --git a/lib/uefi/boot_service_provider.h b/lib/uefi/boot_service_provider.h index 6db70f55..87aa54ee 100644 --- a/lib/uefi/boot_service_provider.h +++ b/lib/uefi/boot_service_provider.h @@ -121,4 +121,9 @@ struct EFI_LOADED_IMAGE_PROTOCOL { static constexpr size_t EFI_LOADED_IMAGE_PROTOCOL_REVISION = 0x1000; +// This function would be called from GBL before jumping into android kernel +// LK provides a default no-op implementation that is weakly linked, +// different platforms can override with their own implementation. +EfiStatus exit_boot_services(EfiHandle image_handle, size_t map_key); + #endif diff --git a/lib/uefi/include/uefi.h b/lib/uefi/include/uefi.h new file mode 100644 index 00000000..1aea929d --- /dev/null +++ b/lib/uefi/include/uefi.h @@ -0,0 +1,15 @@ + +#ifndef __LIB_UEFI_HEADER_ +#define __LIB_UEFI_HEADER_ + +#ifdef __cplusplus +extern "C" { +#endif + +int load_pe_file(const char *blkdev); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/lib/uefi/relocation.cpp b/lib/uefi/relocation.cpp index bbf5be9e..49e2907d 100644 --- a/lib/uefi/relocation.cpp +++ b/lib/uefi/relocation.cpp @@ -1,10 +1,14 @@ +#include "relocation.h" + #include #include #include #include "pe.h" +namespace { + constexpr size_t BIT26 = 1 << 26; constexpr size_t BIT11 = 1 << 11; constexpr size_t BIT10 = 1 << 10; @@ -97,6 +101,8 @@ void ThumbMovwMovtImmediatePatch(uint16_t *Instructions, uint32_t Address) { 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(); diff --git a/lib/uefi/rules.mk b/lib/uefi/rules.mk index b2afeba6..635eaaaa 100644 --- a/lib/uefi/rules.mk +++ b/lib/uefi/rules.mk @@ -13,6 +13,7 @@ MODULE_SRCS += \ $(LOCAL_DIR)/boot_service_provider.cpp \ $(LOCAL_DIR)/memory_protocols.cpp \ $(LOCAL_DIR)/blockio_protocols.cpp \ + $(LOCAL_DIR)/uefi_platform.cpp \ $(LOCAL_DIR)/runtime_service_provider.cpp \ $(LOCAL_DIR)/switch_stack.S \ $(LOCAL_DIR)/configuration_table.cpp \ diff --git a/lib/uefi/runtime_service_provider.cpp b/lib/uefi/runtime_service_provider.cpp index 97b22b52..d129d52c 100644 --- a/lib/uefi/runtime_service_provider.cpp +++ b/lib/uefi/runtime_service_provider.cpp @@ -16,14 +16,16 @@ */ #include "runtime_service_provider.h" -#include "types.h" +#include #include #include +#include "types.h" + namespace { -constexpr auto &&kSecureBoot = L"SecureBoot"; +constexpr auto &&kSecureBoot = "SecureBoot"; EFI_STATUS GetVariable(char16_t *VariableName, EfiGuid *VendorGuid, uint32_t *Attributes, size_t *DataSize, void *Data) { @@ -37,7 +39,7 @@ EFI_STATUS GetVariable(char16_t *VariableName, EfiGuid *VendorGuid, i += j; } buffer[i] = 0; - if (strcmp(buffer, "SecureBoot") == 0 || strcmp(buffer, "SetupMode") == 0) { + if (strncmp(buffer, kSecureBoot, sizeof(kSecureBoot)) == 0 || strcmp(buffer, "SetupMode") == 0) { if (DataSize) { *DataSize = 1; } @@ -64,10 +66,17 @@ EFI_STATUS SetVariable(char16_t *VariableName, EfiGuid *VendorGuid, return UNSUPPORTED; } -} // namespace + +void ResetSystem(EFI_RESET_TYPE ResetType, EFI_STATUS ResetStatus, + size_t DataSize, void *ResetData) { + platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET); +} + +} // namespace void setup_runtime_service_table(EfiRuntimeService *service) { service->GetVariable = GetVariable; service->SetVariable = SetVariable; service->SetVirtualAddressMap = SetVirtualAddressMap; + service->ResetSystem = ResetSystem; } diff --git a/lib/uefi/uefi_platform.cpp b/lib/uefi/uefi_platform.cpp new file mode 100644 index 00000000..a1fd0a71 --- /dev/null +++ b/lib/uefi/uefi_platform.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include "defer.h" +#include "uefi_platform.h" +#include "protocols/gbl_efi_os_configuration_protocol.h" + +__WEAK EFI_STATUS efi_dt_fixup(struct EfiDtFixupProtocol *self, void *fdt, + size_t *buffer_size, uint32_t flags) { + auto offset = fdt_subnode_offset(fdt, 0, "chosen"); + if (offset < 0) { + printf("Failed to find chosen node %d\n", offset); + return SUCCESS; + } + int length = 0; + auto prop = fdt_get_property(fdt, offset, "bootargs", &length); + + if (prop == nullptr) { + printf("Failed to find chosen/bootargs prop\n"); + return SUCCESS; + } + char *new_prop_data = reinterpret_cast(malloc(length)); + DEFER { + free(new_prop_data); + new_prop_data = nullptr; + }; + auto prop_length = strnlen(prop->data, length); + static constexpr auto &&to_add = + "console=ttyAMA0 earlycon=pl011,mmio32,0x9000000 "; + memset(new_prop_data, 0, length); + memcpy(new_prop_data, to_add, sizeof(to_add) - 1); + memcpy(new_prop_data + sizeof(to_add) - 1, prop->data, prop_length); + auto ret = fdt_setprop(fdt, offset, "bootargs", new_prop_data, length); + + printf("chosen/bootargs: %d %d \"%s\"\n", ret, length, new_prop_data); + + return SUCCESS; +} + +// Generates fixups for the kernel command line built by GBL. +__WEAK EfiStatus fixup_kernel_commandline( + struct GblEfiOsConfigurationProtocol *self, const char *command_line, + char *fixup, size_t *fixup_buffer_size) { + printf("%s(%p, \"%s\")\n", __FUNCTION__, self, command_line); + *fixup_buffer_size = 0; + return SUCCESS; +} + +// Generates fixups for the bootconfig built by GBL. +__WEAK EfiStatus fixup_bootconfig(struct GblEfiOsConfigurationProtocol *self, + const char *bootconfig, size_t size, + char *fixup, size_t *fixup_buffer_size) { + printf("%s(%p, %s, %lu, %lu)\n", __FUNCTION__, self, bootconfig, size, + *fixup_buffer_size); + constexpr auto &&to_add = + "\nandroidboot.fstab_suffix=cf.f2fs." + "hctr2\nandroidboot.boot_devices=4010000000.pcie"; + const auto final_len = sizeof(to_add); + if (final_len > *fixup_buffer_size) { + *fixup_buffer_size = final_len; + return OUT_OF_RESOURCES; + } + *fixup_buffer_size = final_len; + memcpy(fixup, to_add, final_len); + + return SUCCESS; +} + +// Selects which device trees and overlays to use from those loaded by GBL. +__WEAK EfiStatus select_device_trees(struct GblEfiOsConfigurationProtocol *self, + GblEfiVerifiedDeviceTree *device_trees, + size_t num_device_trees) { + printf("%s(%p, %p %lu)\n", __FUNCTION__, self, device_trees, + num_device_trees); + return UNSUPPORTED; +} + +__WEAK EfiStatus exit_boot_services(EfiHandle image_handle, size_t map_key) { + printf("%s is called\n", __FUNCTION__); + return SUCCESS; +} diff --git a/lib/uefi/uefi_platform.h b/lib/uefi/uefi_platform.h new file mode 100644 index 00000000..3c860ece --- /dev/null +++ b/lib/uefi/uefi_platform.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __GBL_OS_CONFIGURATION_ +#define __GBL_OS_CONFIGURATION_ + +#include + +#include "protocols/gbl_efi_os_configuration_protocol.h" + +// Functions which should be implemented by individual platforms. +// The UEFI library provides a default no-op implementation that +// is weakly linked. + +EFI_STATUS efi_dt_fixup(struct EfiDtFixupProtocol *self, void *fdt, + size_t *buffer_size, uint32_t flags); + +EfiStatus fixup_kernel_commandline(struct GblEfiOsConfigurationProtocol *self, + const char *command_line, char *fixup, + size_t *fixup_buffer_size); + +EfiStatus fixup_bootconfig(struct GblEfiOsConfigurationProtocol *self, + const char *bootconfig, size_t size, char *fixup, + size_t *fixup_buffer_size); + +EfiStatus select_device_trees(struct GblEfiOsConfigurationProtocol *self, + GblEfiVerifiedDeviceTree *device_trees, + size_t num_device_trees); +EfiStatus exit_boot_services(EfiHandle image_handle, size_t map_key); +#endif \ No newline at end of file