Skip to content

Commit

Permalink
[app][uefi] Add block device protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangxp1998 committed Jan 6, 2025
1 parent 2c2b6b7 commit 2fb3bca
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 38 deletions.
11 changes: 11 additions & 0 deletions lib/bio/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion lib/bio/include/lib/bio.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,18 @@ enum bio_ioctl_num {
BIO_IOCTL_IS_MAPPED, /* if supported, returns whether or not the device is memory mapped. */
};

__END_CDECLS
void bio_iter_devices(bool (*callback)(void *, bdev_t *), void *cookie);

__END_CDECLS

#ifdef __cplusplus
template <typename Callable>
bool iter_device_callback(void *cookie, bdev_t *dev) {
auto func = reinterpret_cast<Callable *>(cookie);
return (*func)(dev);
}

template <typename Callable> void bio_iter_devices(Callable &&func) {
bio_iter_devices(&iter_device_callback<Callable>, &func);
}
#endif
216 changes: 198 additions & 18 deletions lib/uefi/boot_service_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@
*
*/
#include "boot_service_provider.h"
#include "arch/defines.h"
#include "boot_service.h"

#include "kernel/thread.h"
#include "kernel/vm.h"
#include "lib/bio.h"
#include "lib/dlmalloc.h"
#include "protocols/block_io_protocol.h"
#include "protocols/loaded_image_protocol.h"

#include "switch_stack.h"
#include "types.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

static vmm_aspace_t *old_aspace = nullptr;

Expand Down Expand Up @@ -62,7 +71,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<void *>(pa);
}
Expand Down Expand Up @@ -108,6 +118,24 @@ 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)) {
Expand Down Expand Up @@ -136,23 +164,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;
Expand Down Expand Up @@ -387,6 +398,172 @@ void copy_mem(void *dest, const void *src, size_t 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<EfiBlockIoInterface *>(self);
auto dev = reinterpret_cast<bdev_t *>(interface->dev);
if (lba >= dev->block_count) {
printf("OOB read %ld %ld\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<ssize_t>(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<EfiBlockIoInterface *>(
mspace_malloc(get_mspace(), sizeof(EfiBlockIoInterface)));
memset(interface, 0, sizeof(EfiBlockIoInterface));
auto dev = bio_open(reinterpret_cast<const char *>(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<char *>(io_stack) + kIoStackSize;
*intf = interface;
return SUCCESS;
}

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<EfiLoadedImageProtocol *>(
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;
}
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;
}
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<char **>(
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<EfiHandle *>(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;
}
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;
}

} // namespace

void setup_boot_service_table(EfiBootService *service) {
Expand All @@ -409,4 +586,7 @@ void setup_boot_service_table(EfiBootService *service) {
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;
}
20 changes: 19 additions & 1 deletion lib/uefi/boot_service_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -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}};
Expand All @@ -58,6 +58,24 @@ 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}};

using EFI_IMAGE_UNLOAD = EfiStatus (*)(EfiHandle);

//******************************************************
Expand Down
24 changes: 16 additions & 8 deletions lib/uefi/local/include/protocols/block_io_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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__
Loading

0 comments on commit 2fb3bca

Please sign in to comment.