aboutsummaryrefslogtreecommitdiff
path: root/kernel/l0
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-12-06 23:15:06 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-12-06 23:15:06 +0100
commitacc786cb5805d057932ada3e7c571bb8e901cd67 (patch)
treefe6a9da99a9c5492f1004363a2a1a7aa8bfc8fed /kernel/l0
parent0b5d6568c468075b6c1a2de065332b270345611b (diff)
downloadmacroscope-acc786cb5805d057932ada3e7c571bb8e901cd67.tar.gz
macroscope-acc786cb5805d057932ada3e7c571bb8e901cd67.zip
Begin review of taking model : making things thread safe.
Diffstat (limited to 'kernel/l0')
-rw-r--r--kernel/l0/dbglog.c6
-rw-r--r--kernel/l0/frame.c12
-rw-r--r--kernel/l0/gdt.c67
-rw-r--r--kernel/l0/idt.c153
-rw-r--r--kernel/l0/kmain.c7
-rw-r--r--kernel/l0/region.c2
6 files changed, 186 insertions, 61 deletions
diff --git a/kernel/l0/dbglog.c b/kernel/l0/dbglog.c
index 5a7251b..e042625 100644
--- a/kernel/l0/dbglog.c
+++ b/kernel/l0/dbglog.c
@@ -1,6 +1,8 @@
#include <stdarg.h>
#include <string.h>
#include <printf.h>
+#include <mutex.h>
+
#include <dbglog.h>
#include <config.h>
#include <sys.h>
@@ -121,13 +123,17 @@ static void serial_puts(const char *c) {
// ==================================================================
+STATIC_MUTEX(dbglog_mutex);
+
void dbglog_setup() {
+ mutex_lock(&dbglog_mutex);
#ifdef DBGLOG_TO_SCREEN
vga_init();
#endif
#ifdef DBGLOG_TO_SERIAL
serial_init();
#endif
+ mutex_unlock(&dbglog_mutex);
}
void dbg_print(const char* str) {
diff --git a/kernel/l0/frame.c b/kernel/l0/frame.c
index c646a48..489d010 100644
--- a/kernel/l0/frame.c
+++ b/kernel/l0/frame.c
@@ -1,6 +1,8 @@
#include <frame.h>
#include <dbglog.h>
+#include <mutex.h>
+
// TODO: buddy allocator
// this is a simple bitmap allocator
@@ -32,9 +34,12 @@ void frame_init_allocator(size_t total_ram, void** kernel_data_end) {
begin_search_at = INDEX_FROM_BIT(kernel_pages);
}
+STATIC_MUTEX(frame_allocator_mutex);
+
uint32_t frame_alloc(size_t n) {
if (n > 32) return 0;
+ mutex_lock(&frame_allocator_mutex);
for (uint32_t i = begin_search_at; i < INDEX_FROM_BIT(nframes); i++) {
if (frame_bitset[i] == 0xFFFFFFFF) {
if (i == begin_search_at) begin_search_at++;
@@ -46,14 +51,19 @@ uint32_t frame_alloc(size_t n) {
if (!(frame_bitset[i]&to_test)) {
frame_bitset[i] |= to_test;
nused_frames += n;
+
+ mutex_unlock(&frame_allocator_mutex);
return i * 32 + j;
}
}
}
+ mutex_unlock(&frame_allocator_mutex);
return 0;
}
void frame_free(uint32_t base, size_t n) {
+ mutex_lock(&frame_allocator_mutex);
+
for (size_t i = 0; i < n; i++) {
uint32_t idx = INDEX_FROM_BIT(base + i);
uint32_t ofs = OFFSET_FROM_BIT(base + i);
@@ -64,6 +74,8 @@ void frame_free(uint32_t base, size_t n) {
}
if (INDEX_FROM_BIT(base) < begin_search_at)
begin_search_at = INDEX_FROM_BIT(base);
+
+ mutex_unlock(&frame_allocator_mutex);
}
void dbg_print_frame_stats() {
diff --git a/kernel/l0/gdt.c b/kernel/l0/gdt.c
index 9ed5210..eadde5f 100644
--- a/kernel/l0/gdt.c
+++ b/kernel/l0/gdt.c
@@ -3,11 +3,66 @@
#define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init.
+/* One entry of the table */
+struct gdt_entry {
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t granularity;
+ uint8_t base_high;
+} __attribute__((packed));
+typedef struct gdt_entry gdt_entry_t;
+
+/* Structure defining the whole table : address and size (in bytes). */
+struct gdt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+typedef struct gdt_ptr gdt_ptr_t;
+
+/* The TSS is used for hardware multitasking.
+ We don't use that, but we still need a TSS so that user mode process exceptions
+ can be handled correctly by the kernel. */
+struct tss_entry {
+ uint32_t prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list.
+ uint32_t esp0; // The stack pointer to load when we change to kernel mode.
+ uint32_t ss0; // The stack segment to load when we change to kernel mode.
+ uint32_t esp1; // Unused...
+ uint32_t ss1;
+ uint32_t esp2;
+ uint32_t ss2;
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t es; // The value to load into ES when we change to kernel mode.
+ uint32_t cs; // The value to load into CS when we change to kernel mode.
+ uint32_t ss; // The value to load into SS when we change to kernel mode.
+ uint32_t ds; // The value to load into DS when we change to kernel mode.
+ uint32_t fs; // The value to load into FS when we change to kernel mode.
+ uint32_t gs; // The value to load into GS when we change to kernel mode.
+ uint32_t ldt; // Unused...
+ uint16_t trap;
+ uint16_t iomap_base;
+} __attribute__((packed));
+typedef struct tss_entry tss_entry_t;
+
+// ========================= //
+// Actual definitions
+
static gdt_entry_t gdt_entries[GDT_ENTRIES];
static gdt_ptr_t gdt_ptr;
/* For internal use only. Writes one entry of the GDT with given parameters. */
-static void gdt_setGate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
+static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
gdt_entries[num].base_low = (base & 0xFFFF);
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
gdt_entries[num].base_high = (base >> 24) & 0xFF;
@@ -23,11 +78,11 @@ void gdt_init() {
gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1;
gdt_ptr.base = (uint32_t)&gdt_entries;
- gdt_setGate(0, 0, 0, 0, 0); //Null segment
- gdt_setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment 0x08
- gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10
- gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18
- gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20
+ gdt_set_gate(0, 0, 0, 0, 0); //Null segment
+ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment 0x08
+ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10
+ gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18
+ gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20
asm volatile ("lgdt %0"::"m"(gdt_ptr):"memory");
}
diff --git a/kernel/l0/idt.c b/kernel/l0/idt.c
index 2d7b3bc..76aa225 100644
--- a/kernel/l0/idt.c
+++ b/kernel/l0/idt.c
@@ -1,8 +1,31 @@
#include <idt.h>
+#include <gdt.h>
#include <sys.h>
#include <string.h>
#include <dbglog.h>
+struct idt_entry {
+ uint16_t base_lo; //Low part of address to jump to
+ uint16_t sel; //Kernel segment selector
+ uint8_t always0;
+ uint8_t type_attr; //Type
+ uint16_t base_hi; //High part of address to jump to
+} __attribute__((packed));
+typedef struct idt_entry idt_entry_t;
+
+struct idt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+typedef struct idt_ptr idt_ptr_t;
+
+#define GATE_TYPE_INTERRUPT 14 // IF is cleared on interrupt
+#define GATE_TYPE_TRAP 15 // IF stays as is
+
+#define GATE_PRESENT (1<<7)
+#define GATE_DPL_SHIFT 5
+
+
void isr0();
void isr1();
void isr2();
@@ -91,15 +114,84 @@ void idt_syscallHandler(registers_t *regs) {
}
/* For internal use only. Sets up an entry of the IDT with given parameters. */
-static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
+static void idt_set_gate(uint8_t num, void (*fun)(), uint8_t type) {
+ uint32_t base = (uint32_t)fun;
+
idt_entries[num].base_lo = base & 0xFFFF;
idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
- idt_entries[num].sel = sel;
+ idt_entries[num].sel = K_CODE_SEGMENT;
idt_entries[num].always0 = 0;
- idt_entries[num].flags = flags | 0x60;
+ idt_entries[num].type_attr = GATE_PRESENT
+ | (3 << GATE_DPL_SHIFT) // accessible from user mode
+ | type;
}
+static const struct {
+ uint8_t num;
+ void (*fun)();
+ uint8_t type;
+} gates[] = {
+ // Processor exceptions are traps : handling them should be preemptible
+ { 0, isr0, GATE_TYPE_TRAP },
+ { 1, isr1, GATE_TYPE_TRAP },
+ { 2, isr2, GATE_TYPE_TRAP },
+ { 3, isr3, GATE_TYPE_TRAP },
+ { 4, isr4, GATE_TYPE_TRAP },
+ { 5, isr5, GATE_TYPE_TRAP },
+ { 6, isr6, GATE_TYPE_TRAP },
+ { 7, isr7, GATE_TYPE_TRAP },
+ { 8, isr8, GATE_TYPE_TRAP },
+ { 9, isr9, GATE_TYPE_TRAP },
+ { 10, isr10, GATE_TYPE_TRAP },
+ { 11, isr11, GATE_TYPE_TRAP },
+ { 12, isr12, GATE_TYPE_TRAP },
+ { 13, isr13, GATE_TYPE_TRAP },
+ { 14, isr14, GATE_TYPE_TRAP },
+ { 15, isr15, GATE_TYPE_TRAP },
+ { 16, isr16, GATE_TYPE_TRAP },
+ { 17, isr17, GATE_TYPE_TRAP },
+ { 18, isr18, GATE_TYPE_TRAP },
+ { 19, isr19, GATE_TYPE_TRAP },
+ { 20, isr20, GATE_TYPE_TRAP },
+ { 21, isr21, GATE_TYPE_TRAP },
+ { 22, isr22, GATE_TYPE_TRAP },
+ { 23, isr23, GATE_TYPE_TRAP },
+ { 24, isr24, GATE_TYPE_TRAP },
+ { 25, isr25, GATE_TYPE_TRAP },
+ { 26, isr26, GATE_TYPE_TRAP },
+ { 27, isr27, GATE_TYPE_TRAP },
+ { 28, isr28, GATE_TYPE_TRAP },
+ { 29, isr29, GATE_TYPE_TRAP },
+ { 30, isr30, GATE_TYPE_TRAP },
+ { 31, isr31, GATE_TYPE_TRAP },
+
+ // IRQs are not preemptible ; an IRQ handler should do the bare minimum
+ // (communication with the hardware), and then pass a message to a worker
+ // process in order to do further processing
+ { 32, irq0, GATE_TYPE_INTERRUPT },
+ { 33, irq1, GATE_TYPE_INTERRUPT },
+ { 34, irq2, GATE_TYPE_INTERRUPT },
+ { 35, irq3, GATE_TYPE_INTERRUPT },
+ { 36, irq4, GATE_TYPE_INTERRUPT },
+ { 37, irq5, GATE_TYPE_INTERRUPT },
+ { 38, irq6, GATE_TYPE_INTERRUPT },
+ { 39, irq7, GATE_TYPE_INTERRUPT },
+ { 40, irq8, GATE_TYPE_INTERRUPT },
+ { 41, irq9, GATE_TYPE_INTERRUPT },
+ { 42, irq10, GATE_TYPE_INTERRUPT },
+ { 43, irq11, GATE_TYPE_INTERRUPT },
+ { 44, irq12, GATE_TYPE_INTERRUPT },
+ { 45, irq13, GATE_TYPE_INTERRUPT },
+ { 46, irq14, GATE_TYPE_INTERRUPT },
+ { 47, irq15, GATE_TYPE_INTERRUPT },
+
+ // Of course, syscalls are preemptible
+ { 64, syscall64, GATE_TYPE_TRAP },
+
+ { 0, 0, 0 }
+};
+
/* Remaps the IRQs. Sets up the IDT. */
void idt_init() {
memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry_t) * 256);
@@ -116,62 +208,15 @@ void idt_init() {
outb(0x21, 0x0);
outb(0xA1, 0x0);
- idt_setGate(0, (int32_t)isr0, 0x08, 0x8E);
- idt_setGate(1, (int32_t)isr1, 0x08, 0x8E);
- idt_setGate(2, (int32_t)isr2, 0x08, 0x8E);
- idt_setGate(3, (int32_t)isr3, 0x08, 0x8E);
- idt_setGate(4, (int32_t)isr4, 0x08, 0x8E);
- idt_setGate(5, (int32_t)isr5, 0x08, 0x8E);
- idt_setGate(6, (int32_t)isr6, 0x08, 0x8E);
- idt_setGate(7, (int32_t)isr7, 0x08, 0x8E);
- idt_setGate(8, (int32_t)isr8, 0x08, 0x8E);
- idt_setGate(9, (int32_t)isr9, 0x08, 0x8E);
- idt_setGate(10, (int32_t)isr10, 0x08, 0x8E);
- idt_setGate(11, (int32_t)isr11, 0x08, 0x8E);
- idt_setGate(12, (int32_t)isr12, 0x08, 0x8E);
- idt_setGate(13, (int32_t)isr13, 0x08, 0x8E);
- idt_setGate(14, (int32_t)isr14, 0x08, 0x8E);
- idt_setGate(15, (int32_t)isr15, 0x08, 0x8E);
- idt_setGate(16, (int32_t)isr16, 0x08, 0x8E);
- idt_setGate(17, (int32_t)isr17, 0x08, 0x8E);
- idt_setGate(18, (int32_t)isr18, 0x08, 0x8E);
- idt_setGate(19, (int32_t)isr19, 0x08, 0x8E);
- idt_setGate(20, (int32_t)isr20, 0x08, 0x8E);
- idt_setGate(21, (int32_t)isr21, 0x08, 0x8E);
- idt_setGate(22, (int32_t)isr22, 0x08, 0x8E);
- idt_setGate(23, (int32_t)isr23, 0x08, 0x8E);
- idt_setGate(24, (int32_t)isr24, 0x08, 0x8E);
- idt_setGate(25, (int32_t)isr25, 0x08, 0x8E);
- idt_setGate(26, (int32_t)isr26, 0x08, 0x8E);
- idt_setGate(27, (int32_t)isr27, 0x08, 0x8E);
- idt_setGate(28, (int32_t)isr28, 0x08, 0x8E);
- idt_setGate(29, (int32_t)isr29, 0x08, 0x8E);
- idt_setGate(30, (int32_t)isr30, 0x08, 0x8E);
- idt_setGate(31, (int32_t)isr31, 0x08, 0x8E);
-
- idt_setGate(32, (int32_t)irq0, 0x08, 0x8E);
- idt_setGate(33, (int32_t)irq1, 0x08, 0x8E);
- idt_setGate(34, (int32_t)irq2, 0x08, 0x8E);
- idt_setGate(35, (int32_t)irq3, 0x08, 0x8E);
- idt_setGate(36, (int32_t)irq4, 0x08, 0x8E);
- idt_setGate(37, (int32_t)irq5, 0x08, 0x8E);
- idt_setGate(38, (int32_t)irq6, 0x08, 0x8E);
- idt_setGate(39, (int32_t)irq7, 0x08, 0x8E);
- idt_setGate(40, (int32_t)irq8, 0x08, 0x8E);
- idt_setGate(41, (int32_t)irq9, 0x08, 0x8E);
- idt_setGate(42, (int32_t)irq10, 0x08, 0x8E);
- idt_setGate(43, (int32_t)irq11, 0x08, 0x8E);
- idt_setGate(44, (int32_t)irq12, 0x08, 0x8E);
- idt_setGate(45, (int32_t)irq13, 0x08, 0x8E);
- idt_setGate(46, (int32_t)irq14, 0x08, 0x8E);
- idt_setGate(47, (int32_t)irq15, 0x08, 0x8E);
-
- idt_setGate(64, (int32_t)syscall64, 0x08, 0x8E);
+ for (int i = 0; gates[i].type != 0; i++) {
+ idt_set_gate(gates[i].num, gates[i].fun, gates[i].type);
+ }
idt_ptr.limit = (sizeof(idt_entry_t) * 256) - 1;
idt_ptr.base = (uint32_t)&idt_entries;
asm volatile ("lidt %0"::"m"(idt_ptr):"memory");
+ asm volatile ("sti"); // from now on we accept interruptions... although we don't do much with them
}
/* Sets up an IRQ handler for given IRQ. */
diff --git a/kernel/l0/kmain.c b/kernel/l0/kmain.c
index 63ed6ac..5d85fe5 100644
--- a/kernel/l0/kmain.c
+++ b/kernel/l0/kmain.c
@@ -24,6 +24,11 @@ void* page_alloc_fun_for_kmalloc(size_t bytes) {
return addr;
}
+void yield() {
+ // multitasking not implemented yet
+ dbg_printf("Warning : probable deadlock?\n");
+}
+
slab_type_t slab_sizes[] = {
{ "8B obj", 8, 2 },
{ "16B obj", 16, 2 },
@@ -51,7 +56,7 @@ void kmain(struct multiboot_info_t *mbd, int32_t mb_magic) {
idt_init(); dbg_printf("IDT set up.\n");
idt_set_ex_handler(EX_BREAKPOINT, breakpoint_handler);
- // asm volatile("int $0x3"); // test breakpoint
+ asm volatile("int $0x3"); // test breakpoint
size_t total_ram = ((mbd->mem_upper + mbd->mem_lower) * 1024);
dbg_printf("Total ram: %d Kb\n", total_ram / 1024);
diff --git a/kernel/l0/region.c b/kernel/l0/region.c
index 513af45..8d59b49 100644
--- a/kernel/l0/region.c
+++ b/kernel/l0/region.c
@@ -383,3 +383,5 @@ void dbg_print_region_stats() {
}
dbg_printf("\\\n");
}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/