1 |
2 |
drasko |
/*
|
2 |
|
|
* Virtual memory area descriptors.
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 2007, 2008 Bahadir Balban
|
5 |
|
|
*/
|
6 |
|
|
#ifndef __VM_AREA_H__
|
7 |
|
|
#define __VM_AREA_H__
|
8 |
|
|
|
9 |
|
|
#include <stdio.h>
|
10 |
|
|
#include <l4/macros.h>
|
11 |
|
|
#include <l4/config.h>
|
12 |
|
|
#include <l4/types.h>
|
13 |
|
|
#include <task.h>
|
14 |
|
|
#include <lib/spinlock.h>
|
15 |
|
|
#include <physmem.h>
|
16 |
|
|
#include <linker.h>
|
17 |
|
|
#include __INC_ARCH(mm.h)
|
18 |
|
|
|
19 |
|
|
// #define DEBUG_FAULT_HANDLING
|
20 |
|
|
#ifdef DEBUG_FAULT_HANDLING
|
21 |
|
|
#define dprintf(...) printf(__VA_ARGS__)
|
22 |
|
|
#else
|
23 |
|
|
#define dprintf(...)
|
24 |
|
|
#endif
|
25 |
|
|
|
26 |
|
|
/* Some task segment marks for mm0 */
|
27 |
|
|
#define PAGER_MMAP_SEGMENT SZ_1MB
|
28 |
|
|
#define PAGER_MMAP_START (page_align_up(__stack))
|
29 |
|
|
#define PAGER_MMAP_END (PAGER_MMAP_START + PAGER_MMAP_SEGMENT)
|
30 |
|
|
#define PAGER_EXT_VIRTUAL_START PAGER_MMAP_END
|
31 |
|
|
#define PAGER_EXT_VIRTUAL_END (unsigned long)(PAGER_MMAP_END + SZ_2MB)
|
32 |
|
|
#define PAGER_VIRTUAL_START PAGER_EXT_VIRTUAL_END
|
33 |
|
|
|
34 |
|
|
/* Protection flags */
|
35 |
|
|
#define VM_NONE (1 << 0)
|
36 |
|
|
#define VM_READ (1 << 1)
|
37 |
|
|
#define VM_EXEC (1 << 2)
|
38 |
|
|
#define VM_WRITE (1 << 3)
|
39 |
|
|
#define VM_PROT_MASK (VM_READ | VM_WRITE | VM_EXEC)
|
40 |
|
|
|
41 |
|
|
/* Shared copy of a file */
|
42 |
|
|
#define VMA_SHARED (1 << 4)
|
43 |
|
|
/* VMA that's not file-backed, always maps devzero as VMA_COW */
|
44 |
|
|
#define VMA_ANONYMOUS (1 << 5)
|
45 |
|
|
/* Private copy of a file */
|
46 |
|
|
#define VMA_PRIVATE (1 << 6)
|
47 |
|
|
/* For wired pages */
|
48 |
|
|
#define VMA_FIXED (1 << 7)
|
49 |
|
|
/* For stack, where mmap returns end address */
|
50 |
|
|
#define VMA_GROWSDOWN (1 << 8)
|
51 |
|
|
|
52 |
|
|
/* Set when the page is dirty in cache but not written to disk */
|
53 |
|
|
#define VM_DIRTY (1 << 9)
|
54 |
|
|
|
55 |
|
|
/* Defines the type of file. A device file? Regular file? One used at boot? */
|
56 |
|
|
enum VM_FILE_TYPE {
|
57 |
|
|
VM_FILE_DEVZERO = 1,
|
58 |
|
|
VM_FILE_VFS,
|
59 |
|
|
VM_FILE_SHM,
|
60 |
|
|
};
|
61 |
|
|
|
62 |
|
|
/* Defines the type of object. A file? Just a standalone object? */
|
63 |
|
|
#define VM_OBJ_SHADOW (1 << 10) /* Anonymous pages, swap_pager */
|
64 |
|
|
#define VM_OBJ_FILE (1 << 11) /* VFS file and device pages */
|
65 |
|
|
|
66 |
|
|
struct page {
|
67 |
|
|
int refcnt; /* Refcount */
|
68 |
|
|
struct spinlock lock; /* Page lock. */
|
69 |
|
|
struct link list; /* For list of a vm_object's in-memory pages */
|
70 |
|
|
struct vm_object *owner;/* The vm_object the page belongs to */
|
71 |
|
|
unsigned long virtual; /* If refs >1, first mapper's virtual address */
|
72 |
|
|
unsigned int flags; /* Flags associated with the page. */
|
73 |
|
|
unsigned long offset; /* The offset page resides in its owner */
|
74 |
|
|
};
|
75 |
|
|
extern struct page *page_array;
|
76 |
|
|
|
77 |
|
|
#define page_refcnt(x) ((x)->count + 1)
|
78 |
|
|
#define virtual(x) ((x)->virtual)
|
79 |
|
|
|
80 |
|
|
/* TODO: Calculate these by indexing each bank according to pfn */
|
81 |
|
|
#define phys_to_page(x) (page_array + __pfn((x) - membank[0].start))
|
82 |
|
|
#define page_to_phys(x) (__pfn_to_addr((((void *)(x)) - \
|
83 |
|
|
(void *)page_array) / \
|
84 |
|
|
sizeof(struct page)) + \
|
85 |
|
|
membank[0].start)
|
86 |
|
|
|
87 |
|
|
/* Multiple conversions together */
|
88 |
|
|
#define virt_to_page(x) (phys_to_page(virt_to_phys(x)))
|
89 |
|
|
#define page_to_virt(x) (phys_to_virt((void *)page_to_phys(x)))
|
90 |
|
|
|
91 |
|
|
/* Fault data specific to this task + ptr to kernel's data */
|
92 |
|
|
struct fault_data {
|
93 |
|
|
fault_kdata_t *kdata; /* Generic data forged by the kernel */
|
94 |
|
|
unsigned int reason; /* Generic fault reason flags */
|
95 |
|
|
unsigned int address; /* Aborted address */
|
96 |
|
|
unsigned int pte_flags; /* Generic protection flags on pte */
|
97 |
|
|
struct vm_area *vma; /* Inittask-related fault data */
|
98 |
|
|
struct tcb *task; /* Inittask-related fault data */
|
99 |
|
|
};
|
100 |
|
|
|
101 |
|
|
struct vm_pager_ops {
|
102 |
|
|
struct page *(*page_in)(struct vm_object *vm_obj,
|
103 |
|
|
unsigned long pfn_offset);
|
104 |
|
|
int (*page_out)(struct vm_object *vm_obj,
|
105 |
|
|
unsigned long pfn_offset);
|
106 |
|
|
int (*release_pages)(struct vm_object *vm_obj);
|
107 |
|
|
};
|
108 |
|
|
|
109 |
|
|
/* Describes the pager task that handles a vm_area. */
|
110 |
|
|
struct vm_pager {
|
111 |
|
|
struct vm_pager_ops ops; /* The ops the pager does on area */
|
112 |
|
|
};
|
113 |
|
|
|
114 |
|
|
/*
|
115 |
|
|
* Describes the in-memory representation of a resource. This could
|
116 |
|
|
* point at a file or another resource, e.g. a device area, swapper space,
|
117 |
|
|
* the anonymous internal state of a process, etc. This covers more than
|
118 |
|
|
* just files, e.g. during a fork, captures the state of internal shared
|
119 |
|
|
* copy of private pages for a process, which is really not a file.
|
120 |
|
|
*/
|
121 |
|
|
struct vm_object {
|
122 |
|
|
int npages; /* Number of pages in memory */
|
123 |
|
|
int nlinks; /* Number of mapper links that refer */
|
124 |
|
|
int shadows; /* Number of shadows that refer */
|
125 |
|
|
struct link shref; /* Shadow reference from original object */
|
126 |
|
|
struct link shdw_list; /* List of vm objects that shadows this one */
|
127 |
|
|
struct link link_list; /* List of links that refer to this object */
|
128 |
|
|
struct vm_object *orig_obj; /* Original object that this one shadows */
|
129 |
|
|
unsigned int flags; /* Defines the type and flags of the object */
|
130 |
|
|
struct link list; /* List of all vm objects in memory */
|
131 |
|
|
struct vm_pager *pager; /* The pager for this object */
|
132 |
|
|
struct link page_cache;/* List of in-memory pages */
|
133 |
|
|
};
|
134 |
|
|
|
135 |
|
|
/* In memory representation of either a vfs file, a device. */
|
136 |
|
|
struct vm_file {
|
137 |
|
|
int openers;
|
138 |
|
|
struct link list;
|
139 |
|
|
unsigned int type;
|
140 |
|
|
unsigned long length;
|
141 |
|
|
struct vm_object vm_obj;
|
142 |
|
|
void (*destroy_priv_data)(struct vm_file *f);
|
143 |
|
|
struct vnode *vnode;
|
144 |
|
|
void *private_file_data; /* FIXME: To be removed and placed into vnode!!! */
|
145 |
|
|
};
|
146 |
|
|
|
147 |
|
|
/* To create per-vma vm_object lists */
|
148 |
|
|
struct vm_obj_link {
|
149 |
|
|
struct link list;
|
150 |
|
|
struct link linkref;
|
151 |
|
|
struct vm_object *obj;
|
152 |
|
|
};
|
153 |
|
|
|
154 |
|
|
static inline void vm_link_object(struct vm_obj_link *link, struct vm_object *obj)
|
155 |
|
|
{
|
156 |
|
|
link->obj = obj;
|
157 |
|
|
list_insert(&link->linkref, &obj->link_list);
|
158 |
|
|
obj->nlinks++;
|
159 |
|
|
}
|
160 |
|
|
|
161 |
|
|
static inline struct vm_object *vm_unlink_object(struct vm_obj_link *link)
|
162 |
|
|
{
|
163 |
|
|
/* Delete link from object's link list */
|
164 |
|
|
list_remove(&link->linkref);
|
165 |
|
|
|
166 |
|
|
/* Reduce object's mapper link count */
|
167 |
|
|
link->obj->nlinks--;
|
168 |
|
|
|
169 |
|
|
return link->obj;
|
170 |
|
|
}
|
171 |
|
|
|
172 |
|
|
#define vm_object_to_file(obj) container_of(obj, struct vm_file, vm_obj)
|
173 |
|
|
|
174 |
|
|
/*
|
175 |
|
|
* Describes a virtually contiguous chunk of memory region in a task. It covers
|
176 |
|
|
* a unique virtual address area within its task, meaning that it does not
|
177 |
|
|
* overlap with other regions in the same task. The region could be backed by a
|
178 |
|
|
* file or various other resources.
|
179 |
|
|
*
|
180 |
|
|
* COW: Upon copy-on-write, each copy-on-write instance creates a shadow of the
|
181 |
|
|
* original vm object which supersedes the original vm object with its copied
|
182 |
|
|
* modified pages. This creates a stack of shadow vm objects, where the top
|
183 |
|
|
* object's copy of pages supersede the ones lower in the stack.
|
184 |
|
|
*/
|
185 |
|
|
struct vm_area {
|
186 |
|
|
struct link list; /* Per-task vma list */
|
187 |
|
|
struct link vm_obj_list; /* Head for vm_object list. */
|
188 |
|
|
unsigned long pfn_start; /* Region start virtual pfn */
|
189 |
|
|
unsigned long pfn_end; /* Region end virtual pfn, exclusive */
|
190 |
|
|
unsigned long flags; /* Protection flags. */
|
191 |
|
|
unsigned long file_offset; /* File offset in pfns */
|
192 |
|
|
};
|
193 |
|
|
|
194 |
|
|
/*
|
195 |
|
|
* Finds the vma that has the given address.
|
196 |
|
|
* TODO: In the future a lot of use cases may need to traverse each vma
|
197 |
|
|
* rather than searching the address. E.g. munmap/msync
|
198 |
|
|
*/
|
199 |
|
|
static inline struct vm_area *find_vma(unsigned long addr,
|
200 |
|
|
struct link *vm_area_list)
|
201 |
|
|
{
|
202 |
|
|
struct vm_area *vma;
|
203 |
|
|
unsigned long pfn = __pfn(addr);
|
204 |
|
|
|
205 |
|
|
list_foreach_struct(vma, vm_area_list, list)
|
206 |
|
|
if ((pfn >= vma->pfn_start) && (pfn < vma->pfn_end))
|
207 |
|
|
return vma;
|
208 |
|
|
return 0;
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
/* Adds a page to its vm_objects's page cache in order of offset. */
|
212 |
|
|
int insert_page_olist(struct page *this, struct vm_object *vm_obj);
|
213 |
|
|
|
214 |
|
|
/* Find a page in page cache via page offset */
|
215 |
|
|
struct page *find_page(struct vm_object *obj, unsigned long pfn);
|
216 |
|
|
|
217 |
|
|
/* Pagers */
|
218 |
|
|
extern struct vm_pager file_pager;
|
219 |
|
|
extern struct vm_pager devzero_pager;
|
220 |
|
|
extern struct vm_pager swap_pager;
|
221 |
|
|
|
222 |
|
|
/* vm object and vm file lists */
|
223 |
|
|
extern struct link vm_object_list;
|
224 |
|
|
|
225 |
|
|
/* vm object link related functions */
|
226 |
|
|
struct vm_obj_link *vm_objlink_create(void);
|
227 |
|
|
struct vm_obj_link *vma_next_link(struct link *link,
|
228 |
|
|
struct link *head);
|
229 |
|
|
|
230 |
|
|
/* vm file and object initialisation */
|
231 |
|
|
struct vm_object *vm_object_create(void);
|
232 |
|
|
struct vm_file *vm_file_create(void);
|
233 |
|
|
int vm_file_delete(struct vm_file *f);
|
234 |
|
|
int vm_object_delete(struct vm_object *vmo);
|
235 |
|
|
void vm_file_put(struct vm_file *f);
|
236 |
|
|
|
237 |
|
|
/* Printing objects, files */
|
238 |
|
|
void vm_object_print(struct vm_object *vmo);
|
239 |
|
|
void vm_print_objects(struct link *vmo_list);
|
240 |
|
|
void vm_print_files(struct link *file_list);
|
241 |
|
|
|
242 |
|
|
/* Buggy version. Used for pre-faulting a page from mm0 */
|
243 |
|
|
struct page *task_prefault_page(struct tcb *task, unsigned long address,
|
244 |
|
|
unsigned int vmflags);
|
245 |
|
|
/* New version */
|
246 |
|
|
struct page *task_prefault_smart(struct tcb *task, unsigned long address,
|
247 |
|
|
unsigned int vmflags);
|
248 |
|
|
struct page *page_init(struct page *page);
|
249 |
|
|
struct page *find_page(struct vm_object *vmo, unsigned long page_offset);
|
250 |
|
|
void *pager_map_page(struct vm_file *f, unsigned long page_offset);
|
251 |
|
|
void pager_unmap_page(void *vaddr);
|
252 |
|
|
|
253 |
|
|
/* Changes all shadows and their ptes to read-only */
|
254 |
|
|
int vm_freeze_shadows(struct tcb *task);
|
255 |
|
|
|
256 |
|
|
int vm_compare_prot_flags(unsigned int current, unsigned int needed);
|
257 |
|
|
int task_insert_vma(struct vm_area *vma, struct link *vma_list);
|
258 |
|
|
|
259 |
|
|
/* Main page fault entry point */
|
260 |
|
|
struct page *page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
|
261 |
|
|
|
262 |
|
|
int vma_copy_links(struct vm_area *new_vma, struct vm_area *vma);
|
263 |
|
|
int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link);
|
264 |
|
|
int vma_drop_merge_delete_all(struct vm_area *vma);
|
265 |
|
|
|
266 |
|
|
void global_add_vm_object(struct vm_object *obj);
|
267 |
|
|
void global_remove_vm_object(struct vm_object *obj);
|
268 |
|
|
void global_add_vm_file(struct vm_file *f);
|
269 |
|
|
void global_remove_vm_file(struct vm_file *f);
|
270 |
|
|
|
271 |
|
|
#endif /* __VM_AREA_H__ */
|