Compare commits

..

No commits in common. "23a2f8b90314b9597640e5bc2ed8fc2b6277e8f7" and "8141b9977d283e7fbf5c62aad36ede5b1fa59e7a" have entirely different histories.

49 changed files with 470 additions and 646 deletions

View File

@ -1,22 +0,0 @@
#include <BAN/Assert.h>
#if __is_kernel
#include <kernel/Panic.h>
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
{
Kernel::panic_impl(location, msg);
}
#else
#include <BAN/Debug.h>
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
{
derrorln("{}: {}", location, msg);
__builtin_trap();
}
#endif

View File

@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.26)
project(BAN CXX)
set(BAN_SOURCES
BAN/Assert.cpp
BAN/New.cpp
BAN/String.cpp
BAN/StringView.cpp

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Iterators.h>
#include <BAN/Span.h>
@ -18,7 +19,7 @@ namespace BAN
using const_iterator = ConstIteratorSimple<T, Array>;
public:
Array() = default;
Array();
Array(const T&);
iterator begin() { return iterator(m_data); }
@ -43,9 +44,16 @@ namespace BAN
T* data() { return m_data; }
private:
T m_data[S] {};
T m_data[S];
};
template<typename T, size_t S>
Array<T, S>::Array()
{
for (size_type i = 0; i < S; i++)
m_data[i] = T();
}
template<typename T, size_t S>
Array<T, S>::Array(const T& value)
{

View File

@ -1,13 +1,33 @@
#pragma once
#define __ban_assert_stringify_helper(s) #s
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
#include <BAN/Traits.h>
#if defined(__is_kernel)
#include <kernel/Panic.h>
#define ASSERT(cond) \
(__builtin_expect(!(cond), 0) \
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
: (void)0)
do { \
if (!(cond)) \
Kernel::panic("ASSERT(" #cond ") failed"); \
} while (false)
#define ASSERT_NOT_REACHED() ASSERT(false)
#define __ASSERT_BIN_OP(lhs, rhs, name, op) \
do { \
auto&& _lhs = (lhs); \
auto&& _rhs = (rhs); \
if (!(_lhs op _rhs)) \
Kernel::panic(name "(" #lhs ", " #rhs ") ({} " #op " {}) failed", _lhs, _rhs); \
} while (false)
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
#define ASSERT_LT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LT", <)
#define ASSERT_LTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LTE", <=)
#define ASSERT_GT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GT", >)
#define ASSERT_GTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GTE", >=)
#define ASSERT_EQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_EQ", ==)
#define ASSERT_NEQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_NEQ", !=)
#define ASSERT_NOT_REACHED() Kernel::panic("ASSERT_NOT_REACHED() failed")
#else
#include <assert.h>
#define ASSERT(cond) assert((cond) && "ASSERT("#cond") failed")
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
#endif

View File

@ -1,7 +1,6 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Move.h>
#include <BAN/PlacementNew.h>
#include <stdint.h>

View File

@ -1,10 +1,8 @@
#pragma once
#if __is_kernel
#include <kernel/Debug.h>
#else
#error "This is userspace only file"
#endif
#include <BAN/Formatter.h>
#include <stdio.h>
@ -31,5 +29,3 @@
dprintln(__VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m"); \
} while(false)
#endif

View File

@ -1,6 +1,4 @@
#pragma once
#include <stddef.h>
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }

View File

@ -40,9 +40,9 @@ set(KERNEL_SOURCES
kernel/Input/PS2/Keyboard.cpp
kernel/Input/PS2/Keymap.cpp
kernel/Input/PS2/Mouse.cpp
kernel/Interruptable.cpp
kernel/InterruptController.cpp
kernel/kernel.cpp
kernel/Lock/SpinLock.cpp
kernel/Memory/DMARegion.cpp
kernel/Memory/FileBackedRegion.cpp
kernel/Memory/Heap.cpp
@ -136,7 +136,6 @@ set(LAI_SOURCES
)
set(BAN_SOURCES
../BAN/BAN/Assert.cpp
../BAN/BAN/New.cpp
../BAN/BAN/String.cpp
../BAN/BAN/StringView.cpp

View File

@ -1,32 +1,68 @@
#include <BAN/Array.h>
#include <kernel/GDT.h>
#include <kernel/Debug.h>
#include <string.h>
namespace Kernel
namespace Kernel::GDT
{
GDT* GDT::create()
struct TaskStateSegment
{
auto* gdt = new GDT();
ASSERT(gdt);
uint32_t reserved1;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved2;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved3;
uint16_t reserved4;
uint16_t iopb;
} __attribute__((packed));
gdt->write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
gdt->write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
gdt->write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
gdt->write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
gdt->write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
gdt->write_tss();
union SegmentDescriptor
{
struct
{
uint16_t limit1;
uint16_t base1;
uint8_t base2;
uint8_t access;
uint8_t limit2 : 4;
uint8_t flags : 4;
uint8_t base3;
} __attribute__((packed));
return gdt;
}
struct
{
uint32_t low;
uint32_t high;
} __attribute__((packed));
void GDT::write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
} __attribute__((packed));
struct GDTR
{
uint16_t size;
uint64_t address;
} __attribute__((packed));
static constexpr uint16_t s_tss_offset = 0x28;
static TaskStateSegment s_tss;
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
static GDTR s_gdtr;
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
uint8_t idx = offset / sizeof(SegmentDescriptor);
auto& desc = m_gdt[idx];
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
desc.base1 = (base >> 0) & 0xFFFF;
desc.base2 = (base >> 16) & 0xFF;
desc.base3 = (base >> 24) & 0xFF;
@ -39,18 +75,49 @@ namespace Kernel
desc.flags = flags & 0x0F;
}
void GDT::write_tss()
static void write_tss()
{
memset(&m_tss, 0x00, sizeof(TaskStateSegment));
m_tss.iopb = sizeof(TaskStateSegment);
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
s_tss.iopb = sizeof(TaskStateSegment);
uint64_t base = reinterpret_cast<uint64_t>(&m_tss);
uint64_t base = (uint64_t)&s_tss;
write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)];
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
desc.low = base >> 32;
desc.high = 0;
}
void set_tss_stack(uintptr_t rsp)
{
s_tss.rsp0 = rsp;
}
static void flush_gdt()
{
asm volatile("lgdt %0" :: "m"(s_gdtr));
}
static void flush_tss()
{
asm volatile("ltr %0" :: "m"(s_tss_offset));
}
void initialize()
{
s_gdtr.address = (uint64_t)&s_gdt;
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
write_tss();
flush_gdt();
flush_tss();
}
}

View File

@ -12,7 +12,7 @@
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
namespace Kernel
namespace Kernel::IDT
{
struct Registers
@ -42,6 +42,26 @@ namespace Kernel
uint64_t rax;
};
struct GateDescriptor
{
uint16_t offset1;
uint16_t selector;
uint8_t IST;
uint8_t flags;
uint16_t offset2;
uint32_t offset3;
uint32_t reserved;
} __attribute__((packed));
struct IDTR
{
uint16_t size;
uint64_t offset;
} __attribute__((packed));
static IDTR s_idtr;
static GateDescriptor* s_idt = nullptr;
#define X(num) 1 +
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
#undef X
@ -143,13 +163,6 @@ namespace Kernel
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
{
if (g_paniced)
{
// FIXME: tell other processors kernel panic has occured
dprintln("Processor {} halted", Processor::current_id());
asm volatile("cli; 1: hlt; jmp 1b");
}
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
@ -321,9 +334,14 @@ done:
ASSERT(Thread::current().state() != Thread::State::Terminated);
}
void IDT::register_interrupt_handler(uint8_t index, void (*handler)())
static void flush_idt()
{
auto& descriptor = m_idt[index];
asm volatile("lidt %0"::"m"(s_idtr));
}
static void register_interrupt_handler(uint8_t index, void(*handler)())
{
GateDescriptor& descriptor = s_idt[index];
descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
@ -333,13 +351,13 @@ done:
descriptor.flags = 0x8E;
}
void IDT::register_syscall_handler(uint8_t index, void (*handler)())
static void register_syscall_handler(uint8_t index, void(*handler)())
{
register_interrupt_handler(index, handler);
m_idt[index].flags = 0xEE;
s_idt[index].flags = 0xEE;
}
void IDT::register_irq_handler(uint8_t irq, Interruptable* interruptable)
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
{
if (irq > s_interruptables.size())
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
@ -356,36 +374,34 @@ done:
extern "C" void syscall_asm();
IDT* IDT::create(bool is_bsb)
void initialize()
{
auto* idt = new IDT();
ASSERT(idt);
s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor));
ASSERT(s_idt);
memset(s_idt, 0x00, 0x100 * sizeof(GateDescriptor));
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
s_idtr.offset = (uint64_t)s_idt;
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
#define X(num) idt->register_interrupt_handler(num, isr ## num);
#define X(num) register_interrupt_handler(num, isr ## num);
ISR_LIST_X
#undef X
// FIXME: distribute IRQs more evenly?
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
if (is_bsb)
{
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
IRQ_LIST_X
}
#undef X
idt->register_syscall_handler(0x80, syscall_asm);
register_syscall_handler(0x80, syscall_asm);
return idt;
flush_idt();
}
[[noreturn]] void IDT::force_triple_fault()
[[noreturn]] void force_triple_fault()
{
// load 0 sized IDT and trigger an interrupt to force triple fault
Processor::set_interrupt_state(InterruptState::Disabled);
Processor::idt().m_idtr.size = 0;
Processor::idt().load();
asm volatile("cli");
s_idtr.size = 0;
flush_idt();
asm volatile("int $0x00");
ASSERT_NOT_REACHED();
}

View File

@ -20,6 +20,7 @@ namespace Kernel
RecursiveSpinLock PageTable::s_fast_page_lock;
static PageTable* s_kernel = nullptr;
static PageTable* s_current = nullptr;
static bool s_has_nxe = false;
static bool s_has_pge = false;
@ -70,51 +71,40 @@ namespace Kernel
void PageTable::initialize()
{
if (CPUID::has_nxe())
{
asm volatile(
"movl $0xC0000080, %ecx;"
"rdmsr;"
"orl $0x800, %eax;"
"wrmsr"
);
s_has_nxe = true;
}
if (CPUID::has_pge())
uint32_t ecx, edx;
CPUID::get_features(ecx, edx);
if (edx & CPUID::EDX_PGE)
{
asm volatile(
"movq %cr4, %rax;"
"orq $0x80, %rax;"
"movq %rax, %cr4;"
);
s_has_pge = true;
}
// enable write protect to kernel
asm volatile(
"movq %cr0, %rax;"
"orq $0x10000, %rax;"
"movq %rax, %cr0;"
);
ASSERT(s_kernel == nullptr);
s_kernel = new PageTable();
ASSERT(s_kernel);
s_kernel->initialize_kernel();
s_kernel->initial_load();
}
void PageTable::initial_load()
{
if (s_has_nxe)
{
asm volatile(
"movl $0xC0000080, %%ecx;"
"rdmsr;"
"orl $0x800, %%eax;"
"wrmsr"
::: "eax", "ecx", "edx", "memory"
);
}
if (s_has_pge)
{
asm volatile(
"movq %%cr4, %%rax;"
"orq $0x80, %%rax;"
"movq %%rax, %%cr4;"
::: "rax"
);
}
// enable write protect
asm volatile(
"movq %%cr0, %%rax;"
"orq $0x10000, %%rax;"
"movq %%rax, %%cr0;"
::: "rax"
);
load();
s_kernel->load();
}
PageTable& PageTable::kernel()
@ -123,6 +113,12 @@ namespace Kernel
return *s_kernel;
}
PageTable& PageTable::current()
{
ASSERT(s_current);
return *s_current;
}
bool PageTable::is_valid_pointer(uintptr_t pointer)
{
if (!is_canonical(pointer))
@ -212,7 +208,7 @@ namespace Kernel
void PageTable::map_fast_page(paddr_t paddr)
{
ASSERT(s_kernel);
ASSERT(paddr);
ASSERT_NEQ(paddr, 0);
SpinLockGuard _(s_fast_page_lock);
@ -312,7 +308,7 @@ namespace Kernel
{
SpinLockGuard _(m_lock);
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
Processor::set_current_page_table(this);
s_current = this;
}
void PageTable::invalidate(vaddr_t vaddr)
@ -326,7 +322,7 @@ namespace Kernel
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET)
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
@ -371,6 +367,8 @@ namespace Kernel
{
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET && s_current)
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);

View File

@ -158,6 +158,13 @@ enable_sse:
movl %eax, %cr4
ret
initialize_lapic_id:
movl $1, %eax
cpuid
shrl $24, %ebx
movw %bx, %gs
ret
initialize_paging:
# enable PAE
movl %cr4, %ecx
@ -191,6 +198,7 @@ _start:
movl %ebx, V2P(bootloader_info)
movl $V2P(boot_stack_top), %esp
call initialize_lapic_id
call check_requirements
call enable_sse
@ -270,6 +278,7 @@ ap_protected_mode:
movl ap_stack_ptr, %esp
movb $1, V2P(g_ap_stack_loaded)
call V2P(initialize_lapic_id)
call V2P(enable_sse)

View File

@ -78,6 +78,5 @@ namespace CPUID
void get_features(uint32_t& ecx, uint32_t& edx);
bool is_64_bit();
bool has_nxe();
bool has_pge();
}

View File

@ -1,101 +1,16 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/NoCopyMove.h>
#include <stdint.h>
namespace Kernel
namespace Kernel::GDT
{
struct TaskStateSegment
{
uint32_t reserved1;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved2;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved3;
uint16_t reserved4;
uint16_t iopb;
} __attribute__((packed));
union SegmentDescriptor
{
struct
{
uint16_t limit1;
uint16_t base1;
uint8_t base2;
uint8_t access;
uint8_t limit2 : 4;
uint8_t flags : 4;
uint8_t base3;
} __attribute__((packed));
struct
{
uint32_t low;
uint32_t high;
} __attribute__((packed));
} __attribute__((packed));
struct GDTR
{
uint16_t size;
uint64_t address;
} __attribute__((packed));
class GDT
{
BAN_NON_COPYABLE(GDT);
BAN_NON_MOVABLE(GDT);
public:
static GDT* create();
void load() { flush_gdt(); flush_tss(); }
static constexpr inline bool is_user_segment(uint8_t segment)
{
return (segment & 3) == 3;
}
void set_tss_stack(uintptr_t rsp)
{
m_tss.rsp0 = rsp;
}
private:
GDT() = default;
void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags);
void write_tss();
void flush_gdt()
{
asm volatile("lgdt %0" :: "m"(m_gdtr) : "memory");
}
void flush_tss()
{
asm volatile("ltr %0" :: "rm"((uint16_t)0x28) : "memory");
}
private:
BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
TaskStateSegment m_tss;
const GDTR m_gdtr {
.size = m_gdt.size() * sizeof(SegmentDescriptor) - 1,
.address = reinterpret_cast<uint64_t>(m_gdt.data())
};
};
void initialize();
void set_tss_stack(uintptr_t);
}

View File

@ -1,62 +1,13 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/NoCopyMove.h>
#include <kernel/Interruptable.h>
#include <stdint.h>
constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
namespace Kernel
namespace Kernel::IDT
{
struct GateDescriptor
{
uint16_t offset1;
uint16_t selector;
uint8_t IST;
uint8_t flags;
uint16_t offset2;
uint32_t offset3;
uint32_t reserved;
} __attribute__((packed));
struct IDTR
{
uint16_t size;
uint64_t offset;
} __attribute__((packed));
class IDT
{
BAN_NON_COPYABLE(IDT);
BAN_NON_MOVABLE(IDT);
public:
static IDT* create(bool is_bsb);
[[noreturn]] static void force_triple_fault();
void register_irq_handler(uint8_t irq, Interruptable* interruptable);
void load()
{
asm volatile("lidt %0" :: "m"(m_idtr) : "memory");
}
private:
IDT() = default;
void register_interrupt_handler(uint8_t index, void (*handler)());
void register_syscall_handler(uint8_t index, void (*handler)());
private:
BAN::Array<GateDescriptor, 0x100> m_idt;
IDTR m_idtr {
.size = m_idt.size() * sizeof(GateDescriptor) - 1,
.offset = reinterpret_cast<uint64_t>(m_idt.data())
};
};
void initialize();
[[noreturn]] void force_triple_fault();
}

View File

@ -1,7 +1,7 @@
#pragma once
#include <kernel/Input/PS2/Controller.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
namespace Kernel::Input
{

View File

@ -8,6 +8,23 @@
namespace Kernel
{
class Interruptable
{
public:
void set_irq(int irq);
void enable_interrupt();
void disable_interrupt();
virtual void handle_irq() = 0;
protected:
Interruptable() = default;
~Interruptable() {}
private:
int m_irq { -1 };
};
class InterruptController
{
public:

View File

@ -1,23 +0,0 @@
#pragma once
namespace Kernel
{
class Interruptable
{
public:
void set_irq(int irq);
void enable_interrupt();
void disable_interrupt();
virtual void handle_irq() = 0;
protected:
Interruptable() = default;
~Interruptable() {}
private:
int m_irq { -1 };
};
}

View File

@ -21,12 +21,12 @@ namespace Kernel
{
auto tid = Scheduler::current_tid();
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
ASSERT_GT(m_lock_depth, 0);
else
{
while (!m_locker.compare_exchange(-1, tid))
Scheduler::get().reschedule();
ASSERT(m_lock_depth == 0);
ASSERT_EQ(m_lock_depth, 0);
}
m_lock_depth++;
}
@ -35,20 +35,20 @@ namespace Kernel
{
auto tid = Scheduler::current_tid();
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
ASSERT_GT(m_lock_depth, 0);
else
{
if (!m_locker.compare_exchange(-1, tid))
return false;
ASSERT(m_lock_depth == 0);
ASSERT_EQ(m_lock_depth, 0);
}
m_lock_depth++;
}
void unlock()
{
ASSERT(m_locker == Scheduler::current_tid());
ASSERT(m_lock_depth > 0);
ASSERT_EQ(m_locker.load(), Scheduler::current_tid());
ASSERT_GT(m_lock_depth, 0);
if (--m_lock_depth == 0)
m_locker = -1;
}
@ -74,7 +74,7 @@ namespace Kernel
{
auto tid = Scheduler::current_tid();
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
ASSERT_GT(m_lock_depth, 0);
else
{
bool has_priority = tid ? !Thread::current().is_userspace() : true;
@ -82,7 +82,7 @@ namespace Kernel
m_queue_length++;
while (!(has_priority || m_queue_length == 0) || !m_locker.compare_exchange(-1, tid))
Scheduler::get().reschedule();
ASSERT(m_lock_depth == 0);
ASSERT_EQ(m_lock_depth, 0);
}
m_lock_depth++;
}
@ -91,7 +91,7 @@ namespace Kernel
{
auto tid = Scheduler::current_tid();
if (tid == m_locker)
ASSERT(m_lock_depth > 0);
ASSERT_GT(m_lock_depth, 0);
else
{
bool has_priority = tid ? !Thread::current().is_userspace() : true;
@ -99,7 +99,7 @@ namespace Kernel
return false;
if (has_priority)
m_queue_length++;
ASSERT(m_lock_depth == 0);
ASSERT_EQ(m_lock_depth, 0);
}
m_lock_depth++;
}
@ -107,8 +107,8 @@ namespace Kernel
void unlock()
{
auto tid = Scheduler::current_tid();
ASSERT(m_locker == tid);
ASSERT(m_lock_depth > 0);
ASSERT_EQ(m_locker.load(), tid);
ASSERT_GT(m_lock_depth, 0);
if (--m_lock_depth == 0)
{
bool has_priority = tid ? !Thread::current().is_userspace() : true;

View File

@ -1,6 +1,5 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Atomic.h>
#include <BAN/NoCopyMove.h>
#include <kernel/Processor.h>
@ -18,32 +17,8 @@ namespace Kernel
public:
SpinLock() = default;
InterruptState lock()
{
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
auto id = Processor::current_id();
ASSERT(m_locker != id);
while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
__builtin_ia32_pause();
return state;
}
void unlock(InterruptState state)
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
ASSERT(m_locker == Processor::current_id());
m_locker.store(PROCESSOR_NONE, BAN::MemoryOrder::memory_order_release);
Processor::set_interrupt_state(state);
}
bool current_processor_has_lock() const
{
return m_locker == Processor::current_id();
}
InterruptState lock();
void unlock(InterruptState state);
private:
BAN::Atomic<ProcessorID> m_locker { PROCESSOR_NONE };
@ -57,44 +32,45 @@ namespace Kernel
public:
RecursiveSpinLock() = default;
InterruptState lock();
void unlock(InterruptState state);
private:
BAN::Atomic<ProcessorID> m_locker { PROCESSOR_NONE };
uint32_t m_lock_depth { 0 };
};
class SpinLockUnsafe
{
BAN_NON_COPYABLE(SpinLockUnsafe);
BAN_NON_MOVABLE(SpinLockUnsafe);
public:
SpinLockUnsafe() = default;
InterruptState lock()
{
auto id = Processor::current_id();
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
auto id = Processor::current_id();
if (m_locker == id)
ASSERT(m_lock_depth > 0);
else
{
while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
__builtin_ia32_pause();
ASSERT(m_lock_depth == 0);
}
m_lock_depth++;
return state;
}
void unlock(InterruptState state)
{
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
ASSERT(m_locker == Processor::current_id());
ASSERT(m_lock_depth > 0);
if (--m_lock_depth == 0)
m_locker.store(PROCESSOR_NONE, BAN::MemoryOrder::memory_order_release);
Processor::set_interrupt_state(state);
}
bool current_processor_has_lock() const
{
return m_locker == Processor::current_id();
}
bool is_locked() const { return m_locker != PROCESSOR_NONE; }
private:
BAN::Atomic<ProcessorID> m_locker { PROCESSOR_NONE };
uint32_t m_lock_depth { 0 };
};
template<typename Lock>

View File

@ -40,7 +40,7 @@ namespace Kernel
static void initialize();
static PageTable& kernel();
static PageTable& current() { return *reinterpret_cast<PageTable*>(Processor::get_current_page_table()); }
static PageTable& current();
static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; }
@ -109,7 +109,6 @@ namespace Kernel
vaddr_t reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
void load();
void initial_load();
InterruptState lock() const { return m_lock.lock(); }
void unlock(InterruptState state) const { m_lock.unlock(state); }

View File

@ -1,7 +1,7 @@
#pragma once
#include <BAN/UniqPtr.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/Networking/E1000/Definitions.h>
#include <kernel/Networking/NetworkInterface.h>

View File

@ -2,29 +2,28 @@
#include <kernel/Debug.h>
#define __panic_stringify_helper(s) #s
#define __panic_stringify(s) __panic_stringify_helper(s)
#define panic(...) detail::panic_impl(__FILE__, __LINE__, __VA_ARGS__)
#define panic(...) panic_impl(__FILE__ ":" __panic_stringify(__LINE__), __VA_ARGS__)
namespace Kernel
namespace Kernel::detail
{
extern volatile bool g_paniced;
extern bool g_paniced;
template<typename... Args>
__attribute__((__noreturn__))
static void panic_impl(const char* location, const char* message, Args&&... args)
static void panic_impl(const char* file, int line, const char* message, Args&&... args)
{
asm volatile("cli");
derrorln("Kernel panic at {}", location);
derrorln("Kernel panic at {}:{}", file, line);
derrorln(message, BAN::forward<Args>(args)...);
if (!g_paniced)
{
g_paniced = true;
Debug::dump_stack_trace();
}
asm volatile("ud2");
for (;;)
asm volatile("hlt");
__builtin_unreachable();
}
}

View File

@ -1,10 +1,7 @@
#pragma once
#include <BAN/ForwardList.h>
#include <kernel/Arch.h>
#include <kernel/GDT.h>
#include <kernel/IDT.h>
namespace Kernel
{
@ -22,16 +19,20 @@ namespace Kernel
class Processor
{
BAN_NON_COPYABLE(Processor);
BAN_NON_MOVABLE(Processor);
public:
static Processor& create(ProcessorID id);
static Processor& initialize();
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); }
static ProcessorID current_id()
{
uint16_t id;
asm volatile("movw %%gs, %0" : "=rm"(id));
return id;
}
static ProcessorID bsb_id() { return s_bsb_id; }
static bool current_is_bsb() { return current_id() == bsb_id(); }
static Processor& get(ProcessorID);
static Processor& current() { return get(current_id()); }
static void set_interrupt_state(InterruptState state)
{
@ -50,71 +51,23 @@ namespace Kernel
return InterruptState::Disabled;
};
static uintptr_t current_stack_bottom() { return reinterpret_cast<uintptr_t>(read_gs_ptr(offsetof(Processor, m_stack))); }
static uintptr_t current_stack_top() { return current_stack_bottom() + s_stack_size; }
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
uintptr_t stack_top() const { return stack_bottom() + s_stack_size; }
static GDT& gdt() { return *reinterpret_cast<GDT*>(read_gs_ptr(offsetof(Processor, m_gdt))); }
static IDT& idt() { return *reinterpret_cast<IDT*>(read_gs_ptr(offsetof(Processor, m_idt))); }
static void* get_current_page_table() { return read_gs_ptr(offsetof(Processor, m_current_page_table)); }
static void set_current_page_table(void* page_table) { write_gs_ptr(offsetof(Processor, m_current_page_table), page_table); }
uintptr_t stack_top() const { return stack_bottom() + m_stack_size; }
private:
Processor() = default;
~Processor() { ASSERT_NOT_REACHED(); }
template<typename T>
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
Processor(Processor&& other)
{
#define __ASM_INPUT(operation) operation " %%gs:(%[offset]), %[result]" : [result]"=rm"(result) : [offset]"rm"(offset)
T result;
if constexpr(sizeof(T) == 8)
asm volatile(__ASM_INPUT("movq"));
if constexpr(sizeof(T) == 4)
asm volatile(__ASM_INPUT("movl"));
if constexpr(sizeof(T) == 2)
asm volatile(__ASM_INPUT("movw"));
if constexpr(sizeof(T) == 1)
asm volatile(__ASM_INPUT("movb"));
return result;
#undef __ASM_INPUT
m_stack = other.m_stack;
other.m_stack = nullptr;
}
template<typename T>
static void write_gs_sized(uintptr_t offset, T value) requires(sizeof(T) <= 8)
{
#define __ASM_INPUT(operation) operation " %[value], %%gs:(%[offset])" :: [value]"rm"(value), [offset]"rm"(offset) : "memory"
if constexpr(sizeof(T) == 8)
asm volatile(__ASM_INPUT("movq"));
if constexpr(sizeof(T) == 4)
asm volatile(__ASM_INPUT("movl"));
if constexpr(sizeof(T) == 2)
asm volatile(__ASM_INPUT("movw"));
if constexpr(sizeof(T) == 1)
asm volatile(__ASM_INPUT("movb"));
#undef __ASM_INPUT
}
static void* read_gs_ptr(uintptr_t offset) { return read_gs_sized<void*>(offset); }
static void write_gs_ptr(uintptr_t offset, void* value) { write_gs_sized<void*>(offset, value); }
~Processor();
private:
static ProcessorID s_bsb_id;
ProcessorID m_id { PROCESSOR_NONE };
static constexpr size_t s_stack_size { 4096 };
void* m_stack { nullptr };
static constexpr size_t m_stack_size { 4096 };
GDT* m_gdt { nullptr };
IDT* m_idt { nullptr };
void* m_current_page_table { nullptr };
friend class BAN::Array<Processor, 0xFF>;
friend class BAN::Vector<Processor>;
};
#else
#error

View File

@ -62,7 +62,7 @@ namespace Kernel
Semaphore* semaphore;
};
SpinLock m_lock;
SpinLockUnsafe m_lock;
Thread* m_idle_thread { nullptr };
BAN::LinkedList<SchedulerThread> m_active_threads;

View File

@ -2,7 +2,7 @@
#include <BAN/Array.h>
#include <BAN/RefPtr.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/PCI.h>
#include <kernel/Storage/ATA/AHCI/Definitions.h>

View File

@ -3,7 +3,7 @@
#include <BAN/ByteSpan.h>
#include <BAN/RefPtr.h>
#include <BAN/Vector.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel

View File

@ -2,7 +2,7 @@
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/DMARegion.h>
#include <kernel/Semaphore.h>

View File

@ -2,7 +2,7 @@
#include <BAN/CircularQueue.h>
#include <BAN/Errors.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Terminal/TTY.h>
namespace Kernel

View File

@ -1,6 +1,6 @@
#pragma once
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Timer/Timer.h>

View File

@ -1,6 +1,6 @@
#pragma once
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Timer/Timer.h>
namespace Kernel

View File

@ -31,35 +31,6 @@ extern volatile uint8_t g_ap_stack_loaded[];
namespace Kernel
{
enum ICR_LO : uint32_t
{
ICR_LO_reserved_mask = 0xFFF32000,
ICR_LO_delivery_mode_fixed = 0b000 << 8,
ICR_LO_delivery_mode_lowest_priority = 0b001 << 8,
ICR_LO_delivery_mode_smi = 0b010 << 8,
ICR_LO_delivery_mode_nmi = 0b100 << 8,
ICR_LO_delivery_mode_init = 0b101 << 8,
ICR_LO_delivery_mode_start_up = 0b110 << 8,
ICR_LO_destination_mode_physical = 0 << 11,
ICR_LO_destination_mode_logical = 1 << 11,
ICR_LO_delivery_status_idle = 0 << 12,
ICR_LO_delivery_status_send_pending = 1 << 12,
ICR_LO_level_deassert = 0 << 14,
ICR_LO_level_assert = 1 << 14,
ICR_LO_trigger_mode_edge = 0 << 15,
ICR_LO_trigger_mode_level = 1 << 15,
ICR_LO_destination_shorthand_none = 0b00 << 18,
ICR_LO_destination_shorthand_self = 0b01 << 18,
ICR_LO_destination_shorthand_all_including_self = 0b10 << 18,
ICR_LO_destination_shorthand_all_excluding_self = 0b11 << 18,
};
struct MADT : public Kernel::ACPI::SDTHeader
{
uint32_t local_apic;
@ -237,7 +208,7 @@ namespace Kernel
write_to_local_apic(LAPIC_ICR_HI_REG, (read_from_local_apic(LAPIC_ICR_HI_REG) & 0x00FFFFFF) | (processor << 24));
write_to_local_apic(LAPIC_ICR_LO_REG, data);
udelay(ud);
while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending)
while (read_from_local_apic(LAPIC_ICR_LO_REG) & (1 << 12))
__builtin_ia32_pause();
};
@ -261,55 +232,31 @@ namespace Kernel
dprintln("Trying to enable processor (lapic id {})", processor.apic_id);
auto& proc = Kernel::Processor::create(processor.apic_id);
Kernel::Processor::create(processor.processor_id);
PageTable::with_fast_page((paddr_t)g_ap_init_addr, [&] {
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(proc.stack_top());
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(Kernel::Processor::get(processor.processor_id).stack_top());
});
*g_ap_stack_loaded = 0;
write_to_local_apic(LAPIC_ERROR_REG, 0x00);
// send INIT IPI
send_ipi(processor.apic_id,
(read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_reserved_mask)
| ICR_LO_delivery_mode_init
| ICR_LO_destination_mode_physical
| ICR_LO_level_assert
| ICR_LO_trigger_mode_edge
| ICR_LO_destination_shorthand_none
, 0
);
// TODO: If we are on processor predating Pentium, we need to send deassert
send_ipi(processor.processor_id, (read_from_local_apic(LAPIC_ICR_LO_REG) & 0xFFF00000) | 0x0000C500, 0);
send_ipi(processor.processor_id, (read_from_local_apic(LAPIC_ICR_LO_REG) & 0xFFF0F800) | 0x00008500, 0);
udelay(10 * 1000);
for (int i = 0; i < 2; i++)
{
write_to_local_apic(LAPIC_ERROR_REG, 0x00);
// send 2 SETUP IPIs with 200 us delay
send_ipi(processor.apic_id,
(read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_reserved_mask)
| ICR_LO_delivery_mode_start_up
| ICR_LO_destination_mode_physical
| ICR_LO_level_assert
| ICR_LO_trigger_mode_edge
| ICR_LO_destination_shorthand_none
| ap_init_page
, 200
);
send_ipi(processor.processor_id, (read_from_local_apic(LAPIC_ICR_LO_REG) & 0xFFF0F800) | 0x00000600 | ap_init_page, 200);
}
// give processor upto 100 * 100 us + 200 us to boot
// give processor upto 100 * 100 us (10 ms to boot)
for (int i = 0; *g_ap_stack_loaded == 0 && i < 100; i++)
udelay(100);
}
*g_ap_startup_done = 1;
// give processors 100 us time to increment running count
udelay(100);
dprintln("{} processors started", *g_ap_running_count);
}

View File

@ -50,13 +50,6 @@ namespace CPUID
return buffer[3] & (1 << 20);
}
bool has_pge()
{
uint32_t ecx, edx;
get_features(ecx, edx);
return edx & CPUID::EDX_PGE;
}
const char* feature_string_ecx(uint32_t feat)
{
switch (feat)

View File

@ -128,9 +128,9 @@ namespace Kernel
auto inode_location = find_inode(ino);
PageTable::with_fast_page(inode_location.paddr, [&] {
auto& inode_info = PageTable::fast_page_as_sized<TmpInodeInfo>(inode_location.index);
ASSERT(inode_info.nlink == 0);
ASSERT_EQ(inode_info.nlink, 0);
for (auto paddr : inode_info.block)
ASSERT(paddr == 0);
ASSERT_EQ(paddr, 0);
inode_info = {};
});
ASSERT(!m_inode_cache.contains(ino));
@ -166,8 +166,8 @@ namespace Kernel
{
LockGuard _(m_mutex);
ASSERT(ino >= first_inode);
ASSERT(ino < max_inodes);
ASSERT_GTE(ino, first_inode);
ASSERT_LT(ino, max_inodes);
constexpr size_t inodes_per_page = PAGE_SIZE / sizeof(TmpInodeInfo);
@ -220,7 +220,7 @@ namespace Kernel
{
LockGuard _(m_mutex);
ASSERT(index > 0);
ASSERT_GT(index, 0);
return find_indirect(m_data_pages, index - first_data_page, 3);
}

View File

@ -1,9 +1,6 @@
#include <kernel/Debug.h>
#include <kernel/Input/KeyEvent.h>
#include <kernel/Input/PS2/Keymap.h>
#include <string.h>
namespace Kernel::Input
{

View File

@ -8,8 +8,29 @@
namespace Kernel
{
namespace IDT { void register_irq_handler(uint8_t irq, Interruptable*); }
static InterruptController* s_instance = nullptr;
void Interruptable::set_irq(int irq)
{
if (m_irq != -1)
IDT::register_irq_handler(m_irq, nullptr);
m_irq = irq;
IDT::register_irq_handler(irq, this);
}
void Interruptable::enable_interrupt()
{
ASSERT(m_irq != -1);
InterruptController::get().enable_irq(m_irq);
}
void Interruptable::disable_interrupt()
{
ASSERT_NOT_REACHED();
}
InterruptController& InterruptController::get()
{
ASSERT(s_instance);

View File

@ -1,28 +0,0 @@
#include <kernel/IDT.h>
#include <kernel/Interruptable.h>
#include <kernel/InterruptController.h>
#include <kernel/Processor.h>
namespace Kernel
{
void Interruptable::set_irq(int irq)
{
if (m_irq != -1)
Processor::idt().register_irq_handler(m_irq, nullptr);
m_irq = irq;
Processor::idt().register_irq_handler(irq, this);
}
void Interruptable::enable_interrupt()
{
ASSERT(m_irq != -1);
InterruptController::get().enable_irq(m_irq);
}
void Interruptable::disable_interrupt()
{
ASSERT_NOT_REACHED();
}
}

View File

@ -0,0 +1,61 @@
#include <kernel/InterruptController.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Scheduler.h>
// FIXME: try to move these to header
namespace Kernel
{
InterruptState SpinLock::lock()
{
auto id = Processor::current_id();
ASSERT_NEQ(m_locker.load(), id);
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
__builtin_ia32_pause();
return state;
}
void SpinLock::unlock(InterruptState state)
{
ASSERT_EQ(m_locker.load(), Processor::current_id());
m_locker.store(PROCESSOR_NONE, BAN::MemoryOrder::memory_order_release);
Processor::set_interrupt_state(state);
}
InterruptState RecursiveSpinLock::lock()
{
auto id = Processor::current_id();
auto state = Processor::get_interrupt_state();
Processor::set_interrupt_state(InterruptState::Disabled);
if (id == m_locker)
ASSERT_GT(m_lock_depth, 0);
else
{
while (!m_locker.compare_exchange(PROCESSOR_NONE, id, BAN::MemoryOrder::memory_order_acquire))
__builtin_ia32_pause();
ASSERT_EQ(m_lock_depth, 0);
}
m_lock_depth++;
return state;
}
void RecursiveSpinLock::unlock(InterruptState state)
{
ASSERT_EQ(m_locker.load(), Processor::current_id());
ASSERT_GT(m_lock_depth, 0);
if (--m_lock_depth == 0)
m_locker.store(PROCESSOR_NONE, BAN::MemoryOrder::memory_order_release);
Processor::set_interrupt_state(state);
}
}

View File

@ -129,7 +129,7 @@ namespace Kernel
size_t file_offset = m_offset + (vaddr - m_vaddr);
size_t bytes = BAN::Math::min<size_t>(m_size - file_offset, PAGE_SIZE);
ASSERT(&PageTable::current() == &m_page_table);
ASSERT_EQ(&PageTable::current(), &m_page_table);
auto read_ret = m_inode->read(file_offset, BAN::ByteSpan((uint8_t*)vaddr, bytes));
if (read_ret.is_error())

View File

@ -158,9 +158,9 @@ namespace Kernel
return;
// Verify no overflow
ASSERT(bytes <= size());
ASSERT(offset <= size());
ASSERT(offset <= size() - bytes);
ASSERT_LTE(bytes, size());
ASSERT_LTE(offset, size());
ASSERT_LTE(offset, size() - bytes);
if (&PageTable::current() == &m_page_table || &PageTable::kernel() == &m_page_table)
{

View File

@ -259,7 +259,7 @@ namespace Kernel
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
{
ASSERT(buffer.size() + sizeof(EthernetHeader) <= E1000_TX_BUFFER_SIZE);
ASSERT_LTE(buffer.size() + sizeof(EthernetHeader), E1000_TX_BUFFER_SIZE);
SpinLockGuard _(m_lock);
@ -299,7 +299,7 @@ namespace Kernel
auto& descriptor = reinterpret_cast<volatile e1000_rx_desc*>(m_rx_descriptor_region->vaddr())[rx_current];
if (!(descriptor.status & 1))
break;
ASSERT(descriptor.length <= E1000_RX_BUFFER_SIZE);
ASSERT_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + rx_current * E1000_RX_BUFFER_SIZE),

View File

@ -455,7 +455,7 @@ namespace Kernel
if (m_send_window.data_size > 0 && m_send_window.current_ack - m_send_window.has_ghost_byte > m_send_window.start_seq)
{
uint32_t acknowledged_bytes = m_send_window.current_ack - m_send_window.start_seq - m_send_window.has_ghost_byte;
ASSERT(acknowledged_bytes <= m_send_window.data_size);
ASSERT_LTE(acknowledged_bytes, m_send_window.data_size);
m_send_window.data_size -= acknowledged_bytes;
m_send_window.start_seq += acknowledged_bytes;

View File

@ -1,6 +1,6 @@
#include <kernel/Panic.h>
namespace Kernel
namespace Kernel::detail
{
volatile bool g_paniced = false;
bool g_paniced = false;
}

View File

@ -1,70 +1,34 @@
#include <kernel/Memory/kmalloc.h>
#include <BAN/Vector.h>
#include <kernel/Processor.h>
#include <kernel/Debug.h>
namespace Kernel
{
static constexpr uint32_t MSR_IA32_GS_BASE = 0xC0000101;
ProcessorID Processor::s_bsb_id { PROCESSOR_NONE };
static BAN::Array<Processor, 0xFF> s_processors;
static ProcessorID read_processor_id()
{
uint8_t id;
asm volatile(
"movl $1, %%eax;"
"cpuid;"
"shrl $24, %%ebx;"
"movb %%bl, %0;"
: "=rm"(id)
:: "eax", "ebx", "ecx", "edx"
);
return id;
}
static BAN::Vector<Processor> s_processors;
Processor& Processor::create(ProcessorID id)
{
// bsb is the first processor
if (s_bsb_id == PROCESSOR_NONE)
s_bsb_id = id = read_processor_id();
while (s_processors.size() <= id)
MUST(s_processors.emplace_back());
auto& processor = s_processors[id];
ASSERT(processor.m_id == PROCESSOR_NONE);
processor.m_id = id;
processor.m_stack = kmalloc(s_stack_size, 4096, true);
ASSERT(processor.m_stack);
processor.m_gdt = GDT::create();
ASSERT(processor.m_gdt);
processor.m_idt = IDT::create(id == s_bsb_id);
ASSERT(processor.m_idt);
return processor;
}
Processor& Processor::initialize()
if (processor.m_stack == nullptr)
{
auto id = read_processor_id();
auto& processor = s_processors[id];
// set gs base to pointer to this processor
uint64_t ptr = reinterpret_cast<uint64_t>(&processor);
asm volatile("wrmsr" :: "d"(ptr >> 32), "a"(ptr), "c"(MSR_IA32_GS_BASE));
ASSERT(processor.m_gdt);
processor.gdt().load();
ASSERT(processor.m_idt);
processor.idt().load();
processor.m_stack = kmalloc(m_stack_size, 4096, true);
ASSERT(processor.m_stack);
}
return processor;
}
Processor::~Processor()
{
if (m_stack)
kfree(m_stack);
m_stack = nullptr;
}
Processor& Processor::get(ProcessorID id)
{
return s_processors[id];
}
}

View File

@ -18,7 +18,7 @@ namespace Kernel
ALWAYS_INLINE static void load_temp_stack()
{
asm volatile("movq %0, %%rsp" :: "rm"(Processor::current_stack_top()));
asm volatile("movq %0, %%rsp" :: "rm"(Processor::current().stack_top()));
}
BAN::ErrorOr<void> Scheduler::initialize()
@ -64,7 +64,7 @@ namespace Kernel
auto state = m_lock.lock();
wake_threads();
if (save_current_thread())
return Processor::set_interrupt_state(state);
return m_lock.unlock(state);
advance_current_thread();
execute_current_thread_locked();
ASSERT_NOT_REACHED();
@ -86,7 +86,7 @@ namespace Kernel
if (m_active_threads.empty() || &current_thread() != m_idle_thread)
return m_lock.unlock(state);
if (save_current_thread())
return Processor::set_interrupt_state(state);
return m_lock.unlock(state);
m_current_thread = m_active_threads.begin();
execute_current_thread_locked();
ASSERT_NOT_REACHED();
@ -94,7 +94,7 @@ namespace Kernel
void Scheduler::wake_threads()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
uint64_t current_time = SystemTimer::get().ms_since_boot();
while (!m_sleeping_threads.empty() && m_sleeping_threads.front().wake_time <= current_time)
@ -124,7 +124,7 @@ namespace Kernel
void Scheduler::advance_current_thread()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
if (m_active_threads.empty())
{
@ -137,7 +137,7 @@ namespace Kernel
void Scheduler::remove_and_advance_current_thread()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
ASSERT(m_current_thread);
@ -158,7 +158,7 @@ namespace Kernel
// after getting the rsp
ALWAYS_INLINE bool Scheduler::save_current_thread()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
uintptr_t rsp, rip;
push_callee_saved();
@ -209,7 +209,7 @@ namespace Kernel
void Scheduler::execute_current_thread_locked()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
load_temp_stack();
PageTable::kernel().load();
execute_current_thread_stack_loaded();
@ -218,12 +218,12 @@ namespace Kernel
NEVER_INLINE void Scheduler::execute_current_thread_stack_loaded()
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
#if SCHEDULER_VERIFY_STACK
vaddr_t rsp;
read_rsp(rsp);
ASSERT(Processor::current_stack_bottom() <= rsp && rsp <= Processor::current_stack_top());
ASSERT(Processor::current().stack_bottom() <= rsp && rsp <= Processor::current().stack_top());
ASSERT(&PageTable::current() == &PageTable::kernel());
#endif
@ -256,7 +256,7 @@ namespace Kernel
if (current->has_process())
{
current->process().page_table().load();
Processor::gdt().set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size());
GDT::set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size());
}
else
PageTable::kernel().load();
@ -281,7 +281,7 @@ namespace Kernel
void Scheduler::set_current_thread_sleeping_impl(uint64_t wake_time)
{
ASSERT(m_lock.current_processor_has_lock());
ASSERT(m_lock.is_locked());
if (save_current_thread())
return;
@ -307,18 +307,16 @@ namespace Kernel
void Scheduler::set_current_thread_sleeping(uint64_t wake_time)
{
auto state = m_lock.lock();
SpinLockGuard _(m_lock);
m_current_thread->semaphore = nullptr;
set_current_thread_sleeping_impl(wake_time);
Processor::set_interrupt_state(state);
}
void Scheduler::block_current_thread(Semaphore* semaphore, uint64_t wake_time)
{
auto state = m_lock.lock();
SpinLockGuard _(m_lock);
m_current_thread->semaphore = semaphore;
set_current_thread_sleeping_impl(wake_time);
Processor::set_interrupt_state(state);
}
void Scheduler::unblock_threads(Semaphore* semaphore)

View File

@ -1,5 +1,4 @@
#include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/InterruptController.h>
#include <kernel/Storage/ATA/AHCI/Controller.h>
#include <kernel/Storage/ATA/ATABus.h>
#include <kernel/Storage/ATA/ATAController.h>

View File

@ -170,7 +170,7 @@ namespace Kernel
// Signal mask is inherited
// Setup stack for returning
ASSERT(m_rsp % PAGE_SIZE == 0);
ASSERT_EQ(m_rsp % PAGE_SIZE, 0u);
PageTable::with_fast_page(process().page_table().physical_address_of(m_rsp - PAGE_SIZE), [&] {
uintptr_t rsp = PageTable::fast_page() + PAGE_SIZE;
write_to_stack(rsp, nullptr); // alignment
@ -199,7 +199,7 @@ namespace Kernel
m_signal_pending_mask = 0;
m_signal_block_mask = ~0ull;
ASSERT(m_rsp % PAGE_SIZE == 0);
ASSERT_EQ(m_rsp % PAGE_SIZE, 0u);
PageTable::with_fast_page(process().page_table().physical_address_of(m_rsp - PAGE_SIZE), [&] {
uintptr_t rsp = PageTable::fast_page() + PAGE_SIZE;
write_to_stack(rsp, nullptr); // alignment

View File

@ -102,12 +102,16 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
parse_boot_info(boot_magic, boot_info);
dprintln("boot info parsed");
Processor::create(0);
Processor::initialize();
Processor::create(Processor::current_id());
dprintln("BSP initialized");
GDT::initialize();
dprintln("GDT initialized");
IDT::initialize();
dprintln("IDT initialized");
PageTable::initialize();
PageTable::kernel().initial_load();
dprintln("PageTable initialized");
Heap::initialize();
@ -125,6 +129,8 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
SystemTimer::initialize(cmdline.force_pic);
dprintln("Timers initialized");
InterruptController::get().initialize_multiprocessor();
DevFileSystem::initialize();
dprintln("devfs initialized");
@ -137,8 +143,6 @@ extern "C" void kernel_main(uint32_t boot_magic, uint32_t boot_info)
if (g_terminal_driver)
dprintln("Framebuffer terminal initialized");
InterruptController::get().initialize_multiprocessor();
ProcFileSystem::initialize();
dprintln("procfs initialized");
@ -211,11 +215,8 @@ extern "C" void ap_main()
{
using namespace Kernel;
Processor::initialize();
PageTable::kernel().initial_load();
dprintln("ap{} initialized", Processor::current_id());
dprintln("hello from processor {}", Processor::current_id());
for (;;)
asm volatile("hlt");
asm volatile("");
}

View File

@ -30,8 +30,6 @@ set(LIBC_SOURCES
unistd.cpp
math.S
icxxabi.cpp
../BAN/BAN/Assert.cpp
)
add_custom_target(libc-headers