NOVA-microhypervisor/inc/uefi.hpp

200 lines
6.2 KiB
C++

/*
* Unified Extensible Firmware Interface (UEFI)
*
* Copyright (C) 2019-2025 Udo Steinberg, BlueRock Security, Inc.
*
* This file is part of the NOVA microhypervisor.
*
* NOVA is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* NOVA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*/
#pragma once
#include "compiler.hpp"
#include "macros.hpp"
#include "signature.hpp"
#include "uuid.hpp"
class Uefi final
{
public:
struct Info
{
uint64_t rsdp;
uint64_t fdtp;
uint64_t mmap;
uint32_t msiz;
uint16_t dsiz;
uint16_t dver;
};
private:
// Data Types (2.3.1)
using handle = void *;
using uintn = uintptr_t;
using phys_addr = uint64_t;
using virt_addr = uint64_t;
// Status Codes (Appendix D)
enum class Status : uintn
{
SUCCESS = 0x0,
BUFFER_TOO_SMALL = 0x5 | BIT64 (63),
};
// Allocate Type (7.2)
enum class Allocate_type : unsigned
{
ANY_PAGES,
MAX_ADDRESS,
ADDRESS,
};
// Search Type (7.3)
enum class Search_type : unsigned
{
ALL_HANDLES,
BY_REGISTER_NOTIFY,
BY_PROTOCOL,
};
// Memory Type (7.2)
enum class Memory_type : unsigned
{
RESERVED,
LDR_CODE,
LDR_DATA,
BSV_CODE,
BSV_DATA,
RSV_CODE,
RSV_DATA,
CONVENTIONAL,
UNUSABLE,
ACPI_RECLAIM,
ACPI_NVS,
MMIO,
MMIO_PORT,
PAL_CODE,
};
// Memory Descriptor (7.2)
struct Memory_desc
{
uint32_t type;
phys_addr phys;
virt_addr virt;
uint64_t pcnt;
uint64_t attr;
};
// Table Header (4.2)
struct Table_header
{
uint64_t signature;
uint32_t revision;
uint32_t size;
uint32_t crc;
uint32_t reserved;
};
// Configuration Table (4.6)
struct Cfg_table
{
Uuid uuid;
void * table;
};
static_assert (__is_standard_layout (Cfg_table));
// Boot Services Table (4.4)
struct Bsv_table
{
Table_header header;
Status (EFICALL *f1[2])();
Status (EFICALL *allocate_pages)(Allocate_type, Memory_type, uintn, phys_addr *);
Status (EFICALL *free_pages)(phys_addr, uintn);
Status (EFICALL *get_memory_map)(uintn *, Memory_desc *, uintn *, uintn *, uint32_t *);
Status (EFICALL *allocate_pool)(Memory_type, uintn, void **);
Status (EFICALL *free_pool)(void *);
Status (EFICALL *f2[19])();
Status (EFICALL *exit_boot_services)(handle, uintn);
Status (EFICALL *f3[4])();
Status (EFICALL *disconnect_controller)(handle, handle, handle);
Status (EFICALL *open_protocol)(handle, Uuid const *, void **, handle, handle, uint32_t);
Status (EFICALL *close_protocol)(handle, Uuid const *, handle, handle);
Status (EFICALL *f4[2])();
Status (EFICALL *locate_handle_buffer)(Search_type, Uuid const *, void *, uintn *, handle **);
Status (EFICALL *f5[7])();
[[nodiscard]] SEC_INIT bool valid() const { return header.signature == Signature::u64 ("BOOTSERV") && header.size == sizeof (*this); }
SEC_INIT bool exit_boot_dev (handle) const;
SEC_INIT bool exit_boot_svc (handle, Info *) const;
};
static_assert (__is_standard_layout (Bsv_table));
// System Table (4.3)
struct Sys_table
{
Table_header header;
void * firmware_vendor;
uint32_t firmware_revision;
handle con_in_handle;
void * con_in;
handle con_out_handle;
void * con_out;
handle con_err_handle;
void * con_err;
void * rsv_table;
Bsv_table * bsv_table;
uintn cfg_entries;
Cfg_table * cfg_table;
[[nodiscard]] SEC_INIT bool valid() const { return header.signature == Signature::u64 ("IBI SYST") && header.size == sizeof (*this); }
};
static_assert (__is_standard_layout (Sys_table));
// PCI I/O Protocol (14.4)
class Pci_io_protocol final
{
private:
enum class Width : unsigned
{
UINT8,
UINT16,
UINT32,
UINT64,
};
Status (EFICALL *f1[6])();
Status (EFICALL *pci_read)(Pci_io_protocol const *, Width, uint32_t, uintn, void *);
Status (EFICALL *pci_write)(Pci_io_protocol const *, Width, uint32_t, uintn, void *);
Status (EFICALL *f2[6])();
Status (EFICALL *get_location)(Pci_io_protocol const *, uintn *, uintn *, uintn *, uintn *);
Status (EFICALL *f3[3])();
uint64_t rom_size;
void * rom_image;
public:
SEC_INIT bool should_disconnect() const;
SEC_INIT void disable_busmaster() const;
};
static_assert (__is_standard_layout (Pci_io_protocol));
public:
// UEFI parameters must be in a non-BSS section
SEC_DATA static inline constinit Info info asm ("uefi_info") { 0, 0, 0, 0, 0, 0 };
SEC_INIT static void init (handle, Sys_table *, Info *) asm ("uefi_init");
};