Nucleus
Barry Interrupt handlers b33d632 (3 years, 3 months ago)
diff --git a/.gitignore b/.gitignore
index 80f3926..631ee4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
build/
*.o
nucleus
+!/include/nucleus/
diff --git a/Makefile b/Makefile
index 4f8fdb8..ac7a391 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
PRODUCT=nucleus
CC=i686-orion-gcc
-CFLAGS=-Iinclude/
+CFLAGS=-Iinclude/ -mgeneral-regs-only
AS=i686-orion-as
AFLAGS=
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..ec0abcf
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,97 @@
+#ifndef KERNEL_IO_H
+#define KERNEL_IO_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+/* Read byte from port */
+static inline uint8_t
+inb(uint16_t port)
+{
+ uint8_t value;
+ asm volatile("inb %w1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+/* Write byte to port */
+static inline void
+outb(uint16_t port, uint8_t value)
+{
+ asm volatile("outb %b0, %w1" : : "a" (value), "Nd" (port));
+}
+
+/* Read word from port */
+static inline uint16_t
+inw(uint16_t port)
+{
+ uint16_t value;
+ asm volatile("inw %w1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+/* Write word to port */
+static inline void
+outw(uint16_t port, uint16_t value)
+{
+ asm volatile("outw %w0, %w1" : : "a" (value), "Nd" (port));
+}
+
+/* Read dword from port */
+static inline uint32_t
+inl(uint16_t port)
+{
+ uint32_t value;
+ asm volatile("inl %1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+/* Write dword to port */
+static inline void
+outl(uint16_t port, uint32_t value)
+{
+ asm volatile("outl %0, %1" : : "a" (value), "Nd" (port));
+}
+
+/* Wait for IO to be ready */
+static inline void
+io_wait(void)
+{
+ outb(0x80, 0);
+}
+
+/* Read words into buffer */
+static inline void
+insw(uint16_t port, void *addr, size_t count)
+{
+ asm volatile(
+ "cld;"
+ "repne; insw;"
+ : "=D" (addr), "=c" (count)
+ : "d" (port), "0" (addr), "1" (count)
+ : "memory", "cc"
+ );
+}
+/* Write words out from buffer */
+static inline void
+outsw(uint16_t port, void *addr, size_t count)
+{
+ asm volatile(
+ "cld;"
+ "repne; outsw;"
+ : "=D" (addr), "=c" (count)
+ : "d" (port), "0" (addr), "1" (count)
+ : "memory", "cc"
+ );
+}
+
+/* Read dwords into buffer */
+static inline void
+insl(uint16_t port, void *addr, size_t count)
+{
+ asm volatile(
+ "cld;"
+ "repne; insl;"
+ : "=D" (addr), "=c" (count)
+ : "d" (port), "0" (addr), "1" (count)
+ : "memory", "cc"
+ );
+}
+
+#endif
diff --git a/memory/memory.h b/include/nucleus/memory.h
similarity index 78%
rename from memory/memory.h
rename to include/nucleus/memory.h
index a4abeb0..c6446b0 100644
--- a/memory/memory.h
+++ b/include/nucleus/memory.h
@@ -1,5 +1,5 @@
-#ifndef MEMORY_H
-#define MEMORY_H
+#ifndef _NUCLEUS_MEMORY_H
+#define _NUCLEUS_MEMORY_H
#include <stdint.h>
#include <stddef.h>
diff --git a/include/nucleus/panic.h b/include/nucleus/panic.h
new file mode 100644
index 0000000..413fee6
--- /dev/null
+++ b/include/nucleus/panic.h
@@ -0,0 +1,13 @@
+#ifndef _NUCLEUS_PANIC_H
+#define _NUCLEUS_PANIC_H
+
+_Noreturn void panic(char *fmt, ...);
+
+#define ASSERT(c) ({ \
+ if (__builtin_expect(!(c),0)) \
+ panic("Assertion failed (%s:%d): " #c, \
+ __FILE__, __LINE__); \
+ c; \
+})
+
+#endif
diff --git a/kernel/000.S b/kernel/000.S
index 1ae6600..9c49ee8 100644
--- a/kernel/000.S
+++ b/kernel/000.S
@@ -7,7 +7,7 @@ header:
.long 0, 0, 0, 0, 0
-.section .bss
+.section .bss, "aw", @nobits
stack_bottom:
.skip 16384
stack_top:
@@ -16,7 +16,7 @@ stack_top:
.extern kmain
.global _start
_start:
- mov stack_top, %ebp
+ mov $stack_top, %ebp
mov %ebp, %esp
push %ebx
push %esp
diff --git a/kernel/idt.c b/kernel/idt.c
new file mode 100644
index 0000000..4c594bb
--- /dev/null
+++ b/kernel/idt.c
@@ -0,0 +1,352 @@
+/*
+ * This file deals with the Interrupt Descriptor Table. It creates a simple
+ * IDT, with hard-coded handler functions. It is these handler functions that
+ * can run custom handlers, registered at runtime. This file does not deal with
+ * dispatching messages/signals to processes on an interrupt.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <nucleus/panic.h>
+#include <nucleus/memory.h>
+#include <io.h>
+#include "idt.h"
+
+/* Structure for an IDT Entry */
+static struct IDTEntry {
+ uint16_t offsetLower, selector;
+ uint8_t zero, typeAttr;
+ uint16_t offsetHigher;
+} __attribute__((packed)) *IDT;
+
+void (**exceptions)(struct InterruptFrame *, uint32_t);
+void (**interrupts)(struct InterruptFrame *);
+
+/* Install an IDT Entry */
+static void
+install_idt_entry(uint8_t num, void *addr)
+{
+ IDT[num].offsetLower = (uintptr_t) addr & 0xFFFF;
+ IDT[num].selector = 0x08;
+ IDT[num].zero = 0;
+ IDT[num].typeAttr = 0x8E | 0x60; /* Allowed from ring 3 */
+ IDT[num].offsetHigher = (uintptr_t) addr >> 16;
+}
+
+/* First level generic exception handler */
+static void
+exc_handler(int num, struct InterruptFrame *frame, uint32_t err)
+{
+ ASSERT(exceptions[num]);
+ exceptions[num](frame, err);
+
+ /* TODO: Send APIC EOI */
+}
+
+/* First level generic interrupt handler */
+static void
+int_handler(int num, struct InterruptFrame *frame)
+{
+ if (interrupts[num - 32])
+ interrupts[num - 32](frame);
+
+ /* Send EOI */
+ if (num >= 8)
+ outb(0xA0, 0x20);
+ outb(0x20, 0x20);
+ /* TODO: Send APIC EOI*/
+}
+
+/* Exceptions */
+__attribute__((interrupt))
+static void
+exc0(struct InterruptFrame *frame)
+{
+ exc_handler(0, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc1(struct InterruptFrame *frame)
+{
+ exc_handler(1, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc2(struct InterruptFrame *frame)
+{
+ exc_handler(2, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc3(struct InterruptFrame *frame)
+{
+ exc_handler(3, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc4(struct InterruptFrame *frame)
+{
+ exc_handler(4, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc5(struct InterruptFrame *frame)
+{
+ exc_handler(5, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc6(struct InterruptFrame *frame)
+{
+ exc_handler(6, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc7(struct InterruptFrame *frame)
+{
+ exc_handler(7, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc8(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(8, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc9(struct InterruptFrame *frame)
+{
+ exc_handler(9, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc10(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(10, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc11(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(11, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc12(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(12, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc13(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(13, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc14(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(14, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc15(struct InterruptFrame *frame)
+{
+ exc_handler(15, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc16(struct InterruptFrame *frame)
+{
+ exc_handler(16, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc17(struct InterruptFrame *frame, uint32_t err)
+{
+ exc_handler(17, frame, err);
+}
+__attribute__((interrupt))
+static void
+exc18(struct InterruptFrame *frame)
+{
+ exc_handler(18, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc19(struct InterruptFrame *frame)
+{
+ exc_handler(19, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc20(struct InterruptFrame *frame)
+{
+ exc_handler(20, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc30(struct InterruptFrame *frame)
+{
+ exc_handler(30, frame, 0);
+}
+__attribute__((interrupt))
+static void
+exc128(struct InterruptFrame *frame)
+{
+ exc_handler(128, frame, 0);
+}
+
+/* Interrupts */
+__attribute__((interrupt))
+static void
+int0(struct InterruptFrame *frame)
+{
+ int_handler(32, frame);
+}
+__attribute__((interrupt))
+static void
+int1(struct InterruptFrame *frame)
+{
+ int_handler(33, frame);
+}
+__attribute__((interrupt))
+static void
+int2(struct InterruptFrame *frame)
+{
+ int_handler(34, frame);
+}
+__attribute__((interrupt))
+static void
+int3(struct InterruptFrame *frame)
+{
+ int_handler(35, frame);
+}
+__attribute__((interrupt))
+static void
+int4(struct InterruptFrame *frame)
+{
+ int_handler(36, frame);
+}
+__attribute__((interrupt))
+static void
+int5(struct InterruptFrame *frame)
+{
+ int_handler(37, frame);
+}
+__attribute__((interrupt))
+static void
+int6(struct InterruptFrame *frame)
+{
+ int_handler(38, frame);
+}
+__attribute__((interrupt))
+static void
+int7(struct InterruptFrame *frame)
+{
+ int_handler(39, frame);
+}
+__attribute__((interrupt))
+static void
+int8(struct InterruptFrame *frame)
+{
+ int_handler(40, frame);
+}
+__attribute__((interrupt))
+static void
+int9(struct InterruptFrame *frame)
+{
+ int_handler(41, frame);
+}
+__attribute__((interrupt))
+static void
+int10(struct InterruptFrame *frame)
+{
+ int_handler(42, frame);
+}
+__attribute__((interrupt))
+static void
+int11(struct InterruptFrame *frame)
+{
+ int_handler(43, frame);
+}
+__attribute__((interrupt))
+static void
+int12(struct InterruptFrame *frame)
+{
+ int_handler(44, frame);
+}
+__attribute__((interrupt))
+static void
+int13(struct InterruptFrame *frame)
+{
+ int_handler(45, frame);
+}
+__attribute__((interrupt))
+static void
+int14(struct InterruptFrame *frame)
+{
+ int_handler(46, frame);
+}
+__attribute__((interrupt))
+static void
+int15(struct InterruptFrame *frame)
+{
+ int_handler(47, frame);
+}
+
+/* Initialise the IDT */
+void
+init_idt(void)
+{
+ IDT = (void *) alloc_frame();
+
+ /* Install exceptions */
+ install_idt_entry(0, exc0);
+ install_idt_entry(1, exc1);
+ install_idt_entry(2, exc2);
+ install_idt_entry(3, exc3);
+ install_idt_entry(4, exc4);
+ install_idt_entry(5, exc5);
+ install_idt_entry(6, exc6);
+ install_idt_entry(7, exc7);
+ install_idt_entry(8, exc8);
+ install_idt_entry(9, exc9);
+ install_idt_entry(10, exc10);
+ install_idt_entry(11, exc11);
+ install_idt_entry(12, exc12);
+ install_idt_entry(13, exc13);
+ install_idt_entry(14, exc14);
+ install_idt_entry(15, exc15);
+ install_idt_entry(16, exc16);
+ install_idt_entry(17, exc17);
+ install_idt_entry(18, exc18);
+ install_idt_entry(19, exc19);
+ install_idt_entry(20, exc20);
+ install_idt_entry(30, exc30);
+
+ /* Install interrupts */
+ install_idt_entry(32, int0);
+ install_idt_entry(33, int1);
+ install_idt_entry(34, int2);
+ install_idt_entry(35, int3);
+ install_idt_entry(36, int4);
+ install_idt_entry(37, int5);
+ install_idt_entry(38, int6);
+ install_idt_entry(39, int7);
+ install_idt_entry(40, int8);
+ install_idt_entry(41, int9);
+ install_idt_entry(42, int10);
+ install_idt_entry(43, int11);
+ install_idt_entry(44, int12);
+ install_idt_entry(45, int13);
+ install_idt_entry(46, int14);
+ install_idt_entry(47, int15);
+
+ /* Install system call handler */
+ install_idt_entry(128, exc128);
+
+ exceptions = (void *) (IDT + 256);
+ interrupts = (void *) (exceptions + 32);
+ memset(exceptions, 0, 1024);
+}
diff --git a/kernel/idt.h b/kernel/idt.h
new file mode 100644
index 0000000..204f285
--- /dev/null
+++ b/kernel/idt.h
@@ -0,0 +1,13 @@
+#ifndef KERNEL_IDT_H
+#define KERNEL_IDT_H
+
+#include <stdint.h>
+
+/* Structure for an Interrupt Frame */
+struct InterruptFrame {
+ uint32_t eip, cs, eflags;
+};
+
+void init_idt(void);
+
+#endif
diff --git a/kernel/main.c b/kernel/main.c
index 5a10a59..e797bbc 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -6,8 +6,10 @@
#include <stdint.h>
#include <string.h>
+#include <nucleus/memory.h>
+#include <nucleus/panic.h>
#include "multiboot.h"
-#include "../memory/memory.h"
+#include "idt.h"
extern char _bss[], _end[];
@@ -21,5 +23,8 @@ kmain(uint32_t esp, struct MultibootInfo *mbinfo)
/* Setup frame allocator */
init_frames(mbinfo->mmapLen, (void *) mbinfo->mmapAddr);
- while (1);
+ /* Processor startup */
+ init_idt();
+
+ panic("End of kernel!");
}
diff --git a/kernel/panic.c b/kernel/panic.c
new file mode 100644
index 0000000..415b2b1
--- /dev/null
+++ b/kernel/panic.c
@@ -0,0 +1,29 @@
+/*
+ * This file implements the full kernel panic routine. This routine does not
+ * return, and is essentially a shutdown routine. It will print a message to
+ * the debug port and halt the processor. In an ideal build, this function
+ * won't need to be linked in.
+ */
+
+#include <stdint.h>
+#include <io.h>
+
+/* Kernel panic */
+_Noreturn void
+panic(char *fmt, ...)
+{
+ outb(0xE9, '\033');
+ outb(0xE9, '[');
+ outb(0xE9, '3');
+ outb(0xE9, '1');
+ outb(0xE9, 'm');
+
+ char *p = fmt;
+ while (*p)
+ outb(0xE9, *p++);
+ outb(0xE9, '\n');
+
+ asm volatile("cli");
+ while (1)
+ asm volatile("hlt");
+}
diff --git a/memory/frame.c b/memory/frame.c
index 35b2fed..40075b0 100644
--- a/memory/frame.c
+++ b/memory/frame.c
@@ -7,7 +7,8 @@
#include <stdint.h>
#include <stddef.h>
-#include "memory.h"
+#include <nucleus/memory.h>
+#include <nucleus/panic.h>
/* Types of an E820 Memory Map Entry */
enum E820Type {
@@ -56,6 +57,7 @@ init_frames(uint32_t size, void *addr)
* memory. This map must be read so the memory manager can avoid bad
* areas of memory and areas that are mapped to hardware, ACPI, etc.
*/
+
size_t i, j;
struct E820Entry *memMap = addr;
for (i = 0; i < size / sizeof(struct E820Entry); i++) {
@@ -64,7 +66,11 @@ init_frames(uint32_t size, void *addr)
|| memMap[i].type != E820_USABLE)
continue;
- for (j = 0; j < memMap[i].length; j += PAGE_SIZE)
+ for (j = 0; j < memMap[i].length; j += PAGE_SIZE) {
+ if ((memMap[i].base + j) >= 0x100000
+ && (memMap[i].base + j) < 0x180000)
+ continue;
free_frame(memMap[i].baseHigh + memMap[i].base + j);
+ }
}
}