### Install Fish Shell and Basic Tools Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/extra/building-on-android/index.md Installs the fish shell, sets it as the default, and installs essential tools like wget and tar. Adjust commands for bash if not using fish. ```bash pkg install fish chsh -s fish fish ``` ```bash pkg install wget tar ``` -------------------------------- ### Install Build Tools for ISO Generation Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html On Fedora, install NASM, xorriso, and the QEMU system emulator for x86_64 architecture to build and test the OS. ```bash sudo dnf install nasm xorriso qemu-system-x86 ``` -------------------------------- ### Install Git Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/extra/building-on-android/index.md Installs the Git version control system. ```bash pkg install git ``` -------------------------------- ### Install cargo-xbuild and bootimage Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/extra/building-on-android/index.md Installs the `cargo-xbuild` and `bootimage` Cargo subcommands. ```bash cargo install cargo-xbuild bootimage ``` -------------------------------- ### Basic Library Setup Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/04-testing/index.md Initial setup for a Rust library crate, including the `no_std` attribute. ```rust #![no_std] ``` -------------------------------- ### Build and Install Binutils Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/cross-compile-binutils.md Compiles the configured Binutils source code and installs the resulting binaries to the specified prefix directory. This step can take a significant amount of time. ```bash make make install ``` -------------------------------- ### Start QEMU and GDB for Debugging Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Commands to launch QEMU in debugging mode and attach GDB to the kernel binary for live debugging. ```bash qemu-system-x86_64 -hda build/os-x86_64.iso -s -S ``` ```bash gdb build/kernel-x86_64.bin ``` -------------------------------- ### Install xorriso on Ubuntu Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Install the xorriso package on Ubuntu if it's missing, which is required for creating ISO images. ```bash sudo apt install xorriso ``` -------------------------------- ### Install Cross-Compiler Tools via Homebrew Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Commands to tap and install the necessary cross-compiler toolchains for x86_64-elf using Homebrew. ```bash brew tap sevki/gcc_cross_compilers brew install x86_64-elf-gcc x86_64-elf-binutils ``` ```bash brew tap alexcrichton/formula brew install x86_64-elf-gcc x86_64-elf-binutils ``` -------------------------------- ### GDB Breakpoint Example Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/03-returning-from-exceptions/index.md This example demonstrates setting a breakpoint in GDB to verify that the kernel successfully returns from an `int3` instruction. This confirms the `iretq` mechanism is working. ```text (gdb) break blog_os/src/lib.rs:61 Breakpoint 1 at 0x110a95: file /home/.../blog_os/src/lib.rs, line 61. (gdb) continue Continuing. Breakpoint 1, blog_os::rust_main (multiboot_information_address=1539136) at /home/.../blog_os/src/lib.rs:61 61 println!("It did not crash!"); ``` -------------------------------- ### Define Heap Start and Size Constants Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/10-heap-allocation/index.tr.md Defines the starting virtual address and size for the kernel heap. The heap starts at a specific virtual address and is allocated a fixed size in KiB. ```Rust pub const HEAP_START: usize = 0x_4444_4444_0000; pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB ``` -------------------------------- ### Basic Integration Test Setup Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/04-testing/index.md Sets up a basic integration test executable, including necessary crate attributes and entry point functions. ```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 {} } ``` -------------------------------- ### Get Multiboot Information Start and End Addresses Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/allocating-frames.html Use the `start_address()` and `end_address()` methods from `BootInformation` to retrieve the start and end addresses of the Multiboot information. This is an alternative to manual address calculation. ```Rust let multiboot_start = boot_info.start_address(); let multiboot_end = boot_info.end_address(); ``` -------------------------------- ### Install the bootimage tool Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/02-minimal-rust-kernel/index.md Install the `bootimage` command-line tool globally using Cargo. This tool is used to create bootable disk images from your Rust kernel. ```bash cargo install bootimage ``` -------------------------------- ### Basic Println Macro Example Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/04-printing-to-screen/index.md This example demonstrates a simple `println!` macro usage within a Rust block. It highlights how nested operations within macro arguments can lead to unexpected behavior. ```rust println!( "{}", { println!( "inner" ); "outer" } ); ``` -------------------------------- ### Install grub-pc-bin on Ubuntu Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Install the grub-pc-bin package on Ubuntu to resolve 'Could not read from CDROM (code 0009)' errors when booting ISOs. ```bash sudo apt install grub-pc-bin ``` -------------------------------- ### Install xargo Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/cross-compile-libcore.md Install the xargo tool, a wrapper for cargo that simplifies cross-compilation by automatically building the core library for custom targets. Ensure cmake and OpenSSL headers are installed if the installation fails. ```bash cargo install xargo ``` -------------------------------- ### Hello World using Custom println! Macro Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/03-vga-text-buffer/index.md Example of using the custom `println!` macro in the `_start` function to print "Hello World!". The macro is available in the root namespace. ```rust // in src/main.rs #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); loop {} } ``` -------------------------------- ### Frame Start Address Implementation Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/06-page-tables/index.md Provides the start_address method for the Frame struct, calculating the physical start address based on the frame's number and PAGE_SIZE. Assumes PAGE_SIZE is defined elsewhere. ```Rust use self::paging::PhysicalAddress; fn start_address(&self) -> PhysicalAddress { self.number * PAGE_SIZE } ``` -------------------------------- ### Start State Transition Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/12-async-await/index.md Handles the initial state of the state machine. It executes code until the first `.await` and transitions 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 Rust Nightly and Cargo Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/extra/building-on-android/index.md Installs the nightly version of Rust compiler and Cargo package manager. ```bash pkg install rustc cargo rustc-nightly ``` -------------------------------- ### Kernel Main Function with Executor Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/12-async-await/index.md Demonstrates setting up and running a `SimpleExecutor` within the kernel's main function. It spawns an example task and executes it. ```rust use blog_os::task::{Task, simple_executor::SimpleExecutor}; fn kernel_main(boot_info: &'static BootInfo) -> ! { // […] initialization routines, including `init_heap` let mut executor = SimpleExecutor::new(); executor.spawn(Task::new(example_task())); executor.run(); // […] test_main, "it did not crash" message, hlt_loop } ``` -------------------------------- ### Installing x86_64-elf Cross-Compiler on macOS Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html This command shows how to install the necessary x86_64-elf cross-compiler toolchain on macOS using MacPorts, which is required for building the kernel. ```shell sudo port install x86_64-elf-gcc ``` -------------------------------- ### Loading the GDT in Assembly Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/02-entering-longmode/index.md Demonstrates how to load the 64-bit GDT using the `lgdt` instruction within an assembly `start` function after enabling paging. ```nasm start: ... call enable_paging ; load the 64-bit GDT lgdt [gdt64.pointer] ; print `OK` to screen ... ``` -------------------------------- ### Calling Paging and Long Mode Functions in Start Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/02-entering-longmode/index.md This snippet shows how to integrate the new paging and long mode enabling functions into the main `start` routine of the OS. It calls `set_up_page_tables` and `enable_paging` before proceeding. ```nasm start: mov esp, stack_top call check_multiboot call check_cpuid call check_long_mode call set_up_page_tables ; new call enable_paging ; new ; print `OK` to screen mov dword [0xb8000], 0x2f4b2f4f hlt ``` -------------------------------- ### Write to VGA buffer from _start function Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/03-vga-text-buffer/index.md Import the `core::fmt::Write` trait to enable writing strings and formatted output to the VGA buffer via the synchronized `WRITER`. This example demonstrates writing a string and formatted numbers. ```rust use core::fmt::Write; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { use core::fmt::Write; vga_buffer::WRITER.lock().write_str("Hello again").unwrap(); write!(vga_buffer::WRITER.lock(), ", some numbers: {} {}", 42, 1.337).unwrap(); loop {} } ``` -------------------------------- ### Accessing Build Information in Kernel Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/printing-to-screen.html This example demonstrates how to expose build number and date from the build process into the kernel. It involves modifying the Makefile to define symbols and then accessing these symbols in Rust code. ```Makefile BUILD_NUMBER_FILE := buildno.txt BUILD_NUMBER_LDFLAGS = --defsym _BUILD_NUMBER=$(shell cat $(BUILD_NUMBER_FILE)) --defsym _BUILD_DATE=$(shell date +'%Y%m%d') $(kernel): builddata cargo $(kernel) builddata: touch $(BUILD_NUMBER_FILE) @echo $$(($$(cat $(BUILD_NUMBER_FILE)) + 1)) > $(BUILD_NUMBER_FILE) ``` ```Rust extern { fn _BUILD_NUMBER(); fn _BUILD_DATE(); } // In rust_main or elsewhere: let build_number = _BUILD_NUMBER as u32; let build_date = _BUILD_DATE as u32; println!("Build {}: {} ", build_number, build_date); ``` -------------------------------- ### Create Example Memory Mapping Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/09-paging-implementation/index.md Maps a given virtual page to the physical frame `0xb8000` (VGA text buffer). Requires a mutable mapper and frame allocator. The `map_to` function is unsafe and requires careful usage. ```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(); } ``` -------------------------------- ### Configure Binutils for x86_64-elf Target Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/cross-compile-binutils.md Configures the Binutils build for the x86_64-elf target. It specifies the installation prefix, disables native language support and Werror, and removes unneeded features to reduce build time. ```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 ``` -------------------------------- ### Boot ISO Image with QEMU Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/01-multiboot-kernel/index.md Launches the QEMU emulator to boot from the created ISO image, allowing testing of the kernel. ```bash qemu-system-x86_64 -cdrom os.iso ``` -------------------------------- ### Get Start Address of a Page Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/06-page-tables/index.md Calculates the starting physical address for a given `Page`. This is the inverse operation of `containing_address`. ```Rust fn start_address(&self) -> usize { self.number * PAGE_SIZE } ``` -------------------------------- ### Boot the disk image in QEMU Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/02-minimal-rust-kernel/index.md Launch the created bootable disk image using QEMU for testing. The `format=raw` option is important for raw disk images. ```bash > qemu-system-x86_64 -drive format=raw,file=target/x86_64-blog_os/debug/bootimage-blog_os.bin ``` -------------------------------- ### Rust: Define Custom Entry Point `_start` Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/01-freestanding-rust-binary/index.md Implement the `_start` function as the entry point for the freestanding binary. Use `#[no_mangle]` and `extern "C"` to ensure correct linkage and calling convention. The function must diverge. ```rust #[no_mangle] pub extern "C" fn _start() -> ! { loop {} } ``` -------------------------------- ### Main Function with println! Usage Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/04-printing-to-screen/index.md The entry point of the OS, demonstrating how to import and use the custom `println!` macro to clear the screen and print a "Hello World!" message. ```rust // in src/lib.rs #[macro_use] mod vga_buffer; #[no_mangle] pub extern fn rust_main() { // ATTENTION: we have a very small stack and no guard page vga_buffer::clear_screen(); println!("Hello World{}", "!"); loop{} } ``` -------------------------------- ### Specify Entry Point on Windows Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/01-freestanding-rust-binary/index.md Use this command to tell the Windows linker to look for the `_start` function as the entry point, overriding the default. ```bash cargo rustc -- -C link-arg=/ENTRY:_start ``` -------------------------------- ### Run QEMU with SDL Video Output Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Standard command to run QEMU with an ISO image. May fail on systems without a detected video device. ```bash qemu-system-x86_64 -cdrom os-x86_64.iso ``` -------------------------------- ### Calculating Kernel Start and End Addresses Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/05-allocating-frames/index.md Determines the start and end memory addresses of the loaded kernel by finding the minimum and maximum addresses of its ELF sections. ```rust let kernel_start = elf_sections_tag.sections().map(|s| s.addr) .min().unwrap(); let kernel_end = elf_sections_tag.sections().map(|s| s.addr + s.size) .max().unwrap(); ``` -------------------------------- ### Run QEMU with Console Output Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html Alternative QEMU command using the -curses option to force console output, useful when SDL video initialization fails. ```bash qemu-system-x86_64 -curses -cdrom os-x86_64.iso ``` -------------------------------- ### Booting an ISO with `dd` Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/multiboot-kernel.html This command is used to write an ISO image to a USB drive. Ensure you select the correct device name for your USB stick to avoid data loss. ```bash sudo dd if=build/os.iso of=/dev/sdX && sync ``` -------------------------------- ### Main Executable Using the Library Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/04-testing/index.md The main executable (`src/main.rs`) configured to use the `blog_os` library for testing and panic handling. ```rust #![no_std] #![no_main] #![feature(custom_test_frameworks)] #![test_runner(blog_os::test_runner)] #![reexport_test_harness_main = "test_main"] use core::panic::PanicInfo; use blog_os::println; #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { println!("Hello World{!}", "!"); #[cfg(test)] test_main(); loop {} } /// This function is called on panic. #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { println!("{}", info); loop {} } #[cfg(test)] #[panic_handler] fn panic(info: &PanicInfo) -> ! { blog_os::test_panic_handler(info) } ``` -------------------------------- ### Global Allocator Attribute Example Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/08-kernel-heap/index.md This example shows how to use the `global_allocator` attribute to designate a static variable as the system's memory allocator. The Alloc trait is implemented for a shared reference to the allocator. ```rust #[global_allocator] static MY_ALLOCATOR: MyAllocator = MyAllocator {...}; impl<'a> Alloc for &'a MyAllocator { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {} unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {} } ``` -------------------------------- ### Get P4 Table References Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/06-page-tables/index.md Provides methods to get immutable and mutable references to the P4 table. These methods use unsafe blocks to dereference the unique pointer, assuming the pointer is valid. ```rust fn p4(&self) -> &Table { unsafe { self.p4.as_ref() } } fn p4_mut(&mut self) -> &mut Table { unsafe { self.p4.as_mut() } } ``` -------------------------------- ### Compiling for Host System with Linker Arguments Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/01-freestanding-rust-binary/index.md These commands demonstrate how to compile a freestanding Rust binary for the host system (Linux and Windows) by providing specific linker arguments. ```bash # Linux ``` ```bash cargo rustc -- -C link-arg=-nostartfiles ``` ```bash # Windows ``` ```bash cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console" ``` -------------------------------- ### Rust Naked Function Example Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/02-better-exception-messages/index.md This example demonstrates the syntax for defining a naked function in Rust using the `#[naked]` attribute and `asm!` macro. Naked functions are unstable and require enabling the `naked_functions` feature. ```rust #![feature(naked_functions)] #[naked] extern "C" fn naked_function_example() { unsafe { asm!("mov rax, 0x42" ::: "rax" : "intel"); }; } ``` -------------------------------- ### Colored "Hello World" with Code Page 437 Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/set-up-rust.html This example shows how to print a "Hello World" message with special characters from Code Page 437, including colored smiley faces. It involves defining a byte array with control characters and color codes. ```rust let hello = b"\x02\x01 Hello World! \x01\x02"; let color_byte = 0x1f; let mut hello_colored = [color_byte; 36]; ``` -------------------------------- ### Example of a stack-allocated IDT causing a triple fault Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/01-catching-exceptions/index.md This example demonstrates a scenario where an IDT is allocated on the stack and loaded. When the function returns, the stack frame is reused, leading to an invalid IDT and a triple fault upon an interrupt. ```rust pub fn init() { load_idt(); cause_page_fault(); } fn load_idt() { let mut idt = idt::Idt::new(); idt.set_handler(14, page_fault_handler); idt.load(); } fn cause_page_fault() { let x = [1,2,3,4,5,6,7,8,9]; unsafe{ *(0xdeadbeaf as *mut u64) = x[4] }; } ``` -------------------------------- ### Custom String Length Future Combinator Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/12-async-await/index.md This example shows a custom combinator `string_len` that converts a `Future` into a `Future`. It polls the inner future and returns the length of the string when ready. Note that this example does not handle pinning. ```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) } ``` -------------------------------- ### Add Rust Source Components Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/03-returning-from-exceptions/index.md Installs the 'rust-src' component using rustup, which is a prerequisite for xargo to cross-compile the core library. ```bash rustup component add rust-src ``` -------------------------------- ### Running QEMU with KVM Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/02-better-exception-messages/index.md Launch QEMU with KVM enabled to reproduce the triple fault bug on a system that supports it. This allows for easier debugging compared to real hardware. ```bash > qemu-system-x86_64 -cdrom build/os-x86_64.iso -enable-kvm ``` -------------------------------- ### Build a bootable disk image Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/02-minimal-rust-kernel/index.md Execute the `cargo bootimage` command in your project directory to compile your kernel and bootloader, then link them into a bootable disk image. ```bash > cargo bootimage ``` -------------------------------- ### Memory Leak Example Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/08-kernel-heap/index.md Demonstrates a memory leak by repeatedly creating strings within a loop, highlighting the need for an effective allocator. ```rust // in rust_main in src/lib.rs for i in 0..10000 { format!("Some String"); } ``` -------------------------------- ### Create Bootable ISO Image Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/01-multiboot-kernel/index.md Uses grub-mkrescue to create a bootable ISO image from the specified directory structure containing the kernel and GRUB configuration. ```bash grub-mkrescue -o os.iso isofiles ``` -------------------------------- ### Build Freestanding Executable on Linux Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/01-freestanding-rust-binary/index.md Use this command to build a freestanding executable on Linux by telling the linker not to include the C startup routine. ```bash cargo rustc -- -C link-arg=-nostartfiles ``` -------------------------------- ### Global Allocator Setup Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/10-heap-allocation/index.tr.md Define a static `LockedHeap` instance to serve as the global allocator for the operating system. This uses a spinlock for thread safety. ```rust use linked_list_allocator::LockedHeap; #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); ``` -------------------------------- ### Create Build Directory for Binutils Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/cross-compile-binutils.md Creates a new directory for building Binutils and changes into it. This isolates the build process from the source code. ```bash mkdir build-binutils cd build-binutils ``` -------------------------------- ### Heap-allocating SelfReferential with Box::pin Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/12-async-await/index.md This example demonstrates creating a Pin> using Box::pin, which is necessary for types that opt out of Unpin. ```rust let mut heap_value = Box::pin(SelfReferential { self_ptr: 0 as *const _, _pin: PhantomPinned, }); ``` -------------------------------- ### Integrate GDT Initialization into System Init Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/06-double-faults/index.md Shows how to call the GDT initialization function from the main system initialization routine. This ensures the GDT is loaded early in the boot process. ```rust pub fn init() { gdt::init(); interrupts::init_idt(); } ``` -------------------------------- ### Example Async Function with Self-Referential Data Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/12-async-await/index.md This async function demonstrates a scenario that can lead to self-referential structs by referencing an element within a local array. ```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 } ``` -------------------------------- ### Original Test Case with Manual Printing Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/04-testing/index.md This is an example of a test case that manually prints its status using `serial_print!` and `serial_println!`. This approach is cumbersome and will be automated. ```rust #[test_case] fn trivial_assertion() { serial_print!("trivial assertion... "); assert_eq!(1, 1); serial_println!("[ok]"); } ``` -------------------------------- ### Aligning Kernel Sections in Linker Script Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/07-remap-the-kernel/index.md Example of a linker script section definition using `ALIGN(4K)` to ensure page alignment. ```linker script SECTIONS { . = 1M; .text : { *(.text .text.*) . = ALIGN(4K); } } ``` -------------------------------- ### Calculating Multiboot Information Structure Address Range Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/05-allocating-frames/index.md Calculates the start and end addresses of the Multiboot Information structure based on its known address and total size. ```rust let multiboot_start = multiboot_information_address; let multiboot_end = multiboot_start + (boot_info.total_size as usize); ``` -------------------------------- ### Basic Heap Usage with Box and Vec Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/08-kernel-heap/index.md Demonstrates the functionality of `Box` and `Vec` after the kernel heap has been successfully initialized. Includes basic operations like dereferencing and element modification. ```rust // in rust_main in src/lib.rs use alloc::boxed::Box; let mut heap_test = Box::new(42); *heap_test -= 15; let heap_test2 = Box::new("hello"); println!("{:?} {:?}", heap_test, heap_test2); let mut vec_test = vec![1,2,3,4,5,6,7]; vec_test[3] = 42; for i in &vec_test { print!("{} ", i); } ``` -------------------------------- ### Initial `handler_with_error_code` Macro Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/extra/naked-exceptions/03-returning-from-exceptions/index.md The initial version of the `handler_with_error_code` macro before modifications for returning from exceptions with error codes. It uses `pop rsi` to get the error code. ```Rust macro_rules! handler_with_error_code { ($name: ident) => {{ #[naked] extern "C" fn wrapper() -> ! { unsafe { asm!("pop rsi // pop error code into rsi mov rdi, rsp sub rsp, 8 // align the stack pointer call $0" :: "i"($name as extern "C" fn( &ExceptionStackFrame, u64)) : "rdi","rsi" : "intel"); asm!("iretq" :::: "intel", "volatile"); ::core::intrinsics::unreachable(); } } wrapper }} } ``` -------------------------------- ### Frame Range Iterator Implementation Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/07-remap-the-kernel/index.md Defines a custom iterator for a range of frames, inclusive of both start and end frames. This is used to iterate over all frames belonging to a kernel section. ```Rust // in src/memory/mod.rs impl Frame { fn range_inclusive(start: Frame, end: Frame) -> FrameIter { FrameIter { start: start, end: end, } } } struct FrameIter { start: Frame, end: Frame, } impl Iterator for FrameIter { type Item = Frame; fn next(&mut self) -> Option { if self.start <= self.end { let frame = self.start.clone(); self.start.number += 1; Some(frame) } else { None } } } ``` -------------------------------- ### Print Available Memory Areas Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/05-allocating-frames/index.md Loads Multiboot information, retrieves the memory map tag, and iterates through available memory areas to print their start address and length. ```rust let boot_info = unsafe{ multiboot2::load(multiboot_information_address) }; let memory_map_tag = boot_info.memory_map_tag() .expect("Memory map tag required"); println!("memory areas:"); for area in memory_map_tag.memory_areas() { println!(" start: 0x{:x}, length: 0x{:x}", area.base_addr, area.length); } ``` -------------------------------- ### QEMU Test Arguments Configuration Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/04-testing/index.md Configures the bootimage tool to pass specific arguments to QEMU during test execution. This includes setting up the ISA debug exit device, redirecting serial output, and disabling the graphical display. ```toml # in Cargo.toml [package.metadata.bootimage] test-args = [ "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio", "-display", "none" ] ``` -------------------------------- ### Makefile Target Without xargo Source: https://github.com/phil-opp/blog_os/blob/main/blog/templates/edition-1/comments/set-up-rust.html This is an alternative Makefile target that works around issues related to the `xargo` command by removing it from the dependencies. This can be useful if `xargo` is not properly installed or configured. ```makefile $(kernel): kernel $(rust_os) $(assembly_object_files) $(linker_script) @ld -n --gc-sections -T $(linker_script) -o $(kernel) \ $(assembly_object_files) $(rust_os) ``` -------------------------------- ### Specify Subsystem and Entry Point on Windows Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-2/posts/01-freestanding-rust-binary/index.md Use this command to explicitly define the subsystem and entry point for Windows executables when the default cannot be inferred. ```bash cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console" ``` -------------------------------- ### Setting the Global Allocator Source: https://github.com/phil-opp/blog_os/blob/main/blog/content/edition-1/posts/08-kernel-heap/index.md Defines constants for heap start and size, and declares a static `BumpAllocator` instance to be used as the system's global allocator. Requires the `global_allocator` feature. ```rust pub const HEAP_START: usize = 0o_000_001_000_000_0000; pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB #[global_allocator] static HEAP_ALLOCATOR: BumpAllocator = BumpAllocator::new(HEAP_START, HEAP_START + HEAP_SIZE); ```