diff --git a/Cargo.lock b/Cargo.lock index 54839fc..7a088fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,9 @@ version = 4 [[package]] name = "rkos" version = "0.1.0" +dependencies = [ + "rkos-arch", +] [[package]] name = "rkos-arch" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6561731 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +PROJECT_NAME := rkos +TARGET := x86_64-unknown-none +BUILD_MODE := release +KERNEL_BIN := target/$(TARGET)/$(BUILD_MODE)/$(PROJECT_NAME) + +QEMU := qemu-system-x86_64 +QEMU_FLAGS := -machine q35 -kernel $(KERNEL_BIN) -serial stdio + +CARGO := cargo +CARGO_FLAGS := --target $(TARGET) +ifeq ($(BUILD_MODE), release) + CARGO_FLAGS += --release +endif + +.PHONY: all build run clean check help + +all: build + +build: + @echo "Building $(PROJECT_NAME) in $(BUILD_MODE) mode..." + $(CARGO) build $(CARGO_FLAGS) +clippy: + @echo "Clippy $(PROJECT_NAME) in $(BUILD_MODE) mode..." + $(CARGO) clippy $(CARGO_FLAGS) --bins --lib -- -D warnings +run: build + @echo "Starting QEMU..." + @$(QEMU) $(QEMU_FLAGS) +clean: + @echo "Cleaning project..." + @$(CARGO) clean + @rm -f build.log + +check: + @$(CARGO) check $(CARGO_FLAGS) + +.DEFAULT_GOAL := check diff --git a/README.org b/README.org index 516ae8e..4601a32 100644 --- a/README.org +++ b/README.org @@ -1,2 +1,14 @@ -* Rk +* rkos +[[Github Repo Starts][https://img.shields.io/github/stars/barrensea/rkos]] +[[https://crates.io/crates/rkos][https://img.shields.io/crates/d/rkos.svg]] +[[repo-size][https://img.shields.io/github/repo-size/barrensea/algori.svg]] +** High Performance Rust Operation System Core in Rust! + +** Start + +Fist install the qemu, then + +#+begin_src shell + make run +#+end_src diff --git a/crates/rkos-arch/src/x86/head_64.S b/crates/rkos-arch/src/x86/head_64.S index e7df2fa..aa0688f 100644 --- a/crates/rkos-arch/src/x86/head_64.S +++ b/crates/rkos-arch/src/x86/head_64.S @@ -1,6 +1,6 @@ /* Bootstrapping x86_64 kernel - see also: https://wiki.osdev.org/Entering_Long_Mode + see also: https://wiki.osdev.org/Setting_Up_Long_Mode */ /* prepare space for 4-level paging to entering long mode .bss: | PML4 | PML3 | PML2 | Kernel_Stack(.bss.stack)| @@ -54,7 +54,7 @@ gdt64_pointer: /* length of gdt64 minus 1 */ .word 15 /* pointer to gdt64 */ - .quad gdt64 + .long gdt64 /* multiboot header @@ -151,4 +151,4 @@ long_mode_start: /* if _main returns, loop forever */ .loop64: hlt - jmp .loop64 \ No newline at end of file + jmp .loop64 diff --git a/crates/rkos-arch/src/x86/mod.rs b/crates/rkos-arch/src/x86/mod.rs index 8b13789..b1fc0cf 100644 --- a/crates/rkos-arch/src/x86/mod.rs +++ b/crates/rkos-arch/src/x86/mod.rs @@ -1 +1 @@ - +pub mod serial; diff --git a/crates/rkos-arch/src/x86/serial.rs b/crates/rkos-arch/src/x86/serial.rs new file mode 100644 index 0000000..672c2c3 --- /dev/null +++ b/crates/rkos-arch/src/x86/serial.rs @@ -0,0 +1,65 @@ +// see also: https://wiki.osdev.org/Serial_Ports +use core::arch::asm; +use core::fmt; + +const COM1: u16 = 0x3F8; + +/// Write a byte to the serial port +unsafe fn outb(port: u16, val: u8) { + unsafe { + asm!("out dx, al", in("dx") port, in("al") val, options(nomem, nostack, preserves_flags)); + } +} + +/// Read a byte from the serial port +unsafe fn inb(port: u16) -> u8 { + let mut val: u8; + unsafe { + asm!("in al, dx", out("al") val, in("dx") port, options(nomem, nostack, preserves_flags)); + } + val +} + +pub struct SerialPort; + +impl SerialPort { + /// Initialize the standard COM1 serial port + pub fn init() { + unsafe { + outb(COM1 + 1, 0x00); // Disable all interrupts + outb(COM1 + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(COM1, 0x03); // Set divisor to 3 (lo byte) 38400 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 + } + } + + /// Check if transmit buffer is empty + fn is_transmit_empty() -> bool { + unsafe { inb(COM1 + 5) & 0x20 != 0 } + } + + /// Write a byte to the serial port + pub fn write_byte(b: u8) { + while !Self::is_transmit_empty() {} + unsafe { + outb(COM1, b); + } + } +} + +impl fmt::Write for SerialPort { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + SerialPort::write_byte(byte); + } + Ok(()) + } +} + +pub fn _print(args: fmt::Arguments) { + let mut serial = SerialPort; + let _ = fmt::Write::write_fmt(&mut serial, args); +} diff --git a/crates/rkos/Cargo.toml b/crates/rkos/Cargo.toml index 4a4d212..8a78be3 100644 --- a/crates/rkos/Cargo.toml +++ b/crates/rkos/Cargo.toml @@ -10,7 +10,7 @@ description.workspace = true rust-version.workspace = true [dependencies] - +rkos-arch = { path = "../rkos-arch" } # [lints] # workspace = true diff --git a/crates/rkos/src/console.rs b/crates/rkos/src/console.rs new file mode 100644 index 0000000..9c12d11 --- /dev/null +++ b/crates/rkos/src/console.rs @@ -0,0 +1,18 @@ +use core::fmt; + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::console::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($fmt:expr) => ($crate::print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*)); +} + +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + rkos_arch::x86::serial::_print(args); +} diff --git a/crates/rkos/src/main.rs b/crates/rkos/src/main.rs index ff7f6b4..a531d29 100644 --- a/crates/rkos/src/main.rs +++ b/crates/rkos/src/main.rs @@ -7,20 +7,15 @@ use core::panic::PanicInfo; #[cfg(target_arch = "x86_64")] global_asm!(include_str!("../../rkos-arch/src/x86/head_64.S")); +#[macro_use] +pub mod console; + #[unsafe(no_mangle)] pub extern "C" fn _main() { - // VGA_BASE: 0xb8000 - let vga_buffer = 0xb8000 as *mut u8; - - let text = b"[OK] Barrensea rkos has conquered 64-bit Long Mode!!!"; - let color_byte = 0x0a; + rkos_arch::x86::serial::SerialPort::init(); - for (i, &byte) in text.iter().enumerate() { - unsafe { - *vga_buffer.add(i * 2) = byte; - *vga_buffer.add(i * 2 + 1) = color_byte; - } - } + println!("[OK] Barrensea rkos has conquered 64-bit Long Mode!!!"); + println!("Hello from rkos serial output!"); unsafe extern "C" { fn stext();