diff --git a/lib/bio/bio.c b/lib/bio/bio.c index d11165bd27..afdd0114aa 100644 --- a/lib/bio/bio.c +++ b/lib/bio/bio.c @@ -534,6 +534,17 @@ void bio_unregister_device(bdev_t *dev) { bdev_dec_ref(dev); // remove the ref the list used to have } +void bio_iter_devices(bool (*callback)(void *, bdev_t *), void *cookie) { + bdev_t *entry = NULL; + mutex_acquire(&bdevs.lock); + list_for_every_entry(&bdevs.list, entry, bdev_t, node) { + if (!callback(cookie, entry)) { + break; + } + } + mutex_release(&bdevs.lock); +} + void bio_dump_devices(void) { printf("block devices:\n"); bdev_t *entry; diff --git a/lib/bio/include/lib/bio.h b/lib/bio/include/lib/bio.h index 4019f909f0..e8aaf5dae3 100644 --- a/lib/bio/include/lib/bio.h +++ b/lib/bio/include/lib/bio.h @@ -130,4 +130,23 @@ enum bio_ioctl_num { BIO_IOCTL_IS_MAPPED, /* if supported, returns whether or not the device is memory mapped. */ }; -__END_CDECLS \ No newline at end of file +// The callback will be called once for every block device, with the cookie and pointer +// to the bdev structure. Note callback would be called with internal mutex held, which +// prevents other process/threads from using APIs such as bio_open, so kindly ask callers +// not to do any long blocking operations in callback functions. If the callback function +// returns |false|, iteration stop immediately, and bio_iter_devices returns. +void bio_iter_devices(bool (*callback)(void *, bdev_t *), void *cookie); + +__END_CDECLS + +#ifdef __cplusplus +template +bool iter_device_callback(void *cookie, bdev_t *dev) { + auto func = reinterpret_cast(cookie); + return (*func)(dev); +} + +template void bio_iter_devices(Callable &&func) { + bio_iter_devices(&iter_device_callback, &func); +} +#endif diff --git a/lib/uefi/boot_service_provider.cpp b/lib/uefi/boot_service_provider.cpp index 3ff9bd4d2c..ca619ba399 100644 --- a/lib/uefi/boot_service_provider.cpp +++ b/lib/uefi/boot_service_provider.cpp @@ -15,13 +15,26 @@ * */ #include "boot_service_provider.h" +#include "arch/defines.h" #include "boot_service.h" + +#include "defer.h" +#include "kernel/thread.h" #include "kernel/vm.h" +#include "lib/bio.h" #include "lib/dlmalloc.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 "switch_stack.h" #include "types.h" #include #include #include +#include static vmm_aspace_t *old_aspace = nullptr; @@ -62,7 +75,8 @@ void *identity_map(void *addr, size_t size) { printf("Failed to identity map physical address 0x%lx\n", pa); return nullptr; } - printf("Identity mapped physical address 0x%lx flags 0x%x\n", pa, flags); + printf("Identity mapped physical address 0x%lx size %zu flags 0x%x\n", pa, + size, flags); return reinterpret_cast(pa); } @@ -108,14 +122,32 @@ bool guid_eq(const EfiGuid *a, const EfiGuid &b) { return memcmp(a, &b, sizeof(*a)) == 0; } +constexpr size_t kHeapSize = 256ul * 1024 * 1024; + +void *get_heap() { + static auto heap = alloc_page(kHeapSize); + return heap; +} + +mspace create_mspace_with_base_limit(void *base, size_t capacity, int locked) { + auto space = create_mspace_with_base(get_heap(), kHeapSize, 1); + mspace_set_footprint_limit(space, capacity); + return space; +} + +mspace get_mspace() { + static auto space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); + return space; +} + EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, void **intf) { if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { printf("handle_protocol(%p, LOADED_IMAGE_PROTOCOL_GUID, %p);\n", handle, intf); - auto loaded_image = static_cast( - malloc(sizeof(EFI_LOADED_IMAGE_PROTOCOL))); - loaded_image = {}; + const auto loaded_image = static_cast( + mspace_malloc(get_mspace(), sizeof(EFI_LOADED_IMAGE_PROTOCOL))); + *loaded_image = {}; loaded_image->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; loaded_image->ParentHandle = nullptr; loaded_image->SystemTable = nullptr; @@ -136,23 +168,6 @@ EfiStatus handle_protocol(EfiHandle handle, const EfiGuid *protocol, return UNSUPPORTED; } -constexpr size_t kHeapSize = 8ul * 1024 * 1024; -void *get_heap() { - static auto heap = alloc_page(kHeapSize); - return heap; -} - -mspace create_mspace_with_base_limit(void *base, size_t capacity, int locked) { - auto space = create_mspace_with_base(get_heap(), kHeapSize, 1); - mspace_set_footprint_limit(space, capacity); - return space; -} - -mspace get_mspace() { - static auto space = create_mspace_with_base_limit(get_heap(), kHeapSize, 1); - return space; -} - EfiStatus allocate_pool(EfiMemoryType pool_type, size_t size, void **buf) { if (buf == nullptr) { return INVALID_PARAMETER; @@ -323,7 +338,7 @@ EfiStatus allocate_pages(EfiAllocatorType type, EfiMemoryType memory_type, if (memory == nullptr) { return INVALID_PARAMETER; } - if (type == ALLOCATE_MAX_ADDRESS && *memory != 0xffffffffffffffff) { + if (type == ALLOCATE_MAX_ADDRESS && *memory < 0xFFFFFFFF) { printf("allocate_pages(%d, %d, %zu, 0x%llx) unsupported\n", type, memory_type, pages, *memory); return UNSUPPORTED; @@ -382,6 +397,311 @@ EfiStatus exit_boot_services(EfiHandle image_handle, size_t map_key) { return SUCCESS; } +void copy_mem(void *dest, const void *src, size_t len) { + memcpy(dest, src, len); +} +void set_mem(void *buf, size_t len, uint8_t val) { memset(buf, val, len); } + +EfiTpl raise_tpl(EfiTpl new_tpl) { + printf("%s is called %zu\n", __FUNCTION__, new_tpl); + return APPLICATION; +} + +EfiStatus reset(EfiBlockIoProtocol *self, bool extended_verification) { + printf("%s is called\n", __FUNCTION__); + return UNSUPPORTED; +} + +EfiStatus read_blocks(EfiBlockIoProtocol *self, uint32_t media_id, uint64_t lba, + size_t buffer_size, void *buffer) { + auto interface = reinterpret_cast(self); + auto dev = reinterpret_cast(interface->dev); + if (lba >= dev->block_count) { + printf("OOB read %llu %u\n", lba, dev->block_count); + return END_OF_MEDIA; + } + + const auto bytes_read = + call_with_stack(interface->io_stack, bio_read_block, dev, buffer, lba, + buffer_size / dev->block_size); + if (bytes_read != static_cast(buffer_size)) { + printf("Failed to read %ld bytes from %s\n", buffer_size, dev->name); + return DEVICE_ERROR; + } + return SUCCESS; +} + +EfiStatus write_blocks(EfiBlockIoProtocol *self, uint32_t media_id, + uint64_t lba, size_t buffer_size, const void *buffer) { + printf("%s is called\n", __FUNCTION__); + return SUCCESS; +} + +EfiStatus flush_blocks(EfiBlockIoProtocol *self) { + printf("%s is called\n", __FUNCTION__); + return SUCCESS; +} + +EfiStatus open_block_device(EfiHandle handle, void **intf) { + static constexpr size_t kIoStackSize = 1024ul * 1024 * 64; + static void *io_stack = nullptr; + if (io_stack == nullptr) { + vmm_alloc(vmm_get_kernel_aspace(), "uefi_io_stack", kIoStackSize, &io_stack, + PAGE_SIZE_SHIFT, 0, 0); + } + printf("%s(%s)\n", __FUNCTION__, handle); + const auto interface = reinterpret_cast( + mspace_malloc(get_mspace(), sizeof(EfiBlockIoInterface))); + memset(interface, 0, sizeof(EfiBlockIoInterface)); + auto dev = bio_open(reinterpret_cast(handle)); + interface->dev = dev; + interface->protocol.reset = reset; + interface->protocol.read_blocks = read_blocks; + interface->protocol.write_blocks = write_blocks; + interface->protocol.flush_blocks = flush_blocks; + interface->protocol.media = &interface->media; + interface->media.block_size = dev->block_size; + interface->media.io_align = interface->media.block_size; + interface->media.last_block = dev->block_count - 1; + interface->io_stack = reinterpret_cast(io_stack) + kIoStackSize; + *intf = interface; + return SUCCESS; +} + +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(0x%lx, \"%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(0x%lx, %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(0x%lx, %lx, %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, + EfiOpenProtocolAttributes attr) { + if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { + auto interface = reinterpret_cast( + mspace_malloc(get_mspace(), sizeof(EfiLoadedImageProtocol))); + memset(interface, 0, sizeof(*interface)); + interface->parent_handle = handle; + interface->image_base = handle; + *intf = interface; + printf("%s(LOADED_IMAGE_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + return SUCCESS; + } else if (guid_eq(protocol, EFI_DEVICE_PATH_PROTOCOL_GUID)) { + printf( + "%s(EFI_DEVICE_PATH_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + return UNSUPPORTED; + } else if (guid_eq(protocol, EFI_BLOCK_IO_PROTOCOL_GUID)) { + printf("%s(EFI_BLOCK_IO_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + return open_block_device(handle, intf); + } else if (guid_eq(protocol, EFI_BLOCK_IO2_PROTOCOL_GUID)) { + printf("%s(EFI_BLOCK_IO2_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + return UNSUPPORTED; + } else if (guid_eq(protocol, EFI_DT_FIXUP_PROTOCOL_GUID)) { + printf("%s(EFI_DT_FIXUP_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + if (intf != nullptr) { + EfiDtFixupProtocol *fixup = nullptr; + allocate_pool(BOOT_SERVICES_DATA, sizeof(EfiDtFixupProtocol), + reinterpret_cast(&fixup)); + if (fixup == nullptr) { + return OUT_OF_RESOURCES; + } + fixup->revision = EFI_DT_FIXUP_PROTOCOL_REVISION; + fixup->fixup = efi_dt_fixup; + *intf = reinterpret_cast(fixup); + } + return SUCCESS; + } else if (guid_eq(protocol, EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID)) { + printf("%s(EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID, handle=0x%lx, " + "agent_handle=0x%lx, " + "controller_handle=0x%lx, attr=0x%x)\n", + __FUNCTION__, handle, agent_handle, controller_handle, attr); + GblEfiOsConfigurationProtocol *config = nullptr; + allocate_pool(BOOT_SERVICES_DATA, sizeof(*config), + reinterpret_cast(&config)); + if (config == nullptr) { + return OUT_OF_RESOURCES; + } + config->revision = GBL_EFI_OS_CONFIGURATION_PROTOCOL_REVISION; + config->fixup_bootconfig = fixup_bootconfig; + config->fixup_kernel_commandline = fixup_kernel_commandline; + config->select_device_trees = select_device_trees; + *intf = reinterpret_cast(config); + return SUCCESS; + } + printf("%s is unsupported 0x%x 0x%x 0x%x 0x%llx\n", __FUNCTION__, + protocol->data1, protocol->data2, protocol->data3, + *(uint64_t *)&protocol->data4); + return UNSUPPORTED; +} + +EfiStatus close_protocol(EfiHandle handle, const EfiGuid *protocol, + EfiHandle agent_handle, EfiHandle controller_handle) { + if (guid_eq(protocol, LOADED_IMAGE_PROTOCOL_GUID)) { + printf("%s(LOADED_IMAGE_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx)\n", + __FUNCTION__, handle, agent_handle, controller_handle); + return SUCCESS; + } else if (guid_eq(protocol, EFI_DEVICE_PATH_PROTOCOL_GUID)) { + printf( + "%s(EFI_DEVICE_PATH_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx)\n", + __FUNCTION__, handle, agent_handle, controller_handle); + return SUCCESS; + } else if (guid_eq(protocol, EFI_BLOCK_IO_PROTOCOL_GUID)) { + printf("%s(EFI_BLOCK_IO_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx)\n", + __FUNCTION__, handle, agent_handle, controller_handle); + return SUCCESS; + } else if (guid_eq(protocol, EFI_DT_FIXUP_PROTOCOL_GUID)) { + printf("%s(EFI_DT_FIXUP_PROTOCOL_GUID, handle=0x%lx, agent_handle=0x%lx, " + "controller_handle=0x%lx)\n", + __FUNCTION__, handle, agent_handle, controller_handle); + return SUCCESS; + } + printf("%s is called\n", __FUNCTION__); + return UNSUPPORTED; +} + +EfiStatus list_block_devices(size_t *num_handles, EfiHandle **buf) { + size_t device_count = 0; + bio_iter_devices([&device_count](bdev_t *dev) { + device_count++; + return true; + }); + auto devices = reinterpret_cast( + mspace_malloc(get_mspace(), sizeof(char *) * device_count)); + size_t i = 0; + bio_iter_devices([&i, devices, device_count](bdev_t *dev) { + devices[i] = dev->name; + i++; + return i < device_count; + }); + *num_handles = i; + *buf = reinterpret_cast(devices); + return SUCCESS; +} + +EfiStatus locate_handle_buffer(EfiLocateHandleSearchType search_type, + const EfiGuid *protocol, void *search_key, + size_t *num_handles, EfiHandle **buf) { + if (guid_eq(protocol, EFI_BLOCK_IO_PROTOCOL_GUID)) { + if (search_type == BY_PROTOCOL) { + return list_block_devices(num_handles, buf); + } + printf("%s(0x%x, EFI_BLOCK_IO_PROTOCOL_GUID, search_key=0x%lx)\n", + __FUNCTION__, search_type, search_key); + return UNSUPPORTED; + } else if (guid_eq(protocol, EFI_TEXT_INPUT_PROTOCOL_GUID)) { + printf("%s(0x%x, EFI_TEXT_INPUT_PROTOCOL_GUID, search_key=0x%lx)\n", + __FUNCTION__, search_type, search_key); + return NOT_FOUND; + } else if (guid_eq(protocol, EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID)) { + printf( + "%s(0x%x, EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID, search_key=0x%lx)\n", + __FUNCTION__, search_type, search_key); + if (num_handles != nullptr) { + *num_handles = 1; + } + if (buf != nullptr) { + *buf = reinterpret_cast( + mspace_malloc(get_mspace(), sizeof(buf))); + } + return SUCCESS; + } else if (guid_eq(protocol, EFI_DT_FIXUP_PROTOCOL_GUID)) { + printf("%s(0x%x, EFI_DT_FIXUP_PROTOCOL_GUID, search_key=0x%lx)\n", + __FUNCTION__, search_type, search_key); + if (num_handles != nullptr) { + *num_handles = 1; + } + if (buf != nullptr) { + *buf = reinterpret_cast( + mspace_malloc(get_mspace(), sizeof(buf))); + } + return SUCCESS; + } + printf("%s(0x%x, (0x%x 0x%x 0x%x 0x%llx), search_key=0x%lx)\n", __FUNCTION__, + search_type, protocol->data1, protocol->data2, protocol->data3, + *(uint64_t *)&protocol->data4, search_key); + return UNSUPPORTED; +} + +EfiStatus wait_for_event(size_t num_events, EfiEvent *event, size_t *index) { + return UNSUPPORTED; +} + } // namespace void setup_boot_service_table(EfiBootService *service) { @@ -402,4 +722,10 @@ void setup_boot_service_table(EfiBootService *service) { service->locate_device_path = locate_device_path; service->install_configuration_table = install_configuration_table; service->exit_boot_services = exit_boot_services; + service->copy_mem = copy_mem; + service->set_mem = set_mem; + service->open_protocol = open_protocol; + service->locate_handle_buffer = locate_handle_buffer; + service->close_protocol = close_protocol; + service->wait_for_event = wait_for_event; } diff --git a/lib/uefi/boot_service_provider.h b/lib/uefi/boot_service_provider.h index 63354209a1..d89d78f945 100644 --- a/lib/uefi/boot_service_provider.h +++ b/lib/uefi/boot_service_provider.h @@ -31,7 +31,7 @@ static constexpr auto LOADED_IMAGE_PROTOCOL_GUID = {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}; static constexpr auto EFI_DEVICE_PATH_PROTOCOL_GUID = - EfiGuid{0x09576e91, + EfiGuid{0x9576e91, 0x6d3f, 0x11d2, {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}; @@ -58,6 +58,36 @@ static constexpr auto EFI_LOAD_FILE2_PROTOCOL_GUID = 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d}}; +static constexpr auto EFI_BLOCK_IO_PROTOCOL_GUID = + EfiGuid{0x964e5b21, + 0x6459, + 0x11d2, + {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}; + +static constexpr auto EFI_BLOCK_IO2_PROTOCOL_GUID = + EfiGuid{0xa77b2472, + 0xe282, + 0x4e9f, + {0xa2, 0x45, 0xc2, 0xc0, 0xe2, 0x7b, 0xbc, 0xc1}}; + +static constexpr auto EFI_TEXT_INPUT_PROTOCOL_GUID = + EfiGuid{0x387477c1, + 0x69c7, + 0x11d2, + {0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}; + +static constexpr auto EFI_GBL_OS_CONFIGURATION_PROTOCOL_GUID = + EfiGuid{0xdda0d135, + 0xaa5b, + 0x42ff, + {0x85, 0xac, 0xe3, 0xad, 0x6e, 0xfb, 0x46, 0x19}}; + +static constexpr auto EFI_DT_FIXUP_PROTOCOL_GUID = + EfiGuid{0xe617d64c, + 0xfe08, + 0x46da, + {0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00}}; + using EFI_IMAGE_UNLOAD = EfiStatus (*)(EfiHandle); //****************************************************** diff --git a/lib/uefi/configuration_table.cpp b/lib/uefi/configuration_table.cpp index ef91157664..ab9133b3c9 100644 --- a/lib/uefi/configuration_table.cpp +++ b/lib/uefi/configuration_table.cpp @@ -17,15 +17,25 @@ #include "configuration_table.h" #include "boot_service_provider.h" +#include "libfdt.h" +#include "platform.h" #include "system_table.h" #include void setup_configuration_table(EfiSystemTable *table) { - auto &rng = table->configuration_table[0]; + auto &rng = table->configuration_table[table->number_of_table_entries++]; rng.vendor_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; rng.vendor_table = alloc_page(PAGE_SIZE); auto rng_seed = reinterpret_cast(rng.vendor_table); rng_seed->size = 512; memset(&rng_seed->bits, 0, rng_seed->size); - table->number_of_table_entries = 1; + + const void *fdt = get_fdt(); + if (fdt != nullptr) { + auto &dtb = table->configuration_table[table->number_of_table_entries++]; + dtb.vendor_guid = DEVICE_TREE_GUID; + const auto fdt_size = fdt_totalsize(fdt); + dtb.vendor_table = alloc_page(fdt_size); + memcpy(dtb.vendor_table, fdt, fdt_size); + } } \ No newline at end of file diff --git a/lib/uefi/configuration_table.h b/lib/uefi/configuration_table.h index 348608fd3a..6b3978c237 100644 --- a/lib/uefi/configuration_table.h +++ b/lib/uefi/configuration_table.h @@ -31,6 +31,11 @@ static constexpr auto LINUX_EFI_RANDOM_SEED_TABLE_GUID = 0x7ceb, 0x42f2, {0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b}}; +static constexpr auto DEVICE_TREE_GUID = + EfiGuid{0xb1b621d5, + 0xf19c, + 0x41a5, + {0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0}}; void setup_configuration_table(EfiSystemTable *table); diff --git a/lib/uefi/local/include/protocols/block_io_protocol.h b/lib/uefi/local/include/protocols/block_io_protocol.h index 48a975dda8..a2c54e6b47 100644 --- a/lib/uefi/local/include/protocols/block_io_protocol.h +++ b/lib/uefi/local/include/protocols/block_io_protocol.h @@ -25,13 +25,14 @@ typedef struct EfiBlockIoProtocol EfiBlockIoProtocol; struct EfiBlockIoProtocol { uint64_t revision; - EfiBlockIoMedia* media; - EfiStatus (*reset)(EfiBlockIoProtocol* self, bool extended_verification); - EfiStatus (*read_blocks)(EfiBlockIoProtocol* self, uint32_t media_id, uint64_t lba, - size_t buffer_size, void* buffer); - EfiStatus (*write_blocks)(EfiBlockIoProtocol* self, uint32_t media_id, uint64_t lba, - size_t buffer_size, const void* buffer); - EfiStatus (*flush_blocks)(EfiBlockIoProtocol* self); + EfiBlockIoMedia *media; + EfiStatus (*reset)(EfiBlockIoProtocol *self, bool extended_verification); + EfiStatus (*read_blocks)(EfiBlockIoProtocol *self, uint32_t media_id, + uint64_t lba, size_t buffer_size, void *buffer); + EfiStatus (*write_blocks)(EfiBlockIoProtocol *self, uint32_t media_id, + uint64_t lba, size_t buffer_size, + const void *buffer); + EfiStatus (*flush_blocks)(EfiBlockIoProtocol *self); }; struct EfiBlockIoMedia { @@ -54,4 +55,11 @@ struct EfiBlockIoMedia { uint32_t optimal_transfer_length_granularity; }; -#endif //__BLOCK_IO_PROTOCOL_H__ +struct EfiBlockIoInterface { + EfiBlockIoProtocol protocol; + void *dev; + EfiBlockIoMedia media; + void *io_stack; +}; + +#endif //__BLOCK_IO_PROTOCOL_H__ diff --git a/lib/uefi/local/include/protocols/dt_fixup_protocol.h b/lib/uefi/local/include/protocols/dt_fixup_protocol.h new file mode 100644 index 0000000000..ccf7a5bc3e --- /dev/null +++ b/lib/uefi/local/include/protocols/dt_fixup_protocol.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 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. + * + */ + +// This is a protocol proposed by U-boot and being used by Kernel UEFI stub. +// https://github.com/U-Boot-EFI/EFI_DT_FIXUP_PROTOCOL +// https://github.com/u-boot/u-boot/blob/master/include/efi_dt_fixup.h + +#ifndef __EFI_DT_FIXUP_PROTOCOL_H__ +#define __EFI_DT_FIXUP_PROTOCOL_H__ + +#include "types.h" + +constexpr uint64_t EFI_DT_FIXUP_PROTOCOL_REVISION = 0x00010000; + +// Add nodes and update properties +constexpr uint32_t EFI_DT_APPLY_FIXUPS = 0x00000001; +// Reserve memory according to the /reserved-memory node and the memory +// reservation block +constexpr uint32_t EFI_DT_RESERVE_MEMORY = 0x00000002; +// Install the device-tree as configuration table +constexpr uint32_t EFI_DT_INSTALL_TABLE = 0x00000004; +constexpr uint32_t EFI_DT_ALL = + EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY | EFI_DT_INSTALL_TABLE; + +typedef struct EfiDtFixupProtocol { + uint64_t revision; + EfiStatus (*fixup)(struct EfiDtFixupProtocol *self, void *fdt, + size_t *buffer_size, uint32_t flags); +} EfiDtFixupProtocol; + +#endif // __EFI_DT_FIXUP_PROTOCOL_H__ diff --git a/lib/uefi/local/include/protocols/gbl_efi_os_configuration_protocol.h b/lib/uefi/local/include/protocols/gbl_efi_os_configuration_protocol.h new file mode 100644 index 0000000000..8cbc6f607c --- /dev/null +++ b/lib/uefi/local/include/protocols/gbl_efi_os_configuration_protocol.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 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. + * + */ + +// This is a custom protocol introduced by GBL. +// See gbl/docs/gbl_efi_os_configuration_protocol.md for details. + +#ifndef __GBL_OS_CONFIGURATION_PROTOCOL_H__ +#define __GBL_OS_CONFIGURATION_PROTOCOL_H__ + +#include "types.h" + +static constexpr size_t GBL_EFI_OS_CONFIGURATION_PROTOCOL_REVISION = 0x00000000; + +typedef enum GBL_EFI_DEVICE_TREE_SOURCE { + BOOT, + VENDOR_BOOT, + DTBO, + DTB +} GblEfiDeviceTreeSource; + +typedef struct { + // GblDeviceTreeSource + uint32_t source; + // Values are zeroed and must not be used in case of BOOT / VENDOR_BOOT source + uint32_t id; + uint32_t rev; + uint32_t custom[4]; + // Make sure GblDeviceTreeMetadata size is 8-bytes aligned. Also reserved for + // the future cases + uint32_t reserved; +} GblEfiDeviceTreeMetadata; + +typedef struct { + GblEfiDeviceTreeMetadata metadata; + // Base device tree / overlay buffer (guaranteed to be 8-bytes aligned), + // cannot be NULL. Device tree size can be identified by the header totalsize + // field + const void *device_tree; + // Indicates whether this device tree (or overlay) must be included in the + // final device tree. Set to true by a FW if this component must be used + bool selected; +} GblEfiVerifiedDeviceTree; + +// Warning: API is UNSTABLE +// Documentation: +// https://cs.android.com/android/platform/superproject/main/+/main:bootable/libbootloader/gbl/docs/gbl_os_configuration_protocol.md +typedef struct GblEfiOsConfigurationProtocol { + uint64_t revision; + + // 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); + + // 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); + + // 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); +} GblEfiOsConfigurationProtocol; + +#endif //__GBL_OS_CONFIGURATION_PROTOCOL_H__ \ No newline at end of file diff --git a/lib/uefi/switch_stack.S b/lib/uefi/switch_stack.S index ea188c554c..e4ffd8bbae 100644 --- a/lib/uefi/switch_stack.S +++ b/lib/uefi/switch_stack.S @@ -18,21 +18,23 @@ #include -// int call_with_stack(void *stack, int (*fp)(), int param1, int param2); +// int call_with_stack(void *stack, int (*fp)(), int arg1, int arg2, int arg3, int arg4); FUNCTION(call_with_stack) stp fp, lr, [sp, #-16]! mov fp, sp sub x0,x0,16 -mov x6,sp -str x6,[x0] +mov x7,sp +str x7,[x0] mov sp,x0 -mov x5,x1 +mov x6,x1 mov x0,x2 mov x1,x3 -blr x5 -ldr x6,[sp] -mov sp,x6 +mov x2,x4 +mov x3,x5 +blr x6 +ldr x7,[sp] +mov sp,x7 ldp fp, lr, [sp], 16 ret lr diff --git a/lib/uefi/switch_stack.h b/lib/uefi/switch_stack.h index 572559f34d..45948aadd9 100644 --- a/lib/uefi/switch_stack.h +++ b/lib/uefi/switch_stack.h @@ -15,13 +15,28 @@ * */ +#include + #ifdef __cplusplus extern "C" { #endif -int call_with_stack(void *stack, int (*fp)(void *, void *), void *param1, - void *param2); +size_t call_with_stack(void *stack, int (*fp)(void *, void *), void *param1, + void *param2, void *param3 = nullptr, + void *param4 = nullptr); + +#ifdef __cplusplus +} + +#endif #ifdef __cplusplus +template +size_t call_with_stack(void *stack, Function &&fp, P1 &¶m1, P2 &¶m2, + P3 param3, P4 &¶m4) { + return call_with_stack( + stack, reinterpret_cast(fp), + reinterpret_cast(param1), reinterpret_cast(param2), + reinterpret_cast(param3), reinterpret_cast(param4)); } #endif \ No newline at end of file diff --git a/lib/uefi/uefi.cpp b/lib/uefi/uefi.cpp index ed5b3bdf70..604a3d1f26 100644 --- a/lib/uefi/uefi.cpp +++ b/lib/uefi/uefi.cpp @@ -18,6 +18,7 @@ #include "boot_service.h" #include "boot_service_provider.h" #include "defer.h" +#include "kernel/thread.h" #include "pe.h" #include @@ -288,6 +289,7 @@ int load_sections_and_execute(bdev_t *dev, table.runtime_service = &runtime_service; table.boot_services = &boot_service; table.header.signature = EFI_SYSTEM_TABLE_SIGNATURE; + table.header.revision = 2 << 16; EfiSimpleTextOutputProtocol console_out = get_text_output_protocol(); table.con_out = &console_out; table.configuration_table = @@ -297,6 +299,8 @@ int load_sections_and_execute(bdev_t *dev, constexpr size_t kStackSize = 8 * 1024ul * 1024; auto stack = reinterpret_cast(alloc_page(kStackSize, 23)); memset(stack, 0, kStackSize); + printf("Calling kernel with stack [0x%lx, 0x%lx]\n", stack, + stack + kStackSize - 1); return call_with_stack(stack + kStackSize, entry, image_base, &table); } @@ -306,7 +310,10 @@ int load_pe_file(const char *blkdev) { printf("error opening block device %s\n", blkdev); return -1; } - DEFER { bio_close(dev); }; + DEFER { + bio_close(dev); + dev = nullptr; + }; constexpr size_t kBlocKSize = 4096; lk_time_t t = current_time(); diff --git a/platform/include/platform.h b/platform/include/platform.h index 78353e4442..0db8c41396 100644 --- a/platform/include/platform.h +++ b/platform/include/platform.h @@ -82,5 +82,8 @@ void platform_init(void); /* called by the arch init code to get the platform to set up any mmu mappings it may need */ void platform_init_mmu_mappings(void); +/* Called by LK to get the device tree */ +const void *get_fdt(void); + __END_CDECLS diff --git a/platform/init.c b/platform/init.c index 9f36a3b00f..5703cedb6b 100644 --- a/platform/init.c +++ b/platform/init.c @@ -27,3 +27,8 @@ __WEAK void platform_init(void) { __WEAK void platform_quiesce(void) { } + +__WEAK const void *get_fdt(void) { + return NULL; +} + diff --git a/platform/qemu-virt-arm/platform.c b/platform/qemu-virt-arm/platform.c index 6b722f72df..2f02b90771 100644 --- a/platform/qemu-virt-arm/platform.c +++ b/platform/qemu-virt-arm/platform.c @@ -60,6 +60,10 @@ struct mmu_initial_mapping mmu_initial_mappings[] = { const void *fdt = (void *)KERNEL_BASE; +const void *get_fdt(void) { + return fdt; +} + void platform_early_init(void) { const struct pl011_config uart_config = { .base = UART_BASE,