diff --git a/Makefile b/Makefile index 5cbd34e..bece67e 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ eos_grub.iso : kernel.bin grub/grub.cfg eos.iso: bootloader/bootloader.bin kernel.bin cat $^ > eos.iso -kernel.bin: kernel/kernel_entry.o $(OBJ) +kernel.bin: kernel/kernel_entry.o kernel/sr_memory.o kernel/enable_paging.o $(OBJ) gcc -o $@ $^ -Wl,--oformat=binary -ffreestanding -nostdlib -shared -Ttext 0x1000 -m32 diff --git a/drivers/vga.c b/drivers/vga.c index 45096a0..8821fe7 100644 --- a/drivers/vga.c +++ b/drivers/vga.c @@ -1,31 +1,37 @@ // VGA Graphics Library #include "vga.h" +#include "../lib/types.h" #include "../kernel/io.h" +#include "../kernel/memory.h" #include "../lib/str.h" +#include "../lib/conv.h" -static unsigned int cursor_row = 0; -static unsigned int cursor_col = 0; +static uint cursor_row = 0; +static uint cursor_col = 0; void vga_init() { + // Allocate VGA memory range + pm_alloc_range(VGA_ADDRESS, VGA_ADDRESS_MAX, true); // force alloc the VGA range + // Disable cursor port_outb(0x3d4, 0x0a); port_outb(0x3d5, 0x20); // Clear screen // clear_row(0); - // clear_screen(); + clear_screen(); - set_cursor_pos(0, 11); + set_cursor_pos(0, 0); } /* VGA & Memory Functions */ -char* get_memory_charpos(unsigned int col, unsigned int row) { +char* get_memory_charpos(uint col, uint row) { return (char*)(VGA_ADDRESS + 2*((row*80) + col)); } -void writechar(char c, unsigned int col, unsigned int row, int attribute_byte) { +void writechar(char c, uint col, uint row, int attribute_byte) { if( !attribute_byte ) attribute_byte = DEFAULT_COLOR; @@ -36,7 +42,7 @@ void writechar(char c, unsigned int col, unsigned int row, int attribute_byte) { } -void set_cursor_pos(unsigned int col, unsigned int row) { +void set_cursor_pos(uint col, uint row) { cursor_col = col; cursor_row = row; } @@ -45,7 +51,7 @@ void set_cursor_pos(unsigned int col, unsigned int row) { /* Graphics Functions */ -void clear_row(unsigned int row) { +void clear_row(uint row) { for( int c = 0; c < MAX_COLS; c++ ) writechar(0x20, c, row, 0x0); } @@ -61,7 +67,7 @@ void clear_screen() { */ void print(char* str, int attribute_byte) { for( char* c = str; *c != '\0'; c++ ) - writechar(*c, (unsigned int)(c - str) + cursor_col, cursor_row, attribute_byte); + writechar(*c, (uint)(c - str) + cursor_col, cursor_row, attribute_byte); } void println(char* str, int attribute_byte) { @@ -69,11 +75,20 @@ void println(char* str, int attribute_byte) { cursor_row++; // Increment to next y-pos (newline) } +void printint(int i, int attribute_byte) { + /* + char* strbuf; + + strbuf = int_to_str(i, strbuf); + println(strbuf, attribute_byte); + */ +} + void printalign(char* str, int attribute_byte, enum align alignment) { - unsigned int strlenbuf = strlen(str); + uint strlenbuf = strlen(str); if( !alignment || alignment == LEFT ) { - print(str, attribute_byte); + set_cursor_pos(0, cursor_row); } else if ( alignment == RIGHT ) { set_cursor_pos(MAX_COLS - strlenbuf, cursor_row); } else if ( alignment == MIDDLE ) { @@ -81,4 +96,5 @@ void printalign(char* str, int attribute_byte, enum align alignment) { } print(str, attribute_byte); + set_cursor_pos(0, cursor_row+1); } diff --git a/drivers/vga.h b/drivers/vga.h index 82c5af4..0ba4f1f 100644 --- a/drivers/vga.h +++ b/drivers/vga.h @@ -1,7 +1,10 @@ -#define VGA_ADDRESS (char*)0xb8000 -#define VGA_ADDRESS_MAX (char*)0xb8fa0 +#define VGA_ADDRESS 0xb8000 +#define VGA_ADDRESS_MAX 0xb8fa0 #define DEFAULT_COLOR 0x07 +#define URGET_COLOR 0x0c +#define SUCCESS_COLOR 0x0a + #define MAX_ROWS 25 #define MAX_COLS 80 @@ -17,5 +20,6 @@ void clear_row(unsigned int row); void set_cursor_pos(); void print(); void println(); +void printint(int i, int attribute_byte); void printalign(char* str, int attribute_byte, enum align alignment); void vga_init(); diff --git a/kernel/enable_paging.asm b/kernel/enable_paging.asm new file mode 100644 index 0000000..9a12923 --- /dev/null +++ b/kernel/enable_paging.asm @@ -0,0 +1,23 @@ +[bits 32] ; 32-bit mode + +PAGING_ENABLE_FLAG equ 0x80000001 +PAGE_DIRECTORY_ADDR equ 0xffffffff ; TODO: change me to something good + +global enable_paging_registers ; make the SR "global" so that we can access it in the kernel etc +enable_paging_registers: + push eax + mov eax, PAGE_DIRECTORY_ADDR ; Move the address of the + ; page register (page directory) into eax + ; (Using eax as a middle-man register) + mov cr3, eax ; Put the address into the cr3 register (required by the MMU) + + mov eax, cr0 ; eax as a middle-man register (again) + or eax, PAGING_ENABLE_FLAG ; perform the OR operation on eax (ex: 0b01 or 0b10 = 0b11) + ; This is needed to enable paging (set the flag as "enabled") + + mov cr0, eax ; Move it into cr0 to finally enable paging + + pop eax + ret ; return to last location + + diff --git a/kernel/kernel.c b/kernel/kernel.c index ff1adce..2005a4d 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,23 +1,20 @@ #include "kernel.h" #include "memory.h" +#include "paging.h" #include "../drivers/vga.h" #include "../lib/str.h" -#include "../lib/strf.h" - -void display_status(char* status_text, unsigned int bg_color) { - clear_row(0); - set_cursor_pos(0, 0); - - print(status_text, bg_color | STATUS_TEXT_COLOR); -} +#include "../lib/conv.h" void init() { - display_status("Kernel loaded", 0x70); - vga_init(); // Initialize the screen first // i.e. clear the screen et cetera. - char* title = "eOS Version 0.2 2021"; + println("Kernel loaded", SUCCESS_COLOR); + + // enable_paging(); + + println(""); + char* title = "eOS Version 0.3 2021"; println(title, DEFAULT_COLOR); char* subtitle = "A x86 operating system, licenced under GPL-2.0"; @@ -28,8 +25,35 @@ void init() { println("0x1000", DEFAULT_COLOR); */ + + char* intbuf = "xxxx"; + int num = 1234; + intbuf = int_to_str(num, intbuf); + print("TEST NUM: ", DEFAULT_COLOR); + println(intbuf, DEFAULT_COLOR); + + /* + + // Memory allocation testing + printalign("-- PMM Tests --", DEFAULT_COLOR, MIDDLE); + + println("THESE ALLOC SHOULD WORK:", 0xa0); + for(int i=0; i < 4; i++) { + block_alloc(i); + } + + println("(2) THIS ALLOC SHOULD FAIL:", 0xc0); + block_alloc(2); // this should fail + + println("(2) Freeing 2nd block, alloc after should succeed", DEFAULT_COLOR); + block_free(2); // after this, allocation of 2nd block should work + block_alloc(2); + + printalign("-- End of PMM Tests --", DEFAULT_COLOR, MIDDLE); + char* strbuf = "Concat test: "; char* str2 = "Works!"; strbuf = strcat(strbuf, str2); println(strbuf, DEFAULT_COLOR); + */ } diff --git a/kernel/memory.c b/kernel/memory.c index 8c5815e..265121e 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -1,2 +1,102 @@ #include "memory.h" +#include "../drivers/vga.h" +// https://wiki.osdev.org/Page_Frame_Allocation +// page = block + +// MAX_BLOCK_SIZE_IN_BITS/8 bytes +// i.e. : bit i of byte n define status of block 8n+i +// block = 8n+i + +// in 32-bit mode, we have access to 2^32 blocks +// which is (2^32)*BLOCK_SIZE blocks +// and with a blocksize of 1024, we git around 4.3 trillion blocks +// which is more than enough + +#define CHECK_BITMAP(map, idx) ((map) & (1<<(idx))) + +#define BLOCK_TO_MEMP(idx) (pointer)(PM_MEM_START + (idx*BLOCK_SIZE)) + +#define MEMP_TO_BLOCK(memp) (uint)((memp - PM_MEM_START)/BLOCK_SIZE) + +static int bitmap = 0; +static uint last_block; +void mod_bitmap(uint bit, uint bflag) { + // create a bitmask that will be applied to the bitmap + int bitmask = 1 << bit; + + // apply the bitmask, resulting in the bit:n bit will set + // set to bflag + bitmap = (((bitmap & ~bitmask)) | (bflag << bit)); +} + + +pointer block_alloc(uint blockidx) { + int block_bflag; + block_bflag = CHECK_BITMAP(bitmap, blockidx); + + if( block_bflag == BM_FREE ) { // check if block is free + println("Allocating block...", DEFAULT_COLOR); + + mod_bitmap(blockidx, 1); + last_block = blockidx; + + return BLOCK_TO_MEMP(blockidx); + } else { + println("[ERROR] Attemped to allocate non-free block.", 0x0c); + + return 0; + } +} + +void block_free(uint blockidx) { + println("Dealloc block...", DEFAULT_COLOR); + mod_bitmap(blockidx, BM_FREE); + last_block = blockidx; +} + +uint find_free(uint block_count) { + // TODO: find a free start block to allocate + // loop through bitmap + // check if range is free +} + +bool check_block_range(uint start, uint end) { + bool allowed = true; + + uint idx; + for(idx = start; idx <= end; idx++) { + if( CHECK_BITMAP(bitmap, idx) != BM_FREE ) + allowed = false; + break; + } + + return allowed; +} + +void pm_alloc_range(ulong start, ulong end, bool force) { + uint idx_start; + uint idx_end; + + ulong d_addr = end - start; // memory size + uint num_blocks = (d_addr/BLOCK_SIZE) + 1; // amount of blocks to be allocated + + uint start_block = MEMP_TO_BLOCK(start); // start idx, end = start_block + num_blocks - 1 + bool allowed = true && check_block_range(start_block, start_block + num_blocks - 1); + + // allocate (if permitted) + if( allowed ) { + uint idx; + for(idx=start_block; idx <= start_block + num_blocks - 1; idx++) + block_alloc(idx); + + return; + } else { + println("[ERROR] Tried to allocate memory range without permission!", 0x0c); + return; + } +} + +pointer pm_malloc(uint block_count) { + +} diff --git a/kernel/memory.h b/kernel/memory.h index b2b140d..f6fce88 100644 --- a/kernel/memory.h +++ b/kernel/memory.h @@ -1,2 +1,25 @@ -char* malloc(unsigned int size); -void mfree(char* p); +#include "../lib/types.h" + +#define BLOCK_SIZE 1024 // 1 KiB +#define MAX_BLOCK_COUNT 32 // placeholder +#define MEMSIZE_TO_BLOCKS(n) ((n*1024)/BLOCK_SIZE) + +#define BM_FREE 0 + +#define PM_MEM_START 0x000000 // start of memory +#define PM_MEM_END 0xb7000 // end of memory TODO: fix me/change or something + +// void init_pmm(uint map_addr, uint bsize); // Initialize physical memory manager + +void mod_bitmap(uint bit, uint flag); + +pointer block_alloc(uint blockidx); // allocate a block +void block_free(uint blockidx); // free a block + +uint find_free(uint block_count); + +bool check_block_range(uint start, uint end); +void pm_alloc_range(ulong start, ulong end, bool force); // allocate a range of memory + +pointer pm_malloc(uint block_count); // allocate some blocks +void pm_free(int* p); // free a var (if allocated with pm_malloc) diff --git a/kernel/paging.c b/kernel/paging.c new file mode 100644 index 0000000..3f020b8 --- /dev/null +++ b/kernel/paging.c @@ -0,0 +1,24 @@ +#include "paging.h" +#include "../drivers/vga.h" + +void enable_paging() { + println("Enabling paging...", DEFAULT_COLOR); + + // extern int enable_paging_registers(); // Call the assembly SR + // enable_paging_registers(); // and enable paging + + return; +} + +// Page Entry struct +//struct page_entry { +// unsigned int index; +// unsigned int start_addr; +//} page_table[PAGE_TABLE_SIZE]; +// +//int get_phys_addr(int virt_addr) { +// int index = virt_addr / PAGE_SIZE; // page index for the virtual address +// int offset = virt_addr % PAGE_SIZE; // actual physical offset for the address +// +// return page_table[index].start_addr + offset; +//} diff --git a/kernel/paging.h b/kernel/paging.h new file mode 100644 index 0000000..a1e88ff --- /dev/null +++ b/kernel/paging.h @@ -0,0 +1,9 @@ +#define PAGE_SIZE 100 +#define PAGE_TABLE_SIZE 128 + +void enable_paging(); + +// struct page_entry; + +// char** heap_alloc(unsigned int size); // Process heap allocation +// int get_phys_addr(int virt_addr); diff --git a/kernel/sr_memory.asm b/kernel/sr_memory.asm new file mode 100644 index 0000000..e69de29 diff --git a/lib/conv.c b/lib/conv.c new file mode 100644 index 0000000..2ba09b2 --- /dev/null +++ b/lib/conv.c @@ -0,0 +1,17 @@ +#include "conv.h" +#include "../drivers/vga.h" + +char* int_to_str(int i, char* buf) { + ulong num = (ulong)i; // convert to ulong + uint len = ulong_len(num); // number of digits + + *(buf+len) = '\0'; // add a "end-of-string" at the end + + int j; + for(j = 0; j < len; j++) // iterate over each digit and assign it to the buffer + // super dangerous memory write + println("char!", DEFAULT_COLOR); + *(buf+j) = (char)(ndigit(num, len-1-j) + ASCII_OFFSET); // apply the ascii offset so that i becomes a char + + return buf; +} diff --git a/lib/conv.h b/lib/conv.h new file mode 100644 index 0000000..8c14438 --- /dev/null +++ b/lib/conv.h @@ -0,0 +1,6 @@ +#include "types.h" +#include "util.h" + +#define ASCII_OFFSET 0x30 + +char* int_to_str(int i, char* buf); diff --git a/lib/math.c b/lib/math.c new file mode 100644 index 0000000..bfded6f --- /dev/null +++ b/lib/math.c @@ -0,0 +1,10 @@ +#include "math.h" + +long pow(int num, uint expon) { + long prod = 1; + while(expon > 0) + prod *= num; + expon--; + + return prod; +} diff --git a/lib/math.h b/lib/math.h new file mode 100644 index 0000000..1abe7e4 --- /dev/null +++ b/lib/math.h @@ -0,0 +1,3 @@ +#include "types.h" + +long pow(int, uint); diff --git a/lib/strf.c b/lib/strf.c deleted file mode 100644 index 65dddc7..0000000 --- a/lib/strf.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "strf.h" - -#define int_offset 48 -// 0:48 - 9:57 - -char* int_to_str(int i, char* strbuf) { - if( i == 0 ) { - return (char*)(int_offset); - } else { - char cbuf; - cbuf = (char)((i % 10) + int_offset); - - return int_to_str(i / 10, strbuf + cbuf); - } -} diff --git a/lib/strf.h b/lib/strf.h deleted file mode 100644 index 29649bc..0000000 --- a/lib/strf.h +++ /dev/null @@ -1 +0,0 @@ -char* int_to_str(int i, char* strbuf); diff --git a/lib/types.h b/lib/types.h new file mode 100644 index 0000000..d79be95 --- /dev/null +++ b/lib/types.h @@ -0,0 +1,6 @@ +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned long* pointer; +typedef int bool; +#define true 1 +#define false 0 diff --git a/lib/util.c b/lib/util.c new file mode 100644 index 0000000..ba9b2d2 --- /dev/null +++ b/lib/util.c @@ -0,0 +1,16 @@ +#include "util.h" +#include "math.h" + +uint ulong_len(ulong n) { // get the digit length of a number + int len = 0; + while (n != 0) { + n = n / 10; + ++len; + } + return len; +} + +uint ndigit(ulong n, uint i) { // OBS: index order is reversed + long den = pow(10, i); + return (n/den) % 10; +} diff --git a/lib/util.h b/lib/util.h new file mode 100644 index 0000000..2cebf96 --- /dev/null +++ b/lib/util.h @@ -0,0 +1,4 @@ +#include "types.h" + +uint ulong_len(ulong n); +uint ndigit(ulong n, uint i);