invoke_cptr, cap, bits).error;
}
-static inline errval_t invoke_vnode_unmap(struct capref cap, size_t entry)
+// XXX: workaround for an inlining bug in gcc 4.3.4
+#if defined(__GNUC__) \
+ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && __GNUC_PATCHLEVEL__ <= 4
+static __attribute__ ((noinline,unused)) errval_t
+invoke_vnode_map(struct capref ptable, capaddr_t slot, capaddr_t from,
+ int frombits, uintptr_t flags, uintptr_t offset, uintptr_t pte_count)
+#else
+static inline errval_t invoke_vnode_map(struct capref ptable, capaddr_t slot,
+ capaddr_t from, int frombits, uintptr_t flags,
+ uintptr_t offset, uintptr_t pte_count)
+#endif
+{
+ uint8_t invoke_bits = get_cap_valid_bits(ptable);
+ capaddr_t invoke_cptr = get_cap_addr(ptable) >> (CPTR_BITS - invoke_bits);
+
+ assert(slot <= 0xffff);
+ assert(frombits <= 0xff);
+
+ // XXX: needs check of flags, offset, and pte_count sizes
+ // XXX: flag transfer breaks for PAE (flags are 64 bits for PAE)
+ return syscall7((invoke_bits << 16) | (VNodeCmd_Map << 8) | SYSCALL_INVOKE,
+ invoke_cptr, from, (slot << 16) | frombits,
+ flags, offset, pte_count).error;
+}
+
+
+static inline errval_t invoke_vnode_unmap(struct capref cap, size_t entry, size_t pte_count)
{
uint8_t invoke_bits = get_cap_valid_bits(cap);
capaddr_t invoke_cptr = get_cap_addr(cap) >> (CPTR_BITS - invoke_bits);
- return syscall3((invoke_bits << 16) | (VNodeCmd_Unmap << 8) | SYSCALL_INVOKE,
- invoke_cptr, entry).error;
+ return syscall4((invoke_bits << 16) | (VNodeCmd_Unmap << 8) | SYSCALL_INVOKE,
+ invoke_cptr, entry, pte_count).error;
}
/**
return sysret.error;
}
+static inline errval_t invoke_kernel_dump_ptables(struct capref kern_cap,
+ struct capref dispcap)
+{
+ uint8_t invoke_bits = get_cap_valid_bits(kern_cap);
+ capaddr_t invoke_cptr = get_cap_addr(kern_cap) >> (CPTR_BITS - invoke_bits);
+
+ capaddr_t dispcaddr = get_cap_addr(dispcap);
+ struct sysret sysret =
+ syscall3((invoke_bits << 16) | (KernelCmd_DumpPTables << 8) | SYSCALL_INVOKE,
+ invoke_cptr,dispcaddr);
+ return sysret.error;
+}
+
+
static inline errval_t invoke_ipi_notify_send(struct capref notify_cap)
{
uint8_t invoke_bits = get_cap_valid_bits(notify_cap);
#define PTABLE_ACCESS_DEFAULT X86_32_PTABLE_ACCESS_DEFAULT
#define PTABLE_ACCESS_READONLY X86_32_PTABLE_ACCESS_READONLY
+#define PTABLE_ENTRY_SIZE X86_32_PTABLE_ENTRY_SIZE
+
#endif // ARCH_X86_32_BARRELFISH_KPI_PAGING_H
#endif
+#define X86_32_PTABLE_ENTRY_SIZE sizeof(union x86_32_pdir_entry)
+
#ifdef CONFIG_PAE
#define X86_32_PDPTE_BASE(base) (((uint32_t)(base) >> 30) & X86_32_PDPTE_MASK)
#define X86_32_PDIR_BASE(base) (((uint32_t)(base) >> 21) & X86_32_PTABLE_MASK)
#include <dispatch.h>
#include <target/x86_32/paging_kernel_target.h>
#include <target/x86_32/offsets_target.h>
+#include <paging_kernel_arch.h>
+#include <string.h>
+#include <cap_predicates.h>
+
+static inline struct cte *cte_for_cap(struct capability *cap)
+{
+ return (struct cte *) (cap - offsetof(struct cte, cap));
+}
#ifdef CONFIG_PAE
/// Map within a x86_32 pdpt
static errval_t x86_32_pdpt(struct capability *dest, cslot_t slot,
- struct capability * src, uintptr_t param1,
- uintptr_t param2)
+ struct capability * src, uintptr_t flags,
+ uintptr_t offset, uintptr_t pte_count)
{
if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
return SYS_ERR_VNODE_SLOT_INVALID;
}
+ if (pte_count > 1) { // disallow multiple pdpt mappings at a time
+ return SYS_ERR_VM_MAP_SIZE;
+ }
+
if (src->type != ObjType_VNode_x86_32_pdir) { // Right mapping
return SYS_ERR_WRONG_MAPPING;
}
union x86_32_pdpte_entry *entry =
(union x86_32_pdpte_entry *)dest_lv + slot;
+ // Set metadata
+ struct cte *src_cte = cte_for_cap(src);
+ src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_32_pdpte_entry);
+ src_cte->mapping_info.pte_count = pte_count;
+ src_cte->mapping_info.offset = offset;
+
// Source
genpaddr_t src_gp = src->u.vnode_x86_32_pdir.base;
lpaddr_t src_lp = gen_phys_to_local_phys(src_gp);
/// Map within a x86_32 pdir
static errval_t x86_32_pdir(struct capability *dest, cslot_t slot,
- struct capability * src, uintptr_t param1,
- uintptr_t param2)
+ struct capability * src, uintptr_t flags,
+ uintptr_t offset, uintptr_t pte_count)
{
if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
return SYS_ERR_VNODE_SLOT_INVALID;
}
+ if (pte_count > 1) { // disallow more than one page at a time
+ // XXX: this prevents mapping multiple superpages at a time
+ return SYS_ERR_VM_MAP_SIZE;
+ }
+
#ifndef CONFIG_PAE
if(slot >= X86_32_PDIR_BASE(X86_32_MEMORY_OFFSET)) { // Kernel mapped here
return SYS_ERR_VNODE_SLOT_RESERVED;
union x86_32_pdir_entry *entry =
(union x86_32_pdir_entry *)dest_lv + slot;
+ // Set metadata
+ struct cte *src_cte = cte_for_cap(src);
+ src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_32_pdir_entry);
+ src_cte->mapping_info.pte_count = pte_count;
+ src_cte->mapping_info.offset = offset;
+
+
// Source
+ // XXX: offset is ignored
genpaddr_t src_gp = src->u.vnode_x86_32_pdir.base;
lpaddr_t src_lp = gen_phys_to_local_phys(src_gp);
paging_x86_32_map_table(entry, src_lp);
/// Map within a x86_32 ptable
static errval_t x86_32_ptable(struct capability *dest, cslot_t slot,
- struct capability * src, uintptr_t param1,
- uintptr_t param2)
+ struct capability * src, uintptr_t uflags,
+ uintptr_t offset, uintptr_t pte_count)
{
if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
return SYS_ERR_VNODE_SLOT_INVALID;
}
+ cslot_t last_slot = slot + pte_count;
+
+ if (last_slot > X86_32_PTABLE_SIZE) {
+ printf("slot = %"PRIuCSLOT", last_slot = %"PRIuCSLOT", PTABLE_SIZE = %d\n", slot, last_slot, X86_32_PTABLE_SIZE);
+ return SYS_ERR_VM_MAP_SIZE;
+ }
+
if (src->type != ObjType_Frame &&
src->type != ObjType_DevFrame) { // Right mapping
return SYS_ERR_WRONG_MAPPING;
}
// check offset within frame
- genpaddr_t offset = param2;
- if (offset + X86_32_BASE_PAGE_SIZE > ((genpaddr_t)1 << src->u.frame.bits)) {
+ if (offset + pte_count * X86_32_BASE_PAGE_SIZE > get_size(src)) {
return SYS_ERR_FRAME_OFFSET_INVALID;
}
paging_x86_32_flags_t flags =
paging_x86_32_cap_to_page_flags(src->rights);
// Mask with provided access rights mask
- flags = paging_x86_32_mask_attrs(flags, X86_32_PTABLE_ACCESS(param1));
+ flags = paging_x86_32_mask_attrs(flags, X86_32_PTABLE_ACCESS(uflags));
// Add additional arch-specific flags
- flags |= X86_32_PTABLE_FLAGS(param1);
+ flags |= X86_32_PTABLE_FLAGS(uflags);
// Unconditionally mark the page present
flags |= X86_32_PTABLE_PRESENT;
- // Destination
- genpaddr_t dest_gp = dest->u.vnode_x86_32_ptable.base;
+ // Convert destination base address
+ genpaddr_t dest_gp = get_address(dest);
lpaddr_t dest_lp = gen_phys_to_local_phys(dest_gp);
lvaddr_t dest_lv = local_phys_to_mem(dest_lp);
- union x86_32_ptable_entry *entry =
- (union x86_32_ptable_entry *)dest_lv + slot;
+ // Convert source base address
+ genpaddr_t src_gp = get_address(src) + offset;
+ lpaddr_t src_lp = gen_phys_to_local_phys(src_gp);
+ // Set metadata
+ struct cte *src_cte = cte_for_cap(src);
+ src_cte->mapping_info.pte = dest_lp + slot * sizeof(union x86_32_ptable_entry);
+ src_cte->mapping_info.pte_count = pte_count;
+ src_cte->mapping_info.offset = offset;
- /* FIXME: Flush TLB if the page is already present
- * in the meantime, since we don't do this, we just assert that
- * we never reuse a VA mapping */
- if (X86_32_IS_PRESENT(entry)) {
- panic("Trying to map into an already present page NYI.");
- }
- // Carry out the page mapping
- genpaddr_t src_gp = src->u.frame.base + offset;
- lpaddr_t src_lp = gen_phys_to_local_phys(src_gp);
- paging_x86_32_map(entry, src_lp, flags);
+ for (; slot < last_slot; slot++, offset += X86_32_BASE_PAGE_SIZE) {
+ union x86_32_ptable_entry *entry =
+ (union x86_32_ptable_entry *)dest_lv + slot;
+
+ /* FIXME: Flush TLB if the page is already present
+ * in the meantime, since we don't do this, we just assert that
+ * we never reuse a VA mapping */
+ if (X86_32_IS_PRESENT(entry)) {
+ panic("Trying to map into an already present page NYI.");
+ }
+
+ // Carry out the page mapping
+ paging_x86_32_map(entry, src_lp + offset, flags);
+ }
return SYS_ERR_OK;
}
typedef errval_t (*mapping_handler_t)(struct capability *dest_cap,
cslot_t dest_slot,
struct capability *src_cap,
- uintptr_t param1, uintptr_t param2);
+ uintptr_t flags, uintptr_t offset,
+ uintptr_t pte_count);
/// Dispatcher table for the type of mapping to create
static mapping_handler_t handler[ObjType_Num] = {
[ObjType_VNode_x86_32_ptable] = x86_32_ptable,
};
+#define DIAGNOSTIC_ON_ERROR 1
+#define RETURN_ON_ERROR 1
+
/// Create page mappings
errval_t caps_copy_to_vnode(struct cte *dest_vnode_cte, cslot_t dest_slot,
- struct cte *src_cte, uintptr_t param1,
- uintptr_t param2)
+ struct cte *src_cte, uintptr_t flags,
+ uintptr_t offset, uintptr_t pte_count)
{
assert(type_is_vnode(dest_vnode_cte->cap.type));
mapping_handler_t handler_func = handler[dest_cap->type];
assert(handler_func != NULL);
- return handler_func(dest_cap, dest_slot, src_cap, param1, param2);
+
+ if (src_cte->mapping_info.pte) {
+ // already mapped
+#if DIAGNOSTIC_ON_ERROR
+ printf("caps_copy_to_vnode: this copy is already mapped @0x%lx\n", src_cte->mapping_info.pte);
+#endif
+#if RETURN_ON_ERROR
+ return SYS_ERR_VM_ALREADY_MAPPED;
+#endif
+ }
+
+ cslot_t last_slot = dest_slot + pte_count;
+
+ // TODO: PAE
+ if (last_slot > X86_32_PTABLE_SIZE) {
+ // requested map overlaps leaf page table
+#if DIAGNOSTIC_ON_ERROR
+ printf("caps_copy_to_vnode: requested mapping spans multiple leaf page tables\n");
+#endif
+#if RETURN_ON_ERROR
+ return SYS_ERR_VM_RETRY_SINGLE;
+#endif
+ }
+
+ genvaddr_t vaddr;
+ compile_vaddr(dest_vnode_cte, dest_slot, &vaddr);
+ printf("caps_copy_to_vnode: mapping %lu pages (slots %"PRIuCSLOT" to %"PRIuCSLOT") to 0x%"PRIxGENVADDR"\n",
+ pte_count, dest_slot, last_slot, vaddr);
+
+ errval_t r = handler_func(dest_cap, dest_slot, src_cap, flags, offset, pte_count);
+ if (err_is_fail(r)) {
+ printf("caps_copy_to_vnode: handler func returned %ld\n", r);
+ }
+#if 1
+ else {
+ printf("mapping_info.pte = 0x%lx\n", src_cte->mapping_info.pte);
+ printf("mapping_info.offset = 0x%"PRIx64"\n", src_cte->mapping_info.offset);
+ printf("mapping_info.pte_count = %zu\n", src_cte->mapping_info.pte_count);
+ }
+#endif
+ return r;
+}
+
+size_t do_unmap(lvaddr_t pt, cslot_t slot, genvaddr_t vaddr, size_t num_pages)
+{
+ size_t unmapped_pages = 0;
+ union x86_32_ptable_entry *ptentry = (union x86_32_ptable_entry *)pt + slot;
+ for (int i = 0; i < num_pages; i++) {
+ ptentry++->raw = 0;
+ unmapped_pages++;
+ }
+ return unmapped_pages;
}
-errval_t page_mappings_unmap(struct capability *pgtable, size_t slot)
+static inline void read_pt_entry(struct capability *pgtable, size_t slot,
+ genpaddr_t *mapped_addr, lpaddr_t *pte,
+ void **entry)
{
assert(type_is_vnode(pgtable->type));
+ genpaddr_t paddr;
+ lpaddr_t pte_;
+ void *entry_;
+
+ genpaddr_t gp = get_address(pgtable);
+ lpaddr_t lp = gen_phys_to_local_phys(gp);
+ lvaddr_t lv = local_phys_to_mem(lp);
+
+ // get paddr
+ switch (pgtable->type) {
+ case ObjType_VNode_x86_32_pdpt:
+ case ObjType_VNode_x86_32_pdir: {
+ union x86_32_pdir_entry *e =
+ (union x86_32_pdir_entry *)lv + slot;
+ paddr = e->d.base_addr << BASE_PAGE_BITS;
+ entry_ = e;
+ pte_ = lp + slot * sizeof(union x86_32_pdir_entry);
+ break;
+ }
+ case ObjType_VNode_x86_32_ptable: {
+ union x86_32_ptable_entry *e =
+ (union x86_32_ptable_entry *)lv + slot;
+ paddr = e->base.base_addr << BASE_PAGE_BITS;
+ entry_ = e;
+ pte_ = lp + slot * sizeof(union x86_32_ptable_entry);
+ break;
+ }
+ default:
+ assert(!"Should not get here");
+ }
+
+ if (mapped_addr) {
+ *mapped_addr = paddr;
+ }
+ if (pte) {
+ *pte = pte_;
+ }
+ if (entry) {
+ *entry = entry_;
+ }
+}
+
+errval_t page_mappings_unmap(struct capability *pgtable, size_t slot, size_t num_pages)
+{
+ assert(type_is_vnode(pgtable->type));
+ printf("page_mappings_unmap(%zd pages, slot = %zd)\n", num_pages, slot);
+
+ // get page table entry data
+ genpaddr_t paddr;
+ lvaddr_t pte;
+ read_pt_entry(pgtable, slot, &paddr, &pte, NULL);
+ lvaddr_t pt = local_phys_to_mem(gen_phys_to_local_phys(get_address(pgtable)));
+
+ // get virtual address of first page
+ // TODO: error checking
+ genvaddr_t vaddr;
+ struct cte *leaf_pt = cte_for_cap(pgtable);
+ compile_vaddr(leaf_pt, slot, &vaddr);
+ printf("vaddr = 0x%"PRIxGENVADDR"\n", vaddr);
+ printf("num_pages = %zu\n", num_pages);
+
+ // get cap for mapping
+ struct cte *mem;
+ errval_t err = lookup_cap_for_mapping(paddr, pte, &mem);
+ if (err_is_fail(err)) {
+ printf("page_mappings_unmap: %ld\n", err);
+ return err;
+ }
+ //printf("state before unmap: mapped_pages = %zd\n", mem->mapping_info.mapped_pages);
+ //printf("state before unmap: num_pages = %zd\n", num_pages);
+
+ if (num_pages != mem->mapping_info.pte_count) {
+ // want to unmap a different amount of pages than was mapped
+ return SYS_ERR_VM_MAP_SIZE;
+ }
+
+ do_unmap(pt, slot, vaddr, num_pages);
+
+ // update mapping info
+ memset(&mem->mapping_info, 0, sizeof(struct mapping_info));
+
+ do_tlb_flush();
+
+ return SYS_ERR_OK;
+}
+
+__attribute__((unused))
+static errval_t old_page_mappings_unmap(struct capability *pgtable, size_t slot, size_t pte_count)
+{
+ printf("page_mappings_unmap(%zd)\n", pte_count);
+ assert(type_is_vnode(pgtable->type));
+
switch (pgtable->type) {
case ObjType_VNode_x86_32_pdpt: {
genpaddr_t gp = pgtable->u.vnode_x86_32_pdpt.base;
return SYS_ERR_OK;
}
+
+void dump_hw_page_tables(struct dcb *dispatcher)
+{
+ printf("dump_hw_page_tables\n");
+ lvaddr_t root_pt = local_phys_to_mem(dispatcher->vspace);
+
+#ifdef CONFIG_PAE
+ // loop over pdpt entries
+ for (int pdir_index = 0; pdir_index < X86_64_PDPTE_SIZE; pdir_index++) {
+ // get pdir
+ union x86_32_pdpte_entry *pdir = (union x86_64_pdir_entry *)root_pt + pdir_index;
+ if (!pdir->raw) { continue; }
+ genpaddr_t pdir_gp = pdir->d.base_addr << BASE_PAGE_BITS;
+ lvaddr_t pdir_lv = local_phys_to_mem(gen_phys_to_local_phys(pdir_gp));
+#else
+ int pdir_index = 0;
+ lvaddr_t pdir_lv = root_pt;
+#endif
+
+ for (int ptable_index = 0; ptable_index < X86_32_PDIR_SIZE; ptable_index++) {
+ // get ptable
+ union x86_32_pdir_entry *ptable = (union x86_32_pdir_entry *)pdir_lv + ptable_index;
+ if (!ptable->raw) { continue; }
+ genpaddr_t ptable_gp = ptable->d.base_addr << BASE_PAGE_BITS;
+ lvaddr_t ptable_lv = local_phys_to_mem(gen_phys_to_local_phys(ptable_gp));
+
+ for (int entry = 0; entry < X86_32_PTABLE_SIZE; entry++) {
+ union x86_32_ptable_entry *e =
+ (union x86_32_ptable_entry *)ptable_lv + entry;
+ genpaddr_t paddr = e->base.base_addr << BASE_PAGE_BITS;
+ if (!paddr) {
+ continue;
+ }
+ printf("%d.%d.%d: 0x%"PRIxGENPADDR"\n", pdir_index, ptable_index, entry, paddr);
+ }
+ }
+#ifdef CONFIG_PAE
+ } // endfor PDPT entries
+#endif
+}
return handle_revoke_common(root, args, false);
}
+static struct sysret handle_map(struct capability *pgtable,
+ int cmd, uintptr_t *args)
+{
+ /* Retrive arguments */
+ capaddr_t source_cptr = args[0];
+ capaddr_t dest_slot = args[1] >> 16;
+ int source_vbits = args[1] & 0xff;
+ uintptr_t flags, offset,pte_count;
+ flags = args[2];
+ offset = args[3];
+ pte_count = args[4];
+
+ return sys_map(pgtable, dest_slot, source_cptr, source_vbits,
+ flags, offset, pte_count);
+}
+
static struct sysret handle_unmap(struct capability *pgtable,
int cmd, uintptr_t *args)
{
size_t entry = args[0];
- errval_t err = page_mappings_unmap(pgtable, entry);
+ size_t pte_count = args[1];
+ errval_t err = page_mappings_unmap(pgtable, entry, pte_count);
return SYSRET(err);
}
}
#endif
+static struct sysret kernel_dump_ptables(struct capability *cap,
+ int cmd, uintptr_t *args)
+{
+ assert(cap->type == ObjType_Kernel);
+
+ printf("kernel_dump_ptables\n");
+
+ capaddr_t dispcaddr = args[0];
+
+ struct cte *dispcte;
+ errval_t err = caps_lookup_slot(&dcb_current->cspace.cap, dispcaddr, CPTR_BITS,
+ &dispcte, CAPRIGHTS_WRITE);
+ if (err_is_fail(err)) {
+ printf("failed to lookup dispatcher cap\n");
+ return SYSRET(err_push(err, SYS_ERR_DISP_FRAME));
+ }
+ struct capability *dispcap = &dispcte->cap;
+ if (dispcap->type != ObjType_Dispatcher) {
+ printf("dispcap is not dispatcher cap\n");
+ return SYSRET(err_push(err, SYS_ERR_DISP_FRAME_INVALID));
+ }
+
+ struct dcb *dispatcher = dispcap->u.dispatcher.dcb;
+
+ dump_hw_page_tables(dispatcher);
+
+ return SYSRET(SYS_ERR_OK);
+}
+
typedef struct sysret (*invocation_handler_t)(struct capability *to,
int cmd, uintptr_t *args);
[CNodeCmd_Revoke] = handle_revoke,
},
[ObjType_VNode_x86_32_pdpt] = {
+ [VNodeCmd_Map] = handle_map,
[VNodeCmd_Unmap] = handle_unmap,
},
[ObjType_VNode_x86_32_pdir] = {
+ [VNodeCmd_Map] = handle_map,
[VNodeCmd_Unmap] = handle_unmap,
},
[ObjType_VNode_x86_32_ptable] = {
+ [VNodeCmd_Map] = handle_map,
[VNodeCmd_Unmap] = handle_unmap,
},
[ObjType_Kernel] = {
#ifdef __scc__
[KernelCmd_Spawn_SCC_Core] = monitor_spawn_scc_core,
[KernelCmd_IPI_Register] = kernel_rck_register,
- [KernelCmd_IPI_Delete] = kernel_rck_delete
+ [KernelCmd_IPI_Delete] = kernel_rck_delete,
#else
[KernelCmd_IPI_Register] = kernel_ipi_register,
- [KernelCmd_IPI_Delete] = kernel_ipi_delete
+ [KernelCmd_IPI_Delete] = kernel_ipi_delete,
#endif
+ [KernelCmd_DumpPTables] = kernel_dump_ptables,
},
[ObjType_IRQTable] = {
[IRQTableCmd_Set] = handle_irq_table_set,
}
}
-static inline errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, struct cte **retcte)
-{
- // lookup matching cap
- struct cte *mem, *last, *orig;
- // find a cap for paddr
- errval_t err = mdb_find_cap_for_address(paddr, &mem);
- if (err_is_fail(err)) {
- printf("could not find a cap for 0x%"PRIxGENPADDR" (%ld)\n", paddr, err);
- return err;
- }
-#if 0
- printf("lookup request = 0x%"PRIxGENPADDR"\n", paddr);
- printf("has_copies(mem) = %d\n", has_copies(mem));
- printf("pte = 0x%lx\n", pte);
- printf("0x%lx, %zd\n", get_address(&mem->cap), get_size(&mem->cap));
- printf("mem->mapping_info.pte = 0x%lx\n", mem->mapping_info.pte);
- printf("mem->mapping_info.offset = %zd\n", mem->mapping_info.offset);
- printf("mem->mapping_info.pte_count = %zd\n", mem->mapping_info.pte_count);
- printf("mem = %p\n", mem);
-#endif
-
- // look at all copies of mem
- last = mem;
- orig = mem;
- // search backwards in tree
- while (is_copy(&mem->cap, &last->cap)) {
- struct capability *cap = &mem->cap;
- struct mapping_info *map = &mem->mapping_info;
- genpaddr_t base = get_address(cap);
- // only match mappings that start where we want to unmap
- if (base + map->offset == paddr && map->pte == pte)
- {
- // found matching cap
- *retcte = mem;
- return SYS_ERR_OK;
- }
- last = mem;
- mem = mdb_predecessor(mem);
- }
- last = orig;
- // search forward in tree
- mem = mdb_successor(orig);
- while (is_copy(&mem->cap, &last->cap)) {
- struct capability *cap = &mem->cap;
- struct mapping_info *map = &mem->mapping_info;
- genpaddr_t base = get_address(cap);
- // only match mappings that start where we want to unmap
- if (base + map->offset == paddr && map->pte == pte)
- {
- // found matching cap
- *retcte = mem;
- return SYS_ERR_OK;
- }
- last = mem;
- mem = mdb_successor(mem);
- }
-
- // if we get here, we have not found a matching cap
- return SYS_ERR_CAP_NOT_FOUND;
-}
-
static inline void clear_pt_entry(lvaddr_t pte) {
((union x86_64_pdir_entry *)pte)->raw = 0;
}
-
static inline lvaddr_t get_leaf_ptable_for_vaddr(genvaddr_t vaddr)
{
lvaddr_t root_pt = local_phys_to_mem(dcb_current->vspace);
static inline size_t vnode_entry_bits(enum objtype type) {
#ifdef CONFIG_PAE
- else if (type == ObjType_VNode_x86_32_pdpt)
+ if (type == ObjType_VNode_x86_32_pdpt)
{
return 2; // log2(X86_32_PDPTE_SIZE)
}
return 9; // log2(X86_32_PTABLE_SIZE) == log2(X86_32_PDIR_SIZE)
}
#else
- else if (type == ObjType_VNode_x86_32_pdir ||
- type == ObjType_VNode_x86_32_ptable)
+ if (type == ObjType_VNode_x86_32_pdir ||
+ type == ObjType_VNode_x86_32_ptable)
{
return 10; // log2(X86_32_PTABLE_SIZE) == log2(X86_32_PDIR_SIZE)
}
}
}
+static inline void do_tlb_flush(void)
+{
+ // XXX: FIXME: Going to reload cr3 to flush the entire TLB.
+ // This is inefficient.
+ // The current implementation is also not multicore safe.
+ // We should only invalidate the affected entry using invlpg
+ // and figure out which remote tlbs to flush.
+ uint32_t cr3;
+ __asm__ __volatile__("mov %%cr3,%0" : "=a" (cr3) : );
+ __asm__ __volatile__("mov %0,%%cr3" : : "a" (cr3));
+}
+
#endif // KERNEL_ARCH_X86_32_PAGING_H
}
}
+static inline void do_tlb_flush(void) {
+ // XXX: FIXME: Going to reload cr3 to flush the entire TLB.
+ // This is inefficient.
+ // The current implementation is also not multicore safe.
+ // We should only invalidate the affected entry using invlpg
+ // and figure out which remote tlbs to flush.
+ uint64_t cr3;
+ __asm__ __volatile__("mov %%cr3,%0" : "=a" (cr3) : );
+ __asm__ __volatile__("mov %0,%%cr3" : : "a" (cr3));
+}
+
+
#endif // KERNEL_ARCH_X86_64_PAGING_H
struct cte;
errval_t compile_vaddr(struct cte *ptable, size_t entry, genvaddr_t *retvaddr);
errval_t unmap_capability(struct cte *mem);
+errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, struct cte **retcte);
#endif // PAGING_H
do_unmap(pt, slot, vaddr, mem->mapping_info.pte_count);
- // XXX: FIXME: Going to reload cr3 to flush the entire TLB.
- // This is inefficient.
- // The current implementation is also not multicore safe.
- // We should only invalidate the affected entry using invlpg
- // and figure out which remote tlbs to flush.
- uint64_t cr3;
- __asm__ __volatile__("mov %%cr3,%0" : "=a" (cr3) : );
- __asm__ __volatile__("mov %0,%%cr3" : : "a" (cr3));
+ do_tlb_flush();
return SYS_ERR_OK;
}
+
+errval_t lookup_cap_for_mapping(genpaddr_t paddr, lvaddr_t pte, struct cte **retcte)
+{
+ // lookup matching cap
+ struct cte *mem, *last, *orig;
+ // find a cap for paddr
+ errval_t err = mdb_find_cap_for_address(paddr, &mem);
+ if (err_is_fail(err)) {
+ printf("could not find a cap for 0x%"PRIxGENPADDR" (%ld)\n", paddr, err);
+ return err;
+ }
+#if 0
+ printf("lookup request = 0x%"PRIxGENPADDR"\n", paddr);
+ printf("has_copies(mem) = %d\n", has_copies(mem));
+ printf("pte = 0x%lx\n", pte);
+ printf("0x%lx, %zd\n", get_address(&mem->cap), get_size(&mem->cap));
+ printf("mem->mapping_info.pte = 0x%lx\n", mem->mapping_info.pte);
+ printf("mem->mapping_info.offset = %zd\n", mem->mapping_info.offset);
+ printf("mem->mapping_info.pte_count = %zd\n", mem->mapping_info.pte_count);
+ printf("mem = %p\n", mem);
+#endif
+
+ // look at all copies of mem
+ last = mem;
+ orig = mem;
+ // search backwards in tree
+ while (is_copy(&mem->cap, &last->cap)) {
+ struct capability *cap = &mem->cap;
+ struct mapping_info *map = &mem->mapping_info;
+ genpaddr_t base = get_address(cap);
+ // only match mappings that start where we want to unmap
+ if (base + map->offset == paddr && map->pte == pte)
+ {
+ // found matching cap
+ *retcte = mem;
+ return SYS_ERR_OK;
+ }
+ last = mem;
+ mem = mdb_predecessor(mem);
+ }
+ last = orig;
+ // search forward in tree
+ mem = mdb_successor(orig);
+ while (is_copy(&mem->cap, &last->cap)) {
+ struct capability *cap = &mem->cap;
+ struct mapping_info *map = &mem->mapping_info;
+ genpaddr_t base = get_address(cap);
+ // only match mappings that start where we want to unmap
+ if (base + map->offset == paddr && map->pte == pte)
+ {
+ // found matching cap
+ *retcte = mem;
+ return SYS_ERR_OK;
+ }
+ last = mem;
+ mem = mdb_successor(mem);
+ }
+
+ // if we get here, we have not found a matching cap
+ return SYS_ERR_CAP_NOT_FOUND;
+}
#include <barrelfish/barrelfish.h>
#include <barrelfish/dispatch.h>
+#include <stdio.h>
#include "target/x86/pmap_x86.h"
// Location and size of virtual address space reserved for mapping
return NULL;
}
+static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
+{
+ assert(root != NULL);
+ assert(root->is_vnode);
+ struct vnode *n;
+
+ uint32_t end_entry = entry + len;
+
+ for (n = root->u.vnode.children; n; n = n->next) {
+ if (n->is_vnode && n->entry == entry) {
+ return true;
+ }
+ // n is frame
+ uint32_t end = n->entry + n->u.frame.pte_count;
+ if (n->entry < entry && end > end_entry) {
+ return true;
+ }
+ if (n->entry >= entry && n->entry < end_entry) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
static void remove_vnode(struct vnode *root, struct vnode *item)
{
assert(root->is_vnode);
// Map it
err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
- X86_32_PTABLE_ACCESS_DEFAULT, 0);
+ X86_32_PTABLE_ACCESS_DEFAULT, 0, 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VNODE_MAP);
}
return SYS_ERR_OK;
}
+static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+{
+ struct vnode *root = &pmap->root;
+ struct vnode *pdir;
+ assert(root != NULL);
+
+#ifdef CONFIG_PAE
+ // PDPT mapping
+ if((pdir = find_vnode(root, X86_32_PDPT_BASE(base))) == NULL) {
+ return NULL;
+ }
+#else
+ pdir = root;
+#endif
+
+ // PDIR mapping
+ return find_vnode(pdir, X86_32_PDIR_BASE(base));
+}
+
+static errval_t do_single_map(struct pmap_x86 *pmap, genvaddr_t vaddr, genvaddr_t vend,
+ struct capref frame, size_t offset, size_t pte_count,
+ vregion_flags_t flags)
+{
+ // translate flags
+ paging_x86_32_flags_t pmap_flags = vregion_to_pmap_flag(flags);
+
+ // Get the page table
+ struct vnode *ptable;
+ errval_t err = get_ptable(pmap, vaddr, &ptable);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
+ }
+
+ // check if there is an overlapping mapping
+ if (has_vnode(ptable, X86_32_PTABLE_BASE(vaddr), pte_count)) {
+ printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+ return LIB_ERR_PMAP_EXISTING_MAPPING;
+ }
+
+ // setup userspace mapping
+ struct vnode *page = slab_alloc(&pmap->slab);
+ assert(page);
+ page->is_vnode = false;
+ page->entry = X86_32_PTABLE_BASE(vaddr);
+ page->next = ptable->u.vnode.children;
+ ptable->u.vnode.children = page;
+ page->u.frame.cap = frame;
+ page->u.frame.offset = offset;
+ page->u.frame.flags = flags;
+ page->u.frame.pte_count = pte_count;
+
+ // do map
+ err = vnode_map(ptable->u.vnode.cap, frame, X86_32_PTABLE_BASE(vaddr),
+ pmap_flags, offset, pte_count);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_VNODE_MAP);
+ }
+
+ return SYS_ERR_OK;
+}
+
static errval_t do_map(struct pmap_x86 *pmap, genvaddr_t vaddr,
struct capref frame, size_t offset, size_t size,
vregion_flags_t flags, size_t *retoff, size_t *retsize)
{
+ printf("[do_map] vaddr = 0x%"PRIxGENVADDR", size = %zd\n", vaddr, size);
errval_t err;
- paging_x86_32_flags_t pmap_flags = vregion_to_pmap_flag(flags);
- for (size_t i = offset; i < offset + size; i += X86_32_BASE_PAGE_SIZE) {
- // Get the page table
- struct vnode *ptable;
- err = get_ptable(pmap, vaddr, &ptable);
+ size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+ size_t pte_count = DIVIDE_ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+ genvaddr_t vend = vaddr + size;
+
+ if (X86_32_PDIR_BASE(vaddr) == X86_32_PDIR_BASE(vend)) {
+ // fast path
+ do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
+ }
+ else { // multiple leaf page tables
+ // first leaf
+ uint32_t c = X86_32_PTABLE_SIZE - X86_32_PTABLE_BASE(vaddr);
+ genvaddr_t temp_end = vaddr + c * X86_32_BASE_PAGE_SIZE;
+ err = do_single_map(pmap, vaddr, temp_end, frame, offset, c, flags);
if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
}
- // Create user level datastructure for the mapping
- struct vnode *page = find_vnode(ptable, X86_32_PTABLE_BASE(vaddr));
- assert(!page);
- page = slab_alloc(&pmap->slab);
- assert(page);
- page->is_vnode = false;
- page->entry = X86_32_PTABLE_BASE(vaddr);
- page->next = ptable->u.vnode.children;
- ptable->u.vnode.children = page;
- page->u.frame.cap = frame;
- page->u.frame.offset = i;
- page->u.frame.flags = flags;
-
- // Map entry into the page table
- uint32_t entry = X86_32_PTABLE_BASE(vaddr);
- err = vnode_map(ptable->u.vnode.cap, frame, entry, pmap_flags, i);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_VNODE_MAP);
+ // map full leaves
+ while (X86_32_PDIR_BASE(temp_end) < X86_32_PDIR_BASE(vend)) {
+ // update vars
+ vaddr = temp_end;
+ temp_end = vaddr + X86_32_PTABLE_SIZE * X86_32_BASE_PAGE_SIZE;
+ offset += c * X86_32_BASE_PAGE_SIZE;
+ c = X86_32_PTABLE_SIZE;
+ // copy cap
+ struct capref next;
+ err = slot_alloc(&next);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+ err = cap_copy(next, frame);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+ frame = next;
+
+ // do mapping
+ err = do_single_map(pmap, vaddr, temp_end, frame, offset, X86_32_PTABLE_SIZE, flags);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
}
- vaddr += BASE_PAGE_SIZE;
+ // map remaining part
+ offset += c * X86_32_BASE_PAGE_SIZE;
+ c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(temp_end);
+ if (c) {
+ // copy cap
+ struct capref next;
+ err = slot_alloc(&next);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+ err = cap_copy(next, frame);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+
+ // do mapping
+ err = do_single_map(pmap, temp_end, vend, next, offset, c, flags);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+ }
}
if (retoff) {
return err;
}
+static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
+{
+ errval_t err;
+ struct vnode *pt = find_ptable(pmap, vaddr);
+ if (pt) {
+ struct vnode *page = find_vnode(pt, X86_32_PTABLE_BASE(vaddr));
+ if (page && page->u.frame.pte_count == pte_count) {
+ err = vnode_unmap(pt->u.vnode.cap, page->entry, page->u.frame.pte_count);
+ if (err_is_fail(err)) {
+ printf("vnode_unmap returned error: %s (%d)\n", err_getstring(err), err_no(err));
+ return err_push(err, LIB_ERR_VNODE_UNMAP);
+ }
+
+ // Free up the resources
+ if (delete_cap) {
+ err = cap_destroy(page->u.frame.cap);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP);
+ }
+ }
+ remove_vnode(pt, page);
+ slab_free(&pmap->slab, page);
+ }
+ else {
+ return LIB_ERR_PMAP_FIND_VNODE;
+ }
+ }
+
+ return SYS_ERR_OK;
+}
+
+static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
+ size_t *retsize)
+{
+ printf("[unmap] 0x%"PRIxGENVADDR", %zu\n", vaddr, size);
+ errval_t err, ret = SYS_ERR_OK;
+ struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
+ size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+ genvaddr_t vend = vaddr + size;
+
+ if (X86_32_PDIR_BASE(vaddr) == X86_32_PDIR_BASE(vend)) {
+ // fast path
+ err = do_single_unmap(x86, vaddr, size / X86_32_BASE_PAGE_SIZE, false);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_UNMAP);
+ }
+ }
+ else { // slow path
+ // unmap first leaf
+ uint32_t c = X86_32_PTABLE_SIZE - X86_32_PTABLE_BASE(vaddr);
+ err = do_single_unmap(x86, vaddr, c, false);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_UNMAP);
+ }
+
+ // unmap full leaves
+ vaddr += c * X86_32_BASE_PAGE_SIZE;
+ while (X86_32_PDIR_BASE(vaddr) < X86_32_PDIR_BASE(vend)) {
+ c = X86_32_PTABLE_SIZE;
+ err = do_single_unmap(x86, vaddr, X86_32_PTABLE_SIZE, true);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_UNMAP);
+ }
+ vaddr += c * X86_32_BASE_PAGE_SIZE;
+ }
+
+ // unmap remaining part
+ c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(vaddr);
+ if (c) {
+ err = do_single_unmap(x86, vaddr, c, true);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_UNMAP);
+ }
+ }
+ }
+
+ if (retsize) {
+ *retsize = size;
+ }
+
+ //printf("[unmap] exiting\n");
+ return ret;
+}
+
/**
* \brief Remove page mappings
*
* \param size The size of virtual address to remove
* \param retsize If non-NULL, filled in with the actual size removed
*/
-static errval_t unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
+__attribute__((unused))
+static errval_t old_unmap(struct pmap *pmap, genvaddr_t vaddr, size_t size,
size_t *retsize)
{
errval_t err;
}
// Unmap it in the kernel
- err = vnode_unmap(ptable->u.vnode.cap, page->entry);
+ err = vnode_unmap(ptable->u.vnode.cap, page->entry, 1);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VNODE_UNMAP);
}
err = cap_copy(spawn_frame, frame);
if (err_is_fail(err)) {
// TODO: make debug printf
- printf("cap_copy failed for src_slot = %d, dest_slot = %d\n", frame.slot, spawn_frame.slot);
+ printf("cap_copy failed for src_slot = %"PRIuCSLOT", dest_slot = %"PRIuCSLOT"\n", frame.slot, spawn_frame.slot);
return err_push(err, LIB_ERR_CAP_COPY);
}
}