From 7d0791d806db12199d2d8f5c388563498d85df79 Mon Sep 17 00:00:00 2001 From: Furkan Mudanyali Date: Fri, 22 Jul 2022 17:50:10 +0300 Subject: [PATCH] Paging --- .gitignore | 1 + README.md | 29 +++++++++++++-- build-toolchain.sh | 7 +++- kernel/include/rockos/paging.h | 8 ++++- kernel/rockos/kernel.c | 30 +++++++++++++--- kernel/rockos/paging.c | 64 +++++++++++++++++++++++++++++++--- 6 files changed, 126 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 47bd505..a312394 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.iso isodir sysroot +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 42b6b8d..1a2846a 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,31 @@ Welcome to rockOS project, a hobby OS that aims to run rogue and nethack. - GDT - IDT - PIC initialization -- Semi-working keyboard driver -- Paging initialization +- PIT timer +- Keyboard driver +- Bitmap paging + + +## Usage +Just grab the latest ISO from the releases and run it on a virtual machine +such as QEMU or Virtualbox, bare-metal not tested. + +## Build +### Dependencies +- a decent compiler such as gcc or clang +- grub2 (if under GNU/Linux) +- xorriso +- make +- tar (for compiling the toolchain) +- wget/curl (for compiling the toolchain) + +If it is your first time building, you need to compile the toolchain first. +For that, you just need to run build-toolchain.sh, which will download binutils, +gcc, grub if youre on macOS, and then compile them to $HOME/opt/cross-i686 by default +which can be changed from the prompt. + +After you compiled the toolchain and added $PREFIX/bin to your PATH as instructed by the script, +you can run qemu.sh to compile and open the OS on QEMU or iso.sh to just generate the ISO. ## Credits @@ -15,7 +38,7 @@ Welcome to rockOS project, a hobby OS that aims to run rogue and nethack. ## Acknowledgements -- osdev.org community for huge documentation on osdev +- osdev.org community for huge documentation on OS Development - musl for libc implementation diff --git a/build-toolchain.sh b/build-toolchain.sh index 8e6aa0d..3a8f455 100755 --- a/build-toolchain.sh +++ b/build-toolchain.sh @@ -1,7 +1,8 @@ #!/bin/sh #export PREFIX="$HOME/opt/cross-i686" -echo "Welcome to rockOS toolchain compilation script, where would you like to install your toolchain?\nLeave blank for $HOME/opt/cross-i686" +echo "Welcome to rockOS toolchain compilation script, where would you like to install your toolchain?" +echo "Leave blank for $HOME/opt/cross-i686" read PREFIX @@ -9,6 +10,10 @@ if [ "$PREFIX" == "" ]; then export PREFIX="$HOME/opt/cross-i686" fi +echo "This is the location you chose: $PREFIX" +echo "Press Enter to continue" +read continue + mkdir -p "$PREFIX" export TARGET=i686-elf export PATH="$PREFIX/bin:$PATH" diff --git a/kernel/include/rockos/paging.h b/kernel/include/rockos/paging.h index ffc86d9..775b16b 100644 --- a/kernel/include/rockos/paging.h +++ b/kernel/include/rockos/paging.h @@ -16,10 +16,16 @@ * along with this program. If not, see . */ +#include + #ifndef _ROCKOS_PAGING_H #define _ROCKOS_PAGING_H #define PAGE_ENTRIES 1024 -#define PAGE_SIZE 4 * PAGE_ENTRIES +#define PAGE_SIZE 4096 + +uint32_t* get_page(); +void set_page_free(uint32_t*); +uint32_t get_used_memsize(); #endif \ No newline at end of file diff --git a/kernel/rockos/kernel.c b/kernel/rockos/kernel.c index ff34bd5..20979f7 100644 --- a/kernel/rockos/kernel.c +++ b/kernel/rockos/kernel.c @@ -5,6 +5,7 @@ #include #include #include +#include void kernel_main(void) { printf("Hello, kernel World!\n"); @@ -15,13 +16,34 @@ void kernel_main(void) { printf("And now for 0.1 + 0.2...... which is: %.17f\n", 0.1 + 0.2); initialize_keyset(); - outb(0x70, (0x80 << 7) | 0x0); // Seconds + outb(0x70, 0x0); // Seconds uint8_t sec = inb(0x71); - outb(0x70, (0x80 << 7) | 0x02); // Minutes + outb(0x70, 0x02); // Minutes uint8_t min = inb(0x71); - outb(0x70, (0x80 << 7) | 0x04); // Hours + outb(0x70, 0x04); // Hours uint8_t hour = inb(0x71); - printf("Time: %x:%x:%x\n", hour, min, sec); + // BCD to binary conversion + sec = (sec & 0x0F) + ((sec / 16) * 10); + min = (min & 0x0F) + ((min / 16) * 10); + hour = ((hour & 0x0F) + (((hour & 0x70) / 16) * 10)) | (hour & 0x80); + printf("Time: %02d:%02d:%02d UTC+3\n", (hour + 3) % 24, min, sec); + + uint32_t first = get_used_memsize(); + uint32_t limit = 1024 * 8; + uint32_t* pages[limit]; + + for(uint32_t i = 0; i < limit; i++) { + pages[i] = get_page(); + } + uint32_t middle = get_used_memsize(); + + for(uint32_t i = 0; i < limit; i++) { + set_page_free(pages[i]); + } + uint32_t last = get_used_memsize(); + + printf("Before Allocation: %d KiB\nAfter allocation: %d KiB\nAfter Clear: %d KiB\n", first, middle, last); + printf("Finished!\n"); unsigned char key; for(;;) { diff --git a/kernel/rockos/paging.c b/kernel/rockos/paging.c index ae47352..b0f3f67 100644 --- a/kernel/rockos/paging.c +++ b/kernel/rockos/paging.c @@ -18,24 +18,80 @@ void enable_paging() { ); } +static uint32_t page_dir[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); +static uint32_t first_page_table[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); + void paging_init() { - uint32_t page_dir[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); for(int i = 0; i < PAGE_ENTRIES; i++) { // Supervisor: only kernel-mode can access // Write Enabled: Can be both read and written to // Not Present: Page table not present page_dir[i] = 0x00000002; } - - uint32_t first_page_table[PAGE_ENTRIES] __attribute__((aligned(PAGE_SIZE))); + for(unsigned int i = 0; i < PAGE_ENTRIES; i++) { // As the address is page aligned, it will leave 12 bits zeroed, // which are used by the attributes. - first_page_table[i] = (i * 0x1000) | 3; // attr: supervisor, r/w, present + first_page_table[i] = (i * 0x1000) | 0x103; // attr: supervisor, r/w, present, 9th bit set } page_dir[0] = ((unsigned int)first_page_table) | 3; //attr: supervisor, r/w, present load_page_dir(page_dir); enable_paging(); +} + +uint32_t* get_page() { + // Search directories for tables + for (int i = 0; i < PAGE_ENTRIES; ++i) { + // If table is found (if 2nd and 1st bit are set) + if((page_dir[i] & 0x3) == 0x3) { + // Cast table location + uint32_t *mytable = (uint32_t*)((page_dir[i] >> 12) << 12); + // Search table for pages + for(int j = 0; j < PAGE_ENTRIES; ++j) { + // If page is found (9th, 2nd, 1st bit set) + if((mytable[j] & 0x103) == 0x103) { + mytable[j] &= ~0x100; // Unset 9th bit + return &mytable[j]; + } + } // No page found till last entry + // Check if next table is not initialized + if((page_dir[i+1] & 0x3) != 0x3) { + // The last page of previous table points to the next table + uint32_t *newtable = &mytable[2*PAGE_ENTRIES]; + for(int k = 0; k < PAGE_ENTRIES; ++k) { + newtable[k] = (k * 0x1000) | 0x103; // attr: supervisor, r/w, present, 9th bit set + } + page_dir[i+1] = ((unsigned int)newtable) | 3; //attr: supervisor, r/w, present + } + } + } + return 0; +} + +void set_page_free(uint32_t* addr) { + // Set 9th, 2nd and 1st bits + *(addr) |= 0x103; +} + +uint32_t get_used_memsize() { + uint32_t used = 0; + // Iterate over page_dirs + for(int i = 0; i < PAGE_ENTRIES; ++i) { + // If a table is available + if((page_dir[i] & 3) == 3) { + // Cast the table + uint32_t* table = ((page_dir[i] >> 12) << 12); + // Iterate over table + for(int j = 0; j < PAGE_ENTRIES; ++j) { + // If a page is unavailable + if((table[j] & 0x103) != 0x103) { + // Then it is used + used += 4*4; + } + } + } + } + return used; } \ No newline at end of file