feat: initial scalable x86_64 microkernel skeleton with Limine, Rust, C HAL, and C++20 IPC

This commit is contained in:
RarDog
2026-09-02 16:47:37 +03:00
commit 9cffb01889
47 changed files with 2432 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
# Build artifacts
/build/
/target/
*.o
*.a
*.elf
*.bin
*.iso
*.img
# Cargo
Cargo.lock
**/*.rs.bk
# Editor and OS files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
+43
View File
@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.20)
project(opencoreC C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
# Freestanding flags
set(FREESTANDING_FLAGS "-ffreestanding -fno-stack-protector -fno-pie -no-pie -mno-red-zone -m64")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FREESTANDING_FLAGS} -Wall -Wextra -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FREESTANDING_FLAGS} -Wall -Wextra -O2 -fno-exceptions -fno-rtti")
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/lib/libc/include
${CMAKE_CURRENT_SOURCE_DIR}/lib/libipc_cpp/include
${CMAKE_CURRENT_SOURCE_DIR}/hal/include
)
# Bare-metal libc
add_library(freestanding_libc STATIC
lib/libc/src/string.c
lib/libc/src/syscalls.c
)
# HAL Library
add_library(hal STATIC
hal/src/uart.c
hal/src/pci.c
hal/src/apic.c
)
# Ring 3 User Servers
add_executable(init_server servers/init/main.cpp)
target_link_options(init_server PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/config/user.ld -nostdlib -static)
target_link_libraries(init_server PRIVATE freestanding_libc)
add_executable(uart_driver servers/uart_driver/main.c)
target_link_options(uart_driver PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/config/user.ld -nostdlib -static)
target_link_libraries(uart_driver PRIVATE hal freestanding_libc)
add_executable(procmgr servers/procmgr/main.cpp)
target_link_options(procmgr PRIVATE -T${CMAKE_CURRENT_SOURCE_DIR}/config/user.ld -nostdlib -static)
target_link_libraries(procmgr PRIVATE freestanding_libc)
+16
View File
@@ -0,0 +1,16 @@
[workspace]
members = [
"kernel",
]
resolver = "2"
[profile.dev]
panic = "abort"
opt-level = 1
[profile.release]
panic = "abort"
opt-level = 3
lto = true
codegen-units = 1
debug = false
+115
View File
@@ -0,0 +1,115 @@
# opencoreC - Root Unified Makefile
# Target Architecture: x86_64 Long Mode (Microkernel OS)
SHELL := /usr/bin/env bash
# Toolchain definitions
CC := gcc
CXX := g++
LD := ld
CARGO := cargo
QEMU := qemu-system-x86_64
# Directory layout
BUILD_DIR := build
CONFIG_DIR := config
INCLUDE_DIR := include
LIB_DIR := lib
HAL_DIR := hal
SERVERS_DIR := servers
KERNEL_DIR := kernel
ISO_DIR := $(BUILD_DIR)/iso_root
# Common Freestanding Flags
COMMON_FLAGS := -Wall -Wextra -O2 -ffreestanding -fno-stack-protector \
-fno-pie -no-pie -mno-red-zone -m64 \
-I$(INCLUDE_DIR) -I$(LIB_DIR)/libc/include
CFLAGS := $(COMMON_FLAGS) -std=c11
CXXFLAGS := $(COMMON_FLAGS) -std=c++20 -fno-exceptions -fno-rtti -I$(LIB_DIR)/libipc_cpp/include
# Outputs
KERNEL_BIN := target/x86_64-unknown-none/release/opencore_kernel
KERNEL_ELF := $(BUILD_DIR)/opencore_kernel.elf
INIT_SERVER := $(BUILD_DIR)/init_server.elf
UART_DRIVER := $(BUILD_DIR)/uart_driver.elf
PROCMGR := $(BUILD_DIR)/procmgr.elf
.PHONY: all kernel libc hal servers iso run clean help
all: kernel libc hal servers
@mkdir -p $(BUILD_DIR)
@cp $(KERNEL_BIN) $(KERNEL_ELF)
@echo "======================================================="
@echo " [SUCCESS] opencoreC Skeleton Build Complete!"
@echo " Kernel: $(KERNEL_ELF)"
@echo " Servers: $(INIT_SERVER), $(UART_DRIVER), $(PROCMGR)"
@echo "======================================================="
kernel:
@echo "[CARGO] Compiling Rust Microkernel (x86_64-unknown-none)..."
@RUSTFLAGS="-C link-arg=-T$(CONFIG_DIR)/linker.ld -C code-model=kernel -C relocation-model=static" \
$(CARGO) build --package opencore_kernel --target x86_64-unknown-none --release
libc:
@mkdir -p $(BUILD_DIR)
@echo "[CC] Compiling bare-metal freestanding libc..."
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/string.c -o $(BUILD_DIR)/string.o
@$(CC) $(CFLAGS) -c $(LIB_DIR)/libc/src/syscalls.c -o $(BUILD_DIR)/syscalls.o
hal: libc
@mkdir -p $(BUILD_DIR)
@echo "[CC] Compiling HAL and Hardware Drivers..."
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/uart.c -o $(BUILD_DIR)/uart.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/pci.c -o $(BUILD_DIR)/pci.o
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(HAL_DIR)/src/apic.c -o $(BUILD_DIR)/apic.o
servers: libc hal
@mkdir -p $(BUILD_DIR)
@echo "[CXX/CC] Linking Ring 3 User-space Servers..."
@# Init Root Server
@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/init/main.cpp -o $(BUILD_DIR)/init_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(INIT_SERVER) \
$(BUILD_DIR)/init_main.o $(BUILD_DIR)/syscalls.o $(BUILD_DIR)/string.o
@# Standalone UART Driver Server
@$(CC) $(CFLAGS) -I$(HAL_DIR)/include -c $(SERVERS_DIR)/uart_driver/main.c -o $(BUILD_DIR)/uart_driver_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(UART_DRIVER) \
$(BUILD_DIR)/uart_driver_main.o $(BUILD_DIR)/uart.o $(BUILD_DIR)/syscalls.o $(BUILD_DIR)/string.o
@# Process Manager Daemon
@$(CXX) $(CXXFLAGS) -c $(SERVERS_DIR)/procmgr/main.cpp -o $(BUILD_DIR)/procmgr_main.o
@$(LD) -T $(CONFIG_DIR)/user.ld -nostdlib -static -o $(PROCMGR) \
$(BUILD_DIR)/procmgr_main.o $(BUILD_DIR)/syscalls.o $(BUILD_DIR)/string.o
# Staging Limine Boot ISO directory
iso: all
@mkdir -p $(ISO_DIR)/boot $(ISO_DIR)/EFI/BOOT
@cp $(KERNEL_ELF) $(ISO_DIR)/boot/
@cp $(INIT_SERVER) $(ISO_DIR)/boot/
@cp $(UART_DRIVER) $(ISO_DIR)/boot/
@cp limine.conf $(ISO_DIR)/boot/limine.conf
@cp limine.cfg $(ISO_DIR)/boot/limine.cfg
@echo "[ISO] Staged boot files in $(ISO_DIR)/"
run: all
@echo "[QEMU] Launching opencoreC in QEMU (Serial Output to Terminal)..."
@$(QEMU) -M q35 -m 512M \
-serial stdio \
-display none \
-no-reboot \
-no-shutdown \
-kernel $(KERNEL_ELF)
clean:
@echo "[CLEAN] Removing build directory and cargo target..."
@rm -rf $(BUILD_DIR) target
help:
@echo "opencoreC Microkernel Build System"
@echo "Targets:"
@echo " make all - Build kernel, HAL, libc, and user servers"
@echo " make kernel - Build Rust microkernel only"
@echo " make hal - Build freestanding HAL drivers"
@echo " make servers - Build Ring 3 C++ servers"
@echo " make iso - Stage ISO root boot directory"
@echo " make run - Launch QEMU with serial stdio"
@echo " make clean - Clean build artifacts"
+149
View File
@@ -0,0 +1,149 @@
# opencoreC: High-Performance x86_64 Microkernel OS
[![Architecture](https://img.shields.io/badge/Arch-x86__64%20(Long%20Mode)-blue.svg)]()
[![Kernel](https://img.shields.io/badge/Kernel-Rust%20%23!%5Bno__std%5D-orange.svg)]()
[![HAL](https://img.shields.io/badge/HAL%20%2F%20Drivers-C11%20Freestanding-green.svg)]()
[![Services](https://img.shields.io/badge/Services-C%2B%2B20%20RAII-purple.svg)]()
[![Bootloader](https://img.shields.io/badge/Boot-Limine%20v3-brightgreen.svg)]()
**opencoreC** is a modern, modular, capability-based microkernel operating system written in **Rust (`#![no_std]`)**, **Freestanding C**, and **Modern C++20**. It is designed around principles of strict hardware isolation, capability security, and zero-copy / fast-path inter-process communication (IPC).
---
## 🏛️ Architecture Overview
The system follows a pure microkernel design paradigm where only the essential primitives reside in **Ring 0**, while device drivers, file systems, and system servers operate in isolated **Ring 3** user spaces.
```mermaid
graph TD
subgraph Ring 3 [User Space - Ring 3]
INIT["init_server (C++20 Root Server)"]
PROCMGR["procmgr (Process & Server Manager)"]
UART_DRV["uart_driver (16550 COM1 Driver)"]
FS["VFS / Storage Server (Future)"]
end
subgraph Ring 0 [Microkernel - Ring 0]
IPC["Fast-Path IPC Dispatcher (Registers + SHM)"]
CAP["Capability Table & CNode Tracker"]
VMM["Virtual Memory Manager (PML4 4-Level Paging)"]
PFA["Physical Frame Allocator (Bitmap Allocator)"]
SCHED["Thread Scheduler & Context Switch (ASM)"]
end
INIT -- "Fast-Path IPC (Syscall)" --> IPC
PROCMGR -- "Fast-Path IPC (Syscall)" --> IPC
UART_DRV -- "Fast-Path IPC (Syscall)" --> IPC
IPC --> CAP
IPC --> SCHED
```
### 🔀 Language & Subsystem Distribution
| Component | Language | Privilege | Responsibilities |
| :--- | :--- | :--- | :--- |
| **Microkernel Core** | **Rust** (`#![no_std]`) | Ring 0 | PFA (Physical Memory), VMM (Paging), Capabilities, Fast IPC dispatcher, Scheduler. |
| **Low-Level Glue** | **x86_64 ASM** | Ring 0 / 3 | `_start`, `switch_to` context switch, `syscall_entry` / `sysretq`, IDT vectors. |
| **HAL & Hardware** | **C** (`-ffreestanding`) | Ring 3 / Ring 0 | Minimal bare-metal libc, 16550 UART COM driver, PCI bus scanning, APIC/IOAPIC. |
| **User Services** | **C++20** (`-nostdlib`) | Ring 3 | System servers, process management, RAII IPC endpoints (`ipc::Endpoint`, `ipc::SharedBuffer`). |
---
## 📁 Repository Structure
```text
opencoreC/
├── Cargo.toml # Root Rust workspace manifest
├── rust-toolchain.toml # Fixed toolchain (x86_64-unknown-none)
├── Makefile # Unified root build system
├── CMakeLists.txt # Alternative CMake build for C/C++ components
├── limine.conf # Limine bootloader configuration
├── config/
│ ├── linker.ld # Higher-half kernel linker script (0xffffffff80000000)
│ └── user.ld # Userspace ELF linker script (0x400000)
├── include/
│ └── abi/
│ ├── types.h # ABI primitive types (cap_t, sysret_t, vaddr_t)
│ ├── syscalls.h # Syscall numbers and inline assembly wrappers
│ └── ipc.h # Fast-Path IPC register layout and SHM headers
├── kernel/ # Microkernel crate (Rust)
│ ├── Cargo.toml
│ ├── asm/
│ │ ├── context.S # Cooperative/Preemptive context switcher
│ │ └── syscall_entry.S # x86_64 fast syscall trampoline
│ └── src/
│ ├── main.rs # Kernel entry point & self-tests
│ ├── limine_requests.rs # Limine protocol responses (HHDM, Memmap)
│ ├── arch/ # GDT, TSS, IDT, Syscall MSRs
│ ├── mm/ # Physical Frame Allocator & 4-Level Paging
│ ├── ipc/ # Register-based Fast-Path IPC
│ └── sched/ # Thread control blocks & scheduler
├── lib/
│ ├── libc/ # Minimal freestanding C library
│ └── libipc_cpp/ # Modern C++ RAII IPC client library
├── hal/ # Hardware Abstraction Layer (UART, PCI, APIC)
└── servers/ # Ring 3 User-space servers (init, procmgr, uart_driver)
```
---
## ⚡ Fast-Path IPC Specification
Short messages (up to 32 bytes of arguments) are passed directly through CPU registers without memory allocations or deep kernel stack copies:
* **`RAX`**: Syscall Number (`SYS_IPC_CALL = 1`, `SYS_IPC_REPLY_RECV = 2`, etc.)
* **`RDI`**: Target Capability Handle (`cap_t dest_cap`)
* **`RSI`**: IPC Opcode / Interface Method ID
* **`RDX`**: Argument 0 (`uint64_t`)
* **`R8`** : Argument 1 (`uint64_t`)
* **`R9`** : Argument 2 (`uint64_t`)
* **`R10`**: Argument 3 / SHM token (`uint64_t`)
* **Return Registers**: `RAX` (Status code), `RDX` (Result 0), `R8` (Result 1)
---
## 🚀 Building & Running
### Prerequisites
* `rustc` & `cargo` (with target `x86_64-unknown-none`)
* `gcc` & `g++` (supporting C11 and C++20)
* `qemu-system-x86_64`
### Quick Start
1. **Build all components:**
```bash
make all
```
2. **Run in QEMU with Serial Console Output:**
```bash
make run
```
3. **Clean build artifacts:**
```bash
make clean
```
---
## 🗺️ Roadmap
- [x] Higher-Half Limine bootloader protocol initialization (HHDM).
- [x] Physical Frame Allocator (PFA) via bitmap.
- [x] 4-Level Paging (VMM) with dynamic page table allocation.
- [x] Fast-Path register IPC infrastructure (`syscall`/`sysretq`).
- [x] Freestanding bare-metal libc and 16550 UART driver.
- [x] Modern C++ RAII IPC wrappers and initial userspace servers.
- [ ] **Phase 1:** ELF Loader, User Address Space isolation, and `iretq` jump to Ring 3.
- [ ] **Phase 2:** Synchronous IPC Rendezvous (blocking call / reply loop).
- [ ] **Phase 3:** Preemptive Multi-Tasking via LAPIC Timer interrupts.
- [ ] **Phase 4:** Userspace device driver model & interrupt forwarding.
---
## 📜 License
Distributed under the MIT / Apache-2.0 License.
+51
View File
@@ -0,0 +1,51 @@
/* opencoreC - Higher-Half x86_64 Kernel Linker Script */
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
PHDRS
{
text PT_LOAD FLAGS((1 << 0) | (1 << 2)); /* Execute | Read */
rodata PT_LOAD FLAGS((1 << 2)); /* Read Only */
data PT_LOAD FLAGS((1 << 1) | (1 << 2)); /* Write | Read */
}
SECTIONS
{
/* Higher-half virtual base: 0xffffffff80000000 (-2 GiB) */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
. = ALIGN(CONSTANT(MAXPAGESIZE));
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Limine requests section */
.limine_requests : {
KEEP(*(.limine_requests_start))
KEEP(*(.limine_requests))
KEEP(*(.limine_requests_end))
} :rodata
. = ALIGN(CONSTANT(MAXPAGESIZE));
.data : {
*(.data .data.*)
} :data
.bss : {
*(.bss .bss.*)
*(COMMON)
} :data
/DISCARD/ : {
*(.eh_frame)
*(.note .note.*)
*(.comment)
}
}
+36
View File
@@ -0,0 +1,36 @@
/* opencoreC - Userspace Program Linker Script */
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
. = 0x400000;
.text : {
*(.text .text.*)
}
. = ALIGN(0x1000);
.rodata : {
*(.rodata .rodata.*)
}
. = ALIGN(0x1000);
.data : {
*(.data .data.*)
}
.bss : {
*(.bss .bss.*)
*(COMMON)
}
/DISCARD/ : {
*(.eh_frame)
*(.note .note.*)
*(.comment)
}
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include "stdint.h"
#define LAPIC_ID_REG 0x020
#define LAPIC_VERSION_REG 0x030
#define LAPIC_TPR_REG 0x080
#define LAPIC_EOI_REG 0x0B0
#define LAPIC_SVR_REG 0x0F0
#define LAPIC_ICR_LOW_REG 0x300
#define LAPIC_ICR_HIGH_REG 0x310
#define LAPIC_LVT_TIMER_REG 0x320
#define LAPIC_TIMER_INIT_REG 0x380
#define LAPIC_TIMER_CURR_REG 0x390
#define LAPIC_TIMER_DIV_REG 0x3E0
#ifdef __cplusplus
extern "C" {
#endif
void lapic_init(uintptr_t lapic_base_vaddr);
void lapic_eoi(void);
uint32_t lapic_read(uint32_t reg);
void lapic_write(uint32_t reg, uint32_t value);
uint32_t lapic_get_id(void);
#ifdef __cplusplus
}
#endif
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "stdint.h"
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
typedef struct pci_device {
uint8_t bus;
uint8_t slot;
uint8_t func;
uint16_t vendor_id;
uint16_t device_id;
uint8_t class_code;
uint8_t subclass;
uint8_t prog_if;
uint8_t header_type;
} pci_device_t;
#ifdef __cplusplus
extern "C" {
#endif
uint32_t pci_read_config_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset);
void pci_write_config_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t val);
uint16_t pci_get_vendor_id(uint8_t bus, uint8_t slot, uint8_t func);
uint16_t pci_get_device_id(uint8_t bus, uint8_t slot, uint8_t func);
typedef void (*pci_scan_callback_t)(const pci_device_t *dev);
void pci_scan_bus(pci_scan_callback_t callback);
#ifdef __cplusplus
}
#endif
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "stdint.h"
#include "stddef.h"
#define UART_COM1_PORT 0x3F8
#define UART_COM2_PORT 0x2F8
#ifdef __cplusplus
extern "C" {
#endif
/* Initialize 16550 UART port with target baud rate */
int uart_init(uint16_t port, uint32_t baud);
/* Check if transmit buffer is empty */
int uart_is_tx_empty(uint16_t port);
/* Transmit a single character */
void uart_putc(uint16_t port, char c);
/* Transmit a null-terminated string */
void uart_puts(uint16_t port, const char *s);
/* Transmit a buffer of given length */
void uart_write(uint16_t port, const char *buf, size_t len);
/* Check if data received */
int uart_has_data(uint16_t port);
/* Read a single character (blocking) */
char uart_getc(uint16_t port);
#ifdef __cplusplus
}
#endif
+31
View File
@@ -0,0 +1,31 @@
#include "../include/apic.h"
static volatile uint32_t *lapic_base = (volatile uint32_t *)0;
uint32_t lapic_read(uint32_t reg) {
if (!lapic_base) return 0;
return *(volatile uint32_t *)((uintptr_t)lapic_base + reg);
}
void lapic_write(uint32_t reg, uint32_t value) {
if (!lapic_base) return;
*(volatile uint32_t *)((uintptr_t)lapic_base + reg) = value;
}
void lapic_init(uintptr_t lapic_base_vaddr) {
lapic_base = (volatile uint32_t *)lapic_base_vaddr;
// Enable LAPIC via Spurious Interrupt Vector Register (SVR) + Vector 0xFF
lapic_write(LAPIC_SVR_REG, lapic_read(LAPIC_SVR_REG) | 0x1FF);
// Set Task Priority Register to 0 (accept all interrupts)
lapic_write(LAPIC_TPR_REG, 0x00);
}
void lapic_eoi(void) {
lapic_write(LAPIC_EOI_REG, 0x00);
}
uint32_t lapic_get_id(void) {
return (lapic_read(LAPIC_ID_REG) >> 24) & 0xFF;
}
+79
View File
@@ -0,0 +1,79 @@
#include "../include/pci.h"
static inline void outl(uint16_t port, uint32_t val) {
__asm__ volatile("outl %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint32_t inl(uint16_t port) {
uint32_t ret;
__asm__ volatile("inl %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
uint32_t pci_read_config_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
uint32_t address = (uint32_t)((((uint32_t)bus) << 16) |
(((uint32_t)slot) << 11) |
(((uint32_t)func) << 8) |
(offset & 0xFC) |
((uint32_t)0x80000000));
outl(PCI_CONFIG_ADDRESS, address);
return inl(PCI_CONFIG_DATA);
}
void pci_write_config_dword(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t val) {
uint32_t address = (uint32_t)((((uint32_t)bus) << 16) |
(((uint32_t)slot) << 11) |
(((uint32_t)func) << 8) |
(offset & 0xFC) |
((uint32_t)0x80000000));
outl(PCI_CONFIG_ADDRESS, address);
outl(PCI_CONFIG_DATA, val);
}
uint16_t pci_get_vendor_id(uint8_t bus, uint8_t slot, uint8_t func) {
uint32_t dword = pci_read_config_dword(bus, slot, func, 0x00);
return (uint16_t)(dword & 0xFFFF);
}
uint16_t pci_get_device_id(uint8_t bus, uint8_t slot, uint8_t func) {
uint32_t dword = pci_read_config_dword(bus, slot, func, 0x00);
return (uint16_t)((dword >> 16) & 0xFFFF);
}
void pci_scan_bus(pci_scan_callback_t callback) {
for (uint16_t bus = 0; bus < 256; bus++) {
for (uint8_t slot = 0; slot < 32; slot++) {
uint16_t vendor = pci_get_vendor_id((uint8_t)bus, slot, 0);
if (vendor == 0xFFFF || vendor == 0x0000) {
continue;
}
uint32_t hdr_dword = pci_read_config_dword((uint8_t)bus, slot, 0, 0x0C);
uint8_t header_type = (uint8_t)((hdr_dword >> 16) & 0xFF);
uint8_t num_funcs = (header_type & 0x80) ? 8 : 1;
for (uint8_t func = 0; func < num_funcs; func++) {
uint16_t func_vendor = pci_get_vendor_id((uint8_t)bus, slot, func);
if (func_vendor == 0xFFFF || func_vendor == 0x0000) {
continue;
}
uint32_t class_dword = pci_read_config_dword((uint8_t)bus, slot, func, 0x08);
pci_device_t dev;
dev.bus = (uint8_t)bus;
dev.slot = slot;
dev.func = func;
dev.vendor_id = func_vendor;
dev.device_id = pci_get_device_id((uint8_t)bus, slot, func);
dev.class_code = (uint8_t)((class_dword >> 24) & 0xFF);
dev.subclass = (uint8_t)((class_dword >> 16) & 0xFF);
dev.prog_if = (uint8_t)((class_dword >> 8) & 0xFF);
dev.header_type = header_type;
if (callback) {
callback(&dev);
}
}
}
}
}
+98
View File
@@ -0,0 +1,98 @@
#include "../include/uart.h"
/* Port I/O Helpers */
static inline void outb(uint16_t port, uint8_t val) {
__asm__ volatile("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t inb(uint16_t port) {
uint8_t ret;
__asm__ volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
/* 16550 Register Offsets */
#define UART_DATA 0
#define UART_IER 1
#define UART_BAUD_LO 0
#define UART_BAUD_HI 1
#define UART_FCR 2
#define UART_LCR 3
#define UART_MCR 4
#define UART_LSR 5
int uart_init(uint16_t port, uint32_t baud) {
if (baud == 0) baud = 115200;
uint16_t divisor = (uint16_t)(115200 / baud);
if (divisor == 0) divisor = 1;
// 1. Disable all interrupts
outb(port + UART_IER, 0x00);
// 2. Enable DLAB (Divisor Latch Access Bit)
outb(port + UART_LCR, 0x80);
// 3. Set divisor (baud rate)
outb(port + UART_BAUD_LO, (uint8_t)(divisor & 0xFF));
outb(port + UART_BAUD_HI, (uint8_t)((divisor >> 8) & 0xFF));
// 4. Set 8 bits, no parity, 1 stop bit (8N1)
outb(port + UART_LCR, 0x03);
// 5. Enable FIFO, clear TX/RX, 14-byte threshold
outb(port + UART_FCR, 0xC7);
// 6. Turn on DTR, RTS, and OUT2 (enables interrupts)
outb(port + UART_MCR, 0x0B);
// 7. Test loopback
outb(port + UART_MCR, 0x1E);
outb(port + UART_DATA, 0xAE);
if (inb(port + UART_DATA) != 0xAE) {
return -1; // Faulty serial chip
}
// 8. Normal operation mode (not loopback)
outb(port + UART_MCR, 0x0F);
return 0;
}
int uart_is_tx_empty(uint16_t port) {
return (inb(port + UART_LSR) & 0x20);
}
void uart_putc(uint16_t port, char c) {
while (!uart_is_tx_empty(port)) {
__asm__ volatile("pause");
}
outb(port + UART_DATA, (uint8_t)c);
}
void uart_puts(uint16_t port, const char *s) {
while (*s) {
if (*s == '\n') {
uart_putc(port, '\r');
}
uart_putc(port, *s++);
}
}
void uart_write(uint16_t port, const char *buf, size_t len) {
for (size_t i = 0; i < len; i++) {
if (buf[i] == '\n') {
uart_putc(port, '\r');
}
uart_putc(port, buf[i]);
}
}
int uart_has_data(uint16_t port) {
return (inb(port + UART_LSR) & 0x01);
}
char uart_getc(uint16_t port) {
while (!uart_has_data(port)) {
__asm__ volatile("pause");
}
return (char)inb(port + UART_DATA);
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
/* IPC Protocol Flags */
#define IPC_FLAG_FAST_REGISTERS (1 << 0) /* Message fits entirely in registers */
#define IPC_FLAG_SHM_ATTACHED (1 << 1) /* Attached shared memory buffer */
#define IPC_FLAG_CAP_TRANSFER (1 << 2) /* Delegating capability in message */
#define IPC_FLAG_NONBLOCKING (1 << 3) /* Return immediately if receiver not ready */
/* Shared Memory Descriptor for Zero-Copy Transfers */
typedef struct ipc_shm_desc {
cap_t shm_cap; /* Capability to shared memory region */
uint64_t offset; /* Offset within SHM buffer */
uint64_t length; /* Length of data payload */
uint32_t permissions; /* Read/Write flags */
uint32_t _reserved;
} __attribute__((packed)) ipc_shm_desc_t;
/* IPC Message Payload Representation */
typedef struct ipc_msg {
uint64_t badge; /* Sender authentication badge (injected by kernel) */
uint32_t opcode; /* Interface Method / Function ID */
uint32_t flags; /* IPC_FLAG_* */
/* Fast-Path Register Payload (4 x 64-bit = 32 bytes directly passed) */
uint64_t args[4];
/* Zero-Copy Extended Descriptor */
ipc_shm_desc_t shm;
} __attribute__((aligned(16))) ipc_msg_t;
/* Standard Common IPC Opcodes */
#define IPC_OP_PING 0x0001
#define IPC_OP_PONG 0x0002
#define IPC_OP_REGISTER_SERVER 0x0010
#define IPC_OP_LOOKUP_SERVER 0x0011
#define IPC_OP_NOTIFY_EVENT 0x0020
#define IPC_OP_READ 0x0100
#define IPC_OP_WRITE 0x0101
#define IPC_OP_IOCTL 0x0102
#ifdef __cplusplus
}
#endif
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include "types.h"
/* Syscall Numbers (passed in RAX) */
#define SYS_IPC_CALL 1 /* Synchronous call: send message & wait for reply */
#define SYS_IPC_REPLY_RECV 2 /* Server fast-path: reply to current and wait next */
#define SYS_IPC_SEND 3 /* Asynchronous/non-blocking send */
#define SYS_IPC_RECV 4 /* Block waiting for incoming message */
#define SYS_MEM_MAP 5 /* Map memory / shared memory region */
#define SYS_CAP_GRANT 6 /* Delegate capability to CNode */
#define SYS_THREAD_YIELD 7 /* Yield CPU slice */
#define SYS_THREAD_EXIT 8 /* Terminate current thread */
#define SYS_LOG_DEBUG 9 /* Direct Ring 0 debug print */
#ifndef __ASSEMBLER__
#ifdef __cplusplus
extern "C" {
#endif
/* Low-level inline syscall invocations adhering to System V AMD64 ABI + Fast-Path */
static inline sysret_t sys_ipc_call_raw(cap_t dest_cap, uint64_t msg_code,
uint64_t arg0, uint64_t arg1,
uint64_t arg2, uint64_t arg3,
uint64_t *out0, uint64_t *out1) {
register uint64_t rax __asm__("rax") = SYS_IPC_CALL;
register uint64_t rdi __asm__("rdi") = dest_cap;
register uint64_t rsi __asm__("rsi") = msg_code;
register uint64_t rdx __asm__("rdx") = arg0;
register uint64_t r8 __asm__("r8") = arg1;
register uint64_t r9 __asm__("r9") = arg2;
register uint64_t r10 __asm__("r10") = arg3;
__asm__ volatile(
"syscall"
: "+r"(rax), "+r"(rdx), "+r"(r8)
: "r"(rdi), "r"(rsi), "r"(r9), "r"(r10)
: "rcx", "r11", "memory"
);
if (out0) *out0 = rdx;
if (out1) *out1 = r8;
return (sysret_t)rax;
}
static inline sysret_t sys_yield(void) {
register uint64_t rax __asm__("rax") = SYS_THREAD_YIELD;
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
return (sysret_t)rax;
}
static inline void sys_exit(int code) {
register uint64_t rax __asm__("rax") = SYS_THREAD_EXIT;
register uint64_t rdi __asm__("rdi") = (uint64_t)code;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
__builtin_unreachable();
}
static inline sysret_t sys_log_debug(const char *msg, size_t len) {
register uint64_t rax __asm__("rax") = SYS_LOG_DEBUG;
register uint64_t rdi __asm__("rdi") = (uint64_t)msg;
register uint64_t rsi __asm__("rsi") = (uint64_t)len;
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
return (sysret_t)rax;
}
#ifdef __cplusplus
}
#endif
#endif /* __ASSEMBLER__ */
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#else
#define UINT64_C(c) c
#endif
/* Standard Type Definitions */
typedef uint64_t cap_t; /* Capability handle */
typedef uint64_t vaddr_t; /* Virtual Address */
typedef uint64_t paddr_t; /* Physical Address */
typedef int64_t sysret_t; /* Syscall Return Code */
typedef uint32_t pid_t; /* Process ID */
typedef uint32_t tid_t; /* Thread ID */
/* Standard Return / Error Codes */
#define SYS_OK 0
#define SYS_ERR_INVALID_ARG -1
#define SYS_ERR_INVALID_CAP -2
#define SYS_ERR_NO_MEMORY -3
#define SYS_ERR_IPC_TIMEOUT -4
#define SYS_ERR_IPC_DEADLOCK -5
#define SYS_ERR_PERMISSION -6
#define SYS_ERR_NOT_FOUND -7
#define SYS_ERR_ALREADY_EXISTS -8
#define SYS_ERR_BUSY -9
/* Standard Special Capabilities */
#define CAP_NULL 0
#define CAP_SELF_TASK 1
#define CAP_SELF_THREAD 2
#define CAP_SELF_VMSPACE 3
#define CAP_ROOT_CSPACE 4
#define CAP_ROOT_IRQ 5
#define CAP_ROOT_IO 6
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "opencore_kernel"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "opencore_kernel"
path = "src/main.rs"
test = false
bench = false
+33
View File
@@ -0,0 +1,33 @@
/* opencoreC - Thread Context Switch */
.global switch_to
.section .text
/*
* void switch_to(uint64_t **prev_rsp_ptr, uint64_t *next_rsp);
* RDI = pointer to current thread's stored RSP
* RSI = target thread's RSP
*/
switch_to:
/* Push callee-saved registers of outgoing thread */
push rbp
push rbx
push r12
push r13
push r14
push r15
/* Save current stack pointer */
mov [rdi], rsp
/* Load target stack pointer */
mov rsp, rsi
/* Pop callee-saved registers of incoming thread */
pop r15
pop r14
pop r13
pop r12
pop rbx
pop rbp
ret
+53
View File
@@ -0,0 +1,53 @@
/* opencoreC - Fast Syscall Entry Trampoline (x86_64) */
.global syscall_entry
.extern kernel_syscall_dispatcher
.section .bss
.align 16
user_scratch_rsp:
.quad 0
kernel_temp_stack:
.skip 4096
kernel_temp_stack_top:
.section .text
syscall_entry:
/* Save user stack pointer */
mov [rip + user_scratch_rsp], rsp
lea rsp, [rip + kernel_temp_stack_top]
/* Save user RIP (in RCX) and user RFLAGS (in R11) */
push rcx
push r11
/* Save argument and volatile registers to construct SyscallRegisters */
push rax
push rdi
push rsi
push rdx
push r8
push r9
push r10
/* Pass pointer to SyscallRegisters struct in RDI */
mov rdi, rsp
call kernel_syscall_dispatcher
/* Restore registers (rax, rdx, r8 may have return values from dispatcher) */
pop r10
pop r9
pop r8
pop rdx
pop rsi
pop rdi
pop rax
/* Restore user RIP and RFLAGS */
pop r11
pop rcx
/* Restore user stack */
mov rsp, [rip + user_scratch_rsp]
/* Return to Ring 3 */
sysretq
+102
View File
@@ -0,0 +1,102 @@
//! Global Descriptor Table (GDT) and Task State Segment (TSS) for x86_64
use core::mem::size_of;
#[repr(C, packed)]
pub struct TaskStateSegment {
_reserved1: u32,
pub rsp0: u64,
pub rsp1: u64,
pub rsp2: u64,
_reserved2: u64,
pub ist: [u64; 7],
_reserved3: u64,
_reserved4: u16,
pub iomap_base: u16,
}
impl TaskStateSegment {
pub const fn new() -> Self {
Self {
_reserved1: 0,
rsp0: 0,
rsp1: 0,
rsp2: 0,
_reserved2: 0,
ist: [0; 7],
_reserved3: 0,
_reserved4: 0,
iomap_base: size_of::<TaskStateSegment>() as u16,
}
}
}
#[repr(C, packed)]
struct GdtDescriptor {
limit: u16,
base: u64,
}
pub static mut TSS: TaskStateSegment = TaskStateSegment::new();
// 8 entries: Null, KCode, KData, UData, UCode, TSS Low, TSS High, Null
static mut GDT: [u64; 8] = [
0x0000000000000000, // 0x00: Null
0x00af9a000000ffff, // 0x08: Kernel Code 64 (Ring 0)
0x00cf92000000ffff, // 0x10: Kernel Data 64 (Ring 0)
0x00cff2000000ffff, // 0x18: User Data 64 (Ring 3)
0x00affa000000ffff, // 0x20: User Code 64 (Ring 3)
0x0000000000000000, // 0x28: TSS Low (populated at init)
0x0000000000000000, // 0x30: TSS High (populated at init)
0x0000000000000000, // 0x38: Alignment / padding
];
pub unsafe fn init() {
let tss_addr = core::ptr::addr_of!(TSS) as u64;
let tss_size = (size_of::<TaskStateSegment>() - 1) as u64;
// Build 64-bit TSS descriptor
let tss_low = (tss_size & 0xffff)
| ((tss_addr & 0xffff) << 16)
| (((tss_addr >> 16) & 0xff) << 32)
| (0x89u64 << 40) // Present, 64-bit TSS (Available)
| (((tss_size >> 16) & 0xf) << 48)
| (((tss_addr >> 24) & 0xff) << 56);
let tss_high = tss_addr >> 32;
let gdt_ptr = core::ptr::addr_of_mut!(GDT) as *mut u64;
*gdt_ptr.add(5) = tss_low;
*gdt_ptr.add(6) = tss_high;
let descriptor = GdtDescriptor {
limit: (size_of::<[u64; 8]>() - 1) as u16,
base: gdt_ptr as u64,
};
core::arch::asm!(
"lgdt [{0}]",
"push 0x08",
"lea {tmp}, [2f + rip]",
"push {tmp}",
"retfq",
"2:",
"mov ax, 0x10",
"mov ds, ax",
"mov es, ax",
"mov ss, ax",
"mov fs, ax",
"mov gs, ax",
"ltr {tss_sel:x}",
in(reg) &descriptor,
tmp = out(reg) _,
tss_sel = in(reg) (0x28u16),
options(preserves_flags)
);
}
pub fn set_kernel_stack(stack_top: u64) {
unsafe {
let tss_ptr = core::ptr::addr_of_mut!(TSS);
(*tss_ptr).rsp0 = stack_top;
}
}
+99
View File
@@ -0,0 +1,99 @@
//! Interrupt Descriptor Table (IDT) and Exception Handling
use crate::kprintln;
use core::mem::size_of;
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct IdtEntry {
offset_low: u16,
selector: u16,
ist: u8,
type_attr: u8,
offset_mid: u16,
offset_high: u32,
_reserved: u32,
}
impl IdtEntry {
pub const fn missing() -> Self {
Self {
offset_low: 0,
selector: 0,
ist: 0,
type_attr: 0,
offset_mid: 0,
offset_high: 0,
_reserved: 0,
}
}
pub fn set_handler(&mut self, handler: u64, ist: u8, dpl: u8) {
self.offset_low = (handler & 0xffff) as u16;
self.selector = 0x08; // Kernel code segment
self.ist = ist & 0x7;
self.type_attr = 0x80 | ((dpl & 0x3) << 5) | 0x0E; // 64-bit Interrupt Gate Present
self.offset_mid = ((handler >> 16) & 0xffff) as u16;
self.offset_high = ((handler >> 32) & 0xffffffff) as u32;
self._reserved = 0;
}
}
#[repr(C, packed)]
struct IdtDescriptor {
limit: u16,
base: u64,
}
static mut IDT: [IdtEntry; 256] = [IdtEntry::missing(); 256];
extern "C" {
fn default_isr_stub();
}
// Global assembly ISR stub for default exception handling
core::arch::global_asm!(
".global default_isr_stub",
"default_isr_stub:",
"push rax",
"push rcx",
"push rdx",
"push rsi",
"push rdi",
"push r8",
"push r9",
"push r10",
"push r11",
"mov rdi, rsp",
"call raw_exception_handler",
"pop r11",
"pop r10",
"pop r9",
"pop r8",
"pop rdi",
"pop rsi",
"pop rdx",
"pop rcx",
"pop rax",
"iretq"
);
pub unsafe fn init() {
let stub_addr = default_isr_stub as *const () as usize as u64;
let idt_ptr = core::ptr::addr_of_mut!(IDT) as *mut IdtEntry;
for i in 0..256 {
(*idt_ptr.add(i)).set_handler(stub_addr, 0, 0);
}
let descriptor = IdtDescriptor {
limit: (size_of::<[IdtEntry; 256]>() - 1) as u16,
base: idt_ptr as u64,
};
core::arch::asm!("lidt [{0}]", in(reg) &descriptor, options(preserves_flags));
}
#[no_mangle]
pub extern "C" fn raw_exception_handler(stack_ptr: *const u64) {
kprintln!("[CPU EXCEPTION] Trap triggered at stack frame: {:p}", stack_ptr);
}
+9
View File
@@ -0,0 +1,9 @@
pub mod gdt;
pub mod idt;
pub mod syscall;
pub unsafe fn init() {
gdt::init();
idt::init();
syscall::init();
}
+113
View File
@@ -0,0 +1,113 @@
//! x86_64 Fast Syscall / Sysret Setup and Fast-Path Dispatch
use crate::kprintln;
const IA32_EFER: u32 = 0xC0000080;
const IA32_STAR: u32 = 0xC0000081;
const IA32_LSTAR: u32 = 0xC0000082;
const IA32_FMASK: u32 = 0xC0000084;
#[inline]
unsafe fn wrmsr(msr: u32, value: u64) {
let low = value as u32;
let high = (value >> 32) as u32;
core::arch::asm!(
"wrmsr",
in("ecx") msr,
in("eax") low,
in("edx") high,
options(nostack, preserves_flags)
);
}
#[inline]
unsafe fn rdmsr(msr: u32) -> u64 {
let low: u32;
let high: u32;
core::arch::asm!(
"rdmsr",
in("ecx") msr,
out("eax") low,
out("edx") high,
options(nostack, preserves_flags)
);
((high as u64) << 32) | (low as u64)
}
extern "C" {
fn syscall_entry();
}
pub unsafe fn init() {
// 1. Enable System Call Extension (SCE) in IA32_EFER
let efer = rdmsr(IA32_EFER);
wrmsr(IA32_EFER, efer | 1);
// 2. Set STAR MSR:
// Bits [47:32] = Kernel CS/SS selectors (0x0008)
// Bits [63:48] = User CS/SS selectors base (0x0010 -> SS=0x18, CS=0x20)
let star = (0x0010u64 << 48) | (0x0008u64 << 32);
wrmsr(IA32_STAR, star);
// 3. Set LSTAR to our assembly entry trampoline
wrmsr(IA32_LSTAR, syscall_entry as *const () as usize as u64);
// 4. Set FMASK to clear IF (bit 9, 0x200), DF (bit 10), TF (bit 8)
wrmsr(IA32_FMASK, 0x00000200);
}
#[repr(C)]
pub struct SyscallRegisters {
pub r10: u64,
pub r9: u64,
pub r8: u64,
pub rdx: u64,
pub rsi: u64,
pub rdi: u64,
pub rax: u64, // Syscall number in, return code out
}
/// Dispatcher called directly from syscall_entry assembly trampoline
#[no_mangle]
pub extern "C" fn kernel_syscall_dispatcher(regs: &mut SyscallRegisters) {
match regs.rax {
// SYS_IPC_CALL = 1
1 => {
let dest_cap = regs.rdi;
let opcode = regs.rsi;
let arg0 = regs.rdx;
let arg1 = regs.r8;
let arg2 = regs.r9;
let arg3 = regs.r10;
let (ret, out0, out1) = crate::ipc::fastpath::handle_fastpath_call(
dest_cap, opcode, arg0, arg1, arg2, arg3,
);
regs.rax = ret as u64;
regs.rdx = out0;
regs.r8 = out1;
}
// SYS_THREAD_YIELD = 7
7 => {
regs.rax = 0;
}
// SYS_LOG_DEBUG = 9
9 => {
let msg_ptr = regs.rdi as *const u8;
let len = regs.rsi as usize;
if !msg_ptr.is_null() && len > 0 && len < 4096 {
let slice = unsafe { core::slice::from_raw_parts(msg_ptr, len) };
if let Ok(s) = core::str::from_utf8(slice) {
kprintln!("[USER LOG] {}", s);
regs.rax = 0;
return;
}
}
regs.rax = (-1i64) as u64;
}
_ => {
regs.rax = (-1i64) as u64; // SYS_ERR_INVALID_ARG
}
}
}
+1
View File
@@ -0,0 +1 @@
pub mod serial;
+83
View File
@@ -0,0 +1,83 @@
//! Early Serial Driver (16550 UART on COM1 0x3F8)
use core::fmt::{self, Write};
use core::sync::atomic::{AtomicBool, Ordering};
const COM1: u16 = 0x3F8;
static SERIAL_INITIALIZED: AtomicBool = AtomicBool::new(false);
#[inline]
unsafe fn outb(port: u16, val: u8) {
core::arch::asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags));
}
#[inline]
unsafe fn inb(port: u16) -> u8 {
let mut val: u8;
core::arch::asm!("in al, dx", in("dx") port, out("al") val, options(nomem, nostack, preserves_flags));
val
}
pub struct SerialPort;
impl SerialPort {
pub fn init() {
unsafe {
outb(COM1 + 1, 0x00); // Disable all interrupts
outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor)
outb(COM1 + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
outb(COM1 + 1, 0x00); // (hi byte)
outb(COM1 + 3, 0x03); // 8 bits, no parity, one stop bit
outb(COM1 + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(COM1 + 4, 0x0B); // IRQs enabled, RTS/DSR set
}
SERIAL_INITIALIZED.store(true, Ordering::Release);
}
pub fn write_byte(&self, byte: u8) {
unsafe {
// Wait for transmit buffer empty
while (inb(COM1 + 5) & 0x20) == 0 {
core::hint::spin_loop();
}
outb(COM1, byte);
}
}
pub fn write_str(&self, s: &str) {
for b in s.bytes() {
if b == b'\n' {
self.write_byte(b'\r');
}
self.write_byte(b);
}
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> fmt::Result {
SerialPort.write_str(s);
Ok(())
}
}
pub fn _kprint(args: fmt::Arguments) {
let mut port = SerialPort;
let _ = port.write_fmt(args);
}
#[macro_export]
macro_rules! kprint {
($($arg:tt)*) => {
$crate::drivers::serial::_kprint(format_args!($($arg)*))
};
}
#[macro_export]
macro_rules! kprintln {
() => ($crate::kprint!("\n"));
($($arg:tt)*) => ({
$crate::kprint!("{}\n", format_args!($($arg)*));
});
}
+53
View File
@@ -0,0 +1,53 @@
//! High-Performance Fast-Path IPC Subsystem
use crate::kprintln;
pub const IPC_OP_PING: u64 = 0x0001;
pub const IPC_OP_PONG: u64 = 0x0002;
pub const IPC_OP_REGISTER_SERVER: u64 = 0x0010;
pub const IPC_OP_LOOKUP_SERVER: u64 = 0x0011;
pub const CAP_KERNEL_CONTROL: u64 = 1;
pub const CAP_ROOT_SERVER: u64 = 2;
#[derive(Clone, Copy)]
pub struct FastPathMessage {
pub dest_cap: u64,
pub opcode: u64,
pub args: [u64; 4],
}
/// Dispatches a fast-path register message directly in Ring 0
pub fn handle_fastpath_call(
dest_cap: u64,
opcode: u64,
arg0: u64,
_arg1: u64,
_arg2: u64,
_arg3: u64,
) -> (i64, u64, u64) {
match dest_cap {
CAP_KERNEL_CONTROL => {
match opcode {
IPC_OP_PING => {
// Fast ping-pong check (arg0 is sequence, return arg0 + 1)
(0, IPC_OP_PONG, arg0.wrapping_add(1))
}
IPC_OP_REGISTER_SERVER => {
kprintln!("[IPC-FAST] Server registered with token: {:#x}", arg0);
(0, 0, 0)
}
IPC_OP_LOOKUP_SERVER => {
// Return capability id for requested server hash
(0, CAP_ROOT_SERVER, 0)
}
_ => (-1, 0, 0), // Invalid opcode
}
}
CAP_ROOT_SERVER => {
kprintln!("[IPC-FAST] Forwarding call to Root Server (opcode: {:#x}, arg0: {:#x})", opcode, arg0);
(0, 0xCAFE_BABE, 0)
}
_ => (-2, 0, 0), // Invalid capability
}
}
+5
View File
@@ -0,0 +1,5 @@
pub mod fastpath;
pub fn init() {
crate::kprintln!("[IPC] Capability-based Fast-Path IPC Ready.");
}
+162
View File
@@ -0,0 +1,162 @@
//! Limine Bootloader Protocol Requests & Types for opencoreC Microkernel
//! Implements Base Revision 3 specification.
#[repr(C)]
pub struct LimineBaseRevision {
pub id: [u64; 4],
pub revision: u64,
}
unsafe impl Sync for LimineBaseRevision {}
#[repr(C)]
pub struct LimineHhdmResponse {
pub revision: u64,
pub offset: u64,
}
#[repr(C)]
pub struct LimineHhdmRequest {
pub id: [u64; 4],
pub revision: u64,
pub response: *const LimineHhdmResponse,
}
unsafe impl Sync for LimineHhdmRequest {}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LimineMemoryType {
Usable = 0,
Reserved = 1,
AcpiReclaimable = 2,
AcpiNvs = 3,
BadMemory = 4,
BootloaderReclaimable = 5,
KernelAndModules = 6,
Framebuffer = 7,
}
#[repr(C)]
pub struct LimineMemmapEntry {
pub base: u64,
pub length: u64,
pub typ: u64,
}
#[repr(C)]
pub struct LimineMemmapResponse {
pub revision: u64,
pub entry_count: u64,
pub entries: *const *const LimineMemmapEntry,
}
#[repr(C)]
pub struct LimineMemmapRequest {
pub id: [u64; 4],
pub revision: u64,
pub response: *const LimineMemmapResponse,
}
unsafe impl Sync for LimineMemmapRequest {}
#[repr(C)]
pub struct LimineKernelAddressResponse {
pub revision: u64,
pub physical_base: u64,
pub virtual_base: u64,
}
#[repr(C)]
pub struct LimineKernelAddressRequest {
pub id: [u64; 4],
pub revision: u64,
pub response: *const LimineKernelAddressResponse,
}
unsafe impl Sync for LimineKernelAddressRequest {}
#[repr(C)]
pub struct LimineFile {
pub revision: u64,
pub address: *const u8,
pub size: u64,
pub path: *const u8,
pub cmdline: *const u8,
pub media_type: u32,
pub unused: u32,
pub tftp_ip: u32,
pub tftp_port: u32,
pub partition_index: u32,
pub mbr_disk_id: u32,
pub gpt_disk_uuid: [u8; 16],
pub gpt_part_uuid: [u8; 16],
pub part_uuid: [u8; 16],
}
#[repr(C)]
pub struct LimineModuleResponse {
pub revision: u64,
pub module_count: u64,
pub modules: *const *const LimineFile,
}
#[repr(C)]
pub struct LimineModuleRequest {
pub id: [u64; 4],
pub revision: u64,
pub response: *const LimineModuleResponse,
pub internal_module_count: u64,
pub internal_modules: *const *const LimineFile,
}
unsafe impl Sync for LimineModuleRequest {}
/* Constants for Limine Request Identifiers */
#[used]
#[link_section = ".limine_requests"]
pub static BASE_REVISION: LimineBaseRevision = LimineBaseRevision {
id: [0xf9562b2d5c95a6c8, 0x6a59638edd43477b, 0, 3],
revision: 3,
};
#[used]
#[link_section = ".limine_requests"]
pub static HHDM_REQUEST: LimineHhdmRequest = LimineHhdmRequest {
id: [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x48d150213051ecda, 0x21e2d0708170e71e],
revision: 0,
response: core::ptr::null(),
};
#[used]
#[link_section = ".limine_requests"]
pub static MEMMAP_REQUEST: LimineMemmapRequest = LimineMemmapRequest {
id: [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x67cf3d9d378a14e6, 0xe310ac092f613308],
revision: 0,
response: core::ptr::null(),
};
#[used]
#[link_section = ".limine_requests"]
pub static KERNEL_ADDRESS_REQUEST: LimineKernelAddressRequest = LimineKernelAddressRequest {
id: [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x71ba76863cc55f63, 0xb2644a48c516a487],
revision: 0,
response: core::ptr::null(),
};
#[used]
#[link_section = ".limine_requests"]
pub static MODULE_REQUEST: LimineModuleRequest = LimineModuleRequest {
id: [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b, 0x3e7e2797022b3699, 0xa69dc94525d978b1],
revision: 0,
response: core::ptr::null(),
internal_module_count: 0,
internal_modules: core::ptr::null(),
};
/// Get HHDM direct map virtual offset
pub fn get_hhdm_offset() -> Option<u64> {
unsafe {
let resp = HHDM_REQUEST.response;
if !resp.is_null() {
Some((*resp).offset)
} else {
None
}
}
}
+120
View File
@@ -0,0 +1,120 @@
#![no_std]
#![no_main]
pub mod limine_requests;
pub mod drivers;
pub mod arch;
pub mod mm;
pub mod ipc;
pub mod sched;
use core::panic::PanicInfo;
use limine_requests::*;
// Include assembly trampolines directly into the binary
core::arch::global_asm!(include_str!("../asm/context.S"));
core::arch::global_asm!(include_str!("../asm/syscall_entry.S"));
#[no_mangle]
pub extern "C" fn _start() -> ! {
// 1. Validate Limine Base Revision
if BASE_REVISION.revision != 3 {
// Revision mismatch
loop { core::hint::spin_loop(); }
}
// 2. Early Serial Initialization
drivers::serial::SerialPort::init();
kprintln!("\n=======================================================");
kprintln!(" opencoreC Microkernel v0.1.0 (x86_64)");
kprintln!("=======================================================");
// 3. Obtain Limine responses
let hhdm_offset = get_hhdm_offset().expect("Limine HHDM response missing");
let memmap_resp = MEMMAP_REQUEST.response;
let kernel_addr_resp = KERNEL_ADDRESS_REQUEST.response;
kprintln!("[BOOT] Limine HHDM Base Virtual Address: {:#018x}", hhdm_offset);
if !kernel_addr_resp.is_null() {
unsafe {
kprintln!("[BOOT] Kernel Physical Base: {:#018x}, Virtual Base: {:#018x}",
(*kernel_addr_resp).physical_base,
(*kernel_addr_resp).virtual_base
);
}
}
// 4. Initialize Architecture (GDT, IDT, Syscall MSRs)
kprintln!("[BOOT] Initializing GDT, IDT, and Fast-Path Syscall MSRs...");
unsafe {
arch::init();
}
kprintln!("[BOOT] CPU Subsystem Configured.");
// 5. Initialize Memory Subsystem (Physical Frame Allocator + Virtual Memory Manager)
kprintln!("[BOOT] Initializing Physical Frame Allocator & Paging...");
unsafe {
mm::init(memmap_resp);
}
// 6. Initialize IPC & Capability System
ipc::init();
// 7. Initialize Scheduler
sched::init();
// 8. Inspect Boot Modules (Initial Userspace Servers)
unsafe {
let mod_resp = MODULE_REQUEST.response;
if !mod_resp.is_null() {
let count = (*mod_resp).module_count;
kprintln!("[BOOT] Found {} initial userspace module(s):", count);
for i in 0..count {
let mod_file = *(*mod_resp).modules.add(i as usize);
let path_cstr = (*mod_file).path;
let path_len = (0..256).find(|&j| *path_cstr.add(j) == 0).unwrap_or(0);
let path = core::str::from_utf8(core::slice::from_raw_parts(path_cstr, path_len)).unwrap_or("unknown");
kprintln!(" - Module [{}]: {} (size: {} bytes, addr: {:p})",
i, path, (*mod_file).size, (*mod_file).address);
}
} else {
kprintln!("[BOOT] No external modules passed by bootloader.");
}
}
// 9. Kernel Self-Test: Fast-Path IPC Ping
kprintln!("[TEST] Executing Kernel Fast-Path IPC Self-Test...");
let (status, resp_op, val) = ipc::fastpath::handle_fastpath_call(
ipc::fastpath::CAP_KERNEL_CONTROL,
ipc::fastpath::IPC_OP_PING,
42, 0, 0, 0
);
kprintln!("[TEST] IPC Fast-Path Ping Result: status={}, opcode={:#x}, val={}", status, resp_op, val);
kprintln!("[KERNEL] Initialization complete. Entering kernel idle loop.\n");
loop {
unsafe {
core::arch::asm!("hlt");
}
}
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
kprintln!("\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
kprintln!(" KERNEL PANIC DETECTED ");
kprintln!("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
if let Some(location) = info.location() {
kprintln!("Location: {}:{}:{}", location.file(), location.line(), location.column());
}
kprintln!("Message: {}", info.message());
kprintln!("Halting CPU core.");
loop {
unsafe {
core::arch::asm!("cli; hlt");
}
}
}
+14
View File
@@ -0,0 +1,14 @@
pub mod pfa;
pub mod vmm;
use crate::limine_requests::{LimineMemmapResponse, get_hhdm_offset};
use crate::kprintln;
pub unsafe fn init(memmap: *const LimineMemmapResponse) {
let hhdm = get_hhdm_offset().expect("Limine HHDM is required");
let pfa_ptr = core::ptr::addr_of_mut!(pfa::PFA);
let vmm_ptr = core::ptr::addr_of_mut!(vmm::VMM);
(*pfa_ptr).init(memmap, hhdm);
(*vmm_ptr).init(hhdm);
kprintln!("[MM] Memory Management Subsystem Initialized.");
}
+167
View File
@@ -0,0 +1,167 @@
//! Physical Frame Allocator (PFA)
//! Bitmap-based 4KiB page frame allocator.
use crate::limine_requests::{LimineMemmapResponse, LimineMemoryType};
use crate::kprintln;
pub const PAGE_SIZE: usize = 4096;
pub struct FrameAllocator {
bitmap: *mut u8,
bitmap_size_bytes: usize,
total_frames: usize,
free_frames: usize,
hhdm_offset: u64,
}
unsafe impl Send for FrameAllocator {}
unsafe impl Sync for FrameAllocator {}
pub static mut PFA: FrameAllocator = FrameAllocator {
bitmap: core::ptr::null_mut(),
bitmap_size_bytes: 0,
total_frames: 0,
free_frames: 0,
hhdm_offset: 0,
};
impl FrameAllocator {
pub unsafe fn init(&mut self, memmap: *const LimineMemmapResponse, hhdm: u64) {
self.hhdm_offset = hhdm;
if memmap.is_null() {
return;
}
let entry_count = (*memmap).entry_count as usize;
let entries = (*memmap).entries;
let mut max_paddr: u64 = 0;
for i in 0..entry_count {
let entry = *entries.add(i);
let end = (*entry).base + (*entry).length;
if end > max_paddr {
max_paddr = end;
}
}
self.total_frames = (max_paddr as usize) / PAGE_SIZE;
self.bitmap_size_bytes = (self.total_frames + 7) / 8;
// Find a usable region large enough to place the bitmap
let mut bitmap_paddr: u64 = 0;
for i in 0..entry_count {
let entry = *entries.add(i);
if (*entry).typ == LimineMemoryType::Usable as u64
&& (*entry).length >= self.bitmap_size_bytes as u64
{
bitmap_paddr = (*entry).base;
break;
}
}
if bitmap_paddr == 0 {
kprintln!("[FATAL] Could not find memory for PFA bitmap!");
return;
}
self.bitmap = (bitmap_paddr + hhdm) as *mut u8;
// Initially mark all frames as used (1)
core::ptr::write_bytes(self.bitmap, 0xFF, self.bitmap_size_bytes);
// Mark only truly usable RAM regions as free (0)
self.free_frames = 0;
for i in 0..entry_count {
let entry = *entries.add(i);
if (*entry).typ == LimineMemoryType::Usable as u64 {
let start_frame = ((*entry).base as usize) / PAGE_SIZE;
let count = ((*entry).length as usize) / PAGE_SIZE;
for f in start_frame..(start_frame + count) {
self.clear_bit(f);
self.free_frames += 1;
}
}
}
// Mark the bitmap memory itself as allocated
let bitmap_start_frame = (bitmap_paddr as usize) / PAGE_SIZE;
let bitmap_frame_count = (self.bitmap_size_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
for f in bitmap_start_frame..(bitmap_start_frame + bitmap_frame_count) {
self.set_bit(f);
if self.free_frames > 0 {
self.free_frames -= 1;
}
}
// Also protect low 1MiB
let low_1mb_frames = 0x100000 / PAGE_SIZE;
for f in 0..low_1mb_frames {
if !self.test_bit(f) {
self.set_bit(f);
if self.free_frames > 0 {
self.free_frames -= 1;
}
}
}
kprintln!("[PFA] Initialized: {} MiB total, {} MiB free",
(self.total_frames * PAGE_SIZE) / (1024 * 1024),
(self.free_frames * PAGE_SIZE) / (1024 * 1024)
);
}
#[inline]
fn test_bit(&self, frame: usize) -> bool {
if frame >= self.total_frames {
return true;
}
unsafe {
let byte = *self.bitmap.add(frame / 8);
(byte & (1 << (frame % 8))) != 0
}
}
#[inline]
fn set_bit(&self, frame: usize) {
if frame < self.total_frames {
unsafe {
let ptr = self.bitmap.add(frame / 8);
*ptr |= 1 << (frame % 8);
}
}
}
#[inline]
fn clear_bit(&self, frame: usize) {
if frame < self.total_frames {
unsafe {
let ptr = self.bitmap.add(frame / 8);
*ptr &= !(1 << (frame % 8));
}
}
}
pub fn alloc_frame(&mut self) -> Option<u64> {
for frame in 0..self.total_frames {
if !self.test_bit(frame) {
self.set_bit(frame);
self.free_frames -= 1;
let paddr = (frame * PAGE_SIZE) as u64;
// Zero out the frame
unsafe {
let vaddr = (paddr + self.hhdm_offset) as *mut u8;
core::ptr::write_bytes(vaddr, 0, PAGE_SIZE);
}
return Some(paddr);
}
}
None
}
pub fn free_frame(&mut self, paddr: u64) {
let frame = (paddr as usize) / PAGE_SIZE;
if frame < self.total_frames && self.test_bit(frame) {
self.clear_bit(frame);
self.free_frames += 1;
}
}
}
+90
View File
@@ -0,0 +1,90 @@
//! Virtual Memory Manager (VMM) & 4-Level Paging (x86_64)
use super::pfa::PFA;
pub const PAGE_PRESENT: u64 = 1 << 0;
pub const PAGE_WRITABLE: u64 = 1 << 1;
pub const PAGE_USER: u64 = 1 << 2;
pub const PAGE_WRITE_THROUGH: u64 = 1 << 3;
pub const PAGE_NO_CACHE: u64 = 1 << 4;
pub const PAGE_HUGE: u64 = 1 << 7;
pub const PAGE_NO_EXECUTE: u64 = 1 << 63;
pub const PAGE_MASK: u64 = 0x000F_FFFF_FFFF_F000;
#[repr(C, align(4096))]
pub struct PageTable {
pub entries: [u64; 512],
}
pub struct VirtualMemoryManager {
hhdm_offset: u64,
}
pub static mut VMM: VirtualMemoryManager = VirtualMemoryManager { hhdm_offset: 0 };
impl VirtualMemoryManager {
pub fn init(&mut self, hhdm: u64) {
self.hhdm_offset = hhdm;
}
#[inline]
fn phys_to_virt<T>(&self, paddr: u64) -> *mut T {
(paddr + self.hhdm_offset) as *mut T
}
/// Map a single 4KiB page into the specified PML4
pub unsafe fn map_page(
&self,
pml4_paddr: u64,
vaddr: u64,
paddr: u64,
flags: u64,
) -> Result<(), ()> {
let pml4_idx = ((vaddr >> 39) & 0x1FF) as usize;
let pdpt_idx = ((vaddr >> 30) & 0x1FF) as usize;
let pd_idx = ((vaddr >> 21) & 0x1FF) as usize;
let pt_idx = ((vaddr >> 12) & 0x1FF) as usize;
let pml4 = self.phys_to_virt::<PageTable>(pml4_paddr);
// 1. Traverse / allocate PDPT
let pdpt_paddr = self.get_or_alloc_table(&mut (*pml4).entries[pml4_idx], flags)?;
let pdpt = self.phys_to_virt::<PageTable>(pdpt_paddr);
// 2. Traverse / allocate PD
let pd_paddr = self.get_or_alloc_table(&mut (*pdpt).entries[pdpt_idx], flags)?;
let pd = self.phys_to_virt::<PageTable>(pd_paddr);
// 3. Traverse / allocate PT
let pt_paddr = self.get_or_alloc_table(&mut (*pd).entries[pd_idx], flags)?;
let pt = self.phys_to_virt::<PageTable>(pt_paddr);
// 4. Map the physical page in the PT
(*pt).entries[pt_idx] = (paddr & PAGE_MASK) | flags | PAGE_PRESENT;
// Invalidate TLB for this virtual address
core::arch::asm!("invlpg [{0}]", in(reg) vaddr, options(nostack, preserves_flags));
Ok(())
}
unsafe fn get_or_alloc_table(&self, entry: &mut u64, inherit_flags: u64) -> Result<u64, ()> {
if (*entry & PAGE_PRESENT) != 0 {
// Update permissions if user access required
if (inherit_flags & PAGE_USER) != 0 {
*entry |= PAGE_USER;
}
if (inherit_flags & PAGE_WRITABLE) != 0 {
*entry |= PAGE_WRITABLE;
}
Ok(*entry & PAGE_MASK)
} else {
let pfa_ptr = core::ptr::addr_of_mut!(PFA);
let new_frame = (*pfa_ptr).alloc_frame().ok_or(())?;
let flags = PAGE_PRESENT | PAGE_WRITABLE | (inherit_flags & PAGE_USER);
*entry = (new_frame & PAGE_MASK) | flags;
Ok(new_frame)
}
}
}
+35
View File
@@ -0,0 +1,35 @@
//! Minimal Thread & Task Scheduler Subsystem
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThreadState {
Ready,
Running,
BlockedOnIpc,
Dead,
}
#[repr(C)]
pub struct ContextFrame {
pub r15: u64,
pub r14: u64,
pub r13: u64,
pub r12: u64,
pub rbx: u64,
pub rbp: u64,
pub rsp: u64,
pub rip: u64,
pub rflags: u64,
}
pub struct Thread {
pub id: u64,
pub state: ThreadState,
pub rsp: u64,
pub cr3: u64,
pub kernel_stack_top: u64,
}
pub fn init() {
crate::kprintln!("[SCHED] Scheduler initialized (Round-Robin preemptive stub).");
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
#ifndef NULL
#define NULL ((void*)0)
#endif
#ifndef offsetof
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
+24
View File
@@ -0,0 +1,24 @@
#pragma once
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
#define INT8_MAX 127
#define INT16_MAX 32767
#define INT32_MAX 2147483647
#define INT64_MAX 9223372036854775807LL
#define UINT8_MAX 255
#define UINT16_MAX 65535
#define UINT32_MAX 4294967295U
#define UINT64_MAX 18446744073709551615ULL
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "stddef.h"
#include "stdint.h"
#ifdef __cplusplus
extern "C" {
#endif
int puts(const char *s);
int putchar(int c);
#ifdef __cplusplus
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "stddef.h"
#include "stdint.h"
#ifdef __cplusplus
extern "C" {
#endif
void *memset(void *dest, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
size_t strlen(const char *s);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
#ifdef __cplusplus
}
#endif
+92
View File
@@ -0,0 +1,92 @@
#include "../include/string.h"
void *memset(void *dest, int c, size_t n) {
uint8_t *p = (uint8_t *)dest;
uint8_t val = (uint8_t)c;
while (n--) {
*p++ = val;
}
return dest;
}
void *memcpy(void *dest, const void *src, size_t n) {
uint8_t *d = (uint8_t *)dest;
const uint8_t *s = (const uint8_t *)src;
while (n--) {
*d++ = *s++;
}
return dest;
}
void *memmove(void *dest, const void *src, size_t n) {
uint8_t *d = (uint8_t *)dest;
const uint8_t *s = (const uint8_t *)src;
if (d < s) {
while (n--) {
*d++ = *s++;
}
} else {
d += n;
s += n;
while (n--) {
*--d = *--s;
}
}
return dest;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const uint8_t *p1 = (const uint8_t *)s1;
const uint8_t *p2 = (const uint8_t *)s2;
while (n--) {
if (*p1 != *p2) {
return *p1 - *p2;
}
p1++;
p2++;
}
return 0;
}
size_t strlen(const char *s) {
size_t len = 0;
while (s[len]) {
len++;
}
return len;
}
int strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++;
s2++;
}
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
}
int strncmp(const char *s1, const char *s2, size_t n) {
while (n && *s1 && (*s1 == *s2)) {
s1++;
s2++;
n--;
}
if (n == 0) return 0;
return *(const unsigned char *)s1 - *(const unsigned char *)s2;
}
char *strcpy(char *dest, const char *src) {
char *ret = dest;
while ((*dest++ = *src++));
return ret;
}
char *strncpy(char *dest, const char *src, size_t n) {
char *ret = dest;
while (n && (*dest++ = *src++)) {
n--;
}
while (n--) {
*dest++ = '\0';
}
return ret;
}
+17
View File
@@ -0,0 +1,17 @@
#include "stdio.h"
#include "abi/syscalls.h"
#include "abi/types.h"
int puts(const char *s) {
size_t len = 0;
while (s[len]) len++;
sys_log_debug(s, len);
sys_log_debug("\n", 1);
return (int)len;
}
int putchar(int c) {
char ch = (char)c;
sys_log_debug(&ch, 1);
return c;
}
+116
View File
@@ -0,0 +1,116 @@
#pragma once
#include "abi/types.h"
#include "abi/syscalls.h"
#include "abi/ipc.h"
#include "stddef.h"
#include "stdint.h"
namespace ipc {
// Strongly typed result wrapper (no exceptions)
template <typename T>
struct Result {
sysret_t status;
T value;
constexpr bool is_ok() const noexcept { return status == SYS_OK; }
constexpr bool is_err() const noexcept { return status != SYS_OK; }
constexpr sysret_t error() const noexcept { return status; }
};
struct FastResponse {
uint64_t out0;
uint64_t out1;
};
// RAII Capability Handle
class Capability {
private:
cap_t handle_;
public:
constexpr Capability() noexcept : handle_(CAP_NULL) {}
constexpr explicit Capability(cap_t handle) noexcept : handle_(handle) {}
~Capability() {
// Future: syscall to drop capability reference
}
Capability(const Capability&) = delete;
Capability& operator=(const Capability&) = delete;
constexpr Capability(Capability&& other) noexcept : handle_(other.handle_) {
other.handle_ = CAP_NULL;
}
constexpr Capability& operator=(Capability&& other) noexcept {
if (this != &other) {
handle_ = other.handle_;
other.handle_ = CAP_NULL;
}
return *this;
}
[[nodiscard]] constexpr cap_t get() const noexcept { return handle_; }
[[nodiscard]] constexpr bool is_valid() const noexcept { return handle_ != CAP_NULL; }
};
// RAII IPC Endpoint Wrapper
class Endpoint {
private:
Capability cap_;
public:
explicit Endpoint(Capability&& cap) noexcept : cap_(static_cast<Capability&&>(cap)) {}
explicit Endpoint(cap_t cap) noexcept : cap_(cap) {}
// Fast-path synchronous register call (zero allocations)
[[nodiscard]] Result<FastResponse> call(
uint64_t opcode,
uint64_t arg0 = 0,
uint64_t arg1 = 0,
uint64_t arg2 = 0,
uint64_t arg3 = 0
) const noexcept {
uint64_t out0 = 0;
uint64_t out1 = 0;
sysret_t ret = sys_ipc_call_raw(cap_.get(), opcode, arg0, arg1, arg2, arg3, &out0, &out1);
return Result<FastResponse>{ .status = ret, .value = { out0, out1 } };
}
[[nodiscard]] cap_t raw_handle() const noexcept { return cap_.get(); }
};
// RAII Shared Memory Buffer
class SharedBuffer {
private:
Capability shm_cap_;
void* base_addr_;
size_t size_;
public:
SharedBuffer(Capability&& cap, void* addr, size_t sz) noexcept
: shm_cap_(static_cast<Capability&&>(cap)), base_addr_(addr), size_(sz) {}
~SharedBuffer() {
// Future: sys_unmap(base_addr_, size_)
}
SharedBuffer(const SharedBuffer&) = delete;
SharedBuffer& operator=(const SharedBuffer&) = delete;
SharedBuffer(SharedBuffer&& other) noexcept
: shm_cap_(static_cast<Capability&&>(other.shm_cap_)),
base_addr_(other.base_addr_),
size_(other.size_) {
other.base_addr_ = nullptr;
other.size_ = 0;
}
[[nodiscard]] void* data() const noexcept { return base_addr_; }
[[nodiscard]] size_t size() const noexcept { return size_; }
[[nodiscard]] cap_t handle() const noexcept { return shm_cap_.get(); }
};
} // namespace ipc
+5
View File
@@ -0,0 +1,5 @@
#include "../include/ipc.hpp"
namespace ipc {
// Shared library routines if needed
}
+8
View File
@@ -0,0 +1,8 @@
# Limine Bootloader Configuration (Legacy Alias)
TIMEOUT=3
:opencoreC Microkernel (x86_64)
PROTOCOL=limine
KERNEL_PATH=boot:///boot/opencore_kernel.elf
MODULE_PATH=boot:///boot/init_server.elf
MODULE_PATH=boot:///boot/uart_driver.elf
+9
View File
@@ -0,0 +1,9 @@
# Limine Bootloader Configuration for opencoreC Microkernel
timeout: 3
default_entry: 1
/opencoreC Microkernel (x86_64)
protocol: limine
kernel_path: boot():/boot/opencore_kernel.elf
module_path: boot():/boot/init_server.elf
module_path: boot():/boot/uart_driver.elf
+3
View File
@@ -0,0 +1,3 @@
[toolchain]
targets = ["x86_64-unknown-none"]
profile = "minimal"
+32
View File
@@ -0,0 +1,32 @@
#include "ipc.hpp"
#include "stdio.h"
#include "string.h"
extern "C" void _start() {
puts("[INIT-SERVER] Userspace Root Init Server Started (Ring 3)!");
// 1. Instantiate RAII IPC Endpoint for Kernel Control
ipc::Endpoint kernel_ctrl(CAP_SELF_TASK);
puts("[INIT-SERVER] Sending Fast-Path IPC Ping to Microkernel...");
auto ping_res = kernel_ctrl.call(IPC_OP_PING, 100);
if (ping_res.is_ok()) {
puts("[INIT-SERVER] Received IPC Ping Response from Microkernel!");
} else {
puts("[INIT-SERVER] IPC Call Failed!");
}
// 2. Register Server Endpoint
puts("[INIT-SERVER] Registering Root Server Capability...");
auto reg_res = kernel_ctrl.call(IPC_OP_REGISTER_SERVER, 0x1337BEEF);
if (reg_res.is_ok()) {
puts("[INIT-SERVER] Server Registered Successfully!");
}
puts("[INIT-SERVER] Root Init Server ready. Entering event loop.");
while (true) {
sys_yield();
}
}
+10
View File
@@ -0,0 +1,10 @@
#include "ipc.hpp"
#include "stdio.h"
extern "C" void _start() {
puts("[PROCMGR] Process & Server Manager Daemon Initialized.");
while (true) {
sys_yield();
}
}
+17
View File
@@ -0,0 +1,17 @@
#include "uart.h"
#include "stdio.h"
#include "abi/syscalls.h"
extern void _start(void) {
uart_init(UART_COM1_PORT, 115200);
uart_puts(UART_COM1_PORT, "[RING3-UART-DRIVER] 16550 UART COM1 initialized from userspace!\n");
while (1) {
if (uart_has_data(UART_COM1_PORT)) {
char c = uart_getc(UART_COM1_PORT);
// Echo back
uart_putc(UART_COM1_PORT, c);
}
sys_yield();
}
}