pound-emu_pound/core/arm64/guest.h
Ronald Caesar 13b2e741b9 arm64/mem: Add initial software page table walker
Introduce a software-based page table walker for the arm64 MMU
emulation. This is foundational component for handling GVA-GPA
translations when a request missses the (future) software TLB.

For now, it handles only Page descriptors and does not yet support Block
descriptors or permission checks. These will be added in subsequent
patches.

Signed-off-by: Ronald Caesar <github43132@proton.me>
2025-08-23 02:28:28 -04:00

195 lines
6.6 KiB
C++

#pragma once
#include <cassert>
namespace pound::arm64::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::arm64::memory