Compare commits
12 Commits
8141b9977d
...
23a2f8b903
Author | SHA1 | Date |
---|---|---|
Bananymous | 23a2f8b903 | |
Bananymous | 29fd682672 | |
Bananymous | efed67cbd0 | |
Bananymous | 6234a5bc0b | |
Bananymous | 54f64e7618 | |
Bananymous | f0105cb7fb | |
Bananymous | 76b0f80169 | |
Bananymous | f84df175ce | |
Bananymous | 58aca68726 | |
Bananymous | 8670364f44 | |
Bananymous | 418bc54f2b | |
Bananymous | 9c36d7c338 |
|
@ -0,0 +1,22 @@
|
|||
#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
|
|
@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.26)
|
|||
project(BAN CXX)
|
||||
|
||||
set(BAN_SOURCES
|
||||
BAN/Assert.cpp
|
||||
BAN/New.cpp
|
||||
BAN/String.cpp
|
||||
BAN/StringView.cpp
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Span.h>
|
||||
|
||||
|
@ -19,7 +18,7 @@ namespace BAN
|
|||
using const_iterator = ConstIteratorSimple<T, Array>;
|
||||
|
||||
public:
|
||||
Array();
|
||||
Array() = default;
|
||||
Array(const T&);
|
||||
|
||||
iterator begin() { return iterator(m_data); }
|
||||
|
@ -44,16 +43,9 @@ 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)
|
||||
{
|
||||
|
|
|
@ -1,33 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Traits.h>
|
||||
|
||||
#if defined(__is_kernel)
|
||||
#include <kernel/Panic.h>
|
||||
#define __ban_assert_stringify_helper(s) #s
|
||||
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
|
||||
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) \
|
||||
Kernel::panic("ASSERT(" #cond ") failed"); \
|
||||
} while (false)
|
||||
(__builtin_expect(!(cond), 0) \
|
||||
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
|
||||
: (void)0)
|
||||
|
||||
#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)
|
||||
#define ASSERT_NOT_REACHED() ASSERT(false)
|
||||
|
||||
#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
|
||||
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Move.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#if __is_kernel
|
||||
#error "This is userspace only file"
|
||||
#endif
|
||||
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <stdio.h>
|
||||
|
@ -29,3 +31,5 @@
|
|||
dprintln(__VA_ARGS__); \
|
||||
BAN::Formatter::print(__debug_putchar, "\e[m"); \
|
||||
} while(false)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#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; }
|
||||
|
|
|
@ -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,6 +136,7 @@ set(LAI_SOURCES
|
|||
)
|
||||
|
||||
set(BAN_SOURCES
|
||||
../BAN/BAN/Assert.cpp
|
||||
../BAN/BAN/New.cpp
|
||||
../BAN/BAN/String.cpp
|
||||
../BAN/BAN/StringView.cpp
|
||||
|
|
|
@ -1,68 +1,32 @@
|
|||
#include <BAN/Array.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace Kernel::GDT
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
struct TaskStateSegment
|
||||
GDT* GDT::create()
|
||||
{
|
||||
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));
|
||||
auto* gdt = new GDT();
|
||||
ASSERT(gdt);
|
||||
|
||||
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));
|
||||
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();
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
} __attribute__((packed));
|
||||
return gdt;
|
||||
}
|
||||
|
||||
} __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)
|
||||
void GDT::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);
|
||||
|
||||
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
|
||||
auto& desc = m_gdt[idx];
|
||||
desc.base1 = (base >> 0) & 0xFFFF;
|
||||
desc.base2 = (base >> 16) & 0xFF;
|
||||
desc.base3 = (base >> 24) & 0xFF;
|
||||
|
@ -75,49 +39,18 @@ namespace Kernel::GDT
|
|||
desc.flags = flags & 0x0F;
|
||||
}
|
||||
|
||||
static void write_tss()
|
||||
void GDT::write_tss()
|
||||
{
|
||||
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
|
||||
s_tss.iopb = sizeof(TaskStateSegment);
|
||||
memset(&m_tss, 0x00, sizeof(TaskStateSegment));
|
||||
m_tss.iopb = sizeof(TaskStateSegment);
|
||||
|
||||
uint64_t base = (uint64_t)&s_tss;
|
||||
uint64_t base = reinterpret_cast<uint64_t>(&m_tss);
|
||||
|
||||
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
write_entry(0x28, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
|
||||
|
||||
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
|
||||
auto& desc = m_gdt[0x30 / sizeof(SegmentDescriptor)];
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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::IDT
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
struct Registers
|
||||
|
@ -42,26 +42,6 @@ namespace Kernel::IDT
|
|||
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
|
||||
|
@ -163,6 +143,13 @@ namespace Kernel::IDT
|
|||
|
||||
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)
|
||||
|
@ -334,14 +321,9 @@ done:
|
|||
ASSERT(Thread::current().state() != Thread::State::Terminated);
|
||||
}
|
||||
|
||||
static void flush_idt()
|
||||
void IDT::register_interrupt_handler(uint8_t index, void (*handler)())
|
||||
{
|
||||
asm volatile("lidt %0"::"m"(s_idtr));
|
||||
}
|
||||
|
||||
static void register_interrupt_handler(uint8_t index, void(*handler)())
|
||||
{
|
||||
GateDescriptor& descriptor = s_idt[index];
|
||||
auto& descriptor = m_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);
|
||||
|
@ -351,13 +333,13 @@ done:
|
|||
descriptor.flags = 0x8E;
|
||||
}
|
||||
|
||||
static void register_syscall_handler(uint8_t index, void(*handler)())
|
||||
void IDT::register_syscall_handler(uint8_t index, void (*handler)())
|
||||
{
|
||||
register_interrupt_handler(index, handler);
|
||||
s_idt[index].flags = 0xEE;
|
||||
m_idt[index].flags = 0xEE;
|
||||
}
|
||||
|
||||
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
|
||||
void IDT::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());
|
||||
|
@ -374,34 +356,36 @@ done:
|
|||
|
||||
extern "C" void syscall_asm();
|
||||
|
||||
void initialize()
|
||||
IDT* IDT::create(bool is_bsb)
|
||||
{
|
||||
s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor));
|
||||
ASSERT(s_idt);
|
||||
memset(s_idt, 0x00, 0x100 * sizeof(GateDescriptor));
|
||||
auto* idt = new IDT();
|
||||
ASSERT(idt);
|
||||
|
||||
s_idtr.offset = (uint64_t)s_idt;
|
||||
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
|
||||
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
|
||||
|
||||
#define X(num) register_interrupt_handler(num, isr ## num);
|
||||
#define X(num) idt->register_interrupt_handler(num, isr ## num);
|
||||
ISR_LIST_X
|
||||
#undef X
|
||||
|
||||
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
// FIXME: distribute IRQs more evenly?
|
||||
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
|
||||
if (is_bsb)
|
||||
{
|
||||
IRQ_LIST_X
|
||||
}
|
||||
#undef X
|
||||
|
||||
register_syscall_handler(0x80, syscall_asm);
|
||||
idt->register_syscall_handler(0x80, syscall_asm);
|
||||
|
||||
flush_idt();
|
||||
return idt;
|
||||
}
|
||||
|
||||
[[noreturn]] void force_triple_fault()
|
||||
[[noreturn]] void IDT::force_triple_fault()
|
||||
{
|
||||
// load 0 sized IDT and trigger an interrupt to force triple fault
|
||||
asm volatile("cli");
|
||||
s_idtr.size = 0;
|
||||
flush_idt();
|
||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||
Processor::idt().m_idtr.size = 0;
|
||||
Processor::idt().load();
|
||||
asm volatile("int $0x00");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ 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;
|
||||
|
||||
|
@ -71,40 +70,51 @@ namespace Kernel
|
|||
void PageTable::initialize()
|
||||
{
|
||||
if (CPUID::has_nxe())
|
||||
{
|
||||
asm volatile(
|
||||
"movl $0xC0000080, %ecx;"
|
||||
"rdmsr;"
|
||||
"orl $0x800, %eax;"
|
||||
"wrmsr"
|
||||
);
|
||||
s_has_nxe = true;
|
||||
}
|
||||
|
||||
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;"
|
||||
);
|
||||
if (CPUID::has_pge())
|
||||
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->load();
|
||||
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();
|
||||
}
|
||||
|
||||
PageTable& PageTable::kernel()
|
||||
|
@ -113,12 +123,6 @@ 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))
|
||||
|
@ -208,7 +212,7 @@ namespace Kernel
|
|||
void PageTable::map_fast_page(paddr_t paddr)
|
||||
{
|
||||
ASSERT(s_kernel);
|
||||
ASSERT_NEQ(paddr, 0);
|
||||
ASSERT(paddr);
|
||||
|
||||
SpinLockGuard _(s_fast_page_lock);
|
||||
|
||||
|
@ -308,7 +312,7 @@ namespace Kernel
|
|||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
|
||||
s_current = this;
|
||||
Processor::set_current_page_table(this);
|
||||
}
|
||||
|
||||
void PageTable::invalidate(vaddr_t vaddr)
|
||||
|
@ -322,7 +326,7 @@ namespace Kernel
|
|||
ASSERT(vaddr);
|
||||
ASSERT(vaddr != fast_page());
|
||||
if (vaddr >= KERNEL_OFFSET)
|
||||
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
|
||||
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
|
||||
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
|
||||
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
|
||||
|
||||
|
@ -367,8 +371,6 @@ 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);
|
||||
|
||||
|
|
|
@ -158,13 +158,6 @@ 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
|
||||
|
@ -198,7 +191,6 @@ _start:
|
|||
movl %ebx, V2P(bootloader_info)
|
||||
|
||||
movl $V2P(boot_stack_top), %esp
|
||||
call initialize_lapic_id
|
||||
|
||||
call check_requirements
|
||||
call enable_sse
|
||||
|
@ -278,7 +270,6 @@ ap_protected_mode:
|
|||
|
||||
movl ap_stack_ptr, %esp
|
||||
movb $1, V2P(g_ap_stack_loaded)
|
||||
call V2P(initialize_lapic_id)
|
||||
|
||||
call V2P(enable_sse)
|
||||
|
||||
|
|
|
@ -78,5 +78,6 @@ namespace CPUID
|
|||
void get_features(uint32_t& ecx, uint32_t& edx);
|
||||
bool is_64_bit();
|
||||
bool has_nxe();
|
||||
bool has_pge();
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +1,101 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Kernel::GDT
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
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 initialize();
|
||||
void set_tss_stack(uintptr_t);
|
||||
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())
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,62 @@
|
|||
#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::IDT
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
void initialize();
|
||||
[[noreturn]] void force_triple_fault();
|
||||
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())
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/Input/PS2/Controller.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
|
||||
namespace Kernel::Input
|
||||
{
|
||||
|
|
|
@ -8,23 +8,6 @@
|
|||
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:
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#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 };
|
||||
};
|
||||
|
||||
}
|
|
@ -21,12 +21,12 @@ namespace Kernel
|
|||
{
|
||||
auto tid = Scheduler::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT_GT(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
while (!m_locker.compare_exchange(-1, tid))
|
||||
Scheduler::get().reschedule();
|
||||
ASSERT_EQ(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth == 0);
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
@ -35,20 +35,20 @@ namespace Kernel
|
|||
{
|
||||
auto tid = Scheduler::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT_GT(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
else
|
||||
{
|
||||
if (!m_locker.compare_exchange(-1, tid))
|
||||
return false;
|
||||
ASSERT_EQ(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth == 0);
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
ASSERT_EQ(m_locker.load(), Scheduler::current_tid());
|
||||
ASSERT_GT(m_lock_depth, 0);
|
||||
ASSERT(m_locker == Scheduler::current_tid());
|
||||
ASSERT(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_GT(m_lock_depth, 0);
|
||||
ASSERT(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_EQ(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth == 0);
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ namespace Kernel
|
|||
{
|
||||
auto tid = Scheduler::current_tid();
|
||||
if (tid == m_locker)
|
||||
ASSERT_GT(m_lock_depth, 0);
|
||||
ASSERT(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_EQ(m_lock_depth, 0);
|
||||
ASSERT(m_lock_depth == 0);
|
||||
}
|
||||
m_lock_depth++;
|
||||
}
|
||||
|
@ -107,8 +107,8 @@ namespace Kernel
|
|||
void unlock()
|
||||
{
|
||||
auto tid = Scheduler::current_tid();
|
||||
ASSERT_EQ(m_locker.load(), tid);
|
||||
ASSERT_GT(m_lock_depth, 0);
|
||||
ASSERT(m_locker == tid);
|
||||
ASSERT(m_lock_depth > 0);
|
||||
if (--m_lock_depth == 0)
|
||||
{
|
||||
bool has_priority = tid ? !Thread::current().is_userspace() : true;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Assert.h>
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/NoCopyMove.h>
|
||||
#include <kernel/Processor.h>
|
||||
|
@ -17,8 +18,32 @@ namespace Kernel
|
|||
public:
|
||||
SpinLock() = default;
|
||||
|
||||
InterruptState lock();
|
||||
void unlock(InterruptState state);
|
||||
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();
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::Atomic<ProcessorID> m_locker { PROCESSOR_NONE };
|
||||
|
@ -32,45 +57,44 @@ 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 is_locked() const { return m_locker != PROCESSOR_NONE; }
|
||||
bool current_processor_has_lock() const
|
||||
{
|
||||
return m_locker == Processor::current_id();
|
||||
}
|
||||
|
||||
private:
|
||||
BAN::Atomic<ProcessorID> m_locker { PROCESSOR_NONE };
|
||||
uint32_t m_lock_depth { 0 };
|
||||
};
|
||||
|
||||
template<typename Lock>
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Kernel
|
|||
static void initialize();
|
||||
|
||||
static PageTable& kernel();
|
||||
static PageTable& current();
|
||||
static PageTable& current() { return *reinterpret_cast<PageTable*>(Processor::get_current_page_table()); }
|
||||
|
||||
static constexpr vaddr_t fast_page() { return KERNEL_OFFSET; }
|
||||
|
||||
|
@ -109,6 +109,7 @@ 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); }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Networking/E1000/Definitions.h>
|
||||
#include <kernel/Networking/NetworkInterface.h>
|
||||
|
|
|
@ -2,28 +2,29 @@
|
|||
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
#define panic(...) detail::panic_impl(__FILE__, __LINE__, __VA_ARGS__)
|
||||
#define __panic_stringify_helper(s) #s
|
||||
#define __panic_stringify(s) __panic_stringify_helper(s)
|
||||
|
||||
namespace Kernel::detail
|
||||
#define panic(...) panic_impl(__FILE__ ":" __panic_stringify(__LINE__), __VA_ARGS__)
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
extern bool g_paniced;
|
||||
extern volatile bool g_paniced;
|
||||
|
||||
template<typename... Args>
|
||||
__attribute__((__noreturn__))
|
||||
static void panic_impl(const char* file, int line, const char* message, Args&&... args)
|
||||
static void panic_impl(const char* location, const char* message, Args&&... args)
|
||||
{
|
||||
asm volatile("cli");
|
||||
derrorln("Kernel panic at {}:{}", file, line);
|
||||
derrorln("Kernel panic at {}", location);
|
||||
derrorln(message, BAN::forward<Args>(args)...);
|
||||
if (!g_paniced)
|
||||
{
|
||||
g_paniced = true;
|
||||
Debug::dump_stack_trace();
|
||||
}
|
||||
for (;;)
|
||||
asm volatile("hlt");
|
||||
__builtin_unreachable();
|
||||
asm volatile("ud2");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/ForwardList.h>
|
||||
|
||||
#include <kernel/Arch.h>
|
||||
#include <kernel/GDT.h>
|
||||
#include <kernel/IDT.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
@ -19,20 +22,16 @@ 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()
|
||||
{
|
||||
uint16_t id;
|
||||
asm volatile("movw %%gs, %0" : "=rm"(id));
|
||||
return id;
|
||||
}
|
||||
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); }
|
||||
|
||||
static Processor& get(ProcessorID);
|
||||
|
||||
static Processor& current() { return get(current_id()); }
|
||||
static ProcessorID bsb_id() { return s_bsb_id; }
|
||||
static bool current_is_bsb() { return current_id() == bsb_id(); }
|
||||
|
||||
static void set_interrupt_state(InterruptState state)
|
||||
{
|
||||
|
@ -51,23 +50,71 @@ 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() + m_stack_size; }
|
||||
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); }
|
||||
|
||||
private:
|
||||
Processor() = default;
|
||||
Processor(Processor&& other)
|
||||
~Processor() { ASSERT_NOT_REACHED(); }
|
||||
|
||||
template<typename T>
|
||||
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
|
||||
{
|
||||
m_stack = other.m_stack;
|
||||
other.m_stack = nullptr;
|
||||
#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
|
||||
}
|
||||
~Processor();
|
||||
|
||||
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); }
|
||||
|
||||
private:
|
||||
void* m_stack { nullptr };
|
||||
static constexpr size_t m_stack_size { 4096 };
|
||||
static ProcessorID s_bsb_id;
|
||||
|
||||
friend class BAN::Vector<Processor>;
|
||||
ProcessorID m_id { PROCESSOR_NONE };
|
||||
|
||||
static constexpr size_t s_stack_size { 4096 };
|
||||
void* m_stack { nullptr };
|
||||
|
||||
GDT* m_gdt { nullptr };
|
||||
IDT* m_idt { nullptr };
|
||||
|
||||
void* m_current_page_table { nullptr };
|
||||
|
||||
friend class BAN::Array<Processor, 0xFF>;
|
||||
};
|
||||
#else
|
||||
#error
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace Kernel
|
|||
Semaphore* semaphore;
|
||||
};
|
||||
|
||||
SpinLockUnsafe m_lock;
|
||||
SpinLock m_lock;
|
||||
|
||||
Thread* m_idle_thread { nullptr };
|
||||
BAN::LinkedList<SchedulerThread> m_active_threads;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <BAN/Array.h>
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/PCI.h>
|
||||
#include <kernel/Storage/ATA/AHCI/Definitions.h>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <BAN/ByteSpan.h>
|
||||
#include <BAN/RefPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
|
||||
namespace Kernel
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
#include <kernel/Memory/DMARegion.h>
|
||||
#include <kernel/Semaphore.h>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <BAN/CircularQueue.h>
|
||||
#include <BAN/Errors.h>
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
|
||||
namespace Kernel
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Lock/SpinLock.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/InterruptController.h>
|
||||
#include <kernel/Interruptable.h>
|
||||
#include <kernel/Timer/Timer.h>
|
||||
|
||||
namespace Kernel
|
||||
|
|
|
@ -31,6 +31,35 @@ 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;
|
||||
|
@ -208,7 +237,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) & (1 << 12))
|
||||
while ((read_from_local_apic(LAPIC_ICR_LO_REG) & ICR_LO_delivery_status_send_pending) == ICR_LO_delivery_status_send_pending)
|
||||
__builtin_ia32_pause();
|
||||
};
|
||||
|
||||
|
@ -232,31 +261,55 @@ namespace Kernel
|
|||
|
||||
dprintln("Trying to enable processor (lapic id {})", processor.apic_id);
|
||||
|
||||
Kernel::Processor::create(processor.processor_id);
|
||||
|
||||
auto& proc = Kernel::Processor::create(processor.apic_id);
|
||||
PageTable::with_fast_page((paddr_t)g_ap_init_addr, [&] {
|
||||
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(Kernel::Processor::get(processor.processor_id).stack_top());
|
||||
PageTable::fast_page_as_sized<uint32_t>(2) = V2P(proc.stack_top());
|
||||
});
|
||||
*g_ap_stack_loaded = 0;
|
||||
|
||||
write_to_local_apic(LAPIC_ERROR_REG, 0x00);
|
||||
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);
|
||||
|
||||
// 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
|
||||
|
||||
udelay(10 * 1000);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
write_to_local_apic(LAPIC_ERROR_REG, 0x00);
|
||||
send_ipi(processor.processor_id, (read_from_local_apic(LAPIC_ICR_LO_REG) & 0xFFF0F800) | 0x00000600 | ap_init_page, 200);
|
||||
|
||||
// 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
|
||||
);
|
||||
}
|
||||
|
||||
// give processor upto 100 * 100 us (10 ms to boot)
|
||||
// give processor upto 100 * 100 us + 200 us 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,13 @@ 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)
|
||||
|
|
|
@ -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_EQ(inode_info.nlink, 0);
|
||||
ASSERT(inode_info.nlink == 0);
|
||||
for (auto paddr : inode_info.block)
|
||||
ASSERT_EQ(paddr, 0);
|
||||
ASSERT(paddr == 0);
|
||||
inode_info = {};
|
||||
});
|
||||
ASSERT(!m_inode_cache.contains(ino));
|
||||
|
@ -166,8 +166,8 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
ASSERT_GTE(ino, first_inode);
|
||||
ASSERT_LT(ino, max_inodes);
|
||||
ASSERT(ino >= first_inode);
|
||||
ASSERT(ino < max_inodes);
|
||||
|
||||
constexpr size_t inodes_per_page = PAGE_SIZE / sizeof(TmpInodeInfo);
|
||||
|
||||
|
@ -220,7 +220,7 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
ASSERT_GT(index, 0);
|
||||
ASSERT(index > 0);
|
||||
return find_indirect(m_data_pages, index - first_data_page, 3);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include <kernel/Debug.h>
|
||||
#include <kernel/Input/KeyEvent.h>
|
||||
#include <kernel/Input/PS2/Keymap.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace Kernel::Input
|
||||
{
|
||||
|
||||
|
|
|
@ -8,29 +8,8 @@
|
|||
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);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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_EQ(&PageTable::current(), &m_page_table);
|
||||
ASSERT(&PageTable::current() == &m_page_table);
|
||||
auto read_ret = m_inode->read(file_offset, BAN::ByteSpan((uint8_t*)vaddr, bytes));
|
||||
|
||||
if (read_ret.is_error())
|
||||
|
|
|
@ -158,9 +158,9 @@ namespace Kernel
|
|||
return;
|
||||
|
||||
// Verify no overflow
|
||||
ASSERT_LTE(bytes, size());
|
||||
ASSERT_LTE(offset, size());
|
||||
ASSERT_LTE(offset, size() - bytes);
|
||||
ASSERT(bytes <= size());
|
||||
ASSERT(offset <= size());
|
||||
ASSERT(offset <= size() - bytes);
|
||||
|
||||
if (&PageTable::current() == &m_page_table || &PageTable::kernel() == &m_page_table)
|
||||
{
|
||||
|
|
|
@ -259,7 +259,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> E1000::send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
ASSERT_LTE(buffer.size() + sizeof(EthernetHeader), E1000_TX_BUFFER_SIZE);
|
||||
ASSERT(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_LTE((uint16_t)descriptor.length, E1000_RX_BUFFER_SIZE);
|
||||
ASSERT(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),
|
||||
|
|
|
@ -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_LTE(acknowledged_bytes, m_send_window.data_size);
|
||||
ASSERT(acknowledged_bytes <= m_send_window.data_size);
|
||||
|
||||
m_send_window.data_size -= acknowledged_bytes;
|
||||
m_send_window.start_seq += acknowledged_bytes;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <kernel/Panic.h>
|
||||
|
||||
namespace Kernel::detail
|
||||
namespace Kernel
|
||||
{
|
||||
bool g_paniced = false;
|
||||
volatile bool g_paniced = false;
|
||||
}
|
||||
|
|
|
@ -1,34 +1,70 @@
|
|||
#include <BAN/Vector.h>
|
||||
#include <kernel/Memory/kmalloc.h>
|
||||
#include <kernel/Processor.h>
|
||||
|
||||
#include <kernel/Debug.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static BAN::Vector<Processor> s_processors;
|
||||
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;
|
||||
}
|
||||
|
||||
Processor& Processor::create(ProcessorID id)
|
||||
{
|
||||
while (s_processors.size() <= id)
|
||||
MUST(s_processors.emplace_back());
|
||||
// bsb is the first processor
|
||||
if (s_bsb_id == PROCESSOR_NONE)
|
||||
s_bsb_id = id = read_processor_id();
|
||||
|
||||
auto& processor = s_processors[id];
|
||||
if (processor.m_stack == nullptr)
|
||||
{
|
||||
processor.m_stack = kmalloc(m_stack_size, 4096, true);
|
||||
|
||||
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()
|
||||
Processor& Processor::initialize()
|
||||
{
|
||||
if (m_stack)
|
||||
kfree(m_stack);
|
||||
m_stack = nullptr;
|
||||
}
|
||||
auto id = read_processor_id();
|
||||
auto& processor = s_processors[id];
|
||||
|
||||
Processor& Processor::get(ProcessorID id)
|
||||
{
|
||||
return 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();
|
||||
|
||||
return processor;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 m_lock.unlock(state);
|
||||
return Processor::set_interrupt_state(state);
|
||||
advance_current_thread();
|
||||
execute_current_thread_locked();
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -86,7 +86,7 @@ namespace Kernel
|
|||
if (m_active_threads.empty() || ¤t_thread() != m_idle_thread)
|
||||
return m_lock.unlock(state);
|
||||
if (save_current_thread())
|
||||
return m_lock.unlock(state);
|
||||
return Processor::set_interrupt_state(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.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
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.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
if (m_active_threads.empty())
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::remove_and_advance_current_thread()
|
||||
{
|
||||
ASSERT(m_lock.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
ASSERT(m_current_thread);
|
||||
|
||||
|
@ -158,7 +158,7 @@ namespace Kernel
|
|||
// after getting the rsp
|
||||
ALWAYS_INLINE bool Scheduler::save_current_thread()
|
||||
{
|
||||
ASSERT(m_lock.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
uintptr_t rsp, rip;
|
||||
push_callee_saved();
|
||||
|
@ -209,7 +209,7 @@ namespace Kernel
|
|||
|
||||
void Scheduler::execute_current_thread_locked()
|
||||
{
|
||||
ASSERT(m_lock.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
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.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
#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();
|
||||
GDT::set_tss_stack(current->interrupt_stack_base() + current->interrupt_stack_size());
|
||||
Processor::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.is_locked());
|
||||
ASSERT(m_lock.current_processor_has_lock());
|
||||
|
||||
if (save_current_thread())
|
||||
return;
|
||||
|
@ -307,16 +307,18 @@ namespace Kernel
|
|||
|
||||
void Scheduler::set_current_thread_sleeping(uint64_t wake_time)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
auto state = m_lock.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)
|
||||
{
|
||||
SpinLockGuard _(m_lock);
|
||||
auto state = m_lock.lock();
|
||||
m_current_thread->semaphore = semaphore;
|
||||
set_current_thread_sleeping_impl(wake_time);
|
||||
Processor::set_interrupt_state(state);
|
||||
}
|
||||
|
||||
void Scheduler::unblock_threads(Semaphore* semaphore)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#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>
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace Kernel
|
|||
// Signal mask is inherited
|
||||
|
||||
// Setup stack for returning
|
||||
ASSERT_EQ(m_rsp % PAGE_SIZE, 0u);
|
||||
ASSERT(m_rsp % PAGE_SIZE == 0);
|
||||
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_EQ(m_rsp % PAGE_SIZE, 0u);
|
||||
ASSERT(m_rsp % PAGE_SIZE == 0);
|
||||
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
|
||||
|
|
|
@ -102,16 +102,12 @@ 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(Processor::current_id());
|
||||
Processor::create(0);
|
||||
Processor::initialize();
|
||||
dprintln("BSP initialized");
|
||||
|
||||
GDT::initialize();
|
||||
dprintln("GDT initialized");
|
||||
|
||||
IDT::initialize();
|
||||
dprintln("IDT initialized");
|
||||
|
||||
PageTable::initialize();
|
||||
PageTable::kernel().initial_load();
|
||||
dprintln("PageTable initialized");
|
||||
|
||||
Heap::initialize();
|
||||
|
@ -129,8 +125,6 @@ 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");
|
||||
|
||||
|
@ -143,6 +137,8 @@ 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");
|
||||
|
||||
|
@ -215,8 +211,11 @@ extern "C" void ap_main()
|
|||
{
|
||||
using namespace Kernel;
|
||||
|
||||
dprintln("hello from processor {}", Processor::current_id());
|
||||
Processor::initialize();
|
||||
PageTable::kernel().initial_load();
|
||||
|
||||
dprintln("ap{} initialized", Processor::current_id());
|
||||
|
||||
for (;;)
|
||||
asm volatile("");
|
||||
asm volatile("hlt");
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ set(LIBC_SOURCES
|
|||
unistd.cpp
|
||||
math.S
|
||||
icxxabi.cpp
|
||||
|
||||
../BAN/BAN/Assert.cpp
|
||||
)
|
||||
|
||||
add_custom_target(libc-headers
|
||||
|
|
Loading…
Reference in New Issue