From ae43d587f77740f0b84da554f52a0096457e369f Mon Sep 17 00:00:00 2001 From: shibedrill Date: Mon, 10 Feb 2025 14:14:17 -0500 Subject: [PATCH] It boots! --- .cargo/config.toml | 1 + .envrc | 1 + .gitignore | 1 + README.md | 19 +++++++- build.rs | 8 ++++ build_iso.sh | 29 ++++++++++++ iso/limine.conf => limine.conf | 2 +- linker-scripts/linker-aarch64.ld | 63 ++++++++++++++++++++++++++ linker-scripts/linker-loongarch64.ld | 63 ++++++++++++++++++++++++++ linker-scripts/linker-riscv64.ld | 66 ++++++++++++++++++++++++++++ linker-scripts/linker-x86_64.ld | 63 ++++++++++++++++++++++++++ shell.nix | 27 ++++++++++++ src/boot.rs | 13 +++++- src/display.rs | 3 +- src/main.rs | 15 ++++++- 15 files changed, 368 insertions(+), 6 deletions(-) create mode 100644 .envrc create mode 100644 build.rs mode change 100644 => 100755 build_iso.sh rename iso/limine.conf => limine.conf (54%) create mode 100644 linker-scripts/linker-aarch64.ld create mode 100644 linker-scripts/linker-loongarch64.ld create mode 100644 linker-scripts/linker-riscv64.ld create mode 100644 linker-scripts/linker-x86_64.ld create mode 100644 shell.nix diff --git a/.cargo/config.toml b/.cargo/config.toml index 622eca8..757362c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,3 @@ [build] +rustflags = "-C relocation-model=static" target = "x86_64-unknown-none" \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..65326bb --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix \ No newline at end of file diff --git a/.gitignore b/.gitignore index ea8c4bf..ef27875 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/iso/gila.iso diff --git a/README.md b/README.md index d2481fc..272eaf6 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,21 @@ Licensed under the GNU Public License v3. See [LICENSE](LICENSE) for details. - [process.rs](src/process.rs): Process types and functions. - [resources.rs](src/resources.rs): Resources that are accessible from multiple parts of the code. -## Building and running - TODO +## Building and running -This section is under construction. +To build an ISO image that you can boot, there are several prerequisites: + +- `limine` command installed +- `xorriso` command installed + +Then run the [build_iso.sh](build_iso.sh) script. It will generate `gila.iso`. + +Running the kernel requires qemu. + +You can install all these dependencies automatically by using `nix-shell` and +supplying [shell.nix](shell.nix) as an argument. + +## Credits + +The linker script stuff is from [limine-rust-template](https://github.com/jasondyoungberg/limine-rust-template), +which is available under the BSD 0-Clause License. diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..1cd44f2 --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +fn main() { + + let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + // Tell cargo to pass the linker script to the linker.. + println!("cargo:rustc-link-arg=-Tlinker-scripts/linker-{arch}.ld"); + // ..and to re-run if it changes. + println!("cargo:rerun-if-changed=linker-scripts/linker-{arch}.ld"); +} \ No newline at end of file diff --git a/build_iso.sh b/build_iso.sh old mode 100644 new mode 100755 index e69de29..6cef3dd --- a/build_iso.sh +++ b/build_iso.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "Argument 1 must be the Rust target triple." + exit 1 +fi + +SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit 1 ; pwd -P )" +cd "$SCRIPTPATH" || exit 1 + +rm -rf ./iso/ +rm ./gila.iso +#cargo clean + +mkdir -p ./iso/limine/ +cp ./limine.conf ./iso/ +cp /usr/share/limine/limine-bios.sys ./iso/limine/ +cp /usr/share/limine/limine-bios-cd.bin ./iso/limine/ +cp /usr/share/limine/limine-uefi-cd.bin ./iso/limine/ + +cargo build --target="$1" --release +cp target/"$1"/release/gila ./iso/ + +xorriso -as mkisofs -b limine/limine-bios-cd.bin -no-emul-boot \ + -boot-load-size 4 -boot-info-table --efi-boot \ + limine/limine-uefi-cd.bin -efi-boot-part --efi-boot-image \ + --protective-msdos-label iso -o gila.iso + +limine bios-install gila.iso \ No newline at end of file diff --git a/iso/limine.conf b/limine.conf similarity index 54% rename from iso/limine.conf rename to limine.conf index deea740..87c02e8 100644 --- a/iso/limine.conf +++ b/limine.conf @@ -2,4 +2,4 @@ timeout: 5 /Gila protocol: limine - kernel_path: boot():/gila.bin \ No newline at end of file + kernel_path: boot():/gila \ No newline at end of file diff --git a/linker-scripts/linker-aarch64.ld b/linker-scripts/linker-aarch64.ld new file mode 100644 index 0000000..66a449e --- /dev/null +++ b/linker-scripts/linker-aarch64.ld @@ -0,0 +1,63 @@ +/* Tell the linker that we want an aarch64 ELF64 output file */ +OUTPUT_FORMAT(elf64-littleaarch64) + +/* We want the symbol main to be our entry point */ +ENTRY(main) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + + /* Place the sections that contain the Limine requests as part of the .data */ + /* output section. */ + KEEP(*(.requests_start_marker)) + KEEP(*(.requests)) + KEEP(*(.requests_end_marker)) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} \ No newline at end of file diff --git a/linker-scripts/linker-loongarch64.ld b/linker-scripts/linker-loongarch64.ld new file mode 100644 index 0000000..355f7e4 --- /dev/null +++ b/linker-scripts/linker-loongarch64.ld @@ -0,0 +1,63 @@ +/* Tell the linker that we want a loongarch64 ELF64 output file */ +OUTPUT_FORMAT(elf64-loongarch) + +/* We want the symbol main to be our entry point */ +ENTRY(main) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + + /* Place the sections that contain the Limine requests as part of the .data */ + /* output section. */ + KEEP(*(.requests_start_marker)) + KEEP(*(.requests)) + KEEP(*(.requests_end_marker)) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} \ No newline at end of file diff --git a/linker-scripts/linker-riscv64.ld b/linker-scripts/linker-riscv64.ld new file mode 100644 index 0000000..f15a7d0 --- /dev/null +++ b/linker-scripts/linker-riscv64.ld @@ -0,0 +1,66 @@ +/* Tell the linker that we want a riscv64 ELF64 output file */ +OUTPUT_FORMAT(elf64-littleriscv) + +/* We want the symbol main to be our entry point */ +ENTRY(main) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + + /* Place the sections that contain the Limine requests as part of the .data */ + /* output section. */ + KEEP(*(.requests_start_marker)) + KEEP(*(.requests)) + KEEP(*(.requests_end_marker)) + + *(.sdata .sdata.*) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.sbss .sbss.*) + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} \ No newline at end of file diff --git a/linker-scripts/linker-x86_64.ld b/linker-scripts/linker-x86_64.ld new file mode 100644 index 0000000..73a66d0 --- /dev/null +++ b/linker-scripts/linker-x86_64.ld @@ -0,0 +1,63 @@ +/* Tell the linker that we want an x86_64 ELF64 output file */ +OUTPUT_FORMAT(elf64-x86-64) + +/* We want the symbol main to be our entry point */ +ENTRY(main) + +/* Define the program headers we want so the bootloader gives us the right */ +/* MMU permissions; this also allows us to exert more control over the linking */ +/* process. */ +PHDRS +{ + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ + /* and because that is what the Limine spec mandates. */ + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ + /* that is the beginning of the region. */ + . = 0xffffffff80000000; + + .text : { + *(.text .text.*) + } :text + + /* Move to the next memory page for .rodata */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .rodata : { + *(.rodata .rodata.*) + } :rodata + + /* Move to the next memory page for .data */ + . = ALIGN(CONSTANT(MAXPAGESIZE)); + + .data : { + *(.data .data.*) + + /* Place the sections that contain the Limine requests as part of the .data */ + /* output section. */ + KEEP(*(.requests_start_marker)) + KEEP(*(.requests)) + KEEP(*(.requests_end_marker)) + } :data + + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ + /* unnecessary zeros will be written to the binary. */ + /* If you need, for example, .init_array and .fini_array, those should be placed */ + /* above this. */ + .bss : { + *(.bss .bss.*) + *(COMMON) + } :data + + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } +} \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..858fed4 --- /dev/null +++ b/shell.nix @@ -0,0 +1,27 @@ +let + + nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05"; + + pkgs = import nixpkgs { config = {}; overlays = []; }; + +in + + +pkgs.mkShell { + + packages = with pkgs; [ + + bash + limine + xorriso + rustup + qemu + + ]; + + shellHook = '' + rustup default stable; + rustup target add x86_64-unknown-none + ''; + +} \ No newline at end of file diff --git a/src/boot.rs b/src/boot.rs index 1453c3a..4def5f8 100644 --- a/src/boot.rs +++ b/src/boot.rs @@ -1,6 +1,17 @@ #![allow(dead_code)] -use limine::{request::SmpRequest, BaseRevision}; +use limine::{request::*, BaseRevision}; +#[used] +#[unsafe(link_section = ".requests_start_marker")] +static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); +#[used] +#[unsafe(link_section = ".requests_end_marker")] +static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); + +#[used] +#[unsafe(link_section = ".requests")] pub static BASE_REVISION: BaseRevision = limine::BaseRevision::new(); +#[used] +#[unsafe(link_section = ".requests")] pub static SMP_REQUEST: SmpRequest = limine::request::SmpRequest::new(); \ No newline at end of file diff --git a/src/display.rs b/src/display.rs index d9d3d7b..1603c11 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,8 +1,9 @@ +#![allow(dead_code)] use vga; pub use vga::writers::TextWriter; -struct TextDisplay { +pub struct TextDisplay { writer: vga::writers::Text80x25, column: usize, row: usize, diff --git a/src/main.rs b/src/main.rs index 91f9338..2c54976 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,6 +5,8 @@ #![allow(dead_code)] #![allow(unused_imports)] +use core::arch::asm; + use gila::boot::*; use gila::process; use gila::memory; @@ -13,10 +15,21 @@ use gila::boot; use gila::display::{self, TextWriter}; #[unsafe(no_mangle)] -pub extern "C" fn main() { +unsafe extern "C" fn main() -> !{ assert!(BASE_REVISION.is_supported()); let _smp_response = SMP_REQUEST.get_response(); + loop { + unsafe { + #[cfg(target_arch = "x86_64")] + asm!("hlt"); + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + asm!("wfi"); + #[cfg(target_arch = "loongarch64")] + asm!("idle 0"); + } + } + }