Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ AlignConsecutiveMacros:
Enabled: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
SpaceBeforeCpp11BracedList: true
AllowShortLambdasOnASingleLine: None
IndentWidth: 4
ContinuationIndentWidth: 4
Expand Down
3 changes: 3 additions & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ include ../scripts/defaults.mk
SRC := \
arch/x86/entry.asm \
arch/x86/gdt.cpp \
arch/x86/idt.cpp \
arch/x86/isr.asm \
arch/x86/isr.cpp \
arch/x86/system.cpp \
generic/boot.cpp \
generic/libc.c \
Expand Down
2 changes: 1 addition & 1 deletion kernel/arch/x86/gdt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
namespace arch
{

Gdt gdt{};
Gdt gdt {};

} // namespace arch
56 changes: 56 additions & 0 deletions kernel/arch/x86/idt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "arch-private/idt.hpp"
#include "arch-private/isr.hpp"
#include "bits.hpp"
#include "log.hpp"
#include <cstdint>

namespace arch
{

constinit Idt idt {};

void Idt::set_gate(uint8_t index, uintptr_t offset, uint8_t attributes)
{
IdtEntry *entry = &table[index];

entry->offset_low = offset;
entry->segment_selector = 0x8;
entry->ist = 0;
entry->attributes = attributes;
entry->offset_mid = offset >> 16;
entry->offset_high = offset >> 32;
entry->reserved = 0;
};

void Idt::load()
{
Idtr idtr {
.limit = sizeof(IdtEntry) * 255,
.offset = (uint64_t)&table,
};

__asm__ volatile("lidt %0" ::"m"(idtr) : "memory");

log::debug("Loaded IDT");
}

void Idt::init()
{
int i = 0;
for (; i <= 31; i++)
set_gate(i, isr_stub_table[i], 0b10001111); // Present + Trap Gate
for (; i <= 255; i++)
set_gate(i, isr_stub_table[i], 0b10001110); // Present + Interrupt Gate
}

void Idt::enable_gate(uint8_t idx)
{
FLAG_SET(table[idx].attributes, 0b10000000);
}

void Idt::disable_gate(uint8_t idx)
{
FLAG_UNSET(table[idx].attributes, 0b10000000);
}

} // namespace arch
2 changes: 1 addition & 1 deletion kernel/arch/x86/include/arch-private/gdt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct __attribute__((packed)) Gdt

void load()
{
Gdtr gdtr{
Gdtr gdtr {
.limit = sizeof(Gdt) - 1,
.base = reinterpret_cast<uint64_t>(this),
};
Expand Down
39 changes: 39 additions & 0 deletions kernel/arch/x86/include/arch-private/idt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once
#include <cstdint>

namespace arch
{

struct __attribute__((packed)) IdtEntry
{
uint16_t offset_low;
uint16_t segment_selector;
uint8_t ist; // Only bits 0..2
uint8_t attributes;
uint16_t offset_mid;
uint32_t offset_high;
uint32_t reserved;
};

struct __attribute__((packed)) Idt
{
constexpr Idt() {};

void set_gate(uint8_t index, uintptr_t offset, uint8_t attributes);
void init();
void load();
void enable_gate(uint8_t index);
void disable_gate(uint8_t index);

IdtEntry table[256] {};
};

struct __attribute__((packed)) Idtr
{
uint16_t limit;
uint64_t offset;
};

extern Idt idt;

} // namespace arch
45 changes: 45 additions & 0 deletions kernel/arch/x86/include/arch-private/isr.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once
#include <cstdint>

namespace arch
{

struct __attribute__((packed)) InterruptFrame
{
// Pushed by isr_commom
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rbp;
uint64_t rdi;
uint64_t rsi;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;

// Pushed by isr stub
uint64_t interrupt;
uint64_t error; // Sometimes pushed by CPU

// Pushed by CPU
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
};

using Isr = void (*)(InterruptFrame *frame);

extern "C" uintptr_t isr_stub_table[];

void isr_init();
void isr_register(uint8_t index, Isr handler);

} // namespace arch
106 changes: 106 additions & 0 deletions kernel/arch/x86/isr.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
extern isr_handler

isr_common:
push rax
push rbx
push rcx
push rdx
push rsi
push rdi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15

; puts pointer to the InterruptFrame in argument 1
mov rdi, rsp
call isr_handler

pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rbp
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax

; pops the error code and interrupt number
add rsp, 16
iretq

; %1: replaced with the first argument
; %+: glues it together with the text before

%macro isr_err_stub 1
global isr_stub_%+%1
isr_stub_%+%1:
push %1
jmp isr_common
%endmacro

%macro isr_no_err_stub 1
global isr_stub_%+%1
isr_stub_%+%1:
push 0
push %1
jmp isr_common
%endmacro

isr_no_err_stub 0
isr_no_err_stub 1
isr_no_err_stub 2
isr_no_err_stub 3
isr_no_err_stub 4
isr_no_err_stub 5
isr_no_err_stub 6
isr_no_err_stub 7
isr_err_stub 8
isr_no_err_stub 9
isr_err_stub 10
isr_err_stub 11
isr_err_stub 12
isr_err_stub 13
isr_err_stub 14
isr_no_err_stub 15
isr_no_err_stub 16
isr_err_stub 17
isr_no_err_stub 18
isr_no_err_stub 19
isr_no_err_stub 20
isr_err_stub 21
isr_no_err_stub 22
isr_no_err_stub 23
isr_no_err_stub 24
isr_no_err_stub 25
isr_no_err_stub 26
isr_no_err_stub 27
isr_no_err_stub 28
isr_err_stub 29
isr_err_stub 30
isr_no_err_stub 31
%assign i 32
%rep 224
isr_no_err_stub %[i]
%assign i i+1
%endrep

global isr_stub_table
isr_stub_table:
%assign i 0
%rep 256
dq isr_stub_%+i
%assign i i+1
%endrep
45 changes: 45 additions & 0 deletions kernel/arch/x86/isr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "arch-private/isr.hpp"
#include "arch-private/idt.hpp"
#include "arch/interrupts.hpp"
#include "log.hpp"
#include <cstdint>

namespace arch
{

Isr isr_handlers[256] {};

extern "C" void isr_handler(InterruptFrame *regs)
{
if (isr_handlers[regs->interrupt] != NULL)
{
isr_handlers[regs->interrupt](regs);
}
else if (regs->interrupt >= 32)
{
log::warn("Unhandled interrupt: %i", regs->interrupt);
}
else
{
log::error("unhandled exception: 0x%x", regs->interrupt);
halt();
}
}

void isr_init()
{
uint8_t i = 0;
do
{
idt.enable_gate(i);
} while (i++ != 255);
log::debug("Enabled all IDT gates");
}

void isr_register(uint8_t index, Isr handler)
{
isr_handlers[index] = handler;
log::debug("ISR handler registered for interrupt 0x%02X", index);
}

} // namespace arch
9 changes: 6 additions & 3 deletions kernel/arch/x86/system.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#define LOG_MODULE "arch"

#include "arch/system.hpp"
#include "arch-private/gdt.hpp"
#include "arch-private/idt.hpp"
#include "arch-private/isr.hpp"
#include "log.hpp"
#include "uart/uart.hpp"

Expand All @@ -20,7 +20,7 @@ void uart_log_fn(const char *const message, std::size_t len)
uart_logger);
}

log::Sink uart_sink = log::Sink{nullptr, uart_log_fn};
log::Sink uart_sink = log::Sink {nullptr, uart_log_fn};

} // namespace

Expand All @@ -30,4 +30,7 @@ void arch::initialize()
log::register_sink(&uart_sink);

gdt.load();
idt.init();
idt.load();
isr_init();
}
3 changes: 3 additions & 0 deletions kernel/generic/include/bits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ template <typename B, typename T = B> class Bitfield
int shift_;
B mask_;
};

#define FLAG_SET(x, flag) x |= (flag)
#define FLAG_UNSET(x, flag) x &= ~(flag)
Loading