summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/arch')
-rw-r--r--src/kernel/arch/generic.h4
-rw-r--r--src/kernel/arch/i386/pagedir.c27
2 files changed, 31 insertions, 0 deletions
diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h
index 0b005a2..6200320 100644
--- a/src/kernel/arch/generic.h
+++ b/src/kernel/arch/generic.h
@@ -24,3 +24,7 @@ struct pagedir *pagedir_new();
void pagedir_map(struct pagedir *dir, void *virt, void *phys,
bool user, bool writeable);
void pagedir_switch(struct pagedir *);
+
+// return 0 on failure
+void *pagedir_virt2phys(struct pagedir *dir, const void *virt,
+ bool user, bool writeable);
diff --git a/src/kernel/arch/i386/pagedir.c b/src/kernel/arch/i386/pagedir.c
index 8ab406d..02361e6 100644
--- a/src/kernel/arch/i386/pagedir.c
+++ b/src/kernel/arch/i386/pagedir.c
@@ -91,3 +91,30 @@ void pagedir_map(struct pagedir *dir, void *virt, void *phys,
void pagedir_switch(struct pagedir *dir) {
asm volatile("mov %0, %%cr3;" : : "r" (dir) : "memory");
}
+
+void *pagedir_virt2phys(struct pagedir *dir, const void *virt,
+ bool user, bool writeable)
+{
+ uintptr_t virt_casted = (uintptr_t) virt;
+ uintptr_t phys;
+ uint32_t pd_idx = virt_casted >> 22;
+ uint32_t pt_idx = virt_casted >> 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 0;
+
+ pagetable = (void*)(dir->e[pd_idx].address << 11);
+ page = pagetable[pt_idx];
+
+ if (!page.present) return 0;
+ if (user && !page.user) return 0;
+ if (writeable && !page.writeable) return 0;
+
+ phys = page.address << 11;
+ phys |= (uintptr_t)virt & 0xFFF;
+ return (void*)phys;
+}