2 * \brief Virtual page-table facility
3 * \author Thomas Friebel <tf13@os.inf.tu-dresden.de>
4 * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
7 * This implementation uses l4rm (especially the AVL tree and userptr) to
8 * manage virt->phys mappings. Each mapping region is represented by one
9 * pgtab_object that is kept in the l4rm region userptr.
11 * For this to work, dataspaces must be attached to l4rm regions!
14 #include <l4/dde/ddekit/pgtab.h>
15 #include <l4/dde/ddekit/memory.h>
16 #include <l4/dde/ddekit/panic.h>
17 #include <l4/dde/ddekit/printf.h>
18 #include <l4/dde/ddekit/__usem_wrap.h>
19 #include <l4/util/macros.h>
29 l4_addr_t va; /* virtual start address */
30 l4_addr_t pa; /* physical start address */
32 /* FIXME reconsider the following members */
34 unsigned type; /* pgtab region type */
36 struct pgtab_object * next;
37 struct pgtab_object * prev;
41 * pa_list_head of page-table object list (for get_virtaddr())
43 static struct pgtab_object pa_list_head =
49 .next = &pa_list_head,
54 static void __attribute__((used)) dump_pgtab_list(void)
56 struct pgtab_object *p = pa_list_head.next;
58 ddekit_printf("PA LIST DUMP\n");
59 for ( ; p != &pa_list_head; p = p->next)
61 ddekit_printf("\t%p -> %p -> %p\n", p->prev, p, p->next);
66 static l4_u_semaphore_t pa_list_lock;
67 static l4_cap_idx_t pa_list_cap;
69 void ddekit_pgtab_init(void);
70 void ddekit_pgtab_init(void)
72 __init_lock_unlocked(&pa_list_lock, &pa_list_cap);
76 static struct pgtab_object *__find(l4_addr_t virt)
78 struct pgtab_object *p = NULL;
80 __lock(&pa_list_lock, pa_list_cap);
81 for (p = pa_list_head.next; p != &pa_list_head; p = p->next)
83 if (virt >= p->va && virt < p->va + p->size)
86 __unlock(&pa_list_lock, pa_list_cap);
88 return p == &pa_list_head ? NULL : p;
91 /*****************************
92 ** Page-table facility API **
93 *****************************/
96 * Get physical address for virtual address
98 * \param virtual virtual address
99 * \return physical address or 0
101 ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt)
103 /* find pgtab object */
104 struct pgtab_object *p = __find((l4_addr_t)virt);
106 /* XXX this is verbose */
107 ddekit_debug("%s: no virt->phys mapping for virtual address %p\n", __func__, virt);
111 /* return virt->phys mapping */
112 l4_size_t offset = (l4_addr_t) virt - p->va;
114 return p->pa + offset;
118 * Get virt address for physical address
120 * \param physical physical address
121 * \return virtual address or 0
123 ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)
125 /* find pgtab object */
126 struct pgtab_object *p;
127 ddekit_addr_t retval = 0;
129 /* find phys->virt mapping */
130 __lock(&pa_list_lock, pa_list_cap);
131 for (p = pa_list_head.next ; p != &pa_list_head ; p = p->next) {
132 if (p->pa <= (l4_addr_t)physical &&
133 (l4_addr_t)physical < p->pa + p->size) {
134 l4_size_t offset = (l4_addr_t) physical - p->pa;
135 retval = p->va + offset;
139 __unlock(&pa_list_lock, pa_list_cap);
142 ddekit_debug("%s: no phys->virt mapping for physical address %p", __func__, (void*)physical);
149 int ddekit_pgtab_get_type(const void *virt)
151 /* find pgtab object */
152 struct pgtab_object *p = __find((l4_addr_t)virt);
154 /* XXX this is verbose */
155 ddekit_debug("%s: no virt->phys mapping for %p", __func__, virt);
163 int ddekit_pgtab_get_size(const void *virt)
165 /* find pgtab object */
166 struct pgtab_object *p = __find((l4_addr_t)virt);
168 /* XXX this is verbose */
169 ddekit_debug("%s: no virt->phys mapping for %p", __func__, virt);
178 * Clear virtual->physical mapping for VM region
180 * \param virtual virtual start address for region
181 * \param type pgtab type for region
183 void ddekit_pgtab_clear_region(void *virt, int type __attribute__((unused)))
186 ddekit_printf("before %s\n", __func__);
190 struct pgtab_object *p = __find((l4_addr_t)virt);
192 /* XXX this is verbose */
193 ddekit_debug("%s: no virt->phys mapping for %p\n", __func__, virt);
198 __lock(&pa_list_lock, pa_list_cap);
199 /* remove pgtab object from list */
200 p->next->prev= p->prev;
201 p->prev->next= p->next;
202 __unlock(&pa_list_lock, pa_list_cap);
204 /* free pgtab object */
205 ddekit_simple_free(p);
208 ddekit_printf("after %s\n", __func__);
215 * Set virtual->physical mapping for VM region
217 * \param virtual virtual start address for region
218 * \param physical physical start address for region
219 * \param pages number of pages in region
220 * \param type pgtab type for region
222 void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type)
224 /* allocate pgtab object */
225 struct pgtab_object *p = ddekit_simple_malloc(sizeof(*p));
227 ddekit_printf("ddekit heap exhausted\n");
230 /* initialize pgtab object */
231 p->va = l4_trunc_page((l4_addr_t)virt);
232 p->pa = l4_trunc_page(phys);
233 p->size = pages * L4_PAGESIZE;
236 __lock(&pa_list_lock, pa_list_cap);
238 p->next = pa_list_head.next;
239 p->prev = &pa_list_head;
241 pa_list_head.next = p;
243 __unlock(&pa_list_lock, pa_list_cap);
246 ddekit_printf("after %s\n", __func__);
251 void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type)
253 int p = l4_round_page(size);
255 // ddekit_printf("%s: virt %p, phys %p, pages %d\n", __func__, virt, phys, p);
256 ddekit_pgtab_set_region(virt, phys, p, type);