1 /*
2 * @author: Dirk Vogt
3 * @date 2010-02-10
4 *
5 * This file implements a local pagetable, to prevent IPC on physical
6 * address lookups. For now it's implement in a signle linked list.
7 *
8 * As soon as the DDE will use a premeptive thread mechanism access to
9 * the page table has to be sznchronized.
10 */
11 #include "common.h"
12
13 #include <ddekit/pgtab.h>
14 #include <ddekit/memory.h>
15 #include <ddekit/lock.h>
16
17 #ifdef DDEBUG_LEVEL_PGTAB
18 #undef DDEBUG
19 #define DDEBUG DDEBUG_LEVEL_PGTAB
20 #endif
21
22 #include "util.h"
23 #include "debug.h"
24
25
26 static void lock_pgtab(void);
27 static void unlock_pgtab(void);
28 static struct dde_pgtab_region * allocate_region(void);
29 static void free_region(struct dde_pgtab_region *r);
30 static void add_region(struct dde_pgtab_region *r);
31 static void rm_region(struct dde_pgtab_region *r);
32 static struct dde_pgtab_region * find_region_virt(ddekit_addr_t va);
33 static struct dde_pgtab_region * find_region_phys(ddekit_addr_t pa);
34
35 struct dde_pgtab_region {
36 ddekit_addr_t vm_start;
37 ddekit_addr_t phy_start;
38 unsigned size;
39 unsigned type; /* do we really have to keep track of the type here? */
40 struct dde_pgtab_region *next;
41 struct dde_pgtab_region *prev;
42 };
43
44 static struct dde_pgtab_region head = {0,0,0,0,&head,&head};
45 static ddekit_lock_t lock;
46
47 /*
48 * INTERNAL HELPERS
49 */
50
51 /****************************************************************************/
52 /* lock_pgtab */
53 /****************************************************************************/
lock_pgtab()54 static void lock_pgtab()
55 {
56 ddekit_lock_lock(&lock);
57 }
58
59
60 /****************************************************************************/
61 /* unlock_pgtab */
62 /****************************************************************************/
unlock_pgtab()63 static void unlock_pgtab()
64 {
65 ddekit_lock_unlock(&lock);
66 }
67
68 /****************************************************************************/
69 /* dde_pgtab_region */
70 /****************************************************************************/
allocate_region()71 static struct dde_pgtab_region * allocate_region()
72 {
73 struct dde_pgtab_region * res;
74
75 res = (struct dde_pgtab_region *)
76 ddekit_simple_malloc(sizeof(struct dde_pgtab_region));
77 if (!res)
78 {
79 DDEBUG_MSG_ERR("Could not allocate region");
80 }
81 return res;
82 }
83
84 /****************************************************************************/
85 /* free_region */
86 /****************************************************************************/
free_region(struct dde_pgtab_region * r)87 static void free_region(struct dde_pgtab_region *r)
88 {
89 ddekit_simple_free(r);
90 }
91
92 /****************************************************************************/
93 /* add_region */
94 /****************************************************************************/
add_region(struct dde_pgtab_region * r)95 static void add_region (struct dde_pgtab_region *r)
96 {
97 r->next = head.next;
98 head.next = r;
99 r->prev = &head;
100
101 if (r->next) {
102
103 r->next->prev = r;
104
105 }
106 }
107
108 /****************************************************************************/
109 /* rm_region */
110 /****************************************************************************/
rm_region(struct dde_pgtab_region * r)111 static void rm_region(struct dde_pgtab_region *r)
112 {
113 if (r->next) {
114 r->next->prev = r->prev;
115 }
116 if (r->prev) {
117 r->prev->next = r->next;
118 }
119 r->next = 0;
120 r->prev = 0;
121 }
122
123
124 /****************************************************************************/
125 /* find_region_virt */
126 /****************************************************************************/
find_region_virt(ddekit_addr_t va)127 static struct dde_pgtab_region * find_region_virt(ddekit_addr_t va)
128 {
129 struct dde_pgtab_region * r;
130
131 for( r = head.next; r != &head ; r = r->next ) {
132
133 if ( (r->vm_start <= va) && (va < (r->vm_start + r->size) ) ) {
134 break;
135 }
136 }
137
138 if (r == &head) {
139 DDEBUG_MSG_VERBOSE("No virt->phys mapping found for %x", va);
140 r = 0;
141 }
142
143 return r;
144 }
145
146 /****************************************************************************/
147 /* find_region_phys */
148 /****************************************************************************/
find_region_phys(ddekit_addr_t pa)149 static struct dde_pgtab_region * find_region_phys(ddekit_addr_t pa)
150 {
151 struct dde_pgtab_region * r;
152
153 for( r = head.next; r != &head ; r = r->next ) {
154 if ( (r->phy_start <= pa) && (pa < (r->phy_start + r->size) ) )
155 break;
156 }
157
158 if (r == &head) {
159 r=0;
160 DDEBUG_MSG_VERBOSE("No phys->virt mapping found for %x", pa);
161 }
162
163 return r;
164 }
165
166 /****************************************************************************/
167 /* ddekit_pgtab_do_fo_each_region */
168 /****************************************************************************/
ddekit_pgtab_do_fo_each_region(void (* func)(unsigned,unsigned))169 void ddekit_pgtab_do_fo_each_region(void (*func) (unsigned, unsigned)) {
170 struct dde_pgtab_region * r;
171
172 for( r = head.next; r != &head ; r = r->next ) {
173 ddekit_printf("%p",r->vm_start);
174 func(r->vm_start, r->size);
175 }
176 }
177
178 /*
179 * Interface implementation
180 */
181
182 /****************************************************************************/
183 /* ddekit_pgtab_set_region */
184 /****************************************************************************/
ddekit_pgtab_set_region(void * virt,ddekit_addr_t phys,int pages,int type)185 void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type)
186 {
187 ddekit_pgtab_set_region_with_size(virt, phys, (4096)*pages, type);
188 }
189
190 /****************************************************************************/
191 /* ddekit_pgtab_set_region_with_size */
192 /****************************************************************************/
ddekit_pgtab_set_region_with_size(void * virt,ddekit_addr_t phys,int size,int type)193 void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type)
194 {
195 struct dde_pgtab_region * r;
196
197 lock_pgtab();
198
199 r = allocate_region();
200
201 r->vm_start = (ddekit_addr_t) virt;
202 r->phy_start = phys;
203 r->size = size;
204 r->type = type;
205
206 add_region(r);
207
208 unlock_pgtab();
209 }
210
211
212 /****************************************************************************/
213 /* ddekit_pgtab_clear_region */
214 /****************************************************************************/
ddekit_pgtab_clear_region(void * virt,int type)215 void ddekit_pgtab_clear_region(void *virt, int type) {
216
217 struct dde_pgtab_region *r;
218
219 lock_pgtab();
220
221 r = find_region_virt((ddekit_addr_t)virt);
222
223 if (r)
224 {
225 rm_region(r);
226 free_region(r);
227 }
228
229 unlock_pgtab();
230
231 }
232
233
234 /****************************************************************************/
235 /* ddekit_pgtab_get_physaddr */
236 /****************************************************************************/
ddekit_pgtab_get_physaddr(const void * virt)237 ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt)
238 {
239 struct dde_pgtab_region *r;
240 ddekit_addr_t ret = 0;
241 lock_pgtab();
242 r = find_region_virt((ddekit_addr_t)virt);
243 unlock_pgtab();
244 if (r != NULL) {
245
246 ret = ((ddekit_addr_t) virt - r->vm_start) + r->phy_start;
247 DDEBUG_MSG_VERBOSE("pa: %p -> %p\n", virt, ret);
248 }
249
250 return ret;
251 }
252
253 /****************************************************************************/
254 /* ddekit_pgtab_get_virtaddr */
255 /****************************************************************************/
ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)256 ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical)
257 {
258 struct dde_pgtab_region *r;
259 lock_pgtab();
260 r = find_region_phys((ddekit_addr_t)physical);
261 unlock_pgtab();
262 if (r != NULL)
263 {
264 return ((ddekit_addr_t) physical - r->phy_start) + r->vm_start;
265 }
266
267 return 0;
268 }
269
270 /****************************************************************************/
271 /* ddekit_pgtab_get_size */
272 /****************************************************************************/
ddekit_pgtab_get_type(const void * virt)273 int ddekit_pgtab_get_type(const void *virt)
274 {
275 /*
276 * needed for dde fbsd
277 */
278 struct dde_pgtab_region *r;
279
280 lock_pgtab();
281 r = find_region_virt((ddekit_addr_t)virt);
282 unlock_pgtab();
283 return r->type;
284 }
285
286
287 /****************************************************************************/
288 /* ddekit_pgtab_get_size */
289 /****************************************************************************/
ddekit_pgtab_get_size(const void * virt)290 int ddekit_pgtab_get_size(const void *virt)
291 {
292 /*
293 * needed for fbsd
294 */
295 struct dde_pgtab_region *r;
296
297 lock_pgtab();
298 r = find_region_virt((ddekit_addr_t)virt);
299 unlock_pgtab();
300 if(r)
301 return r->size;
302 else
303 return 0;
304 }
305
306 /****************************************************************************/
307 /* ddekit_pgtab_init */
308 /****************************************************************************/
ddekit_pgtab_init()309 void ddekit_pgtab_init() {
310 /* called by ddekit_init() */
311 ddekit_lock_init(&lock);
312 }
313
314