From 0ebf48a43cb10f291f4e2343ee7677b300adeaa2 Mon Sep 17 00:00:00 2001 From: Donjuanplatinum Date: Sat, 28 Mar 2026 21:42:51 +0800 Subject: [PATCH 1/3] add head_64.S and main function --- .github/workflows/rust-test.yml | 4 + crates/rkos-arch/src/x86/head_64.S | 154 +++++++++++++++++++++++++++++ crates/rkos-arch/src/x86/link.ld | 28 ++++-- crates/rkos/src/main.rs | 57 ++++++----- 4 files changed, 207 insertions(+), 36 deletions(-) create mode 100644 crates/rkos-arch/src/x86/head_64.S diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 3da7c1e..05f6aee 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -11,6 +11,8 @@ on: - "**.ps1" - "**.yml" - "**.toml" + - "**.S" + - "**.ld" - "!**.md" pull_request: types: [opened, synchronize] @@ -21,6 +23,8 @@ on: - "**.ps1" - "**.yml" - "**.toml" + - "**.S" + - "**.ld" - "!**.md" env: diff --git a/crates/rkos-arch/src/x86/head_64.S b/crates/rkos-arch/src/x86/head_64.S new file mode 100644 index 0000000..e7df2fa --- /dev/null +++ b/crates/rkos-arch/src/x86/head_64.S @@ -0,0 +1,154 @@ +/* + Bootstrapping x86_64 kernel + see also: https://wiki.osdev.org/Entering_Long_Mode +*/ + /* prepare space for 4-level paging to entering long mode + .bss: | PML4 | PML3 | PML2 | Kernel_Stack(.bss.stack)| + | 4kb | 4kb | 4kb | 16kb | + */ + .section .bss + .align 4096 +p4_table: + .skip 4096 +p3_table: + .skip 4096 +p2_table: + .skip 4096 + + /* Kernel Stack */ + .section .bss.stack + .align 16 +stack_bottom: + .skip 16384 +stack_top: + + /* + 64-bit Global Descriptor Table (GDT) + see also: https://wiki.osdev.org/Global_Descriptor_Table + */ + + /* because of .rodata is read only now,when adding more features,we should move it to .data */ + .section .rodata + /* every items in gdt64 is 8 bytes */ + .align 8 +gdt64: + /* the first item is null */ + .quad 0x0000000000000000 + + /* the second item is 64-bit code segment + Base 63:56 0x00000000 + G 55 0 + D/B 54 0 + L 53 1 (64-bit code segment) + AVL 52 0 + Limit 51:48 0x0000 + P 47 1 + DPL 46:45 0x00 + S 44 1 + Type 43:40 0x10 + Base 39:16 0x000000 + Limit 15:0 0x0000 + */ + .quad 0x0020980000000000 +gdt64_pointer: + /* length of gdt64 minus 1 */ + .word 15 + /* pointer to gdt64 */ + .quad gdt64 + + /* + multiboot header + see also: https://wiki.osdev.org/Multiboot_Specification + */ + .section .text.entry + .align 4 + + .global multiboot_header +multiboot_header: + /* 0x1badb002: magic number for multiboot protocol*/ + .long 0x1badb002 + /* 0x00010000: flags */ + .long 0x00010000 + /* checksum */ + .long -(0x1badb002 + 0x00010000) + + /* pointer to multiboot_header */ + .long multiboot_header + .long stext + .long edata + .long ebss + .long _start + + /* + start of 32-bit code + */ + .global _start +_start: + .code32 + /* set stack pointer */ + mov esp, offset stack_top + + /* + set up temporary page table + map first 2MB of physical memory to virtual memory + */ + mov eax, offset p3_table + or eax, 0b11 /* 0b11 means present and writable */ + mov dword ptr [p4_table], eax + + /* p3_table[0] -> p2_table */ + mov eax, offset p2_table + or eax, 0b11 + mov dword ptr [p3_table], eax + + /* map first 2MB of physical memory to virtual memory as huge page */ + mov eax, 0x83 /* 0x80 (Huge) + 0x02 (Writable) + 0x01 (Present) */ + mov dword ptr [p2_table], eax + + /* into long mode */ + /* step 1: set CR3 to p4_table */ + mov eax, offset p4_table + mov cr3, eax + + /* step 2: enable PAE in CR4 */ + mov eax, cr4 + or eax, 1 << 5 + mov cr4, eax + + /* step 3: enable LME in EFER */ + mov ecx, 0xC0000080 + rdmsr + or eax, 1 << 8 + wrmsr + + /* step 4: enable paging in CR0 */ + mov eax, cr0 + or eax, 1 << 31 + mov cr0, eax + + /* step 5: load gdt64 */ + lgdt [gdt64_pointer] + + /* jump to 64-bit code */ + push 8 /* push 64-bit code segment */ + mov eax, offset long_mode_start + push eax /* push 64-bit code entry point */ + retf /* retf to long mode */ + + .code64 +long_mode_start: + /* first thing: set all data segment registers to 0 */ + mov ax, 0 + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + /* call _main */ + call _main + + /* if _main returns, loop forever */ +.loop64: + hlt + jmp .loop64 \ No newline at end of file diff --git a/crates/rkos-arch/src/x86/link.ld b/crates/rkos-arch/src/x86/link.ld index ade506b..f59116d 100644 --- a/crates/rkos-arch/src/x86/link.ld +++ b/crates/rkos-arch/src/x86/link.ld @@ -1,3 +1,7 @@ +/* + linker script for x86_64 kernel + see also: https://wiki.osdev.org/Linker_Scripts +*/ OUTPUT_ARCH(i386:x86-64) ENTRY(_start) @@ -8,16 +12,20 @@ KERNEL_BASE_ADDRESS = 0x100000; SECTIONS { . = KERNEL_BASE_ADDRESS; - /* kernel code */ + /* + .text: kernel code + start at 0x100000 + */ .text : { stext = .; - *(.text.entry) + *(.text.entry) *(.text .text.*) . = ALIGN(4096); etext = .; } - - /* kernel rodata */ + /* + .rodata: kernel rodata + */ .rodata : { srodata = .; *(.rodata .rodata.*) @@ -25,7 +33,9 @@ SECTIONS { erodata = .; } - /* kernel data */ + /* + .data: kernel data + */ .data : { sdata = .; *(.data .data.*) @@ -33,7 +43,9 @@ SECTIONS { edata = .; } - /* kernel bss */ + /* + .bss: kernel bss + */ .bss : { sbss = .; *(.bss.stack) /* kernel stack */ @@ -43,7 +55,9 @@ SECTIONS { ebss = .; } - /* kernel end */ + /* + kernel end + */ . = ALIGN(4096); ekernel = .; } diff --git a/crates/rkos/src/main.rs b/crates/rkos/src/main.rs index 6e52051..ff7f6b4 100644 --- a/crates/rkos/src/main.rs +++ b/crates/rkos/src/main.rs @@ -4,35 +4,34 @@ use core::arch::global_asm; use core::panic::PanicInfo; -global_asm!( - r#" - .section .text.entry - .align 4 - - .global multiboot_header - multiboot_header: - - .long 0x1badb002 - .long 0x00010000 - .long -(0x1badb002 + 0x00010000) - - .long multiboot_header - .long stext - .long edata - .long ebss - .long _start - - .global _start - _start: - .code32 - mov eax, 0x4f4f4f4f - mov dword ptr [0xb8000], eax - - .loop: - hlt - jmp .loop - "# -); +#[cfg(target_arch = "x86_64")] +global_asm!(include_str!("../../rkos-arch/src/x86/head_64.S")); + +#[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; + + for (i, &byte) in text.iter().enumerate() { + unsafe { + *vga_buffer.add(i * 2) = byte; + *vga_buffer.add(i * 2 + 1) = color_byte; + } + } + + unsafe extern "C" { + fn stext(); + fn edata(); + fn ebss(); + } + let _text_size = edata as *const () as usize - stext as *const () as usize; + let _bss_size = ebss as *const () as usize - edata as *const () as usize; + + //loop {} +} #[panic_handler] fn panic(_info: &PanicInfo) -> ! { From 582b2291497dd9570ed8bcdb0fbbbd16f6f8f168 Mon Sep 17 00:00:00 2001 From: Donjuanplatinum Date: Sat, 28 Mar 2026 22:08:55 +0800 Subject: [PATCH 2/3] changing readme.org --- README.org | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index 516ae8e..b7f42ec 100644 --- a/README.org +++ b/README.org @@ -1,2 +1,7 @@ -* 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! From 40baa253faf0ab340400c10cd78bd7d56fcdf8a4 Mon Sep 17 00:00:00 2001 From: Donjuanplatinum Date: Sun, 29 Mar 2026 00:35:35 +0800 Subject: [PATCH 3/3] adding serial support --- Cargo.lock | 3 ++ Makefile | 36 +++++++++++++++++ README.org | 7 ++++ crates/rkos-arch/src/x86/head_64.S | 6 +-- crates/rkos-arch/src/x86/mod.rs | 2 +- crates/rkos-arch/src/x86/serial.rs | 65 ++++++++++++++++++++++++++++++ crates/rkos/Cargo.toml | 2 +- crates/rkos/src/console.rs | 18 +++++++++ crates/rkos/src/main.rs | 17 +++----- 9 files changed, 140 insertions(+), 16 deletions(-) create mode 100644 Makefile create mode 100644 crates/rkos-arch/src/x86/serial.rs create mode 100644 crates/rkos/src/console.rs 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 b7f42ec..4601a32 100644 --- a/README.org +++ b/README.org @@ -5,3 +5,10 @@ ** 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();