2 * \brief Virtual page-table facility
4 * Implementation of page tables for saving virt->phys assignments.
6 * FIXME: This works for 32-bit architectures only! (Mostly because of pgtab.h.)
10 * This file is part of DDEKit.
12 * (c) 2006-2012 Bjoern Doebel <doebel@os.inf.tu-dresden.de>
13 * Christian Helmuth <ch12@os.inf.tu-dresden.de>
14 * Thomas Friebel <tf13@os.inf.tu-dresden.de>
15 * economic rights: Technische Universitaet Dresden (Germany)
17 * This file is part of TUD:OS and distributed under the terms of the
18 * GNU General Public License 2.
19 * Please see the COPYING-GPL-2 file for details.
22 #include <l4/dde/ddekit/pgtab.h>
24 #include <l4/sys/l4int.h>
25 #include <l4/sys/consts.h>
26 #include <l4/util/macros.h>
27 #include <l4/dm_mem/dm_mem.h>
28 #include <l4/log/l4log.h>
31 /**********************************
32 ** Page-table utility functions **
33 **********************************/
35 /* some useful consts */
38 PDIR_SHIFT = L4_SUPERPAGESHIFT, /* readable alias */
39 PDIR_MASK = L4_SUPERPAGEMASK, /* readable alias */
40 PDIR_ENTRIES = (1 << (L4_MWORD_BITS - PDIR_SHIFT)),
41 PTAB_ENTRIES = (1 << (PDIR_SHIFT - L4_PAGESHIFT)),
42 PTAB_SIZE = (sizeof(void*) * PTAB_ENTRIES)
47 * bit 00-01: type, 0->largemalloc 1->slab page 2->contigmalloc (PTE_TYPE_*)
48 * bit 02-11: size in number of pages
49 * bit 12-31: physical page address
63 * Calculate offset of address in page directory - page-table number
65 static inline unsigned pt_num(l4_addr_t addr) {
66 return addr >> PDIR_SHIFT; }
70 * Calculate offset of address in page table - page number
72 static inline unsigned pg_num(l4_addr_t addr) {
73 return (addr & ~PDIR_MASK) >> L4_PAGESHIFT; }
77 static ddekit_pte *page_dir[PDIR_ENTRIES];
81 * Get page-table entry
83 static inline ddekit_pte ddekit_get_pte(void *p)
85 l4_addr_t addr = (l4_mword_t)p;
88 tab = page_dir[pt_num(addr)];
89 if (!tab) return (ddekit_pte) 0U;
91 return tab[pg_num(addr)];
96 * Set page-table entry
98 static inline void ddekit_set_pte(void *p, ddekit_pte pte)
100 l4_addr_t addr = (l4_addr_t) p;
103 tab = page_dir[pt_num(addr)];
105 /* create new page table */
107 l4dm_mem_allocate_named(PTAB_SIZE, L4DM_CONTIGUOUS|L4DM_PINNED|L4RM_MAP,
111 memset(tab, 0, PTAB_SIZE);
112 page_dir[pt_num(addr)] = tab;
115 l4_addr_t a = l4_trunc_superpage(addr);
116 LOG("created page table for range [0x%08lx,0x%08lx) @ %p\n",
117 a, a + L4_SUPERPAGESIZE, tab);
122 tab[pg_num(addr)] = pte;
126 /*****************************
127 ** Page-table facility API **
128 *****************************/
131 * Set virtual->physical mapping for VM region
133 * \param virtual virtual start address for region
134 * \param physical physical start address for region
135 * \param pages number of pages in region
136 * \param type pte type for region
138 void ddekit_pte_set_region(void *virtual, ddekit_addr_t physical, int pages, int type)
144 /* assert pte not set yet */
145 pte = ddekit_get_pte(virtual);
146 LOGd(pte.compact, "first pte already set! pte=0x%04x", pte.compact);
150 new.components.type = type;
151 new.components.pages = pages;
152 new.components.phys = physical >> L4_PAGESHIFT;
155 ddekit_set_pte(virtual, new);
157 /* continuation pte-s don't have pages set */
158 new.components.pages = 0;
160 /* set continuation pte-s */
161 for (pages--; pages; pages--) {
162 /* prepare continuation pte */
163 virtual += L4_PAGESIZE;
164 new.components.phys++;
167 /* assert pte not set yet */
168 pte = ddekit_get_pte(virtual);
169 LOGd(pte.compact, "continuation pte already set! pte=0x%04x", pte.compact);
172 /* set continuation pte */
173 ddekit_set_pte(virtual, new);
179 * Clear virtual->physical mapping for VM region
181 * \param virtual virtual start address for region
182 * \param type pte type for region
184 * XXX unused page-tables not free'd
186 void ddekit_pte_clear_region(void *virtual, int type)
190 pte = ddekit_get_pte(virtual);
191 /* get number of pages from pte */
192 pages = pte.components.pages;
193 /* assert pages != 0 */
195 LOG("continuation pte found at base");
198 /* assert pte set and of correct type */
200 LOGd(! pte.compact, "pte is already clear");
201 LOGd(pte.components.type!=type, "pte of wrong type");
203 /* clear first pte */
204 ddekit_set_pte(virtual, (ddekit_pte) 0U);
205 /* clear continuation pte-s */
206 for (pages--; pages; pages--) {
207 virtual += L4_PAGESIZE;
210 /* assert pte set and of correct type */
211 pte = ddekit_get_pte(virtual);
213 LOG("pte is already clear");
216 if (pte.components.type!=type) {
217 LOG("pte of wrong type");
220 if (pte.components.pages) {
221 LOG("unexpected non-continuation pte found");
226 ddekit_set_pte(virtual, (ddekit_pte) 0U);