diff --git a/kernel-src/arch/x86-64/kvmclock.c b/kernel-src/arch/x86-64/kvmclock.c index d3f4ac47..4515df86 100644 --- a/kernel-src/arch/x86-64/kvmclock.c +++ b/kernel-src/arch/x86-64/kvmclock.c @@ -56,7 +56,7 @@ static timekeeper_source_info_t *kvm_timer_init(void) { int page_offset = (uintptr_t)virtual_address % PAGE_SIZE; void *virtual_page = (void *)((uintptr_t)virtual_address - page_offset); - void *physical_page = vmm_getphysical(virtual_page, false); + void *physical_page = vmm_getphysical(virtual_page, 0); __assert(physical_page); timekeeper_source_info->private = (void *)((uintptr_t)physical_page + page_offset); diff --git a/kernel-src/include/kernel/vmm.h b/kernel-src/include/kernel/vmm.h index 8d4c7d96..f85a52b1 100644 --- a/kernel-src/include/kernel/vmm.h +++ b/kernel-src/include/kernel/vmm.h @@ -101,7 +101,10 @@ void vmm_unmap(void *addr, size_t size, int flags); bool vmm_pagefault(void *addr, bool user, int actions); vmmcontext_t *vmm_newcontext(); void vmm_switchcontext(vmmcontext_t *ctx); -void *vmm_getphysical(void *addr, bool hold); + +#define VMM_GET_PHYSICAL_FLAGS_HOLD 1 +#define VMM_GET_PHYSICAL_FLAGS_LOCK 2 +void *vmm_getphysical(void *addr, int flags); void vmm_apinit(); void vmm_init(); diff --git a/kernel-src/include/x86-64/arch/mmu.h b/kernel-src/include/x86-64/arch/mmu.h index 7c3bfe37..95479b91 100644 --- a/kernel-src/include/x86-64/arch/mmu.h +++ b/kernel-src/include/x86-64/arch/mmu.h @@ -24,6 +24,8 @@ #define ARCH_MMU_FLAGS_UC (1 << 4) #define ARCH_MMU_FLAGS_WC ((1 << 12) | (1 << 3)) // PAT5 (limine sets up the 5th PAT entry as WC) +#define PAGE_MASK 0xfffffffffffff000lu + #define ARCH_MMU_REQUIRED_FLAGS ARCH_MMU_FLAGS_READ typedef uint64_t mmuflags_t; diff --git a/kernel-src/io/iovec.c b/kernel-src/io/iovec.c index f3acbc9d..1acdaee0 100644 --- a/kernel-src/io/iovec.c +++ b/kernel-src/io/iovec.c @@ -245,7 +245,7 @@ int iovec_iterator_next_page(iovec_iterator_t *iovec_iterator, size_t *page_offs return 0; } - void *phys = vmm_getphysical((void *)((uintptr_t)addr - offset_in_page), true); + void *phys = vmm_getphysical((void *)((uintptr_t)addr - offset_in_page), VMM_GET_PHYSICAL_FLAGS_HOLD | VMM_GET_PHYSICAL_FLAGS_LOCK); if (phys == NULL) return EFAULT; diff --git a/kernel-src/mm/vmm.c b/kernel-src/mm/vmm.c index c3b5230e..7dfdd13a 100644 --- a/kernel-src/mm/vmm.c +++ b/kernel-src/mm/vmm.c @@ -694,7 +694,43 @@ bool vmm_pagefault(void *addr, bool user, int actions) { return status; } -void *vmm_getphysical(void *addr, bool hold) { +/* +static int lock_page(vmmspace_t *space, void *vaddr) { + vmmrange_t *range = getrange(space, vaddr); + if (!range) + return ENOENT; + + void *mapped_address = arch_mmu_getphysical(current_vmm_context()->pagetable, vaddr); + bool present = arch_mmu_ispresent(current_vmm_context()->pagetable, vaddr); + bool writable = arch_mmu_iswritable(current_vmm_context()->pagetable, vaddr); + bool file_mapping = range->flags & VMM_FLAGS_FILE; + bool private = (range->flags & VMM_FLAGS_SHARED) == 0 || file_mapping == false; + void *real_phys; + + // TODO anon with refcount == 1 can go into another cas + // TODO read-only permission checking for DMA + // TODO shared anonymous mappings are not handled properly by the kernel + if (present && writable == false && private)) { + // CoW cases (private mapping) + real_phys = pmm_allocpage(PMM_SECTION_DEFAULT); + if (real_phys == NULL) + return ENOMEM; + + memcpy(MAKE_HHDM(real_phys), MAKE_HHDM(mapped_address), PAGE_SIZE); + + arch_mmu_remap(current_vmm_context()->pagetable, real_phys, vaddr, range->mmuflags); + arch_mmu_invalidate_range(vaddr, PAGE_SIZE); + if (file_mapping == false || vfs_iscacheable(range->vnode)) + pmm_release(mapped_address); + } else if (present == false && private) { + // not present private mapping case + real_phys = pmm_allocpage(PMM_SECTION_DEFAULT); + if (real_phys == NULL) + } +} +*/ + +void *vmm_getphysical(void *addr, int flags) { void *aligned_addr = (void *)ROUND_DOWN((uintptr_t)addr, PAGE_SIZE); vmmspace_t *space = getspace(aligned_addr); @@ -703,11 +739,19 @@ void *vmm_getphysical(void *addr, bool hold) { MUTEX_ACQUIRE(&space->lock); - void *physical = arch_mmu_getphysical(current_vmm_context()->pagetable, aligned_addr); + void *physical; +/* + if ((flags & VMM_GET_PHYSICAL_FLAGS_LOCK) && lock_page(space, aligned_addrr)) { + physical = NULL; + goto leave; + }*/ - if (hold) + physical = arch_mmu_getphysical(current_vmm_context()->pagetable, aligned_addr); + + if (flags & VMM_GET_PHYSICAL_FLAGS_HOLD) pmm_hold(physical); + leave: MUTEX_RELEASE(&space->lock); return physical + ((uintptr_t)addr - (uintptr_t)aligned_addr); } diff --git a/kernel-src/sys/syscalls/futex.c b/kernel-src/sys/syscalls/futex.c index 557654df..4a633b99 100644 --- a/kernel-src/sys/syscalls/futex.c +++ b/kernel-src/sys/syscalls/futex.c @@ -72,7 +72,7 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value if (unlikely(ret.errno)) goto cleanup; - uint32_t *physical = vmm_getphysical(futexp, false); + uint32_t *physical = vmm_getphysical(futexp, 0); futex_t *futex = getfutex(physical); switch (op) {