### Build command output Source: https://os.phil-opp.com/freestanding-rust-binary Example of the error message encountered when the start language item is missing. ```text > cargo build error: requires `start` lang_item ``` -------------------------------- ### Build and Install Binutils Source: https://os.phil-opp.com/cross-compile-binutils Compile the source code and install the binaries to the specified prefix directory. ```bash make make install ``` -------------------------------- ### Install `llvm-tools-preview` component Source: https://os.phil-opp.com/minimal-rust-kernel Install the necessary Rustup component for `bootimage` to function correctly. This component provides LLVM tools required for building. ```bash rustup component add llvm-tools-preview ``` -------------------------------- ### Handle Start State Transition Source: https://os.phil-opp.com/async-await Illustrates the pseudo-code for the `Start` state's transition, initiating the first async operation and moving to the `WaitingOnFooTxt` state. ```rust ExampleStateMachine::Start(state) => { // from body of `example` let foo_txt_future = async_read_file("foo.txt"); // `.await` operation let state = WaitingOnFooTxtState { min_len: state.min_len, foo_txt_future, }; *self = ExampleStateMachine::WaitingOnFooTxt(state); } ``` -------------------------------- ### Install Cargo xbuild and Bootimage Source: https://os.phil-opp.com/edition-2/extra/building-on-android Installs the `cargo-xbuild` and `bootimage` Cargo subcommands, which are essential for building the OS kernel. ```bash cargo install cargo-xbuild bootimage ``` -------------------------------- ### Install `bootimage` tool Source: https://os.phil-opp.com/minimal-rust-kernel Install the `bootimage` cargo tool globally to create bootable disk images. Ensure you are outside your cargo project directory when running this command. ```bash cargo install bootimage ``` -------------------------------- ### Install Git in Termux Source: https://os.phil-opp.com/edition-2/extra/building-on-android Installs the Git version control system, which is needed to clone the blog_os project repository. ```bash pkg install git ``` -------------------------------- ### Windows Linker Error Example (Entry Point) Source: https://os.phil-opp.com/freestanding-rust-binary This is an example of a linker error encountered on Windows, indicating that the linker could not find the required entry point function. ```text error: linking with `link.exe` failed: exit code: 1561 | = note: "C:\\Program Files (x86)\\…\\link.exe" […] = note: LINK : fatal error LNK1561: entry point must be defined ``` -------------------------------- ### Install Rust Nightly on Termux (Official Repo) Source: https://os.phil-opp.com/edition-2/extra/building-on-android Use these commands to install Rust nightly and its source from Termux's official repository. Ensure your package list is up-to-date before installing. ```bash pkg update pkg install rustc-nightly rust-src-nightly ``` -------------------------------- ### Install Rust Nightly and Cargo Source: https://os.phil-opp.com/edition-2/extra/building-on-android Installs the `rustc` compiler, `cargo` build tool, and a specific nightly version of `rustc` required for the project. ```bash pkg install rustc cargo rustc-nightly ``` -------------------------------- ### Basic Rust Library Structure Source: https://os.phil-opp.com/testing Initial setup for a Rust library crate, requiring `no_std`. ```rust // src/lib.rs #![no_std] ``` -------------------------------- ### Basic Kernel Module Setup Source: https://os.phil-opp.com/cpu-exceptions Sets up the basic module structure for interrupts in `src/lib.rs` by declaring the `interrupts` module. ```rust pub mod interrupts; ``` -------------------------------- ### Install Rust Nightly on Termux (User Repo) Source: https://os.phil-opp.com/edition-2/extra/building-on-android If Rust nightly is moved to the user repository, follow these steps. This involves adding the user repository and then installing the nightly packages. ```bash pkg update pkg install tur-repo pkg update pkg install rustc-nightly rust-src-nightly ``` -------------------------------- ### Create a Separate Test Executable Source: https://os.phil-opp.com/integration-tests Place Rust files in `src/bin` to create independent executables for testing. This example shows a minimal `_start` function and panic handler for a test binary. ```Rust // src/bin/test-something.rs #![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_main)] #![cfg_attr(test, allow(unused_imports))] use core::panic::PanicInfo; #[cfg(not(test))] #[no_mangle] pub extern "C" fn _start() -> ! { // run tests loop {} } #[cfg(not(test))] #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } ``` -------------------------------- ### Build and Package OS Test Binaries Source: https://os.phil-opp.com/testing Uses cargo and jq to locate test binaries and build a bootable image via the bootloader manifest. Requires jq, cargo, and rust-objcopy to be installed in the environment. ```bash TARGET_NAME=$1 TARGET_KIND=$2 KERNEL_BIN_PATH=$(cargo build --tests --message-format=json | jq -r "select(.target.name == "$TARGET_NAME" and (.target.kind | any(index("$TARGET_KIND"))) and .target.test and .profile.test) | .executable | select(. != null)") BOOTLOADER_MANIFEST_PATH=$(cargo metadata --format-version 1 | jq -r '.packages[] | select(.name == "bootloader") | .manifest_path') BOOTLOADER_TARGET_PATH=$(dirname $BOOTLOADER_MANIFEST_PATH)/x86_64-bootloader.json KERNEL=$KERNEL_BIN_PATH KERNEL_MANIFEST=$(pwd)/Cargo.toml cargo build --manifest-path $BOOTLOADER_MANIFEST_PATH -Zbuild-std=core --release --features binary --target $BOOTLOADER_TARGET_PATH --target-dir ./target rust-objcopy -I elf64-x86-64 -O binary --binary-architecture=i386:x86-64 target/x86_64-bootloader/release/bootloader target/bootimage-$TARGET_KIND-$TARGET_NAME.bin ``` -------------------------------- ### Rust Library Test Framework Setup Source: https://os.phil-opp.com/testing Configures the Rust library for testing, including a custom test runner and panic handler. This setup is conditional for test builds. ```rust // in src/lib.rs #![cfg_attr(test, no_main)] #![feature(custom_test_frameworks)] #![test_runner(crate::test_runner)] #![reexport_test_harness_main = "test_main"] use core::panic::PanicInfo; pub trait Testable { fn run(&self) -> (); } impl Testable for T where T: Fn(), { fn run(&self) { serial_print!("{}...\t", core::any::type_name::()); self(); serial_println!("[ok]"); } } pub fn test_runner(tests: &[&dyn Testable]) { serial_println!("Running {} tests", tests.len()); for test in tests { test.run(); } exit_qemu(QemuExitCode::Success); } pub fn test_panic_handler(info: &PanicInfo) -> ! { serial_println!("[failed]\n"); serial_println!("Error: {}\n", info); exit_qemu(QemuExitCode::Failed); loop {} } /// Entry point for `cargo test` #[cfg(test)] #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { test_main(); loop {} } #[cfg(test)] #[panic_handler] fn panic(info: &PanicInfo) -> ! { test_panic_handler(info) } ``` -------------------------------- ### Example lib.rs with test dependencies Source: https://os.phil-opp.com/integration-tests This snippet shows the `lib.rs` file including the necessary `extern crate` declarations for testing in a no_std environment, along with the `no_std` attribute. ```rust #![no_std] // don't link the Rust standard library ... #[cfg(test)] extern crate array_init; #[cfg(test)] extern crate std; ... ``` -------------------------------- ### Define a basic integration test Source: https://os.phil-opp.com/testing This example shows the required crate attributes and entry point for an integration test file located in the tests directory. ```rust // in tests/basic_boot.rs #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(crate::test_runner)] #![reexport_test_harness_main = "test_main"] use core::panic::PanicInfo; #[unsafe(no_mangle)] // don't mangle the name of this function pub extern "C" fn _start() -> ! { test_main(); loop {} } fn test_runner(tests: &[&dyn Fn()]) { unimplemented!(); } #[panic_handler] fn panic(info: &PanicInfo) -> ! { loop {} } ``` -------------------------------- ### Asynchronous File Writing Example Source: https://os.phil-opp.com/async-await Demonstrates an asynchronous function that writes to a file, illustrating how the Waker API signals completion to the executor. ```rust async fn write_file() { async_write_file("foo.txt", "Hello").await; } ``` -------------------------------- ### Cargo.toml Configuration for OS Development Source: https://os.phil-opp.com/testing Example Cargo.toml file for an OS project, specifying dependencies like `bootloader`, `volatile`, `spin`, `x86_64`, and `lazy_static`. Includes metadata for bootimage testing. ```toml [package] name = "blog_os" version = "0.1.0" edition = "2021" [dependencies] bootloader = "0.9.22" volatile = "=0.2.6" spin = "0.5.2" x86_64 = "0.14.12" [dependencies.lazy_static] version = "1.4.0" features = ["spin_no_std"] [package.metadata.bootimage] test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"] ``` -------------------------------- ### Example x86_64 Linux Target Specification Source: https://os.phil-opp.com/minimal-rust-kernel This JSON defines a standard target for x86_64 Linux with the GNU ABI. It includes LLVM configuration, data layout, architecture details, and build-related settings like pre-link arguments. ```json { "llvm-target": "x86_64-unknown-linux-gnu", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", "target-pointer-width": 64, "target-c-int-width": 32, "os": "linux", "executables": true, "linker-flavor": "gcc", "pre-link-args": ["-m64"], "morestack": false } ``` -------------------------------- ### Create Example Mapping Function Source: https://os.phil-opp.com/paging-implementation This function maps a given virtual page to the VGA text buffer frame (0xb8000). It requires a mutable mapper and a frame allocator. The mapping is marked as present and writable. Note the `FIXME` comment indicating the unsafe nature of reusing an already mapped frame. ```rust use x86_64:: PhysAddr, structures::paging::{Page, PhysFrame, Mapper, Size4KiB, FrameAllocator} ; /// Creates an example mapping for the given page to frame `0xb8000`. pub fn create_example_mapping( page: Page, mapper: &mut OffsetPageTable, frame_allocator: &mut impl FrameAllocator, ) { use x86_64::structures::paging::PageTableFlags as Flags; let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000)); let flags = Flags::PRESENT | Flags::WRITABLE; let map_to_result = unsafe { // FIXME: this is not safe, we do it only for testing mapper.map_to(page, frame, flags, frame_allocator) }; map_to_result.expect("map_to failed").flush(); } ``` -------------------------------- ### Implement Basic Boot Integration Test Source: https://os.phil-opp.com/integration-tests A minimal integration test that verifies the _start function is called by printing 'ok' and exiting QEMU. ```rust // in src/bin/test-basic-boot.rs #![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_main)] // disable all Rust-level entry points #![cfg_attr(test, allow(unused_imports))] use core::panic::PanicInfo; use blog_os::{exit_qemu, serial_println}; /// This function is the entry point, since the linker looks for a function /// named `_start` by default. #[cfg(not(test))] #[no_mangle] // don't mangle the name of this function pub extern "C" fn _start() -> ! { serial_println!("ok"); unsafe { exit_qemu(); } loop {} } /// This function is called on panic. #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { serial_println!("failed"); serial_println!("{}", info); unsafe { exit_qemu(); } loop {} } ``` -------------------------------- ### Hello World using println Source: https://os.phil-opp.com/vga-text-mode Use the `println` macro within the `_start` function to display "Hello World!". The macro is available in the root namespace, so no explicit import is needed. ```Rust // in src/main.rs #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); loop {} } ``` -------------------------------- ### Assertion Failure Panic Message Source: https://os.phil-opp.com/hardware-interrupts Example of a panic message encountered during APIC setup when assertion values do not match. ```text assertion failed (left == right) { left: 3 right: 0 } ``` -------------------------------- ### Install xargo via cargo Source: https://os.phil-opp.com/cross-compile-libcore Installs the xargo tool, which acts as a wrapper for cargo to facilitate cross-compilation for custom targets. ```bash cargo install xargo ``` -------------------------------- ### Boot disk image in QEMU Source: https://os.phil-opp.com/minimal-rust-kernel Launch the created bootable disk image in QEMU for testing. The `-drive` option specifies the raw format and the path to the generated `.bin` file. ```bash qemu-system-x86_64 -drive format=raw,file=target/x86_64-blog_os/debug/bootimage-blog_os.bin ``` -------------------------------- ### Testing the Mapping Function in main.rs Source: https://os.phil-opp.com/advanced-paging Initializes the page table and calls `create_example_mapping` to map the page `0x1000` to the VGA text buffer. A volatile write to `0x1900` is performed to test the mapping. ```Rust #[cfg(not(test))] #[no_mangle] pub extern "C" fn _start() -> ! { // [...] // initialize GDT, IDT, PICS use blog_os::memory::{create_example_mapping, EmptyFrameAllocator}; const LEVEL_4_TABLE_ADDR: usize = 0o_177777_777_777_777_777_0000; let mut recursive_page_table = unsafe { memory::init(LEVEL_4_TABLE_ADDR) }; create_example_mapping(&mut recursive_page_table, &mut EmptyFrameAllocator); unsafe { (0x1900 as *mut u64).write_volatile(0xf021_f077_f065_f04e)}; println!("It did not crash!"); blog_os::hlt_loop(); } ``` -------------------------------- ### Create Build Directory Source: https://os.phil-opp.com/cross-compile-binutils Prepare a dedicated directory for the binutils build process. ```bash mkdir build-binutils cd build-binutils ``` -------------------------------- ### QEMU Boot Sequence with SeaBIOS and iPXE Source: https://os.phil-opp.com/minimal-rust-kernel This output shows QEMU attempting to boot using SeaBIOS and iPXE. The sequence indicates failures to boot from hard disk, floppy, and CD-ROM, eventually falling back to network boot via iPXE. This suggests the disk image is not correctly recognized as bootable. ```text SeaBIOS (version 1.16.3-debian-1.16.3-2) iPXE (https://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+06FCAF60+06F0AF60 CA00 Booting from Hard Disk... Boot failed: not a bootable disk Booting from Floppy... Boot failed: could not read the boot disk Booting from DVD/CD... Boot failed: Could not read from CDROM (code 0003) Booting from ROM... iPXE (PCI 00:03.0) starting execution...ok iPXE initialising devices...ok iPXE 1.21.1+git-20220113.fbbdc3926-0ubuntu2 -- Open Source Network Boot Firmware -- https://ipxe.org Features: DNS HTTP HTTPS iSCSI NFS TFTP VLAN AoE ELF MBOOT PXE bzImage Menu PXEX T ``` -------------------------------- ### Basic Boot Test File Reference Source: https://os.phil-opp.com/testing Indicates the file path for the basic boot test implementation. ```text // in tests/basic_boot.rs ``` -------------------------------- ### Define Entry Point on Windows Source: https://os.phil-opp.com/freestanding-rust-binary Pass `/ENTRY:_start` to the linker using `cargo rustc` to specify `_start` as the entry point, resolving the 'entry point must be defined' error on Windows. ```bash cargo rustc -- -C link-arg=/ENTRY:_start ``` -------------------------------- ### Windows Linker Error Example (Subsystem) Source: https://os.phil-opp.com/freestanding-rust-binary This is an example of a linker error encountered on Windows, indicating that the executable's subsystem could not be inferred and must be explicitly defined. ```text error: linking with `link.exe` failed: exit code: 1221 | = note: "C:\\Program Files (x86)\\…\\link.exe" […] = note: LINK : fatal error LNK1221: a subsystem can't be inferred and must be defined ``` -------------------------------- ### Linux Linker Error Example Source: https://os.phil-opp.com/freestanding-rust-binary This is an example of a linker error encountered on Linux when building a `no_std` Rust program, indicating unresolved symbols from the C standard library. ```text error: linking with `cc` failed: exit code: 1 | = note: "cc" […] = note: /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start`: (.text+0x12): undefined reference to `__libc_csu_fini` /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start`: (.text+0x19): undefined reference to `__libc_csu_init` /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start`: (.text+0x25): undefined reference to `__libc_start_main` collect2: error: ld returned 1 exit status ``` -------------------------------- ### Rust Kernel Entry Point and VGA Output Source: https://os.phil-opp.com/minimal-rust-kernel This code snippet demonstrates a minimal Rust kernel's entry point. It writes 'Hello World!' to the VGA text buffer at memory address 0xb8000. Ensure `no_std` and `no_main` are used for bare-metal development. ```rust #![no_std] // don't link the Rust standard library #![no_main] // disable all Rust-level entry points use core::panic::PanicInfo; static HELLO: &[u8] = b"Hello World!"; #[no_mangle] pub extern "C" fn _start() -> ! { let vga_buffer = 0xb8000 as *mut u8; for (i, &byte) in HELLO.iter().enumerate() { unsafe { *vga_buffer.offset(i as isize * 2) = byte; *vga_buffer.offset(i as isize * 2 + 1) = 0xb; } } loop {} } /// This function is called on panic. #[panic_handler] fn panic(_info: &PanicInfo) -> ! { loop {} } ``` -------------------------------- ### Install Fish Shell and Basic Tools in Termux Source: https://os.phil-opp.com/edition-2/extra/building-on-android Installs the fish shell and essential command-line utilities like wget and tar within Termux. Fish is set as the default shell. ```bash pkg install fish chsh -s fish fish ``` ```bash pkg install wget tar ``` -------------------------------- ### Run QEMU in headless mode Source: https://os.phil-opp.com/integration-tests Launch QEMU without a graphical display for automated environments. ```bash qemu-system-x86_64 \ -drive format=raw,file=target/x86_64-blog_os/debug/bootimage-blog_os.bin \ -serial mon:stdio \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -display none ``` ```bash bootimage run -- \ -serial mon:stdio \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ -display none ``` -------------------------------- ### Rust: Assertion Failure in Page Table Setup (Alternative) Source: https://os.phil-opp.com/paging-implementation This panic message, similar to the previous one, points to a physical address assertion failure within the page table setup. It is resolved by configuring the bootloader's physical memory offset. ```rust panicked at 'assertion failed: max_phys_addr < (1 << 48) / 512'. src/main.rs:294:13 ``` -------------------------------- ### Observe Panic Output Source: https://os.phil-opp.com/integration-tests Example output when a panic occurs during test execution. ```text failed panicked at 'explicit panic', src/bin/test-basic-boot.rs:19:5 ``` -------------------------------- ### Execute Integration Test via Bootimage Source: https://os.phil-opp.com/integration-tests Command to run a specific integration test binary with QEMU serial and debug exit configuration. ```bash > bootimage run --bin test-basic-boot -- \ -serial mon:stdio -display none \ -device isa-debug-exit,iobase=0xf4,iosize=0x04 Building kernel Compiling blog_os v0.2.0 (file:///…/blog_os) Finished dev [unoptimized + debuginfo] target(s) in 0.19s Updating registry `https://github.com/rust-lang/crates.io-index` Creating disk image at target/x86_64-blog_os/debug/bootimage-test-basic-boot.bin warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5] ok ``` -------------------------------- ### View Test Output Source: https://os.phil-opp.com/testing Example of the console output when running tests with serial redirection enabled. ```text > cargo test Finished dev [unoptimized + debuginfo] target(s) in 0.02s Running target/x86_64-blog_os/debug/deps/blog_os-7b7c37b4ad62551a Building bootloader Finished release [optimized + debuginfo] target(s) in 0.02s Running: `qemu-system-x86_64 -drive format=raw,file=/…/target/x86_64-blog_os/debug/ deps/bootimage-blog_os-7b7c37b4ad62551a.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -serial stdio` Running 1 tests trivial assertion... [ok] ``` -------------------------------- ### Configure Bootimage Test Arguments Source: https://os.phil-opp.com/testing Sets QEMU arguments and test timeouts in Cargo metadata for bare-metal testing. ```toml [package.metadata.bootimage] test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04","-serial", "stdio","-display","none"] test-success-exit-code = 33 test-timeout = 120 ``` -------------------------------- ### Main Binary Using Library Code Source: https://os.phil-opp.com/integration-tests The `main.rs` file now serves as the entry point, calling functions and using modules defined in the `src/lib.rs` library. ```Rust // src/main.rs #![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_main)] #![cfg_attr(test, allow(unused_imports))] use core::panic::PanicInfo; use blog_os::println; /// This function is the entry point, since the linker looks for a function /// named `_start` by default. #[cfg(not(test))] #[no_mangle] // don't mangle the name of this function pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); loop {} } /// This function is called on panic. #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); loop {} } ``` -------------------------------- ### Initialize State Machine Source: https://os.phil-opp.com/async-await The generated function that initializes the state machine in the Start state without executing it. ```rust fn example(min_len: usize) -> ExampleStateMachine { ExampleStateMachine::Start(StartState { min_len, }) } ``` -------------------------------- ### Configure Binutils Source: https://os.phil-opp.com/cross-compile-binutils Run the configure script with specific flags for the x86_64-elf target. Replace X with the specific version number. ```bash ../binutils-2.X/configure --target=x86_64-elf --prefix="$HOME/opt/cross" \ --disable-nls --disable-werror \ --disable-gdb --disable-libdecnumber --disable-readline --disable-sim ``` -------------------------------- ### Print to VGA buffer from _start function Source: https://os.phil-opp.com/vga-text-mode Demonstrates printing strings and formatted output directly to the VGA buffer from the _start function using the locked WRITER. Requires importing the core::fmt::Write trait. ```rust use core::fmt::Write; vga_buffer::WRITER.lock().write_str("Hello again").unwrap(); write!(vga_buffer::WRITER.lock(), ", some numbers: {} {}", 42, 1.337).unwrap(); ``` -------------------------------- ### Execute Cargo Test Command Source: https://os.phil-opp.com/testing Example of running the custom cargo xtest command in a terminal environment. ```bash lws@lsw:/document/project/flandre-os/FlandreOS$ cargo xtest test_default_writer Compiling flandre_os v0.0.1 (/document/project/flandre-os/FlandreOS) Finished dev [unoptimized + debuginfo] target(s) in 0.33s Running target/x86_64-flandre_os/debug/deps/flandre_os-d120248f92b70111 Building bootloader Compiling bootloader v0.6.0 (/work/tool/rust/cargo/registry/src/mirrors.ustc.edu.cn-61ef6e0cd06fb9b8/bootloader-0.6.0) Finished release [optimized + debuginfo] target(s) in 0.72s Running: `qemu-system-x86_64 -drive format=raw,file=/document/project/flandre-os/FlandreOS/target/x86_64-flandre_os/debug/deps/bootimage-flandre_os-d120248f92b70111.bin -device isa-debug-exit,iobase=0xf4,iosize=0x04 -serial stdio -display none test_default_writer` qemu-system-x86_64: -display none: drive with bus=0, unit=0 (index=0) exists error: test failed, to rerun pass '--lib' ``` -------------------------------- ### Configure QEMU for Serial Output Source: https://os.phil-opp.com/testing Update bootimage configuration to redirect serial output to the host's standard output. ```toml # in Cargo.toml [package.metadata.bootimage] test-args = [ "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio" ] ``` -------------------------------- ### Add Binutils to PATH Source: https://os.phil-opp.com/cross-compile-binutils Update the system PATH environment variable to include the newly installed cross-compilation tools. ```bash export PATH="$HOME/opt/cross/bin:$PATH" ``` -------------------------------- ### Invalid reference after scope Source: https://os.phil-opp.com/heap-allocation An example of code that attempts to hold a reference to heap-allocated memory after the owner has gone out of scope. ```rust let x = { let z = Box::new([1,2,3]); &z[1] }; // z goes out of scope and `deallocate` is called println!("{}", x); ``` -------------------------------- ### Page Table Address Output Source: https://os.phil-opp.com/paging-introduction Example output showing the physical address of the level 4 page table. ```text Level 4 page table at: PhysAddr(0x1000) ``` -------------------------------- ### Linker Error Output Source: https://os.phil-opp.com/unit-testing Verbose linker error output resulting from multiple definitions of _start and undefined references to main. ```text error: linking with `cc` failed: exit code: 1 | = note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/…/lib/rustlib/x86_64-unknown-linux-gnu/lib" […] = note: /…/blog_os-969bdb90d27730ed.2q644ojj2xqxddld.rcgu.o: In function `_start': /…/blog_os/src/main.rs:17: multiple definition of `_start' /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/Scrt1.o:(.text+0x0): first defined here /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/Scrt1.o: In function `_start': (.text+0x20): undefined reference to `main' collect2: error: ld returned 1 exit status ``` -------------------------------- ### View cargo test output Source: https://os.phil-opp.com/testing Example output showing cargo test failing due to the unexpected exit code. ```text > cargo test Finished dev [unoptimized + debuginfo] target(s) in 0.03s Running target/x86_64-blog_os/debug/deps/blog_os-5804fc7d2dd4c9be Building bootloader Compiling bootloader v0.5.3 (/home/philipp/Documents/bootloader) Finished release [optimized + debuginfo] target(s) in 1.07s Running: `qemu-system-x86_64 -drive format=raw,file=/…/target/x86_64-blog_os/debug/ deps/bootimage-blog_os-5804fc7d2dd4c9be.bin -device isa-debug-exit,iobase=0xf4, iosize=0x04` error: test failed, to rerun pass '--bin blog_os' ``` -------------------------------- ### Implement _start function for stack overflow test Source: https://os.phil-opp.com/double-fault-exceptions Defines the entry point for the stack overflow integration test, including GDT initialization and a recursive function to trigger the overflow. ```rust // in tests/stack_overflow.rs use blog_os::serial_print; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { serial_print!("stack_overflow::stack_overflow...\t"); blog_os::gdt::init(); init_test_idt(); // trigger a stack overflow stack_overflow(); panic!("Execution continued after stack overflow"); } #[allow(unconditional_recursion)] fn stack_overflow() { stack_overflow(); // for each recursion, the return address is pushed volatile::Volatile::new(0).read(); // prevent tail recursion optimizations } ``` -------------------------------- ### Provoking a Deadlock in Main Source: https://os.phil-opp.com/hardware-interrupts Example of code that triggers a deadlock by printing in a loop, causing the system to hang when an interrupt occurs. ```rust // in src/main.rs #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { […] loop { use blog_os::print; print!("-"); // new } } ``` -------------------------------- ### Linux Kernel SIMD Configuration Source: https://os.phil-opp.com/disable-simd Example configuration settings for enabling or disabling SIMD-related cryptographic modules in the Linux kernel. ```text CONFIG_CRYPTO_SIMD=y # CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set # CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set CONFIG_CRYPTO_SHA1_SSSE3=y CONFIG_CRYPTO_SHA256_SSSE3=y CONFIG_CRYPTO_SHA512_SSSE3=y ``` -------------------------------- ### Run Additional Test Executable Source: https://os.phil-opp.com/integration-tests Use the `bootimage run --bin` command to build and launch a specific executable from `src/bin`. ```Shell bootimage run --bin test-something ``` -------------------------------- ### Define Self-Referential Async Function Source: https://os.phil-opp.com/async-await An example of an async function that creates a reference to a local variable, resulting in a self-referential state machine. ```rust async fn pin_example() -> i32 { let array = [1, 2, 3]; let element = &array[2]; async_write_file("foo.txt", element.to_string()).await; *element } ``` -------------------------------- ### Const function compilation error Source: https://os.phil-opp.com/vga-text-mode An example of a compiler error occurring when using const fn without the required feature flag. ```text error[E0658]: const fn is unstable (see issue #24111) --> src/vga_buffer.rs:33:5 | 33 | / const fn new(foreground: Color, background: Color) -> ColorCode { 34 | | ColorCode((background as u8) << 4 | (foreground as u8)) 35 | | } | |_____^ | = help: add #![feature(const_fn)] to the crate attributes to enable ``` -------------------------------- ### Specify Subsystem and Entry Point on Windows Source: https://os.phil-opp.com/freestanding-rust-binary Use `cargo rustc` with `-C link-args="/ENTRY:_start /SUBSYSTEM:console"` to explicitly define the entry point and subsystem, resolving linker errors on Windows when the subsystem cannot be inferred. ```bash cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console" ``` -------------------------------- ### Define Custom Entry Point `_start` Source: https://os.phil-opp.com/freestanding-rust-binary Define a custom C-compatible entry point function `_start` that does not return. Use `#[unsafe(no_mangle)]` to prevent name mangling and `extern "C"` for the C calling convention. ```rust #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { loop {} } ``` -------------------------------- ### Define Heap Constants Source: https://os.phil-opp.com/heap-allocation Defines the starting virtual address and size for the kernel heap. Ensure the chosen address range is not already in use. ```rust // in src/allocator.rs pub const HEAP_START: usize = 0x_4444_4444_0000; pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB ``` -------------------------------- ### Initialize Heap in Kernel Source: https://os.phil-opp.com/heap-allocation This code initializes the heap in the kernel. It uses `allocator::init_heap` and panics if initialization fails, as there's no sensible error handling for this in the current context. Ensure the `blog_os::allocator` module is imported. ```rust use blog_os::allocator; fn main() { // Initialize the heap allocator::init_heap().expect("heap initialization failed"); let x = Box::new(41); // [...] call `test_main` in test mode println!("It did not crash!"); blog_os::hlt_loop(); } ``` -------------------------------- ### Invalid Reference Return Example Source: https://os.phil-opp.com/heap-allocation Demonstrates a compiler error caused by attempting to return a reference to a local variable that does not outlive the function scope. ```rust fn inner(i: usize) -> &'static u32 { let z = [1, 2, 3]; &z[i] } ``` -------------------------------- ### Add `bootloader` dependency Source: https://os.phil-opp.com/minimal-rust-kernel Add the `bootloader` crate to your `Cargo.toml` file to manage bootloader functionality. This version (0.9) is specifically required for this guide. ```toml [dependencies] bootloader = "0.9" ``` -------------------------------- ### Call exit_qemu in _start Source: https://os.phil-opp.com/integration-tests Invoke the shutdown function from the kernel entry point after completing tasks. ```rust #[cfg(not(test))] #[no_mangle] pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); // prints to vga buffer serial_println!("Hello Host{}", "!"); unsafe { exit_qemu(); } loop {} } ``` -------------------------------- ### Run All Integration Tests Source: https://os.phil-opp.com/integration-tests Command to execute all tests following the test- prefix convention using the bootimage test runner. ```bash > bootimage test test-panic Finished dev [unoptimized + debuginfo] target(s) in 0.01s Ok test-basic-boot Finished dev [unoptimized + debuginfo] target(s) in 0.01s Ok test-something Finished dev [unoptimized + debuginfo] target(s) in 0.01s Timed Out The following tests failed: test-something: TimedOut ``` -------------------------------- ### Implement a custom Future combinator Source: https://os.phil-opp.com/async-await A basic example of a combinator that transforms a Future into a Future by polling an inner future. ```rust struct StringLen { inner_future: F, } impl Future for StringLen where F: Future { type Output = usize; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { match self.inner_future.poll(cx) { Poll::Ready(s) => Poll::Ready(s.len()), Poll::Pending => Poll::Pending, } } } fn string_len(string: impl Future) -> impl Future { StringLen { inner_future: string, } } // Usage fn file_len() -> impl Future { let file_content_future = async_read_file("foo.txt"); string_len(file_content_future) } ``` -------------------------------- ### Observe heap allocation test failure Source: https://os.phil-opp.com/allocator-designs Example output from running the heap allocation test suite, showing the failure of the long-lived allocation test. ```text > cargo test --test heap_allocation Running 4 tests simple_allocation... [ok] large_vec... [ok] many_boxes... [ok] many_boxes_long_lived... [failed] Error: panicked at 'allocation error: Layout { size_: 8, align_: 8 }', src/lib.rs:86:5 ``` -------------------------------- ### Redirect Serial Output to File Source: https://os.phil-opp.com/integration-tests Configure QEMU to redirect serial output to a file using the `-serial file:output-file.txt` argument. ```bash -serial file:output-file.txt ``` -------------------------------- ### Add Bare Metal Target Source: https://os.phil-opp.com/freestanding-rust-binary Use `rustup target add` to install a toolchain for a specific bare metal target, such as `thumbv7em-none-eabihf` for embedded ARM systems. ```bash rustup target add thumbv7em-none-eabihf ```