From b4b35aa7a7491aa124d0eaec05f378e7c65f1c79 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 21 Apr 2023 00:16:31 -0400 Subject: [PATCH 01/15] identity paging and vaddr translation --- Makefile | 6 +-- src/os/main.c | 2 + src/os/paging.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ src/os/paging.h | 75 +++++++++++++++++++++++++++++++ 4 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 src/os/paging.c create mode 100644 src/os/paging.h diff --git a/Makefile b/Makefile index b965aaa..7c5585d 100644 --- a/Makefile +++ b/Makefile @@ -47,14 +47,12 @@ OS_BIN := mOS.bin C_FILES = $(shell find ./ -name '*.[ch]') -OBJ_NAMES := src/os/main.o src/os/test.o os_entry.o src/lib/video/VGA_text.o \ +OBJ_NAMES := src/os/main.o src/os/test.o os_entry.o src/os/paging.o \ src/os/hard/idt.o src/os/hard/except.o src/os/hard/pic.o \ src/lib/device/serial.o src/lib/device/ps2.o src/lib/device/keyboard.o \ src/lib/container/ring_buffer.o \ src/lib/stdlib/stdio.o src/lib/stdlib/stdlib.o src/lib/stdlib/string.o \ - src/lib/pit/pit.o src/lib/device/key_handlers.o - - + src/lib/pit/pit.o src/lib/device/key_handlers.o src/lib/video/VGA_text.o .PHONY: clean qemu test all: $(OS_BIN) diff --git a/src/os/main.c b/src/os/main.c index 8172a40..6bbedf0 100644 --- a/src/os/main.c +++ b/src/os/main.c @@ -1,12 +1,14 @@ #include "device/ps2.h" #include "device/serial.h" #include "hard/idt.h" +#include "paging.h" #include "pit/pit.h" #include "test.h" #include "video/VGA_text.h" int os_main() { makeInterruptTable(); + initPaging(); init_pit(); serialInit(); ps2Init(); diff --git a/src/os/paging.c b/src/os/paging.c new file mode 100644 index 0000000..4e902fb --- /dev/null +++ b/src/os/paging.c @@ -0,0 +1,117 @@ +#include "paging.h" + +#include "stdlib/string.h" + +/*The page directory and it's tables must be 4KiB aligned (0x1000) + * 0x90000 is the start of the stack, in other words, + * the areas from 0x1000 to 0x90000 are in use! + * But there is a nice open region we can use from 0x91000 - 0x9f000 + * (We technically have until 0x9fc00 before we enter ExBIOS data) + */ + +#define PAGE_DIRECTORY_BASE 0x91000 + +// room for 3 page tables (12 MiB of mapped memory) +#define KERNEL_PT_BASE 0x92000 +#define IDENTITY_PT_LIMIT 0x95000 +#define TABLE_COUNT ((IDENTITY_PT_LIMIT - KERNEL_PT_BASE) / 0x1000) + +PageDirectory *directory = (PageDirectory *)(PAGE_DIRECTORY_BASE); + +bool pageTablePresent(PageDirectoryEntry tableEntry) { + return tableEntry & ENTRY_PRESENT; +} + +bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } + +void setActiveDirectory(PageDirectory *dir) { + if (dir == NULL) + dir = directory; + + __asm__ volatile("mov cr3, %0" : : "a"(dir)); +} + +PageDirectory *getActivePageDir(void) { + PageDirectory *dir = NULL; + + __asm__ volatile("mov %0, cr3" : "=r"(dir)); + + return dir; +} + +void resetTLB(void) { setActiveDirectory(getActivePageDir()); } + +#define PAGE_TABLE_OFFSET 22 +#define PAGE_ENTRY_OFFSET 12 + +void *vaddrToPaddr(void *vaddr) { + + PageDirectory *dir = getActivePageDir(); + + // 10 bits of table (2^10 = 1024) + uint16_t tableidx = (uint32_t)(vaddr) >> PAGE_TABLE_OFFSET; + + // there are 10 bits of entry + uint16_t entryidx = ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0b1111111111; + + // 12 bits of offset + uint32_t paddr = (uint32_t)(vaddr)&0xfff; + + // get and verify page table + PageDirectoryEntry tableEntry = dir->entries[tableidx]; + if (!pageTablePresent(tableEntry)) + return NULL; + + PageTable *table = (PageTable *)(tableEntry & ENTRY_ADDR); + + // get and verify page entry + PageTableEntry entry = table->entries[entryidx]; + if (!pageEntryPresent(entry)) + return NULL; + + // add offset + return (void *)(paddr + (entry & ENTRY_ADDR)); +} + +// identity maps the table at directory entry idx +void identityMapTable(uint16_t idx, uint32_t flags) { + PageTable *table = (PageTable *)(directory->entries[idx] & ENTRY_ADDR); + + // 4GiB per directory + // 4MiB per table + uint32_t baseAddr = idx * 0x400000; + + for (uint32_t page_idx = 0; page_idx < PAGE_ENTRY_COUNT; ++page_idx) { + PageTableEntry entry = flags & ~(ENTRY_ADDR); + + // 4KiB per entry + entry |= (baseAddr + page_idx * 0x1000) & ENTRY_ADDR; + table->entries[page_idx] = entry; + } +} + +// preconditions, idx < PAGE_ENTRY_COUNT, table is 4KiB aligned +void addDirectoryEntry(uint16_t idx, PageTable *table, uint32_t flags) { + PageDirectoryEntry entry = flags & ~(ENTRY_ADDR); + entry |= (uint32_t)(table)&ENTRY_ADDR; + directory->entries[idx] = entry; +} + +void initPaging(void) { + // clear the memory (essentially say no page tables exist) + memset(directory, 0, PAGE_ENTRY_COUNT * sizeof(PageDirectoryEntry)); + + // identity map 12MiB and setup directory + for (uint16_t idx = 0; idx < TABLE_COUNT; ++idx) { + PageTable *addr = (PageTable *)((idx * 0x1000) + KERNEL_PT_BASE); + addDirectoryEntry(idx, addr, DEFAULT_ENTRY_FLAGS); + identityMapTable(idx, DEFAULT_ENTRY_FLAGS); + } + + setActiveDirectory(directory); + + // enable paging flags in cr0 + __asm__ volatile("mov eax, cr0\n\t" + "or eax, 0x80000001\n\t" + "mov cr0, eax"); +} \ No newline at end of file diff --git a/src/os/paging.h b/src/os/paging.h new file mode 100644 index 0000000..4329db2 --- /dev/null +++ b/src/os/paging.h @@ -0,0 +1,75 @@ +#ifndef PAGING_H +#define PAGING_H + +#include +#include + +// unfortunately C's bitfields can't provide the packing we need +typedef uint32_t PageDirectoryEntry; +typedef uint32_t PageTableEntry; + +#define PAGE_ENTRY_COUNT 1024 + +// The entries share flags! +#define ENTRY_PRESENT 0b000000001 +#define ENTRY_RW 0b000000010 +#define ENTRY_US 0b000000100 +#define ENTRY_PWT 0b000001000 +#define ENTRY_PCD 0b000010000 +#define ENTRY_ACESSED 0b000100000 + +// keep this flag should always be 0 +#define ENTRY_PS 0b010000000 + +// only for page table entries, available for OS use in page directory +#define ENTRY_GLOBAL 0b100000000 +#define ENTRY_DIRTY 0b001000000 + +// these bits are also available for the OS +#define ENTRY_AVL 0b111000000000 + +// bits 12-31 +#define ENTRY_ADDR 0xfffff000 + +// default entry is present, read/writable, and accessable by user and +// supervisor +#define DEFAULT_ENTRY_FLAGS (ENTRY_PRESENT | ENTRY_RW | ENTRY_US) + +typedef struct { + PageDirectoryEntry entries[PAGE_ENTRY_COUNT]; +} __attribute__((packed)) PageDirectory; + +// note, this structure must be 4KiB aligned +typedef struct { + PageTableEntry entries[PAGE_ENTRY_COUNT]; +} __attribute__((packed)) PageTable; + +bool pageTablePresent(PageDirectoryEntry tableEntry); +bool pageEntryPresent(PageTableEntry entry); + +// sets the active page directory, if NULL uses the identity directory +void setActivePageDir(PageDirectory *dir); + +// gets the current page dir from cr3 +PageDirectory *getActivePageDir(void); + +/* + * resets the translation lookaside buffer + * the TLB needs to be reset whenever an entry is modified + */ +void resetTLB(void); + +/* + * Converts virtual address to physical address + * (according to the current page table/directory) + * returns NULL when the address isn't present + */ +void *vaddrToPaddr(void *vaddr); + +/* + * enables paging and identity maps the kernel (1st MiB) + * as well as identity mapping 1MiB - 12MiB + */ +void initPaging(void); + +#endif \ No newline at end of file From 58bbff6b214f27c84e48bee5accb773ea4484240 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 21 Apr 2023 08:17:54 -0400 Subject: [PATCH 02/15] Nicer interface --- src/os/paging.c | 56 ++++++++++++++++++++++++++++++------------------- src/os/paging.h | 9 ++++++++ 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 4e902fb..0f5f836 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -9,14 +9,14 @@ * (We technically have until 0x9fc00 before we enter ExBIOS data) */ -#define PAGE_DIRECTORY_BASE 0x91000 +#define ID_PAGE_DIRECTORY_BASE 0x91000 // room for 3 page tables (12 MiB of mapped memory) -#define KERNEL_PT_BASE 0x92000 +#define IDENTITY_PT_BASE 0x92000 #define IDENTITY_PT_LIMIT 0x95000 -#define TABLE_COUNT ((IDENTITY_PT_LIMIT - KERNEL_PT_BASE) / 0x1000) +#define TABLE_COUNT ((IDENTITY_PT_LIMIT - IDENTITY_PT_BASE) / 0x1000) -PageDirectory *directory = (PageDirectory *)(PAGE_DIRECTORY_BASE); +PageDirectory *idendirectory = (PageDirectory *)(ID_PAGE_DIRECTORY_BASE); bool pageTablePresent(PageDirectoryEntry tableEntry) { return tableEntry & ENTRY_PRESENT; @@ -26,7 +26,7 @@ bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } void setActiveDirectory(PageDirectory *dir) { if (dir == NULL) - dir = directory; + dir = idendirectory; __asm__ volatile("mov cr3, %0" : : "a"(dir)); } @@ -41,21 +41,32 @@ PageDirectory *getActivePageDir(void) { void resetTLB(void) { setActiveDirectory(getActivePageDir()); } + #define PAGE_TABLE_OFFSET 22 #define PAGE_ENTRY_OFFSET 12 -void *vaddrToPaddr(void *vaddr) { +// highest 10 bits +uint16_t vaddrDirectoryIdx(void *vaddr) { + return (uint32_t)(vaddr) >> PAGE_TABLE_OFFSET; +} - PageDirectory *dir = getActivePageDir(); +// middle 10 bits +uint16_t vaddrEntryIdx(void *vaddr) { + return ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0b1111111111; +} - // 10 bits of table (2^10 = 1024) - uint16_t tableidx = (uint32_t)(vaddr) >> PAGE_TABLE_OFFSET; +// low 12 bits +uint32_t vaddrOffset(void* vaddr) { + return (uint32_t)(vaddr) & 0xfff; +} + +void *vaddrToPaddr(void *vaddr) { - // there are 10 bits of entry - uint16_t entryidx = ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0b1111111111; + PageDirectory *dir = getActivePageDir(); - // 12 bits of offset - uint32_t paddr = (uint32_t)(vaddr)&0xfff; + uint16_t tableidx = vaddrDirectoryIdx(vaddr); + uint16_t entryidx = vaddrEntryIdx(vaddr); + uint32_t paddr = vaddrOffset(vaddr); // get and verify page table PageDirectoryEntry tableEntry = dir->entries[tableidx]; @@ -73,8 +84,8 @@ void *vaddrToPaddr(void *vaddr) { return (void *)(paddr + (entry & ENTRY_ADDR)); } -// identity maps the table at directory entry idx -void identityMapTable(uint16_t idx, uint32_t flags) { +// identity maps the entire table at directory entry idx +void identityMapTable(PageDirectory* directory, uint16_t idx, uint32_t flags) { PageTable *table = (PageTable *)(directory->entries[idx] & ENTRY_ADDR); // 4GiB per directory @@ -85,13 +96,13 @@ void identityMapTable(uint16_t idx, uint32_t flags) { PageTableEntry entry = flags & ~(ENTRY_ADDR); // 4KiB per entry - entry |= (baseAddr + page_idx * 0x1000) & ENTRY_ADDR; + entry |= (baseAddr + page_idx * PAGE_SIZE) & ENTRY_ADDR; table->entries[page_idx] = entry; } } // preconditions, idx < PAGE_ENTRY_COUNT, table is 4KiB aligned -void addDirectoryEntry(uint16_t idx, PageTable *table, uint32_t flags) { +void addTableToDirectory(PageDirectory* directory, uint16_t idx, PageTable *table, uint32_t flags) { PageDirectoryEntry entry = flags & ~(ENTRY_ADDR); entry |= (uint32_t)(table)&ENTRY_ADDR; directory->entries[idx] = entry; @@ -99,16 +110,17 @@ void addDirectoryEntry(uint16_t idx, PageTable *table, uint32_t flags) { void initPaging(void) { // clear the memory (essentially say no page tables exist) - memset(directory, 0, PAGE_ENTRY_COUNT * sizeof(PageDirectoryEntry)); + memset(idendirectory, 0, PAGE_ENTRY_COUNT * sizeof(PageDirectoryEntry)); // identity map 12MiB and setup directory for (uint16_t idx = 0; idx < TABLE_COUNT; ++idx) { - PageTable *addr = (PageTable *)((idx * 0x1000) + KERNEL_PT_BASE); - addDirectoryEntry(idx, addr, DEFAULT_ENTRY_FLAGS); - identityMapTable(idx, DEFAULT_ENTRY_FLAGS); + PageTable *addr = (PageTable *)((idx * PAGE_SIZE) + IDENTITY_PT_BASE); + memset(addr, 0, PAGE_ENTRY_COUNT * sizeof(PageTableEntry)); + addTableToDirectory(idendirectory, idx, addr, DEFAULT_ENTRY_FLAGS); + identityMapTable(idendirectory, idx, DEFAULT_ENTRY_FLAGS); } - setActiveDirectory(directory); + setActiveDirectory(idendirectory); // enable paging flags in cr0 __asm__ volatile("mov eax, cr0\n\t" diff --git a/src/os/paging.h b/src/os/paging.h index 4329db2..b3ef357 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -9,6 +9,7 @@ typedef uint32_t PageDirectoryEntry; typedef uint32_t PageTableEntry; #define PAGE_ENTRY_COUNT 1024 +#define PAGE_SIZE 0x1000 // The entries share flags! #define ENTRY_PRESENT 0b000000001 @@ -59,6 +60,14 @@ PageDirectory *getActivePageDir(void); */ void resetTLB(void); +// adds a table to a directory, TLB must be reset manually if directory is the current page directory +void addTableToDirectory(PageDirectory* directory, uint16_t idx, PageTable *table, uint32_t flags); + +// translation helpers +uint16_t vaddrDirectoryIdx(void *vaddr); +uint16_t vaddrEntryIdx(void *vaddr); +uint32_t vaddrOffset(void* vaddr); + /* * Converts virtual address to physical address * (according to the current page table/directory) From 9773714c1cdae27a3048882c8f38be01064dd6af Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 21 Apr 2023 08:36:32 -0400 Subject: [PATCH 03/15] More granularity --- src/os/paging.c | 34 ++++++++++++++++++++------------- src/os/paging.h | 13 ++++++++++--- tests/expected/os/paging.expect | 0 tests/src/os/paging.c | 9 +++++++++ 4 files changed, 40 insertions(+), 16 deletions(-) create mode 100644 tests/expected/os/paging.expect create mode 100644 tests/src/os/paging.c diff --git a/src/os/paging.c b/src/os/paging.c index 0f5f836..7b7397f 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -60,28 +60,36 @@ uint32_t vaddrOffset(void* vaddr) { return (uint32_t)(vaddr) & 0xfff; } -void *vaddrToPaddr(void *vaddr) { +PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr) { + uint16_t tableidx = vaddrDirectoryIdx(vaddr); + return &directory->entries[tableidx]; +} - PageDirectory *dir = getActivePageDir(); +PageTableEntry* vaddrTableEntry(PageDirectory* directory, void *vaddr) { + // this will never be null (unless something really bad happened) + PageDirectoryEntry* dirEntry = vaddrDirEntry(directory, vaddr); + PageTable* table = (PageTable*)((*dirEntry) & ENTRY_ADDR); + + if (table == NULL) + return NULL; - uint16_t tableidx = vaddrDirectoryIdx(vaddr); uint16_t entryidx = vaddrEntryIdx(vaddr); - uint32_t paddr = vaddrOffset(vaddr); + return &table->entries[entryidx]; +} - // get and verify page table - PageDirectoryEntry tableEntry = dir->entries[tableidx]; - if (!pageTablePresent(tableEntry)) - return NULL; +void *vaddrToPaddr(void *vaddr) { - PageTable *table = (PageTable *)(tableEntry & ENTRY_ADDR); + PageDirectory *dir = getActivePageDir(); // get and verify page entry - PageTableEntry entry = table->entries[entryidx]; - if (!pageEntryPresent(entry)) + PageTableEntry* entry = vaddrTableEntry(dir, vaddr); + if (entry == NULL) return NULL; - // add offset - return (void *)(paddr + (entry & ENTRY_ADDR)); + uint32_t paddr = vaddrOffset(vaddr); + + // apply offset + return (void *)(paddr + ((*entry) & ENTRY_ADDR)); } // identity maps the entire table at directory entry idx diff --git a/src/os/paging.h b/src/os/paging.h index b3ef357..5de2111 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -36,14 +36,15 @@ typedef uint32_t PageTableEntry; // supervisor #define DEFAULT_ENTRY_FLAGS (ENTRY_PRESENT | ENTRY_RW | ENTRY_US) +// note: these structures are lacking attrib packed typedef struct { PageDirectoryEntry entries[PAGE_ENTRY_COUNT]; -} __attribute__((packed)) PageDirectory; +} PageDirectory; // note, this structure must be 4KiB aligned typedef struct { PageTableEntry entries[PAGE_ENTRY_COUNT]; -} __attribute__((packed)) PageTable; +} PageTable; bool pageTablePresent(PageDirectoryEntry tableEntry); bool pageEntryPresent(PageTableEntry entry); @@ -68,10 +69,16 @@ uint16_t vaddrDirectoryIdx(void *vaddr); uint16_t vaddrEntryIdx(void *vaddr); uint32_t vaddrOffset(void* vaddr); +// returns the associated directory entry of vaddr, never null +PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr); + +// returns the associated table entry of vaddr, null if invalid/unmapped address +PageTableEntry* vaddrTableEntry(PageDirectory* directory, void* vaddr); + /* * Converts virtual address to physical address * (according to the current page table/directory) - * returns NULL when the address isn't present + * returns NULL when the address is invalid/unmapped */ void *vaddrToPaddr(void *vaddr); diff --git a/tests/expected/os/paging.expect b/tests/expected/os/paging.expect new file mode 100644 index 0000000..e69de29 diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c new file mode 100644 index 0000000..bddd8c0 --- /dev/null +++ b/tests/src/os/paging.c @@ -0,0 +1,9 @@ +#include "../test_helper.h" + +#include <../os/paging.h> + + + +void test_main() { + //PageDirectory* dir = getActivePageDir(); +} \ No newline at end of file From c39404ca2d4b4532b8c1df82c7a866d4678ebb7e Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 21 Apr 2023 18:17:29 -0400 Subject: [PATCH 04/15] tests --- src/os/paging.c | 31 +++++++-- src/os/paging.h | 15 ++++- tests/expected/os/paging.expect | 3 + tests/src/os/paging.c | 110 +++++++++++++++++++++++++++++++- 4 files changed, 150 insertions(+), 9 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 7b7397f..4458bfa 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -24,7 +24,15 @@ bool pageTablePresent(PageDirectoryEntry tableEntry) { bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } -void setActiveDirectory(PageDirectory *dir) { +void setEntryAddr(PageTableEntry* entry, void* addr) { + if (entry == NULL) + return; + + *entry = ((uint32_t)(addr) & ENTRY_ADDR) | (*entry & ~(ENTRY_ADDR)); +} + + +void setActivePageDir(PageDirectory *dir) { if (dir == NULL) dir = idendirectory; @@ -39,7 +47,7 @@ PageDirectory *getActivePageDir(void) { return dir; } -void resetTLB(void) { setActiveDirectory(getActivePageDir()); } +void resetTLB(void) { setActivePageDir(getActivePageDir()); } #define PAGE_TABLE_OFFSET 22 @@ -56,11 +64,21 @@ uint16_t vaddrEntryIdx(void *vaddr) { } // low 12 bits -uint32_t vaddrOffset(void* vaddr) { +uint16_t vaddrOffset(void* vaddr) { return (uint32_t)(vaddr) & 0xfff; } +void* toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { + uint32_t vaddr = offset; + vaddr |= (uint32_t)(entryIdx) << PAGE_ENTRY_OFFSET; + vaddr |= (uint32_t)(dirIdx) << PAGE_TABLE_OFFSET; + return (void*)(vaddr); +} + PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr) { + if (directory == NULL) + directory = getActivePageDir(); + uint16_t tableidx = vaddrDirectoryIdx(vaddr); return &directory->entries[tableidx]; } @@ -77,9 +95,10 @@ PageTableEntry* vaddrTableEntry(PageDirectory* directory, void *vaddr) { return &table->entries[entryidx]; } -void *vaddrToPaddr(void *vaddr) { +void *vaddrToPaddr(PageDirectory *dir, void *vaddr) { - PageDirectory *dir = getActivePageDir(); + if (dir == NULL) + dir = getActivePageDir(); // get and verify page entry PageTableEntry* entry = vaddrTableEntry(dir, vaddr); @@ -128,7 +147,7 @@ void initPaging(void) { identityMapTable(idendirectory, idx, DEFAULT_ENTRY_FLAGS); } - setActiveDirectory(idendirectory); + setActivePageDir(idendirectory); // enable paging flags in cr0 __asm__ volatile("mov eax, cr0\n\t" diff --git a/src/os/paging.h b/src/os/paging.h index 5de2111..6995ef1 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -49,6 +49,11 @@ typedef struct { bool pageTablePresent(PageDirectoryEntry tableEntry); bool pageEntryPresent(PageTableEntry entry); +// sets the entry's physical page to that of addr +void setEntryAddr(PageTableEntry* entry, void* addr); + +// NOTE: IF PageDirectory* IS NULL IT USES THE CURRENT DIRECTORY (unless otherwise specified) + // sets the active page directory, if NULL uses the identity directory void setActivePageDir(PageDirectory *dir); @@ -67,7 +72,10 @@ void addTableToDirectory(PageDirectory* directory, uint16_t idx, PageTable *tabl // translation helpers uint16_t vaddrDirectoryIdx(void *vaddr); uint16_t vaddrEntryIdx(void *vaddr); -uint32_t vaddrOffset(void* vaddr); +uint16_t vaddrOffset(void* vaddr); + +// translates table indexes and offset to virtual address +void* toVaddr(uint16_t dirIdx, uint16_t tableIdx, uint16_t offset); // returns the associated directory entry of vaddr, never null PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr); @@ -75,12 +83,15 @@ PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr); // returns the associated table entry of vaddr, null if invalid/unmapped address PageTableEntry* vaddrTableEntry(PageDirectory* directory, void* vaddr); +// identity maps the PageTable at directory index idx +void identityMapTable(PageDirectory* directory, uint16_t idx, uint32_t flags); + /* * Converts virtual address to physical address * (according to the current page table/directory) * returns NULL when the address is invalid/unmapped */ -void *vaddrToPaddr(void *vaddr); +void *vaddrToPaddr(PageDirectory *dir, void *vaddr); /* * enables paging and identity maps the kernel (1st MiB) diff --git a/tests/expected/os/paging.expect b/tests/expected/os/paging.expect index e69de29..4ca01fd 100644 --- a/tests/expected/os/paging.expect +++ b/tests/expected/os/paging.expect @@ -0,0 +1,3 @@ +test_composition done +test_identity done +test_swap done diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index bddd8c0..c593372 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -2,8 +2,116 @@ #include <../os/paging.h> +// 1st megabyte is a safe place to read from, but not to write to +#define MiB1 0x100000 +// 3rd megabyte is safe to both read and write to +#define MiB3 (MiB1 * 3) + +// placed so that the test goes over the table 0 and table 1 boundary +#define IDENT_LOCATION ((MiB1 * 4) - PAGE_SIZE) + +void assert_identity(PageDirectory* dir, void* addr) { + ASSERT(vaddrToPaddr(dir, addr) == addr); +} + +void test_identity(PageDirectory* idDir) { + + // test 2 whole pages (and first byte of 3rd) + for (int i = 0; i <= PAGE_SIZE * 2; ++i) { + assert_identity(idDir, (void*)(IDENT_LOCATION + i)); + } + + char done[] = "test_identity done\n"; + serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); +} + +void assert_compose(uint16_t didx, uint16_t tidx, uint16_t off) { + void* addr = toVaddr(didx, tidx, off); + + ASSERT(addr == (void*)((didx * 0x400000) + (tidx * 0x1000) + off)); + + ASSERT(vaddrOffset(addr) == off); + ASSERT(vaddrEntryIdx(addr) == tidx); + ASSERT(vaddrDirectoryIdx(addr) == didx); +} + +void test_composition(void) { + + assert_compose(0, 0, 0); + assert_compose(0, 0, 0xfff); + assert_compose(1023, 0, 0); + assert_compose(0, 1023, 0); + assert_compose(1023, 1023, 0xfff); + assert_compose(123, 456, 789); + + char done[] = "test_composition done\n"; + serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); +} + +#define BOUND ((void*)(MiB1 * 4)) + +void test_swap_page(PageDirectory *base) { + // steal the 3MiB page and 3 more + PageDirectory* newDir = (PageDirectory*)(MiB3); + PageTable* tables = (PageTable*)(MiB3 + sizeof(PageDirectory)); + + // setup identity paged dir + addTableToDirectory(newDir, 0, tables, DEFAULT_ENTRY_FLAGS); + addTableToDirectory(newDir, 1, tables + 1, DEFAULT_ENTRY_FLAGS); + addTableToDirectory(newDir, 2, tables + 2, DEFAULT_ENTRY_FLAGS); + + identityMapTable(newDir, 0, DEFAULT_ENTRY_FLAGS); + identityMapTable(newDir, 1, DEFAULT_ENTRY_FLAGS); + identityMapTable(newDir, 2, DEFAULT_ENTRY_FLAGS); + + // first and second entry of page table at index 1 + PageTableEntry* entry1 = vaddrTableEntry(newDir, BOUND); + PageTableEntry* entry2 = vaddrTableEntry(newDir, BOUND + PAGE_SIZE); + ASSERT(entry1 == &tables[1].entries[0]); + ASSERT(entry2 == &tables[1].entries[1]); + + // map 4th MiB to 4th MiB + 1 page and vice versa + setEntryAddr(entry1, BOUND + PAGE_SIZE); + setEntryAddr(entry2, BOUND); + ASSERT(vaddrToPaddr(newDir, BOUND) == BOUND + PAGE_SIZE); + ASSERT(vaddrToPaddr(newDir, BOUND + PAGE_SIZE) == BOUND); + + uint32_t* magicLocation = (uint32_t*)(BOUND); + uint32_t* boringLocation = (uint32_t*)(BOUND + PAGE_SIZE); + + // setup data + magicLocation[0] = 0xdeadbeef; + boringLocation[0] = 0xc0decafe; + + // swap to new directory + setActivePageDir(newDir); + + // currently the two locations should be flipped + ASSERT(magicLocation[0] == 0xc0decafe); + ASSERT(boringLocation[0] == 0xdeadbeef); + magicLocation[0] = 0xdeadbeef; + boringLocation[0] = 0xc0decafe; + + // swap back + setActivePageDir(base); + + // they swapped!!! + ASSERT(magicLocation[0] == 0xc0decafe); + ASSERT(boringLocation[0] == 0xdeadbeef); + + char done[] = "test_swap done\n"; + serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); +} void test_main() { - //PageDirectory* dir = getActivePageDir(); + test_composition(); + + PageDirectory* idDir = getActivePageDir(); + ASSERT(idDir != NULL); + + test_identity(idDir); + + test_swap_page(idDir); + } \ No newline at end of file From 6eb84deee804bd21fba514bac174d65a1ac2fb67 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 21 Apr 2023 18:18:55 -0400 Subject: [PATCH 05/15] format --- src/os/paging.c | 33 +++++++++++++++------------------ src/os/paging.h | 21 ++++++++++++--------- tests/src/os/paging.c | 29 ++++++++++++++--------------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 4458bfa..2e3ed11 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -14,7 +14,7 @@ // room for 3 page tables (12 MiB of mapped memory) #define IDENTITY_PT_BASE 0x92000 #define IDENTITY_PT_LIMIT 0x95000 -#define TABLE_COUNT ((IDENTITY_PT_LIMIT - IDENTITY_PT_BASE) / 0x1000) +#define TABLE_COUNT ((IDENTITY_PT_LIMIT - IDENTITY_PT_BASE) / 0x1000) PageDirectory *idendirectory = (PageDirectory *)(ID_PAGE_DIRECTORY_BASE); @@ -24,14 +24,13 @@ bool pageTablePresent(PageDirectoryEntry tableEntry) { bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } -void setEntryAddr(PageTableEntry* entry, void* addr) { +void setEntryAddr(PageTableEntry *entry, void *addr) { if (entry == NULL) return; - *entry = ((uint32_t)(addr) & ENTRY_ADDR) | (*entry & ~(ENTRY_ADDR)); + *entry = ((uint32_t)(addr)&ENTRY_ADDR) | (*entry & ~(ENTRY_ADDR)); } - void setActivePageDir(PageDirectory *dir) { if (dir == NULL) dir = idendirectory; @@ -49,7 +48,6 @@ PageDirectory *getActivePageDir(void) { void resetTLB(void) { setActivePageDir(getActivePageDir()); } - #define PAGE_TABLE_OFFSET 22 #define PAGE_ENTRY_OFFSET 12 @@ -64,18 +62,16 @@ uint16_t vaddrEntryIdx(void *vaddr) { } // low 12 bits -uint16_t vaddrOffset(void* vaddr) { - return (uint32_t)(vaddr) & 0xfff; -} +uint16_t vaddrOffset(void *vaddr) { return (uint32_t)(vaddr)&0xfff; } -void* toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { +void *toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { uint32_t vaddr = offset; vaddr |= (uint32_t)(entryIdx) << PAGE_ENTRY_OFFSET; vaddr |= (uint32_t)(dirIdx) << PAGE_TABLE_OFFSET; - return (void*)(vaddr); + return (void *)(vaddr); } -PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr) { +PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, void *vaddr) { if (directory == NULL) directory = getActivePageDir(); @@ -83,12 +79,12 @@ PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr) { return &directory->entries[tableidx]; } -PageTableEntry* vaddrTableEntry(PageDirectory* directory, void *vaddr) { +PageTableEntry *vaddrTableEntry(PageDirectory *directory, void *vaddr) { // this will never be null (unless something really bad happened) - PageDirectoryEntry* dirEntry = vaddrDirEntry(directory, vaddr); - PageTable* table = (PageTable*)((*dirEntry) & ENTRY_ADDR); + PageDirectoryEntry *dirEntry = vaddrDirEntry(directory, vaddr); + PageTable *table = (PageTable *)((*dirEntry) & ENTRY_ADDR); - if (table == NULL) + if (table == NULL) return NULL; uint16_t entryidx = vaddrEntryIdx(vaddr); @@ -101,7 +97,7 @@ void *vaddrToPaddr(PageDirectory *dir, void *vaddr) { dir = getActivePageDir(); // get and verify page entry - PageTableEntry* entry = vaddrTableEntry(dir, vaddr); + PageTableEntry *entry = vaddrTableEntry(dir, vaddr); if (entry == NULL) return NULL; @@ -112,7 +108,7 @@ void *vaddrToPaddr(PageDirectory *dir, void *vaddr) { } // identity maps the entire table at directory entry idx -void identityMapTable(PageDirectory* directory, uint16_t idx, uint32_t flags) { +void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags) { PageTable *table = (PageTable *)(directory->entries[idx] & ENTRY_ADDR); // 4GiB per directory @@ -129,7 +125,8 @@ void identityMapTable(PageDirectory* directory, uint16_t idx, uint32_t flags) { } // preconditions, idx < PAGE_ENTRY_COUNT, table is 4KiB aligned -void addTableToDirectory(PageDirectory* directory, uint16_t idx, PageTable *table, uint32_t flags) { +void addTableToDirectory(PageDirectory *directory, uint16_t idx, + PageTable *table, uint32_t flags) { PageDirectoryEntry entry = flags & ~(ENTRY_ADDR); entry |= (uint32_t)(table)&ENTRY_ADDR; directory->entries[idx] = entry; diff --git a/src/os/paging.h b/src/os/paging.h index 6995ef1..6953ae9 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -50,9 +50,10 @@ bool pageTablePresent(PageDirectoryEntry tableEntry); bool pageEntryPresent(PageTableEntry entry); // sets the entry's physical page to that of addr -void setEntryAddr(PageTableEntry* entry, void* addr); +void setEntryAddr(PageTableEntry *entry, void *addr); -// NOTE: IF PageDirectory* IS NULL IT USES THE CURRENT DIRECTORY (unless otherwise specified) +// NOTE: IF PageDirectory* IS NULL IT USES THE CURRENT DIRECTORY (unless +// otherwise specified) // sets the active page directory, if NULL uses the identity directory void setActivePageDir(PageDirectory *dir); @@ -66,25 +67,27 @@ PageDirectory *getActivePageDir(void); */ void resetTLB(void); -// adds a table to a directory, TLB must be reset manually if directory is the current page directory -void addTableToDirectory(PageDirectory* directory, uint16_t idx, PageTable *table, uint32_t flags); +// adds a table to a directory, TLB must be reset manually if directory is the +// current page directory +void addTableToDirectory(PageDirectory *directory, uint16_t idx, + PageTable *table, uint32_t flags); // translation helpers uint16_t vaddrDirectoryIdx(void *vaddr); uint16_t vaddrEntryIdx(void *vaddr); -uint16_t vaddrOffset(void* vaddr); +uint16_t vaddrOffset(void *vaddr); // translates table indexes and offset to virtual address -void* toVaddr(uint16_t dirIdx, uint16_t tableIdx, uint16_t offset); +void *toVaddr(uint16_t dirIdx, uint16_t tableIdx, uint16_t offset); // returns the associated directory entry of vaddr, never null -PageDirectoryEntry* vaddrDirEntry(PageDirectory* directory, void *vaddr); +PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, void *vaddr); // returns the associated table entry of vaddr, null if invalid/unmapped address -PageTableEntry* vaddrTableEntry(PageDirectory* directory, void* vaddr); +PageTableEntry *vaddrTableEntry(PageDirectory *directory, void *vaddr); // identity maps the PageTable at directory index idx -void identityMapTable(PageDirectory* directory, uint16_t idx, uint32_t flags); +void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags); /* * Converts virtual address to physical address diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index c593372..6d40115 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -11,15 +11,15 @@ // placed so that the test goes over the table 0 and table 1 boundary #define IDENT_LOCATION ((MiB1 * 4) - PAGE_SIZE) -void assert_identity(PageDirectory* dir, void* addr) { +void assert_identity(PageDirectory *dir, void *addr) { ASSERT(vaddrToPaddr(dir, addr) == addr); } -void test_identity(PageDirectory* idDir) { +void test_identity(PageDirectory *idDir) { // test 2 whole pages (and first byte of 3rd) for (int i = 0; i <= PAGE_SIZE * 2; ++i) { - assert_identity(idDir, (void*)(IDENT_LOCATION + i)); + assert_identity(idDir, (void *)(IDENT_LOCATION + i)); } char done[] = "test_identity done\n"; @@ -27,9 +27,9 @@ void test_identity(PageDirectory* idDir) { } void assert_compose(uint16_t didx, uint16_t tidx, uint16_t off) { - void* addr = toVaddr(didx, tidx, off); + void *addr = toVaddr(didx, tidx, off); - ASSERT(addr == (void*)((didx * 0x400000) + (tidx * 0x1000) + off)); + ASSERT(addr == (void *)((didx * 0x400000) + (tidx * 0x1000) + off)); ASSERT(vaddrOffset(addr) == off); ASSERT(vaddrEntryIdx(addr) == tidx); @@ -49,12 +49,12 @@ void test_composition(void) { serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } -#define BOUND ((void*)(MiB1 * 4)) +#define BOUND ((void *)(MiB1 * 4)) void test_swap_page(PageDirectory *base) { // steal the 3MiB page and 3 more - PageDirectory* newDir = (PageDirectory*)(MiB3); - PageTable* tables = (PageTable*)(MiB3 + sizeof(PageDirectory)); + PageDirectory *newDir = (PageDirectory *)(MiB3); + PageTable *tables = (PageTable *)(MiB3 + sizeof(PageDirectory)); // setup identity paged dir addTableToDirectory(newDir, 0, tables, DEFAULT_ENTRY_FLAGS); @@ -66,8 +66,8 @@ void test_swap_page(PageDirectory *base) { identityMapTable(newDir, 2, DEFAULT_ENTRY_FLAGS); // first and second entry of page table at index 1 - PageTableEntry* entry1 = vaddrTableEntry(newDir, BOUND); - PageTableEntry* entry2 = vaddrTableEntry(newDir, BOUND + PAGE_SIZE); + PageTableEntry *entry1 = vaddrTableEntry(newDir, BOUND); + PageTableEntry *entry2 = vaddrTableEntry(newDir, BOUND + PAGE_SIZE); ASSERT(entry1 == &tables[1].entries[0]); ASSERT(entry2 == &tables[1].entries[1]); @@ -77,8 +77,8 @@ void test_swap_page(PageDirectory *base) { ASSERT(vaddrToPaddr(newDir, BOUND) == BOUND + PAGE_SIZE); ASSERT(vaddrToPaddr(newDir, BOUND + PAGE_SIZE) == BOUND); - uint32_t* magicLocation = (uint32_t*)(BOUND); - uint32_t* boringLocation = (uint32_t*)(BOUND + PAGE_SIZE); + uint32_t *magicLocation = (uint32_t *)(BOUND); + uint32_t *boringLocation = (uint32_t *)(BOUND + PAGE_SIZE); // setup data magicLocation[0] = 0xdeadbeef; @@ -99,7 +99,7 @@ void test_swap_page(PageDirectory *base) { // they swapped!!! ASSERT(magicLocation[0] == 0xc0decafe); ASSERT(boringLocation[0] == 0xdeadbeef); - + char done[] = "test_swap done\n"; serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } @@ -107,11 +107,10 @@ void test_swap_page(PageDirectory *base) { void test_main() { test_composition(); - PageDirectory* idDir = getActivePageDir(); + PageDirectory *idDir = getActivePageDir(); ASSERT(idDir != NULL); test_identity(idDir); test_swap_page(idDir); - } \ No newline at end of file From 9d8f63b503d660608a6268d1eccd4ecc179f47d3 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 23 Apr 2023 14:44:51 -0400 Subject: [PATCH 06/15] another test and const --- src/os/paging.c | 14 ++++----- src/os/paging.h | 14 ++++----- tests/expected/os/paging.expect | 1 + tests/src/os/paging.c | 54 +++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 2e3ed11..a033dc7 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -24,7 +24,7 @@ bool pageTablePresent(PageDirectoryEntry tableEntry) { bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } -void setEntryAddr(PageTableEntry *entry, void *addr) { +void setEntryAddr(PageTableEntry *entry, const void *addr) { if (entry == NULL) return; @@ -52,17 +52,17 @@ void resetTLB(void) { setActivePageDir(getActivePageDir()); } #define PAGE_ENTRY_OFFSET 12 // highest 10 bits -uint16_t vaddrDirectoryIdx(void *vaddr) { +uint16_t vaddrDirectoryIdx(const void *vaddr) { return (uint32_t)(vaddr) >> PAGE_TABLE_OFFSET; } // middle 10 bits -uint16_t vaddrEntryIdx(void *vaddr) { +uint16_t vaddrEntryIdx(const void *vaddr) { return ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0b1111111111; } // low 12 bits -uint16_t vaddrOffset(void *vaddr) { return (uint32_t)(vaddr)&0xfff; } +uint16_t vaddrOffset(const void *vaddr) { return (uint32_t)(vaddr)&0xfff; } void *toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { uint32_t vaddr = offset; @@ -71,7 +71,7 @@ void *toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { return (void *)(vaddr); } -PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, void *vaddr) { +PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, const void *vaddr) { if (directory == NULL) directory = getActivePageDir(); @@ -79,7 +79,7 @@ PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, void *vaddr) { return &directory->entries[tableidx]; } -PageTableEntry *vaddrTableEntry(PageDirectory *directory, void *vaddr) { +PageTableEntry *vaddrTableEntry(PageDirectory *directory, const void *vaddr) { // this will never be null (unless something really bad happened) PageDirectoryEntry *dirEntry = vaddrDirEntry(directory, vaddr); PageTable *table = (PageTable *)((*dirEntry) & ENTRY_ADDR); @@ -91,7 +91,7 @@ PageTableEntry *vaddrTableEntry(PageDirectory *directory, void *vaddr) { return &table->entries[entryidx]; } -void *vaddrToPaddr(PageDirectory *dir, void *vaddr) { +void *vaddrToPaddr(PageDirectory *dir, const void *vaddr) { if (dir == NULL) dir = getActivePageDir(); diff --git a/src/os/paging.h b/src/os/paging.h index 6953ae9..52a8d27 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -50,7 +50,7 @@ bool pageTablePresent(PageDirectoryEntry tableEntry); bool pageEntryPresent(PageTableEntry entry); // sets the entry's physical page to that of addr -void setEntryAddr(PageTableEntry *entry, void *addr); +void setEntryAddr(PageTableEntry *entry, const void *addr); // NOTE: IF PageDirectory* IS NULL IT USES THE CURRENT DIRECTORY (unless // otherwise specified) @@ -73,18 +73,18 @@ void addTableToDirectory(PageDirectory *directory, uint16_t idx, PageTable *table, uint32_t flags); // translation helpers -uint16_t vaddrDirectoryIdx(void *vaddr); -uint16_t vaddrEntryIdx(void *vaddr); -uint16_t vaddrOffset(void *vaddr); +uint16_t vaddrDirectoryIdx(const void *vaddr); +uint16_t vaddrEntryIdx(const void *vaddr); +uint16_t vaddrOffset(const void *vaddr); // translates table indexes and offset to virtual address void *toVaddr(uint16_t dirIdx, uint16_t tableIdx, uint16_t offset); // returns the associated directory entry of vaddr, never null -PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, void *vaddr); +PageDirectoryEntry *vaddrDirEntry(PageDirectory *directory, const void *vaddr); // returns the associated table entry of vaddr, null if invalid/unmapped address -PageTableEntry *vaddrTableEntry(PageDirectory *directory, void *vaddr); +PageTableEntry *vaddrTableEntry(PageDirectory *directory, const void *vaddr); // identity maps the PageTable at directory index idx void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags); @@ -94,7 +94,7 @@ void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags); * (according to the current page table/directory) * returns NULL when the address is invalid/unmapped */ -void *vaddrToPaddr(PageDirectory *dir, void *vaddr); +void *vaddrToPaddr(PageDirectory *dir, const void *vaddr); /* * enables paging and identity maps the kernel (1st MiB) diff --git a/tests/expected/os/paging.expect b/tests/expected/os/paging.expect index 4ca01fd..a6be962 100644 --- a/tests/expected/os/paging.expect +++ b/tests/expected/os/paging.expect @@ -1,3 +1,4 @@ test_composition done test_identity done test_swap done +test_modify_in_place done diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index 6d40115..31d462b 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -104,6 +104,58 @@ void test_swap_page(PageDirectory *base) { serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } +void test_modify_in_place(PageDirectory* base) { + // steal the 3MiB page and 3 more + PageDirectory *newDir = (PageDirectory *)(MiB3); + PageTable *tables = (PageTable *)(MiB3 + sizeof(PageDirectory)); + + // setup identity paged dir + addTableToDirectory(newDir, 0, tables, DEFAULT_ENTRY_FLAGS); + addTableToDirectory(newDir, 1, tables + 1, DEFAULT_ENTRY_FLAGS); + addTableToDirectory(newDir, 2, tables + 2, DEFAULT_ENTRY_FLAGS); + + identityMapTable(newDir, 0, DEFAULT_ENTRY_FLAGS); + identityMapTable(newDir, 1, DEFAULT_ENTRY_FLAGS); + identityMapTable(newDir, 2, DEFAULT_ENTRY_FLAGS); + + setActivePageDir(newDir); + + // first and second entry of page table at index 1 + PageTableEntry *entry1 = vaddrTableEntry(newDir, BOUND); + PageTableEntry *entry2 = vaddrTableEntry(newDir, BOUND + PAGE_SIZE); + ASSERT(entry1 == &tables[1].entries[0]); + ASSERT(entry2 == &tables[1].entries[1]); + + // volatile is extremely important here, or else gcc will optimize our tests to fail + volatile uint32_t *baseLocation = (uint32_t *)(BOUND); + volatile uint32_t *magicLocation = (uint32_t *)(BOUND + PAGE_SIZE); + + // setup values + *baseLocation = 0xdeadbeef; + *magicLocation = 123; + ASSERT(*baseLocation == 0xdeadbeef); + ASSERT(*magicLocation == 123); + + // map 4th MiB + 1 page to 4th MiB page + setEntryAddr(entry2, BOUND); + resetTLB(); // ensure change is seen by MMU + + *magicLocation = 0x1337; + ASSERT(*baseLocation == 0x1337); + + // map back + setEntryAddr(entry2, BOUND + PAGE_SIZE); + resetTLB(); + + ASSERT(*magicLocation == 123); + + // swap back + setActivePageDir(base); + + char done[] = "test_modify_in_place done\n"; + serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); +} + void test_main() { test_composition(); @@ -113,4 +165,6 @@ void test_main() { test_identity(idDir); test_swap_page(idDir); + + test_modify_in_place(idDir); } \ No newline at end of file From e264b25982763c9f5927b0162fed064a8781ac42 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 23 Apr 2023 16:03:53 -0400 Subject: [PATCH 07/15] ran formatter --- tests/src/os/paging.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index 31d462b..06161af 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -104,7 +104,7 @@ void test_swap_page(PageDirectory *base) { serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } -void test_modify_in_place(PageDirectory* base) { +void test_modify_in_place(PageDirectory *base) { // steal the 3MiB page and 3 more PageDirectory *newDir = (PageDirectory *)(MiB3); PageTable *tables = (PageTable *)(MiB3 + sizeof(PageDirectory)); @@ -126,13 +126,14 @@ void test_modify_in_place(PageDirectory* base) { ASSERT(entry1 == &tables[1].entries[0]); ASSERT(entry2 == &tables[1].entries[1]); - // volatile is extremely important here, or else gcc will optimize our tests to fail + // volatile is extremely important here, or else gcc will optimize our tests + // to fail volatile uint32_t *baseLocation = (uint32_t *)(BOUND); volatile uint32_t *magicLocation = (uint32_t *)(BOUND + PAGE_SIZE); // setup values *baseLocation = 0xdeadbeef; - *magicLocation = 123; + *magicLocation = 123; ASSERT(*baseLocation == 0xdeadbeef); ASSERT(*magicLocation == 123); From 2618a50073b31c8db35df97b418ef1c5ed2da2fc Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Mon, 24 Apr 2023 20:51:42 -0400 Subject: [PATCH 08/15] docs --- docs/os/paging.md | 50 +++++++++++++++++++++++++++++++++++++++ docs/os/vaddr_decomp.png | Bin 0 -> 14307 bytes 2 files changed, 50 insertions(+) create mode 100644 docs/os/paging.md create mode 100644 docs/os/vaddr_decomp.png diff --git a/docs/os/paging.md b/docs/os/paging.md new file mode 100644 index 0000000..085d722 --- /dev/null +++ b/docs/os/paging.md @@ -0,0 +1,50 @@ +# Paging + +## MMU and You + +The Memory Management Unit (MMU) is responsible for translating "virtual" addresses to "physical" addresses. A "physical" address is an address that maps directly to a system's memory. On the other hand, a "virtual" address is an address that indirectly maps to a system's memory. When addresses are identity mapped, a virtual address is equivalent to a physical address (in that context). + +The MMU will always translate addresses once it is enabled (via `cr0`). However, this creates overhead for one of the most frequent operations. To minimize this overhead, the MMU maintains a cache referred to as the Translation Lookaside Buffer (TLB). Since the TLB doesn't constantly monitor if the translation tables are modified, it must be invalidated whenever a change is made. This takes the form of either `mov eax, cr3; mov cr3, eax` or `invlpg eax`. The first essentially sets the active translation context to itself, while `invlpg` is a dedicated instruction for invalidating just 1 page (although it may invalidate more). + +## Page Directory + +A Page Directory is a translation context. There can be many, and multiprocess operating systems may give each process its own page directory. However, only one is active at a time, the address of which can be found in `cr3`. The structure itself is 4KiB and consists of 1024 4-byte entries (for 32-bit x86). Each entry consists of 20-bits of address pointing to a page aligned Page Table, several flags, and some available bits. The important flags are Present, Accessed, Cache Disable, Write Through, Read/Write, User/Supervisor. + +- Present signifies that the table exists, if this is false, when the MMU tries to access this entry it will cause a page fault. +- Accessed is set to 1 whenever the MMU accesses that entry, this value should be reset by the OS if the OS intends to use it. +- Cache Disable, as the name implies, prevents the entry from being cached into the TLB. +- Write Through is when data is written to both cache and main memory at the same time, when this flag is 0 write back is used instead. Write back is when cache is used until the cache is invalidated where it then writes to main memory. +- Read/Write and User/Supervisor are permission flags that control who and what is allowed to interact with certain pages. + +## Page Table + +A Page Table is what determines which physical address is mapped to a virtual address. There are 1024 per page directory, and similarly the structure itself is 4KiB. The structure MUST be page aligned (since the page directory only stores the top 20-bits). The structure consists of 1024 4-byte entries (for 32-bit x86). Each entry consists of 20-bits of address pointing to a 4KiB page in physical memory, several flags, and some available bits. The important flags are the same as the Page Directory, with the addition of the Dirty bit. The dirty bit is set whenever the page is written to, the OS should reset this bit if it wishes to use it. + +### Virtual Address Decomposition + +A virtual address is comprised of 3 parts, a table index, a entry index, and an offset. The table and entry indexes are 10-bits giving them a range of [0, 1024). The offset is 12-bits, which is [0, 4096). + +The following diagram shows a decomposition. The construction of a physical address requires having a page directory populated with tables. + +[Decomposition](vaddr_decomp.png) + +### Mappings + +(In the context of a single directory) + +Identity mapping is when virtual addresses are the same as physical addresses. + +1:1 mapping is when each virtual address maps uniquely to a physical address. Identity mapping is a 1:1 mapping. + +N:1 mapping is when multiple virtual addresses map to a phsyical address. + +1:N mapping can only occur with multiple directories. + +#### Further Reading + +[Paging](https://wiki.osdev.org/Paging) +[Page Tables](https://wiki.osdev.org/Page_Tables) +[Identity Paging](https://wiki.osdev.org/Identity_Paging) +[MMU](https://wiki.osdev.org/Memory_Management_Unit) +[TLB](https://wiki.osdev.org/TLB) +[invlpg](https://www.felixcloutier.com/x86/invlpg) diff --git a/docs/os/vaddr_decomp.png b/docs/os/vaddr_decomp.png new file mode 100644 index 0000000000000000000000000000000000000000..38b6ff131eedf419595d3ba50d9806733cb24b55 GIT binary patch literal 14307 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 xEP@Q=(N7?cR?Cn Date: Sun, 11 Jun 2023 15:26:36 -0400 Subject: [PATCH 09/15] Move macros --- src/os/paging.c | 9 +-------- src/os/paging.h | 9 +++++++++ tests/src/os/paging.c | 5 +++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index a033dc7..1f47080 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -2,14 +2,7 @@ #include "stdlib/string.h" -/*The page directory and it's tables must be 4KiB aligned (0x1000) - * 0x90000 is the start of the stack, in other words, - * the areas from 0x1000 to 0x90000 are in use! - * But there is a nice open region we can use from 0x91000 - 0x9f000 - * (We technically have until 0x9fc00 before we enter ExBIOS data) - */ - -#define ID_PAGE_DIRECTORY_BASE 0x91000 + // room for 3 page tables (12 MiB of mapped memory) #define IDENTITY_PT_BASE 0x92000 diff --git a/src/os/paging.h b/src/os/paging.h index 52a8d27..5ea1598 100644 --- a/src/os/paging.h +++ b/src/os/paging.h @@ -8,6 +8,15 @@ typedef uint32_t PageDirectoryEntry; typedef uint32_t PageTableEntry; +/*The page directory and it's tables must be 4KiB aligned (0x1000) + * 0x90000 is the start of the stack, in other words, + * the areas from 0x1000 to 0x90000 are in use! + * But there is a nice open region we can use from 0x91000 - 0x9f000 + * (We technically have until 0x9fc00 before we enter ExBIOS data) + */ + +#define ID_PAGE_DIRECTORY_BASE 0x91000 + #define PAGE_ENTRY_COUNT 1024 #define PAGE_SIZE 0x1000 diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index 06161af..01c64dd 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -11,6 +11,9 @@ // placed so that the test goes over the table 0 and table 1 boundary #define IDENT_LOCATION ((MiB1 * 4) - PAGE_SIZE) +// 4MiB +#define BOUND ((void *)(MiB1 * 4)) + void assert_identity(PageDirectory *dir, void *addr) { ASSERT(vaddrToPaddr(dir, addr) == addr); } @@ -49,8 +52,6 @@ void test_composition(void) { serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } -#define BOUND ((void *)(MiB1 * 4)) - void test_swap_page(PageDirectory *base) { // steal the 3MiB page and 3 more PageDirectory *newDir = (PageDirectory *)(MiB3); From 26be8323602a53626a8098a80f9d1661f538a850 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 11 Jun 2023 15:26:57 -0400 Subject: [PATCH 10/15] formater --- src/os/paging.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 1f47080..af091e4 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -2,8 +2,6 @@ #include "stdlib/string.h" - - // room for 3 page tables (12 MiB of mapped memory) #define IDENTITY_PT_BASE 0x92000 #define IDENTITY_PT_LIMIT 0x95000 From ae2a6761f14a27c26e25dbf1650c90294ec5ac35 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 10 Sep 2023 12:53:00 -0400 Subject: [PATCH 11/15] comments + no binary --- src/os/paging.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index af091e4..f99682b 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -37,7 +37,10 @@ PageDirectory *getActivePageDir(void) { return dir; } -void resetTLB(void) { setActivePageDir(getActivePageDir()); } +void resetTLB(void) { + // setting the active directory to the current updates the TLB + setActivePageDir(getActivePageDir()); +} #define PAGE_TABLE_OFFSET 22 #define PAGE_ENTRY_OFFSET 12 @@ -49,11 +52,15 @@ uint16_t vaddrDirectoryIdx(const void *vaddr) { // middle 10 bits uint16_t vaddrEntryIdx(const void *vaddr) { - return ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0b1111111111; + // shifted right 12 then 10-bit mask + return ((uint32_t)(vaddr) >> PAGE_ENTRY_OFFSET) & 0x3ff; } // low 12 bits -uint16_t vaddrOffset(const void *vaddr) { return (uint32_t)(vaddr)&0xfff; } +uint16_t vaddrOffset(const void *vaddr) { + // 12-bit mask + return (uint32_t)(vaddr)&0xfff; +} void *toVaddr(uint16_t dirIdx, uint16_t entryIdx, uint16_t offset) { uint32_t vaddr = offset; From b94b1d853bd2c4c50a0a08aca71795c4ef183e60 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 10 Sep 2023 12:54:17 -0400 Subject: [PATCH 12/15] missed a comment --- src/os/paging.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/os/paging.c b/src/os/paging.c index f99682b..52cb1a4 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -13,7 +13,10 @@ bool pageTablePresent(PageDirectoryEntry tableEntry) { return tableEntry & ENTRY_PRESENT; } -bool pageEntryPresent(PageTableEntry entry) { return entry & ENTRY_PRESENT; } +bool pageEntryPresent(PageTableEntry entry) { + // mask out all but first bit + return entry & ENTRY_PRESENT; +} void setEntryAddr(PageTableEntry *entry, const void *addr) { if (entry == NULL) From 55b5ddbbe45487c319080142a356fffc1c04bf52 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Sun, 10 Sep 2023 23:42:29 -0400 Subject: [PATCH 13/15] at&t syntax --- src/os/paging.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/os/paging.c b/src/os/paging.c index 52cb1a4..129663b 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -29,13 +29,13 @@ void setActivePageDir(PageDirectory *dir) { if (dir == NULL) dir = idendirectory; - __asm__ volatile("mov cr3, %0" : : "a"(dir)); + __asm__ volatile("mov %0, %%cr3" : : "a"(dir)); } PageDirectory *getActivePageDir(void) { PageDirectory *dir = NULL; - __asm__ volatile("mov %0, cr3" : "=r"(dir)); + __asm__ volatile("mov %%cr3, %0" : "=r"(dir)); return dir; } @@ -148,7 +148,7 @@ void initPaging(void) { setActivePageDir(idendirectory); // enable paging flags in cr0 - __asm__ volatile("mov eax, cr0\n\t" - "or eax, 0x80000001\n\t" - "mov cr0, eax"); + __asm__ volatile("mov %cr0, %eax \n\t" + "or $0x80000001, %eax\n\t" + "mov %eax, %cr0"); } \ No newline at end of file From d4654b995b74d3197deedc40c842b292b13c1beb Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Tue, 12 Sep 2023 22:55:42 -0400 Subject: [PATCH 14/15] small changes --- docs/os/paging.md | 2 +- src/os/paging.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/os/paging.md b/docs/os/paging.md index 085d722..420c46d 100644 --- a/docs/os/paging.md +++ b/docs/os/paging.md @@ -26,7 +26,7 @@ A virtual address is comprised of 3 parts, a table index, a entry index, and an The following diagram shows a decomposition. The construction of a physical address requires having a page directory populated with tables. -[Decomposition](vaddr_decomp.png) +![Decomposition](vaddr_decomp.png) ### Mappings diff --git a/src/os/paging.c b/src/os/paging.c index 129663b..1fdda44 100644 --- a/src/os/paging.c +++ b/src/os/paging.c @@ -7,6 +7,8 @@ #define IDENTITY_PT_LIMIT 0x95000 #define TABLE_COUNT ((IDENTITY_PT_LIMIT - IDENTITY_PT_BASE) / 0x1000) +#define MiB4 0x400000 + PageDirectory *idendirectory = (PageDirectory *)(ID_PAGE_DIRECTORY_BASE); bool pageTablePresent(PageDirectoryEntry tableEntry) { @@ -114,7 +116,7 @@ void identityMapTable(PageDirectory *directory, uint16_t idx, uint32_t flags) { // 4GiB per directory // 4MiB per table - uint32_t baseAddr = idx * 0x400000; + uint32_t baseAddr = idx * MiB4; for (uint32_t page_idx = 0; page_idx < PAGE_ENTRY_COUNT; ++page_idx) { PageTableEntry entry = flags & ~(ENTRY_ADDR); From 6bbedcc93da22cbfdee8732909210adfe1646430 Mon Sep 17 00:00:00 2001 From: Sploder12 Date: Fri, 28 Feb 2025 21:30:01 -0500 Subject: [PATCH 15/15] Add page fault test gcc makes things so difficult --- tests/expected/os/paging.expect | 1 + tests/src/os/paging.c | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/tests/expected/os/paging.expect b/tests/expected/os/paging.expect index a6be962..bedff05 100644 --- a/tests/expected/os/paging.expect +++ b/tests/expected/os/paging.expect @@ -2,3 +2,4 @@ test_composition done test_identity done test_swap done test_modify_in_place done +test_entry_not_present done diff --git a/tests/src/os/paging.c b/tests/src/os/paging.c index 01c64dd..9915d9f 100644 --- a/tests/src/os/paging.c +++ b/tests/src/os/paging.c @@ -1,5 +1,6 @@ #include "../test_helper.h" +#include <../os/hard/idt.h> #include <../os/paging.h> // 1st megabyte is a safe place to read from, but not to write to @@ -158,6 +159,60 @@ void test_modify_in_place(PageDirectory *base) { serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); } +volatile uint32_t errCode = -1; + +void test_handler(isr_registers_t *regs) { + errCode = regs->err_code; + + // We are manually incrementing the instruction pointer. + // This is to avoid faulting on the same instruction forever. + // But it can cause some unexpected things to happen. + regs->eip++; +} + +void assert_on_fault_code(uint32_t expected) { + InterruptState iprev = disableInterrupts(); + uint32_t got = errCode; + errCode = -1; + setInterrupts(iprev); + + // ASSERT must be called with interrupts enabled! + ASSERT_M(expected == got, "Expected %i but got %i as fault error code.", + expected, got); +} + +void test_entry_not_present(PageDirectory *base) { + // steal the 3MiB page and 2 more + PageDirectory *newDir = (PageDirectory *)(MiB3); + PageTable *tables = (PageTable *)(MiB3 + sizeof(PageDirectory)); + + // setup identity paged dir + addTableToDirectory(newDir, 0, tables, DEFAULT_ENTRY_FLAGS); + addTableToDirectory(newDir, 1, tables + 1, DEFAULT_ENTRY_FLAGS); + + identityMapTable(newDir, 0, DEFAULT_ENTRY_FLAGS); + identityMapTable(newDir, 1, ENTRY_RW | ENTRY_US); + + setActivePageDir(newDir); + + volatile uint32_t *faulter = (uint32_t *)(BOUND); + + // cause a page fault + *faulter; + + // this nop helps eip++ not do bad things + __asm__ volatile("nop"); + + // confusingly, the not present error code is 0. + assert_on_fault_code(0); + + // swap back + setActivePageDir(base); + + char done[] = "test_entry_not_present done\n"; + serialWrite(COM1, (uint8_t *)(done), sizeof(done) - 1); +} + void test_main() { test_composition(); @@ -169,4 +224,9 @@ void test_main() { test_swap_page(idDir); test_modify_in_place(idDir); + + // beware the page fault handler is overriden from this point on. + isrSetHandler(14, test_handler); + + test_entry_not_present(idDir); } \ No newline at end of file