From c712d7f6f801b073920c7b914ee1b95358113893 Mon Sep 17 00:00:00 2001 From: Alexis211 Date: Sun, 8 Nov 2009 16:51:30 +0100 Subject: Introduced V86 mode. It really fits in nicely :) --- Source/Applications/Shell/Shell.ns.cpp | 3 +- Source/Kernel/Core/Sys.ns.cpp | 21 ++- Source/Kernel/Core/Sys.ns.h | 2 + Source/Kernel/Core/kmain.wtf.cpp | 15 ++ Source/Kernel/Makefile | 2 + Source/Kernel/MemoryManager/GDT.ns.cpp | 1 + Source/Kernel/MemoryManager/GDT.ns.h | 1 + .../Kernel/MemoryManager/PageDirectory.class.cpp | 18 +- Source/Kernel/MemoryManager/PhysMem.ns.cpp | 1 + Source/Kernel/SyscallManager/IDT.ns.cpp | 2 +- Source/Kernel/TaskManager/Thread.class.cpp | 32 ++-- Source/Kernel/TaskManager/Thread.class.h | 7 +- Source/Kernel/TaskManager/V86/V86Thread.class.cpp | 200 +++++++++++++++++++++ Source/Kernel/TaskManager/V86/V86Thread.class.h | 59 ++++++ Source/Kernel/TaskManager/V86/v86.wtf.asm | 11 ++ Source/Library/Userland/Syscall/Syscall.wtf.cpp | 4 + Source/Library/Userland/Syscall/Syscall.wtf.h | 1 + 17 files changed, 353 insertions(+), 27 deletions(-) create mode 100644 Source/Kernel/TaskManager/V86/V86Thread.class.cpp create mode 100644 Source/Kernel/TaskManager/V86/V86Thread.class.h create mode 100644 Source/Kernel/TaskManager/V86/v86.wtf.asm diff --git a/Source/Applications/Shell/Shell.ns.cpp b/Source/Applications/Shell/Shell.ns.cpp index cd091d5..d34c360 100644 --- a/Source/Applications/Shell/Shell.ns.cpp +++ b/Source/Applications/Shell/Shell.ns.cpp @@ -26,11 +26,12 @@ u32int run() { while (1) { outvt << "{" << cwd.getName() << "}: "; String s = invt.readLine(); + if (s.empty()) continue; while (s[0] == WChar(" ") or s[0] == WChar("\t")) { s = s.substr(1, s.size() - 1); } - if (s[0] == WChar("#")) continue; if (s.empty()) continue; + if (s[0] == WChar("#")) continue; //Parse string Vector cmd; diff --git a/Source/Kernel/Core/Sys.ns.cpp b/Source/Kernel/Core/Sys.ns.cpp index e5dbdc0..30d9755 100644 --- a/Source/Kernel/Core/Sys.ns.cpp +++ b/Source/Kernel/Core/Sys.ns.cpp @@ -71,6 +71,16 @@ void bochs_output_hex(u32int i) { } } +void dumpRegs(registers_t *regs, VirtualTerminal& vt) { + vt << "ds=" << (u32int)regs->ds << ", eip=" << (u32int)regs->eip << ", cs=" << (u32int)regs->cs << "\n"; + vt << "edi=" << (u32int)regs->edi << ", esi=" << (u32int)regs->esi << ", ebp=" << (u32int)regs->ebp << + ", esp=" << (u32int)regs->esp << "\n"; + vt << "eax=" << (u32int)regs->eax << ", ebx=" << (u32int)regs->ebx << ", ecx=" << (u32int)regs->ecx << + ", edx=" << (u32int)regs->edx << "\n"; + vt << "int_no=" << (s32int)regs->int_no << ", err_code=" << (u32int)regs->err_code << "\n"; + vt << "eflags=" << (u32int)regs->eflags << ", useresp=" << (u32int)regs->useresp << ", ss=" << (u32int)regs->ss << "\n"; +} + //Used by PANIC() macro (see common.wtf.h) void panic(char *message, char *file, u32int line) { asm volatile("cli"); @@ -91,19 +101,14 @@ void panic(char *message, registers_t *regs, char *file, u32int line) { vt.write("\n"); vt << "PANIC : " << message << "\n => in " << file << " at " << (s32int)line << "\n\n"; - vt << "ds=" << (u32int)regs->ds << ", eip=" << (u32int)regs->eip << ", cs=" << (u32int)regs->cs << "\n"; - vt << "edi=" << (u32int)regs->edi << ", esi=" << (u32int)regs->esi << ", ebp=" << (u32int)regs->ebp << - ", esp=" << (u32int)regs->esp << "\n"; - vt << "eax=" << (u32int)regs->eax << ", ebx=" << (u32int)regs->ebx << ", ecx=" << (u32int)regs->ecx << - ", edx=" << (u32int)regs->edx << "\n"; - vt << "int_no=" << (s32int)regs->int_no << ", err_code=" << (u32int)regs->err_code << "\n"; - vt << "eflags=" << (u32int)regs->eflags << ", useresp=" << (u32int)regs->useresp << ", ss=" << (u32int)regs->ss << "\n"; + dumpRegs(regs, vt); + if (regs->int_no == 14) { u32int cr2; asm volatile("mov %%cr2, %0" : "=r"(cr2)); vt << "cr2=" << (u32int)cr2 << "\n"; } - vt << "\n"; + vt << "\n\n"; while (1) asm volatile("cli; hlt"); diff --git a/Source/Kernel/Core/Sys.ns.h b/Source/Kernel/Core/Sys.ns.h index 1ed446c..c5e4400 100644 --- a/Source/Kernel/Core/Sys.ns.h +++ b/Source/Kernel/Core/Sys.ns.h @@ -18,12 +18,14 @@ //This file contains system-relative functions class String; +class VirtualTerminal; struct registers_t; namespace Sys { void outb(u16int port, u8int value); u8int inb(u16int port); u16int inw(u16int port); + void dumpRegs(registers_t *regs, VirtualTerminal& vt); void panic(char* message, char *file, u32int line); void panic(char* message, registers_t *regs, char *file, u32int line); void panic_assert(char* file, u32int line, char *desc); diff --git a/Source/Kernel/Core/kmain.wtf.cpp b/Source/Kernel/Core/kmain.wtf.cpp index 62f96d5..26afdfd 100644 --- a/Source/Kernel/Core/kmain.wtf.cpp +++ b/Source/Kernel/Core/kmain.wtf.cpp @@ -31,6 +31,18 @@ #include +#include +extern v86_function_t v86test; + +void testV86() { + VirtualTerminal* vt = new ScrollableVT(15, 76, 200, SHELL_FGCOLOR, SHELL_BGCOLOR); + Task::currProcess()->setOutVT(vt); + v86_retval_t r; + new V86Thread(&v86test, &r, 0); + while (!r.finished); + PANIC("V86 TEST END"); +} + extern u32int end; //Placement address extern "C" void kmain(multiboot_info_t* mbd, u32int magic); @@ -184,10 +196,13 @@ void kmain(multiboot_info_t* mbd, u32int magic) { Sys::halt(); */ + testV86(); + Process* p = Process::run("/System/Applications/PaperWork.app", 0); if (p == 0) { PANIC("Could not launch PaperWork !"); } else { + Log::log(KL_STATUS, "kmain : Starting PaperWork (init)"); VirtualTerminal* vt = new ScrollableVT(15, 76, 200, SHELL_FGCOLOR, SHELL_BGCOLOR); Kbd::setFocus(vt); ((ScrollableVT*)vt)->map(9); diff --git a/Source/Kernel/Makefile b/Source/Kernel/Makefile index b7a8bd3..506faf4 100644 --- a/Source/Kernel/Makefile +++ b/Source/Kernel/Makefile @@ -28,6 +28,8 @@ Objects = Core/loader.wtf.o \ TaskManager/Process.class.o \ TaskManager/Process-sc.class.o \ TaskManager/Thread.class.o \ + TaskManager/V86/V86Thread.class.o \ + TaskManager/V86/v86.wtf.o \ TaskManager/Task.ns.o \ TaskManager/Task.wtf.o \ VTManager/VirtualTerminal.proto.o \ diff --git a/Source/Kernel/MemoryManager/GDT.ns.cpp b/Source/Kernel/MemoryManager/GDT.ns.cpp index f1f5c94..668dc57 100644 --- a/Source/Kernel/MemoryManager/GDT.ns.cpp +++ b/Source/Kernel/MemoryManager/GDT.ns.cpp @@ -34,6 +34,7 @@ void writeTSS(s32int num, u16int ss0, u32int esp0) { tss_entry.ss0 = ss0; tss_entry.esp0 = esp0; + tss_entry.iomap_base = sizeof(tss_entry_t) - 8192; tss_entry.cs = 0x0B; //0x0B = Kernel code segment + RPL=3 (meaning it is supposed to be called from user mode) //0x13 = Kernel data segment + RPL=3 (meaning to be called from ring3) diff --git a/Source/Kernel/MemoryManager/GDT.ns.h b/Source/Kernel/MemoryManager/GDT.ns.h index 9505433..d42587f 100644 --- a/Source/Kernel/MemoryManager/GDT.ns.h +++ b/Source/Kernel/MemoryManager/GDT.ns.h @@ -42,6 +42,7 @@ namespace GDT { u32int ldt; // Unused... u16int trap; u16int iomap_base; + u8int ioports[8192]; } __attribute__((packed)); struct gdt_ptr_t { diff --git a/Source/Kernel/MemoryManager/PageDirectory.class.cpp b/Source/Kernel/MemoryManager/PageDirectory.class.cpp index 13fbc36..c10f844 100644 --- a/Source/Kernel/MemoryManager/PageDirectory.class.cpp +++ b/Source/Kernel/MemoryManager/PageDirectory.class.cpp @@ -23,6 +23,7 @@ PageDirectory::PageDirectory(PageDirectory* other) { for (u32int j = 0; j < 1024; j++) { if (!(other->tables[i]->pages[j].frame)) continue; + if (i == 0 and j < 256) continue; //Frame is below 1M, probably used by some V86 stuff. Ignore it. PhysMem::allocFrame(&tables[i]->pages[j], true, true); tables[i]->pages[j].present = other->tables[i]->pages[j].present; tables[i]->pages[j].rw = other->tables[i]->pages[j].rw; @@ -46,6 +47,7 @@ PageDirectory::~PageDirectory() { for (int i = 0; i < 768; i++) { //Only free addresses below 0xC0000000, upper is kernel space if (tables[i] != 0) { for (int j = 0; j < 1024; j++) { + if (i == 0 and j < 256) continue; //Frame is below 1M, probably used by some V86 stuff. Ignore it. PhysMem::freeFrame(&(tables[i]->pages[j])); } PageAlloc::free((void*)tables[i]); @@ -74,13 +76,25 @@ page_t *PageDirectory::getPage(u32int address, bool make) { void PageDirectory::allocFrame(u32int address, bool is_user, bool is_writable) { page_t *p = getPage(address, true); - if (p != 0) PhysMem::allocFrame(p, is_user, is_writable); + if (address < 0x100000) { + p->present = 1; + p->user = (is_user ? 1 : 0); + p->rw = (is_writable ? 1 : 0); + p->frame = (address / 0x1000); + } else { + if (p != 0) PhysMem::allocFrame(p, is_user, is_writable); + } } void PageDirectory::freeFrame(u32int address) { page_t *p = getPage(address, false); if (p == 0) return; - PhysMem::freeFrame(p); + if (address < 0x100000) { + p->frame = 0; + p->present = 0; + } else { + PhysMem::freeFrame(p); + } } void PageDirectory::switchTo() { diff --git a/Source/Kernel/MemoryManager/PhysMem.ns.cpp b/Source/Kernel/MemoryManager/PhysMem.ns.cpp index 1b40e88..54eb4de 100644 --- a/Source/Kernel/MemoryManager/PhysMem.ns.cpp +++ b/Source/Kernel/MemoryManager/PhysMem.ns.cpp @@ -63,6 +63,7 @@ void freeFrame(page_t *page) { if (page->frame >= 0x100) { //First 1M are reserved (system) frames->clearBit(page->frame); } + page->present = 0; page->frame = 0; } } diff --git a/Source/Kernel/SyscallManager/IDT.ns.cpp b/Source/Kernel/SyscallManager/IDT.ns.cpp index 042ef92..7c4b5cb 100644 --- a/Source/Kernel/SyscallManager/IDT.ns.cpp +++ b/Source/Kernel/SyscallManager/IDT.ns.cpp @@ -67,7 +67,7 @@ extern "C" void interrupt_handler(registers_t regs) { if (regs.int_no < 32) { if ((u32int)Task::currThread() == 0xFFFFFFFF or Task::currThread() == 0) PANIC_DUMP("Exception cannot be handled.", ®s); - Task::currThread()->handleException(regs, regs.int_no); + Task::currThread()->handleException(®s, regs.int_no); } else if (regs.int_no < 48) { if (regs.int_no >= 40) outb(0xA0, 0x20); diff --git a/Source/Kernel/TaskManager/Thread.class.cpp b/Source/Kernel/TaskManager/Thread.class.cpp index ba3612d..f1c3df1 100644 --- a/Source/Kernel/TaskManager/Thread.class.cpp +++ b/Source/Kernel/TaskManager/Thread.class.cpp @@ -18,7 +18,7 @@ u32int Thread::scall(u8int wat, u32int a, u32int b, u32int c, u32int d) { return (u32int) - 1; } -void runThread(Thread* thread, void* data, thread_entry_t entry_point) { +void Thread::run(Thread* thread, void* data, thread_entry_t entry_point) { thread->m_process->getPagedir()->switchTo(); if (thread->m_isKernel) { asm volatile("sti"); @@ -84,7 +84,7 @@ Thread::~Thread() { Task::unregisterThread(this); Mem::free(m_kernelStack.addr); m_process->getPagedir()->switchTo(); - if (m_userStack.addr != 0) { + if (m_userStack.addr != 0 && !m_isKernel) { m_process->heap().free(m_userStack.addr); } if (m_xchgspace != 0) { @@ -109,7 +109,7 @@ void Thread::setup(Process* process, thread_entry_t entry_point, void* data, boo } u32int* stack = (u32int*)((u32int)(m_kernelStack.addr) + m_kernelStack.size); - //Pass function parameters for runThread() + //Pass function parameters for run() stack--; *stack = (u32int)entry_point; //Push entry point (function parameter) stack--; @@ -120,7 +120,7 @@ void Thread::setup(Process* process, thread_entry_t entry_point, void* data, boo *stack = 0; //Null return address m_esp = (u32int)stack; m_ebp = m_esp + 8; - m_eip = (u32int)runThread; + m_eip = (u32int)run; m_state = T_RUNNING; m_process->registerThread(this); @@ -140,7 +140,7 @@ void Thread::finish(u32int errcode) { m_process->threadFinishes(this, errcode); } -void Thread::handleException(registers_t regs, int no) { +void Thread::handleException(registers_t *regs, int no) { char* exceptions[] = { "Division by zero", "Debug exception", "Non maskable interrupt", "Breakpoint exception", "'Into detected overflow'", "Out of bounds exception", @@ -156,15 +156,23 @@ void Thread::handleException(registers_t regs, int no) { VirtualTerminal &vt = *(m_process->m_outVT); - vt << "\nUnhandled exception " << (s32int)no << " at " << (u32int)regs.cs << ":" << - (u32int)regs.eip << "\n:: " << exceptions[no]; - if (m_isKernel) PANIC_DUMP("Exception in kernel thread", ®s); + vt << "\nUnhandled exception " << (s32int)no << " at " << (u32int)regs->cs << ":" << + (u32int)regs->eip << "\n:: " << exceptions[no]; + if (no == 3) { + vt << "\n\nBreakpoint data :\n"; + Sys::dumpRegs(regs, vt); + vt << "Press any key to continue execution of program..."; + m_process->m_inVT->getKeypress(false); + vt << "\n"; + return; + } + if (m_isKernel) PANIC_DUMP("Exception in kernel thread", regs); if (no == 14) { //Page fault - int present = !(regs.err_code & 0x1); - int rw = regs.err_code & 0x2; - int us = regs.err_code & 0x4; - int rsvd = regs.err_code & 0x8; + int present = !(regs->err_code & 0x1); + int rw = regs->err_code & 0x2; + int us = regs->err_code & 0x4; + int rsvd = regs->err_code & 0x8; u32int faddr; asm volatile("mov %%cr2, %0" : "=r"(faddr)); vt << "\n "; diff --git a/Source/Kernel/TaskManager/Thread.class.h b/Source/Kernel/TaskManager/Thread.class.h index 6d37350..b325117 100644 --- a/Source/Kernel/TaskManager/Thread.class.h +++ b/Source/Kernel/TaskManager/Thread.class.h @@ -13,9 +13,10 @@ typedef u32int(*thread_entry_t)(void*); class Thread : public Ressource { friend class Process; //This might be useful - friend void runThread(Thread*, void*, thread_entry_t); - private: + protected: + static void run(Thread* thread, void* data, thread_entry_t entry_point); + Thread(); //Creates a thread without initializing anything. Used by Process::createKernel(); Process *m_process; //Associated process @@ -50,7 +51,7 @@ class Thread : public Ressource { Thread(Process* process, thread_entry_t entry_point, void* data); ~Thread(); void finish(u32int errcode); //Called by run() when thread returns, and by exception handler. Can also be called by the thread itself - void handleException(registers_t regs, int no); + virtual void handleException(registers_t *regs, int no); void setState(u32int esp, u32int ebp, u32int eip); void setKernelStack(); diff --git a/Source/Kernel/TaskManager/V86/V86Thread.class.cpp b/Source/Kernel/TaskManager/V86/V86Thread.class.cpp new file mode 100644 index 0000000..babf5b6 --- /dev/null +++ b/Source/Kernel/TaskManager/V86/V86Thread.class.cpp @@ -0,0 +1,200 @@ +#include "V86Thread.class.h" +#include + +u16int V86Thread::allocSeg = V86_ALLOC_START; + +u16int V86Thread::alloc(u16int length) { + if (length & 0xF) length = (length & 0xFFFF0) + 0x10; + u16int segments = length / 16; + if (allocSeg < V86_ALLOC_START) allocSeg = V86_ALLOC_START; + if (allocSeg + segments > V86_ALLOC_END) allocSeg = V86_ALLOC_START; + u16int ret = allocSeg; + allocSeg += segments; + return ret; +} + +void V86Thread::runV86(V86Thread* thread, u32int data, u32int ss, u32int cs) { + thread->m_process->getPagedir()->switchTo(); + //Setup values on user stack + u32int *stack = (u32int*)(FP_TO_LINEAR(ss, V86_STACKSIZE)); + stack--; *stack = data; + + u32int sp = V86_STACKSIZE - 4; + + //Setup a false iret structure on the kernel stack, containing (first pushed first) : + // - gs = cs + // - fs = cs + // - ds = cs + // - es = cs + // - stack segment = ss (temporarily in ecx) + // - stack pointer = sp (temp in ebx) + // - flags (OR'ed with EFLAGS.VM) + // - code segment = cs (temp in eax) + // - instruction pointer = ip (is 0) + asm volatile(" \ + pushl %%eax; \ + pushl %%eax; \ + pushl %%eax; \ + pushl %%eax; \ + pushl %%ecx; \ + pushl %%ebx; \ + pushf; \ + pop %%ebx; \ + or $0x200, %%ebx; \ + or $0x20000, %%ebx; \ + push %%ebx; \ + pushl %%eax; \ + pushl $0; \ + iret; \ + " : : "a"(cs), "c"(ss), "b"(sp)); +} + +/* + * Set up a V86 task : + * Allocate space for the kernel stack + * Map frames in lower 1MB : IVT (first page), BDA (0xA0000 to 0xFFFFF) + * Find somewhere to put the stack and the code, still in lower 1MB + * Map that space, and copy the 16bit code to that place + * Setup values on the kernel stack for starting the thread (V86Thread::runV86), + * giving it entry point and stack location + */ + +V86Thread::V86Thread(v86_function_t* entry, v86_retval_t* ret, u32int data) : Thread() { + m_ret = ret; m_ret->finished = false; + m_xchgspace = 0; + m_isKernel = true; + m_if = true; + m_process = Task::currProcess(); + m_kernelStack.addr = Mem::alloc(STACKSIZE); + m_kernelStack.size = STACKSIZE; + + m_process->getPagedir()->switchTo(); + + m_process->getPagedir()->allocFrame(0, true, true); //Map IVT frame + for (u32int i = 0xA0000; i < 0xFFFFF; i += 0x1000) { //Map BDA frames + m_process->getPagedir()->allocFrame(i, true, true); + } + + u16int cs = alloc(entry->size); //Alocate segments for the code to run in + u8int* codeptr = (u8int*)(FP_TO_LINEAR(cs, 0)); + for (u32int i = ((u32int)(codeptr) & 0xFFFFF000); i < (u32int)(codeptr) + entry->size; i += 0x1000) { + m_process->getPagedir()->allocFrame(i, true, true); + } + memcpy(codeptr, entry->data, entry->size); //Copy the code there + + u16int ss = alloc(V86_STACKSIZE); + u8int* stackptr = (u8int*)(FP_TO_LINEAR(ss, 0)); + for (u32int i = ((u32int)stackptr & 0xFFFFF000); i < (u32int)stackptr + V86_STACKSIZE; i += 0x1000) { + m_process->getPagedir()->allocFrame(i, true, true); + } + + u32int* stack = (u32int*)((u32int)m_kernelStack.addr + m_kernelStack.size); + stack--; *stack = cs; //Pass code segment (ip = 0) + stack--; *stack = ss; //Pass stack segment (sp = V86_STACKSIZE) + stack--; *stack = data; //Pass data for thread + stack--; *stack = (u32int)this; //Pass thread pointer + stack--; *stack = 0; + m_esp = (u32int)stack; + m_ebp = m_esp + 8; + m_eip = (u32int)runV86; + + m_state = T_RUNNING; + m_process->registerThread(this); + Task::registerThread(this); +} + +bool V86Thread::handleV86GPF(registers_t *regs) { + u8int* ip = (u8int*)FP_TO_LINEAR(regs->cs, regs->eip); + u16int *ivt = 0; + u16int *stack = (u16int*)FP_TO_LINEAR(regs->ss, regs->useresp); + u32int *stack32 = (u32int*)stack; + bool is_operand32 = false, is_address32 = false; + + while (true) { + switch (ip[0]) { + case 0x66: // O32 + is_operand32 = true; + ip++; regs->eip = (u16int)(regs->eip + 1); + break; + case 0x67: // A32 + is_address32 = true; + ip++; regs->eip = (u16int)(regs->eip + 1); + break; + case 0x9C: // PUSHF + if (is_operand32) { + regs->esp = ((regs->esp & 0xFFFF) - 4) & 0xFFFF; + stack32--; + *stack32 = regs->eflags & VALID_FLAGS; + if (m_if) + *stack32 |= EFLAGS_IF; + else + *stack32 &= ~EFLAGS_IF; + } else { + regs->esp = ((regs->esp & 0xFFFF) - 2) & 0xFFFF; + stack--; + *stack = regs->eflags; + if (m_if) + *stack |= EFLAGS_IF; + else + *stack &= ~EFLAGS_IF; + } + regs->eip = (u16int)(regs->eip + 1); + return true; + case 0x9D: // POPF + if (is_operand32) { + regs->eflags = EFLAGS_IF | EFLAGS_VM | (stack32[0] & VALID_FLAGS); + m_if = (stack32[0] & EFLAGS_IF) != 0; + regs->esp = ((regs->esp & 0xFFFF) + 4) & 0xFFFF; + } else { + regs->eflags = EFLAGS_IF | EFLAGS_VM | stack[0]; + m_if = (stack[0] & EFLAGS_IF) != 0; + regs->esp = ((regs->esp & 0xFFFF) + 2) & 0xFFFF; + } + regs->eip = (u16int)(regs->eip + 1); + return true; + case 0xCD: // INT N + if (ip[1] == 3) return false; //Breakpoint exception, here used for telling that thread has ended + + stack -= 3; + regs->useresp = ((regs->useresp & 0xFFFF) - 6) & 0xFFFF; + + stack[0] = (u16int)(regs->eip + 2); + stack[1] = regs->cs; + stack[2] = (u16int)regs->eflags; + + regs->cs = ivt[ip[1] * 2 + 1]; + regs->eip = ivt[ip[1] * 2]; + return true; + case 0xCF: // IRET + regs->eip = stack[0]; + regs->cs = stack[1]; + regs->eflags = EFLAGS_IF | EFLAGS_VM | stack[2]; + m_if = (stack[2] & EFLAGS_IF) != 0; + regs->esp = (u16int)(regs->esp + 6); + return true; + case 0xFA: // CLI + m_if = false; + regs->eip = (u16int)(regs->eip + 1); + return true; + case 0xFB: // STI + m_if = true; + regs->eip = (u16int)(regs->eip + 1); + return true; + default: + return false; + } + } +} + +void V86Thread::handleException(registers_t *regs, int no) { + if (no == 13) { //General protection fault + if (!handleV86GPF(regs)) { + m_ret->finished = true; + m_ret->regs = *regs; + Task::currentThreadExits(0); + return; + } + } else { + Thread::handleException(regs, no); + } +} diff --git a/Source/Kernel/TaskManager/V86/V86Thread.class.h b/Source/Kernel/TaskManager/V86/V86Thread.class.h new file mode 100644 index 0000000..b14670b --- /dev/null +++ b/Source/Kernel/TaskManager/V86/V86Thread.class.h @@ -0,0 +1,59 @@ +#ifndef DEF_V86THREAD_CLASS_H +#define DEF_V86THREAD_CLASS_H + +#include + +typedef u32int FARPTR; +#define MK_FP(seg, off) ((FARPTR)(((u32int)(seg) << 16) | (u16int) (off))) +#define FP_SEG(fp) (((FARPTR)fp) >> 16) +#define FP_OFF(fp) (((FARPTR)fp) & 0xFFFF) +#define FP_TO_LINEAR(seg, off) ((void*)((((u16int)(seg)) << 4) + ((u16int)(off)))) +inline FARPTR LINEAR_TO_FP(void* ptr) { + u32int seg, off; + off = ((size_t) ptr) & 0xF; + seg = ((size_t) ptr - ((size_t) ptr & 0xF)) / 16; + return MK_FP(seg, off); +} + +struct v86_retval_t { + registers_t regs; + bool finished; +}; + +struct v86_function_t { + u16int size; + u8int data[]; +}; + +#define V86_STACKSIZE 1024 + +// (in segments) +#define V86_ALLOC_START 0x1000 +#define V86_ALLOC_END 0x9000 + +#define EFLAGS_IF 0x200 +#define EFLAGS_VM 0x20000 +#define VALID_FLAGS 0xDFF + +class V86Thread : public Thread { + private: + V86Thread(); + V86Thread(V86Thread&); + + v86_retval_t* m_ret; + + bool m_if; //V86 IF flag + + static u16int allocSeg; + static u16int alloc(u16int length); //Returns a segment number + + static void runV86(V86Thread* t, u32int data, u32int ss, u32int cs); + + public: + V86Thread(v86_function_t* entry, v86_retval_t* ret, u32int data); + + bool handleV86GPF(registers_t *regs); + void handleException(registers_t *regs, int no); +}; + +#endif diff --git a/Source/Kernel/TaskManager/V86/v86.wtf.asm b/Source/Kernel/TaskManager/V86/v86.wtf.asm new file mode 100644 index 0000000..15e3969 --- /dev/null +++ b/Source/Kernel/TaskManager/V86/v86.wtf.asm @@ -0,0 +1,11 @@ +[BITS 16] + +[GLOBAL v86test] +v86test: + dw v86test_end - v86test_start +v86test_start: + mov ax, 0013h + int 10h + int 3 +v86test_end: + db 0 diff --git a/Source/Library/Userland/Syscall/Syscall.wtf.cpp b/Source/Library/Userland/Syscall/Syscall.wtf.cpp index b8d9526..7334d6b 100644 --- a/Source/Library/Userland/Syscall/Syscall.wtf.cpp +++ b/Source/Library/Userland/Syscall/Syscall.wtf.cpp @@ -11,6 +11,10 @@ void threadFinishedSyscall(u32int v) { asm volatile("int $66" : : "a"(v)); } +void breakPoint() { + asm volatile("int $3"); +} + void putch(char c) { u32int x = c; syscall(0xFFFFFF01, x); diff --git a/Source/Library/Userland/Syscall/Syscall.wtf.h b/Source/Library/Userland/Syscall/Syscall.wtf.h index 5234579..7bbaefc 100644 --- a/Source/Library/Userland/Syscall/Syscall.wtf.h +++ b/Source/Library/Userland/Syscall/Syscall.wtf.h @@ -9,6 +9,7 @@ void sleep(u32int); void write_hex(u32int); void threadFinishedSyscall(u32int); +void breakPoint(); u32int syscall(u32int n, u32int a, u32int b = 0, u32int c = 0, u32int d = 0, u32int e = 0); -- cgit v1.2.3