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