A repository for a long-term OS project titled DasOS (named after the Greek for "forest")

Adding limine rust template

+731 -53
+4 -53
.gitignore
··· 1 - # Created by https://www.toptal.com/developers/gitignore/api/rust 2 - # Edit at https://www.toptal.com/developers/gitignore?templates=rust 3 - 4 - ### Rust ### 5 - # Generated by Cargo 6 - # will have compiled files and executables 7 - debug/ 8 - target/ 9 - 10 - # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 11 - # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 12 - Cargo.lock 13 - 14 - # These are backup files generated by rustfmt 15 - **/*.rs.bk 16 - 17 - # MSVC Windows builds of rustc generate these, which store debugging information 18 - *.pdb 19 - 20 - # End of https://www.toptal.com/developers/gitignore/api/rust 21 - 22 - 23 - # Added by cargo 24 - 25 - /target 26 - 27 - 28 - # Added by cargo 29 - # 30 - # already existing elements were commented out 31 - 32 - #/target 33 - 34 - 35 - # Added by cargo 36 - # 37 - # already existing elements were commented out 38 - 39 - #/target 40 - 41 - 42 - # Added by cargo 43 - # 44 - # already existing elements were commented out 45 - 46 - #/target 47 - 48 - 49 - # Added by cargo 50 - # 51 - # already existing elements were commented out 52 - 53 - #/target 1 + /limine 2 + /ovmf 3 + *.iso 4 + *.hdd
+251
GNUmakefile
··· 1 + # Nuke built-in rules and variables. 2 + MAKEFLAGS += -rR 3 + .SUFFIXES: 4 + 5 + # Convenience macro to reliably declare user overridable variables. 6 + override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2))) 7 + 8 + # Target architecture to build for. Default to x86_64. 9 + $(call USER_VARIABLE,KARCH,x86_64) 10 + 11 + # Default user QEMU flags. These are appended to the QEMU command calls. 12 + $(call USER_VARIABLE,QEMUFLAGS,-m 2G) 13 + 14 + override IMAGE_NAME := template-$(KARCH) 15 + 16 + .PHONY: all 17 + all: $(IMAGE_NAME).iso 18 + 19 + .PHONY: all-hdd 20 + all-hdd: $(IMAGE_NAME).hdd 21 + 22 + .PHONY: run 23 + run: run-$(KARCH) 24 + 25 + .PHONY: run-hdd 26 + run-hdd: run-hdd-$(KARCH) 27 + 28 + .PHONY: run-x86_64 29 + run-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso 30 + qemu-system-$(KARCH) \ 31 + -M q35 \ 32 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 33 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 34 + -cdrom $(IMAGE_NAME).iso \ 35 + $(QEMUFLAGS) 36 + 37 + .PHONY: run-hdd-x86_64 38 + run-hdd-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd 39 + qemu-system-$(KARCH) \ 40 + -M q35 \ 41 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 42 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 43 + -hda $(IMAGE_NAME).hdd \ 44 + $(QEMUFLAGS) 45 + 46 + .PHONY: run-aarch64 47 + run-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso 48 + qemu-system-$(KARCH) \ 49 + -M virt \ 50 + -cpu cortex-a72 \ 51 + -device ramfb \ 52 + -device qemu-xhci \ 53 + -device usb-kbd \ 54 + -device usb-mouse \ 55 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 56 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 57 + -cdrom $(IMAGE_NAME).iso \ 58 + $(QEMUFLAGS) 59 + 60 + .PHONY: run-hdd-aarch64 61 + run-hdd-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd 62 + qemu-system-$(KARCH) \ 63 + -M virt \ 64 + -cpu cortex-a72 \ 65 + -device ramfb \ 66 + -device qemu-xhci \ 67 + -device usb-kbd \ 68 + -device usb-mouse \ 69 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 70 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 71 + -hda $(IMAGE_NAME).hdd \ 72 + $(QEMUFLAGS) 73 + 74 + .PHONY: run-riscv64 75 + run-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso 76 + qemu-system-$(KARCH) \ 77 + -M virt \ 78 + -cpu rv64 \ 79 + -device ramfb \ 80 + -device qemu-xhci \ 81 + -device usb-kbd \ 82 + -device usb-mouse \ 83 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 84 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 85 + -cdrom $(IMAGE_NAME).iso \ 86 + $(QEMUFLAGS) 87 + 88 + .PHONY: run-hdd-riscv64 89 + run-hdd-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd 90 + qemu-system-$(KARCH) \ 91 + -M virt \ 92 + -cpu rv64 \ 93 + -device ramfb \ 94 + -device qemu-xhci \ 95 + -device usb-kbd \ 96 + -device usb-mouse \ 97 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 98 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 99 + -hda $(IMAGE_NAME).hdd \ 100 + $(QEMUFLAGS) 101 + 102 + .PHONY: run-loongarch64 103 + run-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso 104 + qemu-system-$(KARCH) \ 105 + -M virt \ 106 + -cpu la464 \ 107 + -device ramfb \ 108 + -device qemu-xhci \ 109 + -device usb-kbd \ 110 + -device usb-mouse \ 111 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 112 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 113 + -cdrom $(IMAGE_NAME).iso \ 114 + $(QEMUFLAGS) 115 + 116 + .PHONY: run-hdd-loongarch64 117 + run-hdd-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd 118 + qemu-system-$(KARCH) \ 119 + -M virt \ 120 + -cpu la464 \ 121 + -device ramfb \ 122 + -device qemu-xhci \ 123 + -device usb-kbd \ 124 + -device usb-mouse \ 125 + -drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \ 126 + -drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \ 127 + -hda $(IMAGE_NAME).hdd \ 128 + $(QEMUFLAGS) 129 + 130 + 131 + .PHONY: run-bios 132 + run-bios: $(IMAGE_NAME).iso 133 + qemu-system-$(KARCH) \ 134 + -M q35 \ 135 + -cdrom $(IMAGE_NAME).iso \ 136 + -boot d \ 137 + $(QEMUFLAGS) 138 + 139 + .PHONY: run-hdd-bios 140 + run-hdd-bios: $(IMAGE_NAME).hdd 141 + qemu-system-$(KARCH) \ 142 + -M q35 \ 143 + -hda $(IMAGE_NAME).hdd \ 144 + $(QEMUFLAGS) 145 + 146 + ovmf/ovmf-code-$(KARCH).fd: 147 + mkdir -p ovmf 148 + curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-code-$(KARCH).fd 149 + case "$(KARCH)" in \ 150 + aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \ 151 + loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \ 152 + riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \ 153 + esac 154 + 155 + ovmf/ovmf-vars-$(KARCH).fd: 156 + mkdir -p ovmf 157 + curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-vars-$(KARCH).fd 158 + case "$(KARCH)" in \ 159 + aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \ 160 + loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \ 161 + riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \ 162 + esac 163 + 164 + limine/limine: 165 + rm -rf limine 166 + git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 167 + $(MAKE) -C limine 168 + 169 + .PHONY: kernel 170 + kernel: 171 + $(MAKE) -C kernel 172 + 173 + $(IMAGE_NAME).iso: limine/limine kernel 174 + rm -rf iso_root 175 + mkdir -p iso_root/boot 176 + cp -v kernel/kernel iso_root/boot/ 177 + mkdir -p iso_root/boot/limine 178 + cp -v limine.conf iso_root/boot/limine/ 179 + mkdir -p iso_root/EFI/BOOT 180 + ifeq ($(KARCH),x86_64) 181 + cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/ 182 + cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/ 183 + cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT/ 184 + xorriso -as mkisofs -b boot/limine/limine-bios-cd.bin \ 185 + -no-emul-boot -boot-load-size 4 -boot-info-table \ 186 + --efi-boot boot/limine/limine-uefi-cd.bin \ 187 + -efi-boot-part --efi-boot-image --protective-msdos-label \ 188 + iso_root -o $(IMAGE_NAME).iso 189 + ./limine/limine bios-install $(IMAGE_NAME).iso 190 + endif 191 + ifeq ($(KARCH),aarch64) 192 + cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/ 193 + cp -v limine/BOOTAA64.EFI iso_root/EFI/BOOT/ 194 + xorriso -as mkisofs \ 195 + --efi-boot boot/limine/limine-uefi-cd.bin \ 196 + -efi-boot-part --efi-boot-image --protective-msdos-label \ 197 + iso_root -o $(IMAGE_NAME).iso 198 + endif 199 + ifeq ($(KARCH),riscv64) 200 + cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/ 201 + cp -v limine/BOOTRISCV64.EFI iso_root/EFI/BOOT/ 202 + xorriso -as mkisofs \ 203 + --efi-boot boot/limine/limine-uefi-cd.bin \ 204 + -efi-boot-part --efi-boot-image --protective-msdos-label \ 205 + iso_root -o $(IMAGE_NAME).iso 206 + endif 207 + ifeq ($(KARCH),loongarch64) 208 + cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/ 209 + cp -v limine/BOOTLOONGARCH64.EFI iso_root/EFI/BOOT/ 210 + xorriso -as mkisofs \ 211 + --efi-boot boot/limine/limine-uefi-cd.bin \ 212 + -efi-boot-part --efi-boot-image --protective-msdos-label \ 213 + iso_root -o $(IMAGE_NAME).iso 214 + endif 215 + rm -rf iso_root 216 + 217 + $(IMAGE_NAME).hdd: limine/limine kernel 218 + rm -f $(IMAGE_NAME).hdd 219 + dd if=/dev/zero bs=1M count=0 seek=64 of=$(IMAGE_NAME).hdd 220 + sgdisk $(IMAGE_NAME).hdd -n 1:2048 -t 1:ef00 221 + ifeq ($(KARCH),x86_64) 222 + ./limine/limine bios-install $(IMAGE_NAME).hdd 223 + endif 224 + mformat -i $(IMAGE_NAME).hdd@@1M 225 + mmd -i $(IMAGE_NAME).hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine 226 + mcopy -i $(IMAGE_NAME).hdd@@1M kernel/bin-$(KARCH)/kernel ::/boot 227 + mcopy -i $(IMAGE_NAME).hdd@@1M limine.conf ::/boot/limine 228 + ifeq ($(KARCH),x86_64) 229 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/limine-bios.sys ::/boot/limine 230 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT 231 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT 232 + endif 233 + ifeq ($(KARCH),aarch64) 234 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTAA64.EFI ::/EFI/BOOT 235 + endif 236 + ifeq ($(KARCH),riscv64) 237 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTRISCV64.EFI ::/EFI/BOOT 238 + endif 239 + ifeq ($(KARCH),loongarch64) 240 + mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTLOONGARCH64.EFI ::/EFI/BOOT 241 + endif 242 + 243 + .PHONY: clean 244 + clean: 245 + $(MAKE) -C kernel clean 246 + rm -rf iso_root $(IMAGE_NAME).iso $(IMAGE_NAME).hdd 247 + 248 + .PHONY: distclean 249 + distclean: clean 250 + $(MAKE) -C kernel distclean 251 + rm -rf limine ovmf
+12
LICENSE
··· 1 + Copyright (C) 2023-2024 mintsuki and contributors. 2 + 3 + Permission to use, copy, modify, and/or distribute this software for any 4 + purpose with or without fee is hereby granted. 5 + 6 + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 7 + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 8 + FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 9 + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 10 + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 11 + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 12 + PERFORMANCE OF THIS SOFTWARE.
+33
README.md
··· 1 + # Limine Rust Template 2 + 3 + This repository will demonstrate how to set up a basic kernel in Rust using Limine. 4 + 5 + ## How to use this? 6 + 7 + ### Dependencies 8 + 9 + Any `make` command depends on GNU make (`gmake`) and is expected to be run using it. This usually means using `make` on most GNU/Linux distros, or `gmake` on other non-GNU systems. 10 + 11 + All `make all*` targets depend on Rust. 12 + 13 + Additionally, building an ISO with `make all` requires `xorriso`, and building a HDD/USB image with `make all-hdd` requires `sgdisk` (usually from `gdisk` or `gptfdisk` packages) and `mtools`. 14 + 15 + ### Architectural targets 16 + 17 + The `KARCH` make variable determines the target architecture to build the kernel and image for. 18 + 19 + The default `KARCH` is `x86_64`. Other options include: `aarch64`, `riscv64`, and `loongarch64`. 20 + 21 + Other architectures will need to be enabled in kernel/rust-toolchain.toml 22 + 23 + ### Makefile targets 24 + 25 + Running `make all` will compile the kernel (from the `kernel/` directory) and then generate a bootable ISO image. 26 + 27 + Running `make all-hdd` will compile the kernel and then generate a raw image suitable to be flashed onto a USB stick or hard drive/SSD. 28 + 29 + Running `make run` will build the kernel and a bootable ISO (equivalent to make all) and then run it using `qemu` (if installed). 30 + 31 + Running `make run-hdd` will build the kernel and a raw HDD image (equivalent to make all-hdd) and then run it using `qemu` (if installed). 32 + 33 + The `run-uefi` and `run-hdd-uefi` targets are equivalent to their non `-uefi` counterparts except that they boot `qemu` using a UEFI-compatible firmware.
+2
kernel/.gitignore
··· 1 + /kernel 2 + /target
+25
kernel/Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "bitflags" 7 + version = "2.9.1" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 10 + 11 + [[package]] 12 + name = "limine" 13 + version = "0.5.0" 14 + source = "registry+https://github.com/rust-lang/crates.io-index" 15 + checksum = "af6d2ee42712e7bd2c787365cd1dab06ef59a61becbf87bec7b32b970bd2594b" 16 + dependencies = [ 17 + "bitflags", 18 + ] 19 + 20 + [[package]] 21 + name = "limine-rust-template" 22 + version = "0.1.0" 23 + dependencies = [ 24 + "limine", 25 + ]
+7
kernel/Cargo.toml
··· 1 + [package] 2 + name = "limine-rust-template" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + limine = "0.5"
+44
kernel/GNUmakefile
··· 1 + # Nuke built-in rules and variables. 2 + MAKEFLAGS += -rR 3 + .SUFFIXES: 4 + 5 + # This is the name that our final executable will have. 6 + # Change as needed. 7 + override OUTPUT := kernel 8 + 9 + # Convenience macro to reliably declare user overridable variables. 10 + override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2))) 11 + 12 + # Target architecture to build for. Default to x86_64. 13 + $(call USER_VARIABLE,KARCH,x86_64) 14 + 15 + ifeq ($(RUST_TARGET),) 16 + override RUST_TARGET := $(KARCH)-unknown-none 17 + ifeq ($(KARCH),riscv64) 18 + override RUST_TARGET := riscv64gc-unknown-none-elf 19 + endif 20 + endif 21 + 22 + ifeq ($(RUST_PROFILE),) 23 + override RUST_PROFILE := dev 24 + endif 25 + 26 + override RUST_PROFILE_SUBDIR := $(RUST_PROFILE) 27 + ifeq ($(RUST_PROFILE),dev) 28 + override RUST_PROFILE_SUBDIR := debug 29 + endif 30 + 31 + # Default target. 32 + .PHONY: all 33 + all: 34 + RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE) 35 + cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/$$(cd target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR) && find -maxdepth 1 -perm -111 -type f) kernel 36 + 37 + # Remove object files and the final executable. 38 + .PHONY: clean 39 + clean: 40 + cargo clean 41 + rm -rf kernel 42 + 43 + .PHONY: distclean 44 + distclean: clean
+7
kernel/build.rs
··· 1 + fn main() { 2 + let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); 3 + // Tell cargo to pass the linker script to the linker.. 4 + println!("cargo:rustc-link-arg=-Tlinker-{arch}.ld"); 5 + // ..and to re-run if it changes. 6 + println!("cargo:rerun-if-changed=linker-{arch}.ld"); 7 + }
+63
kernel/linker-aarch64.ld
··· 1 + /* Tell the linker that we want an aarch64 ELF64 output file */ 2 + OUTPUT_FORMAT(elf64-littleaarch64) 3 + 4 + /* We want the symbol kmain to be our entry point */ 5 + ENTRY(kmain) 6 + 7 + /* Define the program headers we want so the bootloader gives us the right */ 8 + /* MMU permissions; this also allows us to exert more control over the linking */ 9 + /* process. */ 10 + PHDRS 11 + { 12 + text PT_LOAD; 13 + rodata PT_LOAD; 14 + data PT_LOAD; 15 + } 16 + 17 + SECTIONS 18 + { 19 + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ 20 + /* and because that is what the Limine spec mandates. */ 21 + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 22 + /* that is the beginning of the region. */ 23 + . = 0xffffffff80000000; 24 + 25 + .text : { 26 + *(.text .text.*) 27 + } :text 28 + 29 + /* Move to the next memory page for .rodata */ 30 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 31 + 32 + .rodata : { 33 + *(.rodata .rodata.*) 34 + } :rodata 35 + 36 + /* Move to the next memory page for .data */ 37 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 + 39 + .data : { 40 + *(.data .data.*) 41 + 42 + /* Place the sections that contain the Limine requests as part of the .data */ 43 + /* output section. */ 44 + KEEP(*(.requests_start_marker)) 45 + KEEP(*(.requests)) 46 + KEEP(*(.requests_end_marker)) 47 + } :data 48 + 49 + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ 50 + /* unnecessary zeros will be written to the binary. */ 51 + /* If you need, for example, .init_array and .fini_array, those should be placed */ 52 + /* above this. */ 53 + .bss : { 54 + *(.bss .bss.*) 55 + *(COMMON) 56 + } :data 57 + 58 + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ 59 + /DISCARD/ : { 60 + *(.eh_frame*) 61 + *(.note .note.*) 62 + } 63 + }
+63
kernel/linker-loongarch64.ld
··· 1 + /* Tell the linker that we want a loongarch64 ELF64 output file */ 2 + OUTPUT_FORMAT(elf64-loongarch) 3 + 4 + /* We want the symbol kmain to be our entry point */ 5 + ENTRY(kmain) 6 + 7 + /* Define the program headers we want so the bootloader gives us the right */ 8 + /* MMU permissions; this also allows us to exert more control over the linking */ 9 + /* process. */ 10 + PHDRS 11 + { 12 + text PT_LOAD; 13 + rodata PT_LOAD; 14 + data PT_LOAD; 15 + } 16 + 17 + SECTIONS 18 + { 19 + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ 20 + /* and because that is what the Limine spec mandates. */ 21 + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 22 + /* that is the beginning of the region. */ 23 + . = 0xffffffff80000000; 24 + 25 + .text : { 26 + *(.text .text.*) 27 + } :text 28 + 29 + /* Move to the next memory page for .rodata */ 30 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 31 + 32 + .rodata : { 33 + *(.rodata .rodata.*) 34 + } :rodata 35 + 36 + /* Move to the next memory page for .data */ 37 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 + 39 + .data : { 40 + *(.data .data.*) 41 + 42 + /* Place the sections that contain the Limine requests as part of the .data */ 43 + /* output section. */ 44 + KEEP(*(.requests_start_marker)) 45 + KEEP(*(.requests)) 46 + KEEP(*(.requests_end_marker)) 47 + } :data 48 + 49 + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ 50 + /* unnecessary zeros will be written to the binary. */ 51 + /* If you need, for example, .init_array and .fini_array, those should be placed */ 52 + /* above this. */ 53 + .bss : { 54 + *(.bss .bss.*) 55 + *(COMMON) 56 + } :data 57 + 58 + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ 59 + /DISCARD/ : { 60 + *(.eh_frame*) 61 + *(.note .note.*) 62 + } 63 + }
+66
kernel/linker-riscv64.ld
··· 1 + /* Tell the linker that we want a riscv64 ELF64 output file */ 2 + OUTPUT_FORMAT(elf64-littleriscv) 3 + 4 + /* We want the symbol kmain to be our entry point */ 5 + ENTRY(kmain) 6 + 7 + /* Define the program headers we want so the bootloader gives us the right */ 8 + /* MMU permissions; this also allows us to exert more control over the linking */ 9 + /* process. */ 10 + PHDRS 11 + { 12 + text PT_LOAD; 13 + rodata PT_LOAD; 14 + data PT_LOAD; 15 + } 16 + 17 + SECTIONS 18 + { 19 + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ 20 + /* and because that is what the Limine spec mandates. */ 21 + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 22 + /* that is the beginning of the region. */ 23 + . = 0xffffffff80000000; 24 + 25 + .text : { 26 + *(.text .text.*) 27 + } :text 28 + 29 + /* Move to the next memory page for .rodata */ 30 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 31 + 32 + .rodata : { 33 + *(.rodata .rodata.*) 34 + } :rodata 35 + 36 + /* Move to the next memory page for .data */ 37 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 + 39 + .data : { 40 + *(.data .data.*) 41 + 42 + /* Place the sections that contain the Limine requests as part of the .data */ 43 + /* output section. */ 44 + KEEP(*(.requests_start_marker)) 45 + KEEP(*(.requests)) 46 + KEEP(*(.requests_end_marker)) 47 + 48 + *(.sdata .sdata.*) 49 + } :data 50 + 51 + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ 52 + /* unnecessary zeros will be written to the binary. */ 53 + /* If you need, for example, .init_array and .fini_array, those should be placed */ 54 + /* above this. */ 55 + .bss : { 56 + *(.sbss .sbss.*) 57 + *(.bss .bss.*) 58 + *(COMMON) 59 + } :data 60 + 61 + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ 62 + /DISCARD/ : { 63 + *(.eh_frame*) 64 + *(.note .note.*) 65 + } 66 + }
+63
kernel/linker-x86_64.ld
··· 1 + /* Tell the linker that we want an x86_64 ELF64 output file */ 2 + OUTPUT_FORMAT(elf64-x86-64) 3 + 4 + /* We want the symbol kmain to be our entry point */ 5 + ENTRY(kmain) 6 + 7 + /* Define the program headers we want so the bootloader gives us the right */ 8 + /* MMU permissions; this also allows us to exert more control over the linking */ 9 + /* process. */ 10 + PHDRS 11 + { 12 + text PT_LOAD; 13 + rodata PT_LOAD; 14 + data PT_LOAD; 15 + } 16 + 17 + SECTIONS 18 + { 19 + /* We want to be placed in the topmost 2GiB of the address space, for optimisations */ 20 + /* and because that is what the Limine spec mandates. */ 21 + /* Any address in this region will do, but often 0xffffffff80000000 is chosen as */ 22 + /* that is the beginning of the region. */ 23 + . = 0xffffffff80000000; 24 + 25 + .text : { 26 + *(.text .text.*) 27 + } :text 28 + 29 + /* Move to the next memory page for .rodata */ 30 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 31 + 32 + .rodata : { 33 + *(.rodata .rodata.*) 34 + } :rodata 35 + 36 + /* Move to the next memory page for .data */ 37 + . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 + 39 + .data : { 40 + *(.data .data.*) 41 + 42 + /* Place the sections that contain the Limine requests as part of the .data */ 43 + /* output section. */ 44 + KEEP(*(.requests_start_marker)) 45 + KEEP(*(.requests)) 46 + KEEP(*(.requests_end_marker)) 47 + } :data 48 + 49 + /* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */ 50 + /* unnecessary zeros will be written to the binary. */ 51 + /* If you need, for example, .init_array and .fini_array, those should be placed */ 52 + /* above this. */ 53 + .bss : { 54 + *(.bss .bss.*) 55 + *(COMMON) 56 + } :data 57 + 58 + /* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */ 59 + /DISCARD/ : { 60 + *(.eh_frame*) 61 + *(.note .note.*) 62 + } 63 + }
+8
kernel/rust-toolchain.toml
··· 1 + [toolchain] 2 + channel = "nightly" 3 + targets = [ 4 + "x86_64-unknown-none", 5 + # "aarch64-unknown-none", 6 + # "riscv64gc-unknown-none-elf", 7 + # "loongarch64-unknown-none", 8 + ]
+73
kernel/src/main.rs
··· 1 + #![no_std] 2 + #![no_main] 3 + 4 + use core::arch::asm; 5 + 6 + use limine::BaseRevision; 7 + use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker}; 8 + 9 + /// Sets the base revision to the latest revision supported by the crate. 10 + /// See specification for further info. 11 + /// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler. 12 + #[used] 13 + // The .requests section allows limine to find the requests faster and more safely. 14 + #[unsafe(link_section = ".requests")] 15 + static BASE_REVISION: BaseRevision = BaseRevision::new(); 16 + 17 + #[used] 18 + #[unsafe(link_section = ".requests")] 19 + static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); 20 + 21 + /// Define the stand and end markers for Limine requests. 22 + #[used] 23 + #[unsafe(link_section = ".requests_start_marker")] 24 + static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); 25 + #[used] 26 + #[unsafe(link_section = ".requests_end_marker")] 27 + static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); 28 + 29 + #[unsafe(no_mangle)] 30 + unsafe extern "C" fn kmain() -> ! { 31 + // All limine requests must also be referenced in a called function, otherwise they may be 32 + // removed by the linker. 33 + assert!(BASE_REVISION.is_supported()); 34 + 35 + if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { 36 + if let Some(framebuffer) = framebuffer_response.framebuffers().next() { 37 + for i in 0..100_u64 { 38 + // Calculate the pixel offset using the framebuffer information we obtained above. 39 + // We skip `i` scanlines (pitch is provided in bytes) and add `i * 4` to skip `i` pixels forward. 40 + let pixel_offset = i * framebuffer.pitch() + i * 4; 41 + 42 + // Write 0xFFFFFFFF to the provided pixel offset to fill it white. 43 + unsafe { 44 + framebuffer 45 + .addr() 46 + .add(pixel_offset as usize) 47 + .cast::<u32>() 48 + .write(0xFFFFFFFF) 49 + }; 50 + } 51 + } 52 + } 53 + 54 + hcf(); 55 + } 56 + 57 + #[panic_handler] 58 + fn rust_panic(_info: &core::panic::PanicInfo) -> ! { 59 + hcf(); 60 + } 61 + 62 + fn hcf() -> ! { 63 + loop { 64 + unsafe { 65 + #[cfg(target_arch = "x86_64")] 66 + asm!("hlt"); 67 + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] 68 + asm!("wfi"); 69 + #[cfg(target_arch = "loongarch64")] 70 + asm!("idle 0"); 71 + } 72 + } 73 + }
+10
limine.conf
··· 1 + # Timeout in seconds that Limine will use before automatically booting. 2 + timeout: 3 3 + 4 + # The entry name that will be displayed in the boot menu. 5 + /Limine Template 6 + # We use the Limine boot protocol. 7 + protocol: limine 8 + 9 + # Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located. 10 + kernel_path: boot():/boot/kernel