From 0fd9c19c5d66a380ad4b2b881881ce7fba9a6d27 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sat, 21 May 2022 18:26:54 +0200
Subject: syscall/memflag: implement freeing memory

---
 src/kernel/arch/i386/pagedir.c | 50 ++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 19 deletions(-)

(limited to 'src/kernel/arch/i386')

diff --git a/src/kernel/arch/i386/pagedir.c b/src/kernel/arch/i386/pagedir.c
index 00539b7..28608dc 100644
--- a/src/kernel/arch/i386/pagedir.c
+++ b/src/kernel/arch/i386/pagedir.c
@@ -68,6 +68,25 @@ void pagedir_free(struct pagedir *dir) {
 	page_free(dir, 1);
 }
 
+static struct pagetable_entry*
+get_entry(struct pagedir *dir, const void __user *virt) {
+	uint32_t pd_idx = ((uintptr_t)virt) >> 22;
+	uint32_t pt_idx = ((uintptr_t)virt) >> 12 & 0x03FF;
+	struct pagetable_entry *pagetable;
+
+	if (!dir->e[pd_idx].present) return NULL;
+
+	pagetable = (void*)(dir->e[pd_idx].address << 11);
+	return &pagetable[pt_idx];
+}
+
+void *pagedir_unmap(struct pagedir *dir, void __user *virt) {
+	void *phys = pagedir_virt2phys(dir, virt, false, false);
+	struct pagetable_entry *page = get_entry(dir, virt);
+	page->present = false;
+	return phys;
+}
+
 void pagedir_map(struct pagedir *dir, void __user *virt, void *phys,
                  bool user, bool writeable)
 {
@@ -146,29 +165,22 @@ struct pagedir *pagedir_copy(const struct pagedir *orig) {
 	return clone;
 }
 
+bool pagedir_iskern(struct pagedir *dir, const void __user *virt) {
+	struct pagetable_entry *page = get_entry(dir, virt);
+	return page && page->present && !page->user;
+}
+
 void *pagedir_virt2phys(struct pagedir *dir, const void __user *virt,
                         bool user, bool writeable)
 {
-	uintptr_t virt_cast = (uintptr_t) virt;
+	struct pagetable_entry *page;
 	uintptr_t phys;
-	uint32_t pd_idx = virt_cast >> 22;
-	uint32_t pt_idx = virt_cast >> 12 & 0x03FF;
-	struct pagetable_entry *pagetable, page;
-
-	/* DOESN'T CHECK PERMISSIONS ON PAGE DIRS, TODO
-	 * while i don't currently see a reason to set permissions
-	 * directly on page dirs, i might see one in the future.
-	 * leaving this as-is would be a security bug */
-	if (!dir->e[pd_idx].present) return NULL;
-
-	pagetable = (void*)(dir->e[pd_idx].address << 11);
-	page      = pagetable[pt_idx];
-
-	if (!page.present)                return NULL;
-	if (user      && !page.user)      return NULL;
-	if (writeable && !page.writeable) return NULL;
+	page = get_entry(dir, virt);
+	if (!page || !page->present) return NULL;
+	if (user && !page->user) return NULL;
+	if (writeable && !page->writeable) return NULL;
 
-	phys  = page.address << 11;
-	phys |= virt_cast & 0xFFF;
+	phys  = page->address << 11;
+	phys |= ((uintptr_t)virt) & 0xFFF;
 	return (void*)phys;
 }
-- 
cgit v1.2.3