From 679eb8cf5716a3cc4b9fcd5702dec23ed5bd8dc4 Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Wed, 1 Feb 2023 20:42:05 -0600 Subject: [PATCH] More advanced Fault handling (recovers to text mode), Keyboard handler converted to C and improved (shifting, simple get_key added) --- Makefile | 2 +- boot.nasm | 2 +- fault.nasm | 146 ++++++++++++++++++++++++++++++++++++++++++ handler.nasm | 172 +++----------------------------------------------- interrupt.c | 77 +++++++++++++++++++++- interrupt.h | 5 ++ kernel.c | 60 ++++++++++++++++-- link.ld | 2 +- usermode.nasm | 2 + 9 files changed, 293 insertions(+), 175 deletions(-) create mode 100644 fault.nasm diff --git a/Makefile b/Makefile index b5849b0..413c5ca 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o gdt.o usermode.o paging.o +objects = entry.o kernel.o task.o handler.o interrupt.o v86.o print.o tss.o dosfs/dosfs.o gdt.o usermode.o paging.o fault.o CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding -march=pentium-m -fno-stack-protector -Wno-int-conversion -nostdlib -c %.o: %.nasm diff --git a/boot.nasm b/boot.nasm index eeef474..cedfe4a 100644 --- a/boot.nasm +++ b/boot.nasm @@ -47,7 +47,7 @@ out 0x92, al after: mov esi, 0x8000 mov edi, 0x100000 -mov ecx, 17000 +mov ecx, 0x10000 rep movsb jmp 08h:0x100000 gdt_desc: diff --git a/fault.nasm b/fault.nasm new file mode 100644 index 0000000..508552f --- /dev/null +++ b/fault.nasm @@ -0,0 +1,146 @@ +extern error_screen ; 80x50 words + +; Switches to text mode and shit +extern error_environment +_fault_coda: +xchg bx,bx +mov ax, 0x10 +mov es, ax +; move to TOP OF kernel stack +mov ebp, 0x400000 +mov esp, ebp +call error_environment +.hlt: +hlt +jmp .hlt + +global unhandled_handler +unhandled_handler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | 'E' | 'R' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'R' | 'O' << 16 +mov dword [error_screen+0x08], 0x0f000f00 | 'R' | '!' << 16 +jmp _fault_coda + +global pageFaultHandler +pageFaultHandler: +mov ax, 0x10 +mov ds, ax +pop eax ; error code +mov ebx, 0x0f000f00 | '0' | '!' << 16 +and eax, 0x7 ; U/S,R/W,P +add ebx, eax +mov dword [error_screen+0x00], 0x0f000f00 | 'P' | 'G' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'F' | 'L' << 16 +mov dword [error_screen+0x08], 0x0f000f00 | 'T' | ':' << 16 +mov dword [error_screen+0x0C], ebx +jmp _fault_coda + +extern gpf_handler_v86 +global gpfHandler +gpfHandler: +push eax +mov ax, 0x10 +mov ds, ax +mov eax, dword [esp+16] ; EFLAGS +and eax, 1 << 17 ; VM flag +test eax, eax +pop eax +jnz gpf_handler_v86 +jmp gpf_handler_32 +gpf_unhandled: +mov dword [error_screen+0x00], 0x0f000f00 | 'G' | 'P' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'F' | '!' << 16 +jmp _fault_coda + +gpf_handler_32: +push eax +mov eax, dword [esp+8] ; EIP +movzx eax, word [eax] +cmp eax, 0x30CD ; int 0x30 +jne gpf_unhandled +pop eax ; return value +jmp return_prev_task + +extern return_prev_task + +global divisionErrorHandler +divisionErrorHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'D' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'E' | '!' << 16 +jmp _fault_coda +global boundRangeHandler +boundRangeHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'B' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'R' | '!' << 16 +jmp _fault_coda +global invalidOpcodeHandler +invalidOpcodeHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'U' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'D' | '!' << 16 +jmp _fault_coda +global deviceNotAvailableHandler +deviceNotAvailableHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'N' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'D' | '!' << 16 +jmp _fault_coda +global doubleFaultHandler +doubleFaultHandler: +mov ax, 0x10 +mov ds, ax +mov dword [0xb8000+0x00], 0x0f000f00 | '#' | 'D' << 16 +mov dword [0xb8000+0x04], 0x0f000f00 | 'F' | '!' << 16 +; double faults simply abort right then +.hlt: hlt +jmp .hlt +global invalidTSSHandler +invalidTSSHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'T' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'S' | '!' << 16 +jmp _fault_coda +global segmentNotPresentHandler +segmentNotPresentHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'N' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'P' | '!' << 16 +jmp _fault_coda +global stackSegmentHandler +stackSegmentHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'S' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'S' | '!' << 16 +jmp _fault_coda +global x87FloatingHandler +x87FloatingHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'M' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'F' | '!' << 16 +jmp _fault_coda +global alignmentCheckHandler +alignmentCheckHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'A' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'C' | '!' << 16 +jmp _fault_coda +global controlProtectionHandler +controlProtectionHandler: +mov ax, 0x10 +mov ds, ax +mov dword [error_screen+0x00], 0x0f000f00 | '#' | 'C' << 16 +mov dword [error_screen+0x04], 0x0f000f00 | 'P' | '!' << 16 +jmp _fault_coda diff --git a/handler.nasm b/handler.nasm index 73b62f6..366379d 100644 --- a/handler.nasm +++ b/handler.nasm @@ -1,61 +1,4 @@ -extern unhandled_handler -unhandled_handler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | 'E' | 'R' << 16 -mov dword [0xb8004], 0x0f000f00 | 'R' | 'O' << 16 -mov dword [0xb8008], 0x0f000f00 | 'R' | '!' << 16 -.hlt: -hlt -jmp .hlt - -global pageFaultHandler -pageFaultHandler: -mov ax, 0x10 -mov ds, ax -pop eax ; error code -mov ebx, 0x0f000f00 | '0' | '!' << 16 -and eax, 0x7 ; U/S,R/W,P -add ebx, eax -mov dword [0xb8000], 0x0f000f00 | 'P' | 'G' << 16 -mov dword [0xb8004], 0x0f000f00 | 'F' | 'L' << 16 -mov dword [0xb8008], 0x0f000f00 | 'T' | ':' << 16 -mov dword [0xb800C], ebx -.hlt: -hlt -jmp .hlt - -extern gpf_handler_v86 -global gpfHandler -gpfHandler: -push eax -mov ax, 0x10 -mov ds, ax -mov eax, dword [esp+16] ; EFLAGS -and eax, 1 << 17 ; VM flag -test eax, eax -pop eax -jnz gpf_handler_v86 -jmp gpf_handler_32 -gpf_unhandled: -mov dword [0xb8000], 0x0f000f00 | 'G' | 'P' << 16 -mov dword [0xb8004], 0x0f000f00 | 'F' | '!' << 16 -.hlt: -hlt -jmp .hlt - -gpf_handler_32: -push eax -mov eax, dword [esp+8] ; EIP -movzx eax, word [eax] -cmp eax, 0x30CD ; int 0x30 -jne gpf_unhandled -pop eax ; return value -jmp return_prev_task - -extern return_prev_task - -scancodesToAscii: db 0, 0 ; 0x00 - 0x01 +oldscancodesToAscii: db 0, 0 ; 0x00 - 0x01 db "1234567890" ; 0x02 - 0x0B db "-=" ; 0x0C - 0x0D db 0, 0 ; 0x0E - 0x0F @@ -71,8 +14,8 @@ db ' ' ; 0x39 db 'C' scancodesToAsciiEnd: cursorCurrent: dd 0xb8000 + (80*6*2) -global keyboardHandler -keyboardHandler: +global oldkeyboardHandler +oldkeyboardHandler: push eax push ebx push ds @@ -82,7 +25,7 @@ xor eax, eax in al, 0x60 cmp eax, 0x3A jg .done -mov al, [scancodesToAscii+eax] +mov al, [oldscancodesToAscii+eax] test al, al jz .done mov ebx, [cursorCurrent] @@ -98,8 +41,7 @@ pop eax iret KBDWAIT: db 0 -global kbd_wait -kbd_wait: +oldkbd_wait: mov byte [KBDWAIT], 0 .loop: hlt @@ -108,13 +50,15 @@ test eax, eax jz .loop ret +TIMERVAL: dd 0 global timerHandler timerHandler: push eax push ds mov ax, 0x10 mov ds, ax -inc byte [(0xb8000 + (80*8*2))] +;inc byte [(0xb8000 + (80*8*2))] +inc dword [TIMERVAL] mov al, 0x20 out 0x20, al pop ds @@ -159,103 +103,3 @@ jmp $+2 jmp $+2 out 0xA1, al ret - -global divisionErrorHandler -divisionErrorHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'D' << 16 -mov dword [0xb8004], 0x0f000f00 | 'E' | '!' << 16 -.hlt: -hlt -jmp .hlt -global boundRangeHandler -boundRangeHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'B' << 16 -mov dword [0xb8004], 0x0f000f00 | 'R' | '!' << 16 -.hlt: -hlt -jmp .hlt -global invalidOpcodeHandler -invalidOpcodeHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'U' << 16 -mov dword [0xb8004], 0x0f000f00 | 'D' | '!' << 16 -.hlt: -hlt -jmp .hlt -global deviceNotAvailableHandler -deviceNotAvailableHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'N' << 16 -mov dword [0xb8004], 0x0f000f00 | 'D' | '!' << 16 -.hlt: -hlt -jmp .hlt -global doubleFaultHandler -doubleFaultHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'D' << 16 -mov dword [0xb8004], 0x0f000f00 | 'F' | '!' << 16 -.hlt: -hlt -jmp .hlt -global invalidTSSHandler -invalidTSSHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'T' << 16 -mov dword [0xb8004], 0x0f000f00 | 'S' | '!' << 16 -.hlt: -hlt -jmp .hlt -global segmentNotPresentHandler -segmentNotPresentHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'N' << 16 -mov dword [0xb8004], 0x0f000f00 | 'P' | '!' << 16 -.hlt: -hlt -jmp .hlt -global stackSegmentHandler -stackSegmentHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'S' << 16 -mov dword [0xb8004], 0x0f000f00 | 'S' | '!' << 16 -.hlt: -hlt -jmp .hlt -global x87FloatingHandler -x87FloatingHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'M' << 16 -mov dword [0xb8004], 0x0f000f00 | 'F' | '!' << 16 -.hlt: -hlt -jmp .hlt -global alignmentCheckHandler -alignmentCheckHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'A' << 16 -mov dword [0xb8004], 0x0f000f00 | 'C' | '!' << 16 -.hlt: -hlt -jmp .hlt -global controlProtectionHandler -controlProtectionHandler: -mov ax, 0x10 -mov ds, ax -mov dword [0xb8000], 0x0f000f00 | '#' | 'C' << 16 -mov dword [0xb8004], 0x0f000f00 | 'P' | '!' << 16 -.hlt: -hlt -jmp .hlt diff --git a/interrupt.c b/interrupt.c index dc850dc..f1bec2e 100644 --- a/interrupt.c +++ b/interrupt.c @@ -84,8 +84,6 @@ void IRQ_clear_mask(char IRQline) { char v86_if = 0; extern uint16_t *ivt; extern void real_test(); -__attribute((__no_caller_saved_registers__)) -extern void kbd_wait(); extern void jmp_usermode_test(); __attribute((__no_caller_saved_registers__)) extern void return_prev_task(); @@ -236,8 +234,81 @@ void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code) { vga[0] = 'G'; vga[2] = 'S'; int_printWord(frame->gs, (uint16_t*)&vga[4]); vga += 14; } +uint8_t scancodesToAscii[0x3B] = +"\0\0" // 0x00 - 0x01 +"1234567890" // 0x02 - 0x0B +"-=" // 0x0C - 0x0D +"\0\0" // 0x0E - 0x0F +"qwertyuiop[]" // 0x10 - 0x1B +"\0\0" // 0x1C - 0x1D +"asdfghjkl;'`" // 0x1E - 0x29 +"\0" // 0x2A +"\\zxcvbnm,./" // 0x2B - 0x35 +"\0" // 0x36 +"*" // 0x37 +"\0" // 0x38 +" " // 0x39 +"\0"; // 0x3A +uint8_t scancodesToAsciiShift[0x3B] = +"\0\0" // 0x00 - 0x01 +"!@#$%^&*()" // 0x02 - 0x0B +"_+" // 0x0C - 0x0D +"\0\0" // 0x0E - 0x0F +"QWERTYUIOP{}" // 0x10 - 0x1B +"\0\0" // 0x1C - 0x1D +"ASDFGHJKL:\"~" // 0x1E - 0x29 +"\0" // 0x2A +"|ZXCVBNM<>?" // 0x2B - 0x35 +"\0" // 0x36 +"*" // 0x37 +"\0" // 0x38 +" " // 0x39 +"\0"; // 0x3A +uint8_t _KBDWAIT; +uint8_t _KEYCAPS = 0, _KEYSHIFT = 0; +uint8_t _LSTKEY = 0; +__attribute__ ((interrupt)) +void keyboardHandler(struct interrupt_frame *frame) { + uint8_t key; + asm volatile("inb $0x60, %%al":"=a"(key)); + if (key == 0x3A) { // caps lock press + _KEYCAPS = !_KEYCAPS; + } else if (key == 0x2A || key == 0x36) { // left and right shift press + _KEYSHIFT = 1; + } else if (key == 0xAA || key == 0xB6) { // left and right shift release + _KEYSHIFT = 0; + } else if (key < 0x3B) { + uint8_t ascii = _KEYCAPS != _KEYSHIFT ? + scancodesToAsciiShift[key] : + scancodesToAscii[key]; + if (ascii) { + _LSTKEY = ascii; + _KBDWAIT = 1; + } + } + asm volatile("outb %%al, $0x20"::"a"(0x20)); +} + +__attribute((__no_caller_saved_registers__)) +void kbd_wait() { + _KBDWAIT = 0; + while(!_KBDWAIT) { + asm volatile("hlt"); + } +} + +__attribute((__no_caller_saved_registers__)) +uint8_t get_key() { + while(!_LSTKEY) { + asm volatile("hlt"); + } + uint8_t k = _LSTKEY; + _LSTKEY = 0; + return k; +} + extern void timerHandler(); -extern void keyboardHandler(); +//extern void keyboardHandler(); extern void gpfHandler(); extern void pageFaultHandler(); extern void unhandled_handler(); diff --git a/interrupt.h b/interrupt.h index 1d8656a..5aeefcf 100644 --- a/interrupt.h +++ b/interrupt.h @@ -28,6 +28,11 @@ typedef uint32_t FARPTR; FARPTR i386LinearToFp(void *ptr); +__attribute((__no_caller_saved_registers__)) +void kbd_wait(); + +__attribute((__no_caller_saved_registers__)) +uint8_t get_key(); __attribute__ ((interrupt)) void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code); diff --git a/kernel.c b/kernel.c index 079d3db..fa1aea6 100644 --- a/kernel.c +++ b/kernel.c @@ -69,16 +69,14 @@ extern void v86GfxMode(); extern void v86TextMode(); extern void v86DiskRead(); extern char *jmp_usermode_test(); -__attribute((__no_caller_saved_registers__)) -extern void kbd_wait(); extern char _edata, _v86code, _ev86code, _bstart, _bend, _loadusercode, _usercode, _eusercode; void setup_binary() { // Put V86 code in proper place based on linker char *s = &_edata; char *d = &_v86code; - //while (d < &_ev86code) - // *d++ = *s++; + while (d < &_ev86code) + *d++ = *s++; // Put Usermode code in proper place based on linker s = &_loadusercode; @@ -91,6 +89,42 @@ void setup_binary() { *d = 0; } +uint16_t error_screen[80*50]; // 50-line VGA screen of error content + +extern uint16_t *ivt; +uint16_t ivt_bkup[0x200]; +uint8_t bios_bkup[0x40000]; +void backup_ivtbios() { + for (int i = 0; i < 0x200; i++) + ivt_bkup[i] = ivt[i]; + for (int i = 0; i < 0x40000; i++) + bios_bkup[i] = ((uint8_t*)0xC0000)[i]; +} + +// This should only be used during fault handling, as it is expensive +void ensure_v86env() { + for (int i = 0; i < 0x200; i++) + ivt[i] = ivt_bkup[i]; + for (int i = 0; i < 0x40000; i++) + ((uint8_t*)0xC0000)[i] = bios_bkup[i]; + char *s = &_edata; + char *d = &_v86code; + while (d < &_ev86code) + *d++ = *s++; + for (int i = 0; i < 80*50; i++) + if (!error_screen[i]) error_screen[i] = 0x0f00; +} + +void error_environment() { + ensure_v86env(); + FARPTR v86_entry = i386LinearToFp(v86TextMode); + enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry)); + printStr("Oh noes!!! System error! ;c", &error_screen[80]); + uint16_t *vga_text = ((uint16_t*)0xB8000); + for (int i = 0; i < 80*50; i++) + vga_text[i] = error_screen[i]; +} + /* Real Mode Accessible (First MB) 00000 - 00400 IVT (1kB) @@ -260,14 +294,30 @@ void start() { //print_cr4(); vga_text += printStr("V86 Test... ", vga_text); + //asm ("xchgw %bx, %bx"); TestV86(); // has int 3 wait in v86 vga_text = (word *)0xb8000 + (80*3); - printStr("Done. Press any key for next test.", vga_text); + backup_ivtbios(); + vga_text += printStr("Done. Press 'N' for next test.", vga_text); + uint8_t key; + while ((key = get_key()) != 'N') { + *vga_text = (*vga_text & 0xFF00) | key; + vga_text++; + } TestGfx(); kbd_wait(); TestDiskRead(); kbd_wait(); TestFAT(); kbd_wait(); + + vga_text = &((uint16_t*)0xB8000)[80*16]; + vga_text += printStr("Press ` for a flagrant system error... ", vga_text); + while ((key = get_key()) != '`') { + *vga_text = (*vga_text & 0xFF00) | key; + vga_text++; + } + // flagrant system error + *((uint8_t*)0x1000000) = 0; } diff --git a/link.ld b/link.ld index cb9c64b..480846f 100644 --- a/link.ld +++ b/link.ld @@ -15,7 +15,7 @@ SECTIONS { _edata = .; } - .realmode (0x8000 + ADDR(.data) + SIZEOF(.data) - 0x100000) : + .realmode 0x8000 : AT ( ADDR(.data) + SIZEOF(.data) ) { _v86code = .; *(.v86); _ev86code = .; } diff --git a/usermode.nasm b/usermode.nasm index 45229e4..2ad8cfa 100644 --- a/usermode.nasm +++ b/usermode.nasm @@ -16,5 +16,7 @@ cmp eax, 200 jl .loop mov eax, 0xA0000 int 0x30 ; Exit +mov edx, 0x105000 ; somewhere in kernel mem +mov edx, [edx] ; should page fault xor ebx, ebx div bl ; Unhandled DIV0 exception