[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Lost] [Patch 1/3] kernel2: RPC
+ kernel2: mmc_automap_user() mappt virtuell zusammenhängenden Speicher aus
einem anderen Kontext (z.B. den Stack eines Tasks, der per RPC aufgerufen
werden soll)
+ kernel2: syscall_fastrpc
+ kernel2: syscall_fastrpc_ret
Dieser Patch ist irgendwas zwischen ziemlich und extrem kaputt. Ich würde es
trotzdem vorziehen, ihn erstmal so einzuchecken und die Details später zu
fixen.
Index: trunk/src/kernel2/include/tasks.h
===================================================================
--- trunk.orig/src/kernel2/include/tasks.h
+++ trunk/src/kernel2/include/tasks.h
@@ -45,6 +45,7 @@
#define PM_STATUS_READY 0
#define PM_STATUS_BLOCKED 1
#define PM_STATUS_RUNNING 2
+#define PM_STATUS_WAIT_FOR_RPC 3
typedef struct pm_process {
/// Die eindeutige Prozessnummer
@@ -79,6 +80,9 @@ typedef struct pm_process {
/// Die Anzahl von p()s (RPC wird erst bei 0 wieder freigegeben)
dword blocked_count;
+
+ /// Eine Liste von RPC-Backlinks
+ list_t* rpcs;
} pm_process_t;
Index: trunk/src/kernel2/src/syscalls/rpc.c
===================================================================
--- trunk.orig/src/kernel2/src/syscalls/rpc.c
+++ trunk/src/kernel2/src/syscalls/rpc.c
@@ -2,7 +2,7 @@
* Copyright (c) 2007 The LOST Project. All rights reserved.
*
* This code is derived from software contributed to the LOST Project
- * by Antoine Kaufmann.
+ * by Kevin Wolf.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,11 +35,26 @@
#include <types.h>
#include <stdint.h>
+#include <stdlib.h>
+#include "kernel.h"
#include "syscall.h"
#include "tasks.h"
#include "cpu.h"
+typedef struct {
+ uintptr_t old_eip;
+ uintptr_t old_esp;
+
+ // FIXME Das tut nur fuer i386...
+ dword eflags;
+ dword eax;
+
+ dword reenable_irq;
+
+ pm_thread_t* caller;
+} rpc_t;
+
/**
* RPC-Handler registrieren. Dieser wird bei jedem RPC aufgerufen und verteilt
* die RPCs Prozessintern weiter.
@@ -48,6 +63,339 @@
*/
void syscall_set_rpc_handler(vaddr_t address)
{
- cpu_get_current()->thread->process->rpc_handler = address;
+ cpu_get_current()->thread->process->rpc_handler = address;
+}
+
+
+#if CONFIG_ARCH == ARCH_I386
+void increase_user_stack_size(pm_thread_t* task_ptr, int pages);
+
+static void adjust_stack_size(pm_thread_t* callee,
+ interrupt_stack_frame_t* callee_isf, size_t rounded_data_size)
+{
+ // Falls der Stack nicht ausreicht, vergrö�ern
+ size_t pages_count = ((rounded_data_size + PAGE_SIZE - 1) / PAGE_SIZE);
+ if ((rounded_data_size % PAGE_SIZE) > (callee_isf->esp % PAGE_SIZE)) {
+ pages_count++;
+ }
+
+ if(mmc_resolve(&callee->process->context,
+ (vaddr_t) callee_isf->esp - rounded_data_size) == NULL)
+ {
+ // TODO Das könnte bis zu (pages_count - 1) Pages zu viel reservieren
+ increase_user_stack_size(callee, pages_count);
+ }
+}
+
+/**
+ * Führt einen RPC durch.
+ *
+ * Der Aufruf einer RPC-Funktion besteht im allgemeinen aus Metadaten (z.B.
+ * die Funktionsnummer der aufzurufenden Funktion, Nachrichten-ID usw.)
+ * und Nutzdaten.
+ *
+ * Die Daten werden dem aufgerufenen Task so auf den Stack gelegt, daÃ? von
+ * esp bis esp + metadata_size die Metadaten liegen, von esp + metadata_size
+ * bis esp + metadata_size + data_size die Nutzdaten. Daraus ergibt sich
+ * insbesondere, daÃ? sich die Grenze zwischen Metadaten und Daten beliebig
+ * ziehen lä�t, wie sie für den Aufrufer am günstigsten ist. Unter anderem
+ * ist es möglich, alle Daten an einem Ort zu übergeben und metadata_size = 0
+ * zu setzen.
+ *
+ * Im Allgemeinen liegen allerdings die Metadaten auf dem Stack des Aufrufers,
+ * während die Nutzdaten oft ein Pointer in den Heap des Aufrufers sind.
+ *
+ * Zur Durchführung eines RPC werden zunächst einige Register des
+ * aufgerufenen Tasks gesichtert (eax, eip, esp, eflags; die übrigen Register
+ * hat der aufgerufene Task selbst zu sichern). AnschlieÃ?end werden die Daten
+ * auf den Stack des aufgerufenen Tasks gelegt, eip auf den RPc-Handler gesetzt
+ * und der Scheduler angewiesen, zum aufgerufenen Task umzuschalten.
+ *
+ * Der RPC-Handler muÃ? als letzte Aktion den Syscall FASTRPC_RET aufrufen, der
+ * die Register wiederherstellt und dadurch den Rücksprung vornimmt.
+ *
+ * TODO Aktualisieren
+ * @param callee Aufzurufender Task
+ * @param metadata_size Länge der Metadaten in Bytes
+ * @param metadata Pointer auf die Metadaten
+ * @param data_size Länger der Daten in Bytes
+ * @param data Pointer auf die Daten
+ *
+ * @return TRUE, wenn der Aufruf erfolgreich durchgeführt wurde, FALSE
+ * sonst. Bei FALSE als Rückgabe sollte der aufrufende Task den RPC-Syscall
+ * wiederholen.
+ */
+#include "kprintf.h"
+int syscall_fastrpc(pid_t callee_pid, size_t metadata_size, void* metadata,
+ size_t data_size, void* data)
+{
+ pm_thread_t* callee =
+ list_get_element_at(pm_get(callee_pid)->threads, 0);
+
+ if (!callee) {
+ // FIXME
+ // abort_task("RPC zu nicht vorhandenem Prozess");
+ return -1;
+ }
+
+ if (metadata_size + data_size > 8 * PAGE_SIZE) {
+ // FIXME
+ // abort_task("RPC-Datenblock zu gross: %d Bytes", data_size);
+ return -1;
+ }
+
+ if (callee->process->rpc_handler == NULL) {
+ return -1;
+ }
+
+/*
+ if (callee == cpu_get_current()->thread) {
+ kprintf("PID %d: Self-RPC ignoriert\n", callee->process->pid);
+ return 0;
+ }
+*/
+
+ // TODO Pointer validieren (is_userspace)
+
+ // Gesamtgrö�e, um die der Stack des aufgerufenen Prozesses vergrö�ert
+ // wird (zusätzlich 4 Bytes für die Rücksprungadresse)
+ size_t total_data_size = metadata_size + data_size
+ + sizeof(data_size) + sizeof(pid_t);
+
+ // Datengrö�e auf ganze vier Bytes aufrunden
+ size_t rounded_data_size = (total_data_size + 3) & ~0x3;
+
+ // Wenn es sich um eine Antwort im Rahmen von asynchronem RPC handelt,
+ // durchlassen, auch wenn der Prozess nicht blockiert werden kann
+ bool ignore_blocked = FALSE;
+ if ((callee->status == PM_STATUS_WAIT_FOR_RPC) && (
+ ((metadata_size >= 4)
+ && (((dword*)metadata)[0] == 513))
+
+ || ((metadata_size == 0)
+ && (data_size >= 4)
+ && (((dword*)data)[0] == 513))
+ ))
+ {
+ ignore_blocked = TRUE;
+ }
+
+ // Waehrend wir am Stack rumbasteln, sollte niemand dazwischenfunken und
+ // erst recht nicht der Task weiterlaufen (momentan unnötig, da im Kernel
+ // keine Interrupts erlaubt sind). AuÃ?erdem wird damit sichergestellt,
+ // dass ein Task, der p() aufgerufen hat, keinen RPC bekommt.
+ //
+ // Wenn der Task nicht blockiert werden kann, soll der Aufrufer es später
+ // nochmal versuchen.
+ if (!ignore_blocked &&
+ ((callee->process->blocked_by_pid) ||
+ !pm_block_rpc(callee->process, syscall_pm_get_pid())))
+ {
+ return -1;
+ }
+
+ // Interrupt Stack Frame des aufgerufenen Tasks mappen
+ paddr_t callee_isf_phys =
+ mmc_resolve(&callee->process->context, callee->kernel_stack);
+
+ interrupt_stack_frame_t* callee_isf = (interrupt_stack_frame_t*)
+ vmm_kernel_automap(callee_isf_phys, sizeof(*callee_isf));
+
+
+ // RPC-Backlinkinformation anlegen
+ rpc_t* rpc = malloc(sizeof(rpc_t));
+
+ rpc->old_eip = callee_isf->eip;
+ rpc->old_esp = callee_isf->esp;
+ rpc->eax = callee_isf->eax;
+ rpc->eflags = callee_isf->eflags;
+ rpc->caller = cpu_get_current()->thread;
+
+ rpc->reenable_irq = 0;
+
+ list_push(callee->process->rpcs, rpc);
+
+
+ // Stack des aufgerufenen Prozesses modifizieren:
+ //
+ // * Stack vergroessern, falls nicht genug freier Platz vorhanden ist
+ // * Kopieren der Datengroesse, der Aufrufer-PID und der Daten auf den
+ // Stack des aufgerufenen Tasks und Anpassen des Stackpointers
+ //
+ // Dazu wird der Stack des aufgerufenen Tasks temporaer gemappt
+
+ adjust_stack_size(callee, callee_isf, rounded_data_size);
+ callee_isf->esp -= rounded_data_size;
+
+ void* first_stack_page = mmc_automap_user(
+ &cpu_get_current()->thread->process->context,
+ &callee->process->context,
+ (vaddr_t) PAGE_ALIGN_ROUND_DOWN(callee_isf->esp),
+ NUM_PAGES(rounded_data_size),
+ KERNEL_MEM_START, KERNEL_MEM_END,
+ MM_FLAGS_KERNEL_DATA);
+ void* stack = first_stack_page + ((uintptr_t) callee_isf->esp % PAGE_SIZE);
+
+ ((uint32_t*) stack)[0] = data_size + metadata_size;
+ ((uint32_t*) stack)[1] = cpu_get_current()->thread->process->pid;
+
+#if 0
+ kprintf("RPC PID %d => %d\n",
+ cpu_get_current()->thread->process->pid,
+ callee->process->pid);
+ kprintf("Kopiere: %08x => %08x, %d Bytes\n",
+ metadata, stack + 8, metadata_size);
+ memcpy(stack + 8, metadata, metadata_size);
+ kprintf("Kopiere: %08x => %08x, %d Bytes\n",
+ data, stack + 8 + metadata_size, data_size);
+#endif
+ memcpy(stack + 8, metadata, metadata_size);
+ memcpy(stack + 8 + metadata_size, data, data_size);
+
+
+ // Zum RPC-Handler springen
+ callee_isf->eip = (uintptr_t) callee->process->rpc_handler;
+
+ // Temporaere Mappings wieder aufheben
+ mmc_unmap(&cpu_get_current()->thread->process->context, first_stack_page,
+ NUM_PAGES(rounded_data_size));
+
+ vmm_kernel_unmap(callee_isf, sizeof(*callee_isf));
+
+ kprintf("[%d => %d] RPC durchgefuehrt.\n",
+ cpu_get_current()->thread->process->pid,
+ callee->process->pid);
+
+ // Der aufgerufene Task darf wieder laufen
+ if (callee->status == PM_STATUS_WAIT_FOR_RPC) {
+ callee->status = PM_STATUS_READY;
+ }
+
+ if (!ignore_blocked) {
+ pm_unblock_rpc(callee->process, syscall_pm_get_pid());
+ }
+
+
+#if 0
+ {
+ schedule_to_task(callee, (dword*) esp);
+ } else {
+ isf->eax = -1;
+ schedule((dword*)esp);
+ }
+#endif
+
+ return 0;
+}
+
+
+#if 0
+/**
+ * Führt einen RPC zur Behandlung eines IRQ durch. Der IRQ wird dabei
+ * deaktiviert, solange der Handler arbeitet und erst anschlieÃ?end
+ * wieder freigegeben. Im sonstigen Verhalten gleicht diese Funktion
+ * fastrpc.
+ *
+ * @see fastrpc
+ */
+bool fastrpc_irq(struct task * callee, dword metadata_size, void* metadata,
+ dword data_size, void* data, byte irq)
+{
+ if (callee->blocked_by_pid && (callee->status != TS_WAIT_FOR_RPC)) {
+ return FALSE;
+ }
+
+ if (fastrpc(callee, metadata_size, metadata, data_size, data)) {
+ rpc_t* rpc = list_get_element_at(current_task->rpcs, 0);
+ rpc->reenable_irq = irq;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+#endif
+
+/**
+ * Wird nach der Ausführung eines RPC-Handlers aufgerufen.
+ *
+ * Nach der Rückkehr vom RPC-Handler wird der neueste Zustand vom RPC-Stack
+ * gepopt und zur Wiederherstellung des ursprünglichen Prozessorzustands
+ * benutzt.
+ *
+ * Dies betrifft eip, esp, eax und eflags. Die übrigen Register sind vom
+ * RPC-Handler zu sicher und vor dem Aufruf von SYSCALL_FASTRPC_RET
+ * wiederherzustellen. eax ist davon ausgenommen, da es die Funktionsnummer
+ * des Syscalls enthalten muÃ?.
+ *
+ * @param esp Interrupt-Stackframe des vom RPC-Handler zurückkehrenden Tasks
+ */
+void syscall_fastrpc_ret(void)
+{
+ rpc_t* rpc = list_pop(cpu_get_current()->thread->process->rpcs);
+ interrupt_stack_frame_t* callee_isf =
+ cpu_get_current()->thread->kernel_stack;
+
+ // Wenn der Task vom RPC-Handler zurückkehrt, obwohl der Handler
+ // gar nicht aufgerufen wurde, läuft was schief
+ if (rpc == NULL) {
+#if 0
+ if(debug_test_flag(DEBUG_FLAG_STACK_BACKTRACE)) {
+ stack_backtrace_ebp(callee_isf->ebp, callee_isf->eip);
+ }
+#endif
+ kprintf("Unerwartete Rueckkehr vom RPC-Handler\n");
+ // TODO abort_task("Unerwartete Rueckkehr vom RPC-Handler");
+ }
+
+ // Wiederherstellen der Register
+ callee_isf->eip = rpc->old_eip;
+ callee_isf->esp = rpc->old_esp;
+ callee_isf->eax = rpc->eax;
+ callee_isf->eflags = rpc->eflags;
+
+ kprintf("[%d => %d] RPC fertig.\n",
+ rpc->caller->process->pid,
+ cpu_get_current()->thread->process->pid);
+
+ // TODO Wechsel zum aufrufenden Task
+#if 0
+ if (rpc->caller) {
+ schedule_to_task(rpc->caller, (dword*) esp);
+ }
+
+ // Wenn es ein IRQ-verarbeitender RPC war, den Interrupt jetzt
+ // wieder aktivieren
+ if (rpc->reenable_irq) {
+ //printf("reenable IRQ %d\n", rpc->reenable_irq);
+ enable_irq(rpc->reenable_irq);
+ }
+#endif
+
+ free(rpc);
+}
+
+#if 0
+/**
+ * Entfernt den gegebenen Task aus allen RPC-Backlinks.
+ *
+ * Diese Funktion wird benoetigt, wenn ein Task einen RPC aufruft und beendet
+ * wird, bevor der RPC fertig ist. Ansonsten zeigt rpc->caller ins Leere,
+ * was in return_from_rpc() zur Katastrophe führt.
+ */
+void rpc_destroy_task_backlinks(struct task* destroyed_task)
+{
+ struct task* task;
+ for (task = first_task; task != NULL; task = task->next_task) {
+ int i;
+ rpc_t* rpc;
+ for (i = 0; (rpc = list_get_element_at(task->rpcs, i)); i++) {
+ if (rpc->caller == destroyed_task) {
+ rpc->caller = NULL;
+ }
+ }
+ }
}
+#endif
+
+#endif
Index: trunk/src/kernel2/include/syscall.h
===================================================================
--- trunk.orig/src/kernel2/include/syscall.h
+++ trunk/src/kernel2/include/syscall.h
@@ -112,6 +112,13 @@ void syscall_init_child_page(pid_t pid,
/// RPC-Handler registrieren
void syscall_set_rpc_handler(vaddr_t address);
+/// RPC durchfuehren
+int syscall_fastrpc(pid_t callee_pid, size_t metadata_size, void* metadata,
+ size_t data_size, void* data);
+
+/// Von einem RPC zurueckkehren
+void syscall_fastrpc_ret(void);
+
// Diverse
/// Textausgabe ueber den Kernel
void syscall_putsn(int char_count, char* source);
Index: trunk/src/kernel2/src/syscall.c
===================================================================
--- trunk.orig/src/kernel2/src/syscall.c
+++ trunk/src/kernel2/src/syscall.c
@@ -65,8 +65,11 @@ void syscall_init()
syscall_register(SYSCALL_PM_CREATE_PROCESS, &syscall_pm_create_process, 4);
syscall_register(SYSCALL_PM_INIT_PAGE, &syscall_init_child_page, 4);
- syscall_register(SYSCALL_SET_RPC_HANDLER, (void*) &syscall_set_rpc_handler,
- 1);
+ syscall_register(SYSCALL_SET_RPC_HANDLER, &syscall_set_rpc_handler, 1);
+#if CONFIG_ARCH == ARCH_I386
+ syscall_register(SYSCALL_FASTRPC, &syscall_fastrpc, 5);
+ syscall_register(SYSCALL_FASTRPC_RET, &syscall_fastrpc_ret, 0);
+#endif
syscall_register(SYSCALL_PUTSN, (void*) &syscall_putsn, 2);
}
Index: trunk/src/kernel2/src/arch/i386/mm/virt.c
===================================================================
--- trunk.orig/src/kernel2/src/arch/i386/mm/virt.c
+++ trunk/src/kernel2/src/arch/i386/mm/virt.c
@@ -147,32 +147,35 @@ void vmm_kernel_unmap(vaddr_t start, siz
}
}
-#if 0
/**
* Vergrössert den Userspace-Stack eines Tasks um pages Seiten
*
* @param task_ptr Pointer zur Task-Struktur
* @param pages Anzahl der zu mappenden Seiten
*/
-void increase_user_stack_size(struct task * task_ptr, int pages)
+void increase_user_stack_size(pm_thread_t* task_ptr, int pages)
{
int i;
for(i = 0; i < pages; i++)
{
- task_ptr->user_stack_bottom -= PAGE_SIZE;
- if(resolve_vaddr((mmc_context_t) task_ptr->cr3, (vaddr_t) task_ptr->user_stack_bottom) != NULL)
+ task_ptr->kernel_stack_bottom -= PAGE_SIZE;
+ if(mmc_resolve(&task_ptr->process->context,
+ (vaddr_t) task_ptr->kernel_stack_bottom) != NULL)
{
+ /*
kprintf("\n"
"\033[1;37m\033[41m" // weiss auf rot
"Task gestoppt: Konnte den Stack nicht weiter vergroessern\n"
"\033[0;37m\033[40m");
+ */
while(1) { asm("hlt"); }
}
- map_page((mmc_context_t) task_ptr->cr3, task_ptr->user_stack_bottom, phys_alloc_page(), PTE_P | PTE_W | PTE_U);
+ mmc_map(&task_ptr->process->context,
+ task_ptr->kernel_stack_bottom,
+ pmm_alloc(1), PTE_P | PTE_W | PTE_U, 1);
}
}
-#endif
/**
* Fuer malloc()
Index: trunk/src/kernel2/include/mm.h
===================================================================
--- trunk.orig/src/kernel2/include/mm.h
+++ trunk/src/kernel2/include/mm.h
@@ -89,6 +89,9 @@ paddr_t mmc_resolve(mmc_context_t* conte
vaddr_t mmc_automap(mmc_context_t* context, paddr_t start, size_t count,
uintptr_t lower_limit, uintptr_t upper_limit, int flags);
+vaddr_t mmc_automap_user(mmc_context_t* target_ctx, mmc_context_t* source_ctx,
+ vaddr_t start, size_t count, uintptr_t lower_limit, uintptr_t upper_limit,
+ int flags);
void mmc_activate(mmc_context_t* context);
Index: trunk/src/kernel2/src/arch/i386/mm/mm_context.c
===================================================================
--- trunk.orig/src/kernel2/src/arch/i386/mm/mm_context.c
+++ trunk/src/kernel2/src/arch/i386/mm/mm_context.c
@@ -509,7 +509,7 @@ static vaddr_t find_contiguous_pages
* Mappt einen Speicherbereich in einen MM-Kontext an eine freie Adresse in
* einem vorgegebenen Adressberech.
*
- * @param page_directory Kontext, in den gemappt werden soll
+ * @param context Kontext, in den gemappt werden soll
* @param start Physische Startadresse des zu mappenden Speicherbereichs
* @param count Anzahl der zu mappenden Seiten
* @param lower_limit Niedrigste zulässige virtuelle Adresse
@@ -532,3 +532,44 @@ vaddr_t mmc_automap(mmc_context_t* conte
return NULL;
}
}
+
+/**
+ * Mappt einen Speicherbereich eines anderen Tasks in einen MM-Kontext an eine
+ * freie Adresse in einem vorgegebenen Adressberech.
+ *
+ * @param target_ctx Kontext, in den gemappt werden soll
+ * @param source_ctx Kontext, aus dem Speicher gemappt werden soll
+ * @param start Virtuelle Startadresse des zu mappenden Speicherbereichs
+ * bezueglich source_ctx
+ * @param count Anzahl der zu mappenden Seiten
+ * @param lower_limit Niedrigste zulaessige virtuelle Adresse
+ * @param upper_limit Hoechste zulaessige virtuelle Adresse
+ * @param flags Flags fuer die Pagetable
+ */
+vaddr_t mmc_automap_user(mmc_context_t* target_ctx, mmc_context_t* source_ctx,
+ vaddr_t start, size_t count, uintptr_t lower_limit, uintptr_t upper_limit,
+ int flags)
+{
+ size_t i;
+ paddr_t paddr;
+ vaddr_t vaddr;
+ vaddr_t free_page =
+ find_contiguous_pages(target_ctx, count, lower_limit, upper_limit);
+
+ if (free_page == NULL) {
+ return NULL;
+ }
+
+ // FIXME Hier wird unter Umstaenden ziemlich oft dieselbe Pagetable gemappt
+ // und wieder ungemappt (in mmc_resolve)
+ for (i = 0; i < count; i++) {
+ paddr = mmc_resolve(source_ctx, start + (i * PAGE_SIZE));
+ vaddr = free_page + (i * PAGE_SIZE);
+ if (!mmc_map(target_ctx, vaddr, paddr, flags, count)) {
+ mmc_unmap(target_ctx, free_page, i);
+ return NULL;
+ }
+ }
+
+ return free_page;
+}
Index: trunk/src/include/collections.h
===================================================================
--- trunk.orig/src/include/collections.h
+++ trunk/src/include/collections.h
@@ -8,7 +8,7 @@ typedef struct {
dword size;
} list_t;
-list_t* list_create();
+list_t* list_create(void);
void list_destroy(list_t* list);
list_t* list_push(list_t* list, void* value);
void* list_pop(list_t* list);
Index: trunk/src/kernel2/src/tasks/pm.c
===================================================================
--- trunk.orig/src/kernel2/src/tasks/pm.c
+++ trunk/src/kernel2/src/tasks/pm.c
@@ -124,9 +124,11 @@ pm_process_t* pm_create(pm_process_t* pa
// Der Prozess ist so lange blockiert, bis er manuell entsperrt wird
process->status = PM_STATUS_BLOCKED;
-
+
+ // RPC initialisieren
process->rpc_handler = NULL;
-
+ process->rpcs = list_create();
+
list_push(process_list, process);
return process;
@@ -141,7 +143,11 @@ void pm_destroy(pm_process_t* process)
{
// Den Prozess blockieren
while (pm_block(process) == FALSE);
-
+
+ // RPC-Strukturen freigeben
+ // TODO Die einzelnen Listenglieder freigeben
+ list_destroy(process->rpcs);
+
// Den Prozess aus der Liste entfernen
pm_process_t* _proc;
int i = 0;
Index: trunk/src/kernel2/src/arch/i386/syscall.c
===================================================================
--- trunk.orig/src/kernel2/src/arch/i386/syscall.c
+++ trunk/src/kernel2/src/arch/i386/syscall.c
@@ -68,22 +68,43 @@ void syscall_arch(machine_state_t* isf)
}
void* handler = syscalls[number].handler;
- dword result;
- dword stack_backup;
- // Die Syscallhandler werden mit dem Userspace-Stack aufgerufen, damit
- // keine Parameter kopiert werden muessen.
- asm("pusha;"
- // Den original-Stackpointer retten
- "movl %%esp, %2;"
- // Stack wechseln
- "movl %1, %%esp;"
- "call *%3;"
- "movl %%eax, %0;"
- "movl %2, %%esp;"
- "popa;"
- : "=m" (result) : "r" (stack), "m" (stack_backup), "r" (handler));
-
- isf->eax = result;
+ // FIXME Das ist alles nur bedingt ueberzeugend...
+ if (handler == syscall_fastrpc) {
+
+ pid_t callee_pid = *((dword*) isf->esp);
+ dword metadata_size = *((dword*) (isf->esp + 4));
+ void* metadata = *((void**) (isf->esp + 8));
+ dword data_size = *((dword*) (isf->esp + 12));
+ void* data = *((void**) (isf->esp + 16));
+
+ isf->eax = syscall_fastrpc(
+ callee_pid,
+ metadata_size, metadata,
+ data_size, data);
+
+ } else if (handler == syscall_fastrpc_ret) {
+
+ syscall_fastrpc_ret();
+
+ } else {
+ dword result;
+ dword stack_backup;
+
+ // Die Syscallhandler werden mit dem Userspace-Stack aufgerufen, damit
+ // keine Parameter kopiert werden muessen.
+ asm("pusha;"
+ // Den original-Stackpointer retten
+ "movl %%esp, %2;"
+ // Stack wechseln
+ "movl %1, %%esp;"
+ "call *%3;"
+ "movl %%eax, %0;"
+ "movl %2, %%esp;"
+ "popa;"
+ : "=m" (result) : "r" (stack), "m" (stack_backup), "r" (handler));
+
+ isf->eax = result;
+ }
}