Skip to content

Commit e6fb79f

Browse files
committed
initial stuff
1 parent 068e972 commit e6fb79f

15 files changed

+336
-0
lines changed

.cargo/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[build]
2+
target = "x86_64-unknown-none"
3+
4+
# [unstable]
5+
# build-std = ["core", "compiler_builtins"]
6+
# build-std-features = ["compiler-builtins-mem"]

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "cargo"
4+
directory: "/"
5+
schedule:
6+
interval: "daily"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target
2+
/build

Cargo.lock

Lines changed: 56 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "monoOS"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "A hobbyist monolithic operating system, targeting x86-64."
6+
readme = "README.md"
7+
license = "MIT"
8+
authors = ["binds <[email protected]>"]
9+
10+
[dependencies]
11+
limine = "0.1.11"
12+
spin = { version = "0.9.8", default-features = false, features = ["spin_mutex", "once"] }
13+
x86 = "0.52.0"
14+
15+
[[bin]]
16+
name = "monoos"
17+
path = "src/main.rs"

Makefile

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Configuration options
2+
FEATURES ?=
3+
PROFILE ?= release
4+
5+
# Command arguments
6+
override CARGO_ARGS = --bin monoos --no-default-features
7+
override QEMU_ARGS = -no-reboot -no-shutdown -M smm=off -machine q35 -drive file=$(ISO),format=raw -bios $(BUILD_ROOT)/OVMF.fd
8+
9+
# Checks
10+
ifneq ($(PROFILE),$(filter $(PROFILE),debug release))
11+
$(error Error: unsupported cargo profile "$(PROFILE)". supported options are "debug" and "release")
12+
endif
13+
14+
ifneq ($(FEATURES),)
15+
override CARGO_ARGS += --features $(FEATURES)
16+
endif
17+
18+
ifeq ($(PROFILE), release)
19+
override CARGO_ARGS += --release
20+
endif
21+
22+
ifeq ($(PROFILE),debug)
23+
override QEMU_ARGS += -s -S
24+
endif
25+
26+
ifneq ($(findstring la57,$(FEATURES)),)
27+
override QEMU_ARGS += -cpu qemu64,+la57
28+
endif
29+
30+
# Environment variables
31+
export MHOS_VERSION = v0.1.0
32+
33+
# Overrides
34+
override BUILD_DIR := build
35+
override BUILD_ROOT := $(BUILD_DIR)/root
36+
override ISO := $(BUILD_ROOT)/monoos.iso
37+
override LIMINE_DIR := $(BUILD_DIR)/limine
38+
override ESP := $(BUILD_ROOT)/EFI/BOOT
39+
override KERNEL_BIN := $(BUILD_ROOT)/monoos.elf
40+
41+
# Targets
42+
.PHONY: all iso run miri clean
43+
all: iso
44+
45+
gen_build_dirs:
46+
@# recursively create from the deepest directory
47+
@mkdir -p $(ESP)
48+
49+
limine: gen_build_dirs
50+
@git clone --depth 1 --branch v5.x-branch-binary https://github.com/limine-bootloader/limine.git $(LIMINE_DIR)
51+
@$(MAKE) -C $(LIMINE_DIR)
52+
53+
ovmf:
54+
@wget https://efi.akeo.ie/OVMF/OVMF-X64.zip -P $(BUILD_ROOT)
55+
@unzip $(BUILD_ROOT)/OVMF-X64.zip -d $(BUILD_ROOT) -x *.txt
56+
57+
kernel_build:
58+
@cargo build $(CARGO_ARGS)
59+
60+
$(ISO): limine ovmf kernel_build
61+
@cp target/x86_64-unknown-none/$(PROFILE)/monoos $(KERNEL_BIN)
62+
@cp limine.cfg $(LIMINE_DIR)/limine-uefi-cd.bin $(BUILD_ROOT)
63+
@cp $(LIMINE_DIR)/BOOTX64.EFI $(ESP)
64+
@xorriso -as mkisofs --efi-boot limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label $(BUILD_ROOT) -o $(ISO)
65+
66+
# Convenience target for $(ISO)
67+
iso: $(ISO)
68+
69+
run: iso
70+
@qemu-system-x86_64 $(QEMU_ARGS)
71+
72+
miri:
73+
@MIRI_NO_STD=1 cargo miri run --target x86_64-unknown-none
74+
75+
clean:
76+
@cargo clean
77+
@rm -rf build

build.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
println!("cargo:rerun-if-changed=build.rs");
3+
println!("cargo:rerun-if-changed=linker.ld");
4+
println!("cargo:rustc-link-arg=-Tlinker.ld");
5+
}

limine.cfg

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
TIMEOUT=0
2+
VERBOSE=yes
3+
4+
: monoOS
5+
PROTOCOL=limine
6+
KASLR=yes
7+
KERNEL_PATH=boot:///monoos.elf

linker.ld

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* output an x86-64 ELF file */
2+
OUTPUT_FORMAT(elf64-x86-64)
3+
4+
/* make kmain symbol the entry point */
5+
ENTRY(kmain)
6+
7+
/* define program headers to get desired MMU permissions */
8+
PHDRS
9+
{
10+
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
11+
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
12+
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
13+
dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
14+
}
15+
16+
SECTIONS
17+
{
18+
/* We wanna be placed in the topmost 2GiB of the address space, for optimisations */
19+
/* and because that is what the Limine spec mandates. */
20+
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
21+
/* that is the beginning of the region. */
22+
. = 0xffffffff80000000;
23+
24+
.text : {
25+
*(.text .text.*)
26+
} :text
27+
28+
/* Move to the next memory page for .rodata */
29+
. += CONSTANT(MAXPAGESIZE);
30+
31+
/* The built-in `x86_64-unknown-none` target generates relocatable executables */
32+
/* by default, so we need to include the relocation information (.dynstr, .dynsym, */
33+
/* and .rela) for the bootloader too properly load the kernel at runtime. */
34+
.dynsym : {
35+
*(.dynsym)
36+
} :rodata
37+
38+
.dynstr : {
39+
*(.dynstr)
40+
} :rodata
41+
42+
.rela : {
43+
*(.rela*)
44+
} :rodata
45+
46+
.rodata : {
47+
*(.rodata .rodata.*)
48+
} :rodata
49+
50+
/* Move to the next memory page for .data */
51+
. += CONSTANT(MAXPAGESIZE);
52+
53+
/* The dynamic table is used to find the relocation info (declared above), so it */
54+
/* must be included both in the :data and :dynamic segments. */
55+
.dynamic : {
56+
*(.dynamic)
57+
} :data :dynamic
58+
59+
.got : {
60+
*(.got)
61+
} :data
62+
63+
.data : {
64+
*(.data.rel.ro .data.rel.ro.*)
65+
*(.data .data.*)
66+
} :data
67+
68+
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
69+
/* unnecessary zeros will be written to the binary. */
70+
/* If you need, for example, .init_array and .fini_array, those should be placed */
71+
/* above this. */
72+
.bss : {
73+
*(COMMON)
74+
*(.dynbss)
75+
*(.bss .bss.*)
76+
} :data
77+
78+
/* Discard .note.* and .eh_frame since they may cause issues on some hosts. */
79+
/DISCARD/ : {
80+
*(.eh_frame)
81+
*(.note .note.*)
82+
}
83+
}

rust-toolchain.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[toolchain]
2+
channel = "nightly"

src/cpu.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! Necessary CPU state setup for x86-64
2+
3+
pub mod gdt;
4+
pub mod idt;

src/cpu/gdt.rs

Whitespace-only changes.

src/cpu/idt.rs

Whitespace-only changes.

src/graphics.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use limine::Framebuffer;
2+
use spin::{Mutex, Once};
3+
4+
#[derive(Debug)]
5+
struct FramebufferInfo {
6+
byte_len: usize,
7+
pitch: u64,
8+
}
9+
10+
impl FramebufferInfo {
11+
fn new(byte_len: usize, pitch: u64) -> Self {
12+
Self { byte_len, pitch }
13+
}
14+
}
15+
16+
#[derive(Debug)]
17+
struct Writer<'a> {
18+
fb_slice: &'a mut [u8],
19+
fb_info: FramebufferInfo,
20+
}
21+
22+
impl<'a> Writer<'a> {
23+
fn new(fb_slice: &'a mut [u8], fb_info: FramebufferInfo) -> Self {
24+
Self { fb_slice, fb_info }
25+
}
26+
}
27+
28+
static WRITER: Once<Mutex<Writer>> = Once::new();
29+
30+
pub fn init(fb: &Framebuffer) {
31+
let fb_info = FramebufferInfo::new(fb.size(), fb.pitch);
32+
33+
// SAFETY: `as_ptr` will never return `None`
34+
let fb_addr = unsafe { fb.address.as_ptr().unwrap_unchecked() };
35+
// SAFETY: `fb_addr` is non-null and aligned
36+
let fb_slice = unsafe { core::slice::from_raw_parts_mut(fb_addr, fb_info.byte_len) };
37+
38+
let writer = Writer::new(fb_slice, fb_info);
39+
40+
WRITER.call_once(|| Mutex::new(writer));
41+
}

src/main.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#![no_std]
2+
#![no_main]
3+
#![allow(dead_code)]
4+
5+
mod cpu;
6+
mod graphics;
7+
8+
use core::panic::PanicInfo;
9+
use limine::FramebufferRequest;
10+
11+
#[cfg(not(target_pointer_width = "64"))]
12+
compile_error!("monoOS is only designed for 64-bit architectures");
13+
14+
#[cfg(not(target_arch = "x86_64"))]
15+
compile_error!("monoOS only supports the x86_64 architecture");
16+
17+
static FRAMEBUFFER: FramebufferRequest = FramebufferRequest::new(0);
18+
19+
fn kmain() -> ! {
20+
// Obtain the framebuffer and setup graphics.
21+
let framebuffer = &*FRAMEBUFFER.get_response().get().unwrap().framebuffers()[0];
22+
graphics::init(framebuffer);
23+
24+
loop {}
25+
}
26+
27+
#[panic_handler]
28+
fn panic(_: &PanicInfo) -> ! {
29+
loop {}
30+
}

0 commit comments

Comments
 (0)