Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 16 additions & 23 deletions arch/x86-family/mm/address_space.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@



static x86_page_t __mm_copy_data(x86_page_t* __s, size_t* size, bool on_demand, int level) {
static x86_page_t __mm_copy_data(x86_page_t* __s, size_t* size, int level) {

DEBUG_ASSERT(__s);
DEBUG_ASSERT(size);
Expand Down Expand Up @@ -71,22 +71,12 @@ static x86_page_t __mm_copy_data(x86_page_t* __s, size_t* size, bool on_demand,
*size += pagesize;


#if defined(CONFIG_DEMAND_PAGING)
if (on_demand) {
uintptr_t page = __alloc_frame(pagesize, false);

return (*__s = (*__s & ~(X86_MMU_PG_RW | X86_MMU_PG_AP_TP_MASK)) | X86_MMU_PG_AP_TP_COW);
memcpy((void*)arch_vmm_p2v(page, ARCH_VMM_AREA_HEAP), (void*)arch_vmm_p2v(*__s & X86_MMU_ADDRESS_MASK, ARCH_VMM_AREA_HEAP), (size_t)pagesize);

} else
#endif
{

uintptr_t page = __alloc_frame(pagesize, false);

memcpy((void*)arch_vmm_p2v(page, ARCH_VMM_AREA_HEAP), (void*)arch_vmm_p2v(*__s & X86_MMU_ADDRESS_MASK, ARCH_VMM_AREA_HEAP), (size_t)pagesize);


return page | X86_MMU_PG_AP_PFB | (*__s & ~X86_MMU_ADDRESS_MASK);
}
return page | X86_MMU_PG_AP_PFB | (*__s & ~X86_MMU_ADDRESS_MASK);
}


Expand All @@ -107,13 +97,13 @@ static void __mm_copy_page(x86_page_t* __s, x86_page_t* __d, size_t* size, int l
if (flags & ARCH_VMM_CLONE_USERSPACE) {


if ((*__s & X86_MMU_PG_AP_TP_MASK) == X86_MMU_PG_AP_TP_COW) {
if (((*__s & X86_MMU_PG_AP_TP_MASK) == X86_MMU_PG_AP_TP_COW) && ((*__s & X86_MMU_ADDRESS_MASK) == 0)) {

*__d = *__s;

} else {

*__d = __mm_copy_data(__s, size, (flags & ARCH_VMM_CLONE_DEMAND), level);
*__d = __mm_copy_data(__s, size, level);
}
}
}
Expand Down Expand Up @@ -231,10 +221,9 @@ static void __mm_free_table(uintptr_t __s, int level) {

__mm_free_table(((uintptr_t)s[i]) & X86_MMU_ADDRESS_MASK, level - 1);

// FIXME: not safe to free frame here, as it may be used by system page tables
// // if(s[i] & X86_MMU_PT_AP_PFB) {
// // __free_frame(((uintptr_t) s[i]) & X86_MMU_ADDRESS_MASK, X86_MMU_PAGESIZE);
// // }
if (s[i] & X86_MMU_PT_AP_PFB) {
__free_frame(((uintptr_t)s[i]) & X86_MMU_ADDRESS_MASK, X86_MMU_PAGESIZE);
}
}
}
}
Expand All @@ -253,6 +242,7 @@ __returns_nonnull vmm_address_space_t* arch_vmm_create_address_space(vmm_address


dest->pm = __alloc_frame(X86_MMU_PAGESIZE, true);
dest->flags = ARCH_VMM_ADDRESS_SPACE_OWNED;



Expand Down Expand Up @@ -305,7 +295,9 @@ void arch_vmm_free_address_space(vmm_address_space_t* space) {
}


// TODO: free all mappings
if (!(space->flags & ARCH_VMM_ADDRESS_SPACE_OWNED)) {
return;
}

#if defined(__x86_64__)
scoped_lock(&space->lock) {
Expand All @@ -320,11 +312,12 @@ void arch_vmm_free_address_space(vmm_address_space_t* space) {
#endif


// FIXME: maybe unsafe
//__free_frame(space->pm, X86_MMU_PAGESIZE);
__free_frame(space->pm, X86_MMU_PAGESIZE);

space->pm = 0UL;
space->size = 0UL;
space->mmap.heap_start = 0UL;
space->mmap.heap_end = 0UL;

kfree(space);
}
7 changes: 6 additions & 1 deletion arch/x86-family/mm/getphysaddr.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
__nonnull(1) uintptr_t arch_vmm_getphysaddr(vmm_address_space_t* space, uintptr_t virtaddr) {


retry:

uintptr_t pagesize = X86_MMU_PAGESIZE;


Expand Down Expand Up @@ -125,8 +127,11 @@ __nonnull(1) uintptr_t arch_vmm_getphysaddr(vmm_address_space_t* space, uintptr_
DEBUG_ASSERT((*d != X86_MMU_CLEAR) && "Page unmapped");


if (unlikely((*d & X86_MMU_PG_AP_TP_MASK) != X86_MMU_PG_AP_TP_PAGE))
if (unlikely((*d & X86_MMU_PG_AP_TP_MASK) != X86_MMU_PG_AP_TP_PAGE)) {
spinlock_unlock(&space->lock);
PANIC_ASSERT(pagefault_handle(current_cpu->frame, virtaddr) == 0);
goto retry;
}


DEBUG_ASSERT(((*d & X86_MMU_PG_AP_TP_MASK) == X86_MMU_PG_AP_TP_PAGE) && "Page bad type");
Expand Down
35 changes: 28 additions & 7 deletions arch/x86-family/mm/pagefault.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@

__nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {

bool locked = false;
vmm_address_space_t* space = NULL;

#if DEBUG_LEVEL_TRACE

Expand All @@ -63,6 +65,12 @@ __nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {
if (unlikely(!pm))
PFE("no memory mapping", 0L);

if (current_task && current_task->address_space && current_task->address_space->pm == pm) {
space = current_task->address_space;
spinlock_lock(&space->lock);
locked = true;
}


uintptr_t pagesize = X86_MMU_PAGESIZE;
uintptr_t s = cr2;
Expand Down Expand Up @@ -120,7 +128,7 @@ __nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {
#elif defined(__i386__)

/* CR3-L2 */
{ d = &((x86_page_t*)arch_vmm_p2v(space->pm, ARCH_VMM_AREA_HEAP))[(s >> 22) & 0x3FF]; }
{ d = &((x86_page_t*)arch_vmm_p2v(pm, ARCH_VMM_AREA_HEAP))[(s >> 22) & 0x3FF]; }


/* HUGE_4MB */
Expand All @@ -129,7 +137,7 @@ __nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {
/* PD-L1 */
{
if (*d == X86_MMU_CLEAR)
PFE("PD-L1 doesn't not exist");
PFE("PD-L1 doesn't not exist", *d);

d = &((x86_page_t*)arch_vmm_p2v(*d & X86_MMU_ADDRESS_MASK, ARCH_VMM_AREA_HEAP))[(s >> 12) & 0x3FF];
}
Expand All @@ -153,21 +161,30 @@ __nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {

//! Handle Copy on Write

uintptr_t page = __alloc_frame(pagesize, false);
uintptr_t old = *d;
uintptr_t page = __alloc_frame(pagesize, (old & X86_MMU_ADDRESS_MASK) == 0);

if ((*d & X86_MMU_ADDRESS_MASK) != 0) {
if ((old & X86_MMU_ADDRESS_MASK) != 0) {

memcpy((void*)arch_vmm_p2v(page, ARCH_VMM_AREA_HEAP), (void*)arch_vmm_p2v(*d & X86_MMU_ADDRESS_MASK, ARCH_VMM_AREA_HEAP), (size_t)pagesize);
memcpy((void*)arch_vmm_p2v(page, ARCH_VMM_AREA_HEAP), (void*)arch_vmm_p2v(old & X86_MMU_ADDRESS_MASK, ARCH_VMM_AREA_HEAP), (size_t)pagesize);

page |= X86_MMU_PG_RW;
}

*d = page | X86_MMU_PG_P | X86_MMU_PG_AP_PFB | X86_MMU_PG_AP_TP_PAGE | ((*d & ~X86_MMU_ADDRESS_MASK) & ~(X86_MMU_PG_AP_TP_MASK));
*d = page | X86_MMU_PG_P | X86_MMU_PG_AP_PFB | X86_MMU_PG_AP_TP_PAGE | ((old & ~X86_MMU_ADDRESS_MASK) & ~(X86_MMU_PG_AP_TP_MASK));
}
}

__asm__ __volatile__("invlpg (%0)" ::"r"(cr2) : "memory");

if (locked) {
spinlock_unlock(&space->lock);
}


current_task->rusage.ru_majflt++;
if (current_task) {
current_task->rusage.ru_majflt++;
}


#if DEBUG_LEVEL_TRACE
Expand All @@ -180,6 +197,10 @@ __nonnull(1) int pagefault_handle(interrupt_frame_t* frame, uintptr_t cr2) {

pfe:

if (locked) {
spinlock_unlock(&space->lock);
}

if (x86_intr_is_user_mode(frame))
return -1;

Expand Down
5 changes: 5 additions & 0 deletions arch/x86-family/mm/vm_access.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ __nonnull(1) int arch_vmm_access(vmm_address_space_t* space, uintptr_t virtaddr,

/* Page Table */
{
check_or_fail(*d != X86_MMU_CLEAR);

if (!(mode & S_OK) && current_cpu->frame && x86_intr_is_user_mode(current_cpu->frame)) {
check_or_fail(*d & X86_MMU_PG_U);
}

if (mode & R_OK) {
if (!(*d & X86_MMU_PG_P)) {
Expand Down
2 changes: 1 addition & 1 deletion arch/x86-family/mm/vm_lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ __nonnull(1) void arch_vmm_lock(vmm_address_space_t* space, uintptr_t virtaddr,

#if defined(CONFIG_X86_ENABLE_SMAP)
if (cpu_has(current_cpu->id, X86_FEATURE_SMAP))
x86_set_cr4(x86_get_cr4() & ~(X86_CR4_SMAP_MASK));
x86_stac();
#endif
}
2 changes: 1 addition & 1 deletion arch/x86-family/mm/vm_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ __nonnull(1) uintptr_t arch_vmm_map(vmm_address_space_t* space, uintptr_t virtad
if (flags & ARCH_VMM_MAP_DEMAND)
*d = X86_MMU_PG_AP_TP_COW | (b & ~X86_MMU_PG_P);
else
*d = __alloc_frame(pagesize, false) | X86_MMU_PG_AP_PFB | b;
*d = __alloc_frame(pagesize, true) | X86_MMU_PG_AP_PFB | b;
}
}

Expand Down
29 changes: 16 additions & 13 deletions arch/x86-family/mm/vm_protect.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,23 @@ __nonnull(1) uintptr_t arch_vmm_mprotect(vmm_address_space_t* space, uintptr_t v



uint64_t b = X86_MMU_PG_P;
uint64_t base = X86_MMU_PG_P;


if (flags & ARCH_VMM_MAP_DISABLED)
b &= ~X86_MMU_PG_P;
base &= ~X86_MMU_PG_P;

if (flags & ARCH_VMM_MAP_RDWR)
b |= X86_MMU_PG_RW;
base |= X86_MMU_PG_RW;

if (flags & ARCH_VMM_MAP_USER)
b |= X86_MMU_PG_U;
base |= X86_MMU_PG_U;

if (flags & ARCH_VMM_MAP_UNCACHED)
b |= X86_MMU_PG_CD;
base |= X86_MMU_PG_CD;

if (flags & ARCH_VMM_MAP_SHARED)
b |= X86_MMU_PG_G;
base |= X86_MMU_PG_G;



Expand All @@ -106,23 +106,23 @@ __nonnull(1) uintptr_t arch_vmm_mprotect(vmm_address_space_t* space, uintptr_t v
//* Set No-Execute Bit
if (flags & ARCH_VMM_MAP_NOEXEC)
if (boot_cpu_has(X86_FEATURE_NX))
b |= X86_MMU_PT_NX; /* NX */
base |= X86_MMU_PT_NX; /* NX */

#endif

if (flags & ARCH_VMM_MAP_HUGETLB) {

b |= X86_MMU_PG_PS;
base |= X86_MMU_PG_PS;

if (flags & ARCH_VMM_MAP_VIDEO_MEMORY)
if (boot_cpu_has(X86_FEATURE_PAT))
b |= X86_MMU_PG_PAT; /* WC */
base |= X86_MMU_PG_PAT; /* WC */

} else {

if (flags & ARCH_VMM_MAP_VIDEO_MEMORY)
if (boot_cpu_has(X86_FEATURE_PAT))
b |= X86_MMU_PT_PAT; /* WC */
base |= X86_MMU_PT_PAT; /* WC */
}


Expand Down Expand Up @@ -203,10 +203,13 @@ __nonnull(1) uintptr_t arch_vmm_mprotect(vmm_address_space_t* space, uintptr_t v
DEBUG_ASSERT((*d != X86_MMU_CLEAR) && "Page unmapped");


if (!(*d & X86_MMU_PG_P))
b &= ~X86_MMU_PG_P;
x86_page_t old = *d;
uint64_t page_flags = base;

*d = (*d & X86_MMU_ADDRESS_MASK) | (*d & X86_MMU_PG_AP_TP_MASK) | b;
if (!(flags & ARCH_VMM_MAP_DISABLED) && !(old & X86_MMU_PG_P) && ((old & X86_MMU_PG_AP_TP_MASK) == X86_MMU_PG_AP_TP_COW))
page_flags &= ~X86_MMU_PG_P;

*d = (old & X86_MMU_ADDRESS_MASK) | (old & (X86_MMU_PG_AP_TP_MASK | X86_MMU_PG_AP_PFB)) | page_flags;



Expand Down
2 changes: 1 addition & 1 deletion arch/x86-family/mm/vm_unlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ __nonnull(1) void arch_vmm_unlock(vmm_address_space_t* space, uintptr_t virtaddr

#if defined(CONFIG_X86_ENABLE_SMAP)
if (cpu_has(current_cpu->id, X86_FEATURE_SMAP))
x86_set_cr4(x86_get_cr4() | X86_CR4_SMAP_MASK);
x86_clac();
#endif
}
2 changes: 1 addition & 1 deletion arch/x86-family/mm/vm_unmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ __nonnull(1) uintptr_t arch_vmm_unmap(vmm_address_space_t* space, uintptr_t virt
}


__asm__ __volatile__("invlpg (%0)" ::"r"(virtaddr) : "memory");
__asm__ __volatile__("invlpg (%0)" ::"r"(s) : "memory");

space->size -= pagesize >> 12;
}
Expand Down
3 changes: 3 additions & 0 deletions include/aplus/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@

#define ARCH_VMM_CLONE_NEW_SPACE (0)

#define ARCH_VMM_ADDRESS_SPACE_OWNED (1 << 0)



typedef struct {
Expand All @@ -107,6 +109,7 @@ typedef struct vmm_address_space {
uintptr_t pm;
size_t size;
size_t refcount;
uint32_t flags;

struct {

Expand Down
8 changes: 8 additions & 0 deletions include/arch/x86/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,14 @@ static inline void x86_swapgs() {
__asm__ __volatile__("swapgs");
}

static inline void x86_stac() {
__asm__ __volatile__("stac" ::: "memory");
}

static inline void x86_clac() {
__asm__ __volatile__("clac" ::: "memory");
}


/*!
* @brief Write to Extended Control Register.
Expand Down
2 changes: 1 addition & 1 deletion include/arch/x86/vmm.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@

#if defined(__x86_64__)
typedef uint64_t x86_page_t;
#elif
#elif defined(__i386__)
typedef uint32_t x86_page_t;
#endif

Expand Down
Loading