|
|
|
@ -27,6 +27,7 @@
|
|
|
|
|
#include <gay/util.h>
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
|
|
|
|
|
/* from linker script */
|
|
|
|
|
extern void _image_start_phys;
|
|
|
|
@ -38,7 +39,7 @@ extern void _image_end_phys;
|
|
|
|
|
*/
|
|
|
|
|
static unsigned long *pagemap;
|
|
|
|
|
/** @brief Pagemap length as in number of `unsigned long`s, *not* bytes! */
|
|
|
|
|
static size_t pagemap_len;
|
|
|
|
|
static usize pagemap_len;
|
|
|
|
|
|
|
|
|
|
/* first and last dynamic page address (watch out, these are physical) */
|
|
|
|
|
static uintptr_t dynpage_start;
|
|
|
|
@ -66,8 +67,8 @@ int mem_init(uintptr_t start_phys, uintptr_t end_phys)
|
|
|
|
|
if ((uintptr_t)&_image_start_phys >= start_phys && (uintptr_t)&_image_start_phys <= end_phys)
|
|
|
|
|
start_phys = (uintptr_t)&_image_end_phys;
|
|
|
|
|
|
|
|
|
|
dynpage_start = (uintptr_t)ptr_align((void *)start_phys, PAGE_SIZE_LOG2);
|
|
|
|
|
dynpage_end = (uintptr_t)ptr_align((void *)end_phys, -PAGE_SIZE_LOG2);
|
|
|
|
|
dynpage_start = (uintptr_t)ptr_align((void *)start_phys, PAGE_SHIFT);
|
|
|
|
|
dynpage_end = (uintptr_t)ptr_align((void *)end_phys, -PAGE_SHIFT);
|
|
|
|
|
|
|
|
|
|
if (dynpage_end - dynpage_start < 1024 * PAGE_SIZE) {
|
|
|
|
|
kprintf("We have < 1024 pages for kmalloc(), this wouldn't go well\n");
|
|
|
|
@ -85,7 +86,8 @@ int mem_init(uintptr_t start_phys, uintptr_t end_phys)
|
|
|
|
|
setup_pagemap();
|
|
|
|
|
|
|
|
|
|
kprintf("Available memory: %zu bytes (%lu pages)\n",
|
|
|
|
|
dynpage_end - dynpage_start, (dynpage_end - dynpage_start) / PAGE_SIZE);
|
|
|
|
|
dynpage_end - dynpage_start,
|
|
|
|
|
(unsigned long)(dynpage_end - dynpage_start) / PAGE_SIZE);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -99,16 +101,16 @@ int map_page(uintptr_t phys, void *virt, enum mm_page_flags flags)
|
|
|
|
|
kprintf("map_page(): unaligned virtual address %p!\n", virt);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
size_t pd_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) / 1024;
|
|
|
|
|
size_t pt_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) % 1024;
|
|
|
|
|
usize pd_index = ((uintptr_t)virt >> PAGE_SHIFT) / 1024;
|
|
|
|
|
usize pt_index = ((uintptr_t)virt >> PAGE_SHIFT) % 1024;
|
|
|
|
|
|
|
|
|
|
struct x86_page_directory *pd = (struct x86_page_directory *)0xfffff000;
|
|
|
|
|
struct x86_page_directory *pd = X86_CURRENT_PD;
|
|
|
|
|
/*
|
|
|
|
|
* warning: pt might not be present yet before the if block below,
|
|
|
|
|
* we only define it here already so we can easily call memset() in
|
|
|
|
|
* the if block
|
|
|
|
|
*/
|
|
|
|
|
struct x86_page_table *pt = &((struct x86_page_table *)0xffc00000)[pd_index];
|
|
|
|
|
struct x86_page_table *pt = &X86_CURRENT_PT_BASE[pd_index];
|
|
|
|
|
|
|
|
|
|
struct x86_page_directory_entry *pd_entry = &pd->entries[pd_index];
|
|
|
|
|
if (!pd_entry->present) {
|
|
|
|
@ -117,7 +119,7 @@ int map_page(uintptr_t phys, void *virt, enum mm_page_flags flags)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
*(unsigned long *)pd_entry = 0;
|
|
|
|
|
pd_entry->shifted_address = pt_phys >> X86_PAGE_DIRECTORY_ADDRESS_SHIFT;
|
|
|
|
|
pd_entry->shifted_address = pt_phys >> PAGE_SHIFT;
|
|
|
|
|
pd_entry->rw = 1;
|
|
|
|
|
pd_entry->present = 1;
|
|
|
|
|
vm_flush();
|
|
|
|
@ -129,7 +131,7 @@ int map_page(uintptr_t phys, void *virt, enum mm_page_flags flags)
|
|
|
|
|
pt_entry->rw = (flags & MM_PAGE_RW) != 0;
|
|
|
|
|
pt_entry->user = (flags & MM_PAGE_USER) != 0;
|
|
|
|
|
pt_entry->cache_disabled = (flags & MM_PAGE_NOCACHE) != 0;
|
|
|
|
|
pt_entry->shifted_address = phys >> X86_PAGE_TABLE_ADDRESS_SHIFT;
|
|
|
|
|
pt_entry->shifted_address = phys >> PAGE_SHIFT;
|
|
|
|
|
pt_entry->present = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@ -142,16 +144,16 @@ uintptr_t unmap_page(void *virt)
|
|
|
|
|
kprintf("map_page(): unaligned virtual address %p!\n", virt);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
struct x86_page_directory *pd = (struct x86_page_directory *)0xfffff000;
|
|
|
|
|
struct x86_page_directory *pd = X86_CURRENT_PD;
|
|
|
|
|
|
|
|
|
|
size_t pd_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) / 1024;
|
|
|
|
|
size_t pt_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) % 1024;
|
|
|
|
|
usize pd_index = ((uintptr_t)virt >> PAGE_SHIFT) / 1024;
|
|
|
|
|
usize pt_index = ((uintptr_t)virt >> PAGE_SHIFT) % 1024;
|
|
|
|
|
|
|
|
|
|
struct x86_page_directory_entry *pd_entry = &pd->entries[pd_index];
|
|
|
|
|
if (!pd_entry->present)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
struct x86_page_table *pt = &((struct x86_page_table *)0xffc00000)[pd_index];
|
|
|
|
|
struct x86_page_table *pt = &X86_CURRENT_PT_BASE[pd_index];
|
|
|
|
|
struct x86_page_table_entry *pt_entry = &pt->entries[pt_index];
|
|
|
|
|
if (!pt_entry->present)
|
|
|
|
|
return 0;
|
|
|
|
@ -159,28 +161,16 @@ uintptr_t unmap_page(void *virt)
|
|
|
|
|
uintptr_t phys_shifted = pt_entry->shifted_address;
|
|
|
|
|
*(unsigned long *)pt_entry = 0;
|
|
|
|
|
|
|
|
|
|
return phys_shifted << X86_PAGE_TABLE_ADDRESS_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline int find_zero_bit(unsigned long bitfield)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(bitfield) * 8; i++) {
|
|
|
|
|
if ((bitfield & (1lu << i)) == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return i;
|
|
|
|
|
return phys_shifted << PAGE_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uintptr_t get_page(void)
|
|
|
|
|
{
|
|
|
|
|
uintptr_t page = 0;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < pagemap_len; i++) {
|
|
|
|
|
for (usize i = 0; i < pagemap_len; i++) {
|
|
|
|
|
if (~pagemap[i] != 0) {
|
|
|
|
|
int bit = find_zero_bit(pagemap[i]);
|
|
|
|
|
int bit = ffsl((long)~pagemap[i]);
|
|
|
|
|
if (bit < sizeof(*pagemap) * 8) {
|
|
|
|
|
unsigned long page_number = i * sizeof(*pagemap) * 8 + bit;
|
|
|
|
|
page = dynpage_start + page_number * PAGE_SIZE;
|
|
|
|
@ -210,8 +200,8 @@ void put_page(uintptr_t phys)
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
size_t page_number = (phys - dynpage_start) >> PAGE_SIZE_LOG2;
|
|
|
|
|
size_t index = page_number / (sizeof(*pagemap) * 8);
|
|
|
|
|
usize page_number = (phys - dynpage_start) >> PAGE_SHIFT;
|
|
|
|
|
usize index = page_number / (sizeof(*pagemap) * 8);
|
|
|
|
|
int bit = page_number % (sizeof(*pagemap) * 8);
|
|
|
|
|
if ((pagemap[index] & (1lu << bit)) == 0)
|
|
|
|
|
kprintf("Double free of page %p!\n", (void *)phys);
|
|
|
|
@ -261,18 +251,18 @@ void x86_isr_page_fault(struct x86_trap_frame *frame, u32 error_code)
|
|
|
|
|
|
|
|
|
|
uintptr_t virt_to_phys(void *virt)
|
|
|
|
|
{
|
|
|
|
|
size_t pd_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) / 1024;
|
|
|
|
|
size_t pt_index = ((uintptr_t)virt >> PAGE_SIZE_LOG2) % 1024;
|
|
|
|
|
usize pd_index = ((uintptr_t)virt >> PAGE_SHIFT) / 1024;
|
|
|
|
|
usize pt_index = ((uintptr_t)virt >> PAGE_SHIFT) % 1024;
|
|
|
|
|
|
|
|
|
|
struct x86_page_directory *pd = (struct x86_page_directory *)0xfffff000;
|
|
|
|
|
struct x86_page_directory *pd = X86_CURRENT_PD;
|
|
|
|
|
if (!pd->entries[pd_index].present)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
struct x86_page_table *pt = &((struct x86_page_table *)0xffc00000)[pd_index];
|
|
|
|
|
struct x86_page_table *pt = &X86_CURRENT_PT_BASE[pd_index];
|
|
|
|
|
if (!pt->entries[pt_index].present)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
uintptr_t phys = pt->entries[pt_index].shifted_address << X86_PAGE_TABLE_ADDRESS_SHIFT;
|
|
|
|
|
uintptr_t phys = pt->entries[pt_index].shifted_address << PAGE_SHIFT;
|
|
|
|
|
/* if the virtual address wasn't page aligned, add the offset into the page */
|
|
|
|
|
return phys | ((uintptr_t)virt & ~PAGE_MASK);
|
|
|
|
|
}
|
|
|
|
@ -318,15 +308,15 @@ static void setup_pagemap(void)
|
|
|
|
|
* map it to a virtual address so we can fill its entries.
|
|
|
|
|
* So this is basically a replacement for a call to map_page().
|
|
|
|
|
*/
|
|
|
|
|
struct x86_page_directory *pd = (struct x86_page_directory *)0xfffff000;
|
|
|
|
|
struct x86_page_directory *pd = X86_CURRENT_PD;
|
|
|
|
|
struct x86_page_directory_entry *pd_entry = &pd->entries[1022];
|
|
|
|
|
*(unsigned long *)pd_entry = 0;
|
|
|
|
|
pd_entry->shifted_address = (uintptr_t)pt_phys >> X86_PAGE_DIRECTORY_ADDRESS_SHIFT;
|
|
|
|
|
pd_entry->shifted_address = (uintptr_t)pt_phys >> PAGE_SHIFT;
|
|
|
|
|
pd_entry->rw = 1;
|
|
|
|
|
pd_entry->present = 1;
|
|
|
|
|
vm_flush();
|
|
|
|
|
|
|
|
|
|
struct x86_page_table *pt = &((struct x86_page_table *)0xffc00000)[1022];
|
|
|
|
|
struct x86_page_table *pt = &X86_CURRENT_PT_BASE[1022];
|
|
|
|
|
memset(pt, 0, sizeof(*pt));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -336,7 +326,7 @@ static void setup_pagemap(void)
|
|
|
|
|
* virtual address, of course.
|
|
|
|
|
*/
|
|
|
|
|
uintptr_t pagemap_phys = dynpage_start;
|
|
|
|
|
size_t pt_index = 0;
|
|
|
|
|
usize pt_index = 0;
|
|
|
|
|
do {
|
|
|
|
|
/*
|
|
|
|
|
* take one page away from the dynamic area and reserve it for
|
|
|
|
@ -349,7 +339,7 @@ static void setup_pagemap(void)
|
|
|
|
|
struct x86_page_table_entry *pt_entry = &pt->entries[pt_index];
|
|
|
|
|
*(unsigned long *)pt_entry = 0;
|
|
|
|
|
uintptr_t address = pagemap_phys + pt_index * PAGE_SIZE;
|
|
|
|
|
pt_entry->shifted_address = address >> X86_PAGE_TABLE_ADDRESS_SHIFT;
|
|
|
|
|
pt_entry->shifted_address = address >> PAGE_SHIFT;
|
|
|
|
|
pt_entry->present = 1;
|
|
|
|
|
pt_entry->rw = 1;
|
|
|
|
|
|
|
|
|
|