summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--GNUmakefile6
-rw-r--r--kernel/src/arch/aarch64/aarch64.cpp4
-rw-r--r--kernel/src/arch/riscv64/riscv64.cpp4
-rw-r--r--kernel/src/arch/x86_64/cpu/gdt.cpp3
-rw-r--r--kernel/src/arch/x86_64/cpu/idt.asm2
-rw-r--r--kernel/src/arch/x86_64/cpu/idt.cpp33
-rw-r--r--kernel/src/arch/x86_64/cpu/lapic.cpp61
-rw-r--r--kernel/src/arch/x86_64/cpu/lapic.hpp51
-rw-r--r--kernel/src/arch/x86_64/cpu/sse.cpp133
-rw-r--r--kernel/src/arch/x86_64/cpu/sse.hpp33
-rw-r--r--kernel/src/arch/x86_64/cpu/xapic.hpp10
-rw-r--r--kernel/src/arch/x86_64/cpu_local.hpp4
-rw-r--r--kernel/src/arch/x86_64/drivers/pci.cpp54
-rw-r--r--kernel/src/arch/x86_64/drivers/pci.hpp57
-rw-r--r--kernel/src/arch/x86_64/drivers/serial.cpp48
-rw-r--r--kernel/src/arch/x86_64/drivers/serial.hpp14
-rw-r--r--kernel/src/arch/x86_64/drivers/tsc.cpp3
-rw-r--r--kernel/src/arch/x86_64/irq.cpp3
-rw-r--r--kernel/src/arch/x86_64/panic.cpp4
-rw-r--r--kernel/src/arch/x86_64/schedule_timer.asm46
-rw-r--r--kernel/src/arch/x86_64/schedule_timer.cpp58
-rw-r--r--kernel/src/arch/x86_64/schedule_timer.hpp8
-rw-r--r--kernel/src/arch/x86_64/scheduling.asm36
-rw-r--r--kernel/src/arch/x86_64/x86_64.cpp28
-rw-r--r--kernel/src/drivers/disk.hpp10
-rw-r--r--kernel/src/drivers/nvme.cpp528
-rw-r--r--kernel/src/drivers/nvme.hpp184
-rw-r--r--kernel/src/drivers/powerbutton.cpp28
-rw-r--r--kernel/src/drivers/powerbutton.hpp6
-rw-r--r--kernel/src/drivers/uacpi_kernel_api.cpp30
-rw-r--r--kernel/src/generic/arch.hpp5
-rw-r--r--kernel/src/generic/bootloader/bootloader.hpp1
-rw-r--r--kernel/src/generic/bootloader/limine.cpp5
-rw-r--r--kernel/src/generic/bootloader/limine.hpp1
-rw-r--r--kernel/src/generic/heap.cpp2
-rw-r--r--kernel/src/generic/lock/spinlock.hpp5
-rw-r--r--kernel/src/generic/mp.cpp66
-rw-r--r--kernel/src/generic/mp.hpp15
-rw-r--r--kernel/src/generic/poweroff.cpp51
-rw-r--r--kernel/src/generic/poweroff.hpp6
-rw-r--r--kernel/src/generic/scheduling.cpp80
-rw-r--r--kernel/src/generic/scheduling.hpp64
-rw-r--r--kernel/src/klibc/stdio.cpp11
-rw-r--r--kernel/src/klibc/string.cpp27
-rw-r--r--kernel/src/main.cpp34
-rw-r--r--kernel/src/utils/assert.hpp6
-rw-r--r--kernel/src/utils/cxx/cxx_stuff.cpp44
-rw-r--r--kernel/src/utils/errno.hpp136
-rw-r--r--kernel/src/utils/signal.hpp119
50 files changed, 2058 insertions, 112 deletions
diff --git a/.gitignore b/.gitignore
index 08e066e..7df8ca1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/limine
/edk2-ovmf
*.iso
-*.hdd \ No newline at end of file
+*.hdd
+disk.img \ No newline at end of file
diff --git a/GNUmakefile b/GNUmakefile
index 97c4632..e777f1f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -5,7 +5,7 @@
ARCH := x86_64
# Default user QEMU flags. These are appended to the QEMU command calls.
-QEMUFLAGS := -m 256M -d int -no-reboot
+QEMUFLAGS := -m 256M -d int -no-reboot -serial stdio
override IMAGE_NAME := orange-$(ARCH)
@@ -30,9 +30,9 @@ run-hdd: run-hdd-$(ARCH)
.PHONY: run-x86_64
run-x86_64: edk2-ovmf $(IMAGE_NAME).iso
- qemu-system-$(ARCH) \
- -enable-kvm \
+ qemu-system-$(ARCH) \
-M q35 \
+ -enable-kvm -cpu host,+x2apic,+la57 \
-drive if=pflash,unit=0,format=raw,file=edk2-ovmf/ovmf-code-$(ARCH).fd,readonly=on \
-cdrom $(IMAGE_NAME).iso \
$(QEMUFLAGS)
diff --git a/kernel/src/arch/aarch64/aarch64.cpp b/kernel/src/arch/aarch64/aarch64.cpp
index 3992ad7..52003f8 100644
--- a/kernel/src/arch/aarch64/aarch64.cpp
+++ b/kernel/src/arch/aarch64/aarch64.cpp
@@ -52,6 +52,10 @@ namespace arch {
return 4;
}
+ [[gnu::weak]] void memory_barrier() {
+ asm volatile("" ::: "memory");
+ }
+
[[gnu::weak]] void init(int stage) {
switch(stage) {
case ARCH_INIT_EARLY:
diff --git a/kernel/src/arch/riscv64/riscv64.cpp b/kernel/src/arch/riscv64/riscv64.cpp
index 2db83bf..784cc94 100644
--- a/kernel/src/arch/riscv64/riscv64.cpp
+++ b/kernel/src/arch/riscv64/riscv64.cpp
@@ -16,6 +16,10 @@ namespace arch {
asm volatile("wfi");
}
+ [[gnu::weak]] void memory_barrier() {
+ asm volatile("" ::: "memory");
+ }
+
[[gnu::weak]] void hcf() {
disable_interrupts();
while(true) {
diff --git a/kernel/src/arch/x86_64/cpu/gdt.cpp b/kernel/src/arch/x86_64/cpu/gdt.cpp
index dd406f2..0498c21 100644
--- a/kernel/src/arch/x86_64/cpu/gdt.cpp
+++ b/kernel/src/arch/x86_64/cpu/gdt.cpp
@@ -46,6 +46,7 @@ void x86_64::gdt::init() {
auto cpudata = x86_64::cpu_data();
cpudata->timer_ist_stack = (std::uint64_t)(pmm::buddy::alloc(KERNEL_STACK_SIZE).phys + etc::hhdm());
- klibc::printf("GDT: tss->rsp0 0x%p tss->ist0 0x%p\r\n",tss->rsp[0],tss->ist[0],tss->ist[1],tss->ist[2],tss->ist[3],cpudata->timer_ist_stack);
+ static bool is_print = 0;
+ if(!is_print) { klibc::printf("GDT: tss->rsp0 0x%p tss->ist0 0x%p\r\n",tss->rsp[0],tss->ist[0],tss->ist[1],tss->ist[2],tss->ist[3],cpudata->timer_ist_stack); is_print = 1; }
} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/cpu/idt.asm b/kernel/src/arch/x86_64/cpu/idt.asm
index 78bed7e..deb0164 100644
--- a/kernel/src/arch/x86_64/cpu/idt.asm
+++ b/kernel/src/arch/x86_64/cpu/idt.asm
@@ -194,7 +194,7 @@ irqStub:
push rax
mov rdi,rsp
xor rbp,rbp
- nop
+ call irqHandler
pop rax
mov cr3,rax
pop rax
diff --git a/kernel/src/arch/x86_64/cpu/idt.cpp b/kernel/src/arch/x86_64/cpu/idt.cpp
index 19cbbcf..c62b1e6 100644
--- a/kernel/src/arch/x86_64/cpu/idt.cpp
+++ b/kernel/src/arch/x86_64/cpu/idt.cpp
@@ -4,6 +4,7 @@
#include <utils/bitmap.hpp>
#include <klibc/stdio.hpp>
#include <arch/x86_64/cpu/lapic.hpp>
+#include <utils/assert.hpp>
x86_64::idt::idt_entry_t idt_entries[255];
utils::bitmap* idt_bitmap;
@@ -12,29 +13,37 @@ x86_64::idt::idtr_t idtr;
extern "C" void* isrTable[];
extern "C" void ignoreStubC() {
+ assert(0,"ignore stub");
x86_64::lapic::eoi();
+
}
void x86_64::idt::init() {
- klibc::memset(idt_entries,0,sizeof(idt_entries));
- idt_bitmap = new utils::bitmap(255);
- idtr.base = (std::uint64_t)idt_entries;
- idtr.limit = (std::uint16_t)sizeof(idt_entry_t) * 256 - 1;
+ static bool is_print = 0;
- for(uint8_t vec = 0;vec <32;vec++){
- set_entry((std::uint64_t)isrTable[vec],vec,0x8E,1);
- }
+ if(!is_print) {
+ klibc::memset(idt_entries,0,sizeof(idt_entries));
+ idt_bitmap = new utils::bitmap(255);
+
+ idtr.base = (std::uint64_t)idt_entries;
+ idtr.limit = (std::uint16_t)sizeof(idt_entry_t) * 256 - 1;
+
+ for(uint8_t vec = 0;vec <32;vec++){
+ set_entry((std::uint64_t)isrTable[vec],vec,0x8E,1);
+ }
+
+ for(uint8_t vec = 32; vec < 255; vec++) {
+ set_entry((std::uint64_t)ignoreStub,vec,0x8E,4);
+ idt_bitmap->clear(vec);
+ }
- for(uint8_t vec = 32; vec < 255; vec++) {
- set_entry((std::uint64_t)ignoreStub,vec,0x8E,4);
- idt_bitmap->clear(vec);
+ idt_bitmap->set(32);
}
- idt_bitmap->set(32);
load();
- klibc::printf("IDT: IDTR is 0x%p\r\n",&idtr);
+ if(!is_print) {klibc::printf("IDT: IDTR is 0x%p\r\n",&idtr); is_print = 1;}
}
void x86_64::idt::load() {
diff --git a/kernel/src/arch/x86_64/cpu/lapic.cpp b/kernel/src/arch/x86_64/cpu/lapic.cpp
new file mode 100644
index 0000000..3bea37c
--- /dev/null
+++ b/kernel/src/arch/x86_64/cpu/lapic.cpp
@@ -0,0 +1,61 @@
+#include <cstdint>
+#include <arch/x86_64/cpu/lapic.hpp>
+#include <arch/x86_64/assembly.hpp>
+#include <generic/time.hpp>
+
+std::uint32_t x86_64::lapic::id() {
+ if(is_x2apic) {
+ return read(0x20);
+ } else {
+ return read(0x20) >> 24;
+ }
+}
+
+void x86_64::lapic::eoi() {
+ write(0xB0,0);
+}
+
+void x86_64::lapic::tick(std::uint64_t tick) {
+ write(0x380,tick);
+}
+
+void x86_64::lapic::off() {
+ uint32_t icr_low = (0x3 << 18) | (0x5 << 8) | (1 << 14);
+ write(0x300, icr_low);
+}
+
+std::uint64_t x86_64::lapic::init(std::uint32_t us) {
+ std::uint32_t a,b,c,d;
+ assembly::cpuid(1,0,&a,&b,&c,&d);
+
+ static bool is_print = 0;
+
+ if(c & (1 << 21)) {
+ // x2apic present
+ if(!is_print) klibc::printf("X2APIC: Enabling x2apic (base is 0x%p)\r\n",0x800);
+ assembly::wrmsr(0x1B,assembly::rdmsr(0x1B) | (1 << 10) | (1 << 11));
+ is_x2apic = 1;
+ } else {
+ assembly::wrmsr(0x1B,assembly::rdmsr(0x1B));
+ }
+
+
+ paging::map_range(gobject::kernel_root,assembly::rdmsr(0x1B) & 0xFFFFF000,(assembly::rdmsr(0x1B) & 0xFFFFF000) + etc::hhdm(),PAGE_SIZE, PAGING_PRESENT | PAGING_RW);
+ write(0xf0,0xff | 0x100);
+ write(0x3e0,1);
+ write(0x320,32 | (1 << 16));
+ write(0x380,0xFFFFFFFF);
+ time::timer->sleep(us);
+ std::uint64_t ticks = 0xFFFFFFFF - read(0x390);
+ write(0x320, 32 | (1 << 17));
+ write(0x3e0,1);
+ write(0x380,ticks);
+
+ if(!is_lapic_init) {
+ if(!is_print) klibc::printf("LAPIC: Calibration time is %lli, ticks %lli\r\n",us,ticks);
+ is_print = 1;
+ is_lapic_init = 1;
+ }
+
+ return ticks;
+} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/cpu/lapic.hpp b/kernel/src/arch/x86_64/cpu/lapic.hpp
index a800116..d2380af 100644
--- a/kernel/src/arch/x86_64/cpu/lapic.hpp
+++ b/kernel/src/arch/x86_64/cpu/lapic.hpp
@@ -9,10 +9,10 @@
#include <utils/gobject.hpp>
#include <arch/x86_64/assembly.hpp>
#include <klibc/stdio.hpp>
-
namespace x86_64 {
inline int is_lapic_init = 0;
+ inline int is_x2apic = 0;
class lapic {
@@ -21,46 +21,27 @@ namespace x86_64 {
}
static inline std::uint32_t read(std::uint32_t reg) {
- return *(volatile std::uint32_t*)(base() + reg);
+ if(is_x2apic) {
+ return assembly::rdmsr(0x800 + (reg >> 4));
+ } else {
+ return *(volatile std::uint32_t*)(base() + reg);
+ }
}
static inline void write(std::uint32_t reg,std::uint32_t value) {
- *(volatile std::uint32_t*)(base() + reg) = value;
+ if(is_x2apic) {
+ assembly::wrmsr(0x800 + (reg >> 4), value);
+ } else {
+ *(volatile std::uint32_t*)(base() + reg) = value;
+ }
}
public:
- static inline std::uint32_t id() {
- return read(0x20) >> 24;
- }
-
- static inline void eoi() {
- write(0xB0,0);
- }
-
- static inline void tick(std::uint64_t tick) {
- write(0x380,tick);
- }
-
- static inline std::uint64_t init(std::uint32_t us) {
- assembly::wrmsr(0x1B,assembly::rdmsr(0x1B));
- paging::map_range(gobject::kernel_root,assembly::rdmsr(0x1B) & 0xFFFFF000,(assembly::rdmsr(0x1B) & 0xFFFFF000) + etc::hhdm(),PAGE_SIZE, PAGING_PRESENT | PAGING_RW);
- write(0xf0,0xff | 0x100);
- write(0x3e0,1);
- write(0x320,32 | (1 << 16));
- write(0x380,0xFFFFFFFF);
- time::timer->sleep(us);
- std::uint64_t ticks = 0xFFFFFFFF - read(0x390);
- write(0x320, 32 | (1 << 17));
- write(0x3e0,1);
- write(0x380,0);
-
- if(!is_lapic_init) {
- klibc::printf("LAPIC: Calibration time is %lli, ticks %lli\r\n",us,ticks);
- is_lapic_init = 1;
- }
-
- return ticks;
- }
+ static std::uint32_t id();
+ static void eoi();
+ static void off();
+ static void tick(std::uint64_t tick);
+ static std::uint64_t init(std::uint32_t us);
};
}; \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/cpu/sse.cpp b/kernel/src/arch/x86_64/cpu/sse.cpp
new file mode 100644
index 0000000..73d53ae
--- /dev/null
+++ b/kernel/src/arch/x86_64/cpu/sse.cpp
@@ -0,0 +1,133 @@
+#include <cstdint>
+#include <arch/x86_64/cpu/sse.hpp>
+#include <arch/x86_64/assembly.hpp>
+#include <klibc/stdio.hpp>
+using namespace x86_64;
+
+std::uint64_t __sse_size = 0;
+char __sse_is_initializied = 0;
+char __sse_legacy_save = 0;
+
+std::uint64_t __sse_cr4_read() {
+ uint64_t val;
+ asm volatile("mov %%cr4, %0" : "=r"(val));
+ return val;
+}
+
+void __sse_cr4_write(std::uint64_t val) {
+ asm volatile("mov %0, %%cr4" : : "r"(val) : "memory");
+}
+
+std::uint64_t __sse_cr0_read() {
+ uint64_t val;
+ asm volatile("mov %%cr0, %0" : "=r"(val));
+ return val;
+}
+
+void __sse_cr0_write(std::uint64_t val) {
+ asm volatile("mov %0, %%cr0" : : "r"(val) : "memory");
+}
+
+
+void __sse_xsetbv(std::uint64_t val) {
+ asm volatile("xsetbv" : : "a"(val), "d"(val >> 32),"c"(0) : "memory");
+}
+
+std::uint64_t __sse_xgetbv() {
+ uint32_t a,d;
+ asm volatile("xgetbv" : "=a"(a),"=d"(d) : "c"(0) : "memory");
+ return ((std::uint64_t)d << 32) | a;
+}
+
+void __sse_xsave(void* buf) {
+ std::uint64_t xcr0 = __sse_xgetbv();
+ asm volatile("xsave (%0)" :: "r"(buf), "a"(xcr0 & 0xFFFFFFFF), "d"(xcr0 >> 32), "c"(0): "memory");
+}
+
+void __sse_xrstor(void* buf) {
+ std::uint64_t xcr0 = __sse_xgetbv();
+ asm volatile("xrstor (%0)" :: "r"(buf), "a"(xcr0 & 0xFFFFFFFF), "d"(xcr0 >> 32), "c"(0): "memory");
+}
+
+void sse::init() {
+ uint32_t a,b,c,d;
+ assembly::cpuid(1,0,&a,&b,&c,&d);
+ if(!__sse_is_initializied) {
+ if(c & SSE_XSAVE_SUPPORT) {
+ assembly::cpuid(13,0,&a,&b,&c,&d);
+ __sse_legacy_save = 0;
+ __sse_size = c;
+ } else {
+ __sse_legacy_save = 1;
+ __sse_size = 512;
+ }
+ __sse_is_initializied = 1;
+ }
+ std::uint64_t cr4 = __sse_cr4_read();
+
+ cr4 |= DEFAULT_SSE_FLAGS;
+
+ std::uint64_t cr0 = __sse_cr0_read();
+
+ cr0 &= ~(1 << 2);
+ cr0 |= (1 << 1);
+
+ __sse_cr0_write(cr0);
+
+ std::uint64_t sse_control = 0;
+
+ __sse_cr4_write(cr4);
+
+ assembly::cpuid(1,0,&a,&b,&c,&d);
+ if(c & SSE_XSAVE_SUPPORT)
+ cr4 |= SSE_XSAVE_CR4;
+ else
+ return;
+
+ __sse_cr4_write(cr4);
+
+ assembly::cpuid(13,0,&a,&b,&c,&d);
+
+ sse_control |= SSE_CONTROL_DEFAULT;
+ SSE_CHECK_AND_SET((1 << 2));
+ SSE_CHECK_AND_SET((1 << 9));
+ SSE_CHECK_AND_SET((0b11 < 3));
+ SSE_CHECK_AND_SET((0b11 < 17))
+ SSE_CHECK_AND_SET((0b111 < 5));
+
+ __sse_xsetbv(sse_control);
+}
+
+std::uint64_t sse::size() {
+ return __sse_size;
+}
+
+void sse::save(std::uint8_t* buf) {
+ if(__sse_legacy_save)
+ asm volatile("fxsave (%0)" : : "r"(buf));
+ else
+ __sse_xsave(buf);
+}
+
+void sse::load(std::uint8_t* buf) {
+ if(__sse_legacy_save)
+ asm volatile("fxrstor (%0)" : : "r"(buf));
+ else
+ __sse_xrstor(buf);
+}
+
+void x86_64::sse::print_sse_features() {
+ std::uint32_t a,b,c,d;
+ assembly::cpuid(1,0,&a,&b,&c,&d);
+
+ klibc::printf(
+ "SSE: Supported features:" "%s%s%s%s%s%s\n",
+ (d & (1 << 25)) ? " SSE" : "\0",
+ (d & (1 << 26)) ? " SSE2" : "\0",
+ (c & (1 << 0)) ? " SSE3\0" : "\0",
+ (c & (1 << 19)) ? " SSE4.1" : "",
+ (c & (1 << 20)) ? " SSE4.2" : "",
+ (c & (1 << 26)) ? " XSAVE" : "",
+ (c & (1 << 28)) ? " AVX" : ""
+ );
+}
diff --git a/kernel/src/arch/x86_64/cpu/sse.hpp b/kernel/src/arch/x86_64/cpu/sse.hpp
new file mode 100644
index 0000000..2109937
--- /dev/null
+++ b/kernel/src/arch/x86_64/cpu/sse.hpp
@@ -0,0 +1,33 @@
+#pragma once
+#include <cstdint>
+
+namespace x86_64 {
+ namespace sse {
+
+ typedef struct {
+ std::uint16_t dumb0;
+ std::uint32_t dumb1;
+ std::uint16_t dumb2;
+ std::uint64_t dumb3;
+ std::uint64_t dumb4;
+ std::uint32_t dumb5;
+ } __attribute__((packed)) fpu_head_t;
+
+ #define DEFAULT_SSE_FLAGS ((1 << 9) | (1 << 10) | (1 << 1))
+ #define SSE_XSAVE_SUPPORT (1 << 26)
+ #define SSE_XSAVE_CR4 (1 << 18)
+
+ #define SSE_CONTROL_DEFAULT ((1 << 0) | (1 << 1))
+
+ #define SSE_CHECK_AND_SET(bit) \
+ if(a & bit) \
+ sse_control |= bit;
+
+ void init();
+ std::uint64_t size();
+ void save(std::uint8_t* buf);
+ void load(std::uint8_t* buf);
+ void print_sse_features();
+ inline static void setup_headers(fpu_head_t* head) { head->dumb5 = 0b0001111110000000; }
+ };
+} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/cpu/xapic.hpp b/kernel/src/arch/x86_64/cpu/xapic.hpp
new file mode 100644
index 0000000..aa7c0cf
--- /dev/null
+++ b/kernel/src/arch/x86_64/cpu/xapic.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include <arch/x86_64/cpu/lapic.hpp>
+
+namespace x86_64 {
+ namespace apic {
+ static inline void eoi() {
+ lapic::eoi();
+ }
+ };
+}; \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/cpu_local.hpp b/kernel/src/arch/x86_64/cpu_local.hpp
index 13bca71..e839413 100644
--- a/kernel/src/arch/x86_64/cpu_local.hpp
+++ b/kernel/src/arch/x86_64/cpu_local.hpp
@@ -3,8 +3,8 @@
#pragma once
-#include <arch/x86_64/cpu_local.hpp>
#include <arch/x86_64/assembly.hpp>
+#include <generic/scheduling.hpp>
#include <klibc/string.hpp>
#include <klibc/stdio.hpp>
#include <generic/arch.hpp>
@@ -13,7 +13,9 @@ typedef struct {
std::uint64_t user_stack;
std::uint64_t kernel_stack;
std::uint64_t timer_ist_stack;
+ std::uint32_t cpu;
std::uint64_t tsc_freq;
+ thread* current_thread;
} cpudata_t;
namespace x86_64 {
diff --git a/kernel/src/arch/x86_64/drivers/pci.cpp b/kernel/src/arch/x86_64/drivers/pci.cpp
new file mode 100644
index 0000000..88d5f36
--- /dev/null
+++ b/kernel/src/arch/x86_64/drivers/pci.cpp
@@ -0,0 +1,54 @@
+#include <arch/x86_64/drivers/pci.hpp>
+#include <cstdint>
+
+pci_driver_t pci_drivers[256];
+
+pci_t __pci_load(std::uint8_t bus, std::uint8_t num, std::uint8_t function) {
+ pci_t pciData;
+ std::uint16_t *p = (std::uint16_t *)&pciData;
+ for (std::uint8_t i = 0; i < 32; i++) {
+ p[i] = x86_64::pci::pci_read_config16(bus, num, function, i * 2);
+ }
+ return pciData;
+}
+
+void x86_64::pci::reg(void (*pcidrv)(pci_t, std::uint8_t, std::uint8_t, std::uint8_t), std::uint8_t _class, std::uint8_t subclass) {
+ for (std::uint16_t i = 0; i < 256; i++) {
+ if (!pci_drivers[i].used) {
+ pci_drivers[i].used = true;
+ pci_drivers[i]._class = _class;
+ pci_drivers[i].subclass = subclass;
+ pci_drivers[i].pcidrv = pcidrv;
+ }
+ }
+}
+
+void __pci_launch(pci_t pci, std::uint8_t bus, std::uint8_t device, std::uint8_t function) {
+ for (std::uint16_t i = 0; i < 256; i++) {
+ if (pci_drivers[i].used && pci_drivers[i]._class == pci._class && pci_drivers[i].subclass == pci.subclass) {
+ pci_drivers[i].pcidrv(pci, bus, device, function);
+ return;
+ }
+ }
+}
+
+void x86_64::pci::initworkspace() {
+ pci_t c_pci;
+ for (std::uint16_t bus = 0; bus < 256; bus++) {
+ c_pci = __pci_load(bus, 0, 0);
+ if (c_pci.vendorID != 0xFFFF) {
+ for (std::uint8_t device = 0; device < 32; device++) {
+ c_pci = __pci_load(bus, device, 0);
+ if (c_pci.vendorID != 0xFFFF) {
+ __pci_launch(c_pci, bus, device, 0);
+ for (std::uint8_t function = 1; function < 8; function++) {
+ pci_t pci = __pci_load(bus, device, function);
+ if (pci.vendorID != 0xFFFF) {
+ __pci_launch(pci, bus, device, function);
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/drivers/pci.hpp b/kernel/src/arch/x86_64/drivers/pci.hpp
index 4474997..7a597ed 100644
--- a/kernel/src/arch/x86_64/drivers/pci.hpp
+++ b/kernel/src/arch/x86_64/drivers/pci.hpp
@@ -1,8 +1,65 @@
+#pragma once
#include <arch/x86_64/drivers/io.hpp>
#include <cstdint>
+typedef struct {
+ std::uint16_t vendorID;
+ std::uint16_t deviceID;
+ std::uint16_t command;
+ std::uint16_t status;
+ std::uint8_t revisionID;
+ std::uint8_t progIF;
+ std::uint8_t subclass;
+ std::uint8_t _class;
+ std::uint8_t cacheLineSize;
+ std::uint8_t latencyTimer;
+ std::uint8_t headerType;
+ std::uint8_t bist;
+ std::uint32_t bar0;
+ std::uint32_t bar1;
+ std::uint32_t bar2;
+ std::uint32_t bar3;
+ std::uint32_t bar4;
+ std::uint32_t bar5;
+ std::uint32_t cardbusCISPointer;
+ std::uint16_t subsystemVendorID;
+ std::uint16_t subsystemID;
+ std::uint32_t expansionROMBaseAddress;
+ std::uint8_t capabilitiesPointer;
+ std::uint8_t reserved0;
+ std::uint16_t reserved1;
+ std::uint32_t reserved2;
+ std::uint8_t irq;
+ std::uint8_t interruptPIN;
+ std::uint8_t minGrant;
+ std::uint8_t maxLatency;
+} __attribute__((packed)) pci_t;
+
+typedef struct pci_cap {
+ std::uint8_t id;
+ std::uint8_t off;
+ std::uint8_t bus;
+ std::uint8_t num;
+ std::uint8_t func;
+ std::uint16_t venID;
+ std::uint16_t devID;
+ std::uint8_t data[32];
+ struct pci_cap* next;
+} __attribute__((packed)) pci_cap_t;
+
+typedef struct {
+ int used;
+ std::uint8_t _class;
+ std::uint8_t subclass;
+ void (*pcidrv)(pci_t, std::uint8_t, std::uint8_t, std::uint8_t);
+} __attribute__((packed)) pci_driver_t;
+
namespace x86_64 {
namespace pci {
+
+ void reg(void (*pcidrv)(pci_t, std::uint8_t, std::uint8_t, std::uint8_t), std::uint8_t _class, std::uint8_t subclass);
+ void initworkspace();
+
inline std::uint32_t pci_read_config32(std::uint8_t bus, std::uint8_t num, std::uint8_t function, std::uint8_t offset) {
std::uint32_t address = (1 << 31) | (bus << 16) | (num << 11) | (function << 8) | (offset);
x86_64::io::outd(0xCF8, address);
diff --git a/kernel/src/arch/x86_64/drivers/serial.cpp b/kernel/src/arch/x86_64/drivers/serial.cpp
new file mode 100644
index 0000000..bf1a954
--- /dev/null
+++ b/kernel/src/arch/x86_64/drivers/serial.cpp
@@ -0,0 +1,48 @@
+#include <arch/x86_64/drivers/io.hpp>
+#include <arch/x86_64/drivers/serial.hpp>
+
+#define PORT 0x3f8
+int is_success_init_serial = 0;
+
+void x86_64::serial::init() {
+ x86_64::io::outb(PORT + 1, 0x00);
+ x86_64::io::outb(PORT + 3, 0x80);
+ x86_64::io::outb(PORT + 0, 0x03);
+ x86_64::io::outb(PORT + 1, 0x00);
+ x86_64::io::outb(PORT + 3, 0x03);
+ x86_64::io::outb(PORT + 2, 0xC7);
+ x86_64::io::outb(PORT + 4, 0x0B);
+ x86_64::io::outb(PORT + 4, 0x1E);
+ x86_64::io::outb(PORT + 0, 0xAE);
+
+ if(x86_64::io::inb(PORT + 0) != 0xAE) {
+ is_success_init_serial = 0;
+ return;
+ }
+
+ is_success_init_serial = 1;
+ x86_64::io::outb(PORT + 4, 0x0F);
+}
+
+int is_transmit_empty() {
+ return x86_64::io::inb(PORT + 5) & 0x20;
+}
+
+void x86_64::serial::write(char c) {
+ if(!is_success_init_serial)
+ return;
+ while (is_transmit_empty() == 0);
+ x86_64::io::outb(PORT,c);
+}
+
+int serial_received() {
+ return x86_64::io::inb(PORT + 5) & 1;
+}
+
+char x86_64::serial::read() {
+ if(!is_success_init_serial)
+ return 0;
+ while (serial_received() == 0);
+
+ return x86_64::io::inb(PORT);
+}
diff --git a/kernel/src/arch/x86_64/drivers/serial.hpp b/kernel/src/arch/x86_64/drivers/serial.hpp
new file mode 100644
index 0000000..453ed3a
--- /dev/null
+++ b/kernel/src/arch/x86_64/drivers/serial.hpp
@@ -0,0 +1,14 @@
+
+namespace x86_64 {
+ namespace serial {
+ void init();
+ void write(char c);
+ char read();
+
+ static inline void write_data(char* buffer, int size) {
+ for(int i = 0;i < size;i++) {
+ write(buffer[i]);
+ }
+ }
+ }
+}; \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/drivers/tsc.cpp b/kernel/src/arch/x86_64/drivers/tsc.cpp
index fbb6fad..0abcf6e 100644
--- a/kernel/src/arch/x86_64/drivers/tsc.cpp
+++ b/kernel/src/arch/x86_64/drivers/tsc.cpp
@@ -54,7 +54,8 @@ void drivers::tsc::init() {
x86_64::cpu_data()->tsc_freq = tsc_freq;
- klibc::printf("TSC: TSC Frequency is %llu\r\n", tsc_freq);
+ static bool is_print = 0;
+ if(!is_print) {klibc::printf("TSC: TSC Frequency is %llu\r\n", tsc_freq); is_print = 1;}
drivers::tsc_timer* tsc_timer = new drivers::tsc_timer;
time::setup_timer(tsc_timer);
}
diff --git a/kernel/src/arch/x86_64/irq.cpp b/kernel/src/arch/x86_64/irq.cpp
index da709eb..eb576a8 100644
--- a/kernel/src/arch/x86_64/irq.cpp
+++ b/kernel/src/arch/x86_64/irq.cpp
@@ -2,6 +2,7 @@
#include <arch/x86_64/irq.hpp>
#include <arch/x86_64/cpu/lapic.hpp>
#include <arch/x86_64/drivers/ioapic.hpp>
+#include <arch/x86_64/cpu/xapic.hpp>
#include <cstdint>
irq_t irq_table[255];
@@ -16,7 +17,7 @@ extern "C" void irqHandler(x86_64::idt::int_frame_t* ctx) {
irq_table[ctx->vec - 1].func(irq_table[ctx->vec - 1].arg);
- x86_64::lapic::eoi();
+ x86_64::apic::eoi();
if(ctx->cs & 3)
ctx->ss |= 3;
diff --git a/kernel/src/arch/x86_64/panic.cpp b/kernel/src/arch/x86_64/panic.cpp
index 0ae6697..df923df 100644
--- a/kernel/src/arch/x86_64/panic.cpp
+++ b/kernel/src/arch/x86_64/panic.cpp
@@ -33,12 +33,12 @@ std::uint8_t gaster[] = {
#embed "src/gaster.txt"
};
-void print_ascii_art() {
+void x86_64::panic::print_ascii_art() {
klibc::printf("%s\n",gaster);
}
extern "C" void CPUKernelPanic(x86_64::idt::int_frame_t* frame) {
- print_ascii_art();
+ x86_64::panic::print_ascii_art();
print_regs(frame);
arch::hcf();
} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/schedule_timer.asm b/kernel/src/arch/x86_64/schedule_timer.asm
new file mode 100644
index 0000000..54c7131
--- /dev/null
+++ b/kernel/src/arch/x86_64/schedule_timer.asm
@@ -0,0 +1,46 @@
+
+extern timer_tick
+global scheduler_timer_asm
+scheduler_timer_asm:
+ cli
+ push qword 0
+ push qword 32
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rbp
+ push rdi
+ push rsi
+ push rdx
+ push rcx
+ push rbx
+ push rax
+ mov rax,cr3
+ push rax
+ mov rdi,rsp
+ xor rbp,rbp
+ call timer_tick
+ pop rax
+ mov cr3,rax
+ pop rax
+ pop rbx
+ pop rcx
+ pop rdx
+ pop rsi
+ pop rdi
+ pop rbp
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ add rsp,16
+ iretq \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/schedule_timer.cpp b/kernel/src/arch/x86_64/schedule_timer.cpp
new file mode 100644
index 0000000..97882c7
--- /dev/null
+++ b/kernel/src/arch/x86_64/schedule_timer.cpp
@@ -0,0 +1,58 @@
+#include <arch/x86_64/schedule_timer.hpp>
+#include <arch/x86_64/cpu/idt.hpp>
+#include <arch/x86_64/cpu/xapic.hpp>
+#include <arch/x86_64/cpu_local.hpp>
+#include <generic/scheduling.hpp>
+#include <klibc/stdio.hpp>
+#include <generic/mp.hpp>
+#include <generic/time.hpp>
+#include <generic/lock/spinlock.hpp>
+#include <atomic>
+
+extern "C" void scheduler_timer_asm();
+
+int is_timer_off = 0;
+std::atomic<int> stfu_cpus = 0;
+
+extern "C" void timer_tick(x86_64::idt::int_frame_t* ctx) {
+
+ if(is_timer_off) {
+ stfu_cpus++;
+ arch::hcf();
+ }
+
+ process::schedule((void*)ctx);
+ static std::atomic<int> i = 0;
+ klibc::printf("timer tick %lli %d\r", i++,x86_64::cpu_data()->cpu);
+ x86_64::apic::eoi();
+}
+
+void x86_64::schedule_timer::off() {
+ is_timer_off = 1;
+
+ if(mp::cpu_count() <= 1)
+ return;
+
+ std::uint32_t timeout = 10;
+
+ klibc::printf("Poweroff: Waiting for all cpus to done work\r\n"); // used from poweroff so
+ while(stfu_cpus != (std::int32_t)(mp::cpu_count() - 1)) {
+ arch::memory_barrier();
+
+ if(--timeout == 0) {
+ klibc::printf("Poweroff: Can't wait longer, forching them to be disabled\r\n");
+ x86_64::lapic::off();
+ return;
+ }
+
+ if(time::timer) {
+ time::timer->sleep(50000);
+ } else {
+ arch::pause();
+ }
+ }
+}
+
+void x86_64::schedule_timer::init() {
+ x86_64::idt::set_entry((std::uint64_t)scheduler_timer_asm,32, 0x8E, 2);
+} \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/schedule_timer.hpp b/kernel/src/arch/x86_64/schedule_timer.hpp
new file mode 100644
index 0000000..3a9b3b6
--- /dev/null
+++ b/kernel/src/arch/x86_64/schedule_timer.hpp
@@ -0,0 +1,8 @@
+#pragma once
+
+namespace x86_64 {
+ namespace schedule_timer {
+ void init();
+ void off();
+ };
+}; \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/scheduling.asm b/kernel/src/arch/x86_64/scheduling.asm
new file mode 100644
index 0000000..859f1e9
--- /dev/null
+++ b/kernel/src/arch/x86_64/scheduling.asm
@@ -0,0 +1,36 @@
+
+global context_switch
+context_switch:
+ mov rsp, rdi
+ pop rax
+ mov cr3,rax
+ pop rax
+ pop rbx
+ pop rcx
+ pop rdx
+ pop rsi
+ pop rdi
+ pop rbp
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+ add rsp,16
+ iretq
+
+extern scheduler_timer_asm
+global yield
+yield:
+ pop rax
+ mov rdx, rsp
+ mov rsp,[gs:16]
+ push qword 0
+ push rdx
+ pushfq
+ push qword 0x08
+ push qword rax
+ jmp scheduler_timer_asm \ No newline at end of file
diff --git a/kernel/src/arch/x86_64/x86_64.cpp b/kernel/src/arch/x86_64/x86_64.cpp
index 804c54f..4d272da 100644
--- a/kernel/src/arch/x86_64/x86_64.cpp
+++ b/kernel/src/arch/x86_64/x86_64.cpp
@@ -12,6 +12,9 @@
#include <arch/x86_64/irq.hpp>
#include <klibc/stdio.hpp>
#include <arch/x86_64/drivers/ioapic.hpp>
+#include <arch/x86_64/schedule_timer.hpp>
+#include <utils/gobject.hpp>
+#include <arch/x86_64/cpu/sse.hpp>
namespace arch {
[[gnu::weak]] void disable_interrupts() {
@@ -37,6 +40,12 @@ namespace arch {
asm volatile("pause");
}
+ [[gnu::weak]] std::uint64_t current_root() {
+ std::uint64_t cr3;
+ asm volatile("mov %%cr3, %0" : "=r"(cr3) : : "memory");
+ return cr3;
+ }
+
[[gnu::weak]] void tlb_flush(std::uintptr_t hint, std::uintptr_t len) {
if (len / PAGE_SIZE > 256 || len == 0) {
std::uint64_t cr3 = 0;
@@ -67,6 +76,19 @@ namespace arch {
x86_64::idt::init();
x86_64::lapic::init(1500);
drivers::ioapic::init();
+ x86_64::schedule_timer::init();
+ x86_64::sse::init();
+ x86_64::sse::print_sse_features();
+ return;
+ case ARCH_INIT_MP:
+ enable_paging(gobject::kernel_root);
+ x86_64::init_cpu_data();
+ drivers::tsc::init();
+ x86_64::gdt::init();
+ x86_64::idt::init();
+ x86_64::lapic::init(1500);
+ x86_64::schedule_timer::init();
+ x86_64::sse::init();
return;
case ARCH_INIT_COMMON:
return;
@@ -74,8 +96,12 @@ namespace arch {
}
[[gnu::weak]] void panic(char* msg) {
- x86_64::panic::print_ascii_art();
klibc::printf("Panic with message \"%s\"\r\n",msg);
+ arch::hcf();
+ }
+
+ [[gnu::weak]] void memory_barrier() {
+ asm volatile("lfence" ::: "memory");
}
[[gnu::weak]] int register_handler(int irq, int type, std::uint64_t flags, void (*func)(void* arg), void* arg) {
diff --git a/kernel/src/drivers/disk.hpp b/kernel/src/drivers/disk.hpp
new file mode 100644
index 0000000..584d94e
--- /dev/null
+++ b/kernel/src/drivers/disk.hpp
@@ -0,0 +1,10 @@
+#pragma once
+#include <cstdint>
+
+struct disk {
+ void* arg;
+ std::size_t lba_size;
+ std::size_t disk_size;
+ bool (*read)(void* arg, char* buffer, std::uint64_t lba, std::size_t len_in_blocks);
+ bool (*write)(void* arg, char* buffer, std::uint64_t lba, std::size_t len_in_blocks);
+}; \ No newline at end of file
diff --git a/kernel/src/drivers/nvme.cpp b/kernel/src/drivers/nvme.cpp
new file mode 100644
index 0000000..4be38c6
--- /dev/null
+++ b/kernel/src/drivers/nvme.cpp
@@ -0,0 +1,528 @@
+#include <cstdint>
+#include <drivers/disk.hpp>
+#include <drivers/nvme.hpp>
+#if defined(__x86_64__)
+#include <arch/x86_64/drivers/pci.hpp>
+#endif
+#include <utils/assert.hpp>
+#include <generic/paging.hpp>
+#include <utils/gobject.hpp>
+#include <generic/hhdm.hpp>
+#include <generic/pmm.hpp>
+#include <generic/arch.hpp>
+#include <klibc/stdio.hpp>
+#include <utils/align.hpp>
+#include <generic/time.hpp>
+
+using namespace drivers;
+
+nvme_controller* nvme_controllers[256];
+int nvme_controller_ptr = 0;
+
+void nvme::disable() {
+ for(std::int32_t i = 0;i < nvme_controller_ptr; i++) {
+ nvme_controller* ctrl = nvme_controllers[i];
+ std::uint32_t cc = nvme::read32(ctrl, NVME_REG_CC);
+ cc &= ~NVME_CC_EN;
+ cc |= NVME_CC_SHN_NORMAL;
+ nvme::write32(ctrl, NVME_REG_CC, cc);
+ while(read32(ctrl, NVME_REG_CSTS) & 1) arch::pause();
+ }
+}
+
+void nvme_submit_admin(nvme_controller* ctrl, nvme_command& cmd) {
+ nvme_command* sq = (nvme_command*)ctrl->admin_sq.address;
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Submitting admin command to controller 0x%p with opcode %d\r\n",ctrl, cmd.cdw0);
+#endif
+
+ klibc::memcpy((void*)(((std::uint64_t)&sq[ctrl->admin_sq_tail]) + etc::hhdm()), &cmd, sizeof(nvme_command));
+
+ ctrl->admin_sq_tail++;
+ if (ctrl->admin_sq_tail > 63) ctrl->admin_sq_tail = 0;
+
+ arch::memory_barrier();
+
+ uint32_t* sq_db = (uint32_t*)((uint8_t*)ctrl->bar0 + 0x1000);
+ *sq_db = ctrl->admin_sq_tail;
+ arch::memory_barrier();
+}
+
+bool nvme_wait_admin(nvme_controller* ctrl, uint64_t timeout_ms) {
+ volatile nvme_completion* cq = (volatile nvme_completion*)(ctrl->admin_cq.address + etc::hhdm());
+ uint64_t elapsed = 0;
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Waiting admin command on controller 0x%p with timeout %lli\r\n",ctrl, timeout_ms);
+#endif
+
+ while (elapsed < timeout_ms * 1000) {
+ arch::memory_barrier();
+
+ if ((cq[ctrl->admin_cq_head].status & 0x1) == ctrl->admin_phase) {
+
+ uint16_t status_code = (cq[ctrl->admin_cq_head].status >> 1) & 0xFF;
+
+ ctrl->admin_cq_head++;
+ if (ctrl->admin_cq_head > 63) {
+ ctrl->admin_cq_head = 0;
+ ctrl->admin_phase ^= 1;
+ }
+
+ uint32_t* cq_db = (uint32_t*)((uint8_t*)ctrl->bar0 + 0x1000 + (1 * ctrl->stride));
+ *cq_db = ctrl->admin_cq_head;
+ arch::memory_barrier();
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Got status %d\r\n",status_code);
+#endif
+
+ if(status_code != 0)
+ return false;
+
+ return true;
+ }
+
+ time::timer->sleep(10);
+ elapsed += 10;
+ }
+
+ klibc::printf("NVME: Timeout !\r\n");
+ return false;
+}
+
+bool nvme_send_io(nvme_pair_queue* queue, nvme_command* cmd) {
+ nvme_command* sq = (nvme_command*)queue->sq.address;
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Submitting io command to queue 0x%p with opcode %d\r\n",queue, cmd->cdw0);
+#endif
+
+ klibc::memcpy((void*)(((std::uint64_t)&sq[queue->sq_tail]) + etc::hhdm()), cmd, sizeof(nvme_command));
+
+ queue->sq_tail++;
+ if (queue->sq_tail > 1) queue->sq_tail = 0;
+
+ arch::memory_barrier();
+
+ *queue->sq_doorbell = queue->sq_tail;
+ arch::memory_barrier();
+
+ return true;
+}
+
+bool nvme_wait_io(nvme_pair_queue* queue, uint64_t timeout_ms) {
+ volatile nvme_completion* cq = (volatile nvme_completion*)(queue->cq.address + etc::hhdm());
+ uint64_t elapsed = 0;
+
+ while (elapsed < timeout_ms * 1000) {
+ arch::memory_barrier();
+
+ if ((cq[queue->cq_head].status & 0x1) == queue->phase) {
+
+ uint16_t status_code = (cq[queue->cq_head].status >> 1) & 0xFF;
+
+ queue->cq_head++;
+ if (queue->cq_head > 63) {
+ queue->cq_head = 0;
+ queue->phase ^= 1;
+ }
+
+ *queue->cq_doorbell = queue->cq_head;
+ arch::memory_barrier();
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Got status %d\r\n",status_code);
+#endif
+
+ if(status_code != 0)
+ return false;
+
+ return true;
+ }
+
+ time::timer->sleep(10);
+ elapsed += 10;
+ }
+
+ klibc::printf("NVME: Timeout !\r\n");
+ return false;
+}
+
+bool nvme_send_io_cmd(nvme_pair_queue* queue, nvme_command* cmd) {
+ queue->lock.lock();
+ nvme_send_io(queue,cmd);
+ bool status = nvme_wait_io(queue, 1000);
+ queue->lock.unlock();
+ return status;
+}
+
+bool nvme_identify_namespace(struct nvme_controller* ctrl, uint32_t nsid) {
+ struct nvme_namespace* ns = &ctrl->namespaces[nsid - 1];
+ ns->ns_data = (nvme_id_ns*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ nvme_command cmd;
+ klibc::memset(&cmd,0,sizeof(nvme_command));
+ cmd.cdw0 = 0x06;
+ cmd.nsid = nsid;
+ cmd.cdw10 = 0x0;
+ cmd.prp1 = (std::uint64_t)ns->ns_data - etc::hhdm();
+
+ nvme_submit_admin(ctrl, cmd);
+ bool result = nvme_wait_admin(ctrl, 1000);
+
+ if(result == false)
+ return false;
+
+ ns->nsid = nsid;
+ ns->size = ns->ns_data->nsze;
+
+ uint8_t lba_format = ns->ns_data->flbas & 0xF;
+ if (lba_format < ns->ns_data->nlbaf) {
+ ns->lba_size = 1 << ns->ns_data->lbaf[lba_format].ds;
+ } else {
+ ns->lba_size = 512;
+ }
+ ns->valid = true;
+
+ klibc::printf("NVME: Detected namespace %d with lba_size %lli bytes and total size %lli bytes\r\n", nsid, ns->lba_size, ns->size * ns->lba_size);
+ return true;
+}
+
+bool allocate_prp2_list(std::size_t num_pages, void** out) {
+ if(num_pages > 1) {
+ *out = (void*)(pmm::buddy::alloc(num_pages * PAGE_SIZE).phys + etc::hhdm());
+ return true;
+ } else {
+ *out = (void*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ return false;
+ }
+ assert(0,"wtf");
+ return false;
+}
+
+bool nvme_write(void* arg, char* buffer, std::uint64_t lba, std::size_t len_in_blocks) {
+ nvme_arg_disk* disk = (nvme_arg_disk*)arg;
+ nvme_command cmd;
+ klibc::memset(&cmd, 0, sizeof(nvme_command));
+
+ cmd.cdw0 = 1;
+ cmd.nsid = disk->nsid;
+ cmd.cdw10 = (uint32_t)(lba & 0xFFFFFFFF);
+ cmd.cdw11_15[0] = (uint32_t)(lba >> 32);
+ cmd.cdw11_15[1] = (len_in_blocks - 1) & 0xFFFF;
+
+ std::size_t lba_size = disk->ctrl->namespaces[disk->nsid - 1].lba_size;
+
+ assert(((std::uint64_t)buffer & PAGE_SIZE) == 0, "Unaligned buffer\r\n");
+
+ std::size_t blocks = len_in_blocks;
+ std::size_t num_pages = ((blocks * lba_size) + PAGE_SIZE - 1) / PAGE_SIZE;
+ std::uint64_t current_root = arch::current_root();
+
+ cmd.prp1 = arch::get_phys_from_page(current_root,(std::uintptr_t)buffer);
+
+ std::uint64_t* list = nullptr;
+ bool is_buddy = false;
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Trying to write lba %lli seek %lli num_pages %lli len %lli buffer 0x%p arg 0x%p controller 0x%p nsid %d\r\n", lba, lba, num_pages, len_in_blocks * lba_size, buffer, arg, disk->ctrl, disk->nsid);
+#endif
+
+ if(num_pages == 1) {
+ cmd.prp2 = 0;
+ } else if(num_pages == 2) {
+ cmd.prp2 = arch::get_phys_from_page(current_root,(std::uintptr_t)buffer);
+ } else {
+ is_buddy = allocate_prp2_list(num_pages, (void**)&list);
+ for (std::size_t i = 1; i < num_pages; i++) {
+ list[i - 1] = arch::get_phys_from_page(current_root,(std::uint64_t)buffer + (i * PAGE_SIZE));
+ }
+ cmd.prp2 = (std::uint64_t)list - etc::hhdm();
+ }
+
+ bool status = nvme_send_io_cmd(disk->ctrl->main_io_queue, &cmd);
+
+ if(list) {
+ if(is_buddy) pmm::buddy::free((std::uint64_t)list - etc::hhdm());
+ else pmm::freelist::free((std::uint64_t)list - etc::hhdm());
+ }
+
+ return status;
+}
+
+bool nvme_read(void* arg, char* buffer, std::uint64_t lba, std::size_t len_in_blocks) {
+ nvme_arg_disk* disk = (nvme_arg_disk*)arg;
+ nvme_command cmd;
+ klibc::memset(&cmd, 0, sizeof(nvme_command));
+
+ cmd.cdw0 = 2;
+ cmd.nsid = disk->nsid;
+ cmd.cdw10 = (uint32_t)(lba & 0xFFFFFFFF);
+ cmd.cdw11_15[0] = (uint32_t)(lba >> 32);
+ cmd.cdw11_15[1] = (len_in_blocks - 1);
+
+ std::size_t lba_size = disk->ctrl->namespaces[disk->nsid - 1].lba_size;
+
+ assert(((std::uint64_t)buffer & PAGE_SIZE) == 0, "Unaligned buffer\r\n");
+
+ std::size_t blocks = len_in_blocks;
+ std::size_t num_pages = ((blocks * lba_size) + PAGE_SIZE - 1) / PAGE_SIZE;
+ std::uint64_t current_root = arch::current_root();
+
+ cmd.prp1 = arch::get_phys_from_page(current_root,(std::uintptr_t)buffer);
+
+ std::uint64_t* list = nullptr;
+ bool is_buddy = false;
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Trying to read lba %lli seek %lli num_pages %lli len %lli buffer 0x%p arg 0x%p controller 0x%p nsid %d\r\n", lba, lba, num_pages, len_in_blocks * lba_size, buffer, arg, disk->ctrl, disk->nsid);
+#endif
+
+ if(num_pages == 1) {
+ cmd.prp2 = 0;
+ } else if(num_pages == 2) {
+ cmd.prp2 = arch::get_phys_from_page(current_root,(std::uintptr_t)buffer);
+ } else {
+ is_buddy = allocate_prp2_list(num_pages, (void**)&list);
+ for (std::size_t i = 1; i < num_pages; i++) {
+ list[i - 1] = arch::get_phys_from_page(current_root,(std::uint64_t)buffer + (i * PAGE_SIZE));
+ }
+ cmd.prp2 = (std::uint64_t)list - etc::hhdm();
+ }
+
+ bool status = nvme_send_io_cmd(disk->ctrl->main_io_queue, &cmd);
+
+ if(list) {
+ if(is_buddy) pmm::buddy::free((std::uint64_t)list - etc::hhdm());
+ else pmm::freelist::free((std::uint64_t)list - etc::hhdm());
+ }
+
+ return status;
+}
+
+static inline int isprint(int c) {
+ return (c >= 0x20 && c <= 0x7E);
+}
+
+
+static inline void print_buffer(const unsigned char *buffer, std::size_t size) {
+ for (std::size_t i = 0; i < size; i++) {
+ if (isprint(buffer[i])) {
+ klibc::printf("%c ", buffer[i]);
+ } else {
+ klibc::printf("0x%02X ", buffer[i]);
+ }
+ }
+ klibc::printf("\r\n");
+}
+
+void nvme_init_namespace(nvme_controller* ctrl, std::uint32_t nsid) {
+ void* buffer_test = (void*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ nvme_arg_disk* new_disk = new nvme_arg_disk;
+ new_disk->ctrl = ctrl;
+ new_disk->nsid = nsid;
+
+ klibc::memset(buffer_test,'a',4096);
+ nvme_write(new_disk, (char*)buffer_test, 0, 2);
+ nvme_read(new_disk, (char*)buffer_test, 0, 2);
+
+ ((char*)buffer_test)[4095] = '\0';
+ klibc::printf("test nvme dumping first 1024 byte \r\n", buffer_test, klibc::strlen((const char*)buffer_test));
+ print_buffer((const unsigned char*)buffer_test, 1024);
+
+}
+
+bool nvme_init_namespaces(nvme_controller* ctrl) {
+ void* ns_list = (void*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ nvme_command cmd;
+ klibc::memset(&cmd,0,sizeof(nvme_command));
+ cmd.cdw0 = 0x06;
+ cmd.cdw10 = 0x2;
+ cmd.prp1 = (std::uint64_t)ns_list - etc::hhdm();
+
+ nvme_submit_admin(ctrl, cmd);
+ bool result = nvme_wait_admin(ctrl, 1000);
+
+ if(result == false)
+ return false;
+
+ uint32_t* ns_ids = (uint32_t*)ns_list;
+ for (int i = 0; i < 1024; i++) {
+ uint32_t nsid = ns_ids[i];
+ if (nsid == 0) break; // End of list
+
+ result = nvme_identify_namespace(ctrl, nsid);
+ if(result == true) {
+ nvme_init_namespace(ctrl, nsid);
+ ctrl->num_namespaces++;
+ }
+ }
+
+ return true;
+}
+
+void nvme_alloc_queue(nvme_queue* queue) {
+ queue->address = pmm::freelist::alloc_4k();
+ queue->size = 2;
+}
+
+std::uint8_t nvme_qid_ptr = 1;
+
+nvme_pair_queue* nvme_create_io_queue(nvme_controller* ctrl) {
+ nvme_pair_queue* queue = new nvme_pair_queue;
+ nvme_alloc_queue(&queue->cq);
+ nvme_alloc_queue(&queue->sq);
+ queue->phase = 1;
+ queue->qid = nvme_qid_ptr;
+ queue->lock.unlock();
+
+ nvme_command cmd;
+ klibc::memset(&cmd, 0, sizeof(nvme_command));
+
+ cmd.cdw0 = 0x05;
+ cmd.cdw10 = ((uint32_t)(1)) | (((uint32_t)queue->qid) << 16);
+ cmd.cdw11_15[0] = 1;
+ cmd.prp1 = queue->cq.address;
+
+ nvme_submit_admin(ctrl, cmd);
+ bool status = nvme_wait_admin(ctrl, 1000);
+
+ if(status == false)
+ return nullptr;
+
+ klibc::memset(&cmd, 0, sizeof(nvme_command));
+
+ cmd.cdw0 = 0x01;
+ cmd.cdw10 = ((uint32_t)(1)) | (((uint32_t)queue->qid) << 16);
+ cmd.cdw11_15[0] = (((uint32_t)queue->qid) << 16) | 0x1;
+ cmd.prp1 = queue->sq.address;
+
+ nvme_submit_admin(ctrl, cmd);
+ status = nvme_wait_admin(ctrl, 1000);
+
+ if(status == false)
+ return nullptr;
+
+ uint8_t* doorbell_base = (uint8_t*)ctrl->bar0 + 0x1000;
+ uint32_t stride_bytes = ctrl->stride;
+ queue->sq_doorbell = (uint32_t*)(doorbell_base + ((2 * queue->qid) * stride_bytes));
+ queue->cq_doorbell = (uint32_t*)(doorbell_base + ((2 * queue->qid + 1) * stride_bytes));
+ nvme_qid_ptr++;
+
+ return queue;
+}
+
+bool nvme_identify(nvme_controller* ctrl) {
+ uint64_t phys_buffer = pmm::freelist::alloc_4k();
+
+#ifdef NVME_ORANGE_TRACE
+ klibc::printf("NVME Trace: Trying to identify controller 0x%p\r\n",ctrl);
+#endif
+
+ nvme_command cmd = {};
+ cmd.cdw0 = 0x06;
+ cmd.prp1 = phys_buffer;
+ cmd.cdw10 = 1;
+ cmd.nsid = 0;
+
+ nvme_submit_admin(ctrl, cmd);
+ bool status = nvme_wait_admin(ctrl, 1000);
+ if(status == false)
+ return false;
+ arch::memory_barrier();
+
+ char model[41];
+ klibc::memcpy(model, (void*)(phys_buffer + etc::hhdm() + 24), 40);
+ model[40] = '\0';
+ klibc::printf("NVME: Controller Model: %s\r\n", model);
+
+ ctrl->identify = (void*)(phys_buffer + etc::hhdm());
+
+ return true;
+}
+
+void nvme_init(std::uint64_t base) {
+
+ if(!time::timer) {
+ klibc::printf("NVME: Can't init without timer !\r\n");
+ return;
+ }
+
+ paging::map_range(gobject::kernel_root, base, base + etc::hhdm(), PAGE_SIZE * 4, PAGING_PRESENT | PAGING_RW | PAGING_NC);
+
+ std::uint64_t start = time::timer->current_nano();
+
+ nvme_controller* controller = new nvme_controller;
+ controller->bar0 = (void*)(base + etc::hhdm());
+ std::uint64_t cap = nvme::read64(controller, NVME_REG_CAP);
+ controller->max_queue_entries = (cap & 0xffff) + 1;
+ controller->stride = 4 << ((cap >> 32) & 0xf);
+ controller->admin_phase = 1;
+
+ std::uint8_t mpsmin = (cap >> 48) & 0xf;
+ controller->mpsmin = mpsmin;
+ controller->page_size = 1 << (12 + mpsmin);
+ if(!((cap >> 37) & 1)) {
+ klibc::printf("NVME: Impossible to init because nvm is not supported\r\n");
+ return;
+ }
+
+ nvme::write32(controller, 0x14, nvme::read32(controller, 0x14) & ~(1 << 0));
+ while(nvme::read32(controller, NVME_REG_CSTS) & 1) arch::pause();
+
+ controller->admin_cq.address = pmm::freelist::alloc_4k();
+ controller->admin_sq.address = pmm::freelist::alloc_4k();
+ controller->admin_cq.size = 63;
+ controller->admin_sq.size = 63;
+ nvme::write64(controller, 0x30, controller->admin_cq.address);
+ nvme::write64(controller, 0x28, controller->admin_sq.address);
+ nvme::write32(controller, 0x24, 63 | (63 << 16));
+
+ nvme::write32(controller, 0x14, (1 << 0) | (4 << 20) | (6 << 16));
+ while(!(nvme::read32(controller, NVME_REG_CSTS) & 1)) arch::pause();
+
+ if(!nvme_identify(controller)) {
+ klibc::printf("NVME: Failed to identify !\r\n");
+ return;
+ }
+
+ controller->main_io_queue = nvme_create_io_queue(controller);
+ if(controller->main_io_queue == nullptr) {
+ klibc::printf("NVME: Failed to create io queue\r\n");
+ return;
+ }
+
+ if(!nvme_init_namespaces(controller)) {
+ klibc::printf("NVME: Failed to init namespaces\r\n");
+ }
+
+ std::uint64_t end = time::timer->current_nano();
+
+ klibc::printf("NVME: Detected %d namespaces in %lli us\r\n", controller->num_namespaces, (end - start) / 1000);
+ nvme_controllers[nvme_controller_ptr++] = controller;
+}
+
+#if defined(__x86_64__)
+void nvme_pci_init(pci_t pci, std::uint8_t a, std::uint8_t b, std::uint8_t c) {
+ if(pci.progIF == 2) { // nvme
+ std::uint32_t cmd = x86_64::pci::pci_read_config32(a,b,c,0x4);
+ klibc::printf("NVME_PCI: Bus mastering %d, memory access %d\r\n",(cmd & (1 << 2)) ? 1 : 0, (cmd & (1 << 1)) ? 1 : 0);
+ cmd |= 1 << 2;
+ cmd |= 1 << 1;
+ x86_64::pci::pci_write_config32(a,b,c,0x4,cmd);
+ nvme_init((std::uint64_t)(((std::uint64_t)pci.bar1 << 32) | (pci.bar0 & 0xFFFFFFF0)));
+ }
+}
+#endif
+
+void drivers::nvme::init() {
+ klibc::memset(nvme_controllers,0,sizeof(nvme_controllers));
+#if defined(__x86_64__)
+ x86_64::pci::reg(nvme_pci_init,1,8);
+#else
+ klibc::printf("todo implement nvme finding on other arches\r\n");
+#endif
+} \ No newline at end of file
diff --git a/kernel/src/drivers/nvme.hpp b/kernel/src/drivers/nvme.hpp
new file mode 100644
index 0000000..69d957c
--- /dev/null
+++ b/kernel/src/drivers/nvme.hpp
@@ -0,0 +1,184 @@
+#pragma once
+#include <cstdint>
+#include <drivers/disk.hpp>
+#include <generic/hhdm.hpp>
+#include <generic/lock/spinlock.hpp>
+#include <generic/arch.hpp>
+
+#define NVME_ORANGE_TRACE
+
+#define NVME_REG_CAP 0x00 // Controller Capabilities
+#define NVME_REG_VS 0x08 // Version
+#define NVME_REG_CC 0x14 // Controller Configuration
+#define NVME_REG_CSTS 0x1C // Controller Status
+#define NVME_REG_AQA 0x24 // Admin Queue Attributes
+#define NVME_REG_ASQ 0x28 // Admin Submission Queue Base Address
+#define NVME_REG_ACQ 0x30 // Admin Completion Queue Base Address
+#define NVME_CAP_MQES_MASK 0xFFFF // Maximum Queue Entries Supported
+#define NVME_CAP_CQR (1ULL << 16) // Contiguous Queues Required
+#define NVME_CAP_DSTRD_MASK (0xFULL << 32) // Doorbell Stride
+#define NVME_CAP_CSS_MASK (0xFFULL << 37) // Command Sets Supported
+#define NVME_CAP_MPSMIN_MASK (0xFULL << 48) // Memory Page Size Minimum
+#define NVME_CAP_MPSMAX_MASK (0xFULL << 52) // Memory Page Size Maximum
+#define NVME_CC_EN (1 << 0) // Enable
+#define NVME_CC_CSS_NVM (0 << 4) // NVM Command Set
+#define NVME_CC_SHN_NORMAL (1 << 14) // Normal shutdown
+#define NVME_CSTS_RDY (1 << 0) // Ready
+#define NVME_CSTS_CFS (1 << 1) // Controller Fatal Status
+#define NVME_MAX_IO_QUEUES (65535)
+#define NVME_MAX_QUEUE_SIZE 64
+#define NVME_RESET_TIMEOUT_MS 30000
+#define NVME_ENABLE_TIMEOUT_MS 30000
+
+struct nvme_lbaf {
+ std::uint16_t ms;
+ std::uint8_t ds;
+ std::uint8_t rp;
+};
+
+struct nvme_command {
+ uint32_t cdw0;
+ uint32_t nsid;
+ uint32_t reserved[2];
+ uint64_t metadata;
+ uint64_t prp1;
+ uint64_t prp2;
+ uint32_t cdw10;
+ uint32_t cdw11_15[5];
+};
+
+struct nvme_completion {
+ uint32_t result;
+ uint32_t reserved;
+ uint16_t sq_head;
+ uint16_t sq_id;
+ uint16_t command_id;
+ uint16_t status;
+};
+
+struct nvme_id_ns {
+ std::uint64_t nsze; // Namespace Size
+ std::uint64_t ncap; // Namespace Capacity
+ std::uint64_t nuse; // Namespace Utilization
+ std::uint8_t nsfeat; // Namespace Features
+ std::uint8_t nlbaf; // Number of LBA Formats
+ std::uint8_t flbas; // Formatted LBA Size
+ std::uint8_t mc; // Metadata Capabilities
+ std::uint8_t dpc; // End-to-end Data Protection Capabilities
+ std::uint8_t dps; // End-to-end Data Protection Type Settings
+ std::uint8_t nmic; // Namespace Multi-path I/O and Namespace Sharing Capabilities
+ std::uint8_t rescap; // Reservation Capabilities
+ std::uint8_t fpi; // Format Progress Indicator
+ std::uint8_t dlfeat; // Deallocate Logical Block Features
+ std::uint16_t nawun; // Namespace Atomic Write Unit Normal
+ std::uint16_t nawupf; // Namespace Atomic Write Unit Power Fail
+ std::uint16_t nacwu; // Namespace Atomic Compare & Write Unit
+ std::uint16_t nabsn; // Namespace Atomic Boundary Size Normal
+ std::uint16_t nabo; // Namespace Atomic Boundary Offset
+ std::uint16_t nabspf; // Namespace Atomic Boundary Size Power Fail
+ std::uint16_t noiob; // Namespace Optimal I/O Boundary
+ std::uint8_t nvmcap[16]; // NVM Capacity
+ std::uint16_t npwg; // Namespace Preferred Write Granularity
+ std::uint16_t npwa; // Namespace Preferred Write Alignment
+ std::uint16_t npdg; // Namespace Preferred Deallocate Granularity
+ std::uint16_t npda; // Namespace Preferred Deallocate Alignment
+ std::uint16_t nows; // Namespace Optimal Write Size
+ std::uint16_t mssrl; // Maximum Single Source Range Length
+ std::uint32_t mcl; // Maximum Copy Length
+ std::uint8_t msrc; // Maximum Source Range Count
+ std::uint8_t rsvd81[11];
+ std::uint32_t anagrpid; // ANA Group Identifier
+ std::uint8_t rsvd96[3];
+ std::uint8_t nsattr; // Namespace Attributes
+ std::uint16_t nvmsetid; // NVM Set Identifier
+ std::uint16_t endgid; // Endurance Group Identifier
+ std::uint8_t nguid[16]; // Namespace Globally Unique Identifier
+ std::uint8_t eui64[8]; // IEEE Extended Unique Identifier
+ nvme_lbaf lbaf[16]; // LBA Format Support
+ std::uint8_t rsvd192[192];
+ std::uint8_t vs[3712]; // Vendor Specific
+};
+
+static_assert(sizeof(nvme_id_ns) == 4096, "nvme_id_ns must be exactly 4096 bytes");
+
+struct nvme_queue {
+ std::uint64_t address;
+ std::size_t size;
+};
+
+struct nvme_namespace {
+ uint32_t nsid;
+ uint64_t size;
+ uint32_t lba_size;
+ uint16_t lba_shift;
+ bool valid;
+ struct nvme_id_ns* ns_data;
+};
+
+struct nvme_pair_queue {
+ nvme_queue sq;
+ nvme_queue cq;
+ std::uint64_t sq_tail;
+ std::uint64_t cq_head;
+ std::uint8_t phase;
+ std::uint8_t qid;
+ volatile std::uint32_t* sq_doorbell;
+ volatile std::uint32_t* cq_doorbell;
+ locks::spinlock lock;
+};
+
+struct nvme_controller {
+ void* bar0;
+ uint32_t stride;
+ uint32_t page_size;
+ uint16_t max_queue_entries;
+ nvme_queue admin_sq;
+ nvme_queue admin_cq;
+ std::uint64_t admin_sq_tail;
+ std::uint64_t admin_cq_head;
+ std::uint8_t admin_phase;
+ nvme_pair_queue* main_io_queue;
+ nvme_namespace namespaces[256];
+ uint32_t num_namespaces;
+ uint8_t mpsmin;
+ void* identify;
+};
+
+struct nvme_arg_disk {
+ nvme_controller* ctrl;
+ std::uint32_t nsid;
+};
+
+namespace drivers {
+ namespace nvme {
+
+ static inline std::uint32_t read32(struct nvme_controller* ctrl, std::uint32_t offset) {
+ volatile std::uint32_t* reg = (volatile std::uint32_t*)((std::uint8_t*)ctrl->bar0 + offset);
+ std::uint32_t value = *reg;
+ arch::memory_barrier();
+ return value;
+ }
+
+ static inline void write32(struct nvme_controller* ctrl, std::uint32_t offset, std::uint32_t value) {
+ volatile std::uint32_t* reg = (volatile std::uint32_t*)((std::uint8_t*)ctrl->bar0 + offset);
+ *reg = value;
+ arch::memory_barrier();
+ }
+
+ static inline std::uint64_t read64(struct nvme_controller* ctrl, uint32_t offset) {
+ volatile std::uint64_t* reg = (volatile std::uint64_t*)((std::uint8_t*)ctrl->bar0 + offset);
+ std::uint64_t value = *reg;
+ arch::memory_barrier();
+ return value;
+ }
+
+ static inline void write64(struct nvme_controller* ctrl, std::uint32_t offset, std::uint32_t value) {
+ volatile std::uint64_t* reg = (volatile std::uint64_t*)((std::uint8_t*)ctrl->bar0 + offset);
+ *reg = value;
+ arch::memory_barrier();
+ }
+
+ void init();
+ void disable();
+ };
+}; \ No newline at end of file
diff --git a/kernel/src/drivers/powerbutton.cpp b/kernel/src/drivers/powerbutton.cpp
new file mode 100644
index 0000000..f34bdb9
--- /dev/null
+++ b/kernel/src/drivers/powerbutton.cpp
@@ -0,0 +1,28 @@
+#include <cstdint>
+#include <drivers/powerbutton.hpp>
+#include <klibc/stdio.hpp>
+#if defined(__x86_64__)
+#include <uacpi/event.h>
+#include <generic/poweroff.hpp>
+
+static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) {
+ (void)ctx;
+ poweroff::reboot();
+ return UACPI_INTERRUPT_HANDLED;
+}
+
+void drivers::powerbutton::init() {
+ uacpi_install_fixed_event_handler(
+ UACPI_FIXED_EVENT_POWER_BUTTON,
+ handle_power_button, UACPI_NULL
+ );
+ klibc::printf("PowerButton: Registered powerbutton at ip 0x%p\r\n",(std::uint64_t)handle_power_button);
+}
+
+#else
+
+void drivers::powerbutton::init() {
+
+}
+
+#endif \ No newline at end of file
diff --git a/kernel/src/drivers/powerbutton.hpp b/kernel/src/drivers/powerbutton.hpp
new file mode 100644
index 0000000..f14c079
--- /dev/null
+++ b/kernel/src/drivers/powerbutton.hpp
@@ -0,0 +1,6 @@
+#pragma once
+namespace drivers {
+ namespace powerbutton {
+ void init();
+ };
+}; \ No newline at end of file
diff --git a/kernel/src/drivers/uacpi_kernel_api.cpp b/kernel/src/drivers/uacpi_kernel_api.cpp
index 532fe63..1a4c5cb 100644
--- a/kernel/src/drivers/uacpi_kernel_api.cpp
+++ b/kernel/src/drivers/uacpi_kernel_api.cpp
@@ -5,6 +5,7 @@
#if defined(__x86_64__)
#include <arch/x86_64/drivers/io.hpp>
#include <arch/x86_64/drivers/pci.hpp>
+#include <arch/x86_64/irq.hpp>
#endif
#include <generic/bootloader/bootloader.hpp>
#include <generic/hhdm.hpp>
@@ -349,6 +350,21 @@ uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request*) {
return UACPI_STATUS_OK;
}
+#if defined(__x86_64__)
+
+uacpi_status uacpi_kernel_install_interrupt_handler(
+ uacpi_u32 irq, uacpi_interrupt_handler base, uacpi_handle ctx,
+ uacpi_handle *out_irq_handle
+) {
+ (void)ctx;
+ std::uint8_t vec = x86_64::irq::create(irq, IRQ_TYPE_LEGACY, (void (*)(void*))((void*)base), 0, 0);
+ *out_irq_handle = (uacpi_handle)((std::uint64_t)vec);
+
+ return UACPI_STATUS_OK;
+}
+
+#else
+
uacpi_status uacpi_kernel_install_interrupt_handler(
uacpi_u32 irq, uacpi_interrupt_handler base, uacpi_handle ctx,
uacpi_handle *out_irq_handle
@@ -360,6 +376,20 @@ uacpi_status uacpi_kernel_install_interrupt_handler(
return UACPI_STATUS_OK;
}
+#endif
+
+uacpi_interrupt_state uacpi_kernel_disable_interrupts(void) {
+ return 1;
+}
+
+/*
+ * Restore the state of the interrupt flags to the kernel-defined value provided
+ * in 'state'.
+ */
+void uacpi_kernel_restore_interrupts(uacpi_interrupt_state state) {
+ (void)state;
+}
+
uacpi_status uacpi_kernel_uninstall_interrupt_handler(
uacpi_interrupt_handler, uacpi_handle irq_handle
) {
diff --git a/kernel/src/generic/arch.hpp b/kernel/src/generic/arch.hpp
index cd569ef..b983a1b 100644
--- a/kernel/src/generic/arch.hpp
+++ b/kernel/src/generic/arch.hpp
@@ -10,6 +10,7 @@
#define ARCH_INIT_EARLY 0
#define ARCH_INIT_COMMON 1
+#define ARCH_INIT_MP 2
#define IRQ_TYPE_OTHER 0
#define IRQ_TYPE_LEGACY 1
#define IRQ_TYPE_MSI 2
@@ -33,6 +34,10 @@ namespace arch {
extern void copy_higher_half(std::uintptr_t root, std::uintptr_t src_root);
extern int level_paging();
+ extern std::uint64_t current_root();
+
+ extern void memory_barrier();
+
extern int register_handler(int irq, int type, std::uint64_t flags, void (*func)(void* arg), void* arg);
extern void panic(char* msg);
diff --git a/kernel/src/generic/bootloader/bootloader.hpp b/kernel/src/generic/bootloader/bootloader.hpp
index 21aa650..de9483e 100644
--- a/kernel/src/generic/bootloader/bootloader.hpp
+++ b/kernel/src/generic/bootloader/bootloader.hpp
@@ -12,6 +12,7 @@ namespace bootloader {
virtual std::uint64_t get_kernel_phys() = 0;
virtual std::uintptr_t get_kernel_virt() = 0;
virtual limine_memmap_response* get_memory_map() = 0;
+ virtual limine_mp_response* get_mp_info() = 0;
virtual bool is_5_level_paging() = 0;
};
diff --git a/kernel/src/generic/bootloader/limine.cpp b/kernel/src/generic/bootloader/limine.cpp
index e7175a4..00a7859 100644
--- a/kernel/src/generic/bootloader/limine.cpp
+++ b/kernel/src/generic/bootloader/limine.cpp
@@ -27,6 +27,7 @@ __attribute__((used, section(".limine_requests"))) volatile limine_hhdm_request
__attribute__((used, section(".limine_requests"))) volatile limine_executable_address_request kaddr_request = { .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID, .revision = 0, .response = nullptr };
+__attribute__((used, section(".limine_requests"))) volatile limine_mp_request mp_request = { .id = LIMINE_MP_REQUEST_ID, .revision = 0, .response = nullptr, .flags = 0};
__attribute__((used, section(".limine_requests"))) volatile limine_rsdp_request rsdp_request = { .id = LIMINE_RSDP_REQUEST_ID, .revision = 0, .response = nullptr };
@@ -74,6 +75,10 @@ namespace bootloader {
return memmap_request.response;
}
+ limine_mp_response* limine::get_mp_info() {
+ return mp_request.response;
+ }
+
#if defined(__x86_64__)
bool limine::is_5_level_paging() {
return _5lvl_paging.response->mode == LIMINE_PAGING_MODE_X86_64_5LVL ? true : false;
diff --git a/kernel/src/generic/bootloader/limine.hpp b/kernel/src/generic/bootloader/limine.hpp
index c0fd78b..eac231d 100644
--- a/kernel/src/generic/bootloader/limine.hpp
+++ b/kernel/src/generic/bootloader/limine.hpp
@@ -10,6 +10,7 @@ public:
std::uint64_t get_kernel_phys() override;
std::uint64_t get_kernel_virt() override;
limine_memmap_response* get_memory_map() override;
+ limine_mp_response* get_mp_info() override;
bool is_5_level_paging() override;
};
}; \ No newline at end of file
diff --git a/kernel/src/generic/heap.cpp b/kernel/src/generic/heap.cpp
index e096a68..6468a8a 100644
--- a/kernel/src/generic/heap.cpp
+++ b/kernel/src/generic/heap.cpp
@@ -23,7 +23,7 @@ void kheap::init() {
}
-int is_early = 1;
+int is_early = 0;
void kheap::opt_free(void* ptr) {
if(!is_early) {
diff --git a/kernel/src/generic/lock/spinlock.hpp b/kernel/src/generic/lock/spinlock.hpp
index 12bbe16..782e682 100644
--- a/kernel/src/generic/lock/spinlock.hpp
+++ b/kernel/src/generic/lock/spinlock.hpp
@@ -1,14 +1,19 @@
+#pragma once
#include <atomic>
#include <cstdint>
#include <generic/arch.hpp>
namespace locks {
+ inline bool is_disabled = 0;
class spinlock {
private:
std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() {
+ if(is_disabled)
+ return;
+
while (flag.test_and_set(std::memory_order_acquire)) {
arch::pause();
}
diff --git a/kernel/src/generic/mp.cpp b/kernel/src/generic/mp.cpp
new file mode 100644
index 0000000..0ab4678
--- /dev/null
+++ b/kernel/src/generic/mp.cpp
@@ -0,0 +1,66 @@
+#include <generic/bootloader/bootloader.hpp>
+#include <generic/lock/spinlock.hpp>
+#if defined(__x86_64__)
+#include <arch/x86_64/cpu_local.hpp>
+#endif
+#include <generic/time.hpp>
+#include <generic/arch.hpp>
+#include <generic/mp.hpp>
+#include <klibc/stdio.hpp>
+#include <cstdint>
+#include <atomic>
+
+std::uint32_t balance_how_much_cpus = 1;
+std::uint32_t how_much_cpus = 0;
+static mp::barrier mp_barrier;
+locks::spinlock smp_lock;
+
+std::uint32_t mp::cpu_count() {
+ return how_much_cpus;
+}
+
+void mp::sync() {
+ if (how_much_cpus <= 1) return;
+
+ uint32_t current_gen = mp_barrier.generation.load(std::memory_order_acquire);
+ if (mp_barrier.count.fetch_add(1, std::memory_order_acq_rel) == (how_much_cpus - 1)) {
+ mp_barrier.count.store(0, std::memory_order_relaxed);
+ mp_barrier.generation.fetch_add(1, std::memory_order_release);
+ } else {
+ while (mp_barrier.generation.load(std::memory_order_acquire) == current_gen) {
+ arch::pause();
+ }
+ }
+}
+
+void smptrampoline(limine_mp_info* smp_info) {
+ smp_lock.lock();
+ std::uint32_t enum_cpu = smp_info->processor_id;
+ arch::init(ARCH_INIT_MP);
+#if defined(__x86_64__)
+ x86_64::cpu_data()->cpu = balance_how_much_cpus++;
+ enum_cpu = x86_64::cpu_data()->cpu;
+#endif
+ klibc::printf("SMP: Cpu %d is online (%d)\r\n",smp_info->lapic_id,enum_cpu);
+ smp_lock.unlock();
+ mp::sync();
+ if(time::timer) time::timer->sleep(10000);
+ mp::sync();
+ arch::enable_interrupts();
+ while(true) {
+ arch::wait_for_interrupt();
+ }
+}
+
+void mp::init() {
+ limine_mp_response* mp_info = bootloader::bootloader->get_mp_info();
+ if(!mp_info)
+ return;
+
+ how_much_cpus = mp_info->cpu_count;
+ for(std::uint16_t i = 0;i < mp_info->cpu_count;i++) {
+ if(mp_info->bsp_lapic_id != i) {
+ mp_info->cpus[i]->goto_address = smptrampoline;
+ }
+ }
+} \ No newline at end of file
diff --git a/kernel/src/generic/mp.hpp b/kernel/src/generic/mp.hpp
new file mode 100644
index 0000000..4820311
--- /dev/null
+++ b/kernel/src/generic/mp.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include <cstdint>
+#include <atomic>
+
+namespace mp {
+
+ struct barrier {
+ std::atomic<uint32_t> count{0};
+ std::atomic<uint32_t> generation{0};
+ };
+
+ void init();
+ void sync();
+ std::uint32_t cpu_count();
+} \ No newline at end of file
diff --git a/kernel/src/generic/poweroff.cpp b/kernel/src/generic/poweroff.cpp
new file mode 100644
index 0000000..d81b3df
--- /dev/null
+++ b/kernel/src/generic/poweroff.cpp
@@ -0,0 +1,51 @@
+#include <cstdint>
+#include <generic/poweroff.hpp>
+#include <drivers/nvme.hpp>
+#if defined(__x86_64__)
+#include <uacpi/sleep.h>
+#include <arch/x86_64/cpu/lapic.hpp>
+#include <arch/x86_64/schedule_timer.hpp>
+#endif
+#include <generic/arch.hpp>
+#include <klibc/stdio.hpp>
+#include <generic/time.hpp>
+#include <generic/lock/spinlock.hpp>
+
+void poweroff::prepare_for_shutdown() {
+ drivers::nvme::disable();
+ klibc::printf("Poweroff: NVME is disabled\r\n");
+#if defined(__x86_64__)
+ x86_64::schedule_timer::off();
+#endif
+ locks::is_disabled = true;
+ klibc::printf("Poweroff: Preparing for shutdown is successful\r\n");
+}
+
+void poweroff::off() {
+ arch::disable_interrupts();
+ prepare_for_shutdown();
+ if(time::timer) {
+ klibc::printf("Poweroff: Shutdowning after 3 seconds\r\n");
+ time::timer->sleep(3 * (1000 * 1000));
+ }
+#if defined(__x86_64__)
+ uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5);
+ uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5);
+#endif
+ klibc::printf("uhh its safe to shutdown yk\r\n");
+ arch::hcf();
+}
+
+void poweroff::reboot() {
+ arch::disable_interrupts();
+ prepare_for_shutdown();
+ if(time::timer) {
+ klibc::printf("Poweroff: Rebooting after 3 seconds\r\n");
+ time::timer->sleep(3 * (1000 * 1000));
+ }
+#if defined(__x86_64__)
+ uacpi_reboot();
+#endif
+ klibc::printf("uhh its safe to reboot yk\r\n");
+ arch::hcf();
+} \ No newline at end of file
diff --git a/kernel/src/generic/poweroff.hpp b/kernel/src/generic/poweroff.hpp
new file mode 100644
index 0000000..7eb482a
--- /dev/null
+++ b/kernel/src/generic/poweroff.hpp
@@ -0,0 +1,6 @@
+#pragma once
+namespace poweroff {
+ void prepare_for_shutdown();
+ void off();
+ void reboot();
+} \ No newline at end of file
diff --git a/kernel/src/generic/scheduling.cpp b/kernel/src/generic/scheduling.cpp
new file mode 100644
index 0000000..22162fe
--- /dev/null
+++ b/kernel/src/generic/scheduling.cpp
@@ -0,0 +1,80 @@
+#include <cstdint>
+#include <generic/scheduling.hpp>
+#include <generic/arch.hpp>
+#include <generic/pmm.hpp>
+#include <generic/paging.hpp>
+#include <generic/hhdm.hpp>
+#include <utils/gobject.hpp>
+#include <generic/mp.hpp>
+#define KERNEL_STACK_SIZE (1024 * 32)
+
+thread* head_proc = 0;
+std::uint32_t last_id = 0;
+
+void scheduling_balance_cpus() {
+ std::uint32_t cpu_ptr = 0;
+ thread* proc = head_proc;
+ while(proc) {
+ if(proc->status != PROCESS_KILLED && proc->status != PROCESS_ZOMBIE) {
+ proc->cpu = cpu_ptr++;
+ if(cpu_ptr == mp::cpu_count()) cpu_ptr = 0;
+ }
+ proc = proc->next;
+ }
+}
+
+
+thread* process::create_process(bool is_user) {
+ (void)is_user;
+ return nullptr;
+}
+
+thread* process::by_id(std::uint32_t id) {
+ thread* current = head_proc;
+ while(current) {
+ if(current->id == id)
+ return current;
+ }
+ return nullptr;
+}
+
+thread* process::kthread(void (*func)(void*), void* arg) {
+ thread* new_thread = (thread*)(pmm::freelist::alloc_4k() + etc::hhdm());
+ new_thread->id = ++last_id;
+ new_thread->lock.lock();
+ new_thread->pid = new_thread->id;
+#if defined(__x86_64__)
+ new_thread->ctx.ss = 0;
+ new_thread->ctx.cs = 0x08;
+ new_thread->ctx.rip = (std::uint64_t)func;
+ new_thread->ctx.rdi = (std::uint64_t)arg;
+ new_thread->ctx.rsp = (std::uint64_t)(pmm::buddy::alloc(KERNEL_STACK_SIZE).phys + etc::hhdm() + (KERNEL_STACK_SIZE - 1024));
+ new_thread->ctx.cr3 = gobject::kernel_root;
+#endif
+ new_thread->original_root = gobject::kernel_root;
+ return new_thread;
+}
+
+void process::wakeup(thread* thread) {
+ thread->status = PROCESS_LIVE;
+ thread->lock.unlock();
+}
+
+void process::kill(thread* thread) {
+ thread->status = PROCESS_ZOMBIE;
+ thread->lock.try_lock();
+ if(thread->syscall_stack) pmm::buddy::free(thread->syscall_stack - etc::hhdm());
+ if(thread->name) pmm::freelist::free((std::uint64_t)thread->name - etc::hhdm());
+ if(thread->chroot) pmm::freelist::free((std::uint64_t)thread->name - etc::hhdm());
+ if(thread->cwd) pmm::freelist::free((std::uint64_t)thread->name - etc::hhdm());
+ if(thread->sig) delete thread->sig;
+ thread->syscall_stack = 0;
+ thread->name = 0;
+ thread->chroot = 0;
+ thread->cwd = 0;
+ thread->sig = 0;
+}
+
+void process::schedule(void* ctx) {
+ (void)ctx;
+} \ No newline at end of file
diff --git a/kernel/src/generic/scheduling.hpp b/kernel/src/generic/scheduling.hpp
new file mode 100644
index 0000000..c775448
--- /dev/null
+++ b/kernel/src/generic/scheduling.hpp
@@ -0,0 +1,64 @@
+#pragma once
+#include <cstdint>
+#if defined(__x86_64__)
+#include <arch/x86_64/cpu/idt.hpp>
+#elif defined(__aarch64__)
+#include <arch/aarch64/cpu/el.hpp>
+#endif
+#include <utils/signal.hpp>
+#include <generic/lock/spinlock.hpp>
+#include <atomic>
+
+#define PROCESS_NONE 1
+#define PROCESS_LIVE 2
+#define PROCESS_KILLED 3
+#define PROCESS_ZOMBIE 4
+#define PROCESS_SLEEP 5
+
+struct signal_member {
+ void* restorer;
+ void* handler;
+ std::uint32_t flags;
+};
+
+struct thread {
+ std::uint32_t id;
+ std::uint32_t pid;
+ std::uint32_t exit_code;
+#if defined(__x86_64__)
+ std::uint8_t* sse_ctx;
+ std::uint64_t fs_base;
+ x86_64::idt::int_frame_t ctx;
+#elif defined(__aarch64__)
+ aarch64::el::int_frame ctx;
+#endif
+ signal_manager* sig;
+ signal_member signals_handlers[32];
+ sig_stack signal_stack;
+ locks::spinlock lock;
+ std::atomic<std::uint32_t> futex;
+ std::atomic<std::uint32_t> status;
+ std::atomic<std::uint32_t> cpu;
+ std::uint64_t syscall_stack;
+ std::uint64_t original_root;
+
+ char* name;
+ char* cwd;
+ char* chroot;
+ thread* next;
+};
+
+static_assert(sizeof(thread) < 4096, "thread struct is bigger than page size (bug)");
+
+namespace process {
+ thread* create_process(bool is_user);
+ thread* by_id(std::uint32_t id);
+ thread* kthread(void (*func)(void*), void* arg);
+ void wakeup(thread* thread);
+ void kill(thread* thread);
+
+ extern "C" void schedule(void* frame);
+
+ extern "C" void switch_ctx(void* frame);
+ extern "C" void yield();
+}; \ No newline at end of file
diff --git a/kernel/src/klibc/stdio.cpp b/kernel/src/klibc/stdio.cpp
index 7e8e283..518e5e2 100644
--- a/kernel/src/klibc/stdio.cpp
+++ b/kernel/src/klibc/stdio.cpp
@@ -17,6 +17,12 @@
#include <cstdint>
#include <cstddef>
+#if defined(__x86_64__)
+#include <arch/x86_64/drivers/serial.hpp>
+#endif
+#include <generic/lock/spinlock.hpp>
+
+locks::spinlock print_lock;
int klibc::_snprintf(char *buffer, std::size_t bufsz, char const *fmt, va_list vlist) {
int const rv = npf_vsnprintf(buffer, bufsz, fmt, vlist);
@@ -24,11 +30,16 @@ int klibc::_snprintf(char *buffer, std::size_t bufsz, char const *fmt, va_list v
}
void klibc::printf(const char* fmt, ...) {
+ print_lock.lock();
va_list val;
va_start(val, fmt);
char buffer[4096];
memset(buffer,0,4096);
int len = _snprintf(buffer,4096,fmt,val);
utils::flanterm::write(buffer,len);
+#if defined(__x86_64__)
+ x86_64::serial::write_data(buffer,len);
+#endif
va_end(val);
+ print_lock.unlock();
} \ No newline at end of file
diff --git a/kernel/src/klibc/string.cpp b/kernel/src/klibc/string.cpp
index 27884ad..e4ead45 100644
--- a/kernel/src/klibc/string.cpp
+++ b/kernel/src/klibc/string.cpp
@@ -3,26 +3,43 @@
#include <klibc/string.hpp>
void* klibc::memcpy(void *__restrict dest, const void *__restrict src, std::size_t n) {
+#if defined(__x86_64__)
+ asm volatile(
+ "rep movsb"
+ : "+D"(dest), "+S"(src), "+c"(n)
+ :
+ : "memory"
+ );
+ return dest;
+#else
std::uint8_t *__restrict pdest = static_cast<std::uint8_t *__restrict>(dest);
const std::uint8_t *__restrict psrc = static_cast<const std::uint8_t *__restrict>(src);
for (std::size_t i = 0; i < n; i++) {
pdest[i] = psrc[i];
}
-
return dest;
+#endif
}
void* klibc::memset(void *s, int c, std::size_t n) {
+#if defined(__x86_64__)
+ void* original_s = s;
+ asm volatile(
+ "rep stosb"
+ : "+D"(s), "+c"(n)
+ : "a"((std::uint8_t)c)
+ : "memory"
+ );
+ return original_s;
+#else
std::uint8_t *p = static_cast<std::uint8_t *>(s);
-
for (std::size_t i = 0; i < n; i++) {
- p[i] = static_cast<uint8_t>(c);
+ p[i] = static_cast<std::uint8_t>(c);
}
-
return s;
+#endif
}
-
void* klibc::memmove(void *dest, const void *src, std::size_t n) {
std::uint8_t *pdest = static_cast<std::uint8_t *>(dest);
const std::uint8_t *psrc = static_cast<const std::uint8_t *>(src);
diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp
index 3722589..6af515e 100644
--- a/kernel/src/main.cpp
+++ b/kernel/src/main.cpp
@@ -8,13 +8,25 @@
#include <generic/heap.hpp>
#include <drivers/acpi.hpp>
#include <generic/time.hpp>
+#include <drivers/nvme.hpp>
+#include <drivers/powerbutton.hpp>
+#include <generic/mp.hpp>
+
+#if defined(__x86_64__)
+#include <arch/x86_64/drivers/pci.hpp>
+#include <arch/x86_64/drivers/serial.hpp>
+#endif
extern std::size_t memory_size;
+extern int is_early;
extern "C" void main() {
utils::cxx::init_constructors();
bootloader::init();
utils::flanterm::init();
+#if defined(__x86_64__)
+ x86_64::serial::init();
+#endif
pmm::init();
paging::init();
kheap::init();
@@ -26,13 +38,19 @@ extern "C" void main() {
arch::init(ARCH_INIT_EARLY);
acpi::full_init();
arch::init(ARCH_INIT_COMMON);
- extern int is_early;
- is_early = 0;
+ mp::init();
+ mp::sync();
+ drivers::powerbutton::init();
+ drivers::nvme::init();
+#if defined(__x86_64__)
+ x86_64::pci::initworkspace();
+ klibc::printf("PCI: launched all drivers\r\n");
+#endif
klibc::printf("Boot is done\r\n");
- klibc::printf("current sec %lli, waiting 2 sec and page faulting\r\n",time::timer->current_nano() / (1000 * 1000 * 1000));
- klibc::printf("current sec %lli\r\n",time::timer->current_nano() / (1000 * 1000 * 1000));
- arch::tlb_flush(0x47afe000,PAGE_SIZE);
- *(int*)0x47afe710 = 0;
-
- arch::hcf();
+ mp::sync();
+ arch::enable_interrupts();
+ while(1) {
+ //klibc::printf("current sec %lli\r\n",time::timer->current_nano() / (1000 * 1000 * 1000));
+ arch::wait_for_interrupt();
+ }
}
diff --git a/kernel/src/utils/assert.hpp b/kernel/src/utils/assert.hpp
new file mode 100644
index 0000000..554c7dc
--- /dev/null
+++ b/kernel/src/utils/assert.hpp
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <generic/arch.hpp>
+#include <klibc/stdio.hpp>
+
+#define assert(cond, msg,...) if(!(cond)) { klibc::printf("Failed assert at %s:%s:%d \"" msg "\"\n" , __FILE__ ,__FUNCTION__, __LINE__ , ##__VA_ARGS__); arch::panic((char*)"Failed assert"); } \ No newline at end of file
diff --git a/kernel/src/utils/cxx/cxx_stuff.cpp b/kernel/src/utils/cxx/cxx_stuff.cpp
index c12546a..54e8b58 100644
--- a/kernel/src/utils/cxx/cxx_stuff.cpp
+++ b/kernel/src/utils/cxx/cxx_stuff.cpp
@@ -1,56 +1,22 @@
#include <cstdint>
+#include <klibc/string.hpp>
extern "C" {
void *memcpy(void *__restrict dest, const void *__restrict src, std::size_t n) {
- std::uint8_t *__restrict pdest = static_cast<std::uint8_t *__restrict>(dest);
- const std::uint8_t *__restrict psrc = static_cast<const std::uint8_t *__restrict>(src);
-
- for (std::size_t i = 0; i < n; i++) {
- pdest[i] = psrc[i];
- }
-
- return dest;
+ return klibc::memcpy(dest, src, n);
}
void *memset(void *s, int c, std::size_t n) {
- std::uint8_t *p = static_cast<std::uint8_t *>(s);
-
- for (std::size_t i = 0; i < n; i++) {
- p[i] = static_cast<uint8_t>(c);
- }
-
- return s;
+ return klibc::memset(s, c, n);
}
void *memmove(void *dest, const void *src, std::size_t n) {
- std::uint8_t *pdest = static_cast<std::uint8_t *>(dest);
- const std::uint8_t *psrc = static_cast<const std::uint8_t *>(src);
-
- if (reinterpret_cast<std::uintptr_t>(src) > reinterpret_cast<std::uintptr_t>(dest)) {
- for (std::size_t i = 0; i < n; i++) {
- pdest[i] = psrc[i];
- }
- } else if (reinterpret_cast<std::uintptr_t>(src) < reinterpret_cast<std::uintptr_t>(dest)) {
- for (std::size_t i = n; i > 0; i--) {
- pdest[i-1] = psrc[i-1];
- }
- }
-
- return dest;
+ return klibc::memmove(dest, src, n);
}
int memcmp(const void *s1, const void *s2, std::size_t n) {
- const std::uint8_t *p1 = static_cast<const std::uint8_t *>(s1);
- const std::uint8_t *p2 = static_cast<const std::uint8_t *>(s2);
-
- for (std::size_t i = 0; i < n; i++) {
- if (p1[i] != p2[i]) {
- return p1[i] < p2[i] ? -1 : 1;
- }
- }
-
- return 0;
+ return klibc::memcmp(s1, s2, n);
}
}
diff --git a/kernel/src/utils/errno.hpp b/kernel/src/utils/errno.hpp
new file mode 100644
index 0000000..be57dd0
--- /dev/null
+++ b/kernel/src/utils/errno.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define E2BIG 7
+#define ENOEXEC 8
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define ENOTBLK 15
+#define EBUSY 16
+#define EEXIST 17
+#define EXDEV 18
+#define ENODEV 19
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENFILE 23
+#define EMFILE 24
+#define ENOTTY 25
+#define ETXTBSY 26
+#define EFBIG 27
+#define ENOSPC 28
+#define ESPIPE 29
+#define EROFS 30
+#define EMLINK 31
+#define EPIPE 32
+#define EDOM 33
+#define ERANGE 34
+#define EDEADLK 35
+#define ENAMETOOLONG 36
+#define ENOLCK 37
+#define ENOSYS 38
+#define ENOTEMPTY 39
+#define ELOOP 40
+#define EWOULDBLOCK EAGAIN
+#define ENOMSG 42
+#define EIDRM 43
+#define ECHRNG 44
+#define EL2NSYNC 45
+#define EL3HLT 46
+#define EL3RST 47
+#define ELNRNG 48
+#define EUNATCH 49
+#define ENOCSI 50
+#define EL2HLT 51
+#define EBADE 52
+#define EBADR 53
+#define EXFULL 54
+#define ENOANO 55
+#define EBADRQC 56
+#define EBADSLT 57
+#define EDEADLOCK EDEADLK
+#define EBFONT 59
+#define ENOSTR 60
+#define ENODATA 61
+#define ETIME 62
+#define ENOSR 63
+#define ENONET 64
+#define ENOPKG 65
+#define EREMOTE 66
+#define ENOLINK 67
+#define EADV 68
+#define ESRMNT 69
+#define ECOMM 70
+#define EPROTO 71
+#define EMULTIHOP 72
+#define EDOTDOT 73
+#define EBADMSG 74
+#define EOVERFLOW 75
+#define ENOTUNIQ 76
+#define EBADFD 77
+#define EREMCHG 78
+#define ELIBACC 79
+#define ELIBBAD 80
+#define ELIBSCN 81
+#define ELIBMAX 82
+#define ELIBEXEC 83
+#define EILSEQ 84
+#define ERESTART 85
+#define ESTRPIPE 86
+#define EUSERS 87
+#define ENOTSOCK 88
+#define EDESTADDRREQ 89
+#define EMSGSIZE 90
+#define EPROTOTYPE 91
+#define ENOPROTOOPT 92
+#define EPROTONOSUPPORT 93
+#define ESOCKTNOSUPPORT 94
+#define EOPNOTSUPP 95
+#define ENOTSUP EOPNOTSUPP
+#define EPFNOSUPPORT 96
+#define EAFNOSUPPORT 97
+#define EADDRINUSE 98
+#define EADDRNOTAVAIL 99
+#define ENETDOWN 100
+#define ENETUNREACH 101
+#define ENETRESET 102
+#define ECONNABORTED 103
+#define ECONNRESET 104
+#define ENOBUFS 105
+#define EISCONN 106
+#define ENOTCONN 107
+#define ESHUTDOWN 108
+#define ETOOMANYREFS 109
+#define ETIMEDOUT 110
+#define ECONNREFUSED 111
+#define EHOSTDOWN 112
+#define EHOSTUNREACH 113
+#define EALREADY 114
+#define EINPROGRESS 115
+#define ESTALE 116
+#define EUCLEAN 117
+#define ENOTNAM 118
+#define ENAVAIL 119
+#define EISNAM 120
+#define EREMOTEIO 121
+#define EDQUOT 122
+#define ENOMEDIUM 123
+#define EMEDIUMTYPE 124
+#define ECANCELED 125
+#define ENOKEY 126
+#define EKEYEXPIRED 127
+#define EKEYREVOKED 128
+#define EKEYREJECTED 129
+#define EOWNERDEAD 130
+#define ENOTRECOVERABLE 131
+#define ERFKILL 132
+#define EHWPOISON 133 \ No newline at end of file
diff --git a/kernel/src/utils/signal.hpp b/kernel/src/utils/signal.hpp
new file mode 100644
index 0000000..ddad3f7
--- /dev/null
+++ b/kernel/src/utils/signal.hpp
@@ -0,0 +1,119 @@
+#pragma once
+#include <cstdint>
+#include <utils/bitmap.hpp>
+#include <generic/lock/spinlock.hpp>
+
+#define SIGHUP 1
+#define SIGQUIT 3
+#define SIGTRAP 5
+#define SIGIOT SIGABRT
+#define SIGBUS 7
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGABRT 6
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGPOLL 29
+#define SIGSYS 31
+#define SIGUNUSED SIGSYS
+#define SIGCANCEL 32
+#define SIGTIMER 33
+
+typedef struct
+{
+ unsigned long long __val;
+} __sigset_t;
+
+typedef __sigset_t sigset_t;
+
+void signal_ret_sigmask(sigset_t* sigmask);
+
+#define __sigmask(sig) \
+ (1UL << (((sig) - 1) % 64))
+
+static inline int
+__sigword (int sig)
+{
+ return (sig - 1) / 64;
+}
+
+static inline int
+__sigismember (sigset_t *set, int sig)
+{
+ return (set->__val & (1 << (sig - 1))) ? 1 : 0;
+}
+
+struct sig_stack {
+ void *ss_sp; /* Base address of stack */
+ int ss_flags; /* Flags */
+ std::size_t ss_size; /* Number of bytes in stack */
+};
+
+class signal_manager {
+private:
+ locks::spinlock lock;
+ utils::bitmap* bitmap;
+ std::uint8_t* sigs;
+public:
+ signal_manager() {
+ bitmap = new utils::bitmap(256);
+ sigs = new std::uint8_t[256];
+ }
+
+ std::int8_t pop(sigset_t* sigset) {
+ this->lock.lock();
+ for(int i = 0;i < 256; i++) {
+ if(this->bitmap->test(i) && (this->sigs[i] == 9 || !__sigismember(sigset,this->sigs[i]))) {
+ std::uint8_t saved_sig = this->sigs[i];
+ this->bitmap->clear(i);
+ this->lock.unlock();
+ return (std::int8_t)saved_sig;
+ }
+ }
+ this->lock.unlock();
+ return -1;
+ }
+
+ void push(std::uint8_t sig) {
+ this->lock.lock();
+ for(int i = 0;i < 256; i++) {
+ if(!this->bitmap->test(i)) {
+ this->bitmap->set(i);
+ this->sigs[i] = sig;
+ this->lock.unlock();
+ return;
+ }
+ }
+ this->lock.unlock();
+ }
+
+ bool is_not_empty_sigset(sigset_t* sigsetz) {
+ this->lock.lock();
+
+ // ban sigset signals :p
+ for(int i = 0; i < 128; i++) {
+ if(this->bitmap->test(i) && !__sigismember(sigsetz,this->sigs[i])) {
+ this->lock.unlock(); // great there's unbanned pending signal
+ return 1;
+ }
+ }
+
+ this->lock.unlock();
+ return 0;
+ }
+
+};