[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;
+    }
 }