aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/include/gdt.h57
-rw-r--r--kernel/include/idt.h15
-rw-r--r--kernel/include/mutex.h21
-rw-r--r--kernel/include/region.h2
-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
-rw-r--r--kernel/lib/mutex.c27
-rw-r--r--kernel/lib/slab_alloc.c3
-rw-r--r--kernel/lib_tests/slab_test.c2
-rw-r--r--kernel/linker.ld1
15 files changed, 248 insertions, 129 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 0db3d6b..9619fb6 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include -g -Wno-u
LD = i586-elf-gcc
LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc -Xlinker -Map=kernel.map
-OBJ = lib/string.o lib/printf.o lib/slab_alloc.o \
+OBJ = lib/string.o lib/printf.o lib/slab_alloc.o lib/mutex.o \
l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o \
l0/gdt.o l0/idt.o l0/interrupt.o \
l0/frame.o l0/paging.o l0/region.o
diff --git a/kernel/include/gdt.h b/kernel/include/gdt.h
index cd66676..a62d0db 100644
--- a/kernel/include/gdt.h
+++ b/kernel/include/gdt.h
@@ -7,58 +7,11 @@
Here, we don't use segmentation to separate processes from one another (this is done with paging).
We only use segmentation to make the difference between kernel mode (ring 3) and user mode (ring 0) */
-/* 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;
-
void gdt_init();
+#define K_CODE_SEGMENT 0x08
+#define K_DATA_SEGMENT 0x10
+#define U_CODE_SEGMENT 0x18
+#define U_DATA_SEGMENT 0x20
+
/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/kernel/include/idt.h b/kernel/include/idt.h
index e054ed5..b697dc3 100644
--- a/kernel/include/idt.h
+++ b/kernel/include/idt.h
@@ -58,21 +58,6 @@
#define EX_INTEL_RESERVED_13 30 // No
#define EX_INTEL_RESERVED_14 31 // No
-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 flags; //Flags
- 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;
-
struct registers {
uint32_t ds; // Data segment selector
uint32_t edi, esi, ebp, useless_esp, ebx, edx, ecx, eax; // Pushed by pusha.
diff --git a/kernel/include/mutex.h b/kernel/include/mutex.h
new file mode 100644
index 0000000..6814adf
--- /dev/null
+++ b/kernel/include/mutex.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <stdint.h>
+
+#define MUTEX_LOCKED 1
+#define MUTEX_UNLOCKED 0
+
+
+typedef uint32_t mutex_t;
+
+void mutex_lock(mutex_t* mutex); //wait for mutex to be free
+int mutex_try_lock(mutex_t* mutex); //lock mutex only if free, returns !0 if locked, 0 if was busy
+void mutex_unlock(mutex_t* mutex);
+
+// the mutex code assumes a yield() function is defined somewhere
+void yield();
+
+#define STATIC_MUTEX(name) static mutex_t name __attribute__((section("locks"))) = MUTEX_UNLOCKED;
+
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/kernel/include/region.h b/kernel/include/region.h
index 4bc8917..5f44626 100644
--- a/kernel/include/region.h
+++ b/kernel/include/region.h
@@ -44,3 +44,5 @@ void region_free_unmap_free(void* addr);
void region_free_unmap(void* addr);
void dbg_print_region_stats();
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
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 :*/
diff --git a/kernel/lib/mutex.c b/kernel/lib/mutex.c
new file mode 100644
index 0000000..cda8049
--- /dev/null
+++ b/kernel/lib/mutex.c
@@ -0,0 +1,27 @@
+#include <mutex.h>
+
+/* Internal use only. This function is atomic, meaning it cannot be interrupted by a system task switch. */
+static uint32_t atomic_exchange(uint32_t* ptr, uint32_t newval) {
+ uint32_t r;
+ asm volatile("xchg (%%ecx), %%eax" : "=a"(r) : "c"(ptr), "a"(newval));
+ return r;
+}
+
+void mutex_lock(uint32_t* mutex) {
+ while (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) {
+ yield();
+ }
+}
+
+int mutex_try_lock(uint32_t* mutex) {
+ if (atomic_exchange(mutex, MUTEX_LOCKED) == MUTEX_LOCKED) {
+ return 0;
+ }
+ return 1;
+}
+
+void mutex_unlock(uint32_t* mutex) {
+ *mutex = MUTEX_UNLOCKED;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/kernel/lib/slab_alloc.c b/kernel/lib/slab_alloc.c
index 63ee0e0..714c49f 100644
--- a/kernel/lib/slab_alloc.c
+++ b/kernel/lib/slab_alloc.c
@@ -278,3 +278,6 @@ void slab_free(mem_allocator_t* a, void* addr) {
ASSERT(false);
}
}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
+
diff --git a/kernel/lib_tests/slab_test.c b/kernel/lib_tests/slab_test.c
index 4bfc6b0..747c785 100644
--- a/kernel/lib_tests/slab_test.c
+++ b/kernel/lib_tests/slab_test.c
@@ -40,3 +40,5 @@ int main(int argc, char *argv[]) {
return 0;
}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/kernel/linker.ld b/kernel/linker.ld
index c92155c..1203950 100644
--- a/kernel/linker.ld
+++ b/kernel/linker.ld
@@ -27,6 +27,7 @@ SECTIONS{
*(.dtor*)
end_dtors = .;
*(.data)
+ *(.locks)
}
.bss : AT(ADDR(.bss) - k_highhalf_addr) {