diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..188ee95 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +src/Binaries diff --git a/boot.asm b/boot.asm deleted file mode 100644 index 1b29f5e..0000000 --- a/boot.asm +++ /dev/null @@ -1,47 +0,0 @@ -[org 0x7c00] - -; create the buffer - -; create 1 bit buffer - -; record keys -; if key is enter -; print buffer -; add char to buffer -; increment buffer pointer - - -mov bx, buffer ; initialise buffer - -start: - mov ah, 0 ; i dont understand this - int 0x16 ; record keys - cmp al, 0x0D ; representation of enter key - je printBuffer - mov ah, 0x0e - int 0x10 - mov [bx], al - inc bx - jmp start - -printBuffer: - mov bx, buffer - mov ah, 0x0e - loop: - mov al, [bx] - cmp al, 0 - je exit - int 0x10 ;print - inc bx - jmp loop - - -exit: - mov bx, buffer - jmp start - -buffer: - db 0 - -times 510 - ($-$$) db 0 -db 0x55, 0xaa diff --git a/boot.bin b/boot.bin deleted file mode 100644 index 8061b66..0000000 Binary files a/boot.bin and /dev/null differ diff --git a/bootBuffer.asm b/bootBuffer.asm deleted file mode 100644 index 51c2430..0000000 --- a/bootBuffer.asm +++ /dev/null @@ -1,21 +0,0 @@ -[org 0x7c00] -jmp 0x0000:start - -char: - db 0 - - -start: - mov ah, 0 - int 0x16 ; type interupt - mov [char], al ; moves al into char - - mov ah, 0x0e ;moves ax into teletype - mov al, [char] ; char into al - int 0x10 ; prints - - jmp start ; restarts - - times 510-($-$$) db 0 - db 0x55, 0xaa -jmp $ \ No newline at end of file diff --git a/boot_0.asm b/boot_0.asm deleted file mode 100644 index c248629..0000000 --- a/boot_0.asm +++ /dev/null @@ -1,17 +0,0 @@ -; add to ~/.bashrc alias sto='cd ~/workspaces/github.com/lregs/os && nasm boot.asm -f bin -o boot.bin && qemu-system-x86_64 -drive format=raw,file=boot.bin -nographic' -section .text - global_start - -_start: - mov ah, 0x0e -loop: - inc al - cmp al, 'Z' + 1 - je exit - int 0x10 - jmp loop -exit: - jmp $ - -times 510-($-$$) db 0 -db 0x55, 0xaa \ No newline at end of file diff --git a/buildcrosscompiler.sh b/buildcrosscompiler.sh new file mode 100644 index 0000000..e91c627 --- /dev/null +++ b/buildcrosscompiler.sh @@ -0,0 +1,50 @@ +# nasm and qemu +sudo dnf install nasm +sudo dnf install qemu +sudo dnf install qemu-kvm + +# GCC cross compiler for i386 systems (might take quite some time, prepare food) + +sudo dnf update +sudo dnf install gcc gcc-c++ make +sudo dnf install bison +sudo dnf install flex +sudo dnf install libgmp3-devel +sudo dnf install libmpc-devel +sudo dnf install libmpfr-devel +sudo dnf install texinfo + +#cURL (needed to clone some required files) +sudo dnf install curl + +export PREFIX="/usr/local/i386elfgcc" +export TARGET=i386-elf +export PATH="$PREFIX/bin:$PATH" + +mkdir /tmp/src +cd /tmp/src +curl -O http://ftp.gnu.org/gnu/binutils/binutils-2.39.tar.gz +tar xf binutils-2.39.tar.gz +mkdir binutils-build +cd binutils-build +../binutils-2.39/configure --target=$TARGET --enable-interwork --enable-multilib --disable-nls --disable-werror --prefix=$PREFIX 2>&1 | tee configure.log +sudo make all install 2>&1 | tee make.log + +cd /tmp/src +curl -O https://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.gz +tar xf gcc-12.2.0.tar.gz +mkdir gcc-build +cd gcc-build +echo Configure: . . . . . . . +../gcc-12.2.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-libssp --enable-language=c,c++ --without-headers +echo MAKE ALL-GCC: +sudo make all-gcc +echo MAKE ALL-TARGET-LIBGCC: +sudo make all-target-libgcc +echo MAKE INSTALL-GCC: +sudo make install-gcc +echo MAKE INSTALL-TARGET-LIBGCC: +sudo make install-target-libgcc +echo HERE U GO MAYBE: +ls /usr/local/i386elfgcc/bin +export PATH="$PATH:/usr/local/i386elfgcc/bin" diff --git a/ourSolution.asm b/ourSolution.asm deleted file mode 100644 index 75bde78..0000000 --- a/ourSolution.asm +++ /dev/null @@ -1,33 +0,0 @@ -[org 0x7c00] - -mov sp, 0 -mov bp, sp - -start: - mov ah, 0 ; i dont understand this - int 0x16 ; record keys - cmp al, 0x0D ; representation of enter key - je printStack - mov ah, 0x0e - int 0x10 - push ax - jmp start - -printStack: - mov al, 0 - mov sp, bp - push ax - loop: - mov ax, [esp] - sub sp, 2 - int 0x10 - cmp ax, 0 - je exit - jmp loop - -exit: - jmp start - - -times 510 - ($-$$) db 0 -db 0x55, 0xaa \ No newline at end of file diff --git a/pchar.bin b/pchar.bin deleted file mode 100644 index e69de29..0000000 diff --git a/src/bootloader/boot.asm b/src/bootloader/boot.asm new file mode 100644 index 0000000..1907a17 --- /dev/null +++ b/src/bootloader/boot.asm @@ -0,0 +1,136 @@ +[org 0x7c00] ; start of data segment +KERNEL_LOCATION equ 0x1000 + + +mov [BOOT_DISK], dl + + +xor ax, ax ;starting at 0x0 +mov es, ax +mov ds, ax +mov bp, 0x8000 +mov sp, bp + +mov bx, KERNEL_LOCATION ; we want to load the kwrnwl to the kernel location +mov dh, 20 ;might have to change this number. number of sectors to read + +mov ah, 0x02 +mov al, dh ; number of sectors +mov ch, 0x00 +mov dh, 0x00 +mov cl, 0x02 +mov dl, [BOOT_DISK] +int 0x13 ;load from disk + + ; error managment +jc error ; jump if carry flag is set +cmp al, 2 +jne error + +jmp endload + + +error: + mov ah, 0x0e + mov bx, errorMsg + +eloop: + mov al, [bx] + cmp al, 0 + je endload + int 0x10 + inc bx + jmp eloop + +endload: + +mov ah, 0x0 +mov al, 0x3 +int 0x10 ; text mode + + +CODE_SEG equ GDT_code - GDT_start +DATA_SEG equ GDT_data - GDT_start + +cli +lgdt [GDT_descriptor] +mov eax, cr0 +or eax, 1 +mov cr0, eax +jmp CODE_SEG:start_protected_mode + +jmp $ + +errorMsg: + db "error", 0 + +BOOT_DISK: db 0 + +GDT_start: + GDT_null: + dd 0x0 ; we get 4gb of memory in protected mode + dd 0x0 ; flat memory model + + GDT_code: + dw 0xffff ; we only define the first 16bits of the limit the real value is 0xfffff + dw 0x0 ; we multiply this value by 0x1000 as described in the flags + db 0x0 + db 0b10011010 + db 0b11001111 ; the last 4 bits of the limit are described here 0b1111 + db 0x0 + + GDT_data: + dw 0xffff + dw 0x0 + db 0x0 + db 0b10010010 + db 0b11001111 + db 0x0 + +GDT_end: + +GDT_descriptor: + dw GDT_end - GDT_start - 1 + dd GDT_start + +; need to refactor this file +; load the idtp + +[bits 32] +start_protected_mode: + mov ax, DATA_SEG ;segment registers ; the value is 16 + mov ds, ax ;data segment + mov ss, ax ;stack segment + mov es, ax ;extra segments + mov fs, ax + mov gs, ax + + mov ebp, 0x90000 ; 32 bit stack base pointer + mov esp, ebp + + ; ; print digit + ; mov ax, ax + ; mov ecx, 0xb8000 ;print digit + ; print_dec: + ; xor dx, dx + ; mov bx, 10 + ; div bx ; remainder goes to dx + + ; xor ah, ah + + ; mov bl, dl + ; add bl, 0x30 + ; mov bh, 0x07 + ; mov [ecx], bx + + ; add ecx, 2 + ; cmp ax, 0 + ; jne print_dec + + + jmp KERNEL_LOCATION + + + +times 510-($-$$) db 0 +dw 0xaa55 diff --git a/src/bootloader/kernel_entry.asm b/src/bootloader/kernel_entry.asm new file mode 100644 index 0000000..6106141 --- /dev/null +++ b/src/bootloader/kernel_entry.asm @@ -0,0 +1,5 @@ +section .text + [bits 32] + [extern _start] + call _start + jmp $ diff --git a/src/bootloader/zeroes.asm b/src/bootloader/zeroes.asm new file mode 100644 index 0000000..eed89f3 --- /dev/null +++ b/src/bootloader/zeroes.asm @@ -0,0 +1 @@ +times 10240 db 0 diff --git a/src/kernel/idt.asm b/src/kernel/idt.asm new file mode 100644 index 0000000..02a36aa --- /dev/null +++ b/src/kernel/idt.asm @@ -0,0 +1,90 @@ + +global _idt_load + +_idt_load: + [extern _idtp] + lidt [_idtp] + ret + +global _isr_generic + +[extern _fault_handler] + +_isr_generic: + pusha + push ds + push es + push fs + push gs + + cli + call _fault_handler ; checks if interrupt number < 32 (if it represents an exception) + hlt + + pop gs + pop fs + pop es + pop ds + popa + iret + + +global _irq_keyboard + +[extern _keyboard_handler] + +_irq_keyboard: + pusha + push ds + push es + push fs + push gs + + call _keyboard_handler + + pop gs + pop fs + pop es + pop ds + popa + iret + +global _irq_under_40 + +[extern _less_than_40] + +_irq_under_40: + pusha + push ds + push es + push fs + push gs + + call _less_than_40 + + pop gs + pop fs + pop es + pop ds + popa + iret + +global _irq_over_39 + +[extern _more_than_39] + +_irq_over_39: + pusha + push ds + push es + push fs + push gs + + call _more_than_39 + + pop gs + pop fs + pop es + pop ds + popa + iret diff --git a/src/kernel/idt.cpp b/src/kernel/idt.cpp new file mode 100644 index 0000000..43aa88d --- /dev/null +++ b/src/kernel/idt.cpp @@ -0,0 +1,120 @@ +#include "keyboard.h" +#include "memory.h" +#include "portio.h" +#include "printing.h" + +extern "C" void _idt_load(); + +extern "C" void _isr_generic(); + +extern "C" void _irq_keyboard(); + +extern "C" void _irq_under_40(); + +extern "C" void _irq_over_39(); + +struct idt_entry { + unsigned short base_lo; + unsigned short sel; + unsigned char always0; + unsigned char flags; + unsigned short base_hi; +} __attribute__((packed)); + +struct idt_ptr { + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +struct idt_entry idt[256]; +struct idt_ptr _idtp; + +void idt_set_gate(unsigned char num, + unsigned long base, + unsigned short sel, + unsigned char flags) { + idt[num].base_hi = (short)(base >> 16) & 0xffff; + idt[num].base_lo = (short)(base & 0xffff); + idt[num].always0 = 0; + idt[num].sel = sel; + idt[num].flags = flags; +} + +void idt_install() { + _idtp.limit = (sizeof(struct idt_entry) * 256) - 1; + _idtp.base = (unsigned long)&idt; + + // Clear out the entire IDT, initializing it to zeros + memset(&idt, 0, sizeof(struct idt_entry) * 256); + + _idt_load(); +} + +extern "C" void _fault_handler() { + sprintln("Exception!"); +} + +void isr_install() { + // for (int i = 0; i < 32; i++) { + // idt_set_gate(i, (unsigned long)_isr_generic, 0x08, 0x8E); + // } + idt_set_gate(0, (unsigned long)_isr_generic, 0x08, 0x8E); +} + +// moves the irqs from the default position to start at isr 32 +// since by default they overlap with the protected mode isrs +// reserved for exceptions. +void irq_remap() { + outb(0x20, 0x11); // Initialize both PICs + outb(0xA0, 0x11); + outb(0x21, 0x20); // Set vector offsets + outb(0xA1, 0x28); + outb(0x21, 0x04); // tell Master PIC theres a slave PIC at IRQ2 (0000 0100) + outb(0xA1, 0x02); // tell Slave PIC its cascade identity (0000 0010) + outb(0x21, 0x01); // have the PICs use 8086 mode (and not 8080 mode) + outb(0xA1, 0x01); + outb(0x21, 0x0); // set masks + outb(0xA1, 0x0); +} + +extern "C" void _more_than_39() { + // sprintln("more"); + outb(0xA0, 0x20); // EOI to pic2 + outb(0x20, 0x20); // EOI to pic1 +} + +extern "C" void _less_than_40() { + // sprintln("less"); + outb(0x20, 0x20); +} + +// not working try timer one instead + +extern "C" void _keyboard_handler() { + keyboard_handle(); + // sprintln("finished"); + outb(0x20, 0x20); + // sprintln("double finished"); +} + +void irq_install() { + irq_remap(); + + idt_set_gate(32, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(33, (unsigned long)_irq_keyboard, 0x08, 0x8E); + idt_set_gate(34, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(35, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(36, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(37, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(38, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(39, (unsigned long)_irq_under_40, 0x08, 0x8E); + idt_set_gate(40, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(41, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(42, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(43, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(44, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(45, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(46, (unsigned long)_irq_over_39, 0x08, 0x8E); + idt_set_gate(47, (unsigned long)_irq_over_39, 0x08, 0x8E); + iprintln((unsigned long)_irq_keyboard, 16); +} diff --git a/src/kernel/idt.h b/src/kernel/idt.h new file mode 100644 index 0000000..12ece1a --- /dev/null +++ b/src/kernel/idt.h @@ -0,0 +1,5 @@ +void idt_install(); + +void isr_install(); + +void irq_install(); diff --git a/src/kernel/kernel.cpp b/src/kernel/kernel.cpp new file mode 100644 index 0000000..ebaeec3 --- /dev/null +++ b/src/kernel/kernel.cpp @@ -0,0 +1,38 @@ +#include "idt.h" +#include "keyboard.h" +#include "printing.h" +#include "shell.h" + +// TODO: +// 0. TTY +// 1. interrupts IDT +// 2. kmalloc -> needed for page frame allocation -> first free aligned address +// after the kernel https://wiki.osdev.org/Memory_Allocation +// 3. paging https://wiki.osdev.org/Paging, +// https://wiki.osdev.org/Setting_Up_Paging +// - identity paging +// - uses the ps register +// 4. processes for malloc https://wiki.osdev.org/Writing_a_memory_manager + +extern "C" int _start() { + idt_install(); + isr_install(); + irq_install(); + + asm volatile("sti"); + + vga_init(); + keyboard_default(); + + sprintln(WELCOMEMSG); + + // iprintln(0xabc, 16); + // sprintln( + // "thisisareallylongstringthatimadetottesthowhethermyprintingworksproperlyi" + // "dontknowwhyIdidntputanyspcaesinitlololol"); + + shell_init(); + for (;;) { + } + return 0; +} diff --git a/src/kernel/keyboard.cpp b/src/kernel/keyboard.cpp new file mode 100644 index 0000000..d98f765 --- /dev/null +++ b/src/kernel/keyboard.cpp @@ -0,0 +1,73 @@ +#include "keyboard.h" +#include "portio.h" +#include "printing.h" +#include "streams.h" + +// TODO figure out modes -> rewrite? +// have an array of all the characters -> index is the scancode +// this is the mapping +// function pointer to handle what to do for each thing + +char MAP_DEFAULT[128] = { + 0, ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '-', '=', BSPACE, TAB, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', '\n', CTRL, 'a', 's', 'd', 'f', 'g', 'h', + 'j', 'k', 'l', ';', '\'', '#', SHIFT, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', SHIFT, 0, 0, ' ', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + AUP, 0, '-', ALEFT, 0, ARIGHT, '+', 0, ADOWN, 0, 0, 0, + 0, 0, 0, 0, 0, 0, // 90 here +}; + +char SHIFT_DEFAULT[128] = + { + 0, ESC, '!', '"', '$', '$', '%', '^', '&', '*', '(', ')', + '_', '+', BSPACE, TAB, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', + 'O', 'P', '{', '}', '\n', CTRL, 'A', 'S', 'D', 'F', 'G', 'H', + 'J', 'K', 'L', ':', '@', '~', SHIFT, '|', 'Z', 'X', 'C', 'V', + 'B', 'B', 'M', '<', '>', '?', SHIFT, 0, 0, ' ', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + AUP, 0, '0', ALEFT, 0, ARIGHT, '0', 0, ADOWN, 0, 0, 0, + 0, 0, 0, 0, 0, 0, // 90 here +}; + +KeyMap KEYMAP; + +// void keyboard_load_mode(Mode mode) {} + +// need to think about how to expose to user land safely +void keyboard_load_mapping(char* normal_layer, char* shift_layer) { + KEYMAP.normal = normal_layer; + KEYMAP.shift = shift_layer; +} + +void keyboard_default() { + keyboard_load_mapping(MAP_DEFAULT, SHIFT_DEFAULT); +} + +void keyboard_handle() { + // preserve between function calls + static int shift = 0; + + unsigned char scancode = inb(0x60); + + // iprintln((short)scancode, 16); + + // if top bit set key released + if (scancode & 0b10000000) { + scancode = scancode ^ 0b10000000; + if (MAP_DEFAULT[scancode] == SHIFT) { + shift = 0; + } + return; + } + + char cout = shift ? KEYMAP.shift[scancode] : KEYMAP.normal[scancode]; + + if (cout == SHIFT) { + shift = 1; + return; + } + + stdin_put(cout); +} diff --git a/src/kernel/keyboard.h b/src/kernel/keyboard.h new file mode 100644 index 0000000..dc4831b --- /dev/null +++ b/src/kernel/keyboard.h @@ -0,0 +1,21 @@ + +enum special_keys { + BSPACE = 1, + SHIFT, + AUP, + ADOWN, + ALEFT, + ARIGHT, + ESC, + TAB, + CTRL, +}; + +typedef struct KeyMap { + char* normal; + char* shift; +} KeyMap; + +void keyboard_handle(); + +void keyboard_default(); diff --git a/src/kernel/memory.cpp b/src/kernel/memory.cpp new file mode 100644 index 0000000..8c15610 --- /dev/null +++ b/src/kernel/memory.cpp @@ -0,0 +1,17 @@ + +// todo move to memory file +void* memset(void* dest, unsigned char val, int count) { + unsigned char* destC = (unsigned char*)dest; + for (int i = 0; i < count; i++) { + destC[i] = val; + } + return dest; +} + +void memcopy(void* dest, void* data, int count) { + unsigned char* destC = (unsigned char*)dest; + unsigned char* dataC = (unsigned char*)data; + for (int i = 0; i < count; i++) { + destC[i] = dataC[i]; + } +} diff --git a/src/kernel/memory.h b/src/kernel/memory.h new file mode 100644 index 0000000..53d2447 --- /dev/null +++ b/src/kernel/memory.h @@ -0,0 +1,3 @@ + +void memcopy(void* dest, void* data, int count); +void* memset(void* dest, unsigned char val, int count); diff --git a/src/kernel/portio.cpp b/src/kernel/portio.cpp new file mode 100644 index 0000000..7677c34 --- /dev/null +++ b/src/kernel/portio.cpp @@ -0,0 +1,10 @@ + +void outb(short port, char byte) { + asm volatile("outb %0, %1" : : "a"(byte), "Nd"(port)); +} + +char inb(short port) { + char res; + asm volatile("inb %1, %0" : "=a"(res) : "Nd"(port)); + return res; +} diff --git a/src/kernel/portio.h b/src/kernel/portio.h new file mode 100644 index 0000000..c2fd9fa --- /dev/null +++ b/src/kernel/portio.h @@ -0,0 +1,3 @@ + +char inb(short port); +void outb(short port, char byte); diff --git a/src/kernel/printing.cpp b/src/kernel/printing.cpp new file mode 100644 index 0000000..b9390ce --- /dev/null +++ b/src/kernel/printing.cpp @@ -0,0 +1,178 @@ +// TODO support coloured text +// TODO move the vga mode cursor + +#include "portio.h" + +typedef struct Cursor { + int x; + int y; +} Cursor; + +const char BACKGROUND = 0x0; +const char FOREGROUND = 0x7; + +Cursor CURSOR; + +char SCREEN[25][80]; + +void write_char(char c, char fcolour, char bcolour, int x, int y) { + short colours = (bcolour << 4) | (fcolour & 0x0f); + volatile short* where; + where = (volatile short*)0xb8000 + (y * 80 + x); + *where = c | (colours << 8); // load the value into the pointer +} + +void printscreen() { + for (int y = 0; y < 25; y++) { + for (int x = 0; x < 80; x++) { + write_char(SCREEN[y][x], FOREGROUND, BACKGROUND, x, y); + } + } +} + +void scroll_without_render() { + for (int i = 0; i < 24; i++) { + for (int j = 0; j < 80; j++) { + SCREEN[i][j] = SCREEN[i + 1][j]; + } + } + for (int i = 0; i < 80; i++) { + SCREEN[24][i] = 0; + } + CURSOR.y--; +} + +// this my cursor we should move the vga cursor aswell +void vga_init() { + CURSOR = {0, 0}; + + // init screen with nulls + for (int i = 0; i < 25; i++) { + for (int j = 0; j < 80; j++) { + SCREEN[i][j] = 0; + } + } + + printscreen(); +} + +void cursor_set(int x, int y) { // Does some I/O black magic + short pos = y * 80 + x; + if (pos >= 0 && pos < 2000) { + outb(0x3d4, 0x0f); + outb(0x3d5, (char)(pos & 0xff)); + outb(0x3d4, 0x0e); + outb(0x3d5, (char)((pos >> 8) & 0xff)); + } +} + +void newline() { + CURSOR.y++; + CURSOR.x = 0; + if (CURSOR.y > 24) { + scroll_without_render(); + } + cursor_set(CURSOR.x, CURSOR.y); + printscreen(); // slow: calling here renders twice in some instances +} + +void cursorlr(int d) { + CURSOR.x += d; + if (CURSOR.x > 79) { + newline(); + } + cursor_set(CURSOR.x, CURSOR.y); +} + +void cursordu(int d) { + if (CURSOR.y == 24 && d > 0) { + return; + } + if (CURSOR.y == 0 && d < 0) { + return; + } + CURSOR.y += d; + cursor_set(CURSOR.x, CURSOR.y); +} + +void sprintln(const char* string) { + while (*string != '\0') { + if (*string == '\n') { + newline(); + string++; + continue; + } + SCREEN[CURSOR.y][CURSOR.x] = *string; + string++; + cursorlr(1); + } + newline(); + printscreen(); +}; + +void sprint(const char* string) { + while (*string != '\0') { + if (*string == '\n') { + newline(); + string++; + continue; + } + SCREEN[CURSOR.y][CURSOR.x] = *string; + string++; + cursorlr(1); + } + printscreen(); +}; + +void iprintln(long integer, int base) { + if (integer == 0) { + SCREEN[CURSOR.y][CURSOR.x] = '0'; + newline(); + printscreen(); + return; + } + char c; + char* outstring; + int counter = 0; + while (integer != 0) { + c = integer % base + 0x30; + outstring[counter] = c > '9' && c < 'A' ? c + 7 : c; + integer /= base; + counter++; + } + for (int i = 1; i <= counter; i++) { + SCREEN[CURSOR.y][CURSOR.x] = outstring[counter - i]; + cursorlr(1); + } + newline(); + printscreen(); +} + +// have a buffer and buffer delete in a tty echo server fingee +// maybe need malloc for that +// can maybe depreciate! +void cdelete() { + cursorlr(-1); + for (int i = CURSOR.x; i < 79; i++) { + SCREEN[CURSOR.y][i] = SCREEN[CURSOR.y][i + 1]; + } + SCREEN[CURSOR.y][79] = 0; + printscreen(); +} + +void clear_line_from_cursor() { + for (int i = CURSOR.x; i < 80; i++) { + SCREEN[CURSOR.y][i] = 0; + } + printscreen(); +} + +void cprint(char c) { + if (c == '\n') { + newline(); + return; + } + SCREEN[CURSOR.y][CURSOR.x] = c; + cursorlr(1); + printscreen(); +} diff --git a/src/kernel/printing.h b/src/kernel/printing.h new file mode 100644 index 0000000..be90a69 --- /dev/null +++ b/src/kernel/printing.h @@ -0,0 +1,28 @@ +#define WELCOMEMSG \ + "\n" \ + "__________ __________ ________ _________\n" \ + "\\____ / \\______ \\\\_____ \\ / _____/\n" \ + " / / | | _/ / | \\ \\_____ \\ \n" \ + " / /_ | | \\/ | \\/ \\\n" \ + "/_______ \\_____|______ /\\_______ /_______ /\n" \ + " \\/_____/ \\/ \\/ \\/ \n\n" \ + "[ Welcome To Zebs Operating System! ]" \ + "\n" + +void sprintln(const char* string); + +void sprint(const char* string); + +void vga_init(); + +void iprintln(long integer, int base); + +void cprint(char c); + +void cdelete(); + +void cursorlr(int d); + +void cursordu(int d); + +void clear_line_from_cursor(); diff --git a/src/kernel/shell.cpp b/src/kernel/shell.cpp new file mode 100644 index 0000000..6f03d8c --- /dev/null +++ b/src/kernel/shell.cpp @@ -0,0 +1,104 @@ +#include "keyboard.h" +#include "memory.h" +#include "printing.h" +#include "streams.h" + +// causes issues when stack allocated / doesn't get allocated on stack when +// called in a function? some compiler funny buisness? +// should have plenty of room on the stack +// Use these to print esp +// register int* esp asm("esp"); +// iprintln(*esp, 16); + +typedef struct CmdBuffer { + int cursor; + int size; + char buffer[256]; +} CmdBuffer; + +CmdBuffer* CB; + +void buffer_reset() { + CB->cursor = -1; + CB->size = 0; + + memset(CB->buffer, '\0', sizeof(char) * 255); +} + +void buffer_remove() { + if (CB->cursor < 0) { + return; + } + for (int i = CB->cursor; i < CB->size; i++) { + CB->buffer[i] = CB->buffer[i + 1]; + } + CB->size--; + CB->buffer[CB->size] = '\0'; + + cursorlr(-1); + clear_line_from_cursor(); + sprint(CB->buffer + CB->cursor); + cursorlr(-(CB->size - CB->cursor)); + CB->cursor--; +} + +void buffer_insert(char c) { + if (CB->cursor >= 255) { + return; + } + CB->cursor++; + for (int i = CB->size; i > CB->cursor; i--) { + CB->buffer[i] = CB->buffer[i - 1]; + } + CB->buffer[CB->cursor] = c; + + clear_line_from_cursor(); + sprint(CB->buffer + CB->cursor); + cursorlr(-(CB->size - CB->cursor)); + + CB->size++; +} + +void buffer_left() { + if (CB->cursor < 0) { + return; + } + CB->cursor--; + cursorlr(-1); +} + +void buffer_right() { + if (CB->cursor >= CB->size - 1) { + return; + } + CB->cursor++; + cursorlr(1); +} + +void shell_init() { + buffer_reset(); + sprint("> "); + for (;;) { + char c = stdin_get(); + switch (c) { + default: + buffer_insert(c); + break; + case BSPACE: + buffer_remove(); + break; + case ALEFT: + buffer_left(); + break; + case ARIGHT: + buffer_right(); + break; + case '\n': + sprintln(""); + sprintln(CB->buffer); + buffer_reset(); + sprint("> "); + break; + } + } +} diff --git a/src/kernel/shell.h b/src/kernel/shell.h new file mode 100644 index 0000000..22f3942 --- /dev/null +++ b/src/kernel/shell.h @@ -0,0 +1,2 @@ + +void shell_init(); diff --git a/src/kernel/streams.cpp b/src/kernel/streams.cpp new file mode 100644 index 0000000..db655aa --- /dev/null +++ b/src/kernel/streams.cpp @@ -0,0 +1,52 @@ +// we should use malloc to define arbitarty streams but lets just use a buffer +// for now. Needs revisiting when we have multiple processes. + +// TODO put mutexs in there own file + +typedef char Mutex; // maybe better as a struct? + +typedef struct Stream { + int count; + Mutex message; + Mutex slot; + char queue[10]; +} Stream; + +Stream STDIN = {0, 0, 1, {'\0'}}; + +// RACE condition? what if 2 processes are waiting at once +// need to use a counting semaphore? +void wait(Mutex* mutex) { + for (;;) { + if (*mutex) { + *mutex = 0; + break; + } + } +} + +void signal(Mutex* mutex) { + *mutex = 1; +} + +char stdin_get() { + wait(&STDIN.message); + char cout = STDIN.queue[0]; + for (int i = 0; i < STDIN.count - 1; i++) { + STDIN.queue[i] = STDIN.queue[i + 1]; + } + STDIN.queue[STDIN.count] = '\0'; + STDIN.count--; + signal(&STDIN.slot); + return cout; +} + +void stdin_put(char c) { + wait(&STDIN.slot); + if (STDIN.count >= 10) { + return; + } + STDIN.queue[STDIN.count] = c; + STDIN.count++; + signal(&STDIN.message); +} diff --git a/src/kernel/streams.h b/src/kernel/streams.h new file mode 100644 index 0000000..828d6e7 --- /dev/null +++ b/src/kernel/streams.h @@ -0,0 +1,4 @@ + + +char stdin_get(); +void stdin_put(char c); diff --git a/src/practice/disk.asm b/src/practice/disk.asm new file mode 100644 index 0000000..5dfc1f0 --- /dev/null +++ b/src/practice/disk.asm @@ -0,0 +1,62 @@ + +[org 0x7c00] ; origin in the data segment + +; chs addressing + +mov [diskNum], dl + +mov ah, 2 ;not sure why +mov al, 1 ;number of sectors to read +mov ch, 0 ;cylinder 0 +mov cl, 2 ;sector number +mov dh, 0 ;head number +mov dl, [diskNum] +mov bx, 0 ;cant move 0 directly to es +mov es, bx +mov bx, 0x7e00 ; es*16+bx = where we want to load the data +int 0x13 ;call the function (kinda lol) + +;check for errors +jc error ;jump if carry flag is set +jmp print + +cmp al, 1 +jne error +jmp print + + +error: + mov ah, 0x0e + mov bx, errorMsg + eloop: + mov al, [bx] + + cmp al, 0 + je end + + int 0x10 + inc bx + + jmp eloop + + + +print: + mov ah, 0x0e ;print the loaded memory + mov al, [0x7e00] + int 0x10 + +end: + +jmp $ + +diskNum: + db 0 + +errorMsg: + db "error", 0 + +times 510 - ($ - $$) db 0 ;510 bytes minus previous code define as 0 +db 0x55, 0xaa ;special code that defines boot sector + +times 512 db 'A' ;fill sector with As a sector is 512 bytes long diff --git a/src/practice/one.asm b/src/practice/one.asm new file mode 100644 index 0000000..582fc59 --- /dev/null +++ b/src/practice/one.asm @@ -0,0 +1,66 @@ +[org 0x7c00] ; set required offset for dereferencing characters from buffers + +xor al, al ; set al to 0 + +main: + mov bx, string ; pointer to bx + + mov ah, 0x0e ; teletype mode + mov al, 10 ; newline character + int 0x10 ; print interupt + int 0x10 + mov al, '>' + int 0x10 + mov al, ' ' + int 0x10 + + loop: + mov ah, 0 + int 0x16 ; wait for keypress + + mov ah, 0x0e ; teletype mode + int 0x10 + + mov [bx], al + inc bx + + cmp al, 0x0D ; enter key + je printBuffer + + ;need to compare size of buffer with offset + + jmp loop + +printBuffer: + mov bx, string + mov ah, 0x0e + + mov al, 10 ; newline character + int 0x10 + + xor cl, cl; initialise register for cleaning buffer + + ploop: + mov al, [bx] + + cmp al, 0 ; if end of string + je main + + int 0x10 ;print + + mov [bx], cl ;reset buffer needs to use a register to know size + inc bx + + jmp ploop + + + + +jmp $ + + +string: ; buffer for input + times 50 db 0 + +times 510 - ($ - $$) db 0 ;510 bytes minus previous code define as 0 +db 0x55, 0xaa ;special code that defines boot sector diff --git a/src/practice/protectedmode.asm b/src/practice/protectedmode.asm new file mode 100644 index 0000000..ab3d026 --- /dev/null +++ b/src/practice/protectedmode.asm @@ -0,0 +1,95 @@ +[org 0x7c00] + + +mov [BOOT_DISK], dl + + + +CODE_SEG equ GDT_code - GDT_start +DATA_SEG equ GDT_data - GDT_start + +cli +lgdt [GDT_descriptor] ; load gdt descriptor +mov eax, cr0 ; load mode into register +or eax, 1 +mov cr0, eax +jmp CODE_SEG:start_protected_mode + +jmp $ + + +GDT_start: ; must be at the end of real mode code + GDT_null: + dd 0x0 + dd 0x0 + + GDT_code: ; ppp 1001 1if segment is used 00 ring priveldge 1 for data or code + dw 0xffff ; type flag 1010 code1, conforming0, readable1, cpuflag0 + dw 0x0 ; other flags 1100 granularity use more memory and 32bit mode + db 0x0 ; 0xffff define meory used set to max + db 0b10011010 + db 0b11001111 + db 0x0 + + GDT_data: + dw 0xffff + dw 0x0 + db 0x0 + db 0b10010010 ;defining the data segment as above + db 0b11001111 + db 0x0 + +GDT_end: + +GDT_descriptor: + dw GDT_end - GDT_start - 1 ;size + dd GDT_start + + +[bits 32] +start_protected_mode: + mov cl, 'Z' ;the secret hiddne letter + mov ch, 0x00 ;background and foreground to blue + mov ebx, 0xb8000 ;video memory start + + bloop: + cmp ebx, 0xb8FA0 ; paint whole background + je bend + mov [ebx], cx + add ebx, 2 + jmp bloop + + bend: + + + mov ebx, 0xb8348 + mov ch, 0x90 ; start on the light blue background + mov eax, welcomeMessage ; in 32 bit mode you have to use eax + zloop: + mov cl, [eax] + cmp cl, 0 + je zend + mov [ebx], cx + inc eax + add ebx, 2 + add ch, 0x10 + cmp ch, 0xF0 + je reset + jmp zloop + + reset: + mov ch, 0x90 + jmp zloop + + zend: + + jmp $ + + welcomeMessage: + db "welcome to ZebOS!", 0 + +BOOT_DISK: db 0 + +times 510-($-$$) db 0 +dw 0xaa55 + diff --git a/src/practice/two.asm b/src/practice/two.asm new file mode 100644 index 0000000..900869c --- /dev/null +++ b/src/practice/two.asm @@ -0,0 +1,60 @@ +[org 0x7c00] ; set required offset for dereferencing characters from buffers + +main: + xor ax, ax + mov sp, bp; reset the stack + + mov ah, 0x0e ; teletype mode + mov al, 0dh ; for some reason need carrage return here + int 0x10 ; i.e move the cursor to the left + + mov al, 10 ; newline character + int 0x10 ; print interupt + int 0x10 + mov al, '>' + int 0x10 + mov al, ' ' + int 0x10 + + xor ah, ah ;clear ah + + loop: + int 0x16 ; wait for keypress + + mov ah, 0x0e ; teletype mode + int 0x10 + + cmp al, 0x0D ; enter key + je printBuffer + + xor ah, ah ;clear ah + push ax + + jmp loop + +printBuffer: + mov ah, 0x0e + mov al, 10 ; newline character + int 0x10 + + mov si, bp ;source index + + ploop: + cmp si, sp ; if end of string + je main + + sub si, 2 ;move pointer + + mov al, [si] + + int 0x10 ;print + + jmp ploop + + + + +jmp $ + +times 510 - ($ - $$) db 0 ;510 bytes minus previous code define as 0 +db 0x55, 0xaa ;special code that defines boot sector diff --git a/src/run.sh b/src/run.sh new file mode 100644 index 0000000..89962d6 --- /dev/null +++ b/src/run.sh @@ -0,0 +1,26 @@ +# TODO make into make file + +export PATH=$PATH:/usr/local/i386elfgcc/bin + +bootloader="bootloader/" +kernel="kernel/" +binaries="Binaries/" + +nasm "${bootloader}boot.asm" -f bin -o "${binaries}boot.bin" +nasm "${bootloader}kernel_entry.asm" -f elf -o "${binaries}kernel_entry.o" +nasm "${kernel}idt.asm" -f elf -o "${binaries}idt_entry.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}kernel.cpp" -o "${binaries}kernel.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}printing.cpp" -o "${binaries}printing.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}idt.cpp" -o "${binaries}idt.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}memory.cpp" -o "${binaries}memory.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}portio.cpp" -o "${binaries}portio.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}keyboard.cpp" -o "${binaries}keyboard.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}streams.cpp" -o "${binaries}streams.o" +i386-elf-gcc -ffreestanding -m32 -g -c "${kernel}shell.cpp" -o "${binaries}shell.o" +nasm "${bootloader}zeroes.asm" -f bin -o "${binaries}zeroes.bin" + +i386-elf-ld -o "${binaries}full_kernel.bin" -Ttext 0x1000 "${binaries}kernel_entry.o" "${binaries}kernel.o" "${binaries}printing.o" "${binaries}idt.o" "${binaries}idt_entry.o" "${binaries}memory.o" "${binaries}portio.o" "${binaries}keyboard.o" "${binaries}shell.o" "${binaries}streams.o" --oformat binary + +cat "${binaries}boot.bin" "${binaries}full_kernel.bin" "${binaries}zeroes.bin" > "${binaries}OS.bin" + +qemu-system-x86_64 -drive format=raw,file="Binaries/OS.bin",index=0,if=floppy, -m 128M diff --git a/zeb_alphabet.asm b/zeb_alphabet.asm deleted file mode 100644 index 638e012..0000000 --- a/zeb_alphabet.asm +++ /dev/null @@ -1,23 +0,0 @@ - -mov ah, 0x0e ; move to the first half of ax say its a character -mov cl, 'A' -mov bl, 'b' - -nacho_loop: - cmp cl, 'Z' + 1 - je exit - mov al, cl - int 0x10 - mov al, bl - int 0x10 - add cl, 2 - add bl, 2 - jmp nacho_loop - -exit: - jmp $ ;) -times 510-($-$$) db 1 -db 0x55, 0xaa -;qemu-system-x86_64 -drive format=raw,file=boot.bin boot.bin -nographic -;nasm -o bin -