AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
vm_space.c
Go to the documentation of this file.
1
5
6#include <core/system.h>
7#include <core/arch.h>
8
9#include <mm/pmap.h>
10#include <mm/vm.h>
11
12#include <ds/queue.h>
13
28{
29 if (!vm_space || !vm_entry)
30 return -EINVAL;
31
32 struct queue *queue = &vm_space->vm_entries;
33
34 int alloc = !vm_entry->base;
35
37
38 struct qnode *cur = NULL;
39 uintptr_t prev_end = 0;
40
41 if (alloc) {
42 /* find the highest gap that the entry fits in */
43 queue_for (node, queue) {
44 struct vm_entry *cur_vm_entry = (struct vm_entry *) node->value;
45
46 if (cur_vm_entry->base - prev_end >= vm_entry->size) {
47 vm_entry->base = cur_vm_entry->base - vm_entry->size;
48 end = vm_entry->base + vm_entry->size;
49 }
50
51 prev_end = cur_vm_entry->base + cur_vm_entry->size;
52 }
53 }
54
55 prev_end = 0;
56
57 queue_for (node, queue) {
58 struct vm_entry *cur_vm_entry = (struct vm_entry *) node->value;
59
60 if (vm_entry->base && cur_vm_entry->base >= end && prev_end <= vm_entry->base) {
61 cur = node;
62 break;
63 }
64
65 prev_end = cur_vm_entry->base + cur_vm_entry->size;
66 }
67
68 if (!cur)
69 return -ENOMEM;
70
71 struct qnode *node = kmalloc(sizeof(struct qnode), &M_QNODE, M_ZERO);
72
73 if (!node)
74 return -ENOMEM;
75
76 node->value = vm_entry;
77 node->next = cur;
78 node->prev = cur->prev;
79
80 if (cur->prev)
81 cur->prev->next = node;
82 else
83 queue->head = node;
84
85 cur->prev = node;
86 vm_entry->qnode = node;
87 ++queue->count;
88
89 return 0;
90}
91
100{
101 if (!vm_space) return NULL;
102
103 vaddr = PAGE_ALIGN(vaddr);
104
105 struct queue *vm_entries = &vm_space->vm_entries;
106
107 queue_for (node, vm_entries) {
108 struct vm_entry *vm_entry = node->value;
109 vaddr_t vm_end = vm_entry->base + vm_entry->size;
110
111 if (vaddr >= vm_entry->base && vaddr < vm_end)
112 return vm_entry;
113 }
114
115 return NULL;
116}
117
125{
126 if (!vm_space)
127 return;
128
129 struct vm_entry *vm_entry = NULL;
130
131 while ((vm_entry = dequeue(&vm_space->vm_entries))) {
134 }
135
137}
138
152int vm_space_fork(struct vm_space *src, struct vm_space *dst)
153{
154 if (!src || !dst)
155 return -EINVAL;
156
157 queue_for (node, &src->vm_entries) {
158 struct vm_entry *s_entry = node->value;
159 struct vm_entry *d_entry = kmalloc(sizeof(struct vm_entry), &M_VM_ENTRY, 0);
160
161 /* out of memory: what was copied so far goes with dst, when the
162 * caller destroys it (fork's error path) */
163 if (!d_entry)
164 return -ENOMEM;
165
166 memcpy(d_entry, s_entry, sizeof(struct vm_entry));
167
168 if (!(d_entry->qnode = enqueue(&dst->vm_entries, d_entry))) {
169 kfree(d_entry);
170 return -ENOMEM;
171 }
172
173 if (s_entry->vm_anon) {
174 s_entry->vm_anon->flags |= VM_COPY;
175 vm_anon_incref(s_entry->vm_anon);
176 }
177
178 if (s_entry->vm_object) {
179 vm_object_incref(s_entry->vm_object);
180 }
181
182 if (s_entry->flags & (VM_UW|VM_KW) && !(s_entry->flags & VM_SHARED)) {
183 /* make the parent's pages read-only: the first write copies */
184 vaddr_t sva = s_entry->base;
185 vaddr_t eva = sva + s_entry->size;
186 unsigned flags = s_entry->flags & ~(VM_UW|VM_KW);
187 pmap_protect(src->pmap, sva, eva, flags);
188 }
189 }
190
191 return 0;
192}
uint64_t vaddr_t
Definition mm.h:40
#define PAGE_ALIGN(ptr)
Definition mm.h:9
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
#define M_ZERO
Definition kvmem.h:26
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
void pmap_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, uint32_t prot)
Changes the permissions of the mapped pages of a range of an address space.
Definition pmap.c:399
void pmap_remove_all(struct pmap *pmap)
Unmaps the whole user half of an address space, and frees its page tables.
Definition pmap.c:382
#define queue_for(n, q)
Definition queue.h:37
#define NULL
Definition stddef.h:27
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
A queue's node, holding one entry.
Definition queue.h:19
void * value
Definition queue.h:20
struct qnode * next
Definition queue.h:22
struct qnode * prev
Definition queue.h:21
A queue.
Definition queue.h:29
size_t count
Definition queue.h:30
struct qnode * head
Definition queue.h:31
int flags
its flags (VM_COPY: to be copied before it's written to)
Definition vm.h:127
A mapping (map entry): a range of an address space, its permissions, and where its pages come from.
Definition vm.h:66
struct vm_anon * vm_anon
its anon: the pages the process wrote to
Definition vm.h:81
uint32_t flags
its permissions and flags (VM_*)
Definition vm.h:78
vaddr_t base
where the mapping starts in its address space
Definition vm.h:72
struct vm_object * vm_object
its object: what its other pages come from (a file)
Definition vm.h:84
struct qnode * qnode
its node in its address space's list of mappings
Definition vm.h:90
size_t size
its size
Definition vm.h:75
An address space: its mappings, and its page tables.
Definition vm.h:25
struct pmap * pmap
its page tables (the architecture's)
Definition vm.h:27
struct queue vm_entries
its mappings (map entries), in address order
Definition vm.h:30
#define VM_KW
kernel write
Definition vm.h:39
#define VM_COPY
to be copied before it's written to
Definition vm.h:47
int vm_space_insert(struct vm_space *vm_space, struct vm_entry *vm_entry)
Adds a map entry to an address space, in address order.
Definition vm_space.c:27
#define VM_SHARED
shared: a fork doesn't copy it
Definition vm.h:46
void vm_entry_destroy(struct vm_entry *vm_entry)
Releases what a map entry holds: its references to its anon and its object.
Definition vm_entry.c:32
void vm_anon_incref(struct vm_anon *vm_anon)
Adds a reference to an anon: another mapping shares it (a fork).
Definition vm_anon.c:117
int vm_space_fork(struct vm_space *parent, struct vm_space *child)
Copies an address space's mappings into another, for fork().
Definition vm_space.c:152
void vm_object_incref(struct vm_object *vm_object)
Adds a reference to a vm object: one more mapping of it.
Definition vm_object.c:25
#define VM_UW
user write
Definition vm.h:42
void vm_space_destroy(struct vm_space *vm_space)
Removes all the mappings of an address space: its entries are released and freed, and its page tables...
Definition vm_space.c:124
struct vm_entry * vm_space_find(struct vm_space *vm_space, vaddr_t vaddr)
Finds the map entry that an address is in.
Definition vm_space.c:99