diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/boot/Makefile b/boot/Makefile old mode 100755 new mode 100644 diff --git a/boot/bootsect.asm b/boot/bootsect.asm old mode 100755 new mode 100644 diff --git a/boot/setup.asm b/boot/setup.asm old mode 100755 new mode 100644 diff --git a/c_os/.clang-tidy b/c_os/.clang-tidy old mode 100755 new mode 100644 diff --git a/c_os/Makefile b/c_os/Makefile index 9f290b6..6ff6cc5 100755 --- a/c_os/Makefile +++ b/c_os/Makefile @@ -70,10 +70,13 @@ DELETE = rm ASM = nasm CC ?= gcc CXX ?= g++ -CFLAGS := $(CFLAGS) -m32 -march=i486 -Wall -fno-stack-protector -nostdlib -I. -g -ffreestanding -fno-pie -fno-pic -mpreferred-stack-boundary=2 -Wno-write-strings -mno-sse -mno-sse2 -mmanual-endbr -CXXFLAGS := $(CFLAGS) -Wno-non-virtual-dtor -fno-threadsafe-statics -fno-use-cxa-atexit -fno-rtti -fno-exceptions -std=c++17 + +# I added O0 to allow paging/bluescreen to work (We need the ebp on the stack) +CFLAGS := $(CFLAGS) -O0 -m32 -march=i486 -Wall -fno-stack-protector -nostdlib -I. -g -ffreestanding -fno-pie -fno-pic -mpreferred-stack-boundary=2 -Wno-write-strings -mno-sse -mno-sse2 -mmanual-endbr + # I added -std=c++17 for if constexpr, but it isn't necessary for anything critical # Needed for template concepts, but we don't have it available: -std=c++20 +CXXFLAGS := $(CFLAGS) -Wno-non-virtual-dtor -fno-threadsafe-statics -fno-use-cxa-atexit -fno-rtti -fno-exceptions -std=c++17 BOOT = ../boot TOOLS = ../tools diff --git a/c_os/devices/CGA_Stream.h b/c_os/devices/CGA_Stream.h index c3fb5dc..97675bb 100755 --- a/c_os/devices/CGA_Stream.h +++ b/c_os/devices/CGA_Stream.h @@ -15,7 +15,8 @@ #ifndef __CGA_Stream_include__ #define __CGA_Stream_include__ -#include "devices/BufferedCGA.h" +// #include "devices/BufferedCGA.h" +#include "devices/CGA.h" #include "lib/OutStream.h" // NOTE: I added this @@ -33,7 +34,7 @@ public: }; // NOTE: I added this (changed this) to use BufferedCGA -class CGA_Stream : public OutStream, public BufferedCGA { +class CGA_Stream : public OutStream, public CGA { private: CGA_Stream(CGA_Stream& copy) = delete; // Verhindere Kopieren diff --git a/c_os/devices/Keyboard.cc b/c_os/devices/Keyboard.cc index fce3400..657e62d 100755 --- a/c_os/devices/Keyboard.cc +++ b/c_os/devices/Keyboard.cc @@ -340,9 +340,10 @@ void Keyboard::trigger() { // NOTE: My keyboard has no delete key... if (key.ctrl_left() && key.alt_left() && (char)key == 'r') { this->reboot(); - } else if ((char)key == 'k' || (char)key == 'j') { - scroll_mode(key); } + // else if ((char)key == 'k' || (char)key == 'j') { + // scroll_mode(key); + // } } // TODO: Where to place this? @@ -350,13 +351,13 @@ void Keyboard::trigger() { // - Ereignisverwaltung, wo man Threads registrieren kann // - Blockierte Threads verwalten und aufwecken bei ereignissen // Waits for keys to control the scrollback buffer display -void scroll_mode(Key key) { - switch ((char)key) { - case 'k': - kout.scroll_page_backward(); - break; - case 'j': - kout.scroll_page_forward(); - break; - } -} +// void scroll_mode(Key key) { +// switch ((char)key) { +// case 'k': +// kout.scroll_page_backward(); +// break; +// case 'j': +// kout.scroll_page_forward(); +// break; +// } +// } diff --git a/c_os/kernel/Paging.cc b/c_os/kernel/Paging.cc new file mode 100644 index 0000000..a45633f --- /dev/null +++ b/c_os/kernel/Paging.cc @@ -0,0 +1,211 @@ +/***************************************************************************** + * * + * P A G I N G * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Rudimentaeres Paging: 1:1 Mapping fuer gesamten logischen* + * Adressraum. logische Adresse = physikalische Adresse * + * * + * Page-Directory (alle Eintraege present, read/write * + * 0. Eintrag zeigt auf eine Page-Table (4 KB Eintraege)* + * Alle restl. Eintraege sind 4 MB Seiten und verweisen * + * somit auf keine Page-Tabelle sondern direkt auf die * + * 4 MB Seite. * + * * + * Page-Table (Logische Adressen 0 - 4 MB) * + * 1. Eintrag not present, read-only * + * -> Null-Pointer abfangen * + * 2. restl. Eintraege present & read/write * + * * + * Memory-Laylout * + * * + * boot.asm * + * 0x07c0: Bootsector vom BIOS geladen * + * 0x0060: Boot-Code verschiebt sich hier hin * + * 0x9000: Setup-Code (max. 64K inkl. Stack) vom * + * Bootsector-Code geladen * + * setup.asm * + * 0x1000: System-Code (max. 512K) geladen * + * BIOS-Aufruf * + * 0x24000: Parameter fuer BIOS-Aufurf * + * 0x25000: Altes ESP sichern, vor BIOS-Aufruf * + * 0x26000: 16-Bit Code-Segment fuer BIOS-Aufurf * + * System-Code * + * 0x100000: System-Code, kopiert nach Umschalten in * + * den Protected Mode kopiert (GRUB kann nur * + * an Adressen >1M laden) * + * Globale Variablen: Direkt nach dem Code liegen die globalen * + * Variablen. * + * Paging: * + * 0x200000: Page-Directory * + * 0x201000: Page-Table * + * 0x202000: erste allozierbare Page (via Paging.cc) * + * 0x3FF000: Anfang der letzten allozierbaren Page * + * Heap: * + * 0x400000: Start-Adresse der Heap-Verwaltung * + * Ende: Letzte Adresse des phys. Speichers * + * * + * * + * Autor: Michael Schoettner, 20.12.2018 * + *****************************************************************************/ +#include "kernel/Paging.h" +#include "kernel/Globals.h" + +// Bits fuer Eintraege in der Page-Table +#define PAGE_PRESENT 0x001 +#define PAGE_WRITEABLE 0x002 +#define PAGE_BIGSIZE 0x080 +#define PAGE_RESERVED 0x800 // Bit 11 ist frei fuer das OS + +// Adresse des Page-Directory (benoetigt 4 KB) +#define PAGE_DIRECTORY 0x200000 + +// Adresse der Page-Table (benoetigt 4 KB) +#define PAGE_TABLE 0x201000 + +// Start- und End-Adresse der 4 KB Seiten die durch die Page-Table adressiert werden +#define FST_ALLOCABLE_PAGE 0x202000 +#define LST_ALLOCABLE_PAGE 0x2FF000 + +// Externe Funktionen in startup.asm +extern "C" { + void paging_on(unsigned int* p_pdir); // Paging einschalten + void invalidate_tlb_entry(unsigned int* ptr); // Page in TLB invalid. +} + +/***************************************************************************** + * Funktion: pg_alloc_page * + *---------------------------------------------------------------------------* + * Beschreibung: Alloziert eine 4 KB Seite. Allozieren heisst hier * + * lediglich Setzen eines eigenen RESERVED-Bits. * + *****************************************************************************/ +unsigned int* pg_alloc_page() { + unsigned int* p_page; + + p_page = (unsigned int*)PAGE_TABLE; + + // 1. Eintrag ist fuer Null-Pointer-Exception reserviert + // ausserdem liegt an die Page-Table an Adresse PAGE_TABLE + // somit ist est PAGE_TABLE + 4 KB frei (bis max. 3 MB, da beginnt der Heap) + for (int i = 1; i < 1024; i++) { + p_page++; + // pruefe ob Page frei + if (((*p_page) & PAGE_RESERVED) == 0) { + *p_page = (*p_page | PAGE_RESERVED); + return (unsigned int*)(i << 12); + } + } + return 0; +} + +/***************************************************************************** + * Funktion: pg_write_protect_page * + *---------------------------------------------------------------------------* + * Beschreibung: Schreibschutz fuer die uebergebene Seite aktivieren. * + * Dies fuer das Debugging nuetzlich. * + *****************************************************************************/ +void pg_write_protect_page(unsigned int* p_page) { + + /* hier muss Code eingefügt werden */ + + unsigned int mask = PAGE_WRITEABLE; // fill to 32bit + *p_page = *p_page & ~mask; // set writable to 0 +} + +/***************************************************************************** + * Funktion: pg_notpresent_page * + *---------------------------------------------------------------------------* + * Beschreibung: Seite als ausgelagert markieren. Nur fuer Testzwecke. * + *****************************************************************************/ +void pg_notpresent_page(unsigned int* p_page) { + + /* hier muss Code eingefügt werden */ + + unsigned int mask = PAGE_PRESENT; + *p_page = *p_page & ~mask; // set present to 0 +} + +/***************************************************************************** + * Funktion: pg_free_page * + *---------------------------------------------------------------------------* + * Beschreibung: Gibt eine 4 KB Seite frei. Es wird hierbei das RESERVED- * + * Bit geloescht. * + *****************************************************************************/ +void pg_free_page(unsigned int* p_page) { + int idx = (unsigned int)p_page >> 12; + + // ausserhalb Page ? + if (idx < 1 || idx > 1023) { + return; + } + + // Eintrag einlesen und aendern (PAGE_WRITEABLE loeschen) + p_page = (unsigned int*)PAGE_TABLE; + p_page += idx; + + *p_page = ((idx << 12) | PAGE_WRITEABLE | PAGE_PRESENT); +} + +/***************************************************************************** + * Funktion: pg_init * + *---------------------------------------------------------------------------* + * Beschreibung: Page-Tables einrichten und Paging mithilfe von * + * startup.asm aktivieren. * + *****************************************************************************/ +void pg_init() { + unsigned int i; + unsigned int* p_pdir; // Zeiger auf Page-Directory + unsigned int* p_page; // Zeiger auf einzige Page-Table fuer 4 KB Pages + unsigned int num_pages; // Anzahl 4 MB Pages die phys. Adressraum umfassen + + // wie viele 4 MB Seiten sollen als 'Present' angelegt werden, + // sodass genau der physikalische Adressraum abgedeckt ist? + num_pages = total_mem / (4096 * 1024); + + kout << "pg_init: " << total_mem << endl; + + kout << " total_mem: " << total_mem << endl; + kout << " #pages: " << total_mem / (4096 * 1024) << endl; + + // + // Aufbau des Page-Directory + // + + // Eintrag 0: Zeiger auf 4 KB Page-Table + p_pdir = (unsigned int*)PAGE_DIRECTORY; + *p_pdir = PAGE_TABLE | PAGE_WRITEABLE | PAGE_PRESENT; + + // Eintraege 1-1023: Direktes Mapping (1:1) auf 4 MB Pages (ohne Page-Table) + for (i = 1; i < 1024; i++) { + p_pdir++; + if (i > num_pages) { + *p_pdir = ((i << 22) | PAGE_BIGSIZE); + } else { + *p_pdir = ((i << 22) | PAGE_BIGSIZE | PAGE_WRITEABLE | PAGE_PRESENT); + } + } + + // + // 1. Page-Table + // + p_page = (unsigned int*)PAGE_TABLE; + + // ersten Eintrag loeschen -> not present, write protected -> Null-Pointer abfangen + *p_page = 0; + + // Eintraege 1-1023: Direktes Mapping (1:1) auf 4 KB page frames + for (i = 1; i < 1024; i++) { + p_page++; + + // Seiten unter FST_ALLOCABLE_PAGE reservieren, damit diese nicht + // alloziert werden und das System kaputt geht + if ((i << 12) >= FST_ALLOCABLE_PAGE) { + *p_page = ((i << 12) | PAGE_WRITEABLE | PAGE_PRESENT); + } else { + *p_page = ((i << 12) | PAGE_WRITEABLE | PAGE_PRESENT | PAGE_RESERVED); + } + } + + // Paging aktivieren (in startup.asm) + paging_on((unsigned int*)PAGE_DIRECTORY); +} diff --git a/c_os/kernel/Paging.h b/c_os/kernel/Paging.h new file mode 100644 index 0000000..3d48591 --- /dev/null +++ b/c_os/kernel/Paging.h @@ -0,0 +1,70 @@ +/***************************************************************************** + * * + * P A G I N G * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Rudimentaeres Paging: 1:1 Mapping fuer gesamten logischen* + * Adressraum. logische Adresse = physikalische Adresse * + * * + * Page-Directory (alle Eintraege present, read/write * + * 0. Eintrag zeigt auf eine Page-Table (4 KB Eintraege)* + * Alle restl. Eintraege sind 4 MB Seiten und verweisen * + * somit auf keine Page-Tabelle sondern direkt auf die * + * 4 MB Seite. * +* * + * Page-Table (Logische Adressen 0 - 4 MB) * + * 1. Eintrag not present, read-only * + * -> Null-Pointer abfangen * + * 2. restl. Eintraege present & read/write * + * * + * Memory-Laylout * + * * + * boot.asm * + * 0x07c0: Bootsector vom BIOS geladen * + * 0x0060: Boot-Code verschiebt sich hier hin * + * 0x9000: Setup-Code (max. 64K inkl. Stack) vom * + * Bootsector-Code geladen * + * setup.asm * + * 0x1000: System-Code (max. 512K) geladen * + * BIOS-Aufruf * + * 0x24000: Parameter fuer BIOS-Aufurf * + * 0x25000: Altes ESP sichern, vor BIOS-Aufruf * + * 0x26000: 16-Bit Code-Segment fuer BIOS-Aufurf * + * System-Code * + * 0x100000: System-Code, kopiert nach Umschalten in * + * den Protected Mode kopiert (GRUB kann nur * + * an Adressen >1M laden) * + * Globale Variablen: Direkt nach dem Code liegen die globalen * + * Variablen. * + * Paging: * + * 0x200000: Page-Directory * + * 0x201000: Page-Table * + * 0x202000: erste allozierbare Page (via Paging.cc) * + * 0x3FF000: letzte allozierbare Page * + * Heap: * + * 0x400000: Start-Adresse der Heap-Verwaltung * + * Ende: Letzte Adresse des phys. Speichers * + * * + * * + * Autor: Michael Schoettner, 2.2.2017 * + *****************************************************************************/ + +#ifndef __Paging_include__ +#define __Paging_include__ + +// ativiert paging +extern void pg_init(); + +// alloziert eine 4 KB Page +extern unsigned int* pg_alloc_page(); + +// Schreibschutz auf Seite setzen -> fuer debugging nuetzlich +extern void pg_write_protect_page(unsigned int* p_page); + +// Present Bit loeschen +extern void pg_notpresent_page(unsigned int* p_page); + +// gibt eine 4 KB Page frei +extern void pg_free_page(unsigned int* p_page); + +#endif diff --git a/c_os/kernel/allocator/TreeAllocator.cc b/c_os/kernel/allocator/TreeAllocator.cc index 9c7c6bd..1ec58b2 100755 --- a/c_os/kernel/allocator/TreeAllocator.cc +++ b/c_os/kernel/allocator/TreeAllocator.cc @@ -10,6 +10,7 @@ void TreeAllocator::init() { this->free_start->left = NULL; this->free_start->right = NULL; this->free_start->parent = NULL; + this->free_start->red = false; // The root is always black this->free_start->next = (list_block_t*)this->free_start; this->free_start->previous = (list_block_t*)this->free_start; @@ -59,9 +60,6 @@ void* TreeAllocator::alloc(unsigned int req_size) { unsigned int size = this->get_size(best_fit); if constexpr (DEBUG) { kout << " - Found best-fit: " << hex << (unsigned int)best_fit << endl; } - // Remove the block first so we can insert correctly when cutting - // kout << " - Removing block from freelist" << endl; - this->rbt_remove(best_fit); if (size > HEAP_MIN_FREE_BLOCK_SIZE + rreq_size + sizeof(list_block_t)) { // Block can be cut if constexpr (DEBUG) { kout << " - Allocating " << dec << rreq_size << " Bytes with cutting" << endl; } @@ -77,6 +75,11 @@ void* TreeAllocator::alloc(unsigned int req_size) { // need to remove it from the freelist, which is done for both cases if constexpr (DEBUG) { kout << " - Allocating " << dec << rreq_size << " Bytes without cutting" << endl; } } + // Remove the old block from the freelist + // BUG: If the first allocation allocates the whole heap, this removal will crash the paging + // as the freelist will no longer contain any notes, gives NullPointerException as it's not handled + // kout << " - Removing block from freelist" << endl; + this->rbt_remove(best_fit); if constexpr (DEBUG) { kout << " - Returned address " << hex << (unsigned int)((char*)best_fit + sizeof(list_block_t)) << endl; } return (void*)((char*)best_fit + sizeof(list_block_t)); diff --git a/c_os/kernel/allocator/TreeAllocator.h b/c_os/kernel/allocator/TreeAllocator.h index 48b0970..c2d46b4 100755 --- a/c_os/kernel/allocator/TreeAllocator.h +++ b/c_os/kernel/allocator/TreeAllocator.h @@ -45,7 +45,7 @@ private: void dump_free_memory(tree_block_t* node); - // NOTE: Would be nice to have this stuff somewhere else for general use, + // NOTE: Would be nice to have this stuff somewhere else for general use (scheduling?) // but that would require different rbt_node/dll_node structures. // If I need this again later I should move it. void rbt_rot_l(tree_block_t* x); diff --git a/c_os/kernel/interrupts/Bluescreen.cc b/c_os/kernel/interrupts/Bluescreen.cc new file mode 100644 index 0000000..1cd36b8 --- /dev/null +++ b/c_os/kernel/interrupts/Bluescreen.cc @@ -0,0 +1,306 @@ +/***************************************************************************** + * * + * B L U E S C R E E N * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. * + * ist der Stack und oder Heap kaputt, weswegen hier nicht * + * kout etc. verwendet wird. * + * * + * Autor: Michael Schoettner, 11.12.2018 * + *****************************************************************************/ +#include "devices/CGA.h" +#include "kernel/Globals.h" + +// in startup.asm +extern "C" { + // CR2 auslesen + unsigned int get_page_fault_address(); + + // 1st level interrupt handler in startup.asm sichert Zeiger auf Stackframe + // unmittelbar nach dem Interrupt und nachdem alle Register mit PUSHAD + // gesichert wurden + // |-------------| + // |  EFLAGS | + // |-------------| + // | CS | + // |-------------| + // | EIP | + // |-------------| + // | [ErrorCode] | + // |-------------| + // | EAX | + // |-------------| + // | ECX | + // |-------------| + // | EDX | + // |-------------| + // | EBX | + // |-------------| + // | ESP | + // |-------------| + // | EBP | + // |-------------| + // | ESI | + // |-------------| + // | EDI | + // |-------------| <-- int_esp + + void get_int_esp(unsigned int** esp); +} + +void break_on_bluescreen() { + + /* wenn auf diese Methode ein breakpoint in GDB gesetzt wird + so kann man sich mithilfe des Hex-Dumps umsehen + */ +} + +// Cursor-Position +int bs_xpos = 0; +int bs_ypos = 0; + +/***************************************************************************** + * Funktion: bs_clear * + *---------------------------------------------------------------------------* + * Beschreibung: Bildschirm loeschen. * + *****************************************************************************/ +void bs_clear() { + unsigned int x; + unsigned int y; + unsigned short* ptr = (unsigned short*)0xb8000; + + for (x = 0; x < 80; x++) { + for (y = 0; y < 25; y++) { + *(ptr + y * 80 + x) = (short)0x1F00; + } + } + + bs_xpos = 0; + bs_ypos = 0; +} + +/***************************************************************************** + * Funktion: bs_lf * + *---------------------------------------------------------------------------* + * Beschreibung: Zeilenvorschub. * + *****************************************************************************/ +void bs_lf() { + bs_ypos++; + bs_xpos = 0; +} + +/***************************************************************************** + * Funktion: bs_print_char * + *---------------------------------------------------------------------------* + * Beschreibung: Ein Zeichen ausgeben. * + *****************************************************************************/ +void bs_print_char(char c) { + unsigned char* ptr = (unsigned char*)0xb8000; + + *(ptr + bs_ypos * 80 * 2 + bs_xpos * 2) = c; + bs_xpos++; +} + +/***************************************************************************** + * Funktion: bs_print_string * + *---------------------------------------------------------------------------* + * Beschreibung: Eine Zeichenkette ausgeben. * + *****************************************************************************/ +void bs_print_string(char* str) { + + while (*str != '\0') { + bs_print_char(*str); + str++; + } +} + +/***************************************************************************** + * Funktion: bs_printHexDigit * + *---------------------------------------------------------------------------* + * Beschreibung: Ein Hex-Zeichen ausgeben. * + *****************************************************************************/ +void bs_printHexDigit(int c) { + if (c < 10) { + bs_print_char('0' + (unsigned char)c); + } else { + bs_print_char('A' + (unsigned char)(c - 10)); + } +} + +/***************************************************************************** + * Funktion: bs_print_uintHex * + *---------------------------------------------------------------------------* + * Beschreibung: Integer ausgeben. * + *****************************************************************************/ +void bs_print_uintHex(unsigned int c) { + for (int i = 28; i >= 0; i = i - 4) { + bs_printHexDigit((c >> i) & 0xF); + } +} + +/***************************************************************************** + * Funktion: bs_printReg * + *---------------------------------------------------------------------------* + * Beschreibung: String mit Integer ausgeben. Wird verwendet um ein * + * Register auszugeben. * + *****************************************************************************/ +void bs_printReg(char* str, int value) { + bs_print_string(str); + bs_print_uintHex(value); + bs_print_string(" \0"); +} + +/***************************************************************************** + * Funktion: bs_dump * + *---------------------------------------------------------------------------* + * Beschreibung: Hauptroutine des Bluescreens. * + *****************************************************************************/ +void bs_dump(unsigned int exceptionNr) { + unsigned int* int_esp; + unsigned int* sptr; + unsigned int faultAdress; + unsigned int has_error_code = 0; + + bs_clear(); + bs_print_string("HHUos crashed with Exception \0"); + + // Exception mit Error-Code? + if ((exceptionNr >= 8 && exceptionNr <= 14) || exceptionNr == 17 || exceptionNr == 30) { + has_error_code = 1; + } + + // Liegt ein Page-Fault vor? + if (exceptionNr == 14) { + faultAdress = get_page_fault_address(); + // Zugriff auf Seite 0 ? -> Null-Ptr. Exception + if ((faultAdress & 0xFFFFF000) == 0) { + exceptionNr = 0x1B; + } + } + + bs_print_uintHex(exceptionNr); + bs_print_string(" (\0"); + + // Spruch ausgeben + switch (exceptionNr) { + case 0x00: bs_print_string("Divide Error\0"); break; + case 0x01: bs_print_string("Debug Exception\0"); break; + case 0x02: bs_print_string("NMI\0"); break; + case 0x03: bs_print_string("Breakpoint Exception\0"); break; + case 0x04: bs_print_string("Into Exception\0"); break; + case 0x05: bs_print_string("Index out of range Exception\0"); break; + case 0x06: bs_print_string("Invalid Opcode\0"); break; + case 0x08: bs_print_string("Double Fault\0"); break; + case 0x0D: bs_print_string("General Protection Error\0"); break; + case 0x0E: bs_print_string("Page Fault\0"); break; + case 0x18: bs_print_string("Stack invalid\0"); break; + case 0x19: bs_print_string("Return missing\0"); break; + case 0x1A: bs_print_string("Type Test Failed\0"); break; + case 0x1B: bs_print_string("Null pointer exception\0"); break; + case 0x1C: bs_print_string("MAGIC.StackTest failed\0"); break; + case 0x1D: bs_print_string("Memory-Panic\0"); break; + case 0x1E: bs_print_string("Pageload failed\0"); break; + case 0x1F: bs_print_string("Stack overflow\0"); break; + default: bs_print_string("unknown\0"); + } + bs_print_string(")\0"); + bs_lf(); + + // Zeiger auf int_esp ueber startup.asm beschaffen (Stack-Layout siehe Anfang dieser Datei) + get_int_esp(&int_esp); + + // wir müssen den Inhalt auslesen und das als Zeiger verwenden, um den Stack auszulesen + sptr = (unsigned int*)*int_esp; + + bs_lf(); + + // wichtigste Register ausgeben + + // Exception mit Error-Code? + bs_printReg("EIP=\0", *(sptr + 8 + has_error_code)); + bs_printReg("EBP=\0", *(sptr + 2)); + bs_printReg("ESP=\0", *(sptr + 3)); + bs_printReg(" CS=\0", *(sptr + 9 + has_error_code)); + bs_lf(); + + // verbleibende nicht-fluechtige Register ausgeben + bs_printReg("EBX=\0", *(sptr + 4)); + bs_printReg("ESI=\0", *(sptr + 1)); + bs_printReg("EDI=\0", *(sptr)); + bs_lf(); + + // verbleibende fluechtige Register ausgeben + bs_printReg("EDX=\0", *(sptr + 5)); + bs_printReg("ECX=\0", *(sptr + 6)); + bs_printReg("EAX=\0", *(sptr + 7)); + bs_printReg("EFL=\0", *(sptr + 10)); + bs_lf(); + + // Pagefault oder Null-Pointer? + if (exceptionNr == 14 || exceptionNr == 0x1B) { + bs_lf(); + bs_print_string("Fault address = \0"); + bs_print_uintHex(faultAdress); + bs_lf(); + + bs_print_string("Last useable address = \0"); + bs_print_uintHex(total_mem - 1); + + bs_lf(); + } + + // Exception mit Error-Code? + if (has_error_code == 1) { + int error_nr = *(sptr + 8); + + if (exceptionNr == 14) { + if (error_nr == 3) { + bs_print_string("Error: write access to read-only page.\0"); + } else if (error_nr == 2) { + bs_print_string("Error: read access to not-present page.\0"); + } else if (error_nr == 0) { + bs_print_string("Error: access to a not-present page.\0"); + } else { + bs_print_string("Error code = \0"); + bs_print_uintHex(error_nr); + } + bs_lf(); + } else { + bs_print_string("Error code = \0"); + bs_print_uintHex(error_nr); + bs_lf(); + } + } + + // Calling stack ... + bs_lf(); + bs_print_string("Calling Stack:\0"); + bs_lf(); + int x = 0; + unsigned int* ebp = (unsigned int*)*(sptr + 2); + unsigned int raddr; + + // solange eip > 1 MB && ebp < 128 MB, max. Aufruftiefe 10 + while (*ebp > 0x100000 && *ebp < 0x8000000 && x < 10) { + + raddr = *(ebp + 1); + bs_printReg(" raddr=\0", raddr); + bs_lf(); + + // dynamische Kette -> zum Aufrufer + ebp = (unsigned int*)*ebp; + + x++; + } + if (x == 0) { + bs_print_string(" empty\0"); + bs_lf(); + } + bs_lf(); + + // nur falls gdb benutzt werden soll + break_on_bluescreen(); + + bs_print_string("System halted\0"); +} diff --git a/c_os/kernel/interrupts/Bluescreen.h b/c_os/kernel/interrupts/Bluescreen.h new file mode 100644 index 0000000..bcc5e62 --- /dev/null +++ b/c_os/kernel/interrupts/Bluescreen.h @@ -0,0 +1,19 @@ +/***************************************************************************** + * * + * B L U E S C R E E N * + * * + *---------------------------------------------------------------------------* + * Beschreibung: Ein Bluescreen, falls eine x86 Exception auftritt. Evt. * + * ist der Stack und oder Heap kaputt, weswegen hier nicht * + * kout etc. verwendet wird. * + * * + * Autor: Michael Schoettner, 2.2.2017 * + *****************************************************************************/ + +#ifndef __Bluescreen_include__ +#define __Bluescreen_include__ + +// dump blue screen (will not return) +void bs_dump(unsigned int exceptionNr); + +#endif diff --git a/c_os/kernel/interrupts/IntDispatcher.cc b/c_os/kernel/interrupts/IntDispatcher.cc index af807b2..4230820 100755 --- a/c_os/kernel/interrupts/IntDispatcher.cc +++ b/c_os/kernel/interrupts/IntDispatcher.cc @@ -13,6 +13,7 @@ #include "kernel/interrupts/IntDispatcher.h" #include "kernel/CPU.h" #include "kernel/Globals.h" +#include "kernel/interrupts/Bluescreen.h" extern "C" void int_disp(unsigned int slot); @@ -31,9 +32,16 @@ extern "C" void int_disp(unsigned int slot); void int_disp(unsigned int vector) { /* hier muss Code eingefuegt werden */ + if (vector < 32) { + bs_dump(vector); + cpu.halt(); + } - // kout << "Ein Interrupt ist aufgetreten (vector: " << vector << ")" << endl; - intdis.report(vector); + if (intdis.report(vector) < 0) { + kout << "Panic: unexpected interrupt " << vector; + kout << " - processor halted." << endl; + cpu.halt(); + } } /***************************************************************************** diff --git a/c_os/kernel/threads/Dispatch.cc b/c_os/kernel/threads/Dispatch.cc old mode 100755 new mode 100644 diff --git a/c_os/kernel/threads/Dispatch.h b/c_os/kernel/threads/Dispatch.h old mode 100755 new mode 100644 diff --git a/c_os/kernel/threads/IdleThread.h b/c_os/kernel/threads/IdleThread.h old mode 100755 new mode 100644 diff --git a/c_os/kernel/threads/Scheduler.cc b/c_os/kernel/threads/Scheduler.cc old mode 100755 new mode 100644 index 35af795..dead80a --- a/c_os/kernel/threads/Scheduler.cc +++ b/c_os/kernel/threads/Scheduler.cc @@ -96,10 +96,12 @@ void Scheduler::yield() { /* hier muss Code eingefuegt werden */ - // if (this->readyQueue.isEmpty()) { - // // Idle thread running - // return; - // } + // When only one thread exists (IdleThread) it can't yield as the readyqueue becomes empty + // and this is not handled anywhere else + if (this->readyQueue.isEmpty()) { + // Idle thread running + return; + } Thread& next = *(Thread*)this->readyQueue.dequeue(); this->readyQueue.enqueue(this->get_active()); diff --git a/c_os/kernel/threads/Scheduler.h b/c_os/kernel/threads/Scheduler.h old mode 100755 new mode 100644 diff --git a/c_os/kernel/threads/Thread.asm b/c_os/kernel/threads/Thread.asm old mode 100644 new mode 100755 diff --git a/c_os/kernel/threads/Thread.cc b/c_os/kernel/threads/Thread.cc old mode 100644 new mode 100755 diff --git a/c_os/kernel/threads/Thread.h b/c_os/kernel/threads/Thread.h old mode 100755 new mode 100644 diff --git a/c_os/kernel/threads/Thread.inc b/c_os/kernel/threads/Thread.inc old mode 100644 new mode 100755 diff --git a/c_os/kernel/threads/ThreadState.h b/c_os/kernel/threads/ThreadState.h old mode 100644 new mode 100755 diff --git a/c_os/lib/Queue.h b/c_os/lib/Queue.h old mode 100755 new mode 100644 diff --git a/c_os/main.cc b/c_os/main.cc index beef0a7..d213b14 100755 --- a/c_os/main.cc +++ b/c_os/main.cc @@ -11,6 +11,8 @@ *****************************************************************************/ #include "kernel/Globals.h" +#include "kernel/Paging.h" +#include "kernel/threads/IdleThread.h" #include "user/CoopThreadDemo.h" #include "user/HelloWorldThread.h" #include "user/VBEdemo.h" @@ -22,11 +24,11 @@ int main() { allocator.init(); // Initialize scrollback buffer after allocator.init() - kout.init(5); + // kout.init(5); // Startmeldung if constexpr (!DEBUG) { - kout << "HHUos 0.7\n" + kout << "HHUos 0.8\n" << "=========\n" << "Unterstuetzte Funktionen:\n" << " - Bildschirmausgaben\n" @@ -36,6 +38,7 @@ int main() { << " - Tastatureingaben per Interrupt\n" << " - Kooperative Threads\n" << " - VESA Graphics Mode\n" + << " - Paging\n" << endl; } @@ -47,18 +50,27 @@ int main() { /* hier muss Code eingefuegt werden */ cpu.enable_int(); - // text_demo(); - // sound_demo(); - // keyboard_demo(); - // heap_demo(); - // key_irq_demo(); - // coroutineDemo.main(); + // Activate paging + // This has to happen after the allocator is initialized but before the scheduler is started + // TODO: Scheduler triggers bluescreen? + pg_init(); - // Threads anlegen + // Trigger Bluescreen + // kout << "Trigger Bluescreen, if you can read this it didn't work" << endl; + + // BlueScreen 1 + // asm("int $3"); + + // BlueScreen 2 + // unsigned int* page = pg_alloc_page(); + // *page = 42; // Should work + // pg_write_protect_page(page); + // *page = 42; // should trigger BlueScreen + + // Demo threads anlegen // scheduler.ready(new HelloWorldThread()); - // scheduler.ready(new CoopThreadDemo()); - - scheduler.ready(new VBEdemo()); + scheduler.ready(new CoopThreadDemo()); + // scheduler.ready(new VBEdemo()); // Switch to VESA graphics mode // Scheduler starten (schedule() erzeugt den Idle-Thread) scheduler.schedule(); @@ -66,5 +78,6 @@ int main() { // TODO: Use templates for queue so threads don't have to be casted down from chain // TODO: Move scrollback control to thread + // Scheduler doesn't return return 0; } diff --git a/c_os/startup.asm b/c_os/startup.asm old mode 100755 new mode 100644 index 5c365e3..f592caa --- a/c_os/startup.asm +++ b/c_os/startup.asm @@ -9,7 +9,7 @@ ;* die weitere Ausfuehrung durch C-Code erfolgen kann. * ;* * ;* Autor: Olaf Spinczyk, TU Dortmund * -;* Michael Schoettner, HHU, 9.9.2016 * +;* Michael Schoettner, HHU, 15.12.2018 * ;****************************************************************************** ; Multiboot-Konstanten @@ -31,6 +31,10 @@ MULTIBOOT_EAX_MAGIC equ 0x2badb002 [GLOBAL idt] [GLOBAL __cxa_pure_virtual] [GLOBAL bios_call] +[GLOBAL invalidate_tlb_entry] +[GLOBAL paging_on] +[GLOBAL get_page_fault_address] +[GLOBAL get_int_esp] ; Michael Schoettner: ; Nachfolgender label steht fuer das 'delete', welches jetzt implementiert @@ -138,7 +142,9 @@ _fini_done: %macro wrapper 1 wrapper_%1: - push eax + pushad ; alle Register sichern (fuer den Bluescreen) + mov ecx, int_esp ; Stack_zeiger sichern, fuer Zugriff im Bluescreen + mov [ecx], esp mov al,%1 jmp wrapper_body %endmacro @@ -161,7 +167,7 @@ wrapper_body: add esp,4 ; Parameter vom Stack entfernen pop edx ; fluechtige Register wieder herstellen pop ecx - pop eax + popad ; alle Register wiederherstellen iret ; fertig! ; @@ -252,6 +258,46 @@ bios_call: lidt [idt_descr] ret +; Paging aktivieren +; (siehe Paging.cc) +paging_on: + mov eax,[4+esp] ; Parameter Addr. Page-Dir. ins eax Register + mov ebx, cr4 + or ebx, 0x10 ; 4 MB Pages aktivieren + mov cr4, ebx ; CR4 schreiben + mov cr3, eax ; Page-Directory laden + mov ebx, cr0 + or ebx, 0x80010000 ; Paging aktivieren + mov cr0, ebx + ret + +; Paging-Fault-Adresse holen +; (siehe Paging.cc) +get_page_fault_address: + mov eax,cr2 + ret + +; Invalidiert eine Seite im TLB. Dies notwendig, falls eine +; die Bits Present, R/W in einem Seitentabelleneintrag +; geaendert werden. Falls die Seite im TLB gespeichert ist +; wuerde die MMU nichts von diesen Aenderungen erkennen, +; da die MMU dann nicht auf die Seitentabellen zugreift. +; (siehe Paging.cc) +invalidate_tlb_entry: + mov eax, [esp+4] + invlpg [eax] + ret + +; Auslesen von 'int_esp' +; wird im Bluescreen benoetigt, um den Stacks zuzugreifen +; +; C Prototyp: void get_int_esp (unsigned int** esp); +get_int_esp: + mov eax,[4+esp] ; esp + mov ecx, int_esp + mov [eax], ecx + ret + [SECTION .data] @@ -319,3 +365,22 @@ gdt_48: idt16_descr: dw 1024 ; idt enthaelt max. 1024 Eintraege dd 0 ; Adresse 0 + +; +; Stack-Zeiger fuer Bluescreen +; (genauerer Stack-Aufbau siehe Bluescreen.cc) +; +; |-------------| +; |  EFLAGS | +; |-------------| +; | CS | +; |-------------| +; | EIP | +; |-------------| +; | [ErrorCode] | +; |-------------| +; | alle Regs. | +; | (PUSHAD) | +; |-------------| <-- int_esp +int_esp: + db 0,0,0,0 diff --git a/c_os/user/CoopThreadDemo.cc b/c_os/user/CoopThreadDemo.cc old mode 100755 new mode 100644 diff --git a/c_os/user/CoopThreadDemo.h b/c_os/user/CoopThreadDemo.h old mode 100755 new mode 100644 diff --git a/c_os/user/HelloWorldThread.cc b/c_os/user/HelloWorldThread.cc old mode 100755 new mode 100644 diff --git a/c_os/user/HelloWorldThread.h b/c_os/user/HelloWorldThread.h old mode 100755 new mode 100644 diff --git a/c_os/user/LoopThread.cc b/c_os/user/LoopThread.cc old mode 100755 new mode 100644 diff --git a/c_os/user/LoopThread.h b/c_os/user/LoopThread.h old mode 100755 new mode 100644 diff --git a/tools/build b/tools/build index 9d69b4d..2fe2ee0 100755 Binary files a/tools/build and b/tools/build differ