]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/dde/ddekit/src/pgtab.c
Inital import
[l4.git] / l4 / pkg / dde / ddekit / src / pgtab.c
1 /*
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>
5  * \date    2006-11-01
6  *
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.
10  *
11  * For this to work, dataspaces must be attached to l4rm regions!
12  */
13
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>
20
21 #include "config.h"
22
23
24 /**
25  * "Page-table" object
26  */
27 struct pgtab_object
28 {
29         l4_addr_t va;    /* virtual start address */
30         l4_addr_t pa;    /* physical start address */
31
32         /* FIXME reconsider the following members */
33         l4_size_t size;
34         unsigned  type;  /* pgtab region type */
35         
36         struct pgtab_object * next;
37         struct pgtab_object * prev;
38 };
39
40 /**
41  * pa_list_head of page-table object list (for get_virtaddr())
42  */
43 static struct pgtab_object pa_list_head =
44 {
45         .va = 0,
46         .pa = 0,
47         .size = 0,
48         .type = 0,
49         .next = &pa_list_head,
50         .prev = &pa_list_head
51 };
52
53
54 static void  __attribute__((used)) dump_pgtab_list(void)
55 {
56         struct pgtab_object *p = pa_list_head.next;
57
58         ddekit_printf("PA LIST DUMP\n");
59         for ( ; p != &pa_list_head; p = p->next)
60         {
61                 ddekit_printf("\t%p -> %p -> %p\n", p->prev, p, p->next);
62         }
63         enter_kdebug("dump");
64 }
65
66 static l4_u_semaphore_t pa_list_lock;
67 static l4_cap_idx_t pa_list_cap;
68
69 void ddekit_pgtab_init(void);
70 void ddekit_pgtab_init(void)
71 {
72         __init_lock_unlocked(&pa_list_lock, &pa_list_cap);
73 }
74
75
76 static struct pgtab_object *__find(l4_addr_t virt)
77 {
78         struct pgtab_object *p = NULL;
79
80         __lock(&pa_list_lock, pa_list_cap);
81         for (p = pa_list_head.next; p != &pa_list_head; p = p->next)
82         {
83                 if (virt >= p->va && virt < p->va + p->size)
84                         break;
85         }
86         __unlock(&pa_list_lock, pa_list_cap);
87
88         return p == &pa_list_head ? NULL : p;
89 }
90
91 /*****************************
92  ** Page-table facility API **
93  *****************************/
94
95 /**
96  * Get physical address for virtual address
97  *
98  * \param virtual  virtual address
99  * \return physical address or 0
100  */
101 ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt)
102 {
103         /* find pgtab object */
104         struct pgtab_object *p = __find((l4_addr_t)virt);
105         if (!p) {
106                 /* XXX this is verbose */
107                 ddekit_debug("%s: no virt->phys mapping for virtual address %p\n", __func__, virt);
108                 return 0;
109         }
110
111         /* return virt->phys mapping */
112         l4_size_t offset = (l4_addr_t) virt - p->va;
113
114         return p->pa + offset;
115 }
116
117 /**
118  * Get virt address for physical address
119  *
120  * \param physical  physical address
121  * \return virtual address or 0
122  */
123 ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)
124 {
125         /* find pgtab object */
126         struct pgtab_object *p;
127         ddekit_addr_t retval = 0;
128         
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;
136                         break;
137                 }
138         }
139         __unlock(&pa_list_lock, pa_list_cap);
140
141         if (!retval)
142                 ddekit_debug("%s: no phys->virt mapping for physical address %p", __func__, (void*)physical);
143
144         return retval;
145 }
146
147
148
149 int ddekit_pgtab_get_type(const void *virt)
150 {
151         /* find pgtab object */
152         struct pgtab_object *p = __find((l4_addr_t)virt);
153         if (!p) {
154                 /* XXX this is verbose */
155                 ddekit_debug("%s: no virt->phys mapping for %p", __func__, virt);
156                 return -1;
157         }
158
159         return p->type;
160 }
161
162
163 int ddekit_pgtab_get_size(const void *virt)
164 {
165         /* find pgtab object */
166         struct pgtab_object *p = __find((l4_addr_t)virt);
167         if (!p) {
168                 /* XXX this is verbose */
169                 ddekit_debug("%s: no virt->phys mapping for %p", __func__, virt);
170                 return -1;
171         }
172
173         return p->size;
174 }
175
176
177 /**
178  * Clear virtual->physical mapping for VM region
179  *
180  * \param virtual   virtual start address for region
181  * \param type      pgtab type for region
182  */
183 void ddekit_pgtab_clear_region(void *virt, int type __attribute__((unused)))
184 {
185 #if 0
186         ddekit_printf("before %s\n", __func__);
187         dump_pgtab_list();
188 #endif
189
190         struct pgtab_object *p = __find((l4_addr_t)virt);
191         if (!p) {
192                 /* XXX this is verbose */
193                 ddekit_debug("%s: no virt->phys mapping for %p\n", __func__, virt);
194                 return;
195         }
196
197
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);
203         
204         /* free pgtab object */
205         ddekit_simple_free(p);
206
207 #if 0
208         ddekit_printf("after %s\n", __func__);
209         dump_pgtab_list();
210 #endif
211 }
212
213
214 /**
215  * Set virtual->physical mapping for VM region
216  *
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
221  */
222 void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type)
223 {
224         /* allocate pgtab object */
225         struct pgtab_object *p = ddekit_simple_malloc(sizeof(*p));
226         if (!p) {
227                 ddekit_printf("ddekit heap exhausted\n");
228                 return;
229         }
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;
234         p->type = type;
235
236         __lock(&pa_list_lock, pa_list_cap);
237
238         p->next = pa_list_head.next;
239         p->prev = &pa_list_head;
240         p->next->prev = p;
241         pa_list_head.next = p;
242
243         __unlock(&pa_list_lock, pa_list_cap);
244
245 #if 0
246         ddekit_printf("after %s\n", __func__);
247         dump_pgtab_list();
248 #endif
249 }
250
251 void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type)
252 {
253         int p = l4_round_page(size);
254         p >>= L4_PAGESHIFT;
255 //      ddekit_printf("%s: virt %p, phys %p, pages %d\n", __func__, virt, phys, p);
256         ddekit_pgtab_set_region(virt, phys, p, type);
257 }
258