diff --git a/Makefile b/Makefile index dc1017e..992e913 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 fault.o tests.o kbd.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 tests.o kbd.o helper.o progs.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/dosfs/dosfs.c b/dosfs/dosfs.c index 645290c..74d15ed 100755 --- a/dosfs/dosfs.c +++ b/dosfs/dosfs.c @@ -10,7 +10,6 @@ #include "dosfs.h" #include "tmpstring.c" -#include "../interrupt.h" #include "../v86defs.h" uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) { diff --git a/fault.nasm b/fault.nasm index b729d83..5ab49e3 100644 --- a/fault.nasm +++ b/fault.nasm @@ -60,7 +60,7 @@ extern get_key extern task_ptr extern _enter_v86_internal_no_task extern return_prev_task -extern v86VideoInt +extern v86Interrupt gpf_handler_32: push eax mov eax, dword [esp+8] ; EIP @@ -76,21 +76,27 @@ cmp al, 0x00 ; get key jne .s1 call get_key jmp .return_to_offender -.s1: cmp al, 0x10 ; video interrupt +.s1: cmp al, 0x86 ; v86 interrupt call jne .return_to_offender add esp, 4 add dword [esp+0], 2 ; add a new task call _gpf_create_return_task ; now enter v86 mode -; get regs from return stack +; get int & regs from return stack mov eax, [esp+12] ; return esp -mov eax, [eax] ; regs +mov eax, [eax] ; interrupt +and eax, 0xff ; ensure 1 byte +shl eax, 8 +or eax, 0x30CD00CD ; command +mov dword [v86Interrupt], eax +mov eax, [esp+12] ; return esp +mov eax, [eax+4] ; regs push eax ; regs -mov eax, v86VideoInt +mov eax, v86Interrupt and eax, 0xffff push eax ; ip -mov eax, v86VideoInt +mov eax, v86Interrupt shr eax, 4 and eax, 0xf000 push eax ; cs diff --git a/helper.c b/helper.c new file mode 100644 index 0000000..6d6d0fc --- /dev/null +++ b/helper.c @@ -0,0 +1,77 @@ +#include "helper.h" + +uint16_t *nextLine(uint16_t *p) { + uintptr_t v = (uintptr_t)p; + return (uint16_t *)(v + (160 - ((v - 0xb8000) % 160))); +} + +void V8086Int(uint8_t interrupt, union V86Regs_t *regs) { + // Edit the v8086 code with the interrupt + // Writing 4 bytes to ensure proper code + *(uint32_t*)v86Interrupt = 0x30CD00CD | (interrupt << 8); + FARPTR v86_entry = i386LinearToFp(v86Interrupt); + enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), regs); +} + +void SetVideo25Lines() { + union V86Regs_t regs; + regs.w.ax = 0x1114; // 80x25 mode + regs.w.bx = 0x0000; + V8086Int(0x10, ®s); +} +void SetVideo50Lines() { + union V86Regs_t regs; + regs.w.ax = 0x1112; // 80x50 mode + regs.w.bx = 0x0000; + V8086Int(0x10, ®s); +} +void SetCursorDisabled() { + union V86Regs_t regs; + regs.w.ax = 0x0100; // set cursor + regs.w.cx = 0x3F00; // disabled + V8086Int(0x10, ®s); +} + +uint32_t OpenVol(VOLINFO *vi) { + uint8_t *diskReadBuf = (uint8_t *)0x20000; + uint8_t pactive, ptype; + uint32_t pstart, psize; + pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize); + return DFS_GetVolInfo(0, diskReadBuf, pstart, vi); +} +uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di) { + uint8_t *diskReadBuf = (uint8_t *)0x20000; + di->scratch = diskReadBuf; + return DFS_OpenDir(vi, path, di); +} + +void File83ToPath(char *src, char *path) { + uint8_t tmp, trailingSpace; + for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) { + path[tmp] = src[tmp]; + if (src[tmp] == ' ') trailingSpace++; + else trailingSpace = 0; + } + tmp -= trailingSpace; + path[tmp++] = '.'; + for (int i = 8; i < 11 && src[i]; i++, tmp++) { + path[tmp] = src[i]; + } + path[tmp] = 0; +} + +void GetFileList(DIRENT *entries, int32_t *entCount, VOLINFO *vi, DIRINFO *di) { + uint8_t *diskReadBuf = (uint8_t *)0x20000; + DIRENT de; + int32_t fileCount = 0; + while (!DFS_GetNext(vi, di, &de)) { + if (de.name[0]) { + uint8_t *d = (uint8_t*)&entries[fileCount]; + uint8_t *s = (uint8_t*)&de; + for (int i = 0; i < sizeof(DIRENT); i++) + d[i] = s[i]; + fileCount++; + } + } + *entCount = fileCount; +} diff --git a/helper.h b/helper.h new file mode 100644 index 0000000..6d37664 --- /dev/null +++ b/helper.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#include "interrupt.h" +#include "v86defs.h" +#include "dosfs/dosfs.h" + +void V8086Int(uint8_t interrupt, union V86Regs_t *regs); + +void SetVideo25Lines(); +void SetVideo50Lines(); +void SetCursorDisabled(); + +uint16_t *nextLine(uint16_t *p); + +uint32_t OpenVol(VOLINFO *vi); +uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di); +void File83ToPath(char *src, char *path); +void GetFileList(DIRENT *entries, int32_t *entCount, VOLINFO *vi, DIRINFO *di); diff --git a/interrupt.c b/interrupt.c index 54e2fc8..9d17933 100644 --- a/interrupt.c +++ b/interrupt.c @@ -3,6 +3,7 @@ #include "interrupt.h" #include "kbd.h" +#include "v86defs.h" char int_nibbleToHex(uint8_t n) { return n > 9 ? (n - 10) + 'A' : n + '0'; diff --git a/interrupt.h b/interrupt.h index cfdb107..3ee0ba0 100644 --- a/interrupt.h +++ b/interrupt.h @@ -7,28 +7,6 @@ struct interrupt_frame { uint32_t esp, ss; uint32_t es, ds, fs, gs; }; - -/* Real Mode helper macros */ -/* segment:offset pair */ -typedef uint32_t FARPTR; - -/* Make a FARPTR from a segment and an offset */ -#define MK_FP(seg, off) ((FARPTR) (((uint32_t) (seg) << 16) | (uint16_t) (off))) - -/* Extract the segment part of a FARPTR */ -#define FP_SEG(fp) (((FARPTR) fp) >> 16) - -/* Extract the offset part of a FARPTR */ -#define FP_OFF(fp) (((FARPTR) fp) & 0xffff) - -/* Convert a segment:offset pair to a linear address */ -#define FP_TO_LINEAR(seg, off) ((void*)(uintptr_t)((((uint32_t)seg) << 4) + ((uint32_t)off))) - -#define EFLAG_IF ((uint32_t)1 << 9) -#define EFLAG_VM ((uint32_t)1 << 17) - -FARPTR i386LinearToFp(void *ptr); - __attribute__ ((interrupt)) void gpf_handler_v86(struct interrupt_frame *frame, unsigned long error_code); diff --git a/kernel.c b/kernel.c index 4d79d5c..47eb95a 100644 --- a/kernel.c +++ b/kernel.c @@ -8,6 +8,8 @@ #include "paging.h" #include "v86defs.h" #include "tests.h" +#include "progs.h" +#include "helper.h" typedef unsigned short word; @@ -146,29 +148,6 @@ Protected Only (1MB+) 400000 - 700000 Usermode Code (3mB) 700000 - 800000 Usermode Stack (1mB) */ - -void SetVideo25Lines() { - union V86Regs_t regs; - regs.w.ax = 0x1114; // 80x25 mode - regs.w.bx = 0x0000; - FARPTR v86_entry = i386LinearToFp(v86VideoInt); - enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); -} -void SetVideo50Lines() { - union V86Regs_t regs; - regs.w.ax = 0x1112; // 80x50 mode - regs.w.bx = 0x0000; - FARPTR v86_entry = i386LinearToFp(v86VideoInt); - enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); -} -void SetCursorDisabled() { - union V86Regs_t regs; - regs.w.ax = 0x0100; // set cursor - regs.w.cx = 0x3F00; // disabled - FARPTR v86_entry = i386LinearToFp(v86VideoInt); - enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); -} - void DrawScreen() { uint16_t *vga_text = (uint16_t *)0xB8000; // clear screen @@ -204,38 +183,8 @@ void DrawScreen() { vga_text[80+44] = 0x1f00 | '-'; } -uint32_t OpenVol(VOLINFO *vi) { - uint8_t *diskReadBuf = (uint8_t *)0x20000; - uint8_t pactive, ptype; - uint32_t pstart, psize; - pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize); - return DFS_GetVolInfo(0, diskReadBuf, pstart, vi); -} -uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di) { - uint8_t *diskReadBuf = (uint8_t *)0x20000; - di->scratch = diskReadBuf; - return DFS_OpenDir(vi, path, di); -} int32_t fileCount; DIRENT *entries = (DIRENT*)0x400000; -void GetFileList(VOLINFO *vi, DIRINFO *di) { - uint8_t *diskReadBuf = (uint8_t *)0x20000; - DIRENT de; - fileCount = 0; - while (!DFS_GetNext(vi, di, &de)) { - if (de.name[0]) { - uint8_t *d = (uint8_t*)&entries[fileCount]; - uint8_t *s = (uint8_t*)&de; - for (int i = 0; i < sizeof(DIRENT); i++) - d[i] = s[i]; - fileCount++; - } - } -} -uint16_t *nextLine(uint16_t *p) { - uintptr_t v = (uintptr_t)p; - return (uint16_t *)(v + (160 - ((v - 0xb8000) % 160))); -} void PrintFileList() { uint16_t *vga_text = &((uint16_t *)0xb8000)[80*6+3]; for (int i = 0; i < fileCount; i++) { @@ -254,329 +203,6 @@ void PrintFileList() { vga_text = nextLine(vga_text) + 3; } } -void HexViewTest(uint8_t *path, VOLINFO *vi) { - uint32_t err; - uint16_t *vga_text = (uint16_t *)0xb8000; - 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; - } - uint32_t successcount; - uint32_t readOffset = 0, lastReadOffset = -1; - char cont = 1; - uint32_t byteCount = 16*24, lastByteCount; - uint32_t screenSize = 80*25; - char reread; - for (;cont;) { - uint8_t diskReadBuf[byteCount]; - if (readOffset != lastReadOffset) { - lastReadOffset = readOffset; - reread = 1; - } - if (byteCount != lastByteCount) { - lastByteCount = byteCount; - reread = 1; - } - if (reread) { - vga_text = (uint16_t *)0xb8000; - for (int i = 0; i < screenSize; i++) - vga_text[i] = 0x0f00; - vga_text += printStr((char*)path, vga_text); - { - const char prnt[] = "Scroll: Up/Down PgUp/PgDown Home/End Exit: E "; - vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)]; - vga_text += printStr((char*)prnt, vga_text); - } - vga_text = &((uint16_t*)0xb8000)[80]; - DFS_Seek(&fi, readOffset, scratch); - if (fi.pointer != readOffset) { - vga_text += printStr("Seek Error", vga_text); - return; - } - err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, byteCount); - if (err && err != DFS_EOF) { - vga_text += printStr("Read Error: ", vga_text); - printDword(err, vga_text); - return; - } - for (uint32_t i = 0; i < successcount && i < byteCount; i += 16) { - vga_text += printDword(i + readOffset, vga_text); - vga_text += printChar(' ', vga_text); - vga_text += printChar(' ', vga_text); - for (uint32_t j = 0; j < 16; j++) { - if (i + j < successcount) - vga_text += printByte(diskReadBuf[i + j], vga_text); - else { - vga_text += printChar(' ', vga_text); - vga_text += printChar(' ', vga_text); - } - vga_text += printChar(' ', vga_text); - if (j == 7) - vga_text += printChar(' ', vga_text); - } - vga_text += printChar(' ', vga_text); - vga_text += printChar('|', vga_text); - for (uint32_t j = 0; j < 16; j++) { - if (i + j < successcount) - vga_text += printChar(diskReadBuf[i + j], vga_text); - else vga_text += printChar(' ', vga_text); - } - vga_text += printChar('|', vga_text); - vga_text = nextLine(vga_text); - } - reread = 0; - } - uint16_t key = get_scancode(); - union V86Regs_t regs; - FARPTR v86_entry; - switch (key & 0xff) { - case KEY_DOWN: // down - if ((readOffset + byteCount) < fi.filelen) - readOffset += byteCount; - else goto end; - break; - case KEY_UP: // up - if ((readOffset - byteCount) < fi.filelen) - readOffset -= byteCount; - else goto home; - break; - case KEY_PGDOWN: - if ((readOffset + (byteCount*4)) < fi.filelen) - readOffset += (byteCount*4); - else goto end; - break; - case KEY_PGUP: - if ((readOffset - (byteCount*4)) < fi.filelen) - readOffset -= (byteCount*4); - else goto home; - break; - case KEY_HOME: home: - readOffset = 0; - break; - case KEY_END: end: - if ((fi.filelen / byteCount) * byteCount > readOffset) - readOffset = (fi.filelen / byteCount) * byteCount; - break; - case KEY_E: // e - cont = 0; - break; - case KEY_F2: - if (byteCount != 16*24) { - SetVideo25Lines(); - SetCursorDisabled(); - screenSize = 80*25; - byteCount = 16*24; - } - break; - case KEY_F5: - if (byteCount != 16*49) { - SetVideo50Lines(); - SetCursorDisabled(); - screenSize = 80*50; - byteCount = 16*49; - } - break; - default: - break; - } - } -} -void TextViewTest(uint8_t *path, VOLINFO *vi) { - uint16_t *vga_text = (uint16_t *)0xb8000; - uint32_t fileLen; - uint8_t *diskReadBuf = (uint8_t *)0x500000; - { - 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; - } - // file too large - 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, &fileLen, fi.filelen); - if (err && err != DFS_EOF) { - vga_text += printStr("Read Error: ", vga_text); - printDword(err, vga_text); - return; - } - } - uint32_t *lineOffsets = (uint32_t *)0x400000; - uint32_t lastLine; - { - char nl; - uint8_t c = 0x0A; // start with a pretend newline - uint32_t line = -1; // start a pretend line behind - for (int32_t o = -1; o < (int32_t)fileLen; c = diskReadBuf[++o]) { - // newline - if (c == 0x0A) { - lineOffsets[++line] = o; - } - // file too large - if ((uintptr_t)&lineOffsets[line] >= 0x4FFFFC) { - vga_text += printStr("File too large.", vga_text); - kbd_wait(); - return; - } - } - lastLine = line; - } - uint32_t currLine = 0; - char cont = 1; - uint32_t screenSize = 80*25; - char redraw = 1; - uint32_t linesOnScreen = 0; - for (;cont;) { - if (redraw) { - vga_text = (uint16_t *)0xb8000; - for (int i = 0; i < screenSize; i++) - vga_text[i] = 0x0f00; - vga_text += printStr((char*)path, vga_text); - vga_text += 2; - vga_text += printStr("Line: ", vga_text); - vga_text += printDec(currLine, vga_text); - vga_text += printChar('/', vga_text); - vga_text += printDec(lastLine, vga_text); - vga_text += printStr(" Scroll: Up/Down PgUp/PgDown Home/End", vga_text); - { - const char prnt[] = "Exit: E "; - vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)]; - vga_text += printStr((char*)prnt, vga_text); - } - for (vga_text = &((uint16_t*)0xb8000)[84]; vga_text < &((uint16_t*)0xb8000)[screenSize]; vga_text += 80) - *(uint8_t*)vga_text = '|'; - vga_text = &((uint16_t*)0xb8000)[0]; - uint32_t lineOff = 6; - uint8_t c = 0x0A; // start with a pretend newline - uint32_t line = currLine - 1; // start a pretend line behind - int32_t o = lineOffsets[currLine]; // the real or fake newline on previous line - linesOnScreen = screenSize/80; - for (; o < (int32_t)fileLen && vga_text < &((uint16_t*)0xb8000)[screenSize]; c = diskReadBuf[++o]) { - // newline - if (c == 0x0A) { - vga_text = nextLine(vga_text); - line++; - { - uint16_t *vga_tmp = vga_text; - uint16_t decTmp[11]; - char cnt = printDec(line, decTmp); - char off = cnt <= 4 ? 0 : cnt - 4; - vga_tmp += 4 - (cnt - off); - for (int i = off; i < cnt; i++, vga_tmp++) - *(uint8_t*)vga_tmp = (uint8_t)decTmp[i]; - } - vga_text += 6; - lineOff = 6; - continue; - } - *(uint8_t*)vga_text = c; - vga_text++; - lineOff++; - if (lineOff == 80) { // last char - vga_text += 6; - lineOff = 6; - linesOnScreen--; - } - } - redraw = 0; - } - uint16_t key = get_scancode(); - union V86Regs_t regs; - FARPTR v86_entry; - switch (key & 0xff) { - case KEY_DOWN: // down - if (currLine < lastLine && lineOffsets[currLine+1] < fileLen) { - currLine++; - redraw = 1; - } - break; - case KEY_UP: // up - if ((currLine > 0 && lineOffsets[currLine-1] < fileLen) || currLine == 1) { - currLine--; - redraw = 1; - } - break; - case KEY_PGDOWN: - if (currLine+(linesOnScreen/2) <= lastLine && lineOffsets[currLine+(linesOnScreen/2)] < fileLen) { - currLine += (linesOnScreen/2); - redraw = 1; - } else goto end; - break; - case KEY_PGUP: - if (currLine > (linesOnScreen/2) && lineOffsets[currLine-(linesOnScreen/2)] < fileLen) { - currLine -= (linesOnScreen/2); - redraw = 1; - } else if (currLine <= (linesOnScreen/2)) { - currLine = 0; - redraw = 1; - } - break; - case KEY_HOME: home: - if (currLine != 0) { - currLine = 0; - redraw = 1; - } - break; - case KEY_END: end: - if (currLine != lastLine) { - currLine = lastLine; - redraw = 1; - } - break; - case KEY_E: // e - cont = 0; - break; - case KEY_F2: - if (screenSize != 80*25) { - SetVideo25Lines(); - SetCursorDisabled(); - screenSize = 80*25; - redraw = 1; - } - break; - case KEY_F5: - if (screenSize != 80*50) { - SetVideo50Lines(); - SetCursorDisabled(); - screenSize = 80*50; - redraw = 1; - } - break; - default: - break; - } - } -} -void File83ToPath(char *src, char *path) { - uint8_t tmp, trailingSpace; - for (trailingSpace=0, tmp = 0; tmp < 8 && src[tmp]; tmp++) { - path[tmp] = src[tmp]; - if (src[tmp] == ' ') trailingSpace++; - else trailingSpace = 0; - } - tmp -= trailingSpace; - path[tmp++] = '.'; - for (int i = 8; i < 11 && src[i]; i++, tmp++) { - path[tmp] = src[i]; - } - path[tmp] = 0; -} void FileSelect() { fileCount = 5; uint16_t *vga_text = (uint16_t *)0xb8000; @@ -588,7 +214,7 @@ void FileSelect() { if (reload) { OpenVol(&vi); OpenDir((uint8_t*)"", &vi, &di); - GetFileList(&vi, &di); + GetFileList(entries, &fileCount, &vi, &di); reload = 0; } PrintFileList(); @@ -610,6 +236,7 @@ void FileSelect() { break; case 0x14: // t RunTests(vga_text); + SetCursorDisabled(); DrawScreen(); reload = 1; break; diff --git a/progs.c b/progs.c new file mode 100644 index 0000000..9b4a89a --- /dev/null +++ b/progs.c @@ -0,0 +1,311 @@ +#include "progs.h" + +void HexViewTest(uint8_t *path, VOLINFO *vi) { + uint32_t err; + uint16_t *vga_text = (uint16_t *)0xb8000; + 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; + } + uint32_t successcount; + uint32_t readOffset = 0, lastReadOffset = -1; + char cont = 1; + uint32_t byteCount = 16*24, lastByteCount; + uint32_t screenSize = 80*25; + char reread; + for (;cont;) { + uint8_t diskReadBuf[byteCount]; + if (readOffset != lastReadOffset) { + lastReadOffset = readOffset; + reread = 1; + } + if (byteCount != lastByteCount) { + lastByteCount = byteCount; + reread = 1; + } + if (reread) { + vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < screenSize; i++) + vga_text[i] = 0x0f00; + vga_text += printStr((char*)path, vga_text); + { + const char prnt[] = "Scroll: Up/Down PgUp/PgDown Home/End Exit: E "; + vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)]; + vga_text += printStr((char*)prnt, vga_text); + } + vga_text = &((uint16_t*)0xb8000)[80]; + DFS_Seek(&fi, readOffset, scratch); + if (fi.pointer != readOffset) { + vga_text += printStr("Seek Error", vga_text); + return; + } + err = DFS_ReadFile(&fi, scratch, diskReadBuf, &successcount, byteCount); + if (err && err != DFS_EOF) { + vga_text += printStr("Read Error: ", vga_text); + printDword(err, vga_text); + return; + } + for (uint32_t i = 0; i < successcount && i < byteCount; i += 16) { + vga_text += printDword(i + readOffset, vga_text); + vga_text += printChar(' ', vga_text); + vga_text += printChar(' ', vga_text); + for (uint32_t j = 0; j < 16; j++) { + if (i + j < successcount) + vga_text += printByte(diskReadBuf[i + j], vga_text); + else { + vga_text += printChar(' ', vga_text); + vga_text += printChar(' ', vga_text); + } + vga_text += printChar(' ', vga_text); + if (j == 7) + vga_text += printChar(' ', vga_text); + } + vga_text += printChar(' ', vga_text); + vga_text += printChar('|', vga_text); + for (uint32_t j = 0; j < 16; j++) { + if (i + j < successcount) + vga_text += printChar(diskReadBuf[i + j], vga_text); + else vga_text += printChar(' ', vga_text); + } + vga_text += printChar('|', vga_text); + vga_text = nextLine(vga_text); + } + reread = 0; + } + uint16_t key = get_scancode(); + union V86Regs_t regs; + FARPTR v86_entry; + switch (key & 0xff) { + case KEY_DOWN: // down + if ((readOffset + byteCount) < fi.filelen) + readOffset += byteCount; + else goto end; + break; + case KEY_UP: // up + if ((readOffset - byteCount) < fi.filelen) + readOffset -= byteCount; + else goto home; + break; + case KEY_PGDOWN: + if ((readOffset + (byteCount*4)) < fi.filelen) + readOffset += (byteCount*4); + else goto end; + break; + case KEY_PGUP: + if ((readOffset - (byteCount*4)) < fi.filelen) + readOffset -= (byteCount*4); + else goto home; + break; + case KEY_HOME: home: + readOffset = 0; + break; + case KEY_END: end: + if ((fi.filelen / byteCount) * byteCount > readOffset) + readOffset = (fi.filelen / byteCount) * byteCount; + break; + case KEY_E: // e + cont = 0; + break; + case KEY_F2: + if (byteCount != 16*24) { + SetVideo25Lines(); + SetCursorDisabled(); + screenSize = 80*25; + byteCount = 16*24; + } + break; + case KEY_F5: + if (byteCount != 16*49) { + SetVideo50Lines(); + SetCursorDisabled(); + screenSize = 80*50; + byteCount = 16*49; + } + break; + default: + break; + } + } +} +void TextViewTest(uint8_t *path, VOLINFO *vi) { + uint16_t *vga_text = (uint16_t *)0xb8000; + uint32_t fileLen; + uint8_t *diskReadBuf = (uint8_t *)0x500000; + { + 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; + } + // file too large + 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, &fileLen, fi.filelen); + if (err && err != DFS_EOF) { + vga_text += printStr("Read Error: ", vga_text); + printDword(err, vga_text); + return; + } + } + uint32_t *lineOffsets = (uint32_t *)0x400000; + uint32_t lastLine; + { + char nl; + uint8_t c = 0x0A; // start with a pretend newline + uint32_t line = -1; // start a pretend line behind + for (int32_t o = -1; o < (int32_t)fileLen; c = diskReadBuf[++o]) { + // newline + if (c == 0x0A) { + lineOffsets[++line] = o; + } + // file too large + if ((uintptr_t)&lineOffsets[line] >= 0x4FFFFC) { + vga_text += printStr("File too large.", vga_text); + kbd_wait(); + return; + } + } + lastLine = line; + } + uint32_t currLine = 0; + char cont = 1; + uint32_t screenSize = 80*25; + char redraw = 1; + uint32_t linesOnScreen = 0; + for (;cont;) { + if (redraw) { + vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < screenSize; i++) + vga_text[i] = 0x0f00; + vga_text += printStr((char*)path, vga_text); + vga_text += 2; + vga_text += printStr("Line: ", vga_text); + vga_text += printDec(currLine, vga_text); + vga_text += printChar('/', vga_text); + vga_text += printDec(lastLine, vga_text); + vga_text += printStr(" Scroll: Up/Down PgUp/PgDown Home/End", vga_text); + { + const char prnt[] = "Exit: E "; + vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)]; + vga_text += printStr((char*)prnt, vga_text); + } + for (vga_text = &((uint16_t*)0xb8000)[84]; vga_text < &((uint16_t*)0xb8000)[screenSize]; vga_text += 80) + *(uint8_t*)vga_text = '|'; + vga_text = &((uint16_t*)0xb8000)[0]; + uint32_t lineOff = 6; + uint8_t c = 0x0A; // start with a pretend newline + uint32_t line = currLine - 1; // start a pretend line behind + int32_t o = lineOffsets[currLine]; // the real or fake newline on previous line + linesOnScreen = screenSize/80; + for (; o < (int32_t)fileLen && vga_text < &((uint16_t*)0xb8000)[screenSize]; c = diskReadBuf[++o]) { + // newline + if (c == 0x0A) { + vga_text = nextLine(vga_text); + line++; + { + uint16_t *vga_tmp = vga_text; + uint16_t decTmp[11]; + char cnt = printDec(line, decTmp); + char off = cnt <= 4 ? 0 : cnt - 4; + vga_tmp += 4 - (cnt - off); + for (int i = off; i < cnt; i++, vga_tmp++) + *(uint8_t*)vga_tmp = (uint8_t)decTmp[i]; + } + vga_text += 6; + lineOff = 6; + continue; + } + *(uint8_t*)vga_text = c; + vga_text++; + lineOff++; + if (lineOff == 80) { // last char + vga_text += 6; + lineOff = 6; + linesOnScreen--; + } + } + redraw = 0; + } + uint16_t key = get_scancode(); + union V86Regs_t regs; + FARPTR v86_entry; + switch (key & 0xff) { + case KEY_DOWN: // down + if (currLine < lastLine && lineOffsets[currLine+1] < fileLen) { + currLine++; + redraw = 1; + } + break; + case KEY_UP: // up + if ((currLine > 0 && lineOffsets[currLine-1] < fileLen) || currLine == 1) { + currLine--; + redraw = 1; + } + break; + case KEY_PGDOWN: + if (currLine+(linesOnScreen/2) <= lastLine && lineOffsets[currLine+(linesOnScreen/2)] < fileLen) { + currLine += (linesOnScreen/2); + redraw = 1; + } else goto end; + break; + case KEY_PGUP: + if (currLine > (linesOnScreen/2) && lineOffsets[currLine-(linesOnScreen/2)] < fileLen) { + currLine -= (linesOnScreen/2); + redraw = 1; + } else if (currLine <= (linesOnScreen/2)) { + currLine = 0; + redraw = 1; + } + break; + case KEY_HOME: home: + if (currLine != 0) { + currLine = 0; + redraw = 1; + } + break; + case KEY_END: end: + if (currLine != lastLine) { + currLine = lastLine; + redraw = 1; + } + break; + case KEY_E: // e + cont = 0; + break; + case KEY_F2: + if (screenSize != 80*25) { + SetVideo25Lines(); + SetCursorDisabled(); + screenSize = 80*25; + redraw = 1; + } + break; + case KEY_F5: + if (screenSize != 80*50) { + SetVideo50Lines(); + SetCursorDisabled(); + screenSize = 80*50; + redraw = 1; + } + break; + default: + break; + } + } +} diff --git a/progs.h b/progs.h new file mode 100644 index 0000000..5569035 --- /dev/null +++ b/progs.h @@ -0,0 +1,11 @@ +#pragma once +#include + +#include "dosfs/dosfs.h" +#include "print.h" +#include "kbd.h" +#include "v86defs.h" +#include "helper.h" + +void HexViewTest(uint8_t *path, VOLINFO *vi); +void TextViewTest(uint8_t *path, VOLINFO *vi); diff --git a/tests.c b/tests.c index 031ea08..71fa2f4 100644 --- a/tests.c +++ b/tests.c @@ -1,5 +1,4 @@ #include "tests.h" -#include "v86defs.h" extern char *jmp_usermode_test(); @@ -34,14 +33,13 @@ void TestDiskRead() { uint16_t *vga_text = (uint16_t *)0xb8000 + (80*5); vga_text += printStr("Setting Text Mode... ", vga_text); regs.w.ax = 3; // text mode - FARPTR v86_entry = i386LinearToFp(v86VideoInt); - enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + V8086Int(0x10, ®s); vga_text += printStr("Done. Starting Disk Read... ", vga_text); char *diskReadBuf = (char *)0x23000; v86disk_addr_packet.transfer_buffer = (uintptr_t)diskReadBuf & 0x000F | (((uintptr_t)diskReadBuf & 0xFFFF0) << 12); - v86_entry = i386LinearToFp(v86DiskRead); + FARPTR v86_entry = i386LinearToFp(v86DiskRead); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); vga_text = (uint16_t *)0xb8000; for (int i = 0; i < (80*25)/2; i++) { diff --git a/tests.h b/tests.h index 793209e..fff34b2 100644 --- a/tests.h +++ b/tests.h @@ -1,3 +1,4 @@ +#pragma once #include "dosfs/dosfs.h" #include "print.h" #include "interrupt.h" diff --git a/usermode.nasm b/usermode.nasm index 72316c3..d149ec9 100644 --- a/usermode.nasm +++ b/usermode.nasm @@ -6,7 +6,7 @@ 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 eax, 0 ; command = 00, get key +mov eax, 0 ; command = 00h, get key int 0x21 ; OS call push 0x00000013 ; eax AH=0,AL=3 set video mode 3 push 0x00000000 ; ecx @@ -15,7 +15,8 @@ push 0x00000000 ; ebx push 0x00000000 ; esi push 0x00000000 ; edi push esp ; regs -mov eax, 0x10 ; command = 10 +push 0x10 ; interrupt +mov eax, 0x86 ; command = 86h, virtual 8086 call int 0x21 ; OS call mov edi, 0xA0000 xor eax, eax diff --git a/v86.nasm b/v86.nasm index b6ca0ca..55882fb 100644 --- a/v86.nasm +++ b/v86.nasm @@ -1,5 +1,12 @@ [BITS 16] [SECTION .v86] + +global v86Interrupt +v86Interrupt: +int 0x00 +int 0x30 +jmp $ + real_hexprint: xor cx, cx mov bl, al @@ -70,13 +77,6 @@ int 0x30 jmp $ .c: db `\0263>=*.\?\?\?=*.\0263>` -global v86GfxMode -v86GfxMode: -mov ax, 0x13 -int 0x10 -int 0x30 -jmp $ - global v86TextMode v86TextMode: mov ax, 0x3 diff --git a/v86defs.h b/v86defs.h index acf20b6..a605073 100644 --- a/v86defs.h +++ b/v86defs.h @@ -1,12 +1,14 @@ #pragma once #include +// Labels of v8086 programs +// TODO Remove these and use +// a single define for location? extern void v86Test(); extern void v86TransFlag(); -extern void v86GfxMode(); +extern void v86Interrupt(); extern void v86TextMode(); extern void v86DiskRead(); -extern void v86VideoInt(); union __attribute((__packed__)) V86Regs_t { struct dword_regs { @@ -41,6 +43,8 @@ union __attribute((__packed__)) V86Regs_t { extern void enter_v86(uint32_t ss, uint32_t esp, uint32_t cs, uint32_t eip, union V86Regs_t *regs); +void V8086Int(uint8_t interrupt, union V86Regs_t *regs); + struct __attribute((__packed__)) Int13DiskPacket_t { uint8_t size; // 0x10 uint8_t reserved; // 0x00 @@ -50,3 +54,25 @@ struct __attribute((__packed__)) Int13DiskPacket_t { }; extern struct Int13DiskPacket_t v86disk_addr_packet; + +/* Real Mode helper macros */ +/* segment:offset pair */ +typedef uint32_t FARPTR; + +/* Make a FARPTR from a segment and an offset */ +#define MK_FP(seg, off) ((FARPTR) (((uint32_t) (seg) << 16) | (uint16_t) (off))) + +/* Extract the segment part of a FARPTR */ +#define FP_SEG(fp) (((FARPTR) fp) >> 16) + +/* Extract the offset part of a FARPTR */ +#define FP_OFF(fp) (((FARPTR) fp) & 0xffff) + +/* Convert a segment:offset pair to a linear address */ +#define FP_TO_LINEAR(seg, off) ((void*)(uintptr_t)((((uint32_t)seg) << 4) + ((uint32_t)off))) + +#define EFLAG_IF ((uint32_t)1 << 9) +#define EFLAG_VM ((uint32_t)1 << 17) + +FARPTR i386LinearToFp(void *ptr); +