[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 4/4] kernel2: VM86
+ SYSCALL_VM86_BIOS_INT fuehrt einen beliebigen BIOS-Interrupt aus
+ kernel2: Unterstuetzung fuer den VM86
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/include/syscallno.h | 3 +-
src/kernel2/include/arch/i386/cpu.h | 12 +
src/kernel2/include/syscall.h | 6 +
src/kernel2/include/vm86.h | 43 ++++
src/kernel2/src/arch/i386/mm/virt.c | 10 +-
src/kernel2/src/arch/i386/vm86.c | 406 +++++++++++++++++++++++++++++++++++
src/kernel2/src/init.c | 4 +
src/kernel2/src/interrupts/im.c | 30 +++-
src/kernel2/src/syscall.c | 3 +
src/kernel2/src/syscalls/vm86.c | 53 +++++
src/modules/include/syscall.h | 1 +
src/modules/lib/syscalls/vm86.c | 58 +++++-
12 files changed, 618 insertions(+), 11 deletions(-)
create mode 100644 src/kernel2/include/vm86.h
create mode 100644 src/kernel2/src/arch/i386/vm86.c
create mode 100644 src/kernel2/src/syscalls/vm86.c
diff --git a/src/include/syscallno.h b/src/include/syscallno.h
index b56ad45..fe2b693 100644
--- a/src/include/syscallno.h
+++ b/src/include/syscallno.h
@@ -54,6 +54,7 @@
#define SYSCALL_PM_SLEEP 6
#define SYSCALL_VM86 81
+#define SYSCALL_VM86_BIOS_INT 83
#define SYSCALL_PM_P 11
#define SYSCALL_PM_V 12
@@ -83,6 +84,6 @@
#define SYSCALL_DEBUG_STACKTRACE 80
//ACHTUNG: Muss eine Zahl groesser als die Groesste Syscall-Nummer sein
-#define SYSCALL_MAX 83
+#define SYSCALL_MAX 84
#endif
diff --git a/src/kernel2/include/arch/i386/cpu.h b/src/kernel2/include/arch/i386/cpu.h
index 772546e..d215cbd 100644
--- a/src/kernel2/include/arch/i386/cpu.h
+++ b/src/kernel2/include/arch/i386/cpu.h
@@ -36,6 +36,7 @@
#define _CPU_H_
#include <types.h>
+#include <stdint.h>
#include "tasks.h"
@@ -65,6 +66,17 @@ typedef struct {
dword ss;
} __attribute__((packed)) interrupt_stack_frame_t;
+/** Der erweiterte Interruptstackframe fuer VM86-Tasks */
+struct vm86_isf {
+ interrupt_stack_frame_t isf;
+
+ uint32_t es;
+ uint32_t ds;
+ uint32_t fs;
+ uint32_t gs;
+} __attribute__((packed));
+
+
#define CPU_IO_BITMAP_LENGTH 0xffff
diff --git a/src/kernel2/include/syscall.h b/src/kernel2/include/syscall.h
index ea182c4..39a6bfa 100644
--- a/src/kernel2/include/syscall.h
+++ b/src/kernel2/include/syscall.h
@@ -166,5 +166,11 @@ void syscall_add_interrupt_handler(uint32_t intr);
/// Textausgabe ueber den Kernel
void syscall_putsn(int char_count, char* source);
+/// -ENOSYS
+int syscall_vm86_old(void* regs, uint32_t* memory);
+
+/// BIOS-Interrupt ausfuehren
+int syscall_vm86(uint8_t intr, void* regs, uint32_t* memory);
+
#endif //ifndef _SYSCALL_H_
diff --git a/src/kernel2/include/vm86.h b/src/kernel2/include/vm86.h
new file mode 100644
index 0000000..978f762
--- /dev/null
+++ b/src/kernel2/include/vm86.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the tyndur Project
+ * and its contributors.
+ * 4. Neither the name of the tyndur Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VM86_H_
+#define _VM86_H_
+
+void vm86_init(void);
+int arch_vm86(uint8_t intr, void* regs, uint32_t* memory);
+
+#endif
+
diff --git a/src/kernel2/src/arch/i386/mm/virt.c b/src/kernel2/src/arch/i386/mm/virt.c
index ecb889b..ad4095b 100644
--- a/src/kernel2/src/arch/i386/mm/virt.c
+++ b/src/kernel2/src/arch/i386/mm/virt.c
@@ -58,8 +58,14 @@ void vmm_init(mmc_context_t* kernel_context)
NUM_PAGES((uintptr_t) kernel_end - (uintptr_t) kernel_start));
// Videospeicher mappen
- mmc_map(kernel_context, (paddr_t) 0xB8000, (vaddr_t) 0xB8000, PTE_W | PTE_P,
- NUM_PAGES(25*80*2));
+ // TODO Usermodus muss die momentan wegen VM86 sehen. Waere wohl besser,
+ // wenn VM86 einen eigenen Adressraum haette.
+ mmc_map(kernel_context, (vaddr_t) 0xB8000, (paddr_t) 0xB8000,
+ PTE_U | PTE_W | PTE_P, 0x10);
+
+ // BIOS mappen
+ mmc_map(kernel_context, (vaddr_t) 0xC0000, (paddr_t) 0xC0000,
+ PTE_U | PTE_P, 0x40);
//mmc_map(kernel_context, kernel_context->page_directory, kernel_context->page_directory, PTE_P | PTE_W, 1);
diff --git a/src/kernel2/src/arch/i386/vm86.c b/src/kernel2/src/arch/i386/vm86.c
new file mode 100644
index 0000000..5d02f2b
--- /dev/null
+++ b/src/kernel2/src/arch/i386/vm86.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2010 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the tyndur Project
+ * and its contributors.
+ * 4. Neither the name of the tyndur Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <syscall_structs.h>
+#include <errno.h>
+
+#include "kernel.h"
+#include "kprintf.h"
+#include "tasks.h"
+#include "cpu.h"
+#include "vm86.h"
+#include "mm.h"
+
+/*
+ * Grundsaetzliche Funktionsweise von VM86 in tyndur:
+ *
+ * Die VM86-Funktionalitaet wird ausschliesslich ueber den Syscall
+ * SYSCALL_VM86_BIOS_INT bereitgestellt. Beim Aufruf dieses Syscalls wird der
+ * aufrufende Thread blockiert und zu einem neu erstellten VM86-Thread
+ * desselben Prozesses gewechselt. Dieser Thread laeuft bis der BIOS-Interrupt
+ * ueber iret zurueckkehrt, dann wird der VM86-Thread beendet und der
+ * urspruengliche Thread fortgesetzt.
+ *
+ * Einsprung in den VM86:
+ *
+ * Um in den VM86-Modus zu wechseln wird derselbe Mechanismus wie beim
+ * normalen Multitasking verwendet (d.h. Softwaremultitasking). Beim
+ * Sprung in den Task muss das VM-Flag in eflags gesetzt sein (0x20000),
+ * damit der Prozessor in den VM86 wechselt. Zusaetzlich zu den normal
+ * gesicherten Registern (esp, eflags, cs, eip) werden bei VM86-Tasks auch
+ * die (Real-Mode-)Segmentregister auf den Stack gesichert und beim iret
+ * wiederhergestellt.
+ *
+ * Behandlung privilegierter Instruktionen:
+ *
+ * Wenn der VM86-Task auf privilegierte Instruktionen stoesst, wird ein
+ * #GP ausgeloest. vm86_exception() faengt diese Exception vor den
+ * normalen Exceptionhandlern ab und emuliert den aktuellen privilegierten
+ * Befehl wenn moeglich.
+ *
+ * Bei der Emulation von iret ist zu beachten, dass der VM86-Task beendet
+ * werden muss, wenn sich der Stack wieder auf dem Anfangswert befindet;
+ * der aufgerufene Interrupthandler ist dann fertig.
+ */
+
+/** Enthaelt eine Kopie der urspruenglichen ersten 4k im physischen Speicher */
+static struct {
+ uint16_t ivt[256][2];
+ uint8_t data[3072];
+} bios_data __attribute__ ((aligned (4096)));
+
+// FIXME Das darf eigentich nicht global sein
+static struct {
+ bool in_use;
+ void* stack;
+ void* nullpage;
+ uint32_t* memory;
+ pm_thread_t* caller;
+ vm86_regs_t* regs;
+} vm86_status = {
+ .in_use = FALSE,
+};
+
+/**
+ * Speichert BIOS-Daten, um sie den VM86-Tasks später bereitstellen zu können
+ */
+void vm86_init(void)
+{
+ memcpy(&bios_data, 0, 4096);
+}
+
+/**
+ * Erstellt einen VM86-Thread im aktuellen Prozess. Der aktuell ausgefuehrte
+ * Thread wird pausiert und ein Taskwechsel zum neuen VM86-Task wird
+ * durchgefuehrt.
+ *
+ * @oaram int Aufzurufender BIOS-Interrupt
+ * @param regs Anfaengliche Registerbelegung
+ * @param stack Virtuelle Adresse der fuer den Stack des VM86-Tasks benutzten
+ * Seite
+ */
+static int create_vm86_task(int intr, vm86_regs_t* regs, uintptr_t stack)
+{
+ uint16_t* ivt_entry = bios_data.ivt[intr];
+
+ // Erst einmal einen ganz normalen Thread erzeugen
+ pm_thread_t* task = pm_thread_create(current_process,
+ (vaddr_t)(uintptr_t) ivt_entry[0]);
+
+ interrupt_stack_frame_t* isf = task->kernel_stack;
+
+ struct vm86_isf visf;
+
+
+ // Register setzen
+ isf->eflags = 0x20202;
+ isf->cs = ivt_entry[1];
+ isf->ss = stack / 16;
+
+ isf->eax = regs->ax;
+ isf->ebx = regs->bx;
+ isf->ecx = regs->cx;
+ isf->edx = regs->dx;
+ isf->esi = regs->si;
+ isf->edi = regs->di;
+ isf->esp = PAGE_SIZE - 16;
+ isf->ebp = 0;
+
+ // Segmentregister setzen
+ // Dabei wird der bisherige Kernelstack in die temporaere
+ // visf-Datenstruktur kopiert, denn er muss verschoben werden, damit die
+ // VM86-Segmentregister noch Platz auf dem Stack haben
+ visf.isf = *isf;
+ visf.ds = regs->ds;
+ visf.es = regs->es;
+
+ // Und das ganze auf den Stack
+ task->kernel_stack = ((uint8_t*) task->kernel_stack)
+ + sizeof(*isf) - sizeof(visf);
+ memcpy(task->kernel_stack, &visf, sizeof(visf));
+
+ // Sofort in den VM86-Task wechseln. Der aufrufende Thread wird
+ // waehrenddessen nicht in den Scheduler zurueckgegeben und gestoppt.
+ current_thread->status = PM_STATUS_BLOCKED;
+ current_thread = task;
+
+ return 0;
+}
+
+/**
+ * Implementiert den Syscall SYSCALL_VM86_BIOS_INT.
+ *
+ * @param intr BIOS-Interrupt, der aufgerufen werden soll
+ * @param regs Pointer auf die Struktur, die die anfaenglichen Registerwerte
+ * enthaelt und in die beim Ende des VM86-Tasks die dann aktuellen
+ * Registerwerte kopiert werden sollen.
+ * @param memory Array von Speicherbereichen, die in den VM86-Task gemappt
+ * werden sollen; NULL fuer keine.
+ *
+ * @return 0 bei Erfolg, -errno im Fehlerfall
+ */
+int arch_vm86(uint8_t intr, void* regs, uint32_t* memory)
+{
+ int res = 0;
+
+ // Wir koennen nur einen VM86-Task
+ if (vm86_status.in_use) {
+ return -EBUSY;
+ }
+
+ // Nullpage mappen
+ uint32_t* page_table = (uint32_t*) PAGETABLES_MEM_START;
+ void* nullpage = pmm_alloc(1);
+ page_table[0] = (uintptr_t) nullpage | PTE_U | PTE_W | PTE_P;
+ asm volatile("invlpg %0" :: "m" (*(char*)0x0));
+ memcpy(0, &bios_data, 4096);
+
+ // Stack mappen
+ void* stack = mmc_valloc_limits(&mmc_current_context(), 1, NULL, NULL,
+ 0x0, 0x9fc00, PTE_U | PTE_W | PTE_P);
+ if (stack == NULL) {
+ kprintf("vm86: Kein Platz fuer den Stack\n");
+ res = -ENOMEM;
+ goto fail_stack;
+ }
+
+ // Videospeicher mappen
+ // FIXME Das tut nur durch Zufall
+ bool ret = mmc_map(&mmc_current_context(),
+ (vaddr_t) 0xa0000, (paddr_t) 0xa0000,
+ PTE_U | PTE_W | PTE_P, 0x10);
+ if (!ret) {
+ kprintf("vm86: Kein Platz fuer den Videospeicher\n");
+ res = -ENOMEM;
+ goto fail_video;
+ }
+
+ // Falls noetig, ein paar Pages mehr mappen
+ if (memory != NULL) {
+ uint32_t infosize = memory[0];
+ uint32_t i;
+
+ for (i = 0; i < infosize; i++) {
+ uint32_t addr = memory[1 + i * 3];
+ uint32_t src = memory[1 + i * 3 + 1];
+ uint32_t size = memory[1 + i * 3 + 2];
+
+ if (size > PAGE_SIZE) {
+ res = -EINVAL;
+ goto fail_memory;
+ }
+
+ paddr_t phys_mem = pmm_alloc(1);
+ if (!mmc_map(&mmc_current_context(), (vaddr_t)(addr & ~0xFFF),
+ phys_mem, PTE_W | PTE_P | PTE_U, 1))
+ {
+ res = -ENOMEM;
+ goto fail_memory;
+ }
+ memcpy((void*)addr, (void*)src, size);
+ }
+ }
+
+ // Informationen speichern
+ // TODO Ordentliches Locking fuer SMP
+ vm86_status.in_use = 1;
+ vm86_status.caller = current_thread;
+ vm86_status.stack = stack;
+ vm86_status.nullpage = nullpage;
+ vm86_status.memory = memory;
+ vm86_status.regs = regs;
+
+ // Innerhalb vom VM86 einen RPC-Handler aufzurufen waere unklug
+ pm_block_rpc(current_process, current_process->pid);
+
+ // Task erstellen
+ create_vm86_task(intr, regs, (uintptr_t) stack);
+
+ return 0;
+
+fail_memory:
+ mmc_unmap(&mmc_current_context(), (vaddr_t) 0xa0000, 0x10);
+fail_video:
+ mmc_vfree(&mmc_current_context(), stack, 1);
+fail_stack:
+ pmm_free(nullpage, 1);
+ return res;
+}
+
+/**
+ * Beendet einen VM86-Task, kopiert alle zu zurueckzugebenden Daten und setzt
+ * die Ausfuehrung des aufrufenden Tasks fort.
+ */
+static void destroy_vm86_task(interrupt_stack_frame_t* isf)
+{
+ pm_thread_t* vm86_task = current_thread;
+ struct vm86_isf* visf = (struct vm86_isf*)
+ (((char*) isf) + (sizeof(*isf) - sizeof(*visf)));
+
+ // Den Thread loeschen und den Aufrufer wieder aktiv machen
+ vm86_task->status = PM_STATUS_BLOCKED;
+ pm_thread_destroy(vm86_task);
+
+ current_thread = vm86_status.caller;
+ current_thread->status = PM_STATUS_RUNNING;
+
+ // Temporaere Mappings rueckgaengig machen
+ mmc_unmap(&mmc_current_context(), (vaddr_t) 0xa0000, 0x10);
+ mmc_unmap(&mmc_current_context(), vm86_status.stack, 1);
+
+ uint32_t* page_table = (uint32_t*) PAGETABLES_MEM_START;
+ page_table[0] = 0;
+ asm volatile("invlpg %0" :: "m" (*(char*)0x0));
+
+ pmm_free(vm86_status.nullpage, 1);
+
+ // Vom Benutzer angeforderte Mappings rueckgaengig machen
+ if (vm86_status.memory != NULL) {
+ uint32_t infosize = vm86_status.memory[0];
+ uint32_t i;
+
+ for (i = 0; i < infosize; i++) {
+ uint32_t addr = vm86_status.memory[1 + i * 3];
+ uint32_t src = vm86_status.memory[1 + i * 3 + 1];
+ uint32_t size = vm86_status.memory[1 + i * 3 + 2];
+
+ memcpy((void*)src, (void*)addr, size);
+ pmm_free(mmc_resolve(&mmc_current_context(),
+ (vaddr_t) (addr & ~0xFFF)), 1);
+ mmc_unmap(&mmc_current_context(), (vaddr_t)(addr & ~0xFFF), 1);
+ }
+ }
+
+ // Register sichern
+ vm86_regs_t* regs = vm86_status.regs;
+ regs->ax = isf->eax;
+ regs->bx = isf->ebx;
+ regs->cx = isf->ecx;
+ regs->dx = isf->edx;
+ regs->si = isf->esi;
+ regs->di = isf->edi;
+ regs->ds = visf->ds;
+ regs->es = visf->es;
+
+ // Wir sind fertig mit VM86 :-)
+ pm_unblock_rpc(current_process, current_process->pid);
+ vm86_status.in_use = 0;
+}
+
+/** Pusht einen Wert auf den Stack des VM86-Tasks */
+static inline void emulator_push(interrupt_stack_frame_t* isf, uint16_t value)
+{
+ isf->esp -= 2;
+ ((uint16_t*)(isf->esp + (isf->ss << 4)))[0] = value;
+}
+
+/** Popt einen Wert vom Stack des VM86-Tasks */
+static inline uint16_t emulator_pop(interrupt_stack_frame_t* isf)
+{
+ uint16_t res = ((uint16_t*)(isf->esp + (isf->ss << 4)))[0];
+ isf->esp += 2;
+ return res;
+}
+
+/**
+ * Diese Funktion wird vom Interrupthandler bei Exceptions aufgerufen, wenn der
+ * aktuelle Task ein VM86-Task ist. Die Exception kann dann entweder hier
+ * behandelt werden oder an die allgemeinen Exceptionhandlern weitergegeben
+ * werden
+ *
+ * @return 1 wenn die Exception fertig behandelt ist; 0, wenn die normalen
+ * Exceptionhandler aufgerufen werden sollen.
+ */
+int vm86_exception(interrupt_stack_frame_t* isf)
+{
+ // Bei #GP muessen wir was emulieren, ansonsten koennen wir fuer den Task
+ // hier nichts tun
+ if (isf->interrupt_number != 13) {
+ return 0;
+ }
+
+ // Ein toller Emulator fuer privilegierte Instruktionen
+ uint8_t* ops = (uint8_t*)(isf->eip + (isf->cs << 4));
+ switch (ops[0]) {
+
+ case 0x9c: /* pushf */
+ emulator_push(isf, isf->eflags);
+ isf->eip++;
+ break;
+
+ case 0x9d: /* popf */
+ // So tun, als würden wir die EFLAGS wiederherstellen.
+ // Das hier ist wohl alles andere als korrekt, aber funzt erstmal.
+ emulator_pop(isf);
+ isf->eip++;
+ break;
+
+ case 0xcd: /* int */
+ {
+ uint16_t intr = ops[1] & 0xff;
+ uint16_t* ivt_entry = bios_data.ivt[intr];
+
+ emulator_push(isf, isf->eip + 2);
+ emulator_push(isf, isf->cs);
+ emulator_push(isf, isf->eflags);
+
+ isf->eip = ivt_entry[0];
+ isf->cs = ivt_entry[1];
+ break;
+ }
+
+ case 0xcf: /* iret */
+
+ // Wenn es das finale iret ist, koennen wir den VM86-Task beenden
+ if (isf->esp == PAGE_SIZE - 16) {
+ destroy_vm86_task(isf);
+ return 1;
+ }
+
+ // Ansonsten muss es ganz normal emuliert werden
+ emulator_pop(isf);
+ isf->cs = emulator_pop(isf);
+ isf->eip = emulator_pop(isf);
+ break;
+
+ default:
+ kprintf("vm86: Unbekannter Opcode %x\n", ops[0]);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/src/kernel2/src/init.c b/src/kernel2/src/init.c
index 6b9b202..1413b88 100644
--- a/src/kernel2/src/init.c
+++ b/src/kernel2/src/init.c
@@ -63,6 +63,7 @@ lock_t init_lock = 0;
void smp_init(void);
void gdt_init(void);
+void vm86_init(void);
/**
* Kernel-Initialisierung erfolgt hier,
@@ -97,6 +98,9 @@ void init(int multiboot_magic, struct multiboot_info *boot_info, bool bsp)
debug_parse_cmdline(multiboot_info.mi_cmdline);
}
#endif
+
+ // IVT fuer den VM86 sichern
+ vm86_init();
debug_print(DEBUG_FLAG_INIT, "Initialisiere physikalische"
"Speicherverwaltung");
diff --git a/src/kernel2/src/interrupts/im.c b/src/kernel2/src/interrupts/im.c
index d7130bd..91f818d 100644
--- a/src/kernel2/src/interrupts/im.c
+++ b/src/kernel2/src/interrupts/im.c
@@ -59,6 +59,7 @@ bool fastrpc_irq(pm_process_t* callee, size_t metadata_size, void* metadata,
size_t data_size, void* data, uint8_t irq);
extern void increase_user_stack_size(pm_thread_t* task_ptr, int pages);
+extern int vm86_exception(interrupt_stack_frame_t* isf);
/**
* Verarbeitet eine CPU-Exception
@@ -71,6 +72,14 @@ static void handle_exception(interrupt_stack_frame_t* isf, uint8_t int_num)
// kprintf("user_stack_bottom = %x\n",
// current_thread->user_stack_bottom);
+ // Pruefen, ob ein VM86-Task die Exception ausgeloest hat
+ // Falls ja lassen wir sie vom VM86-Code behandeln, wenn er kann
+ if (isf->eflags & 0x20000) {
+ if (vm86_exception(isf)) {
+ return;
+ }
+ }
+
if (int_num == 0x0e) {
// Ueberprüfen ob der Pagefault durch einen Stackoverflow
// hervorgerufen wurde. Falls ja: Stack vergroessern und weitermachen
@@ -97,7 +106,11 @@ static void handle_exception(interrupt_stack_frame_t* isf, uint8_t int_num)
// Ein Stacktrace duerfen wir nur ausgeben, wenn kein Pagefault wegen
// dem Stack aufgetreten ist!
if (!((cr2 < isf->esp + 800) && (cr2 >= isf->esp -0x20))) {
- stack_backtrace(isf->ebp, isf->eip);
+ // Und fuer VM86 muessten wir wenigstens noch das Segment
+ // beruecksichtigen, aber eigentlich brauchen wir ihn da gar nicht
+ if ((isf->eflags & 0x20000) == 0) {
+ stack_backtrace(isf->ebp, isf->eip);
+ }
}
// Hier werden alle Prozessoren zum halten gebracht
@@ -166,10 +179,19 @@ interrupt_stack_frame_t* im_handler(interrupt_stack_frame_t* isf)
thread = current_thread;
if (thread != old_thread) {
+ interrupt_stack_frame_t* new_isf =
+ (interrupt_stack_frame_t*) thread->kernel_stack;
+
cpu_get_current()->tss.ss0 = 2 << 3;
- cpu_get_current()->tss.esp0 =
- (uintptr_t) thread->kernel_stack
- + sizeof(interrupt_stack_frame_t);
+ if (new_isf->eflags & 0x20000) {
+ cpu_get_current()->tss.esp0 =
+ (uintptr_t) thread->kernel_stack
+ + sizeof(struct vm86_isf);
+ } else {
+ cpu_get_current()->tss.esp0 =
+ (uintptr_t) thread->kernel_stack
+ + sizeof(interrupt_stack_frame_t);
+ }
mmc_activate(&thread->process->context);
}
diff --git a/src/kernel2/src/syscall.c b/src/kernel2/src/syscall.c
index 4292724..073fe9b 100644
--- a/src/kernel2/src/syscall.c
+++ b/src/kernel2/src/syscall.c
@@ -93,6 +93,9 @@ void syscall_init()
syscall_register(SYSCALL_SHM_CREATE, &syscall_shm_create, 1);
syscall_register(SYSCALL_SHM_ATTACH, &syscall_shm_attach, 1);
syscall_register(SYSCALL_SHM_DETACH, &syscall_shm_detach, 1);
+
+ syscall_register(SYSCALL_VM86, &syscall_vm86_old, 2);
+ syscall_register(SYSCALL_VM86_BIOS_INT, &syscall_vm86, 3);
}
/**
diff --git a/src/kernel2/src/syscalls/vm86.c b/src/kernel2/src/syscalls/vm86.c
new file mode 100644
index 0000000..b105eca
--- /dev/null
+++ b/src/kernel2/src/syscalls/vm86.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2010 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the tyndur Project
+ * and its contributors.
+ * 4. Neither the name of the tyndur Project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include "kernel.h"
+#include "syscall.h"
+#include "vm86.h"
+
+/// -ENOSYS
+int syscall_vm86_old(void* regs, uint32_t* memory)
+{
+ return -ENOSYS;
+}
+
+/// BIOS-Interrupt ausfuehren
+int syscall_vm86(uint8_t intr, void* regs, uint32_t* memory)
+{
+ return arch_vm86(intr, regs, memory);
+}
diff --git a/src/modules/include/syscall.h b/src/modules/include/syscall.h
index 3759d4b..d86a232 100644
--- a/src/modules/include/syscall.h
+++ b/src/modules/include/syscall.h
@@ -91,6 +91,7 @@ void unblock_process(pid_t pid);
char* get_cmdline(void);
bool vm86_int(vm86_regs_t *regs, dword *shm);
+int bios_int(int intr, vm86_regs_t* regs, uint32_t* shm);
task_info_t* enumerate_tasks(void);
diff --git a/src/modules/lib/syscalls/vm86.c b/src/modules/lib/syscalls/vm86.c
index 570558b..39a6666 100644
--- a/src/modules/lib/syscalls/vm86.c
+++ b/src/modules/lib/syscalls/vm86.c
@@ -1,16 +1,66 @@
+/*
+ * Copyright (c) 2007-2010 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Mathias Gottschlag.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
-#include "syscall.h"
+#include <syscall.h>
+#include <errno.h>
+
+int bios_int(int intr, vm86_regs_t* regs, uint32_t* shm)
+{
+ int result;
+
+ asm(
+ "pushl %4;"
+ "pushl %3;"
+ "pushl %2;"
+ "mov %1, %%eax;"
+ "int $0x30;"
+ "add $0xc, %%esp;"
+ : "=a"(result)
+ : "i" (SYSCALL_VM86_BIOS_INT), "r" (intr), "r"(regs), "r"(shm));
+
+ return result;
+}
bool vm86_int(vm86_regs_t *regs, dword *shm)
{
- dword result;
+ int result;
+
asm(
"pushl %3;"
"pushl %2;"
"mov %1, %%eax;"
"int $0x30;"
"add $0x8, %%esp;"
- : "=a"(result): "i" (SYSCALL_VM86), "r"(regs), "r"(shm) );
+ : "=a"(result): "i" (SYSCALL_VM86), "r"(regs), "r"(shm));
+
+ if (result == -ENOSYS) {
+ return bios_int(0x10, regs, shm);
+ }
+
return (bool)result;
}
-
--
1.6.0.2