Skip to content

Commit ab071c6

Browse files
bors[bot]phil-opp
andcommitted
Merge #53
53: Updates for new build system r=phil-opp a=phil-opp Update the documentation for the new build system and add an `example-kernel` that provides an easy way to try the `bootloader`. Builds upon #51. Co-authored-by: Philipp Oppermann <[email protected]>
2 parents e1c6330 + 44b436d commit ab071c6

12 files changed

+201
-26
lines changed

Changelog.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## Breaking
2+
3+
- Change the build system: Use a build script that expects a `KERNEL` environment variable instead of using a separate `builder` executable as before. See [#51](https://github.com/rust-osdev/bootloader/pull/51) and [#53](https://github.com/rust-osdev/bootloader/pull/53) for more information.
4+
- This makes the bootloader incompatible with versions `0.6.*` and earlier of the `bootimage` tool.
5+
- The bootloader also requires the `llvm-tools-preview` rustup component now.
6+
17
# 0.4.0
28

39
## Breaking

README.md

+46-10
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,50 @@ Written for the [second edition](https://github.com/phil-opp/blog_os/issues/360)
1010

1111
TODO
1212

13-
## Build and Run
14-
You need a nightly [Rust](https://www.rust-lang.org) compiler and [cargo xbuild](https://github.com/rust-osdev/cargo-xbuild).
13+
## Requirements
1514

16-
Then you can run the `builder` executable with your kernel as argument:
15+
You need a nightly [Rust](https://www.rust-lang.org) compiler and [cargo xbuild](https://github.com/rust-osdev/cargo-xbuild). You also need the `llvm-tools-preview` component, which can be installed through `rustup component add llvm-tools-preview`.
16+
17+
## Build
18+
19+
The simplest way to use the bootloader is in combination with the [bootimage](https://github.com/rust-osdev/bootimage) tool. With the tool installed, you can add a normal cargo dependency on the `bootloader` crate to your kernel and then run `bootimage build` to create a bootable disk image. You can also execute `bootimage run` to run your kernel in [QEMU](https://www.qemu.org/) (needs to be installed).
20+
21+
To compile the bootloader manually, you need to invoke `cargo xbuild` with a `KERNEL` environment variable that points to your kernel executable (in the ELF format):
1722

1823
```
19-
cd builder
20-
cargo run -- --kernel path/to/your/kernel/elf/file
24+
KERNEL=/path/to/your/kernel/target/debug/your_kernel cargo xbuild
2125
```
2226

23-
This will output a file named `bootimage.bin` in the `../target/x86_64-bootloader/release` folder.
27+
As an example, you can build the bootloader with example kernel from the `example-kernel` directory with the following commands:
2428

25-
You can run this file using [QEMU](https://www.qemu.org/):
29+
```
30+
cd example-kernel
31+
cargo xbuild
32+
cd ..
33+
KERNEL=example-kernel/target/x86_64-example-kernel/debug/example-kernel cargo xbuild --release
34+
```
35+
36+
This results in a bootloader executable at `target/x86_64-bootloader.json/release/bootloader`. This executable is still an ELF file, which can't be run directly.
37+
38+
## Run
39+
40+
To run the compiled bootloader executable, you need to convert it to a binary file. You can use the `llvm-objcopy` tools that ships with the `llvm-tools-preview` rustup component. The easiest way to use this tool is using [`cargo-binutils`](https://github.com/rust-embedded/cargo-binutils), which can be installed through `cargo install cargo-binutils`. Then you can perform the conversion with the following command:
2641

2742
```
28-
qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootimage.bin
43+
cargo objcopy -- -I elf64-x86-64 -O binary --binary-architecture=i386:x86-64 \
44+
target/x86_64-bootloader/release/bootloader target/x86_64-bootloader/release/bootloader.bin
2945
```
3046

31-
Or burn it to an USB drive:
47+
You can run the `bootloader.bin` file using [QEMU](https://www.qemu.org/):
3248

3349
```
34-
dd if=target/x86_64-blog_os/debug/bootimage-blog_os.bin of=/dev/sdX && sync
50+
qemu-system-x86_64 -drive format=raw,file=target/x86_64-bootloader/release/bootloader.bin
51+
```
52+
53+
Or burn it to an USB drive to boot it on real hardware:
54+
55+
```
56+
dd if=target/x86_64-bootloader/release/bootloader.bin of=/dev/sdX && sync
3557
```
3658

3759
Where sdX is the device name of your USB stick. **Be careful** to choose the correct device name, because everything on that device is overwritten.
@@ -40,3 +62,17 @@ Where sdX is the device name of your USB stick. **Be careful** to choose the cor
4062
The bootloader crate can be configured through some cargo features:
4163

4264
- `vga_320x200`: This feature switches the VGA hardware to mode 0x13, a graphics mode with resolution 320x200 and 256 colors per pixel. The framebuffer is linear and lives at address `0xa0000`.
65+
- `recursive_page_table`: Maps the level 4 page table recursively and adds the [`recursive_page_table_address`](https://docs.rs/bootloader/0.4.0/bootloader/bootinfo/struct.BootInfo.html#structfield.recursive_page_table_addr) field to the passed `BootInfo`.
66+
- `map_physical_memory`: Maps the complete physical memory in the virtual address space and passes a [`physical_memory_offset`](https://docs.rs/bootloader/0.4.0/bootloader/bootinfo/struct.BootInfo.html#structfield.physical_memory_offset) field in the `BootInfo`.
67+
68+
## License
69+
70+
Licensed under either of
71+
72+
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
73+
http://www.apache.org/licenses/LICENSE-2.0)
74+
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
75+
76+
at your option.
77+
78+
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

azure-pipelines.yml

+7-4
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,13 @@ steps:
9090
failOnStderr: true
9191
displayName: 'Install QEMU (Windows)'
9292

93-
- script: cargo xbuild --target x86_64-example-kernel.json
94-
workingDirectory: example-kernel
95-
displayName: 'Build Example Kernel'
93+
- script: cargo xbuild
94+
workingDirectory: test-kernel
95+
displayName: 'Build Test Kernel'
9696

9797
- script: cargo xbuild --release
9898
displayName: 'Build Bootloader'
99-
env: { KERNEL: "example-kernel/target/x86_64-example-kernel/debug/example-kernel" }
99+
env: { KERNEL: "test-kernel/target/x86_64-test-kernel/debug/test-kernel" }
100100

101101
- script: cargo objcopy -- -I elf64-x86-64 -O binary --binary-architecture=i386:x86-64 target/x86_64-bootloader/release/bootloader target/x86_64-bootloader/release/bootloader.bin
102102
displayName: 'Convert Bootloader ELF to Binary'
@@ -106,3 +106,6 @@ steps:
106106
if [ $? -eq 123 ]; then (exit 0); else (exit 1); fi
107107
displayName: 'Test Bootloader'
108108

109+
- script: cargo xbuild
110+
workingDirectory: example-kernel
111+
displayName: 'Build Example Kernel'

example-kernel/.cargo/config

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build]
2+
target = "x86_64-example-kernel.json"

example-kernel/src/main.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,29 @@
33

44
use core::panic::PanicInfo;
55

6-
/// This function is called on panic.
7-
#[panic_handler]
8-
fn panic(_info: &PanicInfo) -> ! {
9-
loop {}
10-
}
6+
static HELLO: &[u8] = b"Hello World!";
117

128
#[no_mangle] // don't mangle the name of this function
139
pub extern "C" fn _start() -> ! {
1410
// this function is the entry point, since the linker looks for a function
1511
// named `_start` by default
1612

17-
// exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu)
18-
unsafe { exit_qemu(); }
13+
let vga_buffer = 0xb8000 as *mut u8;
14+
15+
// print `HELLO` to the screen (see
16+
// https://os.phil-opp.com/minimal-rust-kernel/#printing-to-screen)
17+
for (i, &byte) in HELLO.iter().enumerate() {
18+
unsafe {
19+
*vga_buffer.offset(i as isize * 2) = byte;
20+
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
21+
}
22+
}
1923

2024
loop {}
2125
}
2226

23-
pub unsafe fn exit_qemu() {
24-
use x86_64::instructions::port::Port;
25-
26-
let mut port = Port::<u32>::new(0xf4);
27-
port.write(61); // exit code is (61 << 1) | 1 = 123
27+
/// This function is called on panic.
28+
#[panic_handler]
29+
fn panic(_info: &PanicInfo) -> ! {
30+
loop {}
2831
}

rust-toolchain

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

test-kernel/.cargo/config

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[build]
2+
target = "x86_64-test-kernel.json"

test-kernel/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target/
2+
**/*.rs.bk

test-kernel/Cargo.lock

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

test-kernel/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "test-kernel"
3+
version = "0.1.0"
4+
authors = ["Philipp Oppermann <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
x86_64 = "0.3.4"

test-kernel/src/main.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![no_std] // don't link the Rust standard library
2+
#![no_main] // disable all Rust-level entry points
3+
4+
use core::panic::PanicInfo;
5+
6+
/// This function is called on panic.
7+
#[panic_handler]
8+
fn panic(_info: &PanicInfo) -> ! {
9+
loop {}
10+
}
11+
12+
#[no_mangle] // don't mangle the name of this function
13+
pub extern "C" fn _start() -> ! {
14+
// this function is the entry point, since the linker looks for a function
15+
// named `_start` by default
16+
17+
// exit QEMU (see https://os.phil-opp.com/integration-tests/#shutting-down-qemu)
18+
unsafe { exit_qemu(); }
19+
20+
loop {}
21+
}
22+
23+
pub unsafe fn exit_qemu() {
24+
use x86_64::instructions::port::Port;
25+
26+
let mut port = Port::<u32>::new(0xf4);
27+
port.write(61); // exit code is (61 << 1) | 1 = 123
28+
}

test-kernel/x86_64-test-kernel.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+
}

0 commit comments

Comments
 (0)