#ifndef KERNEL_ADDRESS_SPACE_H_ #define KERNEL_ADDRESS_SPACE_H_ #include #include #include #define ADDRESS_SPACE_COPY_ALL ((size_t)-1) struct address_space; struct vm_object; struct vm_area { /* the vm-object mapped into this area. * if this is NULL, the vm_area represents an area of reserved memory. * it cannot be accessed, and mapping operations with MAP_ADDRESS_ANY * will avoid the area, but fixed address mappings in this area * will succeed. */ struct vm_object *vma_object; /* used to link to vm_object->vo_mappings */ struct queue_entry vma_object_entry; /* the memory protection flags applied to this area */ vm_prot_t vma_prot; /* offset in bytes to the start of the object data that was mapped */ off_t vma_object_offset; /* used to link to address_space->s_mappings */ struct btree_node vma_node; /* address of the first byte in this area */ virt_addr_t vma_base; /* address of the last byte in this area */ virt_addr_t vma_limit; }; struct address_space { struct object s_base; /* address of the first byte in this address space */ virt_addr_t s_base_address; /* address of the last byte in this address space */ virt_addr_t s_limit_address; /* btree of struct vm_area representing mapped vm-objects. * sibling entries cannot overlap each other. */ struct btree s_mappings; /* btree of struct vm_area representing reserved regions of the * address space. * reserved regions will not be automatically allocated by the kernel. * sibling entries cannot overlap each other. * overlap between s_mappings and s_reserved IS allowed. */ struct btree s_reserved; /* the corresponding physical address space */ pmap_t s_pmap; }; extern kern_status_t address_space_type_init(void); extern struct address_space *address_space_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 address_space_create( virt_addr_t base, virt_addr_t limit, struct address_space **out); /* 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 address_space_map( struct address_space *space, virt_addr_t map_address, struct vm_object *object, off_t object_offset, size_t length, vm_prot_t prot, virt_addr_t *out); extern kern_status_t address_space_unmap( struct address_space *region, virt_addr_t base, size_t length); /* reserve an area of the address space. the kernel will not place any * new mappings in this area unless explicitly told to (i.e. by not using * MAP_ADDRESS_ANY). Use MAP_ADDRESS_ANY to have the kernel allocate a region * of the address space for you */ extern kern_status_t address_space_reserve( struct address_space *space, virt_addr_t base, size_t length, virt_addr_t *out); /* release a previously reserved area of the address space. */ extern kern_status_t address_space_release( struct address_space *space, virt_addr_t base, size_t length); extern bool address_space_validate_access( struct address_space *region, virt_addr_t base, 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. * this function must be called with `region` UNLOCKED and interrupts ENABLED. */ extern kern_status_t address_space_demand_map( struct address_space *region, virt_addr_t addr, enum pmap_fault_flags flags); /* read data from the user-space area of a vm-region into a kernel-mode buffer */ extern kern_status_t address_space_read( struct address_space *src_region, virt_addr_t src_ptr, size_t count, void *dest, size_t *nr_read); /* write data to the user-space area of a vm-region from a kernel-mode buffer */ extern kern_status_t address_space_write( struct address_space *dst_region, virt_addr_t dst_ptr, size_t count, const void *src, size_t *nr_written); extern kern_status_t address_space_memmove( struct address_space *dest_space, virt_addr_t dest_ptr, struct address_space *src_space, virt_addr_t src_ptr, size_t count, size_t *nr_moved); extern kern_status_t address_space_memmove_v( struct address_space *dest_space, size_t dest_offset, const kern_iovec_t *dest_iov, size_t nr_dest_iov, struct address_space *src_space, size_t src_offset, const kern_iovec_t *src_iov, size_t nr_src_iov, size_t bytes_to_move, size_t *nr_bytes_moved); void address_space_dump(struct address_space *region); DEFINE_OBJECT_LOCK_FUNCTION(address_space, s_base) #endif