Skip to content

Commit 8ca8a7a

Browse files
authored
Merge pull request #166 from rust-osdev/examples
Add some usage examples
2 parents 9589cff + e4cffd4 commit 8ca8a7a

23 files changed

+727
-0
lines changed

.github/workflows/build.yml

+8
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ jobs:
6969
with:
7070
command: test
7171

72+
- name: "Example: `basic`"
73+
working-directory: examples/basic
74+
run: cargo kimage
75+
76+
- name: "Example: `test_framework` example"
77+
working-directory: examples/test_framework
78+
run: cargo ktest
79+
7280
fmt:
7381
name: Check Formatting
7482
runs-on: ubuntu-latest

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ members = [
1515
"tests/test_kernels/map_phys_mem",
1616
"tests/test_kernels/higher_half",
1717
]
18+
exclude = [
19+
"examples/basic",
20+
"examples/test_framework",
21+
]
1822

1923
[[bin]]
2024
name = "builder"

examples/README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
## Usage Examples
2+
3+
- [`basic`](basic)
4+
- [`test_framework`](test_framework)

examples/basic/.cargo/config.toml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[target.'cfg(target_os = "none")']
2+
runner = "cargo run --package simple_boot --"
3+
4+
[alias]
5+
kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"
6+
kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run"
7+
krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"

examples/basic/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

examples/basic/Cargo.lock

+46
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/basic/Cargo.toml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "basic_example"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[workspace]
9+
members = [
10+
"simple_boot",
11+
]
12+
13+
[dependencies]
14+
bootloader = { path = "../.." } # replace this with a version number

examples/basic/README.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Basic Example
2+
3+
This a minimal example how to create a bootable disk image with the `bootloader` crate.
4+
5+
## Structure
6+
7+
The kernel code is in `src/main.rs`. It requires some special build instructions to recompile the `core` library for the custom target defined in `x86_64-custom.json`. It depends on the `bootloader` crate for booting..
8+
9+
The `simple_boot` sub-crate is responsible for combining the kernel with the bootloader to create bootable disk images. It is configured as a [custom _runner_](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerunner), which means that cargo will automatically invoke it on `cargo run`. The compiled kernel will hereby be passed as an argument.
10+
11+
## Build Commands
12+
13+
The `.cargo/config.toml` file defines command aliases for the common commands:
14+
15+
- To build the kernel, run **`cargo kbuild`**.
16+
- To build the kernel and turn it into a bootable disk image, run **`cargo kimage`** (short for "kernel image"). This will invoke our `boot` sub-crate with an additional `--no-run` argument so that it just creates the disk image and exits.
17+
- To additionally run the kernel in QEMU after creating the disk image, run **`cargo krun`**.

examples/basic/simple_boot/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "simple_boot"
3+
version = "0.1.0"
4+
authors = ["Philipp Oppermann <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
bootloader-locator = "0.0.4" # for locating the `bootloader` dependency on disk
11+
locate-cargo-manifest = "0.2.0" # for locating the kernel's `Cargo.toml`
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::{
2+
path::{Path, PathBuf},
3+
process::Command,
4+
};
5+
6+
const RUN_ARGS: &[&str] = &["--no-reboot", "-s"];
7+
8+
fn main() {
9+
let mut args = std::env::args().skip(1); // skip executable name
10+
11+
let kernel_binary_path = {
12+
let path = PathBuf::from(args.next().unwrap());
13+
path.canonicalize().unwrap()
14+
};
15+
let no_boot = if let Some(arg) = args.next() {
16+
match arg.as_str() {
17+
"--no-run" => true,
18+
other => panic!("unexpected argument `{}`", other),
19+
}
20+
} else {
21+
false
22+
};
23+
24+
let bios = create_disk_images(&kernel_binary_path);
25+
26+
if no_boot {
27+
println!("Created disk image at `{}`", bios.display());
28+
return;
29+
}
30+
31+
let mut run_cmd = Command::new("qemu-system-x86_64");
32+
run_cmd
33+
.arg("-drive")
34+
.arg(format!("format=raw,file={}", bios.display()));
35+
run_cmd.args(RUN_ARGS);
36+
37+
let exit_status = run_cmd.status().unwrap();
38+
if !exit_status.success() {
39+
std::process::exit(exit_status.code().unwrap_or(1));
40+
}
41+
}
42+
43+
pub fn create_disk_images(kernel_binary_path: &Path) -> PathBuf {
44+
let bootloader_manifest_path = bootloader_locator::locate_bootloader("bootloader").unwrap();
45+
let kernel_manifest_path = locate_cargo_manifest::locate_manifest().unwrap();
46+
47+
let mut build_cmd = Command::new(env!("CARGO"));
48+
build_cmd.current_dir(bootloader_manifest_path.parent().unwrap());
49+
build_cmd.arg("builder");
50+
build_cmd
51+
.arg("--kernel-manifest")
52+
.arg(&kernel_manifest_path);
53+
build_cmd.arg("--kernel-binary").arg(&kernel_binary_path);
54+
build_cmd
55+
.arg("--target-dir")
56+
.arg(kernel_manifest_path.parent().unwrap().join("target"));
57+
build_cmd
58+
.arg("--out-dir")
59+
.arg(kernel_binary_path.parent().unwrap());
60+
build_cmd.arg("--quiet");
61+
62+
if !build_cmd.status().unwrap().success() {
63+
panic!("build failed");
64+
}
65+
66+
let kernel_binary_name = kernel_binary_path.file_name().unwrap().to_str().unwrap();
67+
let disk_image = kernel_binary_path
68+
.parent()
69+
.unwrap()
70+
.join(format!("boot-bios-{}.img", kernel_binary_name));
71+
if !disk_image.exists() {
72+
panic!(
73+
"Disk image does not exist at {} after bootloader build",
74+
disk_image.display()
75+
);
76+
}
77+
disk_image
78+
}

examples/basic/src/main.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use bootloader::{entry_point, BootInfo};
5+
use core::panic::PanicInfo;
6+
7+
entry_point!(kernel_main);
8+
9+
fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
10+
// turn the screen gray
11+
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
12+
for byte in framebuffer.buffer_mut() {
13+
*byte = 0x90;
14+
}
15+
}
16+
17+
loop {}
18+
}
19+
20+
21+
#[panic_handler]
22+
fn panic(_info: &PanicInfo) -> ! {
23+
loop {}
24+
}

examples/basic/x86_64-custom.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"llvm-target": "x86_64-unknown-none",
3+
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
4+
"arch": "x86_64",
5+
"target-endian": "little",
6+
"target-pointer-width": "64",
7+
"target-c-int-width": "32",
8+
"os": "none",
9+
"executables": true,
10+
"linker-flavor": "ld.lld",
11+
"linker": "rust-lld",
12+
"panic-strategy": "abort",
13+
"disable-redzone": true,
14+
"features": "-mmx,-sse,+soft-float"
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[target.'cfg(target_os = "none")']
2+
runner = "cargo run --package boot --"
3+
4+
[alias]
5+
kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"
6+
kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run"
7+
krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"
8+
ktest = "test --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"

examples/test_framework/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target

0 commit comments

Comments
 (0)