| 1 | /* @title: Virtual Memory Area */ |
| 2 | #pragma once |
| 3 | #include <mem/page.h> |
| 4 | #include <structures/list.h> |
| 5 | #include <structures/rbit.h> |
| 6 | #include <types/types.h> |
| 7 | |
| 8 | enum vma_range_protection { |
| 9 | VMA_PROT_READ = 1, |
| 10 | VMA_PROT_WRITE = 1 << 1, |
| 11 | VMA_PROT_EX = 1 << 2, |
| 12 | }; |
| 13 | |
| 14 | struct vma_range { |
| 15 | struct rbit_node mm_node; |
| 16 | |
| 17 | /* min_low = lowest start in the subtree */ |
| 18 | vaddr_t min_low; |
| 19 | |
| 20 | /* max_gap = largest free gap between consecutive VMAs in the subtree */ |
| 21 | size_t max_gap; |
| 22 | pgoff_t pgoff; /* object-space offset of `start` */ |
| 23 | enum vma_range_protection prot; /* r/w/x, etc. */ |
| 24 | struct anon_vma *anon_vma; |
| 25 | struct mm *mm; /* whose page tables */ |
| 26 | struct list_head anon_vma_chain; /* AVCs: own object + every ancestor */ |
| 27 | }; |
| 28 | |
| 29 | static inline vaddr_t vma_range_start(const struct vma_range *vma_range) { |
| 30 | return vma_range->mm_node.interval.low; |
| 31 | } |
| 32 | static inline vaddr_t vma_range_end(const struct vma_range *vma_range) { |
| 33 | return vma_range->mm_node.interval.high + 1; |
| 34 | } |
| 35 | |
| 36 | struct vma_range *vma_range_alloc(struct mm *mm, vaddr_t start, vaddr_t end, |
| 37 | enum vma_range_protection prot); |
| 38 | void vma_range_free(struct vma_range *vma_range); |
| 39 | |
| 40 | void vma_range_init(struct vma_range *vma_range, struct mm *mm, vaddr_t start, |
| 41 | vaddr_t end, enum vma_range_protection prot); |
| 42 | |
| 43 | struct vma_range *vma_range_find(struct mm *mm, vaddr_t addr); |
| 44 | struct vma_range *vma_range_find_intersection(struct mm *mm, vaddr_t s, |
| 45 | vaddr_t e); |
| 46 | struct vma_range *vma_range_next(struct vma_range *vma_range); |
| 47 | struct vma_range *vma_range_prev(struct vma_range *vma_range); |
| 48 | |
| 49 | /* fault path helper: write fault on an anon VMA, allocate anon_vma |
| 50 | * and AVC, link, stash on vma_range->anon_vma */ |
| 51 | enum errno vma_range_anon_prepare(struct vma_range *vma_range); |
| 52 | |
| 53 | enum errno vma_range_expand(struct vma_range *vma_range, vaddr_t new_start, |
| 54 | vaddr_t new_end); |
| 55 | struct vma_range *vma_range_merge(struct mm *mm, struct vma_range *prev, |
| 56 | struct vma_range *vma_range); |
| 57 | enum errno vma_range_set_prot(struct vma_range *vma_range, |
| 58 | enum vma_range_protection prot); |
| 59 | |
| 60 | void vma_range_unmap_range(struct vma_range *vma_range, vaddr_t s, vaddr_t e); |
| 61 | void vma_range_teardown(struct vma_range *vma_range); |
| 62 | |
| 63 | static inline bool vma_range_is_anonymous(const struct vma_range *vma_range) { |
| 64 | return vma_range->anon_vma != NULL; |
| 65 | } |
| 66 | static inline size_t vma_range_pages(const struct vma_range *vma_range) { |
| 67 | return (vma_range_end(vma_range) - vma_range_start(vma_range)) >> |
| 68 | PAGE_4K_SHIFT; |
| 69 | } |
| 70 | |
| 71 | /* split one VMA into two at `addr`, recompute pgoff + tree intervals */ |
| 72 | struct vma_range *vma_range_split(struct vma_range *vma_range, vaddr_t addr); |
| 73 | |
| 74 | /* fresh VMA in dst_mm with src's attributes but no linkages */ |
| 75 | struct vma_range *vma_range_dup(struct mm *dst_mm, const struct vma_range *src); |
| 76 | |
| 77 | /* The index to VA translation. THE VMA's job, not the anon_vma's. */ |
| 78 | static inline vaddr_t vma_range_address(const struct vma_range *vma_range, |
| 79 | pgoff_t index) { |
| 80 | return vma_range_start(vma_range) + |
| 81 | ((index - vma_range->pgoff) << PAGE_4K_SHIFT); |
| 82 | } |
| 83 | |