3 * \brief Kernel memory management.
7 * Copyright (c) 2012, ETH Zurich.
8 * Copyright (c) 2014, HP Labs.
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
16 #include <paging_generic.h>
17 #include <barrelfish_kpi/paging_arch.h>
19 #include <paging_kernel_arch.h>
20 #include <capabilities.h>
21 #include <cap_predicates.h>
22 #include <mdb/mdb_tree.h>
25 static inline errval_t find_next_ptable(struct cte *old, struct cte **next)
28 if (old->mapping_info.pte) {
29 err = mdb_find_cap_for_address(local_phys_to_gen_phys((lpaddr_t)old->mapping_info.pte), next);
30 if (err_no(err) == CAPS_ERR_CAP_NOT_FOUND) {
31 debug(SUBSYS_PAGING, "could not find cap associated "
32 "with 0x%"PRIxLPADDR"\n", old->mapping_info.pte);
33 return SYS_ERR_VNODE_NOT_INSTALLED;
35 if (err_is_fail(err)) {
36 debug(SUBSYS_PAGING, "error in compile_vaddr:"
37 " mdb_find_range: 0x%"PRIxERRV"\n", err);
40 if (!type_is_vnode((*next)->cap.type)) {
41 return SYS_ERR_VNODE_LOOKUP_NEXT;
47 return SYS_ERR_VNODE_SLOT_INVALID;
51 static inline size_t get_offset(struct cte *old, struct cte *next)
53 return (old->mapping_info.pte - get_address(&next->cap)) / get_pte_size();
57 * compile_vaddr returns the lowest address that is addressed by entry 'entry'
58 * in page table 'ptable'
60 errval_t compile_vaddr(struct cte *ptable, size_t entry, genvaddr_t *retvaddr)
62 if (!type_is_vnode(ptable->cap.type)) {
63 return SYS_ERR_VNODE_TYPE;
67 // shift at least by BASE_PAGE_BITS for first vaddr part
68 size_t shift = BASE_PAGE_BITS;
70 // figure out how much we need to shift (assuming that
71 // compile_vaddr can be used on arbitrary page table types)
72 // A couple of cases have fallthroughs in order to avoid having
73 // multiple calls to vnode_objbits with the same type argument.
74 switch (ptable->cap.type) {
75 case ObjType_VNode_x86_64_pml4:
76 shift += vnode_objbits(ObjType_VNode_x86_64_pdpt);
77 case ObjType_VNode_x86_64_pdpt:
78 shift += vnode_objbits(ObjType_VNode_x86_64_pdir);
79 case ObjType_VNode_x86_64_pdir:
80 shift += vnode_objbits(ObjType_VNode_x86_64_ptable);
81 case ObjType_VNode_x86_64_ptable:
84 case ObjType_VNode_x86_32_pdpt:
85 shift += vnode_objbits(ObjType_VNode_x86_32_pdir);
86 case ObjType_VNode_x86_32_pdir:
87 shift += vnode_objbits(ObjType_VNode_x86_32_ptable);
88 case ObjType_VNode_x86_32_ptable:
91 case ObjType_VNode_ARM_l2:
92 shift += vnode_objbits(ObjType_VNode_ARM_l1);
93 case ObjType_VNode_ARM_l1:
97 return SYS_ERR_VNODE_TYPE;
100 size_t mask = (1ULL<<vnode_objbits(ptable->cap.type))-1;
101 vaddr = ((genvaddr_t)(entry & mask)) << shift;
103 // add next piece of virtual address until we are at root page table
104 struct cte *old = ptable;
107 while (!is_root_pt(old->cap.type))
109 err = find_next_ptable(old, &next);
110 if (err == SYS_ERR_VNODE_NOT_INSTALLED) { // no next page table
114 if (err_is_fail(err)) {
117 // calculate offset into next level ptable
118 size_t offset = get_offset(old, next);
119 // shift new part of vaddr by old shiftwidth + #entries of old ptable
120 shift += vnode_entry_bits(old->cap.type);
122 mask = (1ULL<<vnode_objbits(next->cap.type))-1;
123 vaddr |= ((offset & mask) << shift);
131 errval_t unmap_capability(struct cte *mem)
133 if (!mem->mapping_info.pte) {
134 // mem is not mapped, so just return
142 err = mdb_find_cap_for_address(mem->mapping_info.pte, &pgtable);
143 if (err_is_fail(err)) {
144 // no page table, should be ok.
147 lpaddr_t ptable_lp = gen_phys_to_local_phys(get_address(&pgtable->cap));
148 lvaddr_t ptable_lv = local_phys_to_mem(ptable_lp);
149 cslot_t slot = (mem->mapping_info.pte - ptable_lp) / PTABLE_ENTRY_SIZE;
151 err = compile_vaddr(pgtable, slot, &vaddr);
152 if (err_is_ok(err)) {
153 // only perform unmap when we successfully reconstructed the virtual address
154 do_unmap(ptable_lv, slot, mem->mapping_info.pte_count);
155 if (mem->mapping_info.pte_count > 1) {
158 do_one_tlb_flush(vaddr);
165 errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, struct cte **retcte)
167 // lookup matching cap
168 struct cte *mem, *last, *orig;
169 // find a cap for paddr
171 printf("lookup request = 0x%"PRIxGENPADDR"\n", paddr);
173 errval_t err = mdb_find_cap_for_address(paddr, &mem);
174 if (err_is_fail(err)) {
175 printf("could not find a cap for 0x%"PRIxGENPADDR" (%ld)\n", paddr, err);
179 printf("lookup request = 0x%"PRIxGENPADDR"\n", paddr);
180 printf("has_copies(mem) = %d\n", has_copies(mem));
181 printf("pte = 0x%lx\n", pte);
182 printf("0x%lx, %zd\n", get_address(&mem->cap), get_size(&mem->cap));
183 printf("mem->mapping_info.pte = 0x%lx\n", mem->mapping_info.pte);
184 printf("mem->mapping_info.offset = %zd\n", mem->mapping_info.offset);
185 printf("mem->mapping_info.pte_count = %zd\n", mem->mapping_info.pte_count);
186 printf("mem = %p\n", mem);
189 // look at all copies of mem
192 // search backwards in tree
193 while (is_copy(&mem->cap, &last->cap)) {
194 struct capability *cap = &mem->cap;
195 struct mapping_info *map = &mem->mapping_info;
196 genpaddr_t base = get_address(cap);
197 // only match mappings that start where we want to unmap
198 if (base + map->offset == paddr && map->pte == pte)
200 // found matching cap
205 mem = mdb_predecessor(mem);
208 // search forward in tree
209 mem = mdb_successor(orig);
210 while (is_copy(&mem->cap, &last->cap)) {
211 struct capability *cap = &mem->cap;
212 struct mapping_info *map = &mem->mapping_info;
213 genpaddr_t base = get_address(cap);
214 // only match mappings that start where we want to unmap
215 if (base + map->offset == paddr && map->pte == pte)
217 // found matching cap
222 mem = mdb_successor(mem);
225 // if we get here, we have not found a matching cap
226 return SYS_ERR_CAP_NOT_FOUND;
229 // TODO: cleanup arch compatibility mess for page size selection
230 errval_t paging_tlb_flush_range(struct cte *frame, size_t pages)
232 // reconstruct first virtual address for TLB flushing
235 err = mdb_find_cap_for_address(frame->mapping_info.pte, &leaf_pt);
236 if (err_is_fail(err)) {
240 size_t entry = (frame->mapping_info.pte - get_address(&leaf_pt->cap)) /
242 err = compile_vaddr(leaf_pt, entry, &vaddr);
243 if (err_is_fail(err)) {
244 if (err_no(err) == SYS_ERR_VNODE_NOT_INSTALLED) {
245 debug(SUBSYS_PAGING, "couldn't reconstruct virtual address\n");
251 debug(SUBSYS_PAGING, "flushing TLB entries for vaddrs 0x%"
252 PRIxGENVADDR"--0x%"PRIxGENVADDR"\n",
253 vaddr, vaddr+(pages * BASE_PAGE_SIZE));
254 // flush TLB entries for all modified pages
255 size_t page_size = 0;
256 switch(leaf_pt->cap.type) {
257 #if defined(__x86_64__)
258 case ObjType_VNode_x86_64_ptable:
259 page_size = X86_64_BASE_PAGE_SIZE;
261 case ObjType_VNode_x86_64_pdir:
262 page_size = X86_64_LARGE_PAGE_SIZE;
264 case ObjType_VNode_x86_64_pdpt:
265 page_size = X86_64_HUGE_PAGE_SIZE;
267 #elif defined(__i386__)
268 case ObjType_VNode_x86_32_ptable:
269 page_size = X86_32_BASE_PAGE_SIZE;
271 case ObjType_VNode_x86_32_pdir:
272 page_size = X86_32_LARGE_PAGE_SIZE;
274 #elif defined(__ARM_ARCH_5__)
275 // XXX: cannot add code here without breaking CPU driver?!
277 #elif defined(__ARM_ARCH_7__)
278 case ObjType_VNode_ARM_l1:
279 panic("large page support for ARM NYI!\n");
281 case ObjType_VNode_ARM_l2:
282 page_size = BASE_PAGE_SIZE;
285 #error setup page sizes for arch
291 // TODO: check what tlb flushing instructions expect for large/huge pages
292 for (int i = 0; i < pages; i++) {
293 do_one_tlb_flush(vaddr);