mem: Refactor vma/vmo
This commit is contained in:
+32
-5
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user