[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH 2/2] kernel2: I/O-Bitmap benutzen
! kernel2: Echte Verwaltung der I/O-Bitmap anstatt zufaellig Ports
freizugeben, weil der groesste Teil des TSS aus Nullen besteht
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/kernel2/include/arch/i386/cpu.h | 42 +++++++
src/kernel2/include/syscall.h | 2 +-
src/kernel2/include/tasks.h | 5 +
src/kernel2/src/arch/i386/cpu.c | 2 +
src/kernel2/src/arch/i386/io.c | 214 +++++++++++++++++++++++++++++++++++
src/kernel2/src/interrupts/im.c | 11 ++
src/kernel2/src/syscalls/io.c | 11 ++-
src/kernel2/src/tasks/pm.c | 3 +
8 files changed, 287 insertions(+), 3 deletions(-)
create mode 100644 src/kernel2/src/arch/i386/io.c
diff --git a/src/kernel2/include/arch/i386/cpu.h b/src/kernel2/include/arch/i386/cpu.h
index 23c673b..9b9acbd 100644
--- a/src/kernel2/include/arch/i386/cpu.h
+++ b/src/kernel2/include/arch/i386/cpu.h
@@ -81,6 +81,11 @@ struct vm86_isf {
#define CPU_IO_BITMAP_LENGTH 0xffff
+// Dieser Wert muss ausserhalb des in der GDT definierten Limits
+// fuer das TSS liegen
+#define TSS_IO_BITMAP_NOT_LOADED (sizeof(cpu_tss_t) + 0x100)
+#define TSS_IO_BITMAP_OFFSET offsetof(cpu_tss_t, io_bit_map)
+
/// Task state segment
typedef struct {
uint32_t backlink;
@@ -138,9 +143,46 @@ cpu_t* cpu_get_current(void);
void cpu_dump(machine_state_t* machine_state);
/**
+ * Reserviert einen Bereich von IO-Ports für einen Task.
+ * Es werden entweder alle angeforderten oder im Fehlerfall gar keine Ports
+ * reserviert. Eine teilweise Reservierung tritt nicht auf.
+ *
+ * @param task Task, für den die Ports reserviert werden sollen
+ * @param port Nummer des niedrigsten zu reservierenden Ports
+ * @param length Anzahl der Ports, die zu reservieren sind
+ */
+bool io_ports_request(pm_process_t* task, uint32_t port, uint32_t length);
+
+/**
+ * Gibt einen Bereich von Ports frei.
+ *
+ * @param task Task, der die Freigabe anfordert
+ * @param port Niedrigster freizugebender Port
+ * @param length Anzahl der freizugebenden Ports
+ *
+ * @return true, wenn alle Ports freigegeben werden konnten. Wenn ein Port
+ * nicht freigegeben werden konnte (war nicht für den Task reserviert),
+ * wird false zurückgegeben, die Bearbeitung allerdings nicht abgebrochen,
+ * sondern die weiteren Ports versucht freizugeben.
+ */
+bool io_ports_release(pm_process_t* task, uint32_t port, uint32_t length);
+
+/**
+ * Gibt alle von einem Task reservierten Ports frei
+ *
+ * @param task Task, dessen Ports freigegeben werden sollen
+ */
+void io_ports_release_all(pm_process_t* task);
+
+/**
* Wird aufgerufen, nachdem zu einem neuen Task gewechselt wurde
*/
void cpu_prepare_current_task(void);
+/*
+ * Aktiviert die I/O-Bitmap fuer den Prozess
+ */
+void io_activate_bitmap(pm_process_t* task);
+
#endif //ifndef _CPU_H_
diff --git a/src/kernel2/include/syscall.h b/src/kernel2/include/syscall.h
index 72bbb26..11e4bb7 100644
--- a/src/kernel2/include/syscall.h
+++ b/src/kernel2/include/syscall.h
@@ -130,7 +130,7 @@ void syscall_init_child_page(pid_t pid, vaddr_t src, vaddr_t dest,
size_t size);
/// IO-Ports anfordern
-void syscall_io_request_port(uint32_t port, uint32_t length);
+int syscall_io_request_port(uint32_t port, uint32_t length);
/// Aktuelle Zeit abfragen (Mikrosekunden seit Systemstart)
uint64_t syscall_get_tick_count(void);
diff --git a/src/kernel2/include/tasks.h b/src/kernel2/include/tasks.h
index 744cfc3..9266fa6 100644
--- a/src/kernel2/include/tasks.h
+++ b/src/kernel2/include/tasks.h
@@ -90,6 +90,11 @@ typedef struct pm_process {
/// Eine Liste von geoeffneten SHM-Bereichen
list_t* shm;
+#ifdef ARCH_I386
+ /// IO-Bitmap
+ void* io_bitmap;
+#endif
+
/**
* Eine Liste von Eventhandlern, die beim Loeschen des Prozesses
* aufgerufen werden
diff --git a/src/kernel2/src/arch/i386/cpu.c b/src/kernel2/src/arch/i386/cpu.c
index c170755..43432f2 100644
--- a/src/kernel2/src/arch/i386/cpu.c
+++ b/src/kernel2/src/arch/i386/cpu.c
@@ -171,4 +171,6 @@ void cpu_prepare_current_task(void)
(uintptr_t) thread->user_isf
+ sizeof(interrupt_stack_frame_t);
}
+
+ cpu_get_current()->tss.io_bit_map_offset = TSS_IO_BITMAP_NOT_LOADED;
}
diff --git a/src/kernel2/src/arch/i386/io.c b/src/kernel2/src/arch/i386/io.c
new file mode 100644
index 0000000..0dc6ca7
--- /dev/null
+++ b/src/kernel2/src/arch/i386/io.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2007-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 <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "tasks.h"
+#include "kernel.h"
+
+/* Gesetztes Bit: Port wird benutzt */
+uint8_t global_port_bitmap[CPU_IO_BITMAP_LENGTH / 8] = { 0 };
+
+/**
+ * Reserviert einen einzelnen IO-Port für einen Task
+ *
+ * @param task Task, dem der Port zugeordnet werden soll
+ * @param port Nummer des zuzuordnenden IO-Ports
+ *
+ * @return Gibt true zurück, wenn der Task auf den Port zugreifen kann
+ * (erfolgreiche oder bereits vorhandene Reservierung für denselben Task),
+ * ansonsten false.
+ */
+static bool io_port_request(pm_process_t* task, uint32_t port)
+{
+ uint32_t index = port / 8;
+ uint8_t bit = 1 << (port % 8);
+ uint8_t* io_bitmap = task->io_bitmap;
+
+ // Prüfen, ob der Port überhaupt von der Bitmap abgedeckt wird
+ if (port >= CPU_IO_BITMAP_LENGTH) {
+ return false;
+ }
+
+ // Ist der Port noch frei?
+ // Wenn der Port für denselben Task schon einmal reserviert wurde,
+ // abbrechen, aber true zurückgeben
+ if (global_port_bitmap[index] & bit) {
+ return (io_bitmap && ((io_bitmap[index] & bit) == 0));
+ }
+
+ // Falls der Task noch keine zugeordnete Bitmap hat, wird es jetzt
+ // Zeit, eine anzulegen
+ if (io_bitmap == NULL) {
+ io_bitmap = task->io_bitmap = malloc(CPU_IO_BITMAP_LENGTH / 8);
+ memset(io_bitmap, 0xFF, CPU_IO_BITMAP_LENGTH / 8);
+ }
+
+ // Die eigentliche Reservierung
+ global_port_bitmap[index] |= bit;
+ io_bitmap[index] &= ~bit;
+
+ return true;
+}
+
+/**
+ * Gibt einen einzelnen IO-Port frei.
+ *
+ * @param task Task, der die Freigabe anfordert
+ * @param port Freizugebender Port
+ *
+ * @return true, wenn der Port freigegeben werden konnte, false wenn der
+ * Port nicht für den Task reserviert war.
+ */
+static bool io_port_release(pm_process_t* task, uint32_t port)
+{
+ uint32_t index = port / 8;
+ uint8_t bit = 1 << (port % 8);
+ uint8_t* io_bitmap = task->io_bitmap;
+
+ // Wenn der Port gar nicht für den Task reserviert ist, false zurückgeben
+ if ((!io_bitmap) || (io_bitmap[index] & bit)) {
+ return false;
+ }
+
+ // Wenn der Port zwar für den Task reserviert ist, aber in der globalen
+ // Tabelle als frei markiert, haben wir einen Kernel-Bug.
+ if ((global_port_bitmap[index] & bit) == 0) {
+ panic("IO-Port-Bitmaps sind beschaedigt (Port %d, PID %d)",
+ port, task->pid);
+ }
+
+ // Die eigentliche Freigabe
+ global_port_bitmap[index] &= ~bit;
+ io_bitmap[index] |= bit;
+
+ return true;
+}
+
+/**
+ * Reserviert einen Bereich von IO-Ports für einen Task.
+ * Es werden entweder alle angeforderten oder im Fehlerfall gar keine Ports
+ * reserviert. Eine teilweise Reservierung tritt nicht auf.
+ *
+ * @param task Task, für den die Ports reserviert werden sollen
+ * @param port Nummer des niedrigsten zu reservierenden Ports
+ * @param length Anzahl der Ports, die zu reservieren sind
+ */
+bool io_ports_request(pm_process_t* task, uint32_t port, uint32_t length)
+{
+ uint32_t n = length;
+ while (n--)
+ {
+ if (!io_port_request(task, port++))
+ {
+ // Bereits reservierte Ports wieder freigeben
+ while (++n != length) {
+ io_port_release(task, --port);
+ }
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Gibt einen Bereich von Ports frei.
+ *
+ * @param task Task, der die Freigabe anfordert
+ * @param port Niedrigster freizugebender Port
+ * @param length Anzahl der freizugebenden Ports
+ *
+ * @return true, wenn alle Ports freigegeben werden konnten. Wenn ein Port
+ * nicht freigegeben werden konnte (war nicht für den Task reserviert),
+ * wird false zurückgegeben, die Bearbeitung allerdings nicht abgebrochen,
+ * sondern die weiteren Ports versucht freizugeben.
+ */
+bool io_ports_release(pm_process_t* task, uint32_t port, uint32_t length)
+{
+ bool success = true;
+
+ while (length--)
+ {
+ if (!io_port_release(task, port++)) {
+ success = false;
+ }
+ }
+
+ return success;
+}
+
+/**
+ * Gibt alle von einem Task reservierten Ports frei
+ *
+ * @param task Task, dessen Ports freigegeben werden sollen
+ */
+void io_ports_release_all(pm_process_t* task)
+{
+ uint32_t i;
+ uint8_t* io_bitmap = task->io_bitmap;
+
+ if (io_bitmap == NULL) {
+ return;
+ }
+
+ for (i = 0; i < CPU_IO_BITMAP_LENGTH / 8; i++)
+ {
+ if (io_bitmap[i] != (uint8_t) -1) {
+ io_ports_release(task, 8*i, 8);
+ }
+ }
+}
+
+/*
+ * Aktiviert die I/O-Bitmap fuer den Prozess
+ */
+void io_activate_bitmap(pm_process_t* task)
+{
+ cpu_tss_t* tss = &cpu_get_current()->tss;
+
+ tss->io_bit_map_offset = TSS_IO_BITMAP_OFFSET;
+
+ /* TODO Mit geschicktem Einsatz von Paging koennte man sich die Kopiererei
+ * sparen */
+ if (task->io_bitmap) {
+ memcpy(tss->io_bit_map, task->io_bitmap, CPU_IO_BITMAP_LENGTH / 8);
+ } else {
+ memset(tss->io_bit_map, 0xff, CPU_IO_BITMAP_LENGTH / 8);
+ }
+}
diff --git a/src/kernel2/src/interrupts/im.c b/src/kernel2/src/interrupts/im.c
index 4472947..9fae56b 100644
--- a/src/kernel2/src/interrupts/im.c
+++ b/src/kernel2/src/interrupts/im.c
@@ -80,6 +80,17 @@ static void handle_exception(interrupt_stack_frame_t* isf, uint8_t int_num)
}
}
+ if (int_num == 0x0d) {
+ // Pruefen, ob der #GP moeglicherweise durch eine nicht geladene
+ // I/O-Bitmap verurscht worden ist
+ if (cpu_get_current()->tss.io_bit_map_offset ==
+ TSS_IO_BITMAP_NOT_LOADED)
+ {
+ io_activate_bitmap(current_process);
+ return;
+ }
+ }
+
if (int_num == 0x0e) {
// Ueberprüfen ob der Pagefault durch einen Stackoverflow
// hervorgerufen wurde. Falls ja: Stack vergroessern und weitermachen
diff --git a/src/kernel2/src/syscalls/io.c b/src/kernel2/src/syscalls/io.c
index de840be..efe344b 100644
--- a/src/kernel2/src/syscalls/io.c
+++ b/src/kernel2/src/syscalls/io.c
@@ -35,7 +35,14 @@
#include <stdint.h>
-void syscall_io_request_port(uint32_t port, uint32_t length)
+#include "cpu.h"
+
+int syscall_io_request_port(uint32_t port, uint32_t length)
{
- // TODO syscall_io_request_port
+ int ret;
+
+ ret = io_ports_request(current_process, port, length);
+ io_activate_bitmap(current_process);
+
+ return ret;
}
diff --git a/src/kernel2/src/tasks/pm.c b/src/kernel2/src/tasks/pm.c
index a077621..78cd50f 100644
--- a/src/kernel2/src/tasks/pm.c
+++ b/src/kernel2/src/tasks/pm.c
@@ -197,6 +197,9 @@ void pm_destroy(pm_process_t* process)
}
list_destroy(process->on_destroy);
+ // IO-Ports freigeben
+ io_ports_release_all(process);
+
// Timer freigeben
timer_cancel_all(process);
--
1.6.0.2