From e9c4e993f481ea5e7d2608ee960c26f278657994 Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Sun, 12 Feb 2023 00:42:14 -0600 Subject: [PATCH] Lots of little things, Changed test output, Usermode test build --- Makefile | 15 ++-- disk.c | 43 ++++----- disk.h | 1 + helper.c | 1 + hexedit.c | 6 +- interrupt.c | 14 ++- kbd.c | 7 ++ kbd.h | 3 + kernel.c | 149 +++++++++++++++---------------- link.ld | 36 ++++---- progs.c | 184 +------------------------------------- tests.c | 167 ++++++++++++++++++++++------------- textedit.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++ usermode.nasm | 3 +- v86.nasm | 192 +++++++++++++++++++++++----------------- 15 files changed, 612 insertions(+), 447 deletions(-) create mode 100644 disk.h create mode 100644 textedit.c diff --git a/Makefile b/Makefile index 9f3fe89..b3eb855 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ 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 disk.o hexedit.o + paging.o fault.o tests.o kbd.o helper.o progs.o disk.o hexedit.o textedit.o CFLAGS = -target "i686-elf" -m32 -mgeneral-regs-only -ffreestanding\ -march=i686 -fno-stack-protector -Wno-int-conversion -nostdlib -c LFLAGS = -Wl,--gc-sections -Wl,--print-gc-sections -m32 -nostartfiles -nostdlib @@ -18,11 +18,14 @@ $(OUTFILE): boot.bin kernel.bin # Write kernel beyond boot sector, maximum 128K (256 sectors) dd bs=512 count=256 seek=1 conv=notrunc if=kernel.bin of=$@ -boot.bin: boot.nasm - nasm -o $@ $< +kernel.bin: out.o link.ld usermode.o + clang $(LFLAGS) -Wl,-M -Tlink.ld -ffreestanding -o $@ out.o usermode.o -kernel.bin: out.o link.ld - clang $(LFLAGS) -Wl,-M -Tlink.ld -ffreestanding -o $@ $< +usermode.o: usermode.bin + objcopy -I binary -O elf32-i386 -B i386 $< $@ + +%.bin: %.nasm + nasm -o $@ $< out.o: $(objects) clang $(LFLAGS) -e entry -r -o $@ $^ @@ -38,4 +41,4 @@ virtdisk: echo -n -e '\x55\xaa' | dd bs=1 seek=510 conv=notrunc of=virtdisk.bin clean: - rm -f $(objects) out.o kernel.bin boot.bin + rm -f $(objects) out.o kernel.bin boot.bin usermode.bin diff --git a/disk.c b/disk.c index 8a5ea7f..b206f50 100644 --- a/disk.c +++ b/disk.c @@ -1,3 +1,4 @@ +#include "disk.h" #include "v86defs.h" #include "print.h" #include "dosfs/dosfs.h" @@ -9,14 +10,15 @@ extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n); #define DISKCACHESECTORMASK 7 #define DISKCACHESECTORSIZE 8 #define DISKCACHEBLOCKCOUNT 128 -uint8_t (*DiskCache)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE] = (uint8_t (*)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE])0x280000; +uint8_t (*const DiskCache)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE] = (uint8_t (* const)[DISKCACHEBLOCKCOUNT][DISKCACHEBLOCKSIZE])0x280000; uint32_t DiskCacheLastRead[DISKCACHEBLOCKCOUNT]; uint32_t DiskCacheSector[DISKCACHEBLOCKCOUNT]; extern uint32_t _gpf_eax_save; extern uint32_t _gpf_eflags_save; extern uint16_t error_screen[80*50]; // defined in kernel.c -__attribute((__no_caller_saved_registers__)) +__attribute__((__no_caller_saved_registers__)) +__attribute__((__noreturn__)) extern void error_environment(); // defined in kernel.c uint32_t numHead; uint32_t secPerTrack; @@ -48,12 +50,6 @@ void Disk_SetupCHS() { maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2); useCHS = 1; } - - // Init Cache - for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) { - DiskCacheLastRead[i] = 0; - DiskCacheSector[i] = -1; - } } extern uint32_t TIMERVAL; @@ -95,25 +91,32 @@ void UpdateCache(uint32_t sector, uint8_t *buffer) { ((uint32_t*)cache)[i] = ((uint32_t*)buffer)[i]; } -uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) { - // NOTE If the buffer provided is outside the 0x20000-0x2FE00 range, - // the function will use that buffer for the Virtual 8086 process - // and copy to the other buffer after - uint8_t *v86buf = buffer; - if ((uintptr_t)v86buf >= 0x20000 && (uintptr_t)v86buf < 0x28000) - v86buf = (uint8_t *)0x28000; - else v86buf = (uint8_t *)0x20000; - - // TODO This check should probably happen at the kernel level - if (useCHS == -1) { - Disk_SetupCHS(); +void InitCache() { + for (int i = 0; i < DISKCACHEBLOCKCOUNT; i++) { + DiskCacheLastRead[i] = 0; + DiskCacheSector[i] = -1; } +} +// NOTE Must be run before reading from disk +void InitDisk() { + InitCache(); + Disk_SetupCHS(); +} + +uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) { uint8_t *cache = FindInCache(sector); if (cache) { memcpy(buffer, cache, count * SECTOR_SIZE); return 0; } + + // NOTE If the buffer provided is outside the 0x20000-0x2F000 range, + // the function will use 0x20000 for the Virtual 8086 process + // and copy to the other buffer after + uint8_t *v86buf = (uintptr_t)buffer >= 0x20000 && (uintptr_t)buffer <= 0x2F000 ? + buffer : + (uint8_t*)0x20000; // TODO Do error handling if (!useCHS) { diff --git a/disk.h b/disk.h new file mode 100644 index 0000000..e1af64a --- /dev/null +++ b/disk.h @@ -0,0 +1 @@ +void InitDisk(); diff --git a/helper.c b/helper.c index 38ef099..01de8fd 100644 --- a/helper.c +++ b/helper.c @@ -53,6 +53,7 @@ uint32_t OpenVol(VOLINFO *vi) { uint8_t pactive, ptype; uint32_t pstart, psize; pstart = DFS_GetPtnStart(0, diskReadBuf, 0, &pactive, &ptype, &psize); + if (pstart == -1) return -1; return DFS_GetVolInfo(0, diskReadBuf, pstart, vi); } uint32_t OpenDir(uint8_t *path, VOLINFO *vi, DIRINFO *di) { diff --git a/hexedit.c b/hexedit.c index b649e14..6a49b78 100644 --- a/hexedit.c +++ b/hexedit.c @@ -5,12 +5,12 @@ #define BLOCKSHIFT 16 // blockSize = 1 << blockShift #define MAXFILESIZE 0x80000000 // 2GB #define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE) -uint16_t writtenMap[TOTALBLOCKS] __attribute__((section(".progbss")));; -uint32_t blockLenMap[TOTALBLOCKS] __attribute__((section(".progbss")));; +uint16_t writtenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));; +uint32_t blockLenMap[TOTALBLOCKS] __attribute__((section(".hexbss")));; // NOTE This is linked at the end of program BSS section, // so that it can be expanded without telling C how much // it actually needs -uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".proglatebss"))); +uint8_t writeStoreBase[BLOCKSIZE] __attribute__((section(".hexlatebss"))); void HexEditor(uint8_t *path, VOLINFO *vi) { uint32_t err; uint16_t *vga_text = (uint16_t *)0xb8000; diff --git a/interrupt.c b/interrupt.c index ae55cfa..4f4bf36 100644 --- a/interrupt.c +++ b/interrupt.c @@ -95,9 +95,11 @@ extern uint16_t error_screen[80*50]; // defined in kernel.c extern uint16_t *ivt; extern void real_test(); extern void jmp_usermode_test(); -__attribute((__no_caller_saved_registers__)) +__attribute__((__no_caller_saved_registers__)) +__attribute__((__noreturn__)) extern void return_prev_task(); -__attribute((__no_caller_saved_registers__)) +__attribute__((__no_caller_saved_registers__)) +__attribute__((__noreturn__)) extern void error_environment(); // defined in kernel.c extern uint32_t _gpf_eax_save; #define VALID_FLAGS 0xDFF @@ -333,3 +335,11 @@ void setup_interrupts() { asm volatile("sti"); } +__attribute__((__noreturn__)) +void triple_fault() { + IDTR.size = 0; + asm volatile("lidt %0": : "m"(IDTR)); + asm volatile("sti"); + asm volatile("int $1"); + for(;;); +} diff --git a/kbd.c b/kbd.c index 2b6cec2..895edc5 100644 --- a/kbd.c +++ b/kbd.c @@ -71,6 +71,13 @@ void keyboardHandler(struct interrupt_frame *frame) { ); } +__attribute((__no_caller_saved_registers__)) +void kbd_clear() { + _KBDWAIT = 0; + _LSTKEY_ASCII = 0; + _LSTKEY_SCAN = 0; +} + __attribute((__no_caller_saved_registers__)) void kbd_wait() { _KBDWAIT = 0; diff --git a/kbd.h b/kbd.h index 6835901..10db410 100644 --- a/kbd.h +++ b/kbd.h @@ -5,6 +5,9 @@ __attribute((__no_caller_saved_registers__)) void kbd_wait(); +__attribute((__no_caller_saved_registers__)) +void kbd_clear(); + __attribute((__no_caller_saved_registers__)) uint8_t get_key(); diff --git a/kernel.c b/kernel.c index 5b2e3a5..99d446e 100644 --- a/kernel.c +++ b/kernel.c @@ -10,6 +10,7 @@ #include "tests.h" #include "progs.h" #include "helper.h" +#include "disk.h" typedef unsigned short word; @@ -63,15 +64,6 @@ uint32_t get_cr4() { return reg; } -extern char _loadusercode, _usercode, _eusercode; -void LoadUser() { - // Put Usermode code in proper place based on linker - char *s = &_loadusercode; - char *d = &_usercode; - while (d < &_eusercode) - *d++ = *s++; -} - extern char _edata, _v86code, _ev86code, _bstart, _bend; void setup_binary() { // Put V86 code in proper place based on linker @@ -80,26 +72,11 @@ void setup_binary() { while (d < &_ev86code) *d++ = *s++; - LoadUser(); - // Clear BSS area for (d = &_bstart; d < &_bend; d++) *d = 0; } -extern char _bprogstart, _bprogend; -// NOTE This is linked at the same place -// as the load address of usermode code, -// so things linked with bss here *must not* -// call usermode code at the same place -void ClearProgBss() { - // TODO Make sure there's no weird alignment stuff, - // although more BSS should always come after this - // ideally. - for (uint32_t *d = (uint32_t*)&_bprogstart; d < (uint32_t*)&_bprogend; d++) - *d = 0; -} - uint16_t error_screen[80*50]; // 50-line VGA screen of error content extern uint16_t *ivt; @@ -124,9 +101,11 @@ void ensure_v86env() { *d++ = *s++; } -__attribute((__no_caller_saved_registers__)) +__attribute__((__no_caller_saved_registers__)) +__attribute__((__noreturn__)) extern void return_prev_task(); -__attribute((__no_caller_saved_registers__)) +__attribute__((__no_caller_saved_registers__)) +__attribute__((__noreturn__)) void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32_t stack3, uint32_t stack4, uint32_t stack5) { ensure_v86env(); setup_interrupts(); // just in case @@ -172,7 +151,7 @@ void error_environment(uint32_t stack0, uint32_t stack1, uint32_t stack2, uint32 uint32_t GetFreeStack() { uint32_t stack; asm volatile("mov %%esp,%%eax":"=a"(stack)); - stack = ((stack - 0x4000) / 0x1000) * 0x1000; + stack = ((stack - 0x2000) / 0x1000) * 0x1000; return stack; } @@ -254,12 +233,18 @@ void RestoreVGA() { } int32_t fileCount, fileOffset; -DIRENT *entries = (DIRENT*)0x400000; +// We store dir entries in usermode space, +// which is nice because there's nothing after, +// but it does mean we need to reload the dir +// after every task called. This might be fine, +// since the task might have modified the directory. +extern char _USERMODE; +DIRENT *const DirEntries = (DIRENT*)&_USERMODE; #define MAXDISPFILES 16 void PrintFileList(uint16_t *vga) { uint16_t *vga_text = &((uint16_t *)vga)[80*6+3]; for (int i = 0; (i + fileOffset) < fileCount && i < MAXDISPFILES; i++) { - DIRENT *de = &entries[i + fileOffset]; + DIRENT *de = &DirEntries[i + fileOffset]; for (int i = 0; i < 11 && de->name[i]; i++) { if (i == 8) { *(uint8_t*)vga_text = ' '; vga_text++; } // space for 8.3 *(uint8_t *)vga_text = de->name[i]; @@ -323,7 +308,7 @@ void FileSelect() { OpenVol(&vi); current_path[current_path_end] = 0; OpenDir(current_path, &vi, &di); - GetFileList(entries, &fileCount, INT32_MAX, &vi, &di); + GetFileList(DirEntries, &fileCount, INT32_MAX, &vi, &di); reload = 0; } if (fileHovered >= fileCount) { @@ -365,23 +350,22 @@ void FileSelect() { reload = 1; break; case KEY_P: - if (IsDir(&entries[fileHovered])) break; - File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]); + if (IsDir(&DirEntries[fileHovered])) break; + File83ToPath((char*)DirEntries[fileHovered].name, (char*)¤t_path[current_path_end]); create_child(GetFreeStack(), (uintptr_t)ProgramLoadTest, 2, current_path, &vi); RestoreVGA(); reload = 1; break; case KEY_X: - if (IsDir(&entries[fileHovered])) break; - File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]); - ClearProgBss(); + if (IsDir(&DirEntries[fileHovered])) break; + File83ToPath((char*)DirEntries[fileHovered].name, (char*)¤t_path[current_path_end]); create_child(GetFreeStack(), (uintptr_t)HexEditor, 2, current_path, &vi); RestoreVGA(); reload = 1; break; case KEY_T: - if (IsDir(&entries[fileHovered])) break; - File83ToPath((char*)entries[fileHovered].name, (char*)¤t_path[current_path_end]); + if (IsDir(&DirEntries[fileHovered])) break; + File83ToPath((char*)DirEntries[fileHovered].name, (char*)¤t_path[current_path_end]); //TextViewTest(path, &vi); create_child(GetFreeStack(), (uintptr_t)TextViewTest, 2, current_path, &vi); RestoreVGA(); @@ -389,9 +373,9 @@ void FileSelect() { break; case KEY_O: case 0x9C: // enter release - if (IsDir(&entries[fileHovered])) { + if (IsDir(&DirEntries[fileHovered])) { uint8_t tmp_path[80]; - File83ToPath((char*)entries[fileHovered].name, (char*)tmp_path); + File83ToPath((char*)DirEntries[fileHovered].name, (char*)tmp_path); if ((*(uint32_t*)tmp_path & 0xffff) == ('.' | 0x0000)) { // Current dir, do nothing break; @@ -425,6 +409,45 @@ void FileSelect() { } } +void SystemRun() { + uint16_t *vga_text = (word *)0xb8000; + RestoreVGA(); + DrawScreen((uint16_t*)0xb8000); + + // Check for FAT partition + { + VOLINFO vi; + // TODO Check partitions beyond 0 + while (OpenVol(&vi)) { + vga_text = &((word*)0xb8000)[80*4 + 2]; + vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text); + vga_text = &((word*)0xb8000)[80*5 + 2]; + vga_text += printStr("Press R to retry.", vga_text); + for (;(get_scancode() & 0xff) != KEY_R;); + } + } + + for (;;) { + create_child(GetFreeStack(), (uintptr_t)FileSelect, 0); + // should never return, so if it does, + // we have an error + { + union V86Regs_t regs; + FARPTR v86_entry = i386LinearToFp(v86TextMode); + enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + } + RestoreVGA(); + DrawScreen((uint16_t*)0xb8000); + vga_text = &((word*)0xb8000)[80*4 + 2]; + vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text); + vga_text = &((word*)0xb8000)[80*5 + 2]; + vga_text += printStr("Press R to retry.", vga_text); + for (;(get_scancode() & 0xff) != KEY_R;); + } +} + +__attribute__((__noreturn__)) +extern void triple_fault(); uint32_t kernel_check = 0x12345678; void start() { word *vga_text = (word *)0xb8000; @@ -471,46 +494,26 @@ void start() { //vga_text += printStr("Y ", vga_text); //enable_sse(); - setup_binary(); - - // edit - setup_interrupts(); - setup_tss(); - init_paging(); //print_flags(); vga_text += printStr("CR0:", vga_text); vga_text += printDword(get_cr0(), vga_text); vga_text++; //print_cr3(); //print_cr4(); - backup_ivtbios(); - //vga_text = &((word *)0xb8000)[160]; - //vga_text += printStr("Press T for tests, or any key to continue... ", vga_text); - //uint8_t key = get_key(); - //if (key == 't' || key == 'T') - // create_child(GetFreeStack(), (uintptr_t)RunTests, 0); - RestoreVGA(); - DrawScreen((uint16_t*)0xb8000); - uint32_t stack; - asm volatile("mov %%esp,%%eax":"=a"(stack)); - stack = ((stack - 0x4000) / 0x1000) * 0x1000; - for (;;) { - create_child(stack, (uintptr_t)FileSelect, 0); - // should never return, so if it does, - // we have an error - { - union V86Regs_t regs; - FARPTR v86_entry = i386LinearToFp(v86TextMode); - enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); - } - RestoreVGA(); - DrawScreen((uint16_t*)0xb8000); - vga_text = &((word*)0xb8000)[80*4 + 2]; - vga_text += printStr("Error loading file select. Ensure the disk has a valid MBR and FAT partition.", vga_text); - vga_text = &((word*)0xb8000)[80*5 + 2]; - vga_text += printStr("Press R to retry.", vga_text); - for (;(get_scancode() & 0xff) != KEY_R;); - } + // Setup system + setup_binary(); + setup_interrupts(); + setup_tss(); + init_paging(); + backup_ivtbios(); + InitDisk(); + + create_child(GetFreeStack(), (uintptr_t)SystemRun, 0); + // If this returns, something is *very* wrong, reboot the system + // TODO Maybe try to recover? + + // Triple fault + triple_fault(); } diff --git a/link.ld b/link.ld index 9021fe9..be57bc8 100644 --- a/link.ld +++ b/link.ld @@ -3,14 +3,15 @@ ENTRY(entry) SECTIONS { . = 0x100000; + _USERMODE = 0x400000; .text : { *(.text); } .data : { - *(.data); *(.data*); + *(.data); *(.rodata); *(.rodata*); _edata = .; @@ -19,29 +20,30 @@ SECTIONS { .realmode 0x4000 : AT ( _edata ) { _v86code = .; *(.v86); _ev86code = .; } - . = _edata + SIZEOF(.realmode); - .thing : { _loadusercode = .; } - - .usermode 0x400000 : AT(_loadusercode) { - _usercode = .; *(.user); _eusercode = .; - } - .bss 0x400000 (NOLOAD) : AT(_loadusercode + SIZEOF(.usermode)) { - _bprogstart = .; - *(.progbss); - *(.progbss*); - _bprogend = .; - *(.proglatebss); - *(.proglatebss*); - } - - . = ADDR(.data) + SIZEOF(.data) + SIZEOF(.realmode) + SIZEOF(.usermode); .bss : ALIGN(0x1000) { _bstart = .; *(.bss); *(.bss*) _bend = .; } + .bss _USERMODE (NOLOAD) : AT(_bend) { + _bhexstart = .; + *(.hexbss); + *(.hexbss*); + _bhexend = .; + *(.hexlatebss); + *(.hexlatebss*); + } + .bss _USERMODE (NOLOAD) : AT(_bend) { + _btextstart = .; + *(.textbss); + *(.textbss*); + _btextend = .; + *(.textlatebss); + *(.textlatebss*); + } + /DISCARD/ : { *(.note*) *(.comment*) diff --git a/progs.c b/progs.c index d14cec5..03b8104 100644 --- a/progs.c +++ b/progs.c @@ -1,193 +1,15 @@ #include "progs.h" -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; - char pathBuff[22]; - trimPath((char*)path, pathBuff, sizeof(pathBuff)); - vga_text += printStr(pathBuff, vga_text); - vga_text += 2; - 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)+1]; - 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,(uint16_t*)0xb8000); - 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; - } - } -} // 400000 - 700000 Usermode Code (3mB) // 700000 - 800000 Usermode Stack (1mB) +extern char _USERMODE; 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; + uint8_t *diskReadBuf = (uint8_t *)&_USERMODE; { uint32_t err; uint8_t *scratch = (uint8_t *)0x20000; @@ -227,7 +49,7 @@ void ProgramLoadTest(uint8_t *path, VOLINFO *vi) { vga_text = nextLine(vga_text,(uint16_t*)0xb8000); vga_text += printStr("Press any key to run.", vga_text); kbd_wait(); - uint32_t res = create_user_child(0x800000, 0x400000, 0); + uint32_t res = create_user_child(0x800000, (uintptr_t)&_USERMODE, 0); union V86Regs_t regs; regs.w.ax = 3; // text mode V8086Int(0x10, ®s); diff --git a/tests.c b/tests.c index 81a1c15..e355979 100644 --- a/tests.c +++ b/tests.c @@ -13,18 +13,21 @@ void TestV86() { regs.d.eax = 0x66666666; FARPTR v86_entry = i386LinearToFp(v86Test); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + uint16_t *vga_text = (uint16_t *)0xb8000 + (80*2); + vga_text += printStr("Done.", vga_text); } -extern char _loadusercode, _usercode, _eusercode; +extern char _USERMODE; +extern char _binary_usermode_bin_start, _binary_usermode_bin_end; void ReloadUser() { // Put Usermode code in proper place based on linker - char *s = &_loadusercode; - char *d = &_usercode; - while (d < &_eusercode) + char *s = &_binary_usermode_bin_start; + char *d = (char *)&_USERMODE; + while (s < &_binary_usermode_bin_end) *d++ = *s++; } char TestUser() { ReloadUser(); - char *vga = (char *)(uintptr_t)create_user_child(0x800000, (uintptr_t)user_test, 0); + char *vga = (char *)(uintptr_t)create_user_child(0x800000, (uintptr_t)&_USERMODE, 0); if ((uintptr_t)vga != 0xA0000) { return 1; } @@ -34,24 +37,40 @@ char TestUser() { return 0; } void TestDiskRead() { - //vga_text += printStr("Starting Disk Read... ", vga_text); - union V86Regs_t regs; char *diskReadBuf = (char *)0x20000; - v86disk_addr_packet.transfer_buffer = - (uintptr_t)diskReadBuf & 0x000F | - (((uintptr_t)diskReadBuf & 0xFFFF0) << 12); - regs.h.ah = 0x42; - FARPTR v86_entry = i386LinearToFp(v86DiskOp); - enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); - uint16_t *vga_text = (uint16_t *)0xb8000; - for (int i = 0; i < (80*25)/2; i++) { - printByte(diskReadBuf[i], &vga_text[i*2]); + v86disk_addr_packet.transfer_buffer = + (uintptr_t)diskReadBuf & 0x000F | + (((uintptr_t)diskReadBuf & 0xFFFF0) << 12); + v86disk_addr_packet.start_block = 0; + v86disk_addr_packet.blocks = 2; + union V86Regs_t regs; + kbd_clear(); + for (;;) { + regs.h.ah = 0x42; + FARPTR v86_entry = i386LinearToFp(v86DiskOp); + enter_v86(0x0000, 0x8000, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + uint16_t *vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < 25; i++) { + uint16_t *vga_line = &vga_text[i*80]; + for (int j = 0; j < 26; j++) { + printByte(diskReadBuf[i*26 + j], &vga_line[j*2]); + *(uint8_t*)&vga_line[j + (26*2)+1] = diskReadBuf[i*26 + j]; + } + } + uint16_t scan = get_scancode(); + if ((scan & 0xff) == KEY_PGUP) { + if(v86disk_addr_packet.start_block > 0) v86disk_addr_packet.start_block--; + } else if ((scan & 0xff) == KEY_PGDOWN) + v86disk_addr_packet.start_block++; + else if (scan & 0xff00) break; } } extern uint32_t _gpf_eax_save; extern uint32_t _gpf_eflags_save; void TestCHS() { uint16_t *vga_text = (uint16_t*)0xb8000; + for (int i = 0; i < 80*25; i++) + vga_text[i] = 0x0f00; printStr("CHS Test ", vga_text); // CHS Read union V86Regs_t regs; @@ -175,55 +194,77 @@ void TestFAT() { } void RunTests() { + char doTests = 1; 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); - for(;;) { - key = get_key(); - if (key == 'N' || key == 'n') break; - *vga_text = (*vga_text & 0xFF00) | key; - vga_text++; - } - char userResult = TestUser(); - union V86Regs_t regs; - regs.w.ax = 3; // text mode - V8086Int(0x10, ®s); - vga_text = (uint16_t *)0xb8000 + (80*5); - printStr("Press any key to continue.", vga_text); - if (userResult) { - // Usermode returned wrong value - printStr("Usermode test failed! Press any key to continue.", vga_text); - } - kbd_wait(); - TestCHS(); - kbd_wait(); - TestDiskRead(); - kbd_wait(); - TestFAT(); + for (char l = 1;l;) { + if (doTests) { + vga_text = (uint16_t*)0xb8000; + for (int i = 0; i < 80*25; i++) + vga_text[i] = 0x1f00; + 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("Press 'N' for next test.", vga_text); + for(;;) { + key = get_key(); + if (key == 'N' || key == 'n') break; + *vga_text = (*vga_text & 0xFF00) | key; + vga_text++; + } + if (TestUser()) { + union V86Regs_t regs; + regs.w.ax = 3; // text mode + V8086Int(0x10, ®s); + vga_text = (uint16_t *)0xb8000 + (80*5); + printStr("Usermode test failed! Press any key to continue.", vga_text); + kbd_wait(); + } else { + kbd_wait(); + union V86Regs_t regs; + regs.w.ax = 3; // text mode + V8086Int(0x10, ®s); + } + doTests = 0; + } - vga_text = &((uint16_t*)0xB8000)[80*16]; - vga_text += printStr("Press E for a flagrant system error. Press C to continue... ", vga_text); - for (char l = 1;l;) { switch (key = get_key()) { - case 'e': - case 'E': - // flagrant system error - *((uint8_t*)0x1000000) = 0; - break; - case 'c': - case 'C': - // continue - l = 0; - break; - default: - *vga_text = (*vga_text & 0xFF00) | key; - vga_text++; - break; - }} + vga_text = &((uint16_t*)0xB8000)[80*14]; + vga_text += printStr("Press E for a flagrant system error. ", vga_text); + vga_text = &((uint16_t*)0xB8000)[80*15]; + vga_text += printStr("Press D for disk tests. ", vga_text); + vga_text = &((uint16_t*)0xB8000)[80*16]; + vga_text += printStr("Press R to repeat tests. ", vga_text); + vga_text = &((uint16_t*)0xB8000)[80*17]; + vga_text += printStr("Press C to continue... ", vga_text); + switch (key = get_key()) { + case 'e': + case 'E': + // flagrant system error + *((uint8_t*)0x1000000) = 0; + break; + case 'c': + case 'C': + // continue + l = 0; + break; + case 'd': + case 'D': + // disk tests + TestCHS(); + kbd_wait(); + TestDiskRead(); + TestFAT(); + break; + case 'r': + case 'R': + doTests = 1; + break; + default: + *vga_text = (*vga_text & 0xFF00) | key; + vga_text++; + break; + } + } } diff --git a/textedit.c b/textedit.c new file mode 100644 index 0000000..3b9bdae --- /dev/null +++ b/textedit.c @@ -0,0 +1,238 @@ +#include "progs.h" + +#define MAXFILESIZE 0x300000 // 3MB +#define MAXLINES 100000 +#define BLOCKSIZE 0x1000 +#define BLOCKMASK 0xfff +#define BLOCKSHIFT 12 +#define TOTALBLOCKS (MAXFILESIZE/BLOCKSIZE) +uintptr_t lineOffsets[MAXLINES] __attribute__((section(".textbss")));; +uintptr_t lineLengths[MAXLINES] __attribute__((section(".textbss")));; +uint8_t editedBlocks[TOTALBLOCKS] __attribute__((section(".textbss")));; +uint8_t fileBuffer[MAXFILESIZE] + __attribute__((aligned(0x1000))) + __attribute__((section(".textlatebss"))); +void TextViewTest(uint8_t *path, VOLINFO *vi) { + uint16_t *vga_text = (uint16_t *)0xb8000; + uint32_t fileLen; + { + 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); + kbd_wait(); + return; + } + // file too large + if (fi.filelen > MAXFILESIZE) { + 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); + kbd_wait(); + return; + } + err = DFS_ReadFile(&fi, scratch, fileBuffer, &fileLen, fi.filelen); + if (err && err != DFS_EOF) { + vga_text += printStr("Read Error: ", vga_text); + printDword(err, vga_text); + kbd_wait(); + return; + } + } + uint32_t lastLine; + { + char nl; + uint8_t c = 0x0A; // start with a pretend newline + uint32_t line = -1; // start a pretend line behind + uint32_t lineLen = 0; + for (int32_t o = -1; o < (int32_t)fileLen; lineLen++, c = fileBuffer[++o]) { + // newline + if (c == 0x0A) { + lineOffsets[++line] = o; + lineLengths[line] = lineLen > 0 ? lineLen : 1; + lineLen = 0; + } + // file too large + if (line >= MAXLINES) { + vga_text += printStr("File too large.", vga_text); + kbd_wait(); + return; + } + } + lineLengths[line] = lineLen; + lastLine = line; + } + uint32_t currLine = 0; + char cont = 1; + uint32_t screenSize = 80*25; + char redraw = 1; + uint32_t linesOnScreen = 0; + uint32_t cursorLine = 0; + uint32_t cursorLineOffset = 0; + char cursorChange = 0; + for (;cont;) { + if (cursorLine > lastLine) { + cursorLine = lastLine; + cursorLineOffset = lineLengths[lastLine] - 2; + cursorChange = 1; + } + if (lineLengths[cursorLine+1] == 1 && cursorLineOffset == 0){} + else if (cursorLineOffset >= lineLengths[cursorLine+1] - 1) { + cursorLineOffset = 0; + cursorLine++; + cursorChange = 1; + } + + if (redraw || cursorChange) { + vga_text = (uint16_t *)0xb8000; + for (int i = 0; i < screenSize; i++) + vga_text[i] = 0x0f00; + char pathBuff[22]; + trimPath((char*)path, pathBuff, sizeof(pathBuff)); + vga_text += printStr(pathBuff, vga_text); + vga_text += 2; + 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: F1"; + vga_text = &((uint16_t*)0xb8000)[80-sizeof(prnt)+1]; + 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 screenLineOff = 6; + uint32_t lineOffset = 0; + 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 = fileBuffer[++o]) { + // newline + if (c == 0x0A) { + vga_text = nextLine(vga_text,(uint16_t*)0xb8000); + line++; + lineOffset = 0; + { + 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; + screenLineOff = 6; + if (cursorLine == line && cursorLineOffset == lineOffset) { + ((uint8_t*)vga_text)[1] = 0xf0; + } + continue; + } + *(uint8_t*)vga_text = c; + if (cursorLine == line && cursorLineOffset == lineOffset) { + ((uint8_t*)vga_text)[1] = 0xf0; + } + lineOffset++; + vga_text++; + screenLineOff++; + if (screenLineOff == 80) { // last char + vga_text += 6; + screenLineOff = 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_DOWN: + cursorLine++; + cursorChange = 1; + break; + case KEY_UP: + if (cursorLine > 0) cursorLine--; + cursorChange = 1; + break; + case KEY_LEFT: + if (cursorLineOffset > 0) cursorLineOffset--; + cursorChange = 1; + break; + case KEY_RIGHT: + cursorLineOffset++; + cursorChange = 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_F1: + 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/usermode.nasm b/usermode.nasm index 2e5c355..81ad030 100644 --- a/usermode.nasm +++ b/usermode.nasm @@ -1,4 +1,5 @@ -[SECTION .user] +[BITS 32] +[ORG 0x400000] global user_test user_test: mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16 diff --git a/v86.nasm b/v86.nasm index 54ddd5f..c9382b3 100644 --- a/v86.nasm +++ b/v86.nasm @@ -4,7 +4,83 @@ global v86Interrupt v86Interrupt: int 0x00 int 0x30 -jmp $ +ud2 + +global v86TransFlag +v86TransFlag: +push cs +pop es +mov ax, 0x13 +int 0x10 +mov ax,0x1012 +xor bx,bx +mov cx,5 +mov dx,.c +int 0x10 +push 0xa000 +pop es +xor di,di +xor ax,ax +.loop: +mov cx, 12800 +rep stosb +inc ax +cmp ax,5 +jl .loop +int 0x30 +ud2 +.c: db `\0263>=*.\?\?\?=*.\0263>` + +global v86VideoInt +v86VideoInt: +int 0x10 +int 0x30 +ud2 + +global v86DiskOp +v86DiskOp: +xor bx, bx ; TODO fix assuming we're in first 64k +mov ds, bx +mov dl, 0x80 ; TODO get this from BIOS or something +mov si, v86disk_addr_packet ; ds:si +int 0x13 +jc .err +int 0x30 +.err: +ud2 +global v86disk_addr_packet +v86disk_addr_packet: +db 0x10, 0x00 ; size, reserved +dw 0x1 ; blocks +dd 0x23000000 ; transfer buffer 0x23000 +dq 0x1 ; start block + +global v86DiskGetGeometry +v86DiskGetGeometry: +mov ah, 8 +mov dl, 0x80 +int 0x13 +movzx eax, ch +shl eax, 16 +mov al, cl +mov ah, dh +int 0x30 +ud2 + +global v86DiskReadCHS +v86DiskReadCHS: +push 0x2000 +pop es +int 0x13 +int 0x30 +ud2 + +global v86TextMode +v86TextMode: +mov ax, 0x3 +int 0x10 +int 0x30 +ud2 real_hexprint: xor cx, cx @@ -36,94 +112,48 @@ ret global v86Test v86Test: -mov ax, 0xb814 +mov ax, (0xB8000 + (80*2)) >> 4 mov es, ax -mov di, 20 +mov di, 0 +mov word es:[di+0], 0x1f00 | 'S' +mov word es:[di+2], 0x1f00 | 'S' +mov word es:[di+4], 0x1f00 | ':' +add di, 6 +mov ax, ss +call real_printword +add di, 2 +mov word es:[di+0], 0x1f00 | 'S' +mov word es:[di+2], 0x1f00 | 'P' +mov word es:[di+4], 0x1f00 | ':' +add di, 6 mov ax, sp call real_printword add di, 2 +mov word es:[di+0], 0x1f00 | 'D' +mov word es:[di+2], 0x1f00 | 'S' +mov word es:[di+4], 0x1f00 | ':' +add di, 6 mov ax, ds call real_printword add di, 2 +mov word es:[di+0], 0x1f00 | 'C' +mov word es:[di+2], 0x1f00 | 'S' +mov word es:[di+4], 0x1f00 | ':' +add di, 6 mov ax, cs call real_printword -int 3 +add di, 2 +mov ax, cs +mov ds, ax +mov si, .testStr +mov ah, 0x1f +mov cx, .testStr_end - .testStr +.print: +lodsb +stosw +loop .print +int 3 ; wait for key int 0x30 ; exit -jmp $ - -global v86TransFlag -v86TransFlag: -push cs -pop es -mov ax, 0x13 -int 0x10 -mov ax,0x1012 -xor bx,bx -mov cx,5 -mov dx,.c -int 0x10 -push 0xa000 -pop es -xor di,di -xor ax,ax -.loop: -mov cx, 12800 -rep stosb -inc ax -cmp ax,5 -jl .loop -int 0x30 -jmp $ -.c: db `\0263>=*.\?\?\?=*.\0263>` - -global v86TextMode -v86TextMode: -mov ax, 0x3 -int 0x10 -int 0x30 -jmp $ - -global v86VideoInt -v86VideoInt: -int 0x10 -int 0x30 -jmp $ - -global v86DiskOp -v86DiskOp: -xor bx, bx ; TODO fix assuming we're in first 64k -mov ds, bx -mov dl, 0x80 ; TODO get this from BIOS or something -mov si, v86disk_addr_packet ; ds:si -int 0x13 -jc .err -int 0x30 -.err: -ud2 -jmp $ -global v86disk_addr_packet -v86disk_addr_packet: -db 0x10, 0x00 ; size, reserved -dw 0x1 ; blocks -dd 0x23000000 ; transfer buffer 0x23000 -dq 0x1 ; start block - -global v86DiskGetGeometry -v86DiskGetGeometry: -mov ah, 8 -mov dl, 0x80 -int 0x13 -movzx eax, ch -shl eax, 16 -mov al, cl -mov ah, dh -int 0x30 -ud2 - -global v86DiskReadCHS -v86DiskReadCHS: -push 0x2000 -pop es -int 0x13 -int 0x30 ud2 +.testStr: db "PRESS ANY KEY" +.testStr_end: