the rules around acquiring locks have been strictly defined and
implemented, and general lock usage has been improved, to fix and
prevent several different issues.
a vm-region is now destroyed in two separate steps:
1. it is "killed": all mappings are unmapped and deleted, the
region is removed from its parent, and the region and all of
its sub-regions are marked as "dead", preventing any
further actions from being performed with the region.
2. it is "destroyed": the vm-region object is de-allocated when
the last reference/handle is closed. the references that this
region holds to any sub-regions are also released, meaning
these regions may also be de-allocated too.
182 lines
5.2 KiB
C
182 lines
5.2 KiB
C
#ifndef KERNEL_VM_REGION_H_
|
|
#define KERNEL_VM_REGION_H_
|
|
|
|
#include <kernel/object.h>
|
|
#include <kernel/pmap.h>
|
|
#include <kernel/vm.h>
|
|
|
|
#define VM_REGION_NAME_MAX 64
|
|
#define VM_REGION_COPY_ALL ((size_t)-1)
|
|
|
|
struct vm_region;
|
|
struct vm_object;
|
|
|
|
enum vm_region_status {
|
|
VM_REGION_DEAD = 0,
|
|
VM_REGION_ONLINE,
|
|
};
|
|
|
|
enum vm_region_entry_type {
|
|
VM_REGION_ENTRY_NONE = 0,
|
|
VM_REGION_ENTRY_REGION,
|
|
VM_REGION_ENTRY_MAPPING,
|
|
};
|
|
|
|
struct vm_region_entry {
|
|
union {
|
|
struct btree_node e_node;
|
|
/* this entry is only used to queue vm-region objects for
|
|
* recursive cleanup */
|
|
struct queue_entry e_entry;
|
|
};
|
|
struct vm_region_entry *e_parent;
|
|
enum vm_region_entry_type e_type;
|
|
/* absolute address of this entry */
|
|
virt_addr_t e_address;
|
|
/* offset in bytes of this entry within its immediate parent. */
|
|
off_t e_offset;
|
|
/* size of the entry in bytes */
|
|
size_t e_size;
|
|
};
|
|
|
|
struct vm_region_mapping {
|
|
struct vm_region_entry m_entry;
|
|
struct vm_object *m_object;
|
|
|
|
/* used to link to vm_object->vo_mappings */
|
|
struct queue_entry m_object_entry;
|
|
|
|
vm_prot_t m_prot;
|
|
/* offset in bytes to the start of the object data that was mapped */
|
|
off_t m_object_offset;
|
|
};
|
|
|
|
struct vm_region {
|
|
struct object vr_base;
|
|
enum vm_region_status vr_status;
|
|
struct vm_region_entry vr_entry;
|
|
|
|
char vr_name[VM_REGION_NAME_MAX];
|
|
|
|
/* btree of struct vm_region_entry.
|
|
* sibling entries cannot overlap each other, and child entries must
|
|
* be entirely contained within their immediate parent entry. */
|
|
struct btree vr_entries;
|
|
|
|
/* memory protection restriction mask.
|
|
* any mapping in this region, or any of its children, cannot use
|
|
* protection flags that are not set in this mask.
|
|
* for example, if VM_PROT_EXEC is /not/ set here, no mapping
|
|
* can be created in this region or any child region with VM_PROT_EXEC
|
|
* set. */
|
|
vm_prot_t vr_prot;
|
|
|
|
/* the physical address space in which mappings in this region (and
|
|
* its children) are created */
|
|
pmap_t vr_pmap;
|
|
};
|
|
|
|
extern kern_status_t vm_region_type_init(void);
|
|
extern struct vm_region *vm_region_cast(struct object *obj);
|
|
|
|
/* create a new vm-region, optionally within a parent region.
|
|
* `offset` is the byte offset within the parent region where the new region
|
|
* should start.
|
|
* if no parent is specified, `offset` is the absolute virtual address of the
|
|
* start of the region.
|
|
* in both cases, `len` is the length of the new region in bytes. */
|
|
extern kern_status_t vm_region_create(
|
|
struct vm_region *parent,
|
|
const char *name,
|
|
size_t name_len,
|
|
off_t offset,
|
|
size_t region_len,
|
|
vm_prot_t prot,
|
|
struct vm_region **out);
|
|
|
|
/* recursively kills a given region and all of its sub-regions.
|
|
* when a region is killed, all of its mappings are unmapped, and any further
|
|
* operations on the region are denied. however, all handles and references to
|
|
* the region (any any sub-region) remain valid, and no kernel memory is
|
|
* de-allocated.
|
|
* the memory used by the vm-region object itself is de-allocated when the last
|
|
* handle/reference to the object is released.
|
|
* this function should be called with `region` locked.
|
|
*/
|
|
extern kern_status_t vm_region_kill(
|
|
struct vm_region *region,
|
|
unsigned long *lock_flags);
|
|
|
|
/* map a vm-object into a vm-region.
|
|
* [region_offset,length] must fall within exactly one region, and cannot span
|
|
* multiple sibling regions.
|
|
* if [region_offset,length] falls within a child region, the map operation
|
|
* will be transparently redirected to the relevant region.
|
|
* `prot` must be allowed both by the region into which the mapping is being
|
|
* created AND the vm-object being mapped. */
|
|
extern kern_status_t vm_region_map_object(
|
|
struct vm_region *region,
|
|
off_t region_offset,
|
|
struct vm_object *object,
|
|
off_t object_offset,
|
|
size_t length,
|
|
vm_prot_t prot,
|
|
virt_addr_t *out);
|
|
|
|
extern kern_status_t vm_region_unmap(
|
|
struct vm_region *region,
|
|
off_t region_offset,
|
|
size_t length);
|
|
|
|
extern bool vm_region_validate_access(
|
|
struct vm_region *region,
|
|
off_t offset,
|
|
size_t len,
|
|
vm_prot_t prot);
|
|
|
|
/* find the mapping corresponding to the given virtual address, and page-in the
|
|
* necessary vm_page to allow the memory access to succeed. if the relevant
|
|
* vm-object page hasn't been allocated yet, it will be allocated here. */
|
|
extern kern_status_t vm_region_demand_map(
|
|
struct vm_region *region,
|
|
virt_addr_t addr,
|
|
enum pmap_fault_flags flags);
|
|
|
|
/* get the absolute base virtual address of a region within its
|
|
* parent/ancestors. */
|
|
extern virt_addr_t vm_region_get_base_address(const struct vm_region *region);
|
|
|
|
extern void vm_region_dump(struct vm_region *region);
|
|
|
|
/* read data from the user-space area of a vm-region into a kernel-mode buffer
|
|
*/
|
|
extern kern_status_t vm_region_read_kernel(
|
|
struct vm_region *src_region,
|
|
virt_addr_t src_ptr,
|
|
size_t count,
|
|
void *dest,
|
|
size_t *nr_read);
|
|
|
|
extern kern_status_t vm_region_memmove(
|
|
struct vm_region *dest_region,
|
|
virt_addr_t dest_ptr,
|
|
struct vm_region *src_region,
|
|
virt_addr_t src_ptr,
|
|
size_t count,
|
|
size_t *nr_moved);
|
|
|
|
extern kern_status_t vm_region_memmove_v(
|
|
struct vm_region *dest_region,
|
|
size_t dest_offset,
|
|
struct iovec *dest,
|
|
size_t nr_dest,
|
|
struct vm_region *src_region,
|
|
size_t src_offset,
|
|
const struct iovec *src,
|
|
size_t nr_src,
|
|
size_t bytes_to_move);
|
|
|
|
DEFINE_OBJECT_LOCK_FUNCTION(vm_region, vr_base)
|
|
|
|
#endif
|