/*
* Copyright (c) 2009, 2010, 2011, 2012, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
failure PMAP_ADDR_NOT_FREE "The requested address range is not free",
failure PMAP_FIND_VNODE "vnode not found",
failure PMAP_EXISTING_MAPPING "Cannot replace existing mapping, unmap first",
+ failure PMAP_FRAME_SIZE "Given Frame to small to fulfil mapping request",
+ failure PMAP_FRAME_IDENTIFY "Frame could not be identified",
failure OUT_OF_VIRTUAL_ADDR "Out of virtual address",
--------------------------------------------------------------------------
-- Copyright (c) 2007-2010, 2012, 2013, ETH Zurich.
+-- Copyright (c) 2014, HP Labs.
-- All rights reserved.
--
-- This file is distributed under the terms in the attached LICENSE file.
--newlib_malloc = "dlmalloc" -- use dlmalloc
newlib_malloc = "oldmalloc"
+-- Configure pagesize for libbarrelfish's morecore implementation
+-- x86_64 accepts "small", "large", and "huge" for 4kB, 2MB and 1GB pages
+-- respectively. x86_32 accepts "small" and "large" for 4kB and 2MB/4MB pages
+-- respectively. All other architectures default to their default page size.
+morecore_pagesize :: String
+morecore_pagesize = "large"
+
-- Use a frame pointer
use_fp :: Bool
use_fp = True
sbin/slideshow \
sbin/vbe \
sbin/vmkitmon \
+ sbin/vnode_map_test \
sbin/webserver \
sbin/routing_setup \
sbin/bcached \
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef ARCH_X86_64_BARRELFISH_KPI_PAGING_H
#define LARGE_PAGE_MASK X86_64_LARGE_PAGE_MASK
#define LARGE_PAGE_OFFSET X86_64_LARGE_PAGE_OFFSET
+#define HUGE_PAGE_BITS X86_64_HUGE_PAGE_BITS
+#define HUGE_PAGE_SIZE X86_64_HUGE_PAGE_SIZE
+#define HUGE_PAGE_MASK X86_64_HUGE_PAGE_MASK
+#define HUGE_PAGE_OFFSET X86_64_HUGE_PAGE_OFFSET
+
/**
* Bits within the various page directories and tables.
*/
/*
* Copyright (c) 2007, 2008, 2009, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef BARRELFISH_MORECORE_H
__BEGIN_DECLS
-errval_t morecore_init(void);
+errval_t morecore_init(size_t alignment);
void morecore_use_optimal(void);
+errval_t morecore_reinit(void);
__END_DECLS
*/
/*
- * Copyright (c) 2009, ETH Zurich.
+ * Copyright (c) 2009-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef LIBBARRELFISH_PMAP_H
struct pmap_funcs {
errval_t (*determine_addr)(struct pmap *pmap, struct memobj *memobj,
size_t alignment, genvaddr_t *vaddr);
+ errval_t (*determine_addr_raw)(struct pmap *pmap, size_t size,
+ size_t alignment, genvaddr_t *vaddr);
errval_t (*map)(struct pmap* pmap, genvaddr_t vaddr, struct capref frame,
size_t offset, size_t size, vregion_flags_t flags,
size_t *retoffset, size_t *retsize);
/*
* Copyright (c) 2009, 2010, ETH Zurich.
+ * Copyright (c) 2014 HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef LIBBARRELFISH_VREGION_H
#define VREGION_FLAGS_NOCACHE 0x08 // Caching disabled
#define VREGION_FLAGS_MPB 0x10 // Message passing buffer
#define VREGION_FLAGS_GUARD 0x20 // Guard page
-#define VREGION_FLAGS_MASK 0x2f // Mask of all individual VREGION_FLAGS
+// XXX: figure out how to do this arch-independent(?) -SG, 2014-06-16
+#define VREGION_FLAGS_LARGE 0x40 // Map large pages, if possible
+#define VREGION_FLAGS_HUGE 0x80 // Map huge pages, if possible
+#define VREGION_FLAGS_MASK 0xff // Mask of all individual VREGION_FLAGS
#define VREGION_FLAGS_READ_WRITE \
(VREGION_FLAGS_READ | VREGION_FLAGS_WRITE)
/*
* Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
struct capref frame, vregion_flags_t flags,
struct memobj **retmemobj,
struct vregion **retvregion);
+errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
+ struct capref frame, vregion_flags_t flags,
+ size_t alignment,
+ struct memobj **retmemobj,
+ struct vregion **retvregion);
errval_t vspace_map_one_frame(void **retaddr, size_t size, struct capref frame,
struct memobj **retmemobj,
struct vregion **retvregion);
/*
* Copyright (c) 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef LIBBARRELFISH_VSPACE_MMU_AWARE_H
/// Struct to support mmu_aware memory management
struct vspace_mmu_aware {
size_t size;
+ size_t alignment;
size_t consumed;
struct vregion vregion; ///< Needs just one vregion
struct memobj_anon memobj; ///< Needs just one memobj
};
errval_t vspace_mmu_aware_init(struct vspace_mmu_aware *state, size_t size);
+errval_t vspace_mmu_aware_init_aligned(struct vspace_mmu_aware *state,
+ size_t size, size_t alignment,
+ vregion_flags_t flags);
+errval_t vspace_mmu_aware_reset(struct vspace_mmu_aware *state,
+ struct capref frame, size_t size);
errval_t vspace_mmu_aware_map(struct vspace_mmu_aware *state,
struct capref frame, size_t req_size,
void **retbuf, size_t *retsize);
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef TARGET_X86_32_BARRELFISH_KPI_PAGING_H
#define X86_32_PDPTE_MASK 3
#define X86_32_PDPTE_CLEAR 0
+#define X86_32_PDIR_SIZE 512
+
#define X86_32_PTABLE_SIZE 512 /**< Page directory/table size */
#define X86_32_PTABLE_MASK 0x1ff /**< Page dir/table address mask */
#define X86_32_PTABLE_CLEAR 0 /**< Bitmap of a clear table entry */
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef TARGET_X86_64_BARRELFISH_KPI_PAGING_H
/** The system's base page size is 4kB */
#define X86_64_BASE_PAGE_BITS 12
-#define X86_64_BASE_PAGE_SIZE 0x1000
+#define X86_64_BASE_PAGE_SIZE (1<<X86_64_BASE_PAGE_BITS)
#define X86_64_BASE_PAGE_MASK (X86_64_BASE_PAGE_SIZE - 1)
#define X86_64_BASE_PAGE_OFFSET(a) ((a) & X86_64_BASE_PAGE_MASK)
/** The system's large page size is 2MB */
#define X86_64_LARGE_PAGE_BITS 21
-#define X86_64_LARGE_PAGE_SIZE 0x200000
+#define X86_64_LARGE_PAGE_SIZE (1<<X86_64_LARGE_PAGE_BITS)
#define X86_64_LARGE_PAGE_MASK (X86_64_LARGE_PAGE_SIZE - 1)
#define X86_64_LARGE_PAGE_OFFSET(a) ((a) & X86_64_LARGE_PAGE_MASK)
+/** The system's huge page size is 1GB */
+#define X86_64_HUGE_PAGE_BITS 30
+#define X86_64_HUGE_PAGE_SIZE (1<<X86_64_HUGE_PAGE_BITS)
+#define X86_64_HUGE_PAGE_MASK (X86_64_HUGE_PAGE_SIZE - 1)
+#define X86_64_HUGE_PAGE_OFFSET(a) ((a) & X86_64_HUGE_PAGE_MASK)
+
/**
* Bits within the various page directories and tables.
*/
#define X86_64_PTABLE_READ_WRITE (((paging_x86_64_flags_t)1) << 1)
#define X86_64_PTABLE_PRESENT (((paging_x86_64_flags_t)1) << 0)
-#define X86_64_PTABLE_SIZE 512 /**< Page directory/table size */
+#define X86_64_PTABLE_BITS 9 /**< Page directory/table size in bits */
+/** Page directory/table size */
+#define X86_64_PTABLE_SIZE (1UL<<X86_64_PTABLE_BITS)
#define X86_64_PTABLE_MASK 0x1ff /**< Page dir/table address mask */
#define X86_64_PTABLE_CLEAR 0 /**< Bitmap of a clear table entry */
/*
- * Copyright (c) 2009 - 2012 ETH Zurich.
+ * Copyright (c) 2009 - 2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
}
if (src->type != ObjType_VNode_ARM_l2) {
- panic("oops: wrong src type");
+ //large page mapping goes here
+ printf("kernel large page\n");
+ //panic("oops: wrong src type");
+ assert(0 == (kpi_paging_flags & ~KPI_PAGING_FLAGS_MASK));
+
+ // ARM L1 has 4K entries, but we treat it as if it had 1K
+ if (slot >= (256 * 4)) {
+ panic("oops: slot >= (256 * 4)");
+ return SYS_ERR_VNODE_SLOT_INVALID;
+ }
+
+ if (src->type != ObjType_Frame && src->type != ObjType_DevFrame) {
+ panic("oops: src->type != ObjType_Frame && src->type != ObjType_DevFrame");
+ return SYS_ERR_WRONG_MAPPING;
+ }
+
+ // check offset within frame
+ if ((offset + BYTES_PER_SECTION > get_size(src)) ||
+ ((offset % BYTES_PER_SECTION) != 0)) {
+ panic("oops: frame offset invalid");
+ return SYS_ERR_FRAME_OFFSET_INVALID;
+ }
+
+ // check mapping does not overlap leaf page table
+ if (slot + pte_count > (256 * 4)) {
+ return SYS_ERR_VM_MAP_SIZE;
+ }
+
+ // Destination
+ lpaddr_t dest_lpaddr = gen_phys_to_local_phys(get_address(dest));
+ lvaddr_t dest_lvaddr = local_phys_to_mem(dest_lpaddr);
+
+ union arm_l1_entry* entry = (union arm_l1_entry*)dest_lvaddr + slot;
+ if (entry->invalid.type != L1_TYPE_INVALID_ENTRY) {
+ panic("Remapping valid page.");
+ }
+
+ lpaddr_t src_lpaddr = gen_phys_to_local_phys(get_address(src) + offset);
+ if ((src_lpaddr & (LARGE_PAGE_SIZE - 1))) {
+ panic("Invalid target");
+ }
+
+ struct cte *src_cte = cte_for_cap(src);
+ src_cte->mapping_info.pte_count = pte_count;
+ src_cte->mapping_info.pte = dest_lpaddr;
+ src_cte->mapping_info.offset = offset;
+
+ for (int i = 0; i < pte_count; i++) {
+ entry->raw = 0;
+
+ entry->section.type = L1_TYPE_SECTION_ENTRY;
+ entry->section.bufferable = 1;
+ entry->section.cacheable = (kpi_paging_flags & KPI_PAGING_FLAGS_NOCACHE)? 0: 1;
+ entry->section.ap10 = (kpi_paging_flags & KPI_PAGING_FLAGS_READ)? 2:0;
+ entry->section.ap10 |= (kpi_paging_flags & KPI_PAGING_FLAGS_WRITE)? 3:0;
+ entry->section.ap2 = 0;
+ entry->section.base_address = (src_lpaddr + i * BYTES_PER_SECTION) >> 12;
+
+ entry++;
+
+ debug(SUBSYS_PAGING, "L2 mapping %08"PRIxLVADDR"[%"PRIuCSLOT"] @%p = %08"PRIx32"\n",
+ dest_lvaddr, slot, entry, entry->raw);
+ }
+
+ // Flush TLB if remapping.
+ cp15_invalidate_tlb();
+ return SYS_ERR_OK;
return SYS_ERR_WRONG_MAPPING;
}
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
struct capability * src, uintptr_t flags,
uintptr_t offset, uintptr_t pte_count)
{
+ //printf("x86_32_pdir\n");
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
+ if (slot + pte_count > X86_32_PTABLE_SIZE) {
+ // check that mapping fits page directory
return SYS_ERR_VM_MAP_SIZE;
}
}
#endif
+ // large page code
+ if(src->type == ObjType_Frame || src->type == ObjType_DevFrame)
+ {
+ cslot_t last_slot = slot + pte_count;
+
+ // check offset within frame
+ if (offset + pte_count * X86_32_LARGE_PAGE_SIZE > get_size(src)) {
+ return SYS_ERR_FRAME_OFFSET_INVALID;
+ }
+
+ /* Calculate page access protection flags */
+ // Get frame cap rights
+ paging_x86_32_flags_t flags_large =
+ paging_x86_32_cap_to_page_flags(src->rights);
+ // Mask with provided access rights mask
+ flags_large = paging_x86_32_mask_attrs(flags_large, X86_32_PTABLE_ACCESS(flags));
+ // Add additional arch-specific flags
+ flags_large |= X86_32_PTABLE_FLAGS(flags);
+ // Unconditionally mark the page present
+ flags_large |= X86_32_PTABLE_PRESENT;
+
+ // 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);
+ // Convert source base address
+ genpaddr_t src_gp = get_address(src);
+ 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;
+
+ for (; slot < last_slot; slot++, offset += X86_32_LARGE_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)) {
+ printf("Trying to map into an already present page NYI.\n");
+ return SYS_ERR_VNODE_SLOT_INUSE;
+ }
+
+ // Carry out the page mapping
+ paging_x86_32_map_large(entry, src_lp + offset, flags_large);
+ }
+
+ return SYS_ERR_OK;
+ }
+
if (src->type != ObjType_VNode_x86_32_ptable) { // Right mapping
return SYS_ERR_WRONG_MAPPING;
}
struct capability * src, uintptr_t uflags,
uintptr_t offset, uintptr_t pte_count)
{
+ //printf("x86_32_ptable\n");
if (slot >= X86_32_PTABLE_SIZE) { // Slot within page table
return SYS_ERR_VNODE_SLOT_INVALID;
}
// flush TLB for unmapped pages
// TODO: heuristic that decides if selective or full flush is more
// efficient?
- if (num_pages > 1) {
+ // currently set to trivially flush entire tlb to make large page unmapping work
+ if (num_pages > 1 || true) {
do_full_tlb_flush();
} else {
do_one_tlb_flush(vaddr);
#ifdef CONFIG_PAE
// loop over pdpt entries
- for (int pdir_index = 0; pdir_index < X86_64_PDPTE_SIZE; pdir_index++) {
+ for (int pdir_index = 0; pdir_index < X86_32_PDPTE_SIZE; pdir_index++) {
// get pdir
- union x86_32_pdpte_entry *pdir = (union x86_64_pdir_entry *)root_pt + pdir_index;
+ union x86_32_pdpte_entry *pdir = (union x86_32_pdpte_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));
lvaddr_t pdir_lv = root_pt;
#endif
- for (int ptable_index = 0; ptable_index < X86_32_PDIR_SIZE; ptable_index++) {
+ // only go to 512 because upper half of address space is kernel space
+ // (1:1 mapped)
+ // TODO: figure out what we need to do here for PAE
+ for (int ptable_index = 0; ptable_index < 512; ptable_index++) {
// get ptable
union x86_32_pdir_entry *ptable = (union x86_32_pdir_entry *)pdir_lv + ptable_index;
+ union x86_32_ptable_entry *large = (union x86_32_ptable_entry *)ptable;
if (!ptable->raw) { continue; }
+ if (large->large.always1) {
+ // large page
+ genpaddr_t paddr = large->large.base_addr << X86_32_LARGE_PAGE_BITS;
+ printf("%d.%d: 0x%"PRIxGENPADDR"\n", pdir_index,
+ ptable_index, paddr);
+ }
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));
*/
/*
- * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * Copyright (c) 2007-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
union x86_32_ptable_entry *pdir_base =
&mem_pdir[X86_32_PDPTE_BASE(addr)][X86_32_PDIR_BASE(vaddr)];
#else
- union x86_32_pdir_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
+ union x86_32_pdir_entry *pdir_base = (union x86_32_pdir_entry*) &pdir[X86_32_PDIR_BASE(vaddr)];
# ifndef CONFIG_PSE
union x86_32_ptable_entry *ptable_base =
&mem_ptable[X86_32_PDIR_BASE(addr)][X86_32_PTABLE_BASE(vaddr)];
}
#ifdef CONFIG_PAE
- debug(SUBSYS_PAGING, "Mapping 2M page: vaddr = 0x%x, addr = 0x%x, "
- "PDPTE_BASE = %u, PDIR_BASE = %u -- ", vaddr,
+ debug(SUBSYS_PAGING, "Mapping 2M page: vaddr = 0x%"PRIxLVADDR", addr = 0x%"PRIxLVADDR", "
+ "PDPTE_BASE = %"PRIuLPADDR", PDIR_BASE = %"PRIuLPADDR" -- ", vaddr,
addr, X86_32_PDPTE_BASE(vaddr), X86_32_PDIR_BASE(vaddr));
mapit(pdpte_base, pdir_base, addr, bitmap);
#else
# ifdef CONFIG_PSE
- debug(SUBSYS_PAGING, "Mapping 4M page: vaddr = 0x%x, addr = 0x%x, "
- "PDIR_BASE = %u -- ", vaddr,
+ debug(SUBSYS_PAGING, "Mapping 4M page: vaddr = 0x%"PRIxLVADDR", addr = 0x%"PRIxLVADDR", "
+ "PDIR_BASE = %"PRIuLPADDR" -- ", vaddr,
addr, X86_32_PDIR_BASE(vaddr));
- mapit(pdir_base, addr, bitmap);
+ mapit((union x86_32_ptable_entry*)pdir_base, addr, bitmap);
# else
debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR", "
"addr = 0x%"PRIxLVADDR", "
union x86_32_ptable_entry *pdir_base =
&mem_pdir[X86_32_PDPTE_BASE(mem_to_local_phys(vaddr))][X86_32_PDIR_BASE(vaddr)];
- debug(SUBSYS_PAGING, "Mapping 2M device page: vaddr = 0x%x, addr = 0x%x, "
- "PDPTE_BASE = %u, PDIR_BASE = %u -- ", vaddr,
+ debug(SUBSYS_PAGING, "Mapping 2M device page: vaddr = 0x%"PRIxLPADDR", addr = 0x%"PRIxLPADDR", "
+ "PDPTE_BASE = %"PRIxLPADDR", PDIR_BASE = %"PRIxLPADDR" -- ", vaddr,
addr, X86_32_PDPTE_BASE(vaddr), X86_32_PDIR_BASE(vaddr));
mapit(pdpte_base, pdir_base, addr, bitmap);
#else
# ifdef CONFIG_PSE
union x86_32_ptable_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
- debug(SUBSYS_PAGING, "Mapping 4M device page: vaddr = 0x%x, addr = 0x%x, "
- "PDIR_BASE = %u -- ", vaddr, addr, X86_32_PDIR_BASE(vaddr));
+ debug(SUBSYS_PAGING, "Mapping 4M device page: vaddr = 0x%"PRIxLPADDR", addr = 0x%"PRIxLPADDR", "
+ "PDIR_BASE = %"PRIxLPADDR" -- ", vaddr, addr, X86_32_PDIR_BASE(vaddr));
mapit(pdir_base, addr, bitmap);
# else
union x86_32_pdir_entry *pdir_base = &pdir[X86_32_PDIR_BASE(vaddr)];
(union x86_32_pdpte_entry *)local_phys_to_mem(base);
int i;
- debug(SUBSYS_PAGING, "Is now a PDPTE: table = 0x%x\n", base);
+ debug(SUBSYS_PAGING, "Is now a PDPTE: table = 0x%"PRIuLPADDR"\n", base);
// Map memory
for(i = X86_32_PDPTE_BASE(X86_32_MEMORY_OFFSET); i < X86_32_PDPTE_SIZE; i++) {
newpdpte[i] = pdpte[i];
*/
/*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2007-2013 ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
+ X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE
+ X86_32_PTABLE_BASE(vaddr)];
- debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%x, base = 0x%x, "
- "PDPTE_BASE = %u, PDIR_BASE = %u, "
- "PTABLE_BASE = %u -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
+ debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR
+ ", base = 0x%"PRIxLPADDR", PDPTE_BASE = %lu, PDIR_BASE = %lu, "
+ "PTABLE_BASE = %lu -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr));
#else
union x86_32_ptable_entry *ptable_base = &init_ptable[
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <kernel.h>
struct capability *src, uintptr_t flags,
uintptr_t offset, size_t pte_count)
{
+ //printf("page_mappings_arch:x86_64_non_ptable\n");
if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
return SYS_ERR_VNODE_SLOT_INVALID;
}
}
size_t page_size = 0;
+ paging_x86_64_flags_t flags_large = 0;
switch (dest->type) {
case ObjType_VNode_x86_64_pml4:
if (src->type != ObjType_VNode_x86_64_pdpt) { // Right mapping
}
break;
case ObjType_VNode_x86_64_pdpt:
- // TODO: huge page support, set page_size to HUGE_PAGE_SIZE
+ // huge page support
if (src->type != ObjType_VNode_x86_64_pdir) { // Right mapping
- printf("src type invalid\n");
- return SYS_ERR_WRONG_MAPPING;
+ // TODO: check if the system allows 1GB mappings
+ page_size = X86_64_HUGE_PAGE_SIZE;
+ // check offset within frame
+ genpaddr_t off = offset;
+
+ if (off + pte_count * X86_64_HUGE_PAGE_SIZE > get_size(src)) {
+ return SYS_ERR_FRAME_OFFSET_INVALID;
+ }
+ // Calculate page access protection flags /
+ // Get frame cap rights
+ flags_large = paging_x86_64_cap_to_page_flags(src->rights);
+ // Mask with provided access rights mask
+ flags_large = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(flags));
+ // Add additional arch-specific flags
+ flags_large |= X86_64_PTABLE_FLAGS(flags);
+ // Unconditionally mark the page present
+ flags_large |= X86_64_PTABLE_PRESENT;
}
break;
case ObjType_VNode_x86_64_pdir:
- // TODO: superpage support, set page_size to SUPER_PAGE_SIZE
+ // superpage support
if (src->type != ObjType_VNode_x86_64_ptable) { // Right mapping
- printf("src type invalid\n");
- return SYS_ERR_WRONG_MAPPING;
+ page_size = X86_64_LARGE_PAGE_SIZE;
+
+ // check offset within frame
+ genpaddr_t off = offset;
+
+ if (off + pte_count * X86_64_LARGE_PAGE_SIZE > get_size(src)) {
+ return SYS_ERR_FRAME_OFFSET_INVALID;
+ }
+ // Calculate page access protection flags /
+ // Get frame cap rights
+ flags_large = paging_x86_64_cap_to_page_flags(src->rights);
+ // Mask with provided access rights mask
+ flags_large = paging_x86_64_mask_attrs(flags, X86_64_PTABLE_ACCESS(flags));
+ // Add additional arch-specific flags
+ flags_large |= X86_64_PTABLE_FLAGS(flags);
+ // Unconditionally mark the page present
+ flags_large |= X86_64_PTABLE_PRESENT;
+
}
break;
default:
// cleanup mapping info
// TODO: cleanup already mapped pages
memset(&src_cte->mapping_info, 0, sizeof(struct mapping_info));
+ printf("slot in use\n");
return SYS_ERR_VNODE_SLOT_INUSE;
}
- paging_x86_64_map_table(entry, src_lp + offset);
+ // determine if we map a large/huge page or a normal entry
+ if (page_size == X86_64_LARGE_PAGE_SIZE)
+ {
+ //a large page is mapped
+ paging_x86_64_map_large((union x86_64_ptable_entry *)entry, src_lp + offset, flags_large);
+ } else if (page_size == X86_64_HUGE_PAGE_SIZE) {
+ // a huge page is mapped
+ paging_x86_64_map_huge((union x86_64_ptable_entry *)entry, src_lp + offset, flags_large);
+ } else {
+ //a normal paging structure entry is mapped
+ paging_x86_64_map_table(entry, src_lp + offset);
+ }
}
return SYS_ERR_OK;
struct capability *src, uintptr_t mflags,
uintptr_t offset, size_t pte_count)
{
+ //printf("page_mappings_arch:x86_64_ptable\n");
if (slot >= X86_64_PTABLE_SIZE) { // Within pagetable
+ printf(" vnode_invalid\n");
return SYS_ERR_VNODE_SLOT_INVALID;
}
lvaddr_t root_pt = local_phys_to_mem(dispatcher->vspace);
// loop over pdpts
+ union x86_64_ptable_entry *pt;
size_t kernel_pml4e = X86_64_PML4_BASE(X86_64_MEMORY_OFFSET);
- printk(LOG_NOTE, "1st kernel pml4e: %zu\n", kernel_pml4e);
for (int pdpt_index = 0; pdpt_index < kernel_pml4e; pdpt_index++) {
-
union x86_64_pdir_entry *pdpt = (union x86_64_pdir_entry *)root_pt + pdpt_index;
if (!pdpt->raw) { continue; }
genpaddr_t pdpt_gp = pdpt->d.base_addr << BASE_PAGE_BITS;
for (int pdir_index = 0; pdir_index < X86_64_PTABLE_SIZE; pdir_index++) {
// get pdir
union x86_64_pdir_entry *pdir = (union x86_64_pdir_entry *)pdpt_lv + pdir_index;
+ pt = (union x86_64_ptable_entry*)pdir;
if (!pdir->raw) { continue; }
+ // check if pdir or huge page
+ if (pt->huge.always1) {
+ // is huge page mapping
+ genpaddr_t paddr = (genpaddr_t)pt->huge.base_addr << HUGE_PAGE_BITS;
+ printf("%d.%d: 0x%"PRIxGENPADDR"\n", pdpt_index, pdir_index, paddr);
+ // goto next pdpt entry
+ 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));
for (int ptable_index = 0; ptable_index < X86_64_PTABLE_SIZE; ptable_index++) {
// get ptable
- union x86_64_ptable_entry *ptable = (union x86_64_ptable_entry *)pdir_lv + ptable_index;
+ union x86_64_pdir_entry *ptable = (union x86_64_pdir_entry *)pdir_lv + ptable_index;
+ pt = (union x86_64_ptable_entry *)ptable;
if (!ptable->raw) { continue; }
- genpaddr_t ptable_gp = ptable->base.base_addr << BASE_PAGE_BITS;
+ // check if ptable or large page
+ if (pt->large.always1) {
+ // is large page mapping
+ genpaddr_t paddr = (genpaddr_t)pt->large.base_addr << LARGE_PAGE_BITS;
+ printf("%d.%d.%d: 0x%"PRIxGENPADDR"\n", pdpt_index, pdir_index, ptable_index, paddr);
+ // goto next pdir entry
+ 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_64_PTABLE_SIZE; entry++) {
*/
/*
- * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
+ * Copyright (c) 2007-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#ifndef KERNEL_TARGET_X86_64_PAGING_H
uint64_t global :1;
uint64_t available :3;
uint64_t attr_index :1;
+ uint64_t reserved :17;
+ uint64_t base_addr :10;
+ uint64_t reserved2 :12;
+ uint64_t available2 :11;
+ uint64_t execute_disable :1;
+ } huge;
+ struct {
+ uint64_t present :1;
+ uint64_t read_write :1;
+ uint64_t user_supervisor :1;
+ uint64_t write_through :1;
+ uint64_t cache_disabled :1;
+ uint64_t accessed :1;
+ uint64_t dirty :1;
+ uint64_t always1 :1;
+ uint64_t global :1;
+ uint64_t available :3;
+ uint64_t attr_index :1;
uint64_t reserved :8;
uint64_t base_addr :X86_64_PAGING_LARGE_BASE_BITS;
uint64_t reserved2 :X86_64_PAGING_RESERVED_BITS;
}
/**
+ * \brief Maps a huge page.
+ *
+ * From huge page table entry, pointed to by 'entry', maps physical address
+ * 'base' with page attribute bitmap 'bitmap'.
+ *
+ * \param entry Pointer to page table entry to map from.
+ * \param base Physical address to map to (will be page-aligned).
+ * \param bitmap Bitmap to apply to page attributes.
+ */
+static inline void paging_x86_64_map_huge(union x86_64_ptable_entry *entry,
+ lpaddr_t base, uint64_t bitmap)
+{
+ union x86_64_ptable_entry tmp;
+ tmp.raw = X86_64_PTABLE_CLEAR;
+
+ tmp.huge.present = bitmap & X86_64_PTABLE_PRESENT ? 1 : 0;
+ tmp.huge.read_write = bitmap & X86_64_PTABLE_READ_WRITE ? 1 : 0;
+ tmp.huge.user_supervisor = bitmap & X86_64_PTABLE_USER_SUPERVISOR ? 1 : 0;
+ tmp.huge.write_through = bitmap & X86_64_PTABLE_WRITE_THROUGH ? 1 : 0;
+ tmp.huge.cache_disabled = bitmap & X86_64_PTABLE_CACHE_DISABLED ? 1 : 0;
+ tmp.huge.global = bitmap & X86_64_PTABLE_GLOBAL_PAGE ? 1 : 0;
+ tmp.huge.attr_index = bitmap & X86_64_PTABLE_ATTR_INDEX ? 1 : 0;
+ tmp.huge.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
+ tmp.huge.always1 = 1;
+ tmp.huge.base_addr = base >> X86_64_HUGE_PAGE_BITS;
+
+ *entry = tmp;
+}
+
+/**
* \brief Maps a large page.
*
* From large page table entry, pointed to by 'entry', maps physical address
tmp.large.execute_disable = bitmap & X86_64_PTABLE_EXECUTE_DISABLE ? 1 : 0;
tmp.large.always1 = 1;
tmp.large.base_addr = base >> 21;
-
+
*entry = tmp;
}
*/
/*
- * Copyright (c) 2012 ETH Zurich.
+ * Copyright (c) 2012, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <paging_generic.h>
return SYS_ERR_CAP_NOT_FOUND;
}
+// TODO: cleanup arch compatibility mess for page size selection
errval_t paging_tlb_flush_range(struct cte *frame, size_t pages)
{
// reconstruct first virtual address for TLB flushing
PRIxGENVADDR"--0x%"PRIxGENVADDR"\n",
vaddr, vaddr+(pages * BASE_PAGE_SIZE));
// flush TLB entries for all modified pages
+ size_t page_size = 0;
+ switch(leaf_pt->cap.type) {
+#if __x86_64__
+ case ObjType_VNode_x86_64_ptable:
+ page_size = X86_64_BASE_PAGE_SIZE;
+ break;
+ case ObjType_VNode_x86_64_pdir:
+ page_size = X86_64_LARGE_PAGE_SIZE;
+ break;
+ case ObjType_VNode_x86_64_pdpt:
+ page_size = X86_64_HUGE_PAGE_SIZE;
+ break;
+#elif __i386__
+ case ObjType_VNode_x86_32_ptable:
+ page_size = X86_32_BASE_PAGE_SIZE;
+ break;
+ case ObjType_VNode_x86_32_pdir:
+ page_size = X86_32_LARGE_PAGE_SIZE;
+ break;
+#else
+#error setup page sizes for arch
+#endif
+ default:
+ break;
+ }
+ assert(page_size);
+ // TODO: check what tlb flushing instructions expect for large/huge pages
for (int i = 0; i < pages; i++) {
do_one_tlb_flush(vaddr);
- vaddr += BASE_PAGE_SIZE;
+ vaddr += page_size;
}
return SYS_ERR_OK;
--------------------------------------------------------------------------
-- Copyright (c) 2007-2012, ETH Zurich
+-- Copyright (c) 2014, HP Labs.
-- All rights reserved.
--
-- This file is distributed under the terms in the attached LICENSE file.
getsrcs "multihop" = [ "multihop_chan.c" ]
getsrcs _ = []
+ -- configure default morecore pagesize based on Config.hs
+ morecore_pagesize "x86_64" = case Config.morecore_pagesize of
+ "large" -> "LARGE_PAGE_SIZE"
+ "huge" -> "HUGE_PAGE_SIZE"
+ _ -> "BASE_PAGE_SIZE"
+ morecore_pagesize "x86_32" = case Config.morecore_pagesize of
+ "large" -> "LARGE_PAGE_SIZE"
+ _ -> "BASE_PAGE_SIZE"
+ morecore_pagesize _ = "BASE_PAGE_SIZE"
+
+
-- sources specific to the architecture family
archfam_srcs "x86_32" = [ "arch/x86_32/debug.c" ,
"arch/x86_32/dispatch.c" , "arch/x86_32/syscalls.c" ,
("octopus", ["rpcclient"]),
("spawn", ["rpcclient"]),
("arrakis", ["rpcclient"])],
+ addCFlags = [ "-DMORECORE_PAGESIZE="++(morecore_pagesize arch) ],
addIncludes = [ "include", "include" ./. arch_dir ],
addGeneratedDependencies = [ "/include/asmoffsets.h" ]
}
getsrcs "multihop" = [ "multihop_chan.c" ]
getsrcs _ = []
+ -- configure default morecore pagesize based on Config.hs
+ morecore_pagesize "x86_64" = case Config.morecore_pagesize of
+ "large" -> "LARGE_PAGE_SIZE"
+ "huge" -> "HUGE_PAGE_SIZE"
+ _ -> "BASE_PAGE_SIZE"
+ morecore_pagesize "x86_32" = case Config.morecore_pagesize of
+ "large" -> "LARGE_PAGE_SIZE"
+ _ -> "BASE_PAGE_SIZE"
+ morecore_pagesize _ = "BASE_PAGE_SIZE"
+
+
-- sources specific to the architecture family
archfam_srcs "x86_32" = [ "arch/x86_32/debug.c" ,
"arch/x86_32/dispatch.c" , "arch/x86_32/syscalls.c" ,
cFiles = arch_srcs arch ++ archfam_srcs (archFamily arch)
++ common_srcs ++ idc_srcs,
assemblyFiles = arch_assembly (archFamily arch),
- addCFlags = [ "-DARRAKIS" ],
+ addCFlags = [ "-DARRAKIS", "-DMORECORE_PAGESIZE="++(morecore_pagesize arch) ],
flounderBindings = [ "mem", "octopus", "interdisp", "spawn", "arrakis",
"terminal" ],
-- only makes sense to compile monitor binding for lmp
*/
/*
- * Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
/*
#define ARM_USER_L1_OFFSET(addr) ((uintptr_t)(addr >> 22) & 0x3ffu)
#define ARM_USER_L2_OFFSET(addr) ((uintptr_t)(addr >> 12) & 0x3ffu)
+//large mapping flags
+#define FLAGS_LARGE 0x0100
+#define FLAGS_SECTION 0x0200
+#define FLAGS_SUPERSECTION 0x0300
+
static inline uintptr_t
vregion_flags_to_kpi_paging_flags(vregion_flags_t flags)
{
struct capref frame, size_t offset, size_t pte_count,
vregion_flags_t flags)
{
+ errval_t err = SYS_ERR_OK;
// Get the page table
struct vnode *ptable;
- errval_t err = get_ptable(pmap, vaddr, &ptable);
+ uintptr_t index;
+ if (flags&FLAGS_SECTION) {
+ //section mapping (1MB)
+ //mapped in the L1 table at root
+ ptable = &pmap->root;
+ index = ARM_USER_L1_OFFSET(vaddr);
+ printf("do_single_map: large path\n");
+ } else {
+ //4k mapping
+ err = get_ptable(pmap, vaddr, &ptable);
+ index = ARM_USER_L2_OFFSET(vaddr);
+ }
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
}
- uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags);
+ uintptr_t pmap_flags = vregion_flags_to_kpi_paging_flags(flags&~FLAGS_SUPERSECTION);
// XXX: reassess the following note -SG
// NOTE: strictly speaking a l2 entry only has 8 bits, but due to the way
// Barrelfish allocates l1 and l2 tables, we use 10 bits for the tracking
page->next = ptable->u.vnode.children;
ptable->u.vnode.children = page;
page->u.frame.cap = frame;
+ page->u.frame.flags = flags;
page->u.frame.pte_count = pte_count;
// Map entry into the page table
vregion_flags_t flags, size_t *retoff, size_t *retsize)
{
errval_t err;
+ size_t page_size;
+ size_t offset_level;
+ // determine mapping specific parts
+ if (flags&FLAGS_SECTION) {
+ //section mapping (1MB)
+ page_size = LARGE_PAGE_SIZE;
+ offset_level = ARM_L1_OFFSET(vaddr);
+ printf("do_map: large path\n");
+ printf("page_size: %i, size: %i\n", page_size, size);
+ } else {
+ //normal 4k mapping
+ page_size = BASE_PAGE_SIZE;
+ offset_level = ARM_L2_OFFSET(vaddr);
+ }
- size = ROUND_UP(size, BASE_PAGE_SIZE);
- size_t pte_count = DIVIDE_ROUND_UP(size, BASE_PAGE_SIZE);
+ size = ROUND_UP(size, page_size);
+ size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
genvaddr_t vend = vaddr + size;
- if (ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) {
+ //should be trivially true for section mappings
+ if ((ARM_L1_OFFSET(vaddr) == ARM_L1_OFFSET(vend-1)) ||
+ flags&FLAGS_SECTION) {
// fast path
err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
if (err_is_fail(err)) {
}
} else { // multiple leaf page tables
// first leaf
- uint32_t c = ARM_L2_MAX_ENTRIES - ARM_L2_OFFSET(vaddr);
- genvaddr_t temp_end = vaddr + c * BASE_PAGE_SIZE;
+ uint32_t c = ARM_L2_MAX_ENTRIES - offset_level;
+ genvaddr_t temp_end = vaddr + c * 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_DO_MAP);
// map full leaves
while (ARM_L1_OFFSET(temp_end) < ARM_L1_OFFSET(vend)) { // update vars
vaddr = temp_end;
- temp_end = vaddr + ARM_L2_MAX_ENTRIES * BASE_PAGE_SIZE;
- offset += c * BASE_PAGE_SIZE;
+ temp_end = vaddr + ARM_L2_MAX_ENTRIES * page_size;
+ offset += c * page_size;
c = ARM_L2_MAX_ENTRIES;
// copy cap
struct capref next;
}
// map remaining part
- offset += c * BASE_PAGE_SIZE;
+ offset += c * page_size;
c = ARM_L2_OFFSET(vend) - ARM_L2_OFFSET(temp_end);
if (c) {
// copy cap
size_t l1entries = DIVIDE_ROUND_UP(l2entries, 1024);
return pages + l2entries + l1entries;
}
+static size_t max_slabs_required_large(size_t bytes)
+{
+ // similar to the above, but larger page size and mapped only in a higher lvl paging structure
+ size_t pages = DIVIDE_ROUND_UP(bytes, LARGE_PAGE_SIZE);
+ size_t l1entries = DIVIDE_ROUND_UP(pages, 1024);
+ return pages + l1entries;
+}
/**
* \brief Refill slabs used for metadata
{
struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
- size += BASE_PAGE_OFFSET(offset);
- size = ROUND_UP(size, BASE_PAGE_SIZE);
- offset -= BASE_PAGE_OFFSET(offset);
+ size_t base;
+ size_t page_size;
+ size_t slabs_required;
+
+ // adjust the mapping to be on page boundaries
+ if (flags&FLAGS_SECTION) {
+ //section mapping (1MB)
+ base = LARGE_PAGE_OFFSET(offset);
+ page_size = LARGE_PAGE_SIZE;
+ slabs_required = max_slabs_required_large(size);
+ printf("map: large path, page_size: %i, base: %i, slabs: %i, size: %i\n", page_size, base, slabs_required, size);
+ } else {
+ //4k mapping
+ base = BASE_PAGE_OFFSET(offset);
+ page_size = BASE_PAGE_SIZE;
+ slabs_required = max_slabs_required(size);
+ }
+ size += base;
+ size = ROUND_UP(size, page_size);
+ offset -= base;
const size_t slabs_reserve = 3; // == max_slabs_required(1)
uint64_t slabs_free = slab_freecount(&pmap_arm->slab);
- size_t slabs_required = max_slabs_required(size) + slabs_reserve;
+
+ slabs_required += slabs_reserve;
if (slabs_required > slabs_free) {
if (get_current_pmap() == pmap) {
return SYS_ERR_OK;
}
+/** \brief Retrieves an address that can currently be used for large mappings
+ *
+ */
+static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
+ size_t alignment, genvaddr_t *retvaddr)
+{
+ struct pmap_arm *pmap_arm = (struct pmap_arm *)pmap;
+
+ struct vnode *walk_pdir = pmap_arm->root.u.vnode.children;
+ assert(walk_pdir != NULL); // assume there's always at least one existing entry
+
+ if (alignment == 0) {
+ alignment = BASE_PAGE_SIZE;
+ } else {
+ alignment = ROUND_UP(alignment, BASE_PAGE_SIZE);
+ }
+ size = ROUND_UP(size, alignment);
+
+ size_t free_count = DIVIDE_ROUND_UP(size, LARGE_PAGE_SIZE);
+ //debug_printf("need %zu contiguous free pdirs\n", free_count);
+
+ // compile pdir free list
+ // barrelfish treats L1 as 1024 entries
+ bool f[1024];
+ for (int i = 0; i < 1024; i++) {
+ f[i] = true;
+ }
+ f[walk_pdir->entry] = false;
+ while (walk_pdir) {
+ assert(walk_pdir->is_vnode);
+ f[walk_pdir->entry] = false;
+ walk_pdir = walk_pdir->next;
+ }
+ genvaddr_t first_free = 384;
+ for (; first_free < 512; first_free++) {
+ if (f[first_free]) {
+ for (int i = 1; i < free_count; i++) {
+ if (!f[first_free + i]) {
+ // advance pointer
+ first_free = first_free+i;
+ goto next;
+ }
+ }
+ break;
+ }
+next:
+ assert(1 == 1);// make compiler shut up about label
+ }
+ //printf("first free: %li\n", (uint32_t)first_free);
+ if (first_free + free_count <= 512) {
+ *retvaddr = first_free << 22;
+ return SYS_ERR_OK;
+ } else {
+ return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
+ }
+}
+
+
+
static errval_t do_single_modify_flags(struct pmap_arm *pmap, genvaddr_t vaddr,
size_t pages, vregion_flags_t flags)
{
static struct pmap_funcs pmap_funcs = {
.determine_addr = determine_addr,
+ .determine_addr_raw = determine_addr_raw,
.map = map,
.unmap = unmap,
.modify_flags = modify_flags,
/*
* Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
errval_t pmap_x86_determine_addr(struct pmap *pmap, struct memobj *memobj,
size_t alignment, genvaddr_t *vaddr);
+/**
+ * \brief check whether vnode `root` has children in [entry .. entry+len).
+ * \return * true iff `root` has children in [entry .. entry+len) and
+ * only_pages false
+ * * true iff `root` has valid page mappings in [entry .. entry+len)
+ * and only_pages true
+ */
+bool has_vnode(struct vnode *root, uint32_t entry, size_t len,
+ bool only_pages);
+/**
+ * \return vnode at `entry` in `root`. NULL if no vnode there.
+ */
+struct vnode *find_vnode(struct vnode *root, uint16_t entry);
+
+/**
+ * \return true iff [entry..entry+npages) inside a child of `root`.
+ */
+bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages);
+
+/**
+ * \brief remove vnode `item` from list of children of `root`.
+ */
+void remove_vnode(struct vnode *root, struct vnode *item);
+
+/**
+ * \brief allocate vnode as child of `root` with type `type`. Allocates the
+ * struct vnode with `pmap`'s slab allocator.
+ * \arg entry the entry at which the new vnode is inserted
+ * \arg retvnode pointer to the new vnode.
+ */
+errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
+ enum objtype type, uint32_t entry,
+ struct vnode **retvnode);
+
+/**
+ * \brief remove vnodes with no leafs in [entry .. entry+len), destroy their
+ * associated capabilities and free their slabs.
+ */
+void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root,
+ uint32_t entry, size_t len);
+
#endif // TARGET_X86_BARRELFISH_PMAP_X86_H
*/
/*
- * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, ETH Zurich.
+ * Copyright (c) 2007-2012, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
static bool request_done = false;
+static bool parse_argv(struct spawn_domain_params *params, size_t *morecore_alignment)
+{
+ // grab pagesize config from argv if available
+ size_t morecore_pagesize = MORECORE_PAGESIZE;
+ int i = 1;
+ bool found = false;
+ for (; i < params->argc; i++) {
+ if (!found) {
+ if (!strncmp(params->argv[i], "morecore=", 9)) {
+ morecore_pagesize = strtol(params->argv[i]+9, NULL, 0);
+ // check for valid page size
+ switch (morecore_pagesize) {
+#ifdef __x86_64__
+ case HUGE_PAGE_SIZE:
+#endif
+ case BASE_PAGE_SIZE:
+ case LARGE_PAGE_SIZE:
+ break;
+ default:
+ morecore_pagesize = MORECORE_PAGESIZE;
+ }
+ found = true;
+ }
+ } else {
+ // found so move all other args one to the front
+ params->argv[i-1] = params->argv[i];
+ }
+ }
+ if (found) {
+ params->argc -= 1;
+ }
+
+ if (morecore_alignment) {
+ *morecore_alignment = morecore_pagesize;
+ }
+
+ return found;
+}
+
/** \brief Initialise libbarrelfish.
*
* This runs on a thread in every domain, after the dispatcher is setup but
// TODO: the kernel boots us with a deterministic pmap structure: use it
}
- err = morecore_init();
+ if (init_domain) {
+ // we cannot use large pages in the init domains because we are not
+ // connected to the memory server and need to work with the 4k pages
+ // in the base cn.
+ err = morecore_init(BASE_PAGE_SIZE);
+ } else {
+ size_t morecore_pagesize = 0;
+ parse_argv(params, &morecore_pagesize);
+ err = morecore_init(morecore_pagesize);
+ }
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_MORECORE_INIT);
}
return err_push(err, LIB_ERR_RAM_ALLOC_SET);
}
+ // switch morecore to intended configuration
+ err = morecore_reinit();
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_MORECORE_INIT);
+ }
+
#ifdef CONFIG_TRACE
err = trace_my_setup();
if (err_is_fail(err)) {
/*
* Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
return get_morecore_state()->header_freep;
}
-errval_t morecore_init(void)
+errval_t morecore_init(size_t alignment)
{
errval_t err;
struct morecore_state *state = get_morecore_state();
thread_mutex_init(&state->mutex);
- err = vspace_mmu_aware_init(&state->mmu_state, HEAP_REGION);
+ // setup flags that match the alignment
+ vregion_flags_t morecore_flags = VREGION_FLAGS_READ_WRITE;
+#if __x86_64__
+ morecore_flags |= (alignment == HUGE_PAGE_SIZE ? VREGION_FLAGS_HUGE : 0);
+#endif
+ morecore_flags |= (alignment == LARGE_PAGE_SIZE ? VREGION_FLAGS_LARGE : 0);
+
+ err = vspace_mmu_aware_init_aligned(&state->mmu_state, HEAP_REGION,
+ alignment, morecore_flags);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VSPACE_MMU_AWARE_INIT);
}
return SYS_ERR_OK;
}
+
+errval_t morecore_reinit(void)
+{
+ errval_t err;
+ struct morecore_state *state = get_morecore_state();
+
+ size_t mapoffset = state->mmu_state.mapoffset;
+ size_t remapsize = ROUND_UP(mapoffset, state->mmu_state.alignment);
+ if (remapsize <= mapoffset) {
+ // don't need to do anything if we only recreate the exact same
+ // mapping
+ return SYS_ERR_OK;
+ }
+ struct capref frame;
+ size_t retsize;
+ err = frame_alloc(&frame, remapsize, &retsize);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ return vspace_mmu_aware_reset(&state->mmu_state, frame, remapsize);
+}
/*
* Copyright (c) 2010, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
err = mca->top->alloc(mca->top, &cap);
if (err_is_fail(err)) {
thread_mutex_unlock(&ca->mutex);
+ debug_printf("top allocator out of slots; can't refill\n");
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
thread_mutex_unlock(&ca->mutex); // cnode_create_raw uses ram_alloc
/*
* Copyright (c) 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
#include <barrelfish/pmap.h>
#include "target/x86/pmap_x86.h"
+// this should work for x86_64 and x86_32.
+bool has_vnode(struct vnode *root, uint32_t entry, size_t len,
+ bool only_pages)
+{
+ assert(root != NULL);
+ assert(root->is_vnode);
+ struct vnode *n;
+
+ uint32_t end_entry = entry + len;
+
+ // region we check [entry .. end_entry)
+
+ for (n = root->u.vnode.children; n; n = n->next) {
+ // n is page table, we need to check if it's anywhere inside the
+ // region to check [entry .. end_entry)
+ // this amounts to n->entry == entry for len = 1
+ if (n->is_vnode && n->entry >= entry && n->entry < end_entry) {
+ if (only_pages) {
+ return has_vnode(n, 0, PTABLE_SIZE, true);
+ }
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+ debug_printf("1: found page table inside our region\n");
+#endif
+ return true;
+ } else if (n->is_vnode) {
+ // all other vnodes do not overlap with us, so go to next
+ assert(n->entry < entry || n->entry >= end_entry);
+ continue;
+ }
+ // this remains the same regardless of `only_pages`.
+ // n is frame [n->entry .. end)
+ // 3 cases:
+ // 1) entry < n->entry && end_entry >= end --> n is a strict subset of
+ // our region
+ // 2) entry inside n (entry >= n->entry && entry < end)
+ // 3) end_entry inside n (end_entry >= n->entry && end_entry < end)
+ uint32_t end = n->entry + n->u.frame.pte_count;
+ if (entry < n->entry && end_entry >= end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+ debug_printf("2: found a strict subset of our region: (%"
+ PRIu32"--%"PRIu32") < (%"PRIu32"--%"PRIu32")\n",
+ n->entry, end, entry, end_entry);
+#endif
+ return true;
+ }
+ if (entry >= n->entry && entry < end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+ debug_printf("3: found a region starting inside our region: (%"
+ PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n",
+ n->entry, end, entry, end_entry);
+#endif
+ return true;
+ }
+ if (end_entry > n->entry && end_entry < end) {
+#ifdef LIBBARRELFISH_DEBUG_PMAP
+ debug_printf("4: found a region ending inside our region: (%"
+ PRIu32"--%"PRIu32") <> (%"PRIu32"--%"PRIu32")\n",
+ n->entry, end, entry, end_entry);
+#endif
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * \brief Starting at a given root, return the vnode with entry equal to #entry
+ */
+struct vnode *find_vnode(struct vnode *root, uint16_t entry)
+{
+ assert(root != NULL);
+ assert(root->is_vnode);
+ struct vnode *n;
+
+ for(n = root->u.vnode.children; n != NULL; n = n->next) {
+ if(n->entry == entry) {
+ return n;
+ }
+ }
+ return NULL;
+}
+
+bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
+{
+ assert(root != NULL);
+ assert(root->is_vnode);
+
+ struct vnode *n;
+
+ for (n = root->u.vnode.children; n; n = n->next) {
+ if (!n->is_vnode) {
+ uint16_t end = n->entry + n->u.frame.pte_count;
+ if (n->entry <= entry && entry + npages <= end) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void remove_vnode(struct vnode *root, struct vnode *item)
+{
+ assert(root->is_vnode);
+ struct vnode *walk = root->u.vnode.children;
+ struct vnode *prev = NULL;
+ while (walk) {
+ if (walk == item) {
+ if (prev) {
+ prev->next = walk->next;
+ return;
+ } else {
+ root->u.vnode.children = walk->next;
+ return;
+ }
+ }
+ prev = walk;
+ walk = walk->next;
+ }
+ USER_PANIC("Should not get here");
+}
+
+/**
+ * \brief Allocates a new VNode, adding it to the page table and our metadata
+ */
+errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
+ enum objtype type, uint32_t entry,
+ struct vnode **retvnode)
+{
+ errval_t err;
+
+ struct vnode *newvnode = slab_alloc(&pmap->slab);
+ if (newvnode == NULL) {
+ return LIB_ERR_SLAB_ALLOC_FAIL;
+ }
+
+ // The VNode capability
+ err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_SLOT_ALLOC);
+ }
+
+ err = vnode_create(newvnode->u.vnode.cap, type);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_VNODE_CREATE);
+ }
+
+ // Map it
+ err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
+ PTABLE_ACCESS_DEFAULT, 0, 1);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_VNODE_MAP);
+ }
+
+ // The VNode meta data
+ newvnode->is_vnode = true;
+ newvnode->entry = entry;
+ newvnode->next = root->u.vnode.children;
+ root->u.vnode.children = newvnode;
+ newvnode->u.vnode.children = NULL;
+
+ *retvnode = newvnode;
+ return SYS_ERR_OK;
+}
+
+void remove_empty_vnodes(struct pmap_x86 *pmap, struct vnode *root,
+ uint32_t entry, size_t len)
+{
+ errval_t err;
+ uint32_t end_entry = entry + len;
+ for (struct vnode *n = root->u.vnode.children; n; n = n->next) {
+ if (n->entry >= entry && n->entry < end_entry) {
+ // sanity check and skip leaf entries
+ if (!n->is_vnode) {
+ continue;
+ }
+ // here we know that all vnodes we're interested in are
+ // page tables
+ assert(n->is_vnode);
+ if (n->u.vnode.children) {
+ remove_empty_vnodes(pmap, n, 0, PTABLE_SIZE);
+ }
+
+ // unmap
+ err = vnode_unmap(root->u.vnode.cap, n->u.vnode.cap, n->entry, 1);
+ if (err_is_fail(err)) {
+ debug_printf("remove_empty_vnodes: vnode_unmap: %s\n",
+ err_getstring(err));
+ }
+
+ // delete capability
+ err = cap_destroy(n->u.vnode.cap);
+ if (err_is_fail(err)) {
+ debug_printf("remove_empty_vnodes: cap_destroy: %s\n",
+ err_getstring(err));
+ }
+
+ // remove vnode from list
+ remove_vnode(root, n);
+ slab_free(&pmap->slab, n);
+ }
+ }
+}
+
+
/*
* The serialisation format is depressingly ad-hoc, and assumes a depth-first
* walk of the tree. Each vnode is encoded as an entry in an array.
*/
/*
- * Copyright (c) 2010, 2011, ETH Zurich.
+ * Copyright (c) 2010-2013 ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
#include <stdio.h>
#include "target/x86/pmap_x86.h"
+
// Location and size of virtual address space reserved for mapping
// frames backing refill_slabs
#define META_DATA_RESERVED_BASE ((lvaddr_t)1UL*1024*1024*1024)
#define META_DATA_RESERVED_SIZE (X86_32_BASE_PAGE_SIZE * 1200)
+// flags for large pages
+#define FLAGS_LARGE 0x0100
+
/**
* \brief Translate generic vregion flags to architecture specific pmap flags
*/
{
return (va1>>X86_32_LARGE_PAGE_BITS) == (va2>>X86_32_LARGE_PAGE_BITS);
}
+static inline bool is_same_pdpt(genvaddr_t va1, genvaddr_t va2)
+{
+#ifdef CONFIG_PAE
+ // PDPT in PAE has 4 entries, uses the topmost two bits
+ return (va1>>30) == (va2>>30);
+#else
+ // since there is no PDPT in 32bit, trivially true
+ return true;
+#endif
+}
static inline genvaddr_t get_addr_prefix(genvaddr_t va)
{
return va >> X86_32_LARGE_PAGE_BITS;
}
+
/**
- * \brief Starting at a given root, return the vnode with entry equal to #entry
+ * \brief Returns the vnode for the page directory mapping a given vspace address
*/
-static struct vnode *find_vnode(struct vnode *root, uint16_t entry)
-{
- assert(root != NULL);
- assert(root->is_vnode);
- struct vnode *n;
-
- for(n = root->u.vnode.children; n != NULL; n = n->next) {
- if(n->entry == entry) {
- return n;
- }
- }
- return NULL;
-}
-
-static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
-{
- assert(root != NULL);
- assert(root->is_vnode);
-
- struct vnode *n;
-
- for (n = root->u.vnode.children; n; n = n->next) {
- if (!n->is_vnode) {
- uint16_t end = n->entry + n->u.frame.pte_count;
- if (n->entry <= entry && entry + npages <= end) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
+static errval_t get_pdir(struct pmap_x86 *pmap, genvaddr_t base,
+ struct vnode **pdir)
{
+#ifdef CONFIG_PAE
+ struct vnode *root = &pmap->root;
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);
- struct vnode *walk = root->u.vnode.children;
- struct vnode *prev = NULL;
- while (walk) {
- if (walk == item) {
- if (prev) {
- prev->next = walk->next;
- return;
- } else {
- root->u.vnode.children = walk->next;
- return;
- }
+ // PDPTE mapping
+ if((*pdir = find_vnode(root, X86_32_PDPTE_BASE(base))) == NULL) {
+ errval_t err = alloc_vnode(pmap, root, ObjType_VNode_x86_32_pdir,
+ X86_32_PDPTE_BASE(base), pdir);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
}
- prev = walk;
- walk = walk->next;
}
- USER_PANIC("Should not get here");
-}
-
-/**
- * \brief Allocates a new VNode, adding it to the page table and our metadata
- */
-static errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
- enum objtype type, uint32_t entry,
- struct vnode **retvnode)
-{
- errval_t err;
-
- struct vnode *newvnode = slab_alloc(&pmap->slab);
- if (newvnode == NULL) {
- return LIB_ERR_SLAB_ALLOC_FAIL;
- }
-
- // The VNode capability
- err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_SLOT_ALLOC);
- }
-
- err = vnode_create(newvnode->u.vnode.cap, type);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_VNODE_CREATE);
- }
-
- // Map it
- err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
- X86_32_PTABLE_ACCESS_DEFAULT, 0, 1);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_VNODE_MAP);
- }
-
- // The VNode meta data
- newvnode->is_vnode = true;
- newvnode->entry = entry;
- newvnode->next = root->u.vnode.children;
- root->u.vnode.children = newvnode;
- newvnode->u.vnode.children = NULL;
+#else
+ *pdir = &pmap->root;
+#endif
- *retvnode = newvnode;
return SYS_ERR_OK;
}
{
errval_t err;
struct vnode *pdir;
-
-#ifdef CONFIG_PAE
- struct vnode *root = &pmap->root;
- assert(root != NULL);
-
- // PDPTE mapping
- if((pdir = find_vnode(root, X86_32_PDPTE_BASE(base))) == NULL) {
- err = alloc_vnode(pmap, root, ObjType_VNode_x86_32_pdir,
- X86_32_PDPTE_BASE(base), &pdir);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
- }
+ err = get_pdir(pmap, base, &pdir);
+ if (err_is_fail(err)) {
+ return err;
}
-#else
- pdir = &pmap->root;
-#endif
// PDIR mapping
if((*ptable = find_vnode(pdir, X86_32_PDIR_BASE(base))) == NULL) {
return SYS_ERR_OK;
}
-static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+static struct vnode *find_pdir(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;
- }
+ return find_vnode(root, X86_32_PDPTE_BASE(base));
#else
- pdir = root;
+ return root;
#endif
+}
- // PDIR mapping
- return find_vnode(pdir, X86_32_PDIR_BASE(base));
+static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+{
+ struct vnode *pdir = find_pdir(pmap, base);
+
+ if (pdir) {
+ // PDIR mapping
+ return find_vnode(pdir, X86_32_PDIR_BASE(base));
+ } else {
+ return NULL;
+ }
}
-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,
+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)
{
+ //printf("[do_single_map] vaddr = 0x%"PRIxGENVADDR"\n", vaddr);
// translate flags
paging_x86_32_flags_t pmap_flags = vregion_to_pmap_flag(flags);
- // Get the page table
+ // Get the page table and do mapping specific alterations
struct vnode *ptable;
- errval_t err = get_ptable(pmap, vaddr, &ptable);
+ errval_t err;
+ size_t base;
+
+ if (flags & VREGION_FLAGS_LARGE) {
+ //4M/2M(PAE) mapping
+ err = get_pdir(pmap, vaddr, &ptable);
+ base = X86_32_PDIR_BASE(vaddr);
+ } else {
+ //4k mapping
+ err = get_ptable(pmap, vaddr, &ptable);
+ base = X86_32_PTABLE_BASE(vaddr);
+ }
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
}
+ assert(ptable->is_vnode);
// 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;
+ if (has_vnode(ptable, base, pte_count, false)) {
+ if (has_vnode(ptable, base, pte_count, true)) {
+ printf("page already exists in 0x%"
+ PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+ return LIB_ERR_PMAP_EXISTING_MAPPING;
+ } else {
+ // clean out empty page tables. We do this here because we benefit
+ // from having the page tables in place when doing lots of small
+ // mappings
+ remove_empty_vnodes(pmap, ptable, base, pte_count);
+ }
}
// setup userspace mapping
struct vnode *page = slab_alloc(&pmap->slab);
assert(page);
page->is_vnode = false;
- page->entry = X86_32_PTABLE_BASE(vaddr);
+ page->entry = base;
page->next = ptable->u.vnode.children;
ptable->u.vnode.children = page;
page->u.frame.cap = frame;
page->u.frame.pte_count = pte_count;
// do map
- err = vnode_map(ptable->u.vnode.cap, frame, X86_32_PTABLE_BASE(vaddr),
+ err = vnode_map(ptable->u.vnode.cap, frame, base,
pmap_flags, offset, pte_count);
if (err_is_fail(err)) {
+ printf("error in do_single_map: vnode_map failed\n");
return err_push(err, LIB_ERR_VNODE_MAP);
}
//printf("[do_map] vaddr = 0x%"PRIxGENVADDR", size = %zd\n", vaddr, size);
errval_t err;
- size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
- size_t pte_count = DIVIDE_ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+ // figure out mapping parameters
+ size_t page_size = X86_32_BASE_PAGE_SIZE;
+ size_t base = X86_32_PTABLE_BASE(vaddr);
+ if(flags & VREGION_FLAGS_LARGE) {
+ //4M/2M (PAE) pages
+ page_size = X86_32_LARGE_PAGE_SIZE;
+ base = X86_32_PDIR_BASE(vaddr);
+ }
+
+ // TODO: needs overhaul for mixed-size mappings
+ // TODO: need to make sure we can map that much
+ size = ROUND_UP(size, page_size);
+ size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
genvaddr_t vend = vaddr + size;
- if (is_same_pdir(vaddr, vend)) {
+ if (is_same_pdir(vaddr, vend) ||
+ (flags & VREGION_FLAGS_LARGE && is_same_pdpt(vaddr, vend))) {
// fast path
err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
if (err_is_fail(err)) {
}
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;
+ uint32_t c = X86_32_PTABLE_SIZE - base;
+ genvaddr_t temp_end = vaddr + c * 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_DO_MAP);
while (get_addr_prefix(temp_end) < get_addr_prefix(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;
+ temp_end = vaddr + X86_32_PTABLE_SIZE * page_size;
+ offset += c * page_size;
c = X86_32_PTABLE_SIZE;
// copy cap
struct capref next;
frame = next;
// do mapping
- err = do_single_map(pmap, vaddr, temp_end, frame, offset, X86_32_PTABLE_SIZE, flags);
+ 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);
}
}
// map remaining part
- offset += c * X86_32_BASE_PAGE_SIZE;
- c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(temp_end);
+ offset += c * page_size;
+ if(flags & VREGION_FLAGS_LARGE) {
+ // 4M/2M (PAE) mapping
+ c = X86_32_PDIR_BASE(vend) - X86_32_PDIR_BASE(temp_end);
+ } else {
+ // 4K mapping
+ c = X86_32_PTABLE_BASE(vend) - X86_32_PTABLE_BASE(temp_end);
+ }
if (c) {
// copy cap
struct capref next;
return SYS_ERR_OK;
}
-/// Computer upper limit on number of slabs required to perform a mapping
+/// Compute upper limit on number of slabs required to perform a mapping
static size_t max_slabs_for_mapping(size_t bytes)
{
size_t max_pages = DIVIDE_ROUND_UP(bytes, X86_32_BASE_PAGE_SIZE);
#endif
return max_pages + max_ptable + max_pdir + max_pdpt;
}
+static size_t max_slabs_for_mapping_large(size_t bytes)
+{
+ size_t max_pages = DIVIDE_ROUND_UP(bytes, X86_32_LARGE_PAGE_SIZE);
+ size_t max_pdir = DIVIDE_ROUND_UP(max_pages, X86_32_PTABLE_SIZE) + 1;
+#ifdef CONFIG_PAE
+ size_t max_pdpt = DIVIDE_ROUND_UP(max_pdir, X86_32_PTABLE_SIZE) + 1;
+#else
+ size_t max_pdpt = 0;
+#endif
+ return max_pages + max_pdir + max_pdpt;
+}
/**
* \brief Refill slabs used for metadata
size_t offset, size_t size, vregion_flags_t flags,
size_t *retoff, size_t *retsize)
{
+ //printf("[map] vaddr = 0x%"PRIxGENVADDR", size = %zd\n", vaddr, size);
errval_t err;
struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
+
+ size_t max_slabs;
// Adjust the parameters to page boundaries
- size += X86_32_BASE_PAGE_OFFSET(offset);
- size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
- offset -= X86_32_BASE_PAGE_OFFSET(offset);
+ if(flags&FLAGS_LARGE) {
+ // 4M pages/2M pages(PAE)
+ size += X86_32_LARGE_PAGE_OFFSET(offset);
+ size = ROUND_UP(size, X86_32_LARGE_PAGE_SIZE);
+ offset -= X86_32_LARGE_PAGE_OFFSET(offset);
+ max_slabs = max_slabs_for_mapping_large(size);
+ } else {
+ // 4K pages
+ size += X86_32_BASE_PAGE_OFFSET(offset);
+ size = ROUND_UP(size, X86_32_BASE_PAGE_SIZE);
+ offset -= X86_32_BASE_PAGE_OFFSET(offset);
+ max_slabs = max_slabs_for_mapping(size);
+ }
// Refill slab allocator if necessary
size_t slabs_free = slab_freecount(&x86->slab);
- size_t max_slabs = max_slabs_for_mapping(size);
max_slabs += 4; // minimum amount required to map a page
if (slabs_free < max_slabs) {
struct pmap *mypmap = get_current_pmap();
}
}
+ //printf("[map call do_map] vaddr = 0x%"PRIxGENVADDR", flag = %x\n", vaddr, (int)flags);
err = do_map(x86, vaddr, frame, offset, size, flags, retoff, retsize);
return err;
}
-static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
+/**
+ * \brief Find mapping for `vaddr` in `pmap`.
+ * \arg pmap the pmap to search in
+ * \arg vaddr the virtual address to search for
+ * \arg pt the last-level page table meta-data we found if any
+ * \arg page the page meta-data we found if any
+ * \returns `true` iff we found a mapping for vaddr
+ */
+static bool find_mapping(struct pmap_x86 *pmap, genvaddr_t vaddr,
+ struct vnode **outpt, struct vnode **outpage)
+{
+ struct vnode *pdir = NULL, *pt = NULL, *page = NULL;
+
+ // find page and last-level page table (can be pdir or pdpt)
+ if ((pdir = find_pdir(pmap, vaddr)) != NULL) {
+ page = find_vnode(pdir, X86_32_PDIR_BASE(vaddr));
+ if (page && page->is_vnode) { // not 2M/4M pages
+ pt = page;
+ page = find_vnode(pt, X86_32_PTABLE_BASE(vaddr));
+ } else if (page) {
+ pt = pdir;
+ }
+ }
+ if (outpt) {
+ *outpt = pt;
+ }
+ if (outpage) {
+ *outpage = page;
+ }
+ if (pt) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+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);
+ struct vnode *pt = NULL, *page = NULL;
+
+ find_mapping(pmap, vaddr, &pt, &page);
+
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->u.frame.cap, page->entry, page->u.frame.pte_count);
+ err = vnode_unmap(pt->u.vnode.cap, page->u.frame.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));
+ printf("vnode_unmap returned error: %s (%d)\n",
+ err_getstring(err), err_no(err));
return err_push(err, LIB_ERR_VNODE_UNMAP);
}
slab_free(&pmap->slab, page);
}
else {
+ printf("couldn't find vnode\n");
return LIB_ERR_PMAP_FIND_VNODE;
}
}
return SYS_ERR_OK;
}
+static inline bool is_large_page(struct vnode *p)
+{
+ return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_LARGE;
+}
+static inline bool is_huge_page(struct vnode *p)
+{
+ return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_HUGE;
+}
+
/**
* \brief Remove page mappings
*
//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);
+
+ //determine if we unmap a larger page
+ struct vnode* page = NULL;
+
+ if (!find_mapping(x86, vaddr, NULL, &page)) {
+ // TODO: better error
+ return LIB_ERR_PMAP_UNMAP;
+ }
+ assert(!page->is_vnode);
+
+ size_t page_size = X86_32_BASE_PAGE_SIZE;
+ if (is_large_page(page)) {
+ //large 2M page
+ page_size = X86_32_LARGE_PAGE_SIZE;
+ }
+
+ size = ROUND_UP(size, page_size);
genvaddr_t vend = vaddr + size;
- if (is_same_pdir(vaddr, vend)) {
+ if (is_same_pdir(vaddr, vend) ||
+ (is_same_pdpt(vaddr, vend) && is_large_page(page))) {
// fast path
- err = do_single_unmap(x86, vaddr, size / X86_32_BASE_PAGE_SIZE, false);
+ err = do_single_unmap(x86, vaddr, size / page_size, false);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_UNMAP);
}
}
// unmap full leaves
- vaddr += c * X86_32_BASE_PAGE_SIZE;
+ vaddr += c * page_size;
while (get_addr_prefix(vaddr) < get_addr_prefix(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;
+ vaddr += c * page_size;
}
// unmap remaining part
* \param vaddr The virtual address to unmap
* \param flags New flags for the mapping
* \param retsize If non-NULL, filled in with the actual size modified
+ *
+ * TODO: fix for large page mappings
*/
static errval_t modify_flags(struct pmap *pmap, genvaddr_t vaddr, size_t size,
vregion_flags_t flags, size_t *retsize)
return SYS_ERR_OK;
}
+/** \brief Retrieves an address that can currently be used for large mappings
+ *
+ */
+static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
+ size_t alignment, genvaddr_t *retvaddr)
+{
+ struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
+
+ struct vnode *walk_pdir = x86->root.u.vnode.children;
+ assert(walk_pdir != NULL); // assume there's always at least one existing entry
+
+ if (alignment == 0) {
+ alignment = BASE_PAGE_SIZE;
+ } else {
+ alignment = ROUND_UP(alignment, BASE_PAGE_SIZE);
+ }
+ size = ROUND_UP(size, alignment);
+
+ size_t free_count = DIVIDE_ROUND_UP(size, LARGE_PAGE_SIZE);
+ //debug_printf("need %zu contiguous free pdirs\n", free_count);
+
+ // compile pdir free list
+ bool f[1024];
+ for (int i = 0; i < 1024; i++) {
+ f[i] = true;
+ }
+ f[walk_pdir->entry] = false;
+ while (walk_pdir) {
+ assert(walk_pdir->is_vnode);
+ f[walk_pdir->entry] = false;
+ walk_pdir = walk_pdir->next;
+ }
+ genvaddr_t first_free = 384;
+ // XXX: breaks for PAE
+ for (; first_free < 512; first_free++) {
+ if (f[first_free]) {
+ for (int i = 1; i < free_count; i++) {
+ if (!f[first_free + i]) {
+ // advance pointer
+ first_free = first_free+i;
+ goto next;
+ }
+ }
+ break;
+ }
+next:
+ assert(1 == 1);// make compiler shut up about label
+ }
+ //printf("first free: %li\n", (uint32_t)first_free);
+ if (first_free + free_count <= 512) {
+ *retvaddr = first_free << 22;
+ return SYS_ERR_OK;
+ } else {
+ return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
+ }
+}
+
+
static struct pmap_funcs pmap_funcs = {
.determine_addr = pmap_x86_determine_addr,
+ .determine_addr_raw = determine_addr_raw,
.map = map,
.unmap = unmap,
.modify_flags = modify_flags,
*/
/*
- * Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2009-2013 ETH Zurich.
+ * Copyright (c) 2014 HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
return pmap_flags;
}
+// returns whether va1 and va2 share a page directory entry
+// not using X86_64_PDIR_BASE() macro as this would give false positives (same
+// entry in different directories)
static inline bool is_same_pdir(genvaddr_t va1, genvaddr_t va2)
{
- return (va1>>X86_64_LARGE_PAGE_BITS) == (va2>>X86_64_LARGE_PAGE_BITS);
+ return (va1>>X86_64_LARGE_PAGE_BITS) == ((va2-1)>>X86_64_LARGE_PAGE_BITS);
}
-static inline genvaddr_t get_addr_prefix(genvaddr_t va)
+// returns whether va1 and va2 share a page directory pointer table entry
+static inline bool is_same_pdpt(genvaddr_t va1, genvaddr_t va2)
{
- return va >> X86_64_LARGE_PAGE_BITS;
+ return (va1>>X86_64_HUGE_PAGE_BITS) == ((va2-1)>>X86_64_HUGE_PAGE_BITS);
}
-static bool has_vnode(struct vnode *root, uint32_t entry, size_t len)
+// returns whether va1 and va2 share a page map level 4 entry
+static inline bool is_same_pml4(genvaddr_t va1, genvaddr_t va2)
{
- 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;
+ // the base macros work here as we only have one pml4.
+ return X86_64_PML4_BASE(va1) == X86_64_PML4_BASE(va2-1);
}
-
-/**
- * \brief Starting at a given root, return the vnode with starting entry equal to #entry
- */
-static struct vnode *find_vnode(struct vnode *root, uint32_t entry)
+// size indicates how many bits to shift
+static inline genvaddr_t get_addr_prefix(genvaddr_t va, uint8_t size)
{
- assert(root != NULL);
- assert(root->is_vnode);
- struct vnode *n;
-
- for(n = root->u.vnode.children; n != NULL; n = n->next) {
- if(n->entry == entry) {
- return n;
- }
- }
- return NULL;
+ return va >> size;
}
-static bool inside_region(struct vnode *root, uint32_t entry, uint32_t npages)
+/**
+ * \brief Returns the vnode for the pdpt mapping a given vspace address
+ */
+static inline errval_t get_pdpt(struct pmap_x86 *pmap, genvaddr_t base,
+ struct vnode **pdpt)
{
+ errval_t err;
+ struct vnode *root = &pmap->root;
assert(root != NULL);
- assert(root->is_vnode);
-
- struct vnode *n;
- for (n = root->u.vnode.children; n; n = n->next) {
- if (!n->is_vnode) {
- uint16_t end = n->entry + n->u.frame.pte_count;
- if (n->entry <= entry && entry + npages <= end) {
- return true;
- }
+ // PML4 mapping
+ if((*pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
+ err = alloc_vnode(pmap, root, ObjType_VNode_x86_64_pdpt,
+ X86_64_PML4_BASE(base), pdpt);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
}
}
- return false;
-}
-
-static void remove_vnode(struct vnode *root, struct vnode *item)
-{
- assert(root->is_vnode);
- struct vnode *walk = root->u.vnode.children;
- struct vnode *prev = NULL;
- while (walk) {
- if (walk == item) {
- if (prev) {
- prev->next = walk->next;
- return;
- } else {
- root->u.vnode.children = walk->next;
- return;
- }
- }
- prev = walk;
- walk = walk->next;
- }
- assert(!"Should not get here");
+ return SYS_ERR_OK;
}
/**
- * \brief Allocates a new VNode, adding it to the page table and our metadata
+ * \brief Returns the vnode for the page directory mapping a given vspace
+ * address
*/
-static errval_t alloc_vnode(struct pmap_x86 *pmap, struct vnode *root,
- enum objtype type, uint32_t entry,
- struct vnode **retvnode)
+static inline errval_t get_pdir(struct pmap_x86 *pmap, genvaddr_t base,
+ struct vnode **pdir)
{
errval_t err;
-
- struct vnode *newvnode = slab_alloc(&pmap->slab);
- if (newvnode == NULL) {
- return LIB_ERR_SLAB_ALLOC_FAIL;
- }
-
- // The VNode capability
- err = pmap->p.slot_alloc->alloc(pmap->p.slot_alloc, &newvnode->u.vnode.cap);
+ struct vnode *pdpt;
+ err = get_pdpt(pmap, base, &pdpt);
if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_SLOT_ALLOC);
+ return err;
}
+ assert(pdpt != NULL);
- err = vnode_create(newvnode->u.vnode.cap, type);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_VNODE_CREATE);
- }
-
- // Map it
- //printf("\talloc_vnode calling vnode_map()\n");
- err = vnode_map(root->u.vnode.cap, newvnode->u.vnode.cap, entry,
- PTABLE_ACCESS_DEFAULT, 0, 1);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_VNODE_MAP);
+ // PDPT mapping
+ if((*pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
+ err = alloc_vnode(pmap, pdpt, ObjType_VNode_x86_64_pdir,
+ X86_64_PDPT_BASE(base), pdir);
+ if (err_is_fail(err)) {
+ printf("failure mapping pdpt\n");
+ return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
+ }
}
- // The VNode meta data
- newvnode->is_vnode = true;
- newvnode->entry = entry;
- newvnode->next = root->u.vnode.children;
- root->u.vnode.children = newvnode;
- newvnode->u.vnode.children = NULL;
-
- *retvnode = newvnode;
return SYS_ERR_OK;
}
/**
* \brief Returns the vnode for the pagetable mapping a given vspace address
*/
-static errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
- struct vnode **ptable)
+static inline errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
+ struct vnode **ptable)
{
errval_t err;
- struct vnode *root = &pmap->root;
- struct vnode *pdpt, *pdir;
- assert(root != NULL);
-
- // PML4 mapping
- if((pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
- err = alloc_vnode(pmap, root, ObjType_VNode_x86_64_pdpt,
- X86_64_PML4_BASE(base), &pdpt);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
- }
- }
-
- // PDPT mapping
- if((pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
- err = alloc_vnode(pmap, pdpt, ObjType_VNode_x86_64_pdir,
- X86_64_PDPT_BASE(base), &pdir);
- if (err_is_fail(err)) {
- return err_push(err, LIB_ERR_PMAP_ALLOC_VNODE);
- }
+ struct vnode *pdir;
+ err = get_pdir(pmap, base, &pdir);
+ if (err_is_fail(err)) {
+ return err;
}
+ assert(pdir != NULL);
// PDIR mapping
if((*ptable = find_vnode(pdir, X86_64_PDIR_BASE(base))) == NULL) {
return SYS_ERR_OK;
}
-
/**
- * \brief Returns the vnode for the pagetable mapping a given vspace address,
- * without performing allocations as get_ptable() does
+ * \brief Returns the vnode for the page directory pointer table mapping for a
+ * given vspace address
*/
-static struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+static inline struct vnode *find_pdpt(struct pmap_x86 *pmap, genvaddr_t base)
{
struct vnode *root = &pmap->root;
- struct vnode *pdpt, *pdir;
assert(root != NULL);
- // PML4 mapping
- if((pdpt = find_vnode(root, X86_64_PML4_BASE(base))) == NULL) {
+ // PDPT mapping
+ return find_vnode(root, X86_64_PML4_BASE(base));
+}
+
+/**
+ * \brief Returns the vnode for the page directory mapping a given vspace
+ * address, without performing allocations as get_pdir() does
+ */
+static inline struct vnode *find_pdir(struct pmap_x86 *pmap, genvaddr_t base)
+{
+ struct vnode *pdpt = find_pdpt(pmap, base);
+
+ if (pdpt) {
+ // PDPT mapping
+ return find_vnode(pdpt, X86_64_PDPT_BASE(base));
+ } else {
return NULL;
}
+}
- // PDPT mapping
- if((pdir = find_vnode(pdpt, X86_64_PDPT_BASE(base))) == NULL) {
+/**
+ * \brief Returns the vnode for the pagetable mapping a given vspace address,
+ * without performing allocations as get_ptable() does
+ */
+static inline struct vnode *find_ptable(struct pmap_x86 *pmap, genvaddr_t base)
+{
+ struct vnode *pdir = find_pdir(pmap, base);
+
+ if (pdir) {
+ // PDIR mapping
+ return find_vnode(pdir, X86_64_PDIR_BASE(base));
+ } else {
return NULL;
}
-
- // PDIR mapping
- return find_vnode(pdir, X86_64_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,
+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)
{
+ if (pte_count == 0) {
+ debug_printf("do_single_map: pte_count == 0, called from %p\n",
+ __builtin_return_address(0));
+ return SYS_ERR_OK;
+ }
+ assert(pte_count > 0);
// translate flags
paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags);
- // Get the page table
+ // Get the paging structure and set paging relevant parameters
struct vnode *ptable;
- errval_t err = get_ptable(pmap, vaddr, &ptable);
+ errval_t err;
+ size_t table_base;
+
+ // get the right paging table and address part
+ if(flags & VREGION_FLAGS_LARGE) {
+ //large 2M pages, mapped into pdir
+ err = get_pdir(pmap, vaddr, &ptable);
+ table_base = X86_64_PDIR_BASE(vaddr);
+ } else if (flags & VREGION_FLAGS_HUGE) {
+ //huge 1GB pages, mapped into pdpt
+ err = get_pdpt(pmap, vaddr, &ptable);
+ table_base = X86_64_PDPT_BASE(vaddr);
+ } else {
+ //normal 4K pages, mapped into ptable
+ err = get_ptable(pmap, vaddr, &ptable);
+ table_base = X86_64_PTABLE_BASE(vaddr);
+ }
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_GET_PTABLE);
}
+ assert(ptable->is_vnode);
// check if there is an overlapping mapping
- if (has_vnode(ptable, X86_64_PTABLE_BASE(vaddr), pte_count)) {
- printf("page already exists in 0x%"PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
- return LIB_ERR_PMAP_EXISTING_MAPPING;
+ if (has_vnode(ptable, table_base, pte_count, false)) {
+ if (has_vnode(ptable, table_base, pte_count, true)) {
+ printf("page already exists in 0x%"
+ PRIxGENVADDR"--0x%"PRIxGENVADDR"\n", vaddr, vend);
+ return LIB_ERR_PMAP_EXISTING_MAPPING;
+ } else {
+ // clean out empty page tables. We do this here because we benefit
+ // from having the page tables in place when doing lots of small
+ // mappings
+ remove_empty_vnodes(pmap, ptable, table_base, pte_count);
+ }
}
// setup userspace mapping
struct vnode *page = slab_alloc(&pmap->slab);
assert(page);
page->is_vnode = false;
- page->entry = X86_64_PTABLE_BASE(vaddr);
+ page->entry = table_base;
page->next = ptable->u.vnode.children;
ptable->u.vnode.children = page;
page->u.frame.cap = frame;
page->u.frame.pte_count = pte_count;
// do map
- err = vnode_map(ptable->u.vnode.cap, frame, X86_64_PTABLE_BASE(vaddr),
+ err = vnode_map(ptable->u.vnode.cap, frame, table_base,
pmap_flags, offset, pte_count);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VNODE_MAP);
{
errval_t err;
- size = ROUND_UP(size, X86_64_BASE_PAGE_SIZE);
- size_t pte_count = DIVIDE_ROUND_UP(size, X86_64_BASE_PAGE_SIZE);
+ // determine page size and relevant address part
+ size_t page_size = X86_64_BASE_PAGE_SIZE;
+ size_t table_base = X86_64_PTABLE_BASE(vaddr);
+ uint8_t map_bits = X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
+ bool debug_out = false;
+
+ // get base address and size of frame
+ struct frame_identity fi;
+ err = invoke_frame_identify(frame, &fi);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_DO_MAP);
+ }
+
+ if ((flags & VREGION_FLAGS_HUGE) &&
+ (vaddr & X86_64_HUGE_PAGE_MASK) == 0 &&
+ fi.bits >= X86_64_HUGE_PAGE_BITS &&
+ ((fi.base & X86_64_HUGE_PAGE_MASK) == 0))
+ {
+ // huge page branch (1GB)
+ page_size = X86_64_HUGE_PAGE_SIZE;
+ table_base = X86_64_PDPT_BASE(vaddr);
+ map_bits = X86_64_HUGE_PAGE_BITS + X86_64_PTABLE_BITS;
+ debug_out = false;
+ // remove large flag, if we're doing huge mapping
+ flags &= ~VREGION_FLAGS_LARGE;
+ } else if ((flags & VREGION_FLAGS_LARGE) &&
+ (vaddr & X86_64_LARGE_PAGE_MASK) == 0 &&
+ fi.bits >= X86_64_LARGE_PAGE_BITS &&
+ ((fi.base & X86_64_LARGE_PAGE_MASK) == 0))
+ {
+ // large page branch (2MB)
+ page_size = X86_64_LARGE_PAGE_SIZE;
+ table_base = X86_64_PDIR_BASE(vaddr);
+ map_bits = X86_64_LARGE_PAGE_BITS + X86_64_PTABLE_BITS;
+ debug_out = false;
+ } else {
+ // remove large/huge flags
+ flags &= ~(VREGION_FLAGS_LARGE|VREGION_FLAGS_HUGE);
+ }
+
+ // round to the next full page and calculate end address and #ptes
+ size = ROUND_UP(size, page_size);
+ size_t pte_count = DIVIDE_ROUND_UP(size, page_size);
genvaddr_t vend = vaddr + size;
+ if (offset+size > (1ULL<<fi.bits)) {
+ debug_printf("do_map: offset=%zu; size=%zu; frame size=%zu\n",
+ offset, size, ((size_t)1<<fi.bits));
+ return LIB_ERR_PMAP_FRAME_SIZE;
+ }
+
#if 0
- struct frame_identity fi;
- invoke_frame_identify(frame, &fi);
- genpaddr_t paddr = fi.base + offset;
+ if (true || debug_out) {
+ genpaddr_t paddr = fi.base + offset;
- debug_printf("do_map: 0x%"
- PRIxGENVADDR"--0x%"PRIxGENVADDR" -> 0x%"PRIxGENPADDR
- "; pte_count = %zd; frame bits = %zd\n", vaddr, vend, paddr,
- pte_count, (size_t)fi.bits);
+ debug_printf("do_map: 0x%"
+ PRIxGENVADDR"--0x%"PRIxGENVADDR" -> 0x%"PRIxGENPADDR
+ "; pte_count = %zd; frame bits = %zd; page size = 0x%zx\n",
+ vaddr, vend, paddr, pte_count, (size_t)fi.bits, page_size);
+ }
#endif
-
- if (is_same_pdir(vaddr, vend)) {
+ // all mapping on one leaf table?
+ if (is_same_pdir(vaddr, vend) ||
+ (flags & VREGION_FLAGS_LARGE && is_same_pdpt(vaddr, vend)) ||
+ (flags & VREGION_FLAGS_HUGE && is_same_pml4(vaddr, vend))) {
// fast path
- //debug_printf("do_map: fast path: %zd\n", pte_count);
+ if (debug_out) {
+ debug_printf(" do_map: fast path: %zd\n", pte_count);
+ }
err = do_single_map(pmap, vaddr, vend, frame, offset, pte_count, flags);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_DO_MAP);
}
- } else { // multiple leaf page tables
+ }
+ else { // multiple leaf page tables
// first leaf
- uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
- //debug_printf("do_map: slow path: first leaf %"PRIu32"\n", c);
- genvaddr_t temp_end = vaddr + c * X86_64_BASE_PAGE_SIZE;
+ uint32_t c = X86_64_PTABLE_SIZE - table_base;
+ if (debug_out) {
+ debug_printf(" do_map: slow path: first leaf %"PRIu32"\n", c);
+ }
+ genvaddr_t temp_end = vaddr + c * 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_DO_MAP);
}
// map full leaves
- while (get_addr_prefix(temp_end) < get_addr_prefix(vend)) {
+ while (get_addr_prefix(temp_end, map_bits) <
+ get_addr_prefix(vend, map_bits))
+ {
// update vars
vaddr = temp_end;
- temp_end = vaddr + X86_64_PTABLE_SIZE * X86_64_BASE_PAGE_SIZE;
- offset += c * X86_64_BASE_PAGE_SIZE;
+ temp_end = vaddr + X86_64_PTABLE_SIZE * page_size;
+ offset += c * page_size;
c = X86_64_PTABLE_SIZE;
// copy cap
struct capref next;
frame = next;
// do mapping
- //debug_printf("do_map: slow path: full leaf %d\n", X86_64_PTABLE_SIZE);
- err = do_single_map(pmap, vaddr, temp_end, frame, offset, X86_64_PTABLE_SIZE, flags);
+ if (debug_out) {
+ debug_printf(" do_map: slow path: full leaf\n");
+ }
+ err = do_single_map(pmap, vaddr, temp_end, frame, offset,
+ X86_64_PTABLE_SIZE, flags);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_PMAP_DO_MAP);
}
}
// map remaining part
- offset += c * X86_64_BASE_PAGE_SIZE;
- c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(temp_end);
+ offset += c * page_size;
+
+ // calculate remaining pages (subtract ptable bits from map_bits to
+ // get #ptes of last-level instead of 2nd-to-last).
+ c = get_addr_prefix(vend, map_bits-X86_64_PTABLE_BITS) -
+ get_addr_prefix(temp_end, map_bits-X86_64_PTABLE_BITS);
+
if (c) {
// copy cap
struct capref next;
}
// do mapping
- //debug_printf("do_map: slow path: last leaf %"PRIu32"\n", c);
+ if (debug_out) {
+ debug_printf("do_map: slow path: last leaf %"PRIu32"\n", c);
+ }
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);
return max_pages + max_ptable + max_pdir + max_pdpt;
}
+static size_t max_slabs_for_mapping_large(size_t bytes)
+{
+ size_t max_pages = DIVIDE_ROUND_UP(bytes, X86_64_LARGE_PAGE_SIZE);
+ size_t max_pdir = DIVIDE_ROUND_UP(max_pages, X86_64_PTABLE_SIZE);
+ size_t max_pdpt = DIVIDE_ROUND_UP(max_pdir, X86_64_PTABLE_SIZE);
+ return max_pages + max_pdir + max_pdpt;
+}
+
+static size_t max_slabs_for_mapping_huge(size_t bytes)
+{
+ size_t max_pages = DIVIDE_ROUND_UP(bytes, X86_64_HUGE_PAGE_SIZE);
+ size_t max_pdpt = DIVIDE_ROUND_UP(max_pages, X86_64_PTABLE_SIZE);
+ return max_pages + max_pdpt;
+}
+
/**
* \brief Refill slabs used for metadata
*
/* Grow the slab */
lvaddr_t buf = vspace_genvaddr_to_lvaddr(genvaddr);
- slab_grow(&pmap->slab, (void*)buf, bytes);
+ slab_grow(&pmap->slab, (void*)buf, bytes);
}
return SYS_ERR_OK;
errval_t err;
struct pmap_x86 *x86 = (struct pmap_x86*)pmap;
+ struct frame_identity fi;
+ err = invoke_frame_identify(frame, &fi);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_PMAP_FRAME_IDENTIFY);
+ }
+
+ size_t max_slabs;
// Adjust the parameters to page boundaries
- size += BASE_PAGE_OFFSET(offset);
- size = ROUND_UP(size, BASE_PAGE_SIZE);
- offset -= BASE_PAGE_OFFSET(offset);
+ // TODO: overestimating needed slabs shouldn't hurt much in the long run,
+ // and would keep the code easier to read and possibly faster due to less
+ // branching
+ if ((flags & VREGION_FLAGS_LARGE) &&
+ (vaddr & X86_64_LARGE_PAGE_MASK) == 0 &&
+ (fi.base & X86_64_LARGE_PAGE_MASK) == 0 &&
+ (1UL<<fi.bits) >= offset+size) {
+ //case large pages (2MB)
+ size += LARGE_PAGE_OFFSET(offset);
+ size = ROUND_UP(size, LARGE_PAGE_SIZE);
+ offset -= LARGE_PAGE_OFFSET(offset);
+ max_slabs = max_slabs_for_mapping_large(size);
+ } else if ((flags & VREGION_FLAGS_HUGE) &&
+ (vaddr & X86_64_HUGE_PAGE_MASK) == 0 &&
+ (fi.base & X86_64_HUGE_PAGE_MASK) == 0 &&
+ (1UL<<fi.bits) >= offset+size) {
+ // case huge pages (1GB)
+ size += HUGE_PAGE_OFFSET(offset);
+ size = ROUND_UP(size, HUGE_PAGE_SIZE);
+ offset -= HUGE_PAGE_OFFSET(offset);
+ max_slabs = max_slabs_for_mapping_huge(size);
+ } else {
+ //case normal pages (4KB)
+ size += BASE_PAGE_OFFSET(offset);
+ size = ROUND_UP(size, BASE_PAGE_SIZE);
+ offset -= BASE_PAGE_OFFSET(offset);
+ max_slabs = max_slabs_for_mapping(size);
+ }
// Refill slab allocator if necessary
size_t slabs_free = slab_freecount(&x86->slab);
- size_t max_slabs = max_slabs_for_mapping(size);
+
max_slabs += 5; // minimum amount required to map a page
- if (slabs_free < max_slabs) {
+ if (slabs_free < max_slabs) {
struct pmap *mypmap = get_current_pmap();
if (pmap == mypmap) {
err = refill_slabs(x86, max_slabs);
return err;
}
-static errval_t do_single_unmap(struct pmap_x86 *pmap, genvaddr_t vaddr, size_t pte_count, bool delete_cap)
+/**
+ * \brief Find mapping for `vaddr` in `pmap`.
+ * \arg pmap the pmap to search in
+ * \arg vaddr the virtual address to search for
+ * \arg pt the last-level page table meta-data we found if any
+ * \arg page the page meta-data we found if any
+ * \returns `true` iff we found a mapping for vaddr
+ */
+static bool find_mapping(struct pmap_x86 *pmap, genvaddr_t vaddr,
+ struct vnode **outpt, struct vnode **outpage)
{
- errval_t err;
- struct vnode *pt = find_ptable(pmap, vaddr);
- if (pt) {
- struct vnode *page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
- if (page && page->u.frame.pte_count == pte_count) {
- err = vnode_unmap(pt->u.vnode.cap, page->u.frame.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);
+ struct vnode *pdpt = NULL, *pdir = NULL, *pt = NULL, *page = NULL;
+
+ // find page and last-level page table (can be pdir or pdpt)
+ if ((pdpt = find_pdpt(pmap, vaddr)) != NULL) {
+ page = find_vnode(pdpt, X86_64_PDPT_BASE(vaddr));
+ if (page && page->is_vnode) { // not 1G pages
+ pdir = page;
+ page = find_vnode(pdir, X86_64_PDIR_BASE(vaddr));
+ if (page && page->is_vnode) { // not 2M pages
+ pt = page;
+ page = find_vnode(pt, X86_64_PTABLE_BASE(vaddr));
+ } else if (page) {
+ pt = pdir;
}
+ } else if (page) {
+ pt = pdpt;
+ }
+ }
+ if (outpt) {
+ *outpt = pt;
+ }
+ if (outpage) {
+ *outpage = page;
+ }
+ if (pt && page) {
+ return true;
+ } else {
+ return false;
+ }
+}
- // 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);
+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 = NULL, *page = NULL;
+
+ if (!find_mapping(pmap, vaddr, &pt, &page)) {
+ return LIB_ERR_PMAP_FIND_VNODE;
+ }
+ assert(pt && pt->is_vnode && page && !page->is_vnode);
+
+ if (page->u.frame.pte_count == pte_count) {
+ err = vnode_unmap(pt->u.vnode.cap, page->u.frame.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);
}
- else {
- return LIB_ERR_PMAP_FIND_VNODE;
+
+ // Free up the resources
+ if (delete_cap) {
+ err = cap_destroy(page->u.frame.cap);
+ if (err_is_fail(err)) {
+ printf("delete_cap\n");
+ return err_push(err, LIB_ERR_PMAP_DO_SINGLE_UNMAP);
+ }
}
+ remove_vnode(pt, page);
+ slab_free(&pmap->slab, page);
}
return SYS_ERR_OK;
}
+static inline bool is_large_page(struct vnode *p)
+{
+ return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_LARGE;
+}
+static inline bool is_huge_page(struct vnode *p)
+{
+ return !p->is_vnode && p->u.frame.flags & VREGION_FLAGS_HUGE;
+}
+
/**
* \brief Remove page mappings
*
//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_64_BASE_PAGE_SIZE);
+
+ //determine if we unmap a larger page
+ struct vnode* page = NULL;
+
+ if (!find_mapping(x86, vaddr, NULL, &page)) {
+ //TODO: better error --> LIB_ERR_PMAP_NOT_MAPPED
+ return LIB_ERR_PMAP_UNMAP;
+ }
+
+ assert(!page->is_vnode);
+
+ size_t page_size = X86_64_BASE_PAGE_SIZE;
+ size_t table_base = X86_64_PTABLE_BASE(vaddr);
+ uint8_t map_bits= X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
+ if (is_large_page(page)) {
+ //large 2M page
+ page_size = X86_64_LARGE_PAGE_SIZE;
+ table_base = X86_64_PDIR_BASE(vaddr);
+ map_bits = X86_64_LARGE_PAGE_BITS + X86_64_PTABLE_BITS;
+ } else if (is_huge_page(page)) {
+ //huge 1GB page
+ page_size = X86_64_HUGE_PAGE_SIZE;
+ table_base = X86_64_PDPT_BASE(vaddr);
+ map_bits = X86_64_HUGE_PAGE_BITS + X86_64_PTABLE_BITS;
+ }
+
+ // TODO: match new policy of map when implemented
+ size = ROUND_UP(size, page_size);
genvaddr_t vend = vaddr + size;
- if (is_same_pdir(vaddr, vend)) {
+ if (is_same_pdir(vaddr, vend) ||
+ (is_same_pdpt(vaddr, vend) && is_large_page(page)) ||
+ (is_same_pml4(vaddr, vend) && is_huge_page(page)))
+ {
// fast path
- err = do_single_unmap(x86, vaddr, size / X86_64_BASE_PAGE_SIZE, false);
- if (err_is_fail(err)) {
+ err = do_single_unmap(x86, vaddr, size / page_size, false);
+ if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+ printf("error fast path\n");
return err_push(err, LIB_ERR_PMAP_UNMAP);
}
}
else { // slow path
// unmap first leaf
- uint32_t c = X86_64_PTABLE_SIZE - X86_64_PTABLE_BASE(vaddr);
+ uint32_t c = X86_64_PTABLE_SIZE - table_base;
+
err = do_single_unmap(x86, vaddr, c, false);
- if (err_is_fail(err)) {
+ if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+ printf("error first leaf\n");
return err_push(err, LIB_ERR_PMAP_UNMAP);
}
// unmap full leaves
- vaddr += c * X86_64_BASE_PAGE_SIZE;
- while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
+ vaddr += c * page_size;
+ while (get_addr_prefix(vaddr, map_bits) < get_addr_prefix(vend, map_bits)) {
c = X86_64_PTABLE_SIZE;
err = do_single_unmap(x86, vaddr, X86_64_PTABLE_SIZE, true);
- if (err_is_fail(err)) {
+ if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+ printf("error while loop\n");
return err_push(err, LIB_ERR_PMAP_UNMAP);
}
- vaddr += c * X86_64_BASE_PAGE_SIZE;
+ vaddr += c * page_size;
}
// unmap remaining part
- c = X86_64_PTABLE_BASE(vend) - X86_64_PTABLE_BASE(vaddr);
+ // subtracting ptable bits from map_bits to get #ptes in last-level table
+ // instead of 2nd-to-last.
+ c = get_addr_prefix(vend, map_bits-X86_64_PTABLE_BITS) -
+ get_addr_prefix(vaddr, map_bits-X86_64_PTABLE_BITS);
+ assert(c < X86_64_PTABLE_SIZE);
if (c) {
err = do_single_unmap(x86, vaddr, c, true);
- if (err_is_fail(err)) {
+ if (err_is_fail(err) && err_no(err) != LIB_ERR_PMAP_FIND_VNODE) {
+ printf("error remaining part\n");
return err_push(err, LIB_ERR_PMAP_UNMAP);
}
}
// we're modifying part of a valid mapped region
// arguments to invocation: invoke frame cap, first affected
// page (as offset from first page in mapping), #affected
- // pages, new flags. Invocation should check compatibility of
- // new set of flags with cap permissions.
+ // pages, new flags. Invocation mask flags based on capability
+ // access permissions.
size_t off = ptentry - page->entry;
paging_x86_64_flags_t pmap_flags = vregion_to_pmap_flag(flags);
err = invoke_frame_modify_flags(page->u.frame.cap, off, pages, pmap_flags);
// vaddr and vend specify begin and end of the region (inside a mapping)
// that should receive the new set of flags
+ //
+ // TODO: figure out page_size etc of original mapping
+ uint8_t map_bits = X86_64_BASE_PAGE_BITS + X86_64_PTABLE_BITS;
if (is_same_pdir(vaddr, vend)) {
// fast path
// modify full leaves
vaddr += c * X86_64_BASE_PAGE_SIZE;
- while (get_addr_prefix(vaddr) < get_addr_prefix(vend)) {
+ while (get_addr_prefix(vaddr, map_bits) < get_addr_prefix(vend, map_bits)) {
c = X86_64_PTABLE_SIZE;
err = do_single_modify_flags(x86, vaddr, X86_64_PTABLE_SIZE, flags);
if (err_is_fail(err)) {
{
struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
+ uint32_t base = X86_64_PTABLE_BASE(vaddr);
// Find the page table
struct vnode *ptable = find_ptable(x86, vaddr);
if (ptable == NULL) {
- return LIB_ERR_PMAP_FIND_VNODE;
+ //mapped in pdir?
+ ptable = find_pdir(x86, vaddr);
+ if (ptable == NULL) {
+ return LIB_ERR_PMAP_FIND_VNODE;
+ }
+ base = X86_64_PDIR_BASE(vaddr);
}
// Find the page
- struct vnode *vn = find_vnode(ptable, X86_64_PTABLE_BASE(vaddr));
+ struct vnode *vn = find_vnode(ptable, base);
if (vn == NULL) {
return LIB_ERR_PMAP_FIND_VNODE;
}
return SYS_ERR_OK;
}
+
+
static errval_t dump(struct pmap *pmap, struct pmap_dump_info *buf, size_t buflen, size_t *items_written)
{
struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
return SYS_ERR_OK;
}
+static errval_t determine_addr_raw(struct pmap *pmap, size_t size,
+ size_t alignment, genvaddr_t *retvaddr)
+{
+ struct pmap_x86 *x86 = (struct pmap_x86 *)pmap;
+
+ struct vnode *walk_pml4 = x86->root.u.vnode.children;
+ assert(walk_pml4 != NULL); // assume there's always at least one existing entry
+
+ if (alignment == 0) {
+ alignment = BASE_PAGE_SIZE;
+ } else {
+ alignment = ROUND_UP(alignment, BASE_PAGE_SIZE);
+ }
+ size = ROUND_UP(size, alignment);
+ assert(size < 512ul * 1024 * 1024 * 1024); // pml4 size
+
+ // try to find free pml4 entry
+ bool f[512];
+ for (int i = 0; i < 512; i++) {
+ f[i] = true;
+ }
+ //debug_printf("entry: %d\n", walk_pml4->entry);
+ f[walk_pml4->entry] = false;
+ while (walk_pml4) {
+ //debug_printf("looping over pml4 entries\n");
+ assert(walk_pml4->is_vnode);
+ f[walk_pml4->entry] = false;
+ walk_pml4 = walk_pml4->next;
+ }
+ genvaddr_t first_free = 16;
+ for (; first_free < 512; first_free++) {
+ //debug_printf("f[%"PRIuGENVADDR"] = %d\n", first_free, f[first_free]);
+ if (f[first_free]) {
+ break;
+ }
+ }
+ //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
+ if (first_free < 512) {
+ //debug_printf("first_free: %"PRIuGENVADDR"\n", first_free);
+ *retvaddr = first_free << 39;
+ return SYS_ERR_OK;
+ } else {
+ return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
+ }
+}
+
static struct pmap_funcs pmap_funcs = {
.determine_addr = pmap_x86_determine_addr,
+ .determine_addr_raw = determine_addr_raw,
.map = map,
.unmap = unmap,
.lookup = lookup,
// pointer derefs with suitably large offsets
x86->min_mappable_va = 64 * 1024;
- // maximum mappable VA is drived from X86_64_MEMORY_OFFSET in kernel
+ // maximum mappable VA is derived from X86_64_MEMORY_OFFSET in kernel
x86->max_mappable_va = (genvaddr_t)0xffffff8000000000;
return SYS_ERR_OK;
/*
* Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
}
// Return the frame
- *ret_offset = fwalk->offset;
- *ret_frame = fwalk->frame;
+ if (ret_offset) {
+ *ret_offset = fwalk->offset;
+ }
+ if (ret_frame) {
+ *ret_frame = fwalk->frame;
+ }
if (fprev) {
fprev->next = fwalk->next;
} else {
/*
* Copyright (c) 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
#include <barrelfish/vspace_mmu_aware.h>
#include <barrelfish/core_state.h>
+#include <string.h>
/// Minimum free memory before we return it to memory server
#define MIN_MEM_FOR_FREE (1 * 1024 * 1024)
*/
errval_t vspace_mmu_aware_init(struct vspace_mmu_aware *state, size_t size)
{
+ return vspace_mmu_aware_init_aligned(state, size, 0,
+ VREGION_FLAGS_READ_WRITE);
+}
+
+errval_t vspace_mmu_aware_init_aligned(struct vspace_mmu_aware *state,
+ size_t size, size_t alignment, vregion_flags_t flags)
+{
state->size = size;
state->consumed = 0;
+ state->alignment = alignment;
errval_t err;
return err_push(err, LIB_ERR_MEMOBJ_CREATE_ANON);
}
- err = vregion_map(&state->vregion, get_current_vspace(),
- &state->memobj.m, 0, size,
- VREGION_FLAGS_READ_WRITE);
+ err = vregion_map_aligned(&state->vregion, get_current_vspace(),
+ &state->memobj.m, 0, size,
+ flags, alignment);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_VREGION_MAP);
}
} else {
req_size -= state->mapoffset - state->offset;
}
+ size_t alloc_size = req_size;
size_t ret_size = 0;
- if(req_size > 0) {
+ if (req_size > 0) {
+ if ((state->mapoffset & LARGE_PAGE_MASK) == 0 &&
+ state->alignment >= LARGE_PAGE_SIZE)
+ {
+ // this is an opportunity to switch to 2M pages
+ // we know that we can use large pages without jumping through hoops
+ // if state->alignment is at least LARGE_PAGE_SIZE as we always create
+ // the vregion with VREGION_FLAGS_LARGE.
+ alloc_size = ROUND_UP(req_size, LARGE_PAGE_SIZE);
+ }
// Create frame of appropriate size
- err = frame_create(frame, req_size, &ret_size);
+retry:
+ err = frame_create(frame, alloc_size, &ret_size);
if (err_is_fail(err)) {
if (err_no(err) == LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS) {
+ // we can only get 4k frames for now; retry with 4k
+ if (alloc_size > BASE_PAGE_SIZE && origsize < BASE_PAGE_SIZE) {
+ alloc_size = BASE_PAGE_SIZE;
+ goto retry;
+ }
return err_push(err, LIB_ERR_FRAME_CREATE_MS_CONSTRAINTS);
}
return err_push(err, LIB_ERR_FRAME_CREATE);
return SYS_ERR_OK;
}
+errval_t vspace_mmu_aware_reset(struct vspace_mmu_aware *state,
+ struct capref frame, size_t size)
+{
+ errval_t err;
+ struct vregion *vregion;
+ struct capref oldframe;
+ void *vbuf;
+ // create copy of new region
+ err = slot_alloc(&oldframe);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ err = cap_copy(oldframe, frame);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ err = vspace_map_one_frame_attr_aligned(&vbuf, size, oldframe,
+ VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE, LARGE_PAGE_SIZE,
+ NULL, &vregion);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ // copy over data to new frame
+ genvaddr_t gen_base = vregion_get_base_addr(&state->vregion);
+ memcpy(vbuf, (void*)gen_base, state->mapoffset);
+
+ err = vregion_destroy(vregion);
+ if (err_is_fail(err)) {
+ return err;
+ }
+
+ size_t offset = 0;
+ // Unmap backing frames for [0, size) in state.vregion
+ do {
+ err = state->memobj.m.f.unfill(&state->memobj.m, 0, &oldframe,
+ &offset);
+ if (err_is_fail(err) &&
+ err_no(err) != LIB_ERR_MEMOBJ_UNFILL_TOO_HIGH_OFFSET)
+ {
+ return err_push(err, LIB_ERR_MEMOBJ_UNMAP_REGION);
+ }
+ struct frame_identity fi;
+ // increase address
+ err = invoke_frame_identify(oldframe, &fi);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ offset += (1UL<<fi.bits);
+ err = cap_destroy(oldframe);
+ if (err_is_fail(err)) {
+ return err;
+ }
+ } while(offset < state->mapoffset);
+
+ // Map new frame in
+ err = state->memobj.m.f.fill(&state->memobj.m, 0, frame, size);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_MEMOBJ_FILL);
+ }
+ err = state->memobj.m.f.pagefault(&state->memobj.m, &state->vregion, 0, 0);
+ if (err_is_fail(err)) {
+ return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER);
+ }
+
+ state->mapoffset = size;
+ return SYS_ERR_OK;
+}
+
errval_t vspace_mmu_aware_unmap(struct vspace_mmu_aware *state,
lvaddr_t base, size_t bytes)
{
genvaddr_t min_offset = 0;
bool success = false;
- assert(vspace_lvaddr_to_genvaddr(base) > vregion_get_base_addr(&state->vregion));
+ assert(vspace_lvaddr_to_genvaddr(base) >= vregion_get_base_addr(&state->vregion));
assert(base + bytes == (lvaddr_t)eaddr);
- assert(bytes < state->consumed);
- assert(bytes < state->offset);
+ assert(bytes <= state->consumed);
+ assert(bytes <= state->offset);
// Reduce offset
state->offset -= bytes;
/*
* Copyright (c) 2009, 2010, 2011, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <barrelfish/barrelfish.h>
free(memobj);
free(vregion);
}
-
+
*ret_memobj = (struct memobj *)memobj;
*ret_vregion = vregion;
-
+
return err;
}
struct memobj_anon *memobj = NULL;
struct vregion *vregion = NULL;
-
+
// Allocate space
memobj = malloc(sizeof(struct memobj_anon));
assert(memobj != NULL);
free(memobj);
free(vregion);
}
-
+
*ret_memobj = (struct memobj *)memobj;
*ret_vregion = vregion;
-
+
return err;
}
struct memobj **retmemobj,
struct vregion **retvregion)
{
+ return vspace_map_one_frame_attr_aligned(retaddr, size,
+ frame, flags, 0, retmemobj, retvregion);
+}
+
+/**
+ * \brief Wrapper for creating and mapping a memory object
+ * of type one frame with specific flags and a specific alignment
+ */
+errval_t vspace_map_one_frame_attr_aligned(void **retaddr, size_t size,
+ struct capref frame, vregion_flags_t flags,
+ size_t alignment,
+ struct memobj **retmemobj,
+ struct vregion **retvregion)
+{
errval_t err1, err2;
struct memobj *memobj = NULL;
struct vregion *vregion = NULL;
size = ROUND_UP(size, BASE_PAGE_SIZE);
// Allocate space
- memobj = malloc(sizeof(struct memobj_one_frame));
+ memobj = calloc(1, sizeof(struct memobj_one_frame));
if (!memobj) {
err1 = LIB_ERR_MALLOC_FAIL;
goto error;
}
- vregion = malloc(sizeof(struct vregion));
+ vregion = calloc(1, sizeof(struct vregion));
if (!vregion) {
err1 = LIB_ERR_MALLOC_FAIL;
goto error;
goto error;
}
- err1 = vregion_map(vregion, get_current_vspace(), memobj, 0, size, flags);
+ err1 = vregion_map_aligned(vregion, get_current_vspace(), memobj, 0, size,
+ flags, alignment);
if (err_is_fail(err1)) {
err1 = err_push(err1, LIB_ERR_VREGION_MAP);
goto error;
/*
* Copyright (c) 2009, 2010, ETH Zurich.
+ * Copyright (c) 2014, HP Labs.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
// Add to memobj
err = memobj->f.map_region(memobj, vregion);
if (err_is_fail(err)) {
+ // remove memobj from region if map fails, otherwise we'll get a
+ // follow up error if client code call vregion_destroy() on the
+ // region.
+ vregion->memobj = NULL;
return err_push(err, LIB_ERR_MEMOBJ_MAP_REGION);
}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2010, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for bmp_bench
+--
+--------------------------------------------------------------------------
+
+[
+build application { target = "largepage_64_bench",
+ cFiles = [ "largepage_64_bench.c" ],
+ addLibraries = [ "bench"]
+ }
+]
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <barrelfish/nameservice_client.h>
+#include <barrelfish/sys_debug.h>
+#include <bench/bench.h>
+
+#define SAFE_VADDR (genvaddr_t)(8ULL<<39)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+//0b 0000 0000 0000 0000 0000 0100 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+#define SAFE_PMAP_ADDR_L ((genvaddr_t) (12ULL<<39))
+// 40M
+#define DEFAULT_SIZE 30*X86_64_LARGE_PAGE_SIZE
+
+#define LARGE_PAGE_SIZE X86_64_LARGE_PAGE_SIZE
+
+#define RUN_COUNT 50
+
+unsigned long mean4k;
+unsigned long mean2m;
+unsigned long min4k;
+unsigned long min2m;
+unsigned long mean4krand;
+unsigned long mean2mrand;
+unsigned long min4krand;
+unsigned long min2mrand;
+unsigned long max4krand;
+unsigned long max2mrand;
+unsigned long max4k;
+unsigned long max2m;
+
+unsigned long mean4kshort;
+unsigned long mean2mshort;
+unsigned long mean4kshortrand;
+unsigned long mean2mshortrand;
+unsigned long min4kshort;
+unsigned long min2mshort;
+unsigned long min4kshortrand;
+unsigned long min2mshortrand;
+unsigned long max4kshort;
+unsigned long max2mshort;
+unsigned long max4kshortrand;
+unsigned long max2mshortrand;
+/*static paging_x86_64_flags_t PAGE_DEFAULT_ACCESS =
+ PTABLE_USER_SUPERVISOR |
+ PTABLE_EXECUTE_DISABLE |
+ PTABLE_READ_WRITE;
+ */
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+ VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size, bool large, bool area)
+{
+ cycles_t runs[RUN_COUNT];
+ cycles_t start, end;
+ uint64_t mean = 0;
+ unsigned long min = 0;
+ unsigned long max = 0;
+ printf("base address: %lx\n", (uint64_t) buf);
+
+ //sequential access
+ for (int j = 0; j < RUN_COUNT; j++) {
+
+ start = bench_tsc()/1000;
+ for (unsigned long i = 0; i < size; i+=4) {
+
+ buf[i/4] = i;
+ }
+ for (unsigned long i = 0; i < size; i+=4) {
+ assert(buf[i/4] == i);
+ }
+ end = bench_tsc()/1000;
+ runs[j] = end-start;
+ mean += (unsigned int) runs[j];
+ if (runs[j] < min || j == 0) {min = runs[j];}
+ if (runs[j] > max) {max = runs[j];}
+ printf("run: %u, cycles: %u\n", j, (unsigned int) runs[j]);
+ }
+ mean = mean/RUN_COUNT;
+ printf("\naverage cycles to write the whole area: %u\n", (unsigned int) mean);
+ if(!large && !area) {
+ mean4k = mean;
+ min4k = min;
+ max4k = max;
+ }
+ else if (large && !area) {
+ mean2m = mean;
+ min2m = min;
+ max2m = max;
+ }
+ else if (!large && area) {
+ mean4kshort = mean;
+ min4kshort = min;
+ max4kshort = max;
+ } else {
+ mean2mshort = mean;
+ min2mshort = min;
+ max2mshort = max;
+ }
+
+ //random access
+ //generate 1M random number array
+ unsigned int* addrs;
+ min = 0;
+ max = 0;
+ mean = 0;
+ addrs = malloc(2000000*sizeof(unsigned int));
+ printf("malloc'd\n");
+ for (int i = 0; i<2000000; i++)
+ {
+ addrs[i] = (rand() % (size/4));
+ }
+ printf("randomised\n");
+ for (int j = 0; j < RUN_COUNT; j++) {
+
+ start = bench_tsc()/1000;
+ for (int i = 0; i < 2000000; i++) {
+ buf[addrs[i]] = addrs[i];
+ }
+ for (unsigned long i = 0; i < 2000000; i++) {
+ assert(buf[addrs[i]] == addrs[i]);
+ }
+ end = bench_tsc()/1000;
+ runs[j] = end-start;
+ mean += (unsigned int) runs[j];
+ if (runs[j] < min || j == 0) {min = runs[j];}
+ if (runs[j] > max) {max = runs[j];}
+ printf("run: %u, cycles: %u\n", j, (unsigned int) runs[j]);
+ }
+ mean = mean/RUN_COUNT;
+ printf("\naverage cycles to write the whole area randomly: %u\n", (unsigned int) mean);
+ if(!large && !area) {
+ mean4krand = mean;
+ min4krand = min;
+ max4krand = max;
+ }
+ else if (large && !area){
+ mean2mrand = mean;
+ min2mrand = min;
+ max2mrand = max;
+ }else if (!large && area) {
+ mean4kshortrand = mean;
+ min4kshortrand = min;
+ max4kshortrand = max;
+ } else {
+ mean2mshortrand = mean;
+ min2mshortrand = min;
+ max2mshortrand = max;
+ }
+
+}
+
+int main(void)
+{
+ struct capref frame;
+ size_t bytes = DEFAULT_SIZE;
+ errval_t err;
+ mean4k = 0;
+ mean2m = 0;
+ genvaddr_t address;
+
+
+ //normal pages via pmap interface
+ printf("\nstart 4k map with pmap\n");
+ err = frame_alloc(&frame, bytes, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in frame_alloc: %s\n", err_getstring(err));
+ exit(1);
+ }
+ assert(bytes >= DEFAULT_SIZE);
+ printf(" get pmap\n");
+ struct pmap *pmap = get_current_pmap();
+
+ printf(" obtain address\n");
+ err = pmap->f.determine_addr_raw(pmap, bytes, X86_64_BASE_PAGE_SIZE, &address);
+ if (err_is_fail(err))
+ {
+ printf("error in determine_addr_raw: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ printf(" map\n");
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ printf("addr: %lx\n", address);
+ test_region((uint32_t*)address, DEFAULT_SIZE, false, false);
+
+ printf("\tunmap\n");
+ err = pmap->f.unmap(pmap, address, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ //large page via pmap interface
+ printf("start 2m map with pmap\n");
+ bytes = DEFAULT_SIZE;
+ struct capref frame2;
+ err = frame_alloc(&frame2, bytes, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in frame_alloc: %s\n", err_getstring(err));
+ exit(1);
+ }
+ assert(bytes >= DEFAULT_SIZE);
+ pmap = get_current_pmap();
+
+ printf("determine address\n");
+ err = pmap->f.determine_addr_raw(pmap, bytes, X86_64_LARGE_PAGE_SIZE, &address);
+ if (err_is_fail(err))
+ {
+ printf("error in determine_addr_raw: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ printf("map\n");
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ printf("addr: %lx\n", address);
+ test_region((uint32_t*)address, DEFAULT_SIZE, true, false);
+
+ err = pmap->f.unmap(pmap, address, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ //small area 4k
+ bytes = LARGE_PAGE_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in frame_alloc: %s\n", err_getstring(err));
+ exit(1);
+ }
+ assert(bytes >= LARGE_PAGE_SIZE);
+ pmap = get_current_pmap();
+ err = pmap->f.map(pmap, SAFE_PMAP_ADDR, frame, 0, bytes, PMAP_DEFAULT_ACCESS, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap small 4k\n");
+ exit(1);
+ }
+ test_region((uint32_t*) SAFE_PMAP_ADDR, LARGE_PAGE_SIZE, false, true);
+
+ //small area 2m
+ bytes = LARGE_PAGE_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in frame_alloc: %s\n", err_getstring(err));
+ exit(1);
+ }
+ assert(bytes >= LARGE_PAGE_SIZE);
+ pmap = get_current_pmap();
+
+ printf("map\n");
+ err = pmap->f.map(pmap, SAFE_PMAP_ADDR_L, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ printf("addr: %lx\n", SAFE_PMAP_ADDR_L);
+ test_region((uint32_t*)SAFE_PMAP_ADDR_L, LARGE_PAGE_SIZE, true, true);
+
+
+
+ printf("large area\n");
+ printf("average 4k: %lu, average 2m: %lu\n", mean4k, mean2m);
+ printf("minimal 4k: %lu, minimal 2m: %lu\n", min4k, min2m);
+ printf("maximal 4k: %lu, maximal 2m: %lu\n", max4k, max2m);
+ printf("random: average 4k: %lu, average 2m: %lu\n", mean4krand, mean2mrand);
+ printf("random:minimal 4k: %lu, minimal 2m: %lu\n", min4krand, min2mrand);
+ printf("random:maximal 4k: %lu, maximal 2m: %lu\n\n", max4krand, max2mrand);
+ printf("short area\n");
+ printf("average 4k: %lu, average 2m: %lu\n", mean4kshort, mean2mshort);
+ printf("minimal 4k: %lu, minimal 2m: %lu\n", min4kshort, min2mshort);
+ printf("maximal 4k: %lu, maximal 2m: %lu\n", max4kshort, max2mshort);
+ printf("random: average 4k: %lu, average 2m: %lu\n", mean4kshortrand, mean2mshortrand);
+ printf("random:minimal 4k: %lu, minimal 2m: %lu\n", min4kshortrand, min2mshortrand);
+ printf("random:maximal 4k: %lu, maximal 2m: %lu\n", max4kshortrand, max2mshortrand);
+ printf("exited successfully\n");
+ return 0;
+}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, HP Labs.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/tests/argtest
+--
+-- Argument parsing test.
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "argtest", cFiles = [ "argtest.c" ] }
+]
--- /dev/null
+/**
+ * \file
+ * \brief arguments test.
+ */
+
+/*
+ * Copyright (c) 2014, HP Labs.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ for (int i = 0; i < argc; i++) {
+ printf("argv[%d] = %s\n", i, argv[i]);
+ }
+ return 0;
+}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2014, HP Labs.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/tests/large_page
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "test_large_mappings",
+ cFiles = [ "map_test.c" ],
+ architectures = [ "x86_64" ]
+ },
+ build application { target = "test_large_malloc",
+ cFiles = [ "malloc_test.c" ],
+ architectures = [ "x86_64" ]
+ },
+ build application { target = "test_large_mappings",
+ cFiles = [ "map_test_32.c" ],
+ architectures = [ "x86_32" ]
+ }
+
+]
+
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2014, HP Labs.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+// 128MB buffer
+#define BUFSIZE (128UL*1024*1024)
+
+int main(void)
+{
+ void *bufs[RUNS];
+ for (int k = 0; k < RUNS; k++) {
+ // touch every 4k page in region
+ bufs[k] = malloc(BUFSIZE);
+ uint8_t *buf = bufs[k];
+ for (int i = 0; i < BUFSIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ buf[i*BASE_PAGE_SIZE] = i % 256;
+ }
+ // clear out caches
+ sys_debug_flush_cache();
+ int errors = 0;
+ for (int i = 0; i < BUFSIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+ debug_printf("mismatch in page %d: expected %d, was %d\n",
+ i, i % 256, buf[i*BASE_PAGE_SIZE]);
+ errors++;
+ }
+ }
+ debug_printf("test %s\n", errors ? "FAILED" : "PASSED");
+ if (errors) {
+ debug_printf(" %d errors\n", errors);
+ }
+ }
+ for (int k = 0; k < RUNS; k++) {
+ debug_printf("bufs[%d] = %p\n", k, bufs[k]);
+ }
+ debug_dump_hw_ptables();
+ for (int k = 0; k < RUNS; k++) {
+ free(bufs[k]);
+ }
+ return 0;
+}
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2014, HP Labs.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+
+int main(void)
+{
+ errval_t err;
+ struct capref frame;
+ size_t retsize;
+ void *vbuf;
+ struct vregion *vregion;
+ uint8_t *buf;
+ int errors;
+
+ // get frame
+ err = frame_alloc(&frame, X86_64_HUGE_PAGE_SIZE, &retsize);
+ assert(retsize >= X86_64_HUGE_PAGE_SIZE);
+ if (err_is_fail(err)) {
+ debug_printf("frame_alloc: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ for (int k = 0; k < RUNS; k++) {
+ debug_printf("Running 2M/1G test\n");
+ // map with alignment and large flag (don't need memobj)
+ err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+ VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+ X86_64_HUGE_PAGE_SIZE, NULL, &vregion);
+ if (err_is_fail(err)) {
+ debug_printf("vspace_map: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ debug_printf("vaddr: %p\n", vbuf);
+
+ // touch every 4k page in region
+ buf = vbuf;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ buf[i*BASE_PAGE_SIZE] = i % 256;
+ }
+ // clear out caches
+ sys_debug_flush_cache();
+ errors = 0;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+ debug_printf("mismatch in page %d: expected %d, was %d\n",
+ i, i % 256, buf[i*BASE_PAGE_SIZE]);
+ errors++;
+ }
+ }
+ debug_printf("2M/1G test %s\n", errors ? "FAILED" : "PASSED");
+ if (errors) {
+ debug_printf(" %d errors\n", errors);
+ }
+
+ vregion_destroy(vregion);
+ }
+ for (int k = 0; k < RUNS; k++) {
+ debug_printf("Running 2M/2M test\n");
+ // map with large flag
+ err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+ VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+ X86_64_LARGE_PAGE_SIZE, NULL, &vregion);
+ if (err_is_fail(err)) {
+ debug_printf("vspace_map: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ debug_printf("vaddr: %p\n", vbuf);
+
+ // touch every 4k page in region
+ buf = vbuf;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ buf[i*BASE_PAGE_SIZE] = i % 256;
+ }
+ // clear out caches
+ sys_debug_flush_cache();
+ errors = 0;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+ debug_printf("mismatch in page %d: expected %d, was %d\n",
+ i, i % 256, buf[i*BASE_PAGE_SIZE]);
+ errors++;
+ }
+ }
+ debug_printf("2M/2M test %s\n", errors ? "FAILED" : "PASSED");
+ if (errors) {
+ debug_printf(" %d errors\n", errors);
+ }
+
+ vregion_destroy(vregion);
+ }
+
+ uint32_t eax, ebx, ecx, edx;
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if ((edx >> 26) & 1) {
+ debug_printf("Running 1G/1G test\n");
+ err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+ VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_HUGE,
+ X86_64_HUGE_PAGE_SIZE, NULL, &vregion);
+ if (err_is_fail(err)) {
+ debug_printf("vspace_map: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ // touch every 4k page in region
+ buf = vbuf;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ buf[i*BASE_PAGE_SIZE] = i % 256;
+ }
+ // clear out caches
+ sys_debug_flush_cache();
+ errors = 0;
+ for (int i = 0; i < X86_64_HUGE_PAGE_SIZE / X86_64_BASE_PAGE_SIZE; i++) {
+ if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+ debug_printf("mismatch in page %d: expected %d, was %d\n",
+ i, i % 256, buf[i*BASE_PAGE_SIZE]);
+ errors++;
+ }
+ }
+ debug_printf("1G/1G test %s\n", errors ? "FAILED" : "PASSED");
+ if (errors) {
+ debug_printf(" %d errors\n", errors);
+ }
+ }
+ return 0;
+}
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2014, HP Labs.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/sys_debug.h>
+
+#define RUNS 2
+#define PAGE_COUNT 64
+#define TOTAL_SIZE (PAGE_COUNT * LARGE_PAGE_SIZE)
+
+int main(void)
+{
+#if !defined(CONFIG_PSE)
+ debug_printf("PSE not enabled, change Config.hs and rebuild.\n");
+ return 0;
+#endif
+ errval_t err;
+ struct capref frame;
+ size_t retsize;
+ void *vbuf;
+ struct vregion *vregion;
+ uint8_t *buf;
+ int errors;
+
+ // get frame
+ err = frame_alloc(&frame, TOTAL_SIZE, &retsize);
+ assert(retsize >= TOTAL_SIZE);
+ if (err_is_fail(err)) {
+ debug_printf("frame_alloc: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ for (int k = 0; k < RUNS; k++) {
+ debug_printf("Running large page test\n");
+ // map with alignment and huge flag (don't need memobj and vregion)
+ err = vspace_map_one_frame_attr_aligned(&vbuf, retsize, frame,
+ VREGION_FLAGS_READ_WRITE | VREGION_FLAGS_LARGE,
+ TOTAL_SIZE, NULL, &vregion);
+ if (err_is_fail(err)) {
+ debug_printf("vspace_map: %s\n", err_getstring(err));
+ return 1;
+ }
+
+ debug_printf("vaddr: %p\n", vbuf);
+
+ // touch every 4k page in region
+ buf = vbuf;
+ for (int i = 0; i < TOTAL_SIZE / BASE_PAGE_SIZE; i++) {
+ buf[i*BASE_PAGE_SIZE] = i % 256;
+ }
+ // clear out caches
+ sys_debug_flush_cache();
+ errors = 0;
+ for (int i = 0; i < TOTAL_SIZE / BASE_PAGE_SIZE; i++) {
+ if (buf[i*BASE_PAGE_SIZE] != i % 256) {
+ debug_printf("mismatch in page %d: expected %d, was %d\n",
+ i, i % 256, buf[i*BASE_PAGE_SIZE]);
+ errors++;
+ }
+ }
+ debug_printf("large page test %s\n", errors ? "FAILED" : "PASSED");
+ if (errors) {
+ debug_printf(" %d errors\n", errors);
+ }
+
+ vregion_destroy(vregion);
+ }
+
+ return 0;
+}
--------------------------------------------------------------------------
-- Copyright (c) 2007-2009, 2011, ETH Zurich.
+-- Copyright (c) 2014, HP Labs.
-- All rights reserved.
--
-- This file is distributed under the terms in the attached LICENSE file.
},
build application { target = "test_modify_flags",
cFiles = [ "modify_flags.c" ]
+ },
+ build application { target = "test_invalid_mappings",
+ cFiles = [ "invalid_mappings.c" ]
}
]
--- /dev/null
+/**
+ * \file
+ * \brief Test invalid vnode invocations.
+ */
+
+/*
+ * Copyright (c) 2014, HP Labs.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <barrelfish/cap_predicates.h>
+#include <stdio.h>
+
+#define FRAME_ACCESS_DEFAULT \
+ (PTABLE_USER_SUPERVISOR | PTABLE_EXECUTE_DISABLE | PTABLE_READ_WRITE)
+
+static enum objtype types[7] =
+{
+ ObjType_VNode_x86_64_pml4,
+ ObjType_VNode_x86_64_pdpt,
+ ObjType_VNode_x86_64_pdir,
+ ObjType_VNode_x86_64_ptable,
+ ObjType_Frame,
+ ObjType_Frame,
+ ObjType_Frame
+};
+
+static bool mapping_ok[4][7] =
+{ /*pml4*/ /*pdpt*/ /*pdir*/ /*pt*/ /*frm*/ /*2mfrm*/ /*1gfrm*/
+/*pml4*/{ 0, 1, 0, 0, 0, 0, 0 },
+/*pdpt*/{ 0, 0, 1, 0, 0, 0, 1 },
+/*pdir*/{ 0, 0, 0, 1, 0, 1, 1 },
+/*pt */{ 0, 0, 0, 0, 1, 1, 1 },
+};
+
+static int pass = 0, fail = 0;
+static void check_result(errval_t err, int dest, int src)
+{
+ if (err_is_ok(err) && mapping_ok[dest][src]) {
+ printf("%d<-%d PASSED (%s)\n", dest, src, err_getstring(err));
+ pass++;
+ } else if (err_is_fail(err) && !mapping_ok[dest][src]) {
+ printf("%d<-%d PASSED (%s)\n", dest, src, err_getstring(err));
+ pass++;
+ } else {
+ printf("%d<-%d FAILED (expected: %d, was %s)\n",
+ dest, src, mapping_ok[dest][src], err_getstring(err));
+ fail++;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ // outline:
+ // get pml4, pdpt, pdir, ptable, and frame
+ // check all combinations to make sure that restrictions are implemented
+ // correctly in kernel space
+ // VALID:
+ // map pdpt in pml4
+ // map pdir in pdpt
+ // map pt in pdir
+ // map frame in {pt, pdir, pdpt}
+ // INVALID:
+ // all other combinations
+
+ errval_t err;
+ struct capref caps[7];
+
+ // allocate caps
+ for (int i = 0; i < 5; i++) {
+ // get 4k block
+ struct capref mem;
+ err = ram_alloc(&mem, BASE_PAGE_BITS);
+ if (err_is_fail(err)) {
+ printf("ram_alloc: %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+
+ // get slot for retype dest
+ err = slot_alloc(&caps[i]);
+ if (err_is_fail(err)) {
+ printf("slot_alloc: %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+ // retype to selected type
+ err = cap_retype(caps[i], mem, types[i], BASE_PAGE_BITS);
+ if (err_is_fail(err)) {
+ printf("cap_retype: %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+
+ // cleanup source cap
+ printf("delete ram cap\n");
+ err = cap_destroy(mem);
+ if (err_is_fail(err)) {
+ printf("cap_delete(mem): %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+ }
+ // cap 6: 2M frame
+ size_t rb = 0;
+ err = frame_alloc(&caps[5], X86_64_LARGE_PAGE_SIZE, &rb);
+ if (err_is_fail(err) || rb != X86_64_LARGE_PAGE_SIZE) {
+ printf("frame_alloc: %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+ // cap 7: 1G frame
+ err = frame_alloc(&caps[6], X86_64_HUGE_PAGE_SIZE, &rb);
+ if (err_is_fail(err) || rb != X86_64_HUGE_PAGE_SIZE) {
+ printf("frame_alloc: %s (%ld)\n", err_getstring(err), err);
+ return 1;
+ }
+
+ paging_x86_64_flags_t attr = 0;
+ // select dest (ignore frame, asserts)
+ for (int i = 0; i < 4; i++) {
+ // select source
+ for (int j = 0; j < 7; j++) {
+ if (j >= 4) {
+ // frame
+ attr = FRAME_ACCESS_DEFAULT;
+ } else {
+ // ptable
+ attr = PTABLE_ACCESS_DEFAULT;
+ }
+ // try mapping
+ err = vnode_map(caps[i], caps[j], /*slot*/0, attr, /*off*/0, /*count*/1);
+ check_result(err, i, j);
+ // unmap if mapping succeeded
+ if (err_is_ok(err)) {
+ err = vnode_unmap(caps[i], caps[j], /*entry*/0, /*count*/1);
+ assert(err_is_ok(err));
+ }
+ }
+ }
+
+ printf("All tests executed: %d PASSED, %d FAILED\n", pass, fail);
+
+ return 0;
+}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2013, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/vnode_map_test
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "vnode_map_32",
+ cFiles = [ "vnode_map_32.c" ]
+ }
+]
+
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ *
+ * For this to work, Barrelfish needs to be compiled with the
+ * PSE == true configuration enabled in hake/config.hs
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+#include <limits.h>
+
+#define SAFE_VADDR (genvaddr_t)0x320000//(8ULL<<18)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+
+//4M/2M (in PAE)
+#define DEFAULT_SIZE X86_32_LARGE_PAGE_SIZE
+
+
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+ VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size)
+{
+ int j = 0;
+ for (int i = 0; i < size; i+=4) {
+ j+=4;
+ if( (size-j) < 200)
+ {
+ printf("%i, ", i);
+ }
+
+ buf[i/4] = i;
+ }
+ for (int i = 0; i < size; i+=4) {
+ assert(buf[i/4] == i);
+ }
+
+ printf("\n\n");
+}
+
+
+int main(void)
+{
+ struct capref frame, smallframe;
+ size_t bytes = DEFAULT_SIZE;
+ size_t bits = 4*1024;
+ uint32_t address;
+ struct memobj a;
+ errval_t err;
+ printf("\tpagesize: %i, \taddr: %i\n", (int)bytes, (int)SAFE_VADDR);
+
+ //get 4k frame cap
+ err = frame_alloc(&smallframe, bits, &bits);
+ assert(err_is_ok(err));
+ assert(bits >= 4*1024);
+ // get 2M/4M frame cap
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= DEFAULT_SIZE);
+
+//test determine_addr as address obtainer
+#if 1
+ printf("determine_addr 4k\n");
+
+ //determine address
+ a.size = bits;
+ address = 0;
+ struct pmap *pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, BASE_PAGE_SIZE, (genvaddr_t*)&address);
+ printf("address: %x\n", (unsigned int) address);
+ if (err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ err = pmap->f.map(pmap, address, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ test_region((uint32_t*)address, bits);
+
+ err = pmap->f.unmap(pmap, address, bits, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+#endif
+
+
+// test determine_addr_raw for large pages
+// also test unmap on fast path
+#if 1
+ printf("determine_addr 2m\n");
+ bytes = DEFAULT_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= DEFAULT_SIZE);
+
+ a.size = bytes;
+ printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+ address = 0;
+ pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, (genvaddr_t*)&address);
+ printf("address: %lx\n", (uint32_t) address);
+ if(err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+//for loop to test unmap
+for(int i=0; i<10; ++i) {
+printf("map %i\n", i);
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ printf("address: %lx\n", (uint32_t) address);
+ test_region((uint32_t*)address, DEFAULT_SIZE);
+
+ err = pmap->f.unmap(pmap, address, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+}//endfor
+#endif
+
+
+// test determine_addr_raw for multiple large pages
+// also test unmap on slow path
+#if 1
+ printf("determine_addr 2m multiple\n");
+ bytes = 30*DEFAULT_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= 30*DEFAULT_SIZE);
+
+ a.size = bytes;
+ printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+ address = 0;
+ pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, (genvaddr_t*)&address);
+ printf("address: %lx\n", (uint32_t) address);
+ if(err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+//for loop to test unmap
+for(int i=0; i<10; ++i) {
+printf("map %i\n", i);
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ printf("address: %lx\n", (uint32_t) address);
+ test_region((uint32_t*)address, bytes);
+
+ err = pmap->f.unmap(pmap, address, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+}//endfor
+#endif
+ printf("exited successfully\n");
+ return 0;
+}
--- /dev/null
+--------------------------------------------------------------------------
+-- Copyright (c) 2013, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetsstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /usr/vnode_map_test
+--
+--------------------------------------------------------------------------
+
+[ build application { target = "vnode_map_test",
+ cFiles = [ "vnode_map_test.c" ]
+ }
+]
+
--- /dev/null
+/**
+ * \file
+ * \brief Test program for large page code
+ */
+
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#include <barrelfish/barrelfish.h>
+#include <stdio.h>
+
+#define SAFE_VADDR (genvaddr_t)(8ULL<<39)
+#define SAFE_PMAP_ADDR (genvaddr_t)(9ULL<<39)
+// 2M
+#define DEFAULT_SIZE X86_64_LARGE_PAGE_SIZE
+
+static enum objtype type[] = {
+ ObjType_VNode_x86_64_pml4,
+ ObjType_VNode_x86_64_pdpt,
+ ObjType_VNode_x86_64_pdir,
+ ObjType_VNode_x86_64_ptable
+};
+
+// the offsets of the indices for the different page table levels
+static uint8_t offsets[] = { 39, 30, 21, 12 };
+
+static paging_x86_64_flags_t PAGE_DEFAULT_ACCESS =
+ PTABLE_USER_SUPERVISOR |
+ PTABLE_EXECUTE_DISABLE |
+ PTABLE_READ_WRITE;
+
+static vregion_flags_t PMAP_DEFAULT_ACCESS =
+ VREGION_FLAGS_READ_WRITE;
+
+static void test_region(uint32_t *buf, size_t size)
+{
+ int j = 0;
+ for (int i = 0; i < size; i+=4) {
+ j+=4;
+ if( (size-j) < 200)
+ {
+ printf("%i, ", i);
+ }
+
+ buf[i/4] = i;
+ }
+ for (int i = 0; i < size; i+=4) {
+ assert(buf[i/4] == i);
+ }
+ printf("\n\n");
+
+}
+
+
+int main(void)
+{
+ struct capref frame, smallframe, vnodes[4];
+ size_t bytes = DEFAULT_SIZE;
+ size_t bits = 4*1024;
+ errval_t err;
+
+ //get 4k frame cap
+ err = frame_alloc(&smallframe, bits, &bits);
+ assert(err_is_ok(err));
+ assert(bits >= 4*1024);
+ // get 2M frame cap
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= DEFAULT_SIZE);
+
+ // check that we have the necessary ptables (note: this is not how you
+ // should do this cf. with pmap_target.c
+ // setup reference to pml4 capability
+ vnodes[0] = (struct capref) {
+ .cnode = cnode_page,
+ .slot = 0,
+ };
+ // note we start iterating on 1, because we're using index 0 as the
+ // well-known pml4 capref
+ for (int i = 1; i < sizeof(type) / sizeof(type[0]); i++) {
+ err = slot_alloc(&vnodes[i]);
+ assert(err_is_ok(err));
+ printf("creating vnode for level %d, type %d\n", i, type[i]);
+ err = vnode_create(vnodes[i], type[i]);
+ assert(err_is_ok(err));
+ uint32_t slot = (SAFE_VADDR >> offsets[i-1]) & 0x1f;
+ printf("mapping into slot %d on level %d\n", slot, i-1);
+ err = vnode_map(vnodes[i-1], vnodes[i], slot, PTABLE_ACCESS_DEFAULT, 0, 1);
+ if (err_is_fail(err)) {
+ // this means we already have a page table for this level
+ // XXX: right now we've chosen the SAFE_VADDR such that we don't have
+ // any intermediate level page tables so we don't need to worry
+ // about this case
+ printf("there was a page table already?\n");
+ printf("vnode_map: %s\n", err_getstring(err));
+ exit(1);
+ }
+ }
+
+// map as 4k and 2m frames with vnode_map
+// used to test the kernel code
+#if 1
+ //printf("start 4k vnode map");
+ err = vnode_map(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
+ PAGE_DEFAULT_ACCESS, 0, 4*1024 / X86_64_BASE_PAGE_SIZE);
+#endif
+#if 0
+ if (err_is_fail(err)) {
+ printf("error in vnode_map: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ test_region((uint32_t*)SAFE_VADDR, 4*1024);
+
+ // FROM HERE: unmap and try to map as large page
+
+ // unmap frame
+ printf("start 4k unmap\n");
+ err = vnode_unmap(vnodes[3], smallframe, (SAFE_VADDR>>offsets[3])&0x1f,
+ 4*1024 / X86_64_BASE_PAGE_SIZE);
+ if (err_is_fail(err)) {
+ printf("vnode_unmap: %s\n", err_getstring(err));
+ }
+ assert(err_is_ok(err));
+ // unmap level 3 page table
+ err = vnode_unmap(vnodes[2], vnodes[3], SAFE_VADDR>>offsets[2]&0x1f, 1);
+ assert(err_is_ok(err));
+
+ // map as 2M large page
+ printf("start 2m vnodemap\n");
+ err = vnode_map(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f,
+ PAGE_DEFAULT_ACCESS, 0, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
+ if (err_is_fail(err)) {
+ printf("error in vnode_map: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ test_region((uint32_t*)SAFE_VADDR, DEFAULT_SIZE);
+
+ err = vnode_unmap(vnodes[2], frame, SAFE_VADDR>>offsets[2]&0x1f, DEFAULT_SIZE / X86_64_LARGE_PAGE_SIZE);
+ if (err_is_fail(err)) {
+ printf("vnode_unmap: %s\n", err_getstring(err));
+ }
+ assert(err_is_ok(err));
+#endif
+
+ struct pmap *pmap;
+
+//normal page via pmap interface
+// used to test if 4k code still works
+// (although this would break the whole barrelfish boot)
+#if 0
+ printf("\n\nstart 4k map with pmap\n");
+ bits = 4*1024;
+ printf(" frame_alloc\n");
+ err = frame_alloc(&smallframe, bits, &bits);
+ assert(err_is_ok(err));
+ assert(bits >= 4*1024);
+ printf(" get pmap\n");
+ pmap = get_current_pmap();
+
+
+ printf(" map\n");
+ err = pmap->f.map(pmap, SAFE_PMAP_ADDR, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ }
+ test_region((uint32_t*)SAFE_PMAP_ADDR, 4*1024);
+
+ printf("\tunmap\n");
+ err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bits, NULL);
+#endif
+
+
+//large page via pmap interface
+// used to test the 2M pages on a safe address
+// looped 10 times to see if unmap does work
+#if 0
+ printf("start 2m map with pmap\n");
+ bytes = DEFAULT_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= DEFAULT_SIZE);
+
+ pmap = get_current_pmap();
+
+ for(int i = 0; i<10; ++i){
+ printf("map %i\n", i);
+ err = pmap->f.map(pmap, SAFE_PMAP_ADDR, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ test_region((uint32_t*)SAFE_PMAP_ADDR, DEFAULT_SIZE);
+
+ err = pmap->f.unmap(pmap, SAFE_PMAP_ADDR, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ }//end for
+#endif
+
+
+ struct memobj a;
+ genvaddr_t address;
+
+//test determine_addr_raw as address obtainer
+// mapping 4k page
+#if 0
+ printf("determine_addr 4k\n");
+ bits = 4*1024;
+ err = frame_alloc(&smallframe, bits, &bits);
+ assert(err_is_ok(err));
+ assert(bits >= 4*1024);
+
+ //determine address
+ a.size = bits;
+ address = 0;
+ pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, BASE_PAGE_SIZE, &address);
+ printf("address: %lx\n", (unsigned long) address);
+ if (err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ err = pmap->f.map(pmap, address, smallframe, 0, bits, PMAP_DEFAULT_ACCESS, NULL, &bits);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ test_region((uint32_t*)address, 4*1024);
+#endif
+
+
+// determine_addr_raw for 2m pages
+// for loop inserted currently
+// this was the only way multiple large pages could be accessed
+// no longer necessary
+#if 0
+ printf("determine_addr 2m\n");
+ genvaddr_t* addresses = malloc(200*sizeof(genvaddr_t));
+for(int i = 0; i<200; ++i){
+ bytes = DEFAULT_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= DEFAULT_SIZE);
+
+ a.size = bytes;
+ printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+ address = 0;
+ pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
+ printf("address: %x\n", (unsigned int) address);
+ if(err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+ addresses[i] = address;
+}
+for(int i = 0; i<200; ++i){
+ test_region((uint32_t*)addresses[i], DEFAULT_SIZE);
+}
+#endif
+
+
+// multiple large pages with one go
+// the for loop is to test unmap
+#if 1
+ printf("multiple 2m\n");
+ bytes = 10*DEFAULT_SIZE;
+ err = frame_alloc(&frame, bytes, &bytes);
+ assert(err_is_ok(err));
+ assert(bytes >= 10*DEFAULT_SIZE);
+
+ a.size = bytes;
+ printf("a.size: %x, %i\n", (unsigned int) a.size, (unsigned int) a.size);
+ address = 0;
+ pmap = get_current_pmap();
+ err = pmap->f.determine_addr_raw(pmap, a.size, LARGE_PAGE_SIZE, &address);
+ printf("address: %x\n", (unsigned int) address);
+ if(err_is_fail(err))
+ {
+ printf("error in determine_addr: %s\n", err_getstring(err));
+ exit(1);
+ }
+for (int i=0; i<10; ++i) {
+printf("map %i\n", i);
+ err = pmap->f.map(pmap, address, frame, 0, bytes, PMAP_DEFAULT_ACCESS | 0x0100, NULL, &bytes);
+ if (err_is_fail(err))
+ {
+ printf("error in pmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+
+ test_region((uint32_t*)address, 10*DEFAULT_SIZE);
+
+ err = pmap->f.unmap(pmap, address, bytes, NULL);
+ if (err_is_fail(err))
+ {
+ printf("error in unmap: %s\n", err_getstring(err));
+ exit(1);
+ }
+}//endfor
+#endif
+ printf("exited successfully\n");
+ return 0;
+}