mirror of
https://github.com/pound-emu/pound.git
synced 2025-12-16 04:36:57 +00:00
kvm: Add framework for machine types and MMIO dispatch
The core of the machine-type support is the new operations table, kvm_ops_t. This acts as a standard C-style virtual table decoupling the generic KVM core logic from target specific hardware emualtion. The kvm_t VM instance now points to an ops table, which defines the "personality" of the guest. A kvm_probe() factory function has been added to initialize a kvm_t instance with the correct ops table for a given machine type (eg, Switch 1). The ops table's .mmio_read and .mmio_write function pointers are the link between the armv8 CPU core and this new MMIO dispatcher. When a physical memory access is determined to be MMIO, the VM will call the appropriate function pointer, which in turn will use the MMIO dispatcher to find and execute the correct device handler. The initial implementation for the Switch 1 target (targets/switch1/hardware/probe.cpp) is a stub. The bootstrapping logic will be added in subsequent patches. Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
parent
dea94dc259
commit
c6706dd8a0
57 changed files with 533 additions and 70 deletions
196
src/kvm/guest.h
Normal file
196
src/kvm/guest.h
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace pound::kvm::memory
|
||||
{
|
||||
|
||||
/*
|
||||
* guest_memory_t - Describes a contiguous block of guest physical RAM.
|
||||
* @base: Pointer to the start of the host-allocated memory block.
|
||||
* @size: The size of the memory block in bytes.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* base;
|
||||
uint64_t size;
|
||||
} guest_memory_t;
|
||||
|
||||
/*
|
||||
* gpa_to_hva() - Translate a Guest Physical Address to a Host Virtual Address.
|
||||
* @memory: The guest memory region to translate within.
|
||||
* @gpa: The Guest Physical Address (offset) to translate.
|
||||
*
|
||||
* This function provides a fast, direct translation for a flat guest memory
|
||||
* model. It relies on the critical pre-condition that the guest's physical
|
||||
* RAM is backed by a single, contiguous block of virtual memory in the host's
|
||||
* userspace (typically allocated with mmap()).
|
||||
*
|
||||
* In this model, memory->base is the Host Virtual Address (HVA) of the start of
|
||||
* the backing host memory. The provided Guest Physical Address (gpa) is not
|
||||
* treated as a pointer, but as a simple byte offset from the start of the guest's
|
||||
* physical address space (PAS).
|
||||
*
|
||||
* The translation is therefore a single pointer-offset calculation. This establishes
|
||||
* a direct 1:1 mapping between the guest's PAS and the host's virtual memory block.
|
||||
*
|
||||
* The function asserts that GPA is within bounds. The caller is responsible for
|
||||
* ensuring the validity of the GPA prior to calling.
|
||||
*
|
||||
* Return: A valid host virtual address pointer corresponding to the GPA.
|
||||
*/
|
||||
static inline uint8_t* gpa_to_hva(guest_memory_t* memory, uint64_t gpa)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert(gpa < memory->size);
|
||||
uint8_t* hva = memory->base + gpa;
|
||||
return hva;
|
||||
}
|
||||
|
||||
// TODO(GloriousTacoo:aarch64) Implement big to little endian conversion for guest_mem read and write functions.
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* Guest Memory Read Functions
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* guest_mem_readb() - Read one byte from guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to read from.
|
||||
* Returns the 8-bit value read from memory.
|
||||
*/
|
||||
static inline uint8_t guest_mem_readb(guest_memory_t* memory, uint64_t gpa)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert(gpa <= memory->size);
|
||||
uint8_t* hva = gpa_to_hva(memory, gpa);
|
||||
return *hva;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_readw() - Read a 16-bit word from guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to read from (must be 2-byte aligned).
|
||||
* Returns the 16-bit value, corrected for host endianness.
|
||||
*/
|
||||
static inline uint16_t guest_mem_readw(guest_memory_t* memory, uint64_t gpa)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint16_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 2 bytes.
|
||||
assert((gpa & 1) == 0);
|
||||
uint16_t* hva = (uint16_t*)gpa_to_hva(memory, gpa);
|
||||
return *hva;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_readl() - Read a 32-bit long-word from guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to read from (must be 4-byte aligned).
|
||||
* Returns the 32-bit value, corrected for host endianness.
|
||||
*/
|
||||
static inline uint32_t guest_mem_readl(guest_memory_t* memory, uint64_t gpa)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint32_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 4 bytes.
|
||||
assert((gpa & 3) == 0);
|
||||
uint32_t* hva = (uint32_t*)gpa_to_hva(memory, gpa);
|
||||
return *hva;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_readq() - Read a 64-bit quad-word from guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to read from (must be 8-byte aligned).
|
||||
* Returns the 64-bit value, corrected for host endianness.
|
||||
*/
|
||||
static inline uint64_t guest_mem_readq(guest_memory_t* memory, uint64_t gpa)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint64_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 8 bytes.
|
||||
assert((gpa & 7) == 0);
|
||||
uint64_t* hva = (uint64_t*)gpa_to_hva(memory, gpa);
|
||||
return *hva;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================================================================
|
||||
* Guest Memory Write Functions
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* guest_mem_writeb() - Write one byte to guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to write to.
|
||||
* @val: The 8-bit value to write.
|
||||
*/
|
||||
static inline void guest_mem_writeb(guest_memory_t* memory, uint64_t gpa, uint8_t val)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert(gpa <= memory->size);
|
||||
uint8_t* hva = gpa_to_hva(memory, gpa);
|
||||
*hva = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_writew() - Write a 16-bit word to guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to write to (must be 2-byte aligned).
|
||||
* @val: The 16-bit value to write (will be converted to guest endianness).
|
||||
*/
|
||||
static inline void guest_mem_writew(guest_memory_t* memory, uint64_t gpa, uint16_t val)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint16_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 2 bytes.
|
||||
assert((gpa & 1) == 0);
|
||||
uint16_t* hva = (uint16_t*)gpa_to_hva(memory, gpa);
|
||||
*hva = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_writel() - Write a 32-bit long-word to guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to write to (must be 4-byte aligned).
|
||||
* @val: The 32-bit value to write.
|
||||
*/
|
||||
static inline void guest_mem_writel(guest_memory_t* memory, uint64_t gpa, uint32_t val)
|
||||
{
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint32_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 4 bytes.
|
||||
assert((gpa & 3) == 0);
|
||||
uint32_t* hva = (uint32_t*)gpa_to_hva(memory, gpa);
|
||||
*hva = val;
|
||||
}
|
||||
|
||||
/*
|
||||
* guest_mem_writeq() - Write a 64-bit quad-word to guest memory.
|
||||
* @memory: The guest memory region.
|
||||
* @gpa: The Guest Physical Address to write to (must be 8-byte aligned).
|
||||
* @val: The 64-bit value to write.
|
||||
*/
|
||||
static inline void guest_mem_writeq(guest_memory_t* memory, uint64_t gpa, uint64_t val)
|
||||
{
|
||||
assert(nullptr != memory);
|
||||
assert(nullptr != memory->base);
|
||||
assert((gpa + sizeof(uint64_t)) <= memory->size);
|
||||
// Check if gpa is aligned to 8 bytes.
|
||||
assert((gpa & 7) == 0);
|
||||
uint64_t* hva = (uint64_t*)gpa_to_hva(memory, gpa);
|
||||
*hva = val;
|
||||
}
|
||||
} // namespace pound::kvm::memory
|
||||
Loading…
Add table
Add a link
Reference in a new issue