mem: Refactor vma/vmo

This commit is contained in:
2026-10-25 17:49:25 +01:00
parent ef08e2e5d7
commit efe1feb852
6 changed files with 1084 additions and 317 deletions
+32 -5
View File
@@ -2,21 +2,34 @@
#pragma once
#include <zinnia/amap.h>
#include <zinnia/errno.h>
#include <zinnia/mman.h>
#include <zinnia/mutex.h>
#include <zinnia/pmap.h>
#include <zinnia/spin.h>
#include <zinnia/rwlock.h>
#include <zinnia/tailq.h>
#include <zinnia/vmo.h>
enum vma_flags : uint8_t {
VMA_SHARED = 1 << 0,
VMA_NEEDS_COPY = 1 << 1,
};
struct vma;
struct vma_mapping {
size_t start_page;
size_t end_page;
size_t offset_page;
struct vmo* object;
struct amap* amap;
size_t amap_offset;
struct vma* vma;
enum prot_flags prot;
enum vma_flags flags;
tailq_link(struct vma_mapping) link;
tailq_link(struct vma_mapping) object_link;
};
// Virtual address space.
@@ -24,30 +37,44 @@ struct vma {
// Architecture-specific virtual memory map implementation.
struct pmap pmap;
tailq_head(struct vma_mapping) mappings;
struct spinlock lock;
struct rwlock lock;
mutex_t map_lock;
struct refcount rc;
};
// Try to create a new, empty virtual address space.
errno_t vma_new(struct vma** out);
// Delete a virtual address space.
void vma_free(struct vma* v);
void vma_ref(struct vma* v);
void vma_unref(struct vma* v);
errno_t vma_fork(struct vma* src, struct vma** out);
errno_t vma_map(
struct vma* vma,
struct vmo* vmo,
uintptr_t addr,
size_t len,
enum prot_flags flags,
enum prot_flags prot,
enum vma_flags flags,
uintptr_t vmo_offset
);
errno_t vma_find_free(struct vma* v, uintptr_t hint, size_t len, uintptr_t* out);
bool vma_range_mapped(struct vma* v, uintptr_t vaddr, size_t size);
// Remove any mappings in the given address range.
errno_t vma_unmap(struct vma* v, uintptr_t vaddr, size_t size);
// Change the protection of an existing mapping.
errno_t vma_protect(struct vma* v, uintptr_t vaddr, size_t size, enum prot_flags flags);
errno_t vma_write(struct vma* v, uintptr_t addr, const void* buf, size_t len);
errno_t vma_zero(struct vma* v, uintptr_t addr, size_t len);
errno_t vma_sync(struct vma* v, uintptr_t addr, size_t len);
void vma_object_remove_page(struct vmo* object, uint64_t index, phys_t phys, bool protect);
struct vma_fault_info {
uintptr_t ip;
uintptr_t addr;
+42 -36
View File
@@ -3,57 +3,63 @@
#pragma once
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/iovec.h>
#include <zinnia/mutex.h>
#include <zinnia/pmap.h>
#include <zinnia/radix.h>
#include <zinnia/refcount.h>
#include <zinnia/spin.h>
#include <zinnia/tailq.h>
#include <zinnia/virt.h>
#include <stddef.h>
#include <stdint.h>
struct vmo {
struct refcount rc;
errno_t (*get_page)(struct vmo* vmo, uintptr_t offset_idx, struct page** out);
struct vmo;
struct vma_mapping;
struct vmo_pager_ops {
errno_t (*get_pages)(struct vmo* vmo, uint64_t index, struct page** pages, size_t count, size_t* out_valid);
errno_t (*put_pages)(struct vmo* vmo, uint64_t index, struct page** pages, size_t count);
errno_t (*lookup)(struct vmo* vmo, uint64_t index, phys_t* out);
size_t max_cluster;
void (*destroy)(struct vmo* vmo);
};
struct vmo {
struct refcount rc;
const struct vmo_pager_ops* pager;
mutex_t lock;
struct radix_tree pages;
tailq_head(struct vma_mapping) mappings;
uint64_t ra_next;
size_t ra_window;
enum cache_mode cache;
};
enum vmo_access {
VMO_READ,
VMO_WRITE,
};
void vmo_init(struct vmo* vmo, const struct vmo_pager_ops* pager);
void vmo_ref(struct vmo* obj);
void vmo_unref(struct vmo* obj);
errno_t vmo_read(struct vmo* obj, uintptr_t offset, void* buf, size_t len, size_t* actual_read);
errno_t vmo_write(struct vmo* obj, uintptr_t offset, const void* buf, size_t len, size_t* actual_written);
errno_t vmo_new_anon(struct vmo** out);
errno_t vmo_get_page(struct vmo* vmo, uint64_t index, enum vmo_access access, struct page** out);
void vmo_put_page(struct page* page);
errno_t vmo_read(struct vmo* obj, uint64_t offset, void* buf, size_t len, size_t* actual_read);
errno_t vmo_write(struct vmo* obj, uint64_t offset, const void* buf, size_t len, size_t* actual_written);
errno_t vmo_read_iter(struct vmo* obj, uint64_t offset, iovec_iter_t* iter, size_t len, size_t* actual_read);
errno_t vmo_write_iter(struct vmo* obj, uint64_t offset, iovec_iter_t* iter, size_t len, size_t* actual_written);
errno_t vmo_copy(
struct vmo* target,
uintptr_t target_offset,
uint64_t target_offset,
struct vmo* src,
uintptr_t src_offset,
uint64_t src_offset,
size_t len,
size_t* actual_copied
);
struct pager_ops {
errno_t (*get_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page** out);
errno_t (*put_page)(struct pager_ops* pager, uintptr_t offset_idx, struct page* page);
};
// TODO: change to rbtree
struct page_list {
uintptr_t offset;
struct page* value;
list_link(struct page_list*) next;
};
struct paged_vmo {
struct vmo object;
struct pager_ops source;
list_head(struct page_list*) cache;
struct spinlock lock;
};
errno_t vmo_new_paged(struct pager_ops ops, struct paged_vmo** out);
errno_t vmo_new_phys(struct paged_vmo** out);
// Drops all cached pages past `length` bytes.
void vmo_truncate_paged(struct paged_vmo* paged, size_t length);
// Creates a VMO backed by a specific physical address range (e.g. for MMIO).
errno_t vmo_new_phys_range(uintptr_t addr, size_t length, struct vmo** out);
errno_t vmo_sync(struct vmo* vmo, uint64_t first, uint64_t last);
void vmo_truncate(struct vmo* vmo, uint64_t length);