Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic UEFI support to LittleKernel #408

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/uefi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Build

```
make qemu-virt-arm64-test
```

## Run

```
qemu-system-aarch64 -cpu max -m 512 -smp 1 -machine virt,highmem=off \
-kernel qemu-virt-arm64-test/lk.elf \
-net none -nographic \
-drive if=none,file=lib/uefi/helloworld_aa64.efi,id=blk,format=raw \
-device virtio-blk-device,drive=blk
```


Once you see the main console prompt, enter `uefi_load virtio0` to load the hello world UEFI application.

```
starting app shell
entering main console loop
] uefi_load virtio0
bio_read returns 4096, took 1 msecs (4096000 bytes/sec)
PE header machine type: aa64
Valid UEFI application found.
Entry function located at 0xffff000780067380
Hello World!
```
54 changes: 54 additions & 0 deletions lib/uefi/defer.h
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
Binary file added lib/uefi/helloworld_aa64.efi
Binary file not shown.
138 changes: 138 additions & 0 deletions lib/uefi/include/boot_service.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright (C) 2023 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 __BOOT_SERVICE_TABLE_H__
#define __BOOT_SERVICE_TABLE_H__

#include "protocols/device_path_protocol.h"
#include "types.h"

typedef enum EFI_LOCATE_HANDLE_SEARCH_TYPE {
ALL_HANDLES = 0,
BY_REGITER_NOTIFY,
BY_PROTOCOL,
} EFI_LOCATE_HANDLE_SEARCH_TYPE;

typedef EFI_LOCATE_HANDLE_SEARCH_TYPE EfiLocateHandleSearchType;

typedef enum { EFI_NATIVE_INTERFACE } EFI_INTERFACE_TYPE;

typedef EFI_INTERFACE_TYPE EfiInterfaceType;

typedef enum EFI_ALLOCATOR_TYPE {
ALLOCATE_ANY_PAGES,
ALLOCATE_MAX_ADDRESS,
ALLOCATE_ADDRESS,
MAX_ALLOCATE_TYPE
} EfiAllocatorType;

typedef enum EFI_OPEN_PROTOCOL_ATTRIBUTE : uint32_t {
BY_HANDLE_PROTOCOL = 0x00000001,
GET_PROTOCOL = 0x00000002,
TEST_PROTOCOL = 0x00000004,
BY_CHILD_CONTROLLER = 0x00000008,
BY_DRIVER = 0x00000010,
EXCLUSIVE = 0x00000020,
} EfiOpenProtocolAttributes;

typedef struct {
uint32_t memory_type;
uint32_t padding;
EfiPhysicalAddr physical_start;
EfiVirtualAddr virtual_start;
uint64_t number_of_pages;
uint64_t attributes;
} EfiMemoryDescriptor;

typedef struct {
EfiHandle agent_handle;
EfiHandle controller_handle;
uint32_t attributes;
uint32_t open_count;
} EfiOpenProtocolInformationEntry;

typedef struct {
EfiTableHeader hdr;
EfiTpl (*raise_tpl)(EfiTpl new_tpl);
void (*restore_tpl)(EfiTpl old_tpl);
EfiStatus (*allocate_pages)(EfiAllocatorType type, EfiMemoryType memory_type, size_t pages,
EfiPhysicalAddr* memory);
EfiStatus (*free_pages)(EfiPhysicalAddr memory, size_t pages);
EfiStatus (*get_memory_map)(size_t* memory_map_size, EfiMemoryDescriptor* memory_map,
size_t* map_key, size_t* desc_size, uint32_t* desc_version);
EfiStatus (*allocate_pool)(EfiMemoryType pool_type, size_t size, void** buf);
EfiStatus (*free_pool)(void* buf);
EfiStatus (*create_event)(uint32_t type, EfiTpl notify_tpl, EfiEventNotify notify_fn,
void* notify_ctx, EfiEvent* event);
EfiStatus (*set_timer)(EfiEvent event, EfiTimerDelay type, uint64_t trigger_time);
EfiStatus (*wait_for_event)(size_t num_events, EfiEvent* event, size_t* index);
EfiStatus (*signal_event)(EfiEvent event);
EfiStatus (*close_event)(EfiEvent event);
EfiStatus (*check_event)(EfiEvent event);
EfiStatus (*install_protocol_interface)(EfiHandle* handle, const EfiGuid* protocol,
EfiInterfaceType intf_type, void* intf);
EfiStatus (*reinstall_protocol_interface)(EfiHandle hadle, const EfiGuid* protocol,
void* old_intf, void* new_intf);
EfiStatus (*uninstall_protocol_interface)(EfiHandle handle, const EfiGuid* protocol, void* intf);
EfiStatus (*handle_protocol)(EfiHandle handle, const EfiGuid* protocol, void** intf);
void* reserved;
EfiStatus (*register_protocol_notify)(const EfiGuid* protocol, EfiEvent event,
void** registration);
EfiStatus (*locate_handle)(EfiLocateHandleSearchType search_type, const EfiGuid* protocol,
void* search_key, size_t* buf_size, EfiHandle* buf);
EfiStatus (*locate_device_path)(const EfiGuid* protocol, EfiDevicePathProtocol** path,
EfiHandle* device);
EfiStatus (*install_configuration_table)(const EfiGuid* guid, void* table);
EfiStatus (*load_image)(bool boot_policy, EfiHandle parent_image_handle,
EfiDevicePathProtocol* path, void* src, size_t src_size,
EfiHandle* image_handle);
EfiStatus (*start_image)(EfiHandle image_handle, size_t* exit_data_size, char16_t** exit_data);
EfiStatus (*exit)(EfiHandle image_handle, EfiStatus exit_status, size_t exit_data_size,
char16_t* exit_data);
EfiStatus (*unload_image)(EfiHandle image_handle);
EfiStatus (*exit_boot_services)(EfiHandle image_handle, size_t map_key);
EfiStatus (*get_next_monotonic_count)(uint64_t* count);
EfiStatus (*stall)(size_t microseconds);
EfiStatus (*set_watchdog_timer)(size_t timeout, uint64_t watchdog_code, size_t data_size,
char16_t* watchdog_data);
EfiStatus (*connect_controller)(EfiHandle controller_handle, EfiHandle* driver_image_handle,
EfiDevicePathProtocol* remaining_path, bool recursive);
EfiStatus (*disconnect_controller)(EfiHandle controller_handle, EfiHandle driver_image_handle,
EfiHandle child_handle);
EfiStatus (*open_protocol)(EfiHandle handle, const EfiGuid* protocol, void** intf,
EfiHandle agent_handle, EfiHandle controller_handle,
EfiOpenProtocolAttributes attr);
EfiStatus (*close_protocol)(EfiHandle handle, const EfiGuid* protocol, EfiHandle agent_handle,
EfiHandle controller_handle);
EfiStatus (*open_protocol_information)(EfiHandle handle, const EfiGuid* protocol,
EfiOpenProtocolInformationEntry** entry_buf,
size_t* entry_count);
EfiStatus (*protocols_per_handle)(EfiHandle handle, EfiGuid*** protocol_buf,
size_t* protocol_buf_count);
EfiStatus (*locate_handle_buffer)(EfiLocateHandleSearchType search_type, const EfiGuid* protocol,
void* search_key, size_t* num_handles, EfiHandle** buf);
EfiStatus (*locate_protocol)(const EfiGuid* protocol, void* registration, void** intf);
EfiStatus (*install_multiple_protocol_interfaces)(EfiHandle* handle, ...);
EfiStatus (*uninstall_multiple_protocol_interfaces)(EfiHandle handle, ...);
EfiStatus (*calculate_crc32)(void* data, size_t len, uint32_t* crc32);
void (*copy_mem)(void* dest, const void* src, size_t len);
void (*set_mem)(void* buf, size_t len, uint8_t val);
EfiStatus (*create_event_ex)(EfiEventType type, EfiTpl notify_tpl, EfiEventNotify notify_fn,
const void* notify_ctx, const EfiGuid* event_group, EfiEvent* event);
} EfiBootService;

#endif // __BOOT_SERVICE_TABLE_H__
37 changes: 37 additions & 0 deletions lib/uefi/include/efi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (C) 2023 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 __EFI_H__
#define __EFI_H__

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "boot_service.h"
#include "protocols/android_boot_protocol.h"
#include "protocols/block_io_protocol.h"
#include "protocols/device_path_protocol.h"
#include "protocols/loaded_image_protocol.h"
#include "protocols/riscv_efi_boot_protocol.h"
#include "protocols/simple_network_protocol.h"
#include "protocols/simple_text_input_protocol.h"
#include "protocols/simple_text_output_protocol.h"
#include "system_table.h"
#include "types.h"

#endif // __EFI_H__
38 changes: 38 additions & 0 deletions lib/uefi/include/protocols/android_boot_protocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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/EFI_ANDROID_BOOT_PROTOCOL.md for details.

#include "types.h"

#ifndef __ANDROID_BOOT_PROTOCOL_H__
#define __ANDROID_BOOT_PROTOCOL_H__

typedef struct EfiAndroidBootProtocol {
uint64_t revision;
EfiStatus (*fastboot_usb_interface_start)(struct EfiAndroidBootProtocol* self,
size_t* max_packet_size);
EfiStatus (*fastboot_usb_interface_stop)(struct EfiAndroidBootProtocol* self);
EfiStatus (*fastboot_usb_receive)(struct EfiAndroidBootProtocol* self,
size_t* buffer_size, void* buffer);
EfiStatus (*fastboot_usb_send)(struct EfiAndroidBootProtocol* self,
size_t* buffer_size, const void* buffer);
EfiEvent wait_for_send_completion;
} EfiAndroidBootProtocol;

#endif //__ANDROID_BOOT_PROTOCOL_H__
57 changes: 57 additions & 0 deletions lib/uefi/include/protocols/block_io_protocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 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 "types.h"

#ifndef __BLOCK_IO_PROTOCOL_H__
#define __BLOCK_IO_PROTOCOL_H__

typedef struct EfiBlockIoMedia EfiBlockIoMedia;
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);
};

struct EfiBlockIoMedia {
// present in rev1
uint32_t media_id;
bool removable_media;
bool media_present;
bool logical_partition;
bool read_only;
bool write_caching;
uint32_t block_size;
uint32_t io_align;
uint64_t last_block;

// present in rev2
uint64_t lowest_aligned_lba;
uint32_t logical_blocks_per_physical_block;

// present in rev3
uint32_t optimal_transfer_length_granularity;
};

#endif //__BLOCK_IO_PROTOCOL_H__
Loading
Loading