Skip to content

Commit 2ceec8a

Browse files
committed
Create migration guides and a disk image creation template
1 parent 46c7725 commit 2ceec8a

File tree

5 files changed

+79
-135
lines changed

5 files changed

+79
-135
lines changed

README.md

+34-15
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ You need a nightly [Rust](https://www.rust-lang.org) compiler with the `llvm-too
1212

1313
## Usage
1414

15+
To use this crate, you need to adjust your kernel to be bootable first. Then you can create a bootable disk image from your compiled kernel. These steps are explained in detail below.
16+
17+
If you're already using an older version of the `bootloader` crate, follow our [migration guides](doc/migration).
18+
19+
### Kernel
20+
1521
To make your kernel compatible with `bootloader`:
1622

1723
- Add a dependency on the `bootloader_api` crate in your kernel's `Cargo.toml`.
@@ -29,24 +35,37 @@ To make your kernel compatible with `bootloader`:
2935
};
3036
bootloader_api::entry_point!(kernel_main, config = &CONFIG);
3137
```
32-
- Compile your kernel as normal to an ELF executable. The executable will contain a special section with metadata and the serialized config, which will enable the `bootloader` crate to load it.
38+
- Compile your kernel to an ELF executable by running **`cargo build --target x86_64-unknown-none`**. You might need to run `rustup target add x86_64-unknown-none` before to download precompiled versions of the `core` and `alloc` crates.
39+
- Thanks to the `entry_point` macro, the compiled executable contains a special section with metadata and the serialized config, which will enable the `bootloader` crate to load it.
40+
41+
### Booting
3342

3443
To combine your kernel with a bootloader and create a bootable disk image, follow these steps:
3544

36-
- Create a new runner crate, e.g. through `cargo new runner --bin`.
37-
- Add the `bootloader` crate as a `dependency` in the `runner/Cargo.toml`.
38-
- In the `main.rs`, invoke the build commands for your kernel.
39-
- Alternatively, you can set up an [artifact dependency](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies) on your kernel, provided that you use a `rustup`-supported target for your kernel:
40-
```toml
41-
[dependencies]
42-
my-kernel = { path = "..", artifact = "bin", target = "x86_64-unknown-none" }
43-
```
44-
- After building your kernel, obtain the path to the kernel executable.
45-
- When using an artifact dependency, you can retrieve this path using `env!("CARGO_BIN_FILE_MY_KERNEL_my-kernel")`
46-
- Use the `bootloader::create_boot_partition` function to create a bootable FAT partition at some chosen path.
47-
- Use one or multiple `bootloader::create_*_disk_image` functions to transform the bootable FAT partition into a disk image.
48-
- Use the `bootloader::create_uefi_disk_image` function to create an UEFI-compatible GPT-formatted disk image.
49-
- Use the `bootloader::create_bios_disk_image` function to create a BIOS-compatible MBR-formatted disk image.
45+
- Move your full kernel code into a `kernel` subdirectory.
46+
- Create a new `os` crate at the top level that defines a [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html).
47+
- Add a `build-dependencies` on the `bootloader` crate.
48+
- Create a [`build.rs`](https://doc.rust-lang.org/cargo/reference/build-scripts.html) build script.
49+
- Set up an [artifact dependency](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies) to add your `kernel` crate as a `build-dependency`:
50+
```toml
51+
# in Cargo.toml
52+
[build-dependencies]
53+
kernel = { path = "kernel", artifact = "bin", target = "x86_64-unknown-none" }
54+
```
55+
```toml
56+
# .cargo/config.toml
57+
58+
[unstable]
59+
# enable the unstable artifact-dependencies feature, see
60+
# https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
61+
bindeps = true
62+
```
63+
Alternatively, you can use [`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html) to invoke the build command of your kernel in the `build.rs` script.
64+
- Obtain the path to the kernel executable. When using an artifact dependency, you can retrieve this path using `env!("CARGO_BIN_FILE_MY_KERNEL_my-kernel")`
65+
- Use `bootloader::UefiBoot` and/or `bootloader::BiosBoot` to create a bootable disk image with your kernel.
66+
- Do something with the bootable disk images in your `main.rs` function. For example, run them with QEMU.
67+
68+
See our [disk image creation template](doc/create-disk-image.md) for a more detailed example.
5069

5170
## Architecture
5271

File renamed without changes.

doc/migration/v0.10.md renamed to docs/create-disk-image.md

+3-39
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,6 @@
1-
# Migration from bootloader `v0.10`
1+
# Template: Create a Disk Image
22

3-
This guide summarizes the steps for migrating from `bootloader v0.10.X` to `bootloader v0.11`.
4-
5-
## Kernel
6-
7-
- Replace the `bootloader` dependency of your kernel with a dependency on the `bootloader_api` crate and adjust the import path in your `main.rs`:
8-
```diff
9-
# in Cargo.toml
10-
11-
-bootloader = { version = "0.10.13" }
12-
+bootloader_api = "0.11"
13-
```
14-
```diff
15-
// in main.rs
16-
17-
-use bootloader::{entry_point, BootInfo};
18-
+use bootloader_api::{entry_point, BootInfo};
19-
```
20-
- If you used optional features, such as `map-physical-memory`, you can enable them again through the `entry_point` macro:
21-
```rust
22-
use bootloader_api::config::{BootloaderConfig, Mapping};
23-
24-
pub static BOOTLOADER_CONFIG: BootloaderConfig = {
25-
let mut config = BootloaderConfig::new_default();
26-
config.mappings.physical_memory = Some(Mapping::Dynamic);
27-
config
28-
};
29-
30-
// add a `config` argument to the `entry_point` macro call
31-
entry_point!(kernel_main, config = &BOOTLOADER_CONFIG);
32-
```
33-
See the [`BootloaderConfig`](https://docs.rs/bootloader_api/0.11/bootloader_api/config/struct.BootloaderConfig.html) struct for all configuration options.
34-
35-
To build your kernel, run **`cargo build --target x86_64-unknown-none`**. Since the `x86_64-unknown-none` target is a Tier-2 target, there is no need for `bootimage`, `cargo-xbuild`, or `xargo` anymore. Instead, you can run `rustup target add x86_64-unknown-none` to download precompiled versions of the `core` and `alloc` crates. There is no need for custom JSON-based target files anymore.
36-
37-
## Booting
38-
39-
The `bootloader v0.11` release simplifies the disk image creation. The [`bootloader`](https://docs.rs/bootloader/0.11) crate now provides simple functions to create bootable disk images from a kernel. The basic idea is to build your kernel first and then invoke a builder function that calls the disk image creation functions of the `bootloader` crate.
3+
The [`bootloader`](https://docs.rs/bootloader/0.11) crate provides simple functions to create bootable disk images from a kernel. The basic idea is to build your kernel first and then invoke a builder function that calls the disk image creation functions of the `bootloader` crate.
404

415
A good way to implement this is to move your kernel into a `kernel` subdirectory. Then you can create
426
a new `os` crate at the top level that defines a [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html). The root package has build-dependencies on the `kernel` [artifact](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies) and on the bootloader crate. This allows you to create the bootable disk image in a [cargo build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) and launch the created image in QEMU in the `main` function.
@@ -79,7 +43,7 @@ fn main() {
7943
let out_dir = env::var_os("OUT_DIR").unwrap();
8044
// set by cargo's artifact dependency feature, see
8145
// https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
82-
let kernel = env!("CARGO_BIN_FILE_KERNEL");
46+
let kernel = env!("CARGO_BIN_FILE_KERNEL_kernel");
8347

8448
// create an UEFI disk image (optional)
8549
let uefi_path = out_dir.join("uefi.img");

docs/migration/v0.10.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Migration from bootloader `v0.10`
2+
3+
This guide summarizes the steps for migrating from `bootloader v0.10.X` to `bootloader v0.11`.
4+
5+
## Kernel
6+
7+
- Replace the `bootloader` dependency of your kernel with a dependency on the `bootloader_api` crate and adjust the import path in your `main.rs`:
8+
```diff
9+
# in Cargo.toml
10+
11+
-bootloader = { version = "0.10.13" }
12+
+bootloader_api = "0.11"
13+
```
14+
```diff
15+
// in main.rs
16+
17+
-use bootloader::{entry_point, BootInfo};
18+
+use bootloader_api::{entry_point, BootInfo};
19+
```
20+
- If you used optional features, such as `map-physical-memory`, you can enable them again through the `entry_point` macro:
21+
```rust
22+
use bootloader_api::config::{BootloaderConfig, Mapping};
23+
24+
pub static BOOTLOADER_CONFIG: BootloaderConfig = {
25+
let mut config = BootloaderConfig::new_default();
26+
config.mappings.physical_memory = Some(Mapping::Dynamic);
27+
config
28+
};
29+
30+
// add a `config` argument to the `entry_point` macro call
31+
entry_point!(kernel_main, config = &BOOTLOADER_CONFIG);
32+
```
33+
See the [`BootloaderConfig`](https://docs.rs/bootloader_api/0.11/bootloader_api/config/struct.BootloaderConfig.html) struct for all configuration options.
34+
35+
To build your kernel, run **`cargo build --target x86_64-unknown-none`**. Since the `x86_64-unknown-none` target is a Tier-2 target, there is no need for `bootimage`, `cargo-xbuild`, or `xargo` anymore. Instead, you can run `rustup target add x86_64-unknown-none` to download precompiled versions of the `core` and `alloc` crates. There is no need for custom JSON-based target files anymore.
36+
37+
## Booting
38+
39+
The `bootloader v0.11` release simplifies the disk image creation. The [`bootloader`](https://docs.rs/bootloader/0.11) crate now provides simple functions to create bootable disk images from a kernel. The basic idea is to build your kernel first and then invoke a builder function that calls the disk image creation functions of the `bootloader` crate.
40+
41+
See our [disk image creation template](../create-disk-image.md) for a detailed explanation of the new build process.

doc/migration/v0.9.md renamed to docs/migration/v0.9.md

+1-81
Original file line numberDiff line numberDiff line change
@@ -46,84 +46,4 @@ To build your kernel, run **`cargo build --target x86_64-unknown-none`**. Since
4646

4747
The `bootloader v0.11` release does not use the `bootimage` tool anymore. Instead, the [`bootloader`](https://docs.rs/bootloader/0.11) crate provides functions to create bootable disk images from a kernel. The basic idea is to build your kernel first and then invoke a builder function that calls the disk image creation functions of the `bootloader` crate.
4848

49-
A good way to implement this is to move your kernel into a `kernel` subdirectory. Then you can create
50-
a new `os` crate at the top level that defines a [workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html). The root package has build-dependencies on the `kernel` [artifact](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies) and on the bootloader crate. This allows you to create the bootable disk image in a [cargo build script](https://doc.rust-lang.org/cargo/reference/build-scripts.html) and launch the created image in QEMU in the `main` function.
51-
52-
The files could look like this:
53-
54-
```toml
55-
# .cargo/config.toml
56-
57-
[unstable]
58-
# enable the unstable artifact-dependencies feature, see
59-
# https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
60-
bindeps = true
61-
```
62-
63-
```toml
64-
# Cargo.toml
65-
66-
[package]
67-
name = "os" # or any other name
68-
version = "0.1.0"
69-
70-
[build-dependencies]
71-
bootloader = "0.11"
72-
test-kernel = { path = "kernel", artifact = "bin", target = "x86_64-unknown-none" }
73-
74-
[dependencies]
75-
# used for UEFI booting in QEMU
76-
ovmf_prebuilt = "0.1.0-alpha.1"
77-
78-
[workspace]
79-
members = ["kernel"]
80-
```
81-
82-
```rust
83-
// build.rs
84-
85-
fn main() {
86-
// set by cargo, build scripts should use this directory for output files
87-
let out_dir = env::var_os("OUT_DIR").unwrap();
88-
// set by cargo's artifact dependency feature, see
89-
// https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies
90-
let kernel = env!("CARGO_BIN_FILE_KERNEL");
91-
92-
// create an UEFI disk image (optional)
93-
let uefi_path = out_dir.join("uefi.img");
94-
bootloader::UefiBoot::new(&kernel).create_disk_image(uefi_path).unwrap();
95-
96-
// create a BIOS disk image (optional)
97-
let out_bios_path = out_dir.join("bios.img");
98-
bootloader::BiosBoot::new(&kernel).create_disk_image(uefi_path).unwrap();
99-
100-
// pass the disk image paths as env variables to the `main.rs`
101-
println!("cargo:rustc-env=UEFI_PATH={}", uefi_path.display());
102-
println!("cargo:rustc-env=BIOS_PATH={}", bios_path.display());
103-
}
104-
```
105-
106-
```rust
107-
// src/main.rs
108-
109-
fn main() {
110-
// read env variables that were set in build script
111-
let uefi_path = env!("UEFI_PATH");
112-
let bios_path = env!("BIOS_PATH");
113-
114-
// choose whether to start the UEFI or BIOS image
115-
let uefi = true;
116-
117-
let mut cmd = std::process::Command::new("qemu-system-x86_64");
118-
if uefi {
119-
cmd.arg("-bios").arg(ovmf_prebuilt::ovmf_pure_efi());
120-
cmd.arg("-drive").arg(format!("format=raw,file={uefi_path}"));
121-
} else {
122-
cmd.arg("-drive").arg(format!("format=raw,file={bios_path}"));
123-
}
124-
let mut child = cmd.spawn()?;
125-
child.wait()?;
126-
}
127-
```
128-
129-
Now you should be able to use `cargo build` to create a bootable disk image and `cargo run` to run in QEMU. Your kernel is automatically recompiled when it changes. For more advanced usage, you can add command-line arguments to your `main.rs` to e.g. pass additional arguments to QEMU or to copy the disk images to some path to make it easier to find them (e.g. for copying them to an thumb drive).
49+
See our [disk image creation template](../create-disk-image.md) for a detailed explanation of the new build process.

0 commit comments

Comments
 (0)