summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2026-07-17 19:16:37 +0800
committerlittleblack111 <littleblack11111@gmail.com>2026-07-17 19:16:37 +0800
commitb4d9a57f193c64bca188a76e4f711cc168da9737 (patch)
tree81258da175f58bac49bb8992240c50bf8b154e11
init
with limine as bootloader, changing soon
-rw-r--r--.cargo/config.toml16
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock23
-rw-r--r--Cargo.toml32
-rw-r--r--OVMF_VARS.4m.fdbin0 -> 540672 bytes
-rw-r--r--README.md24
m---------limine0
-rw-r--r--limine.conf6
-rw-r--r--linker.ld47
-rw-r--r--qemu.log5
-rw-r--r--qemu_output.txt4
-rw-r--r--readelf.out23
-rw-r--r--report.typ13
-rw-r--r--src/io.rs1
-rw-r--r--src/io/render.rs1
-rw-r--r--src/io/render/fb.rs2
-rw-r--r--src/io/render/fb/graphic.rs0
-rw-r--r--src/io/render/fb/text.rs1
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs76
-rw-r--r--target.json19
21 files changed, 297 insertions, 0 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml
new file mode 100644
index 0000000..12f8cca
--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,16 @@
+[build]
+target = "target.json"
+
+[unstable]
+build-std = ["core", "compiler_builtins", "alloc"]
+build-std-features = ["compiler-builtins-mem"]
+
+[target.target]
+# Limage compatibility with `cargo run`
+runner = "limage runner"
+# Required for Cargo to pass the correct flags to the linker before running `limage runner`
+rustflags = ["-C", "relocation-model=static", "-C", "link-arg=linker.ld", "-C", "code-model=kernel"]
+
+# [target.target]
+# rustflags = ["-C", "link-arg=-Tlinker.ld", "-C", "link-arg=-zmax-page-size=0x1000"]
+# runner = "./run.sh "
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..c3ebf11
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,23 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "font8x8"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "875488b8711a968268c7cf5d139578713097ca4635a76044e8fe8eedf831d07e"
+
+[[package]]
+name = "limine"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29363c0f37e66e18575fadf7141c56ee7ea04ae5fecbeb25eff303f77af203a9"
+
+[[package]]
+name = "rust-os"
+version = "0.1.0"
+dependencies = [
+ "font8x8",
+ "limine",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..4f49da8
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,32 @@
+[package]
+name = "rust-os"
+version = "0.1.0"
+edition = "2024"
+
+[[bin]]
+name = "rust-os"
+test = false
+bench = false
+
+[lib]
+test = false
+
+[profile.dev]
+panic = "abort"
+
+[profile.release]
+panic = "abort"
+
+[dependencies]
+font8x8 = { version = "0.3.1", default-features = false, features = ["unicode"] }
+limine = "0.6.5"
+
+[package.metadata.limage]
+run-command = [
+ "qemu-system-x86_64",
+ "-drive", "if=pflash,format=raw,readonly=on,file=/usr/share/edk2-ovmf/x64/OVMF_CODE.4m.fd",
+ "-drive", "if=pflash,format=raw,file=OVMF_VARS.4m.fd",
+ "-no-reboot",
+ "-d", "int",
+ "-cdrom", "{}"
+]
diff --git a/OVMF_VARS.4m.fd b/OVMF_VARS.4m.fd
new file mode 100644
index 0000000..c363987
--- /dev/null
+++ b/OVMF_VARS.4m.fd
Binary files differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bb7be93
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# Rust OS
+
+A bare-metal Rust OS kernel utilizing the Limine bootloader protocol v8.x.
+
+This repository demonstrates how to set up a minimal `x86_64` rust kernel that uses `limine` `0.6.5` to retrieve a framebuffer, draw a built-in bitmap font (`font8x8`) to print "Hello World!" on the screen, and output "Hello World!" to the serial port as a fallback.
+
+## Building and Running
+
+1. **Build and Run**
+ ```bash
+ cargo run
+ ```
+ The `runner.sh` script will automatically:
+ - Build the Rust kernel via Cargo
+ - Clone the Limine binary release
+ - Build a bootable ISO with `xorriso` and deploy `limine`
+ - Boot the ISO in QEMU
+
+## Design Notes
+
+- The Limine crate version `0.6.5` relies on raw protocol structures such as `BaseRevision`, `RequestsStartMarker`, `RequestsEndMarker`, and the standard `FramebufferRequest`.
+- Built-in terminal requests were dropped from Limine 5.x+ and therefore they do not exist in the `limine` `0.6.5` crate.
+- We utilize `font8x8` to iterate over character glyphs and plot the pixels directly to the `Framebuffer` slice obtained via Limine.
+- Serial port output is written to `0x3F8` using inline `outb` assembly.
diff --git a/limine b/limine
new file mode 160000
+Subproject aad3edd370955449717a334f0289dee10e2c5f0
diff --git a/limine.conf b/limine.conf
new file mode 100644
index 0000000..be16e24
--- /dev/null
+++ b/limine.conf
@@ -0,0 +1,6 @@
+timeout: 0
+serial: yes
+
+/Rust OS
+ protocol: limine
+ kernel_path: boot():/boot/kernel/kernel
diff --git a/linker.ld b/linker.ld
new file mode 100644
index 0000000..f71177b
--- /dev/null
+++ b/linker.ld
@@ -0,0 +1,47 @@
+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 */
+ dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Dynamic */
+}
+
+SECTIONS
+{
+ . = 0xffffffff80000000;
+
+ .text : {
+ *(.text .text.*)
+ } :text
+
+ . += CONSTANT(MAXPAGESIZE);
+
+ .rodata : {
+ *(.rodata .rodata.*)
+ } :rodata
+
+ . += CONSTANT(MAXPAGESIZE);
+
+ .data : {
+ *(.data .data.*)
+
+ KEEP(*(.requests_start_marker))
+ KEEP(*(.requests))
+ KEEP(*(.requests_end_marker))
+ } :data
+
+ .bss : {
+ *(COMMON)
+ *(.bss .bss.*)
+ } :data
+
+ /DISCARD/ : {
+ *(.eh_frame)
+ *(.note .note.*)
+ }
+}
diff --git a/qemu.log b/qemu.log
new file mode 100644
index 0000000..02feb78
--- /dev/null
+++ b/qemu.log
@@ -0,0 +1,5 @@
+limine: Loading executable `boot():/boot/rust-os`...
+Entered _start!
+BASE_REVISION not supported!
+Hello World!
+qemu-system-x86_64: terminating on signal 15 from pid 773461 (timeout)
diff --git a/qemu_output.txt b/qemu_output.txt
new file mode 100644
index 0000000..3441336
--- /dev/null
+++ b/qemu_output.txt
@@ -0,0 +1,4 @@
+limine: Loading executable `boot():/boot/rust-os`...
+Entered _start!
+BASE_REVISION not supported!
+qemu-system-x86_64: terminating on signal 15 from pid 799698 (timeout)
diff --git a/readelf.out b/readelf.out
new file mode 100644
index 0000000..f47369f
--- /dev/null
+++ b/readelf.out
@@ -0,0 +1,23 @@
+
+Elf file type is EXEC (Executable file)
+Entry point 0xffffffff80000400
+There are 4 program headers, starting at offset 64
+
+Program Headers:
+ Type Offset VirtAddr PhysAddr
+ FileSiz MemSiz Flags Align
+ LOAD 0x0000000000001000 0xffffffff80000000 0xffffffff80000000
+ 0x000000000000d8dc 0x000000000000d8dc R E 0x1000
+ LOAD 0x000000000000e8e0 0xffffffff8000e8e0 0xffffffff8000e8e0
+ 0x0000000000003dbd 0x0000000000003dbd R 0x1000
+ LOAD 0x00000000000126a0 0xffffffff800136a0 0xffffffff800136a0
+ 0x0000000000000078 0x0000000000000078 RW 0x1000
+ DYNAMIC 0x0000000000000000 0x0000000000000000 0x0000000000000000
+ 0x0000000000000000 0x0000000000000000 RW 0x0
+
+ Section to Segment mapping:
+ Segment Sections...
+ 00 .text
+ 01 .rodata
+ 02 .data
+ 03
diff --git a/report.typ b/report.typ
new file mode 100644
index 0000000..eb02d77
--- /dev/null
+++ b/report.typ
@@ -0,0 +1,13 @@
+i got inspiration from this #link("https://os.phil-opp.com")[blog]
+
+booatloader selection:
+i could just use qemu skipping to kernel but i wanted to explore about bootloaders too since im making a os, but i dont wanna spend all my time just doing repetitive stuff and dealing with legacy stuff
+two realistic options only:
+#link("https://crates.io/crates/bootloader_api")[bootloader_api] which is what the aforementioned blog uses
+rejected because:
+- don't wanna deal with manually setting up SMP
+- hands me a poor memory base my mmu off of
+- more niche(thereforee less mature/popular and therefore getting less support) and only gain traction due to the aforementioned blog post
+ - due to that it's tightly coupled with it
+#link("https://crates.io/crates/limine")[limine]
+- cons: no documentation
diff --git a/src/io.rs b/src/io.rs
new file mode 100644
index 0000000..cf25e6c
--- /dev/null
+++ b/src/io.rs
@@ -0,0 +1 @@
+pub mod render;
diff --git a/src/io/render.rs b/src/io/render.rs
new file mode 100644
index 0000000..402daf7
--- /dev/null
+++ b/src/io/render.rs
@@ -0,0 +1 @@
+pub mod fb;
diff --git a/src/io/render/fb.rs b/src/io/render/fb.rs
new file mode 100644
index 0000000..2924838
--- /dev/null
+++ b/src/io/render/fb.rs
@@ -0,0 +1,2 @@
+pub mod graphic;
+pub mod text;
diff --git a/src/io/render/fb/graphic.rs b/src/io/render/fb/graphic.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/io/render/fb/graphic.rs
diff --git a/src/io/render/fb/text.rs b/src/io/render/fb/text.rs
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/io/render/fb/text.rs
@@ -0,0 +1 @@
+
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..f0111d3
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,3 @@
+#![no_std]
+
+pub mod io;
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..bf338df
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,76 @@
+#![no_std]
+#![no_main]
+#![feature(used_with_arg)]
+
+use core::panic::PanicInfo;
+use font8x8::UnicodeFonts;
+use limine::{BaseRevision, request::FramebufferRequest};
+
+#[used(linker)]
+#[unsafe(link_section = ".requests")]
+static BASE_REVISION: BaseRevision = BaseRevision::new();
+
+#[used(linker)]
+#[unsafe(link_section = ".requests")]
+static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
+
+#[unsafe(no_mangle)]
+pub extern "C" fn _start() -> ! {
+ if !BASE_REVISION.is_supported() {
+ panic!("Limine Base Revision not supported");
+ }
+
+ if let Some(response) = FRAMEBUFFER_REQUEST.response() {
+ if let Some(fb) = response
+ .framebuffers()
+ .first()
+ {
+ let pitch = fb.pitch as usize;
+ let bpp = fb.bpp as usize;
+
+ if bpp == 32 {
+ let slice = unsafe { fb.as_slice_mut() };
+ let msg = "Hello World!";
+ let mut cursor_x = 10;
+ let cursor_y = 10;
+
+ for c in msg.chars() {
+ if let Some(glyph) = font8x8::BASIC_FONTS.get(c) {
+ for (y, row) in glyph
+ .iter()
+ .enumerate()
+ {
+ for x in 0..8 {
+ if (*row & (1 << x)) != 0 {
+ let pixel_offset = (cursor_y + y) * pitch + (cursor_x + x) * 4;
+ if pixel_offset + 3 < slice.len() {
+ slice[pixel_offset] = 0xFF; // B
+ slice[pixel_offset + 1] = 0xFF; // G
+ slice[pixel_offset + 2] = 0xFF; // R
+ }
+ }
+ }
+ }
+ }
+ cursor_x += 8;
+ }
+ }
+ }
+ }
+
+ hcf();
+}
+
+fn hcf() -> ! {
+ unsafe {
+ core::arch::asm!("cli");
+ loop {
+ core::arch::asm!("hlt");
+ }
+ }
+}
+
+#[panic_handler]
+fn panic(_info: &PanicInfo) -> ! {
+ hcf()
+}
diff --git a/target.json b/target.json
new file mode 100644
index 0000000..7914b12
--- /dev/null
+++ b/target.json
@@ -0,0 +1,19 @@
+{
+ "llvm-target": "x86_64-unknown-none",
+ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
+ "arch": "x86_64",
+ "target-endian": "little",
+ "target-pointer-width": 64,
+ "target-c-int-width": 32,
+ "os": "none",
+ "executables": true,
+ "linker-flavor": "ld.lld",
+ "linker": "rust-lld",
+ "panic-strategy": "abort",
+ "disable-redzone": true,
+ "features": "-mmx,-sse,+soft-float",
+ "rustc-abi": "x86-softfloat",
+ "relocation-model": "static",
+ "position-independent-executables": false,
+ "code-model": "kernel"
+}