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
|
||||
# will have compiled files and executables
|
||||
debug
|
||||
target
|
||||
|
||||
# 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/
|
||||
/limine
|
||||
/ovmf
|
||||
*.iso
|
||||
*.hdd
|
||||
|
||||
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