mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-04-25 11:49:03 +02:00
Build upon the limine Rust template and a working pipeline, display an orange background on load.
This commit is contained in:
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,21 +1,4 @@
|
|||||||
# Generated by Cargo
|
/limine
|
||||||
# will have compiled files and executables
|
/ovmf
|
||||||
debug
|
*.iso
|
||||||
target
|
*.hdd
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
|
||||||
**/*.rs.bk
|
|
||||||
|
|
||||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# Generated by cargo mutants
|
|
||||||
# Contains mutation testing data
|
|
||||||
**/mutants.out*/
|
|
||||||
|
|
||||||
# RustRover
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
#.idea/
|
|
||||||
|
|||||||
251
GNUmakefile
Normal file
251
GNUmakefile
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# Nuke built-in rules and variables.
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
# Convenience macro to reliably declare user overridable variables.
|
||||||
|
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
$(call USER_VARIABLE,KARCH,x86_64)
|
||||||
|
|
||||||
|
# Default user QEMU flags. These are appended to the QEMU command calls.
|
||||||
|
$(call USER_VARIABLE,QEMUFLAGS,-m 2G)
|
||||||
|
|
||||||
|
override IMAGE_NAME := NeumannOS-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(IMAGE_NAME).iso
|
||||||
|
|
||||||
|
.PHONY: all-hdd
|
||||||
|
all-hdd: $(IMAGE_NAME).hdd
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: run-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: run-hdd
|
||||||
|
run-hdd: run-hdd-$(KARCH)
|
||||||
|
|
||||||
|
.PHONY: run-x86_64
|
||||||
|
run-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-x86_64
|
||||||
|
run-hdd-x86_64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-aarch64
|
||||||
|
run-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu cortex-a72 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-aarch64
|
||||||
|
run-hdd-aarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu cortex-a72 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-riscv64
|
||||||
|
run-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu rv64 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-riscv64
|
||||||
|
run-hdd-riscv64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu rv64 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-loongarch64
|
||||||
|
run-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu la464 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-loongarch64
|
||||||
|
run-hdd-loongarch64: ovmf/ovmf-code-$(KARCH).fd ovmf/ovmf-vars-$(KARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M virt \
|
||||||
|
-cpu la464 \
|
||||||
|
-device ramfb \
|
||||||
|
-device qemu-xhci \
|
||||||
|
-device usb-kbd \
|
||||||
|
-device usb-mouse \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(KARCH).fd,readonly=on \
|
||||||
|
-drive if=pflash,unit=1,format=raw,file=ovmf/ovmf-vars-$(KARCH).fd \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: run-bios
|
||||||
|
run-bios: $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
-boot d \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-bios
|
||||||
|
run-hdd-bios: $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(KARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
ovmf/ovmf-code-$(KARCH).fd:
|
||||||
|
mkdir -p ovmf
|
||||||
|
curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-code-$(KARCH).fd
|
||||||
|
case "$(KARCH)" in \
|
||||||
|
aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \
|
||||||
|
loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \
|
||||||
|
riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \
|
||||||
|
esac
|
||||||
|
|
||||||
|
ovmf/ovmf-vars-$(KARCH).fd:
|
||||||
|
mkdir -p ovmf
|
||||||
|
curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-vars-$(KARCH).fd
|
||||||
|
case "$(KARCH)" in \
|
||||||
|
aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 2>/dev/null;; \
|
||||||
|
loongarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=5242880 2>/dev/null;; \
|
||||||
|
riscv64) dd if=/dev/zero of=$@ bs=1 count=0 seek=33554432 2>/dev/null;; \
|
||||||
|
esac
|
||||||
|
|
||||||
|
limine/limine:
|
||||||
|
rm -rf limine
|
||||||
|
git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1
|
||||||
|
$(MAKE) -C limine
|
||||||
|
|
||||||
|
.PHONY: kernel
|
||||||
|
kernel:
|
||||||
|
$(MAKE) -C kernel
|
||||||
|
|
||||||
|
$(IMAGE_NAME).iso: limine/limine kernel
|
||||||
|
rm -rf iso_root
|
||||||
|
mkdir -p iso_root/boot
|
||||||
|
cp -v kernel/kernel iso_root/boot/
|
||||||
|
mkdir -p iso_root/boot/limine
|
||||||
|
cp -v limine.conf iso_root/boot/limine/
|
||||||
|
mkdir -p iso_root/EFI/BOOT
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/
|
||||||
|
cp -v limine/BOOTIA32.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs -b boot/limine/limine-bios-cd.bin \
|
||||||
|
-no-emul-boot -boot-load-size 4 -boot-info-table \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
./limine/limine bios-install $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),aarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTAA64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTRISCV64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),loongarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTLOONGARCH64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs \
|
||||||
|
--efi-boot boot/limine/limine-uefi-cd.bin \
|
||||||
|
-efi-boot-part --efi-boot-image --protective-msdos-label \
|
||||||
|
iso_root -o $(IMAGE_NAME).iso
|
||||||
|
endif
|
||||||
|
rm -rf iso_root
|
||||||
|
|
||||||
|
$(IMAGE_NAME).hdd: limine/limine kernel
|
||||||
|
rm -f $(IMAGE_NAME).hdd
|
||||||
|
dd if=/dev/zero bs=1M count=0 seek=64 of=$(IMAGE_NAME).hdd
|
||||||
|
sgdisk $(IMAGE_NAME).hdd -n 1:2048 -t 1:ef00
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
./limine/limine bios-install $(IMAGE_NAME).hdd
|
||||||
|
endif
|
||||||
|
mformat -i $(IMAGE_NAME).hdd@@1M
|
||||||
|
mmd -i $(IMAGE_NAME).hdd@@1M ::/EFI ::/EFI/BOOT ::/boot ::/boot/limine
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M kernel/bin-$(KARCH)/kernel ::/boot
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine.conf ::/boot/limine
|
||||||
|
ifeq ($(KARCH),x86_64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/limine-bios.sys ::/boot/limine
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),aarch64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTAA64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTRISCV64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(KARCH),loongarch64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTLOONGARCH64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C kernel clean
|
||||||
|
rm -rf iso_root $(IMAGE_NAME).iso $(IMAGE_NAME).hdd
|
||||||
|
|
||||||
|
.PHONY: distclean
|
||||||
|
distclean: clean
|
||||||
|
$(MAKE) -C kernel distclean
|
||||||
|
rm -rf limine ovmf
|
||||||
34
README.md
Normal file
34
README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# NeumannOS
|
||||||
|
NeumannOS is an OS written from scratch, named after the famous mathematician, physicist, computer scientist and engineer Neumann János Lajos.
|
||||||
|
|
||||||
|
The repo is based on the limine-rust-template.
|
||||||
|
|
||||||
|
## How to use this?
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
All `make all*` targets depend on Rust.
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
### Architectural targets
|
||||||
|
|
||||||
|
The `KARCH` make variable determines the target architecture to build the kernel and image for.
|
||||||
|
|
||||||
|
The default `KARCH` is `x86_64`. Other options include: `aarch64`, `riscv64`, and `loongarch64`.
|
||||||
|
|
||||||
|
Other architectures will need to be enabled in kernel/rust-toolchain.toml
|
||||||
|
|
||||||
|
### Makefile targets
|
||||||
|
|
||||||
|
Running `make all` will compile the kernel (from the `kernel/` directory) and then generate a bootable ISO image.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Running `make run` will build the kernel and a bootable ISO (equivalent to make all) and then run it using `qemu` (if installed).
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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
vendored
Normal file
2
kernel/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/kernel
|
||||||
|
/target
|
||||||
25
kernel/Cargo.lock
generated
Normal file
25
kernel/Cargo.lock
generated
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "limine"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af6d2ee42712e7bd2c787365cd1dab06ef59a61becbf87bec7b32b970bd2594b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "limine-rust-template"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"limine",
|
||||||
|
]
|
||||||
7
kernel/Cargo.toml
Normal file
7
kernel/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "limine-rust-template"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
limine = "0.5"
|
||||||
44
kernel/GNUmakefile
Normal file
44
kernel/GNUmakefile
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# Nuke built-in rules and variables.
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
# This is the name that our final executable will have.
|
||||||
|
# Change as needed.
|
||||||
|
override OUTPUT := kernel
|
||||||
|
|
||||||
|
# Convenience macro to reliably declare user overridable variables.
|
||||||
|
override USER_VARIABLE = $(if $(filter $(origin $(1)),default undefined),$(eval override $(1) := $(2)))
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
$(call USER_VARIABLE,KARCH,x86_64)
|
||||||
|
|
||||||
|
ifeq ($(RUST_TARGET),)
|
||||||
|
override RUST_TARGET := $(KARCH)-unknown-none
|
||||||
|
ifeq ($(KARCH),riscv64)
|
||||||
|
override RUST_TARGET := riscv64gc-unknown-none-elf
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(RUST_PROFILE),)
|
||||||
|
override RUST_PROFILE := dev
|
||||||
|
endif
|
||||||
|
|
||||||
|
override RUST_PROFILE_SUBDIR := $(RUST_PROFILE)
|
||||||
|
ifeq ($(RUST_PROFILE),dev)
|
||||||
|
override RUST_PROFILE_SUBDIR := debug
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
RUSTFLAGS="-C relocation-model=static" cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE)
|
||||||
|
cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/$$(cd target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR) && find -maxdepth 1 -perm -111 -type f) kernel
|
||||||
|
|
||||||
|
# Remove object files and the final executable.
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
cargo clean
|
||||||
|
rm -rf kernel
|
||||||
|
|
||||||
|
.PHONY: distclean
|
||||||
|
distclean: clean
|
||||||
7
kernel/build.rs
Normal file
7
kernel/build.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
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-{arch}.ld");
|
||||||
|
// ..and to re-run if it changes.
|
||||||
|
println!("cargo:rerun-if-changed=linker-{arch}.ld");
|
||||||
|
}
|
||||||
63
kernel/linker-aarch64.ld
Normal file
63
kernel/linker-aarch64.ld
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/* Tell the linker that we want an aarch64 ELF64 output file */
|
||||||
|
OUTPUT_FORMAT(elf64-littleaarch64)
|
||||||
|
|
||||||
|
/* We want the symbol kmain to be our entry point */
|
||||||
|
ENTRY(kmain)
|
||||||
|
|
||||||
|
/* 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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
63
kernel/linker-loongarch64.ld
Normal file
63
kernel/linker-loongarch64.ld
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/* Tell the linker that we want a loongarch64 ELF64 output file */
|
||||||
|
OUTPUT_FORMAT(elf64-loongarch)
|
||||||
|
|
||||||
|
/* We want the symbol kmain to be our entry point */
|
||||||
|
ENTRY(kmain)
|
||||||
|
|
||||||
|
/* 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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
66
kernel/linker-riscv64.ld
Normal file
66
kernel/linker-riscv64.ld
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/* Tell the linker that we want a riscv64 ELF64 output file */
|
||||||
|
OUTPUT_FORMAT(elf64-littleriscv)
|
||||||
|
|
||||||
|
/* We want the symbol kmain to be our entry point */
|
||||||
|
ENTRY(kmain)
|
||||||
|
|
||||||
|
/* 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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
63
kernel/linker-x86_64.ld
Normal file
63
kernel/linker-x86_64.ld
Normal file
@@ -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 kmain to be our entry point */
|
||||||
|
ENTRY(kmain)
|
||||||
|
|
||||||
|
/* 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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
8
kernel/rust-toolchain.toml
Normal file
8
kernel/rust-toolchain.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
|
targets = [
|
||||||
|
"x86_64-unknown-none",
|
||||||
|
# "aarch64-unknown-none",
|
||||||
|
# "riscv64gc-unknown-none-elf",
|
||||||
|
# "loongarch64-unknown-none",
|
||||||
|
]
|
||||||
25
kernel/src/graphics.rs
Normal file
25
kernel/src/graphics.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
use limine::framebuffer::Framebuffer;
|
||||||
|
|
||||||
|
pub fn rgb(r: u8, g: u8, b: u8) -> u32 {
|
||||||
|
((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_rect(framebuffer: &Framebuffer, x: u64, y: u64, width: u64, height: u64, color: u32) {
|
||||||
|
for fb_x in x..x+width {
|
||||||
|
for fb_y in y..y+height {
|
||||||
|
// Calculate the pixel offset using the framebuffer information we obtained above.
|
||||||
|
// We skip `i` scanlines (pitch is provided in bytes) and add `i * 4` to skip `i` pixels forward.
|
||||||
|
let bytes_per_pixel = framebuffer.bpp() as u64 / 8;
|
||||||
|
let pixel_offset = fb_y * framebuffer.pitch() + fb_x * bytes_per_pixel;
|
||||||
|
|
||||||
|
// Write 0xFFFFFFFF to the provided pixel offset to fill it white.
|
||||||
|
unsafe {
|
||||||
|
framebuffer
|
||||||
|
.addr()
|
||||||
|
.add(pixel_offset as usize)
|
||||||
|
.cast::<u32>()
|
||||||
|
.write(color)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
kernel/src/main.rs
Normal file
64
kernel/src/main.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
use limine::BaseRevision;
|
||||||
|
use limine::request::{FramebufferRequest, RequestsEndMarker, RequestsStartMarker};
|
||||||
|
|
||||||
|
mod graphics;
|
||||||
|
use crate::graphics::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// Sets the base revision to the latest revision supported by the crate.
|
||||||
|
/// See specification for further info.
|
||||||
|
/// Be sure to mark all limine requests with #[used], otherwise they may be removed by the compiler.
|
||||||
|
#[used]
|
||||||
|
// The .requests section allows limine to find the requests faster and more safely.
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static BASE_REVISION: BaseRevision = BaseRevision::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".requests")]
|
||||||
|
static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||||
|
|
||||||
|
/// Define the stand and end markers for Limine requests.
|
||||||
|
#[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();
|
||||||
|
|
||||||
|
#[unsafe(no_mangle)]
|
||||||
|
unsafe extern "C" fn kmain() -> ! {
|
||||||
|
// All limine requests must also be referenced in a called function, otherwise they may be
|
||||||
|
// removed by the linker.
|
||||||
|
assert!(BASE_REVISION.is_supported());
|
||||||
|
|
||||||
|
if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() {
|
||||||
|
if let Some(framebuffer) = framebuffer_response.framebuffers().next() {
|
||||||
|
graphics::create_rect(&framebuffer, 0, 0, framebuffer.width(), framebuffer.height(), graphics::rgb(253, 129, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn rust_panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hcf() -> ! {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
limine.conf
Normal file
10
limine.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Timeout in seconds that Limine will use before automatically booting.
|
||||||
|
timeout: 3
|
||||||
|
|
||||||
|
# The entry name that will be displayed in the boot menu.
|
||||||
|
/Limine NeumannOS
|
||||||
|
# We use the Limine boot protocol.
|
||||||
|
protocol: limine
|
||||||
|
|
||||||
|
# Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located.
|
||||||
|
kernel_path: boot():/boot/kernel
|
||||||
Reference in New Issue
Block a user