summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis211 <alexis211@gmail.com>2009-11-08 16:51:30 +0100
committerAlexis211 <alexis211@gmail.com>2009-11-08 16:51:30 +0100
commitc712d7f6f801b073920c7b914ee1b95358113893 (patch)
treeb065a2344ddfa66a1e623347b2a8373cc07d02db
parentec6a6922d074da4b64976282333e308deb39aeec (diff)
downloadMelon-c712d7f6f801b073920c7b914ee1b95358113893.tar.gz
Melon-c712d7f6f801b073920c7b914ee1b95358113893.zip
Introduced V86 mode. It really fits in nicely :)
-rw-r--r--Source/Applications/Shell/Shell.ns.cpp3
-rw-r--r--Source/Kernel/Core/Sys.ns.cpp21
-rw-r--r--Source/Kernel/Core/Sys.ns.h2
-rw-r--r--Source/Kernel/Core/kmain.wtf.cpp15
-rw-r--r--Source/Kernel/Makefile2
-rw-r--r--Source/Kernel/MemoryManager/GDT.ns.cpp1
-rw-r--r--Source/Kernel/MemoryManager/GDT.ns.h1
-rw-r--r--Source/Kernel/MemoryManager/PageDirectory.class.cpp18
-rw-r--r--Source/Kernel/MemoryManager/PhysMem.ns.cpp1
-rw-r--r--Source/Kernel/SyscallManager/IDT.ns.cpp2
-rw-r--r--Source/Kernel/TaskManager/Thread.class.cpp32
-rw-r--r--Source/Kernel/TaskManager/Thread.class.h7
-rw-r--r--Source/Kernel/TaskManager/V86/V86Thread.class.cpp200
-rw-r--r--Source/Kernel/TaskManager/V86/V86Thread.class.h59
-rw-r--r--Source/Kernel/TaskManager/V86/v86.wtf.asm11
-rw-r--r--Source/Library/Userland/Syscall/Syscall.wtf.cpp4
-rw-r--r--Source/Library/Userland/Syscall/Syscall.wtf.h1
17 files changed, 353 insertions, 27 deletions
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<String> 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 <Ressources/Graphics/logo.text.cxd>
+#include <TaskManager/V86/V86Thread.class.h>
+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.", &regs);
- Task::currThread()->handleException(regs, regs.int_no);
+ Task::currThread()->handleException(&regs, 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", &regs);
+ 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 <TaskManager/Task.ns.h>
+
+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 <TaskManager/Thread.class.h>
+
+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);