#ifndef KERNEL_VM_REGION_H_ #define KERNEL_VM_REGION_H_ #include #include #include #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