Lots of little things, Changed test output, Usermode test build

This commit is contained in:
Lucia Ceionia 2023-02-12 00:42:14 -06:00
parent 36e66600f5
commit e9c4e993f4
15 changed files with 612 additions and 447 deletions

View File

@ -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

43
disk.c
View File

@ -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) {

1
disk.h Normal file
View File

@ -0,0 +1 @@
void InitDisk();

View File

@ -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) {

View File

@ -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;

View File

@ -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(;;);
}

7
kbd.c
View File

@ -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;

3
kbd.h
View File

@ -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();

149
kernel.c
View File

@ -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*)&current_path[current_path_end]);
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_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*)&current_path[current_path_end]);
ClearProgBss();
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_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*)&current_path[current_path_end]);
if (IsDir(&DirEntries[fileHovered])) break;
File83ToPath((char*)DirEntries[fileHovered].name, (char*)&current_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), &regs);
}
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), &regs);
}
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();
}

36
link.ld
View File

@ -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*)

184
progs.c
View File

@ -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, &regs);

167
tests.c
View File

@ -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), &regs);
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), &regs);
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), &regs);
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, &regs);
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, &regs);
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, &regs);
}
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;
}
}
}

238
textedit.c Normal file
View File

@ -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;
}
}
}

View File

@ -1,4 +1,5 @@
[SECTION .user]
[BITS 32]
[ORG 0x400000]
global user_test
user_test:
mov dword [0xb8000], 0x0f000f00 | 'U' | 's' << 16

192
v86.nasm
View File

@ -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: