diff --git a/.gitignore b/.gitignore index f8536d7..fac9f9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o *.bin *.lock +*.com bx_enh_dbg.ini diff --git a/fault.nasm b/fault.nasm index 5ab49e3..5821935 100644 --- a/fault.nasm +++ b/fault.nasm @@ -57,6 +57,7 @@ jmp _fault_coda _gpf_old_ds: dw 0 extern get_key +extern get_scancode extern task_ptr extern _enter_v86_internal_no_task extern return_prev_task @@ -76,7 +77,11 @@ cmp al, 0x00 ; get key jne .s1 call get_key jmp .return_to_offender -.s1: cmp al, 0x86 ; v86 interrupt call +.s1: cmp al, 0x01 ; get scancode +jne .s86 +call get_scancode +jmp .return_to_offender +.s86: cmp al, 0x86 ; v86 interrupt call jne .return_to_offender add esp, 4 add dword [esp+0], 2 diff --git a/kernel.c b/kernel.c index a4ca0a3..7621f1b 100644 --- a/kernel.c +++ b/kernel.c @@ -219,7 +219,7 @@ void FileSelect() { int32_t fileHovered = 0, lastFileHovered = 0; for (char reload = 1;;) { // Info line (4) - printStr("T to run tests - X to view in hex - V to view as text", &vga_text[80*4+2]); + printStr("T to run tests - X to view in hex - V to view as text - P to load as program", &vga_text[80*4+2]); VOLINFO vi; DIRINFO di; if (reload) { OpenVol(&vi); @@ -250,6 +250,14 @@ void FileSelect() { DrawScreen(); reload = 1; break; + case KEY_P: + File83ToPath((char*)entries[fileHovered].name, (char*)path); + create_child(0x380000, (uintptr_t)ProgramLoadTest, 2, path, &vi); + SetVideo25Lines(); + SetCursorDisabled(); + DrawScreen(); + reload = 1; + break; case KEY_X: File83ToPath((char*)entries[fileHovered].name, (char*)path); //HexViewTest(path, &vi); diff --git a/progs.c b/progs.c index 9b4a89a..1d0ba85 100644 --- a/progs.c +++ b/progs.c @@ -1,4 +1,6 @@ #include "progs.h" +#include "helper.h" +#include "kbd.h" void HexViewTest(uint8_t *path, VOLINFO *vi) { uint32_t err; @@ -309,3 +311,62 @@ void TextViewTest(uint8_t *path, VOLINFO *vi) { } } } +// 400000 - 700000 Usermode Code (3mB) +// 700000 - 800000 Usermode Stack (1mB) +extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); +void ProgramLoadTest(uint8_t *path, VOLINFO *vi) { + uint16_t *vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < 80*25; i++) + vga_text[i] = 0x0f00; + uint32_t successcount; + uint8_t *diskReadBuf = (uint8_t *)0x400000; + { + uint32_t err; + uint8_t *scratch = (uint8_t *)0x20000; + FILEINFO fi; + err = DFS_OpenFile(vi, path, DFS_READ, scratch, &fi); + if (err) { + vga_text += printStr("Open Error: ", vga_text); + printDword(err, vga_text); + return; + } + if (fi.filelen > 0x300000) { + vga_text += printStr("File too large.", vga_text); + kbd_wait(); + return; + } + DFS_Seek(&fi, 0, scratch); + if (fi.pointer != 0) { + vga_text += printStr("Seek Error", vga_text); + return; + } + err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, fi.filelen); + if (err && err != DFS_EOF) { + vga_text += printStr("Read Error: ", vga_text); + printDword(err, vga_text); + return; + } + if (successcount < fi.filelen) { + vga_text += printStr("Could not read all file bytes.", vga_text); + return; + } + } + vga_text += printStr("Successfully loaded program \"", vga_text); + vga_text += printStr((char*)path, vga_text); + vga_text += printStr("\", ", vga_text); + vga_text += printDec(successcount, vga_text); + vga_text += printStr(" Bytes.", vga_text); + vga_text = nextLine(vga_text); + vga_text += printStr("Press any key to run.", vga_text); + kbd_wait(); + uint32_t res = create_user_child(0x800000, 0x400000, 0); + vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < 80*25; i++) + vga_text[i] = 0x0f00; + vga_text += printStr("Program returned code: ", vga_text); + vga_text += printDec(res, vga_text); + vga_text += printStr(" (0x", vga_text); + vga_text += printDword(res, vga_text); + vga_text += printStr("). Press any key to exit.", vga_text); + kbd_wait(); +} diff --git a/progs.h b/progs.h index 5569035..604f28d 100644 --- a/progs.h +++ b/progs.h @@ -9,3 +9,4 @@ void HexViewTest(uint8_t *path, VOLINFO *vi); void TextViewTest(uint8_t *path, VOLINFO *vi); +void ProgramLoadTest(uint8_t *path, VOLINFO *vi); diff --git a/task.nasm b/task.nasm index 3e256da..f4f2711 100644 --- a/task.nasm +++ b/task.nasm @@ -11,7 +11,6 @@ task_ptr: equ (0x310000-4) ; extern void create_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); global create_child create_child: -xchg bx,bx mov eax, [esp] ; return address lea ecx, [esp+4] ; return stack, minus address call save_current_task @@ -30,6 +29,37 @@ push return_prev_task ; if child returns, return to prev task push eax ret +; extern void create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); +global create_user_child +create_user_child: +mov eax, [esp] ; return address +lea ecx, [esp+4] ; return stack, minus address +call save_current_task +mov eax, [esp+8] ; new eip +mov ecx, [esp+12] ; argc +mov esi, esp ; old esp +mov esp, [esp+4] ; new esp +lea esi, [esi+16] ; args +mov edx, ecx +neg edx +lea esp, [esp+edx*4] ; adjust for args +mov edi, esp +; copy varargs to new stack +rep movsd +push 0x00000000 ; if child returns, return to null, crashing +mov ecx, 0x20 | 3 +mov ds, cx +mov es, cx +mov fs, cx +mov gs, cx +mov ecx, esp +push 0x20 | 3 +push ecx +pushfd +push 0x18 | 3 +push eax +iret + ; return address in EAX ; return stack in ECX ; we can modify EAX, ECX, EDX @@ -145,22 +175,22 @@ iret ; return address in eax, return stack in ebp ;extern save_current_task -extern user_test -global jmp_usermode_test -jmp_usermode_test: -pop eax ; return address -mov ecx, esp ; return stack -call save_current_task -mov esp, 0x800000 ; usermode stack -mov eax, 0x20 | 3 -mov ds, ax -mov es, ax -mov fs, ax -mov gs, ax -mov eax, esp -push 0x20 | 3 -push eax -pushfd -push 0x18 | 3 -push user_test -iret +;extern user_test +;global jmp_usermode_test +;jmp_usermode_test: +;pop eax ; return address +;mov ecx, esp ; return stack +;call save_current_task +;mov esp, 0x800000 ; usermode stack +;mov eax, 0x20 | 3 +;mov ds, ax +;mov es, ax +;mov fs, ax +;mov gs, ax +;mov eax, esp +;push 0x20 | 3 +;push eax +;pushfd +;push 0x18 | 3 +;push user_test +;iret diff --git a/testpgrm.nasm b/testpgrm.nasm new file mode 100644 index 0000000..47e21df --- /dev/null +++ b/testpgrm.nasm @@ -0,0 +1,36 @@ +[BITS 32] +[ORG 0x400000] +xchg bx,bx +mov edi, 0xB8000 +mov ecx, 80*25 +mov eax, 0x2f00 +rep stosw +mov edi, 0xB8000 +mov esi, str0 +mov ecx, str0_end - str0 +mov eax, 0x2f00 +.loop: +lodsb +stosw +loop .loop +mov edi, 0xB8000 + 160 - 2 +.key_loop: +mov eax, 1 ; command = 01h, get scancode +int 0x21 ; OS call +cmp al, 0x3B ; F1 +je .exit +cmp al, 0x3C ; F2 +je .crash +cmp ah, 0x00 +je .key_loop +mov byte [edi], ah ; ASCII value +add edi, 2 +jmp .key_loop +.exit: +mov eax, 0x1337 ; Exit code/Return value +int 0x30 ; Exit +.crash: +jmp 0x00000000 + +str0: db "Running usermode program from disk! Press F1 to exit. Press F2 to crash." +str0_end: diff --git a/tests.c b/tests.c index 79e2247..e6f9255 100644 --- a/tests.c +++ b/tests.c @@ -1,6 +1,7 @@ #include "tests.h" -extern char *jmp_usermode_test(); +extern char *user_test(); +extern uint32_t create_user_child(uint32_t esp, uint32_t eip, uint32_t argc, ...); void TestV86() { union V86Regs_t regs; @@ -21,12 +22,16 @@ void ReloadUser() { while (d < &_eusercode) *d++ = *s++; } -void TestUser() { +char TestUser() { ReloadUser(); - char *vga = jmp_usermode_test(); + char *vga = (char *)(uintptr_t)create_user_child(0x800000, (uintptr_t)user_test, 0); + if ((uintptr_t)vga != 0xA0000) { + return 1; + } for (int i = 0; i < 320; i++) { vga[i] = i; } + return 0; } void TestDiskRead() { union V86Regs_t regs; @@ -119,17 +124,25 @@ void TestFAT() { void RunTests() { uint16_t *vga_text = (uint16_t*)0xb8000; + for (int i = 0; i < 80*25; i++) + vga_text[i] = 0x1f00; uint8_t key; vga_text += printStr("V86 Test... ", vga_text); //asm ("xchgw %bx, %bx"); TestV86(); // has int 3 wait in v86 vga_text = (uint16_t *)0xb8000 + (80*3); vga_text += printStr("Done. Press 'N' for next test.", vga_text); - while ((key = get_key()) != 'N') { + for(;;) { + key = get_key(); + if (key == 'N' || key == 'n') break; *vga_text = (*vga_text & 0xFF00) | key; vga_text++; } - TestUser(); + if (TestUser()) { + // Usermode returned wrong value + vga_text = nextLine(vga_text); + vga_text += printStr("Usermode test failed! Press any key to continue.", vga_text); + } kbd_wait(); TestDiskRead(); kbd_wait(); diff --git a/tests.h b/tests.h index 1d7b5ee..737f749 100644 --- a/tests.h +++ b/tests.h @@ -4,5 +4,6 @@ #include "interrupt.h" #include "v86defs.h" #include "kbd.h" +#include "helper.h" void RunTests(); diff --git a/usermode.nasm b/usermode.nasm index d149ec9..6cc1a0b 100644 --- a/usermode.nasm +++ b/usermode.nasm @@ -6,8 +6,24 @@ mov dword [0xb8004], 0x0f000f00 | 'e' | 'r' << 16 mov dword [0xb8008], 0x0f000f00 | 'm' | 'o' << 16 mov dword [0xb800C], 0x0f000f00 | 'd' | 'e' << 16 mov word [0xb8010], 0x0f00 | '!' +mov dword [0xb8000+160], 0x0f000f00 | 'F' | 'a' << 16 +mov dword [0xb8004+160], 0x0f000f00 | 'u' | 'l' << 16 +mov dword [0xb8008+160], 0x0f000f00 | 't' | 's' << 16 +mov dword [0xb800C+160], 0x0f000f00 | ':' | ' ' << 16 +mov dword [0xb8000+320], 0x0f000f00 | 'd' | ':' << 16 +mov dword [0xb8004+320], 0x0f000f00 | ' ' | '#' << 16 +mov dword [0xb8008+320], 0x0f000f00 | 'D' | 'I' << 16 +mov dword [0xb800C+320], 0x0f000f00 | 'V' | ' ' << 16 +mov dword [0xb8000+480], 0x0f000f00 | 'p' | ':' << 16 +mov dword [0xb8004+480], 0x0f000f00 | ' ' | 'P' << 16 +mov dword [0xb8008+480], 0x0f000f00 | 'G' | 'F' << 16 +mov dword [0xb800C+480], 0x0f000f00 | 'L' | 'T' << 16 mov eax, 0 ; command = 00h, get key int 0x21 ; OS call +cmp al, 'd' +je .div_err +cmp al, 'p' +je .page_err push 0x00000013 ; eax AH=0,AL=3 set video mode 3 push 0x00000000 ; ecx push 0x00000000 ; edx @@ -31,7 +47,9 @@ mov eax, 0xA0000 ;.dbg: ;loop .dbg int 0x30 ; Exit +.page_err: mov edx, 0x105000 ; somewhere in kernel mem mov edx, [edx] ; should page fault +.div_err: xor ebx, ebx div bl ; Unhandled DIV0 exception