tangled
alpha
login
or
join now
cass.cityboundforest.com
/
dasos
0
fork
atom
A repository for a long-term OS project titled DasOS (named after the Greek for "forest")
0
fork
atom
overview
issues
pulls
pipelines
Redoing the whole thing
cass.cityboundforest.com
4 months ago
b87f7680
55b501a7
-283
11 changed files
expand all
collapse all
unified
split
.cargo
config.toml
Cargo.toml
build.rs
kernel
Cargo.toml
src
framebuffer.rs
interrupts.rs
main.rs
rust-toolchain.toml
src
bin
qemu-bios.rs
qemu-uefi.rs
main.rs
-2
.cargo/config.toml
···
1
1
-
[unstable]
2
2
-
bindeps = true
-15
Cargo.toml
···
1
1
-
[package]
2
2
-
name = "dasos"
3
3
-
version = "0.1.0"
4
4
-
edition = "2024"
5
5
-
default-run = "dasos"
6
6
-
7
7
-
[workspace]
8
8
-
members = ["kernel"]
9
9
-
10
10
-
[dependencies]
11
11
-
ovmf-prebuilt = "0.2.4"
12
12
-
13
13
-
[build-dependencies]
14
14
-
kernel = { path = "kernel", artifact = "bin", target = "x86_64-unknown-none" }
15
15
-
bootloader = "0.11.3"
-20
build.rs
···
1
1
-
use bootloader::DiskImageBuilder;
2
2
-
use std::{env, path::PathBuf};
3
3
-
4
4
-
fn main() {
5
5
-
// set by cargo for the kernel artifact dependency
6
6
-
let kernel_path = env::var("CARGO_BIN_FILE_KERNEL").unwrap();
7
7
-
let disk_builder = DiskImageBuilder::new(PathBuf::from(kernel_path));
8
8
-
9
9
-
// specify output paths
10
10
-
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
11
11
-
let uefi_path = out_dir.join("dasos-uefi.img");
12
12
-
let bios_path = out_dir.join("dasos-bios.img");
13
13
-
14
14
-
// create the disk images
15
15
-
disk_builder.create_uefi_image(&uefi_path).unwrap();
16
16
-
disk_builder.create_bios_image(&bios_path).unwrap();
17
17
-
18
18
-
println!("cargo:rustc-env=UEFI_IMAGE={}", uefi_path.display());
19
19
-
println!("cargo:rustc-env=BIOS_IMAGE={}", bios_path.display());
20
20
-
}
-18
kernel/Cargo.toml
···
1
1
-
[package]
2
2
-
name = "kernel"
3
3
-
version = "0.1.0"
4
4
-
edition = "2024"
5
5
-
6
6
-
[dependencies]
7
7
-
bootloader_api = "0.11.2"
8
8
-
embedded-graphics = "0.8.1"
9
9
-
log = { version = "0.4.17", default-features = false }
10
10
-
bootloader-x86_64-common = "0.11.3"
11
11
-
conquer-once = { version = "0.4.0", default-features = false }
12
12
-
x86_64 = "0.15.2"
13
13
-
lazy_static = { version = "1.5.0", features = ["spin_no_std"] }
14
14
-
15
15
-
[[bin]]
16
16
-
name = "kernel"
17
17
-
test = true
18
18
-
bench = false
-107
kernel/src/framebuffer.rs
···
1
1
-
use bootloader_api::info::{FrameBuffer, PixelFormat};
2
2
-
use embedded_graphics::{Pixel, draw_target::DrawTarget, geometry::{OriginDimensions, Size}, pixelcolor::{Rgb888, RgbColor}};
3
3
-
4
4
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5
5
-
pub struct Position {
6
6
-
pub x: usize,
7
7
-
pub y: usize
8
8
-
}
9
9
-
10
10
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11
11
-
pub struct Color {
12
12
-
pub red: u8,
13
13
-
pub green: u8,
14
14
-
pub blue: u8
15
15
-
}
16
16
-
17
17
-
pub fn set_pixel_in(framebuffer: &mut FrameBuffer, position: Position, color: Color) {
18
18
-
let info = framebuffer.info();
19
19
-
20
20
-
// calculate offset to first byte of pixel
21
21
-
let byte_offset = {
22
22
-
// use stride to calculate pixel offset of target line
23
23
-
let line_offset = position.y * info.stride;
24
24
-
// add x position to get the absolute pixel offset in buffer
25
25
-
let pixel_offset = line_offset + position.x;
26
26
-
// convert to byte offest
27
27
-
pixel_offset * info.bytes_per_pixel
28
28
-
};
29
29
-
30
30
-
// set pixel based on color format
31
31
-
let pixel_buffer = &mut framebuffer.buffer_mut()[byte_offset..];
32
32
-
33
33
-
match info.pixel_format {
34
34
-
PixelFormat::Rgb => {
35
35
-
pixel_buffer[0] = color.red;
36
36
-
pixel_buffer[1] = color.green;
37
37
-
pixel_buffer[2] = color.blue;
38
38
-
},
39
39
-
PixelFormat::Bgr => {
40
40
-
pixel_buffer[0] = color.blue;
41
41
-
pixel_buffer[1] = color.green;
42
42
-
pixel_buffer[2] = color.red;
43
43
-
},
44
44
-
PixelFormat::U8 => {
45
45
-
// use a simp;le average-based grayscale transform
46
46
-
let gray = color.red / 3 + color.green / 3 + color.blue / 3;
47
47
-
pixel_buffer[0] = gray;
48
48
-
},
49
49
-
other => panic!("unknown pixel format {other:?}"),
50
50
-
}
51
51
-
}
52
52
-
53
53
-
pub struct Display<'f> {
54
54
-
framebuffer: &'f mut FrameBuffer
55
55
-
}
56
56
-
57
57
-
impl<'f> Display<'f> {
58
58
-
pub fn new(framebuffer: &'f mut FrameBuffer) -> Display<'f> {
59
59
-
Display { framebuffer }
60
60
-
}
61
61
-
62
62
-
fn draw_pixel(&mut self, Pixel(coordinates, color): Pixel<Rgb888>) {
63
63
-
// ignore any out of bounds pixels
64
64
-
let (width, height) = {
65
65
-
let info = self.framebuffer.info();
66
66
-
67
67
-
(info.width, info.height)
68
68
-
};
69
69
-
70
70
-
let (x, y) = {
71
71
-
let c: (i32, i32) = coordinates.into();
72
72
-
(c.0 as usize, c.1 as usize)
73
73
-
};
74
74
-
75
75
-
if (0..width).contains(&x) && (0..height).contains(&y) {
76
76
-
let color = Color { red: color.r(), green: color.g(), blue: color.b() };
77
77
-
78
78
-
set_pixel_in(self.framebuffer, Position { x, y }, color);
79
79
-
}
80
80
-
}
81
81
-
}
82
82
-
83
83
-
impl<'f> DrawTarget for Display<'f> {
84
84
-
type Color = Rgb888;
85
85
-
86
86
-
/// Drawing operations can never fail.
87
87
-
type Error = core::convert::Infallible;
88
88
-
89
89
-
fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
90
90
-
where
91
91
-
I: IntoIterator<Item = Pixel<Self::Color>>,
92
92
-
{
93
93
-
for pixel in pixels.into_iter() {
94
94
-
self.draw_pixel(pixel);
95
95
-
}
96
96
-
97
97
-
Ok(())
98
98
-
}
99
99
-
}
100
100
-
101
101
-
impl<'f> OriginDimensions for Display<'f> {
102
102
-
fn size(&self) -> Size {
103
103
-
let info = self.framebuffer.info();
104
104
-
105
105
-
Size::new(info.width as u32, info.height as u32)
106
106
-
}
107
107
-
}
-18
kernel/src/interrupts.rs
···
1
1
-
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
2
2
-
use lazy_static::lazy_static;
3
3
-
4
4
-
lazy_static! {
5
5
-
static ref IDT: InterruptDescriptorTable = {
6
6
-
let mut idt = InterruptDescriptorTable::new();
7
7
-
idt.breakpoint.set_handler_fn(breakpoint_handler);
8
8
-
idt
9
9
-
};
10
10
-
}
11
11
-
12
12
-
pub fn init_idt() {
13
13
-
IDT.load();
14
14
-
}
15
15
-
16
16
-
extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) {
17
17
-
log::info!("Exception: Breakpoint\n{:#?}", stack_frame);
18
18
-
}
-53
kernel/src/main.rs
···
1
1
-
#![no_std]
2
2
-
#![no_main]
3
3
-
#![feature(abi_x86_interrupt)]
4
4
-
5
5
-
use core::panic::PanicInfo;
6
6
-
use bootloader_api::{BootInfo, info::FrameBufferInfo};
7
7
-
use conquer_once::spin::OnceCell;
8
8
-
use bootloader_x86_64_common::logger::LockedLogger;
9
9
-
10
10
-
mod framebuffer;
11
11
-
mod interrupts;
12
12
-
13
13
-
pub(crate) static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
14
14
-
15
15
-
#[panic_handler]
16
16
-
fn panic(_info: &PanicInfo) -> ! {
17
17
-
loop {}
18
18
-
}
19
19
-
20
20
-
pub(crate) fn init_logger(buffer: &'static mut [u8], info: FrameBufferInfo) {
21
21
-
let logger = LOGGER.get_or_init(move || LockedLogger::new(buffer, info, true, false));
22
22
-
log::set_logger(logger).expect("Logger already set");
23
23
-
log::set_max_level(log::LevelFilter::Trace);
24
24
-
log::info!("Hello, Kernel Mode!");
25
25
-
}
26
26
-
27
27
-
bootloader_api::entry_point!(kernel_main);
28
28
-
29
29
-
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
30
30
-
// free the doubly wrapped framebuffer from the boot info struct
31
31
-
let frame_buffer_optional = &mut boot_info.framebuffer;
32
32
-
33
33
-
// free the wrapped framebuffer from the FFI-safe abstraction provided by bootloader_api
34
34
-
let frame_buffer_option = frame_buffer_optional.as_mut();
35
35
-
36
36
-
// unwrap the framebuffer
37
37
-
let frame_buffer_struct = frame_buffer_option.unwrap();
38
38
-
39
39
-
// extract the framebuffer info and, to satisfy the borrow checker, clone it
40
40
-
let frame_buffer_info = frame_buffer_struct.info().clone();
41
41
-
42
42
-
// get the framebuffer's mutable raw byte slice
43
43
-
let raw_frame_buffer = frame_buffer_struct.buffer_mut();
44
44
-
45
45
-
// finally, initialize the logger using the last two variables
46
46
-
init_logger(raw_frame_buffer, frame_buffer_info);
47
47
-
48
48
-
interrupts::init_idt();
49
49
-
50
50
-
x86_64::instructions::interrupts::int3();
51
51
-
52
52
-
loop {}
53
53
-
}
-5
rust-toolchain.toml
···
1
1
-
[toolchain]
2
2
-
channel = "nightly"
3
3
-
profile = "default"
4
4
-
targets = ["x86_64-unknown-none"]
5
5
-
components = ["rust-src", "llvm-tools-preview"]
-11
src/bin/qemu-bios.rs
···
1
1
-
use std::{env, process::{self, Command}};
2
2
-
3
3
-
fn main() {
4
4
-
let mut qemu = Command::new("qemu-system-x86_64");
5
5
-
qemu.arg("-drive");
6
6
-
qemu.arg(format!("format=raw,file={}", env!("BIOS_IMAGE")));
7
7
-
qemu.arg("-serial");
8
8
-
qemu.arg("stdio");
9
9
-
let exit_status = qemu.status().unwrap();
10
10
-
process::exit(exit_status.code().unwrap_or(-1));
11
11
-
}
-21
src/bin/qemu-uefi.rs
···
1
1
-
use std::{env, process::{self, Command}};
2
2
-
use ovmf_prebuilt::{Arch, FileType, Prebuilt, Source};
3
3
-
4
4
-
fn main() {
5
5
-
let prebuilt = Prebuilt::fetch(Source::LATEST, "target/ovmf").unwrap();
6
6
-
let ovmf_code = prebuilt.get_file(Arch::X64, FileType::Code);
7
7
-
let ovmf_vars = prebuilt.get_file(Arch::X64, FileType::Vars);
8
8
-
let mut qemu = Command::new("qemu-system-x86_64");
9
9
-
qemu.args([
10
10
-
"-drive",
11
11
-
&format!("format=raw,if=pflash,readonly=on,file={}", ovmf_code.display()),
12
12
-
"-drive",
13
13
-
&format!("format=raw,if=pflash,file={}", ovmf_vars.display()),
14
14
-
"-drive",
15
15
-
&format!("format=raw,file={}", env!("UEFI_IMAGE")),
16
16
-
"-serial",
17
17
-
"stdio"
18
18
-
]);
19
19
-
let exit_status = qemu.status().unwrap();
20
20
-
process::exit(exit_status.code().unwrap_or(-1));
21
21
-
}
-13
src/main.rs
···
1
1
-
use std::{env, fs};
2
2
-
3
3
-
fn main() {
4
4
-
let current_exe = env::current_exe().unwrap();
5
5
-
let uefi_target = current_exe.with_file_name("uefi.img");
6
6
-
let bios_target = current_exe.with_file_name("bios.img");
7
7
-
8
8
-
fs::copy(env!("UEFI_IMAGE"), &uefi_target).unwrap();
9
9
-
fs::copy(env!("BIOS_IMAGE"), &bios_target).unwrap();
10
10
-
11
11
-
println!("UEFI disk image at {}", uefi_target.display());
12
12
-
println!("BIOS disk image at {}", bios_target.display());
13
13
-
}