GDT, page frame allocator
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
/kernel-deps
|
||||||
|
/limine
|
||||||
|
/ovmf
|
||||||
|
*.iso
|
||||||
|
*.hdd
|
||||||
Vendored
+67
@@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"array": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"*.tcc": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"numbers": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"span": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"charconv": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"format": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"stdfloat": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"text_encoding": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"cinttypes": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
+249
@@ -0,0 +1,249 @@
|
|||||||
|
# Nuke built-in rules and variables.
|
||||||
|
MAKEFLAGS += -rR
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
ARCH := x86_64
|
||||||
|
|
||||||
|
# Default user QEMU flags. These are appended to the QEMU command calls.
|
||||||
|
QEMUFLAGS := -m 2G
|
||||||
|
|
||||||
|
override IMAGE_NAME := template-$(ARCH)
|
||||||
|
|
||||||
|
# Toolchain for building the 'limine' executable for the host.
|
||||||
|
HOST_CC := cc
|
||||||
|
HOST_CFLAGS := -g -O2 -pipe
|
||||||
|
HOST_CPPFLAGS :=
|
||||||
|
HOST_LDFLAGS :=
|
||||||
|
HOST_LIBS :=
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(IMAGE_NAME).iso
|
||||||
|
|
||||||
|
.PHONY: all-hdd
|
||||||
|
all-hdd: $(IMAGE_NAME).hdd
|
||||||
|
|
||||||
|
.PHONY: run
|
||||||
|
run: run-$(ARCH)
|
||||||
|
|
||||||
|
.PHONY: run-hdd
|
||||||
|
run-hdd: run-hdd-$(ARCH)
|
||||||
|
|
||||||
|
.PHONY: run-x86_64
|
||||||
|
run-x86_64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(ARCH).fd,readonly=on \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-x86_64
|
||||||
|
run-hdd-x86_64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-$(ARCH).fd,readonly=on \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-aarch64
|
||||||
|
run-aarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-aarch64
|
||||||
|
run-hdd-aarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-riscv64
|
||||||
|
run-riscv64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-riscv64
|
||||||
|
run-hdd-riscv64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-loongarch64
|
||||||
|
run-loongarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-loongarch64
|
||||||
|
run-hdd-loongarch64: ovmf/ovmf-code-$(ARCH).fd $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-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-$(ARCH).fd,readonly=on \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: run-bios
|
||||||
|
run-bios: $(IMAGE_NAME).iso
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
|
-boot d \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
.PHONY: run-hdd-bios
|
||||||
|
run-hdd-bios: $(IMAGE_NAME).hdd
|
||||||
|
qemu-system-$(ARCH) \
|
||||||
|
-M q35 \
|
||||||
|
-hda $(IMAGE_NAME).hdd \
|
||||||
|
$(QEMUFLAGS)
|
||||||
|
|
||||||
|
ovmf/ovmf-code-$(ARCH).fd:
|
||||||
|
mkdir -p ovmf
|
||||||
|
curl -Lo $@ https://github.com/osdev0/edk2-ovmf-nightly/releases/latest/download/ovmf-code-$(ARCH).fd
|
||||||
|
case "$(ARCH)" in \
|
||||||
|
aarch64) dd if=/dev/zero of=$@ bs=1 count=0 seek=67108864 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 \
|
||||||
|
CC="$(HOST_CC)" \
|
||||||
|
CFLAGS="$(HOST_CFLAGS)" \
|
||||||
|
CPPFLAGS="$(HOST_CPPFLAGS)" \
|
||||||
|
LDFLAGS="$(HOST_LDFLAGS)" \
|
||||||
|
LIBS="$(HOST_LIBS)"
|
||||||
|
|
||||||
|
kernel-deps:
|
||||||
|
./kernel/get-deps
|
||||||
|
touch kernel-deps
|
||||||
|
|
||||||
|
.PHONY: kernel
|
||||||
|
kernel: kernel-deps
|
||||||
|
$(MAKE) -C kernel
|
||||||
|
|
||||||
|
$(IMAGE_NAME).iso: limine/limine kernel
|
||||||
|
rm -rf iso_root
|
||||||
|
mkdir -p iso_root/boot
|
||||||
|
cp -v kernel/bin-$(ARCH)/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 ($(ARCH),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 -R -r -J -b boot/limine/limine-bios-cd.bin \
|
||||||
|
-no-emul-boot -boot-load-size 4 -boot-info-table -hfsplus \
|
||||||
|
-apm-block-size 2048 --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 ($(ARCH),aarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTAA64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs -R -r -J \
|
||||||
|
-hfsplus -apm-block-size 2048 \
|
||||||
|
--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 ($(ARCH),riscv64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTRISCV64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs -R -r -J \
|
||||||
|
-hfsplus -apm-block-size 2048 \
|
||||||
|
--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 ($(ARCH),loongarch64)
|
||||||
|
cp -v limine/limine-uefi-cd.bin iso_root/boot/limine/
|
||||||
|
cp -v limine/BOOTLOONGARCH64.EFI iso_root/EFI/BOOT/
|
||||||
|
xorriso -as mkisofs -R -r -J \
|
||||||
|
-hfsplus -apm-block-size 2048 \
|
||||||
|
--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
|
||||||
|
PATH=$$PATH:/usr/sbin:/sbin sgdisk $(IMAGE_NAME).hdd -n 1:2048 -t 1:ef00
|
||||||
|
ifeq ($(ARCH),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-$(ARCH)/kernel ::/boot
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine.conf ::/boot/limine
|
||||||
|
ifeq ($(ARCH),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 ($(ARCH),aarch64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTAA64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),riscv64)
|
||||||
|
mcopy -i $(IMAGE_NAME).hdd@@1M limine/BOOTRISCV64.EFI ::/EFI/BOOT
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),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:
|
||||||
|
$(MAKE) -C kernel distclean
|
||||||
|
rm -rf iso_root *.iso *.hdd kernel-deps limine ovmf
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Copyright (C) 2023-2025 mintsuki and contributors.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
PERFORMANCE OF THIS SOFTWARE.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# OS220
|
||||||
|
|
||||||
|
|
||||||
|
# Roadmap
|
||||||
|
[x] GDT
|
||||||
|
[ ] IDT/ISRs/Interrupts
|
||||||
|
[ ] Page frame allocator
|
||||||
|
[ ] Paging
|
||||||
|
[ ] Heap allocator
|
||||||
|
...
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/freestnd-c-hdrs
|
||||||
|
/freestnd-cxx-hdrs
|
||||||
|
/cc-runtime*
|
||||||
|
/src/limine.h
|
||||||
|
/bin-*
|
||||||
|
/obj-*
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
# Target architecture to build for. Default to x86_64.
|
||||||
|
ARCH := x86_64
|
||||||
|
|
||||||
|
# Install prefix; /usr/local is a good, standard default pick.
|
||||||
|
PREFIX := /usr/local
|
||||||
|
|
||||||
|
# Check if the architecture is supported.
|
||||||
|
ifeq ($(filter $(ARCH),aarch64 loongarch64 riscv64 x86_64),)
|
||||||
|
$(error Architecture $(ARCH) not supported)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# User controllable C compiler command.
|
||||||
|
CC := cc
|
||||||
|
|
||||||
|
# User controllable C++ compiler command.
|
||||||
|
CXX := c++
|
||||||
|
|
||||||
|
# User controllable archiver command.
|
||||||
|
AR := ar
|
||||||
|
|
||||||
|
# User controllable C flags.
|
||||||
|
CFLAGS := -g -O2 -pipe
|
||||||
|
|
||||||
|
# User controllable C++ flags. We default to same as C flags.
|
||||||
|
CXXFLAGS := $(CFLAGS)
|
||||||
|
|
||||||
|
# User controllable C/C++ preprocessor flags. We set none by default.
|
||||||
|
CPPFLAGS :=
|
||||||
|
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
# User controllable nasm flags.
|
||||||
|
NASMFLAGS := -F dwarf -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
# User controllable linker flags. We set none by default.
|
||||||
|
LDFLAGS :=
|
||||||
|
|
||||||
|
# Ensure the dependencies have been obtained.
|
||||||
|
ifneq ($(shell ( test '$(MAKECMDGOALS)' = clean || test '$(MAKECMDGOALS)' = distclean ); echo $$?),0)
|
||||||
|
ifeq ($(shell ( ! test -d freestnd-c-hdrs || ! test -d freestnd-cxx-hdrs || ! test -d cc-runtime || ! test -f src/limine.h ); echo $$?),0)
|
||||||
|
$(error Please run the ./get-deps script first)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check if CC is Clang.
|
||||||
|
override CC_IS_CLANG := $(shell ! $(CC) --version 2>/dev/null | grep 'clang' >/dev/null 2>&1; echo $$?)
|
||||||
|
|
||||||
|
# Check if CXX is Clang.
|
||||||
|
override CXX_IS_CLANG := $(shell ! $(CXX) --version 2>/dev/null | grep 'clang' >/dev/null 2>&1; echo $$?)
|
||||||
|
|
||||||
|
# Internal flags shared by both C and C++ compilers.
|
||||||
|
override SHARED_FLAGS := \
|
||||||
|
-Wall \
|
||||||
|
-Wextra \
|
||||||
|
-nostdinc \
|
||||||
|
-ffreestanding \
|
||||||
|
-fno-stack-protector \
|
||||||
|
-fno-stack-check \
|
||||||
|
-fno-PIC \
|
||||||
|
-ffunction-sections \
|
||||||
|
-fdata-sections
|
||||||
|
|
||||||
|
# Internal C/C++ preprocessor flags that should not be changed by the user.
|
||||||
|
override CPPFLAGS_C := \
|
||||||
|
-I src \
|
||||||
|
-isystem freestnd-c-hdrs/$(ARCH)/include \
|
||||||
|
$(CPPFLAGS) \
|
||||||
|
-DLIMINE_API_REVISION=3 \
|
||||||
|
-MMD \
|
||||||
|
-MP
|
||||||
|
|
||||||
|
# Internal C++ only preprocessor flags.
|
||||||
|
override CPPFLAGS_CXX := \
|
||||||
|
-I src \
|
||||||
|
-isystem freestnd-c-hdrs/$(ARCH)/include \
|
||||||
|
-isystem freestnd-cxx-hdrs/$(ARCH)/include \
|
||||||
|
$(CPPFLAGS) \
|
||||||
|
-DLIMINE_API_REVISION=3 \
|
||||||
|
-MMD \
|
||||||
|
-MP
|
||||||
|
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
# Internal nasm flags that should not be changed by the user.
|
||||||
|
override NASMFLAGS += \
|
||||||
|
-Wall
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Architecture specific internal flags.
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
ifeq ($(CC_IS_CLANG),1)
|
||||||
|
override CC += \
|
||||||
|
-target x86_64-unknown-none
|
||||||
|
endif
|
||||||
|
ifeq ($(CXX_IS_CLANG),1)
|
||||||
|
override CXX += \
|
||||||
|
-target x86_64-unknown-none
|
||||||
|
endif
|
||||||
|
override SHARED_FLAGS += \
|
||||||
|
-m64 \
|
||||||
|
-march=x86-64 \
|
||||||
|
-mno-80387 \
|
||||||
|
-mno-mmx \
|
||||||
|
-mno-sse \
|
||||||
|
-mno-sse2 \
|
||||||
|
-mno-red-zone \
|
||||||
|
-mcmodel=kernel
|
||||||
|
override LDFLAGS += \
|
||||||
|
-Wl,-m,elf_x86_64
|
||||||
|
override NASMFLAGS += \
|
||||||
|
-f elf64
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),aarch64)
|
||||||
|
ifeq ($(CC_IS_CLANG),1)
|
||||||
|
override CC += \
|
||||||
|
-target aarch64-unknown-none
|
||||||
|
endif
|
||||||
|
ifeq ($(CXX_IS_CLANG),1)
|
||||||
|
override CXX += \
|
||||||
|
-target aarch64-unknown-none
|
||||||
|
endif
|
||||||
|
override SHARED_FLAGS += \
|
||||||
|
-mgeneral-regs-only
|
||||||
|
override LDFLAGS += \
|
||||||
|
-Wl,-m,aarch64elf
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),riscv64)
|
||||||
|
ifeq ($(CC_IS_CLANG),1)
|
||||||
|
override CC += \
|
||||||
|
-target riscv64-unknown-none
|
||||||
|
override CFLAGS += \
|
||||||
|
-march=rv64imac
|
||||||
|
else
|
||||||
|
override CFLAGS += \
|
||||||
|
-march=rv64imac_zicsr_zifencei
|
||||||
|
endif
|
||||||
|
ifeq ($(CXX_IS_CLANG),1)
|
||||||
|
override CXX += \
|
||||||
|
-target riscv64-unknown-none
|
||||||
|
override CXXFLAGS += \
|
||||||
|
-march=rv64imac
|
||||||
|
else
|
||||||
|
override CXXFLAGS += \
|
||||||
|
-march=rv64imac_zicsr_zifencei
|
||||||
|
endif
|
||||||
|
override SHARED_FLAGS += \
|
||||||
|
-mabi=lp64 \
|
||||||
|
-mno-relax
|
||||||
|
override LDFLAGS += \
|
||||||
|
-Wl,-m,elf64lriscv \
|
||||||
|
-Wl,--no-relax
|
||||||
|
endif
|
||||||
|
ifeq ($(ARCH),loongarch64)
|
||||||
|
ifeq ($(CC_IS_CLANG),1)
|
||||||
|
override CC += \
|
||||||
|
-target loongarch64-unknown-none
|
||||||
|
endif
|
||||||
|
ifeq ($(CXX_IS_CLANG),1)
|
||||||
|
override CXX += \
|
||||||
|
-target loongarch64-unknown-none
|
||||||
|
endif
|
||||||
|
override SHARED_FLAGS += \
|
||||||
|
-march=loongarch64 \
|
||||||
|
-mabi=lp64s
|
||||||
|
override LDFLAGS += \
|
||||||
|
-Wl,-m,elf64loongarch \
|
||||||
|
-Wl,--no-relax
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Internal C flags that should not be changed by the user.
|
||||||
|
override CFLAGS += \
|
||||||
|
-std=gnu11 \
|
||||||
|
$(SHARED_FLAGS)
|
||||||
|
|
||||||
|
# Internal C++ flags that should not be changed by the user.
|
||||||
|
override CXXFLAGS += \
|
||||||
|
-std=gnu++20 \
|
||||||
|
-fno-rtti \
|
||||||
|
-fno-exceptions \
|
||||||
|
$(SHARED_FLAGS)
|
||||||
|
|
||||||
|
# Internal linker flags that should not be changed by the user.
|
||||||
|
override LDFLAGS += \
|
||||||
|
-Wl,--build-id=none \
|
||||||
|
-nostdlib \
|
||||||
|
-static \
|
||||||
|
-z max-page-size=0x1000 \
|
||||||
|
-Wl,--gc-sections \
|
||||||
|
-T linker-$(ARCH).ld
|
||||||
|
|
||||||
|
# Use "find" to glob all *.c, *.cpp, *.S, and *.asm files in the tree and obtain the
|
||||||
|
# object and header dependency file names.
|
||||||
|
override SRCFILES := $(shell cd src && find -L * -type f | LC_ALL=C sort)
|
||||||
|
override CFILES := $(filter %.c,$(SRCFILES))
|
||||||
|
override CXXFILES := $(filter %.cpp,$(SRCFILES))
|
||||||
|
override ASFILES := $(filter %.S,$(SRCFILES))
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
override NASMFILES := $(filter %.asm,$(SRCFILES))
|
||||||
|
endif
|
||||||
|
override OBJ := $(addprefix obj-$(ARCH)/,$(CFILES:.c=.c.o) $(CXXFILES:.cpp=.cpp.o) $(ASFILES:.S=.S.o))
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
override OBJ += $(addprefix obj-$(ARCH)/,$(NASMFILES:.asm=.asm.o))
|
||||||
|
endif
|
||||||
|
override HEADER_DEPS := $(addprefix obj-$(ARCH)/,$(CFILES:.c=.c.d) $(CXXFILES:.cpp=.cpp.d) $(ASFILES:.S=.S.d))
|
||||||
|
|
||||||
|
# Default target. This must come first, before header dependencies.
|
||||||
|
.PHONY: all
|
||||||
|
all: bin-$(ARCH)/$(OUTPUT)
|
||||||
|
|
||||||
|
# Include header dependencies.
|
||||||
|
-include $(HEADER_DEPS)
|
||||||
|
|
||||||
|
# Link rules for building the C compiler runtime.
|
||||||
|
cc-runtime-$(ARCH)/cc-runtime.a: GNUmakefile cc-runtime/*
|
||||||
|
rm -rf cc-runtime-$(ARCH)
|
||||||
|
cp -r cc-runtime cc-runtime-$(ARCH)
|
||||||
|
$(MAKE) -C cc-runtime-$(ARCH) -f cc-runtime.mk \
|
||||||
|
CC="$(CC)" \
|
||||||
|
AR="$(AR)" \
|
||||||
|
CFLAGS="$(CFLAGS)" \
|
||||||
|
CPPFLAGS='-isystem ../freestnd-c-hdrs/$(ARCH)/include -DCC_RUNTIME_NO_FLOAT'
|
||||||
|
|
||||||
|
# Link rules for the final executable.
|
||||||
|
bin-$(ARCH)/$(OUTPUT): GNUmakefile linker-$(ARCH).ld $(OBJ) cc-runtime-$(ARCH)/cc-runtime.a
|
||||||
|
mkdir -p "$$(dirname $@)"
|
||||||
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJ) cc-runtime-$(ARCH)/cc-runtime.a -o $@
|
||||||
|
|
||||||
|
# Compilation rules for *.c files.
|
||||||
|
obj-$(ARCH)/%.c.o: src/%.c GNUmakefile
|
||||||
|
mkdir -p "$$(dirname $@)"
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS_C) -c $< -o $@
|
||||||
|
|
||||||
|
# Compilation rules for *.cpp files.
|
||||||
|
obj-$(ARCH)/%.cpp.o: src/%.cpp GNUmakefile
|
||||||
|
mkdir -p "$$(dirname $@)"
|
||||||
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS_CXX) -c $< -o $@
|
||||||
|
|
||||||
|
# Compilation rules for *.S files.
|
||||||
|
obj-$(ARCH)/%.S.o: src/%.S GNUmakefile
|
||||||
|
mkdir -p "$$(dirname $@)"
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS_C) -c $< -o $@
|
||||||
|
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
# Compilation rules for *.asm (nasm) files.
|
||||||
|
obj-$(ARCH)/%.asm.o: src/%.asm GNUmakefile
|
||||||
|
mkdir -p "$$(dirname $@)"
|
||||||
|
nasm $(NASMFLAGS) $< -o $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Remove object files and the final executable.
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf bin-$(ARCH) obj-$(ARCH) cc-runtime-$(ARCH)
|
||||||
|
|
||||||
|
# Remove everything built and generated including downloaded dependencies.
|
||||||
|
.PHONY: distclean
|
||||||
|
distclean:
|
||||||
|
rm -rf bin-* obj-* freestnd-c-hdrs freestnd-cxx-hdrs cc-runtime* src/limine.h
|
||||||
|
|
||||||
|
# Install the final built executable to its final on-root location.
|
||||||
|
.PHONY: install
|
||||||
|
install: all
|
||||||
|
install -d "$(DESTDIR)$(PREFIX)/share/$(OUTPUT)"
|
||||||
|
install -m 644 bin-$(ARCH)/$(OUTPUT) "$(DESTDIR)$(PREFIX)/share/$(OUTPUT)/$(OUTPUT)-$(ARCH)"
|
||||||
|
|
||||||
|
# Try to undo whatever the "install" target did.
|
||||||
|
.PHONY: uninstall
|
||||||
|
uninstall:
|
||||||
|
rm -f "$(DESTDIR)$(PREFIX)/share/$(OUTPUT)/$(OUTPUT)-$(ARCH)"
|
||||||
|
-rmdir "$(DESTDIR)$(PREFIX)/share/$(OUTPUT)"
|
||||||
Executable
+85
@@ -0,0 +1,85 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
srcdir="$(dirname "$0")"
|
||||||
|
test -z "$srcdir" && srcdir=.
|
||||||
|
|
||||||
|
cd "$srcdir"
|
||||||
|
|
||||||
|
clone_repo_commit() {
|
||||||
|
if test -d "$2/.git"; then
|
||||||
|
git -C "$2" reset --hard
|
||||||
|
git -C "$2" clean -fd
|
||||||
|
if ! git -C "$2" checkout $3; then
|
||||||
|
rm -rf "$2"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test -d "$2"; then
|
||||||
|
set +x
|
||||||
|
echo "error: '$2' is not a Git repository"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if ! test -d "$2"; then
|
||||||
|
git clone $1 "$2"
|
||||||
|
if ! git -C "$2" checkout $3; then
|
||||||
|
rm -rf "$2"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
download_by_hash() {
|
||||||
|
DOWNLOAD_COMMAND="curl -Lo"
|
||||||
|
if ! command -v $DOWNLOAD_COMMAND >/dev/null 2>&1; then
|
||||||
|
DOWNLOAD_COMMAND="wget -O"
|
||||||
|
if ! command -v $DOWNLOAD_COMMAND >/dev/null 2>&1; then
|
||||||
|
set +x
|
||||||
|
echo "error: Neither curl nor wget found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
SHA256_COMMAND="sha256sum"
|
||||||
|
if ! command -v $SHA256_COMMAND >/dev/null 2>&1; then
|
||||||
|
SHA256_COMMAND="sha256"
|
||||||
|
if ! command -v $SHA256_COMMAND >/dev/null 2>&1; then
|
||||||
|
set +x
|
||||||
|
echo "error: Cannot find sha256(sum) command"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if ! test -f "$2" || ! $SHA256_COMMAND "$2" | grep $3 >/dev/null 2>&1; then
|
||||||
|
rm -f "$2"
|
||||||
|
mkdir -p "$2" && rm -rf "$2"
|
||||||
|
$DOWNLOAD_COMMAND "$2" $1
|
||||||
|
if ! $SHA256_COMMAND "$2" | grep $3 >/dev/null 2>&1; then
|
||||||
|
set +x
|
||||||
|
echo "error: Cannot download file '$2' by hash"
|
||||||
|
echo "incorrect hash:"
|
||||||
|
$SHA256_COMMAND "$2"
|
||||||
|
rm -f "$2"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
clone_repo_commit \
|
||||||
|
https://github.com/osdev0/freestnd-c-hdrs.git \
|
||||||
|
freestnd-c-hdrs \
|
||||||
|
21b59ecd6ef67bb32f893da8288ce08a324d1986
|
||||||
|
|
||||||
|
clone_repo_commit \
|
||||||
|
https://github.com/osdev0/freestnd-cxx-hdrs.git \
|
||||||
|
freestnd-cxx-hdrs \
|
||||||
|
d604a4c5033a7a4d610ba41daab3c541be96b43e
|
||||||
|
|
||||||
|
clone_repo_commit \
|
||||||
|
https://github.com/osdev0/cc-runtime.git \
|
||||||
|
cc-runtime \
|
||||||
|
576a01179f3298a4795b92f42c088f9f8800b56b
|
||||||
|
|
||||||
|
download_by_hash \
|
||||||
|
https://github.com/limine-bootloader/limine/raw/4687a182be23939c2d9f15db970382dc353ed956/limine.h \
|
||||||
|
src/limine.h \
|
||||||
|
6879e626f34c1be25ac2f72bf43b083fc2b53887280bb0fcdaee790e258c6974
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* 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
|
||||||
|
{
|
||||||
|
limine_requests PT_LOAD;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||||
|
.limine_requests : {
|
||||||
|
KEEP(*(.limine_requests_start))
|
||||||
|
KEEP(*(.limine_requests))
|
||||||
|
KEEP(*(.limine_requests_end))
|
||||||
|
} :limine_requests
|
||||||
|
|
||||||
|
/* Move to the next memory page for .text */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text .text.*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
/* Move to the next memory page for .rodata */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* C++ is a language that allows for global constructors. In order to obtain the */
|
||||||
|
/* address of the ".init_array" section we need to define a symbol for it. */
|
||||||
|
.init_array : {
|
||||||
|
__init_array = .;
|
||||||
|
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP(*(.init_array .ctors))
|
||||||
|
__init_array_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* Move to the next memory page for .data */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.*)
|
||||||
|
} :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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* 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
|
||||||
|
{
|
||||||
|
limine_requests PT_LOAD;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||||
|
.limine_requests : {
|
||||||
|
KEEP(*(.limine_requests_start))
|
||||||
|
KEEP(*(.limine_requests))
|
||||||
|
KEEP(*(.limine_requests_end))
|
||||||
|
} :limine_requests
|
||||||
|
|
||||||
|
/* Move to the next memory page for .text */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text .text.*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
/* Move to the next memory page for .rodata */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* C++ is a language that allows for global constructors. In order to obtain the */
|
||||||
|
/* address of the ".init_array" section we need to define a symbol for it. */
|
||||||
|
.init_array : {
|
||||||
|
__init_array = .;
|
||||||
|
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP(*(.init_array .ctors))
|
||||||
|
__init_array_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* Move to the next memory page for .data */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.*)
|
||||||
|
} :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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/* 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
|
||||||
|
{
|
||||||
|
limine_requests PT_LOAD;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||||
|
.limine_requests : {
|
||||||
|
KEEP(*(.limine_requests_start))
|
||||||
|
KEEP(*(.limine_requests))
|
||||||
|
KEEP(*(.limine_requests_end))
|
||||||
|
} :limine_requests
|
||||||
|
|
||||||
|
/* Move to the next memory page for .text */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text .text.*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
/* Move to the next memory page for .rodata */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* C++ is a language that allows for global constructors. In order to obtain the */
|
||||||
|
/* address of the ".init_array" section we need to define a symbol for it. */
|
||||||
|
.init_array : {
|
||||||
|
__init_array = .;
|
||||||
|
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP(*(.init_array .ctors))
|
||||||
|
__init_array_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* Move to the next memory page for .data */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.*)
|
||||||
|
*(.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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/* 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
|
||||||
|
{
|
||||||
|
limine_requests PT_LOAD;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||||
|
.limine_requests : {
|
||||||
|
KEEP(*(.limine_requests_start))
|
||||||
|
KEEP(*(.limine_requests))
|
||||||
|
KEEP(*(.limine_requests_end))
|
||||||
|
} :limine_requests
|
||||||
|
|
||||||
|
/* Move to the next memory page for .text */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text .text.*)
|
||||||
|
} :text
|
||||||
|
|
||||||
|
/* Move to the next memory page for .rodata */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* C++ is a language that allows for global constructors. In order to obtain the */
|
||||||
|
/* address of the ".init_array" section we need to define a symbol for it. */
|
||||||
|
.init_array : {
|
||||||
|
__init_array = .;
|
||||||
|
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP(*(.init_array .ctors))
|
||||||
|
__init_array_end = .;
|
||||||
|
} :rodata
|
||||||
|
|
||||||
|
/* Move to the next memory page for .data */
|
||||||
|
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data .data.*)
|
||||||
|
} :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.*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "Panic.hpp"
|
||||||
|
|
||||||
|
void Panic(const char *meditationString, System::Registers registers) {
|
||||||
|
kerr << "=========== Kernel panic ===========" << Kt::newline;
|
||||||
|
kerr << meditationString << Kt::newline;
|
||||||
|
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
asm ("cli");
|
||||||
|
asm ("hlt");
|
||||||
|
#elif defined (__aarch64__) || defined (__riscv)
|
||||||
|
asm ("wfi");
|
||||||
|
#elif defined (__loongarch64)
|
||||||
|
asm ("idle 0");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <System/Registers.hpp>
|
||||||
|
#include <KernelTerminal/terminal.hpp>
|
||||||
|
|
||||||
|
void Panic(const char *meditationString, System::Registers registers);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* UEFI.hpp
|
||||||
|
* Copyright (c) 2025 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Efi {
|
||||||
|
typedef void* EFI_HANDLE;
|
||||||
|
|
||||||
|
struct TableHeader {
|
||||||
|
std::uint64_t Signature;
|
||||||
|
std::uint32_t Revision;
|
||||||
|
std::uint32_t HeaderSize;
|
||||||
|
std::uint32_t CRC32;
|
||||||
|
std::uint32_t Reserved;
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
struct SystemTable {
|
||||||
|
TableHeader Header;
|
||||||
|
void* FirmwareVendor; // Pointer to a CHAR16 string of the fw vendor name string
|
||||||
|
std::uint32_t FirmwareRevision;
|
||||||
|
|
||||||
|
EFI_HANDLE ConsoleInHandle;
|
||||||
|
void* ConIn;
|
||||||
|
EFI_HANDLE ConsoleOutHandle;
|
||||||
|
void* ConOut;
|
||||||
|
|
||||||
|
EFI_HANDLE StandardErrorHandle;
|
||||||
|
void* StdErr;
|
||||||
|
|
||||||
|
// Jackpot
|
||||||
|
void *RuntimeServices;
|
||||||
|
|
||||||
|
void *BootServices;
|
||||||
|
|
||||||
|
std::uint64_t NumberOfTableEntries;
|
||||||
|
|
||||||
|
void *ConfigurationTable;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
;
|
||||||
|
; gdt.asm
|
||||||
|
; Copyright (c) 2025 Daniel Hammer
|
||||||
|
;
|
||||||
|
|
||||||
|
[bits 64]
|
||||||
|
section .text ; Text/code section
|
||||||
|
|
||||||
|
global ReloadSegments
|
||||||
|
global LoadGDT
|
||||||
|
|
||||||
|
LoadGDT:
|
||||||
|
lgdt [rdi] ; Run LGDT on the contents of 1st C parameter
|
||||||
|
ret
|
||||||
|
|
||||||
|
ReloadSegments:
|
||||||
|
push 0x08 ; CS descriptor
|
||||||
|
lea rax, [rel .reload_CS]
|
||||||
|
push rax
|
||||||
|
retfq
|
||||||
|
.reload_CS:
|
||||||
|
mov ax, 0x10 ; DS descriptor
|
||||||
|
|
||||||
|
; ds, es, fs, gs, ss are segment registers on x86_64
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
ret
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* gdt.hpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "GDT.hpp"
|
||||||
|
#include "../KernelTerminal/terminal.hpp"
|
||||||
|
|
||||||
|
// Limine loads a GDT of course, (CS = 0x28) but we will need to make a TSS someday... therefore we load our own now
|
||||||
|
|
||||||
|
namespace Hal {
|
||||||
|
using namespace Kt;
|
||||||
|
|
||||||
|
GDTPointer gdtPointer{};
|
||||||
|
BasicGDT kernelGDT{};
|
||||||
|
|
||||||
|
void PrepareGDT() {
|
||||||
|
kout << "[Hal] GDT at " << base::hex << (uint64_t)&kernelGDT << "\n";
|
||||||
|
kernelGDT = {
|
||||||
|
// Code segment offset 0x08
|
||||||
|
// Data segment offset 0x10
|
||||||
|
|
||||||
|
// Not sure if having LimitLow set to 0xFFFF for the Null segment is kosher
|
||||||
|
{0xFFFF, 0, 0, 0x00, 0x00, 0},
|
||||||
|
|
||||||
|
// Kernel code/data
|
||||||
|
{0xFFFF, 0, 0, 0x9A, 0xA0, 0},
|
||||||
|
{0xFFFF, 0, 0, 0x92, 0xA0, 0},
|
||||||
|
|
||||||
|
// User code/data
|
||||||
|
{0xFFFF, 0, 0, 0x9A, 0xA0, 0},
|
||||||
|
{0xFFFF, 0, 0, 0x92, 0xA0, 0},
|
||||||
|
|
||||||
|
// One day this will point to our actual TSS
|
||||||
|
{
|
||||||
|
// Limit = sizeof(TSS) - 1
|
||||||
|
0,
|
||||||
|
|
||||||
|
// Base = &TSS
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
|
||||||
|
// Access byte = 0xFA
|
||||||
|
0xFA,
|
||||||
|
|
||||||
|
// Granularity = 0x00
|
||||||
|
0x00,
|
||||||
|
|
||||||
|
0x0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
gdtPointer = GDTPointer{
|
||||||
|
.Size = sizeof(kernelGDT) - 1,
|
||||||
|
.GDTAddress = (uint64_t)&kernelGDT
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers implemented in gdt.asm
|
||||||
|
extern "C" void LoadGDT(GDTPointer *gdtPointer);
|
||||||
|
extern "C" void ReloadSegments();
|
||||||
|
|
||||||
|
void BridgeLoadGDT() {
|
||||||
|
// Puts the GDT pointer structure into the GDTR
|
||||||
|
kout << "[Hal] Setting GDTR" << Kt::newline;
|
||||||
|
LoadGDT(&gdtPointer);
|
||||||
|
|
||||||
|
kout << "[Hal] Reloading segments" << Kt::newline;
|
||||||
|
ReloadSegments();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* gdt.hpp
|
||||||
|
* Copyright (c) 2025 Daniel Hammer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// __attribute__((packed)) is the GCC extensions way of telling the compiler to ensure that it doesn't mess with these structures or add packing bytes
|
||||||
|
// for optimization because that would easily result in a triple fault.
|
||||||
|
|
||||||
|
namespace Hal {
|
||||||
|
class GDTEntry {
|
||||||
|
public:
|
||||||
|
// Base/Limit are obsolete in Long mode because segmentation is no longer used
|
||||||
|
// Sadly we must still build and load the GDT during kernel init
|
||||||
|
|
||||||
|
uint16_t LimitLow;
|
||||||
|
uint16_t BaseLow;
|
||||||
|
uint8_t BaseMiddle;
|
||||||
|
|
||||||
|
// Determine which processor rings this segment can be used in
|
||||||
|
uint8_t AccessByte;
|
||||||
|
// Lower 4 bits are the higher 4 bits of limit
|
||||||
|
uint8_t GranularityByte;
|
||||||
|
|
||||||
|
uint8_t BaseHigh;
|
||||||
|
|
||||||
|
// 16 + 16 + 8 + 8 = 48 bits
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
struct BasicGDT {
|
||||||
|
// Conventionally the first entry of the GDT has all values zeroed out.
|
||||||
|
GDTEntry Null;
|
||||||
|
|
||||||
|
// Kernel code segment descriptor
|
||||||
|
GDTEntry KernelCode;
|
||||||
|
|
||||||
|
// Kernel data segment descriptor
|
||||||
|
GDTEntry KernelData;
|
||||||
|
|
||||||
|
// UM code segment descriptor
|
||||||
|
GDTEntry UserCode;
|
||||||
|
|
||||||
|
// UM data segment descriptor
|
||||||
|
GDTEntry UserData;
|
||||||
|
|
||||||
|
// Task State Segment
|
||||||
|
GDTEntry TSS;
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
// Simple structure that tells the CPU the size of the GDT, and it's address
|
||||||
|
struct GDTPointer {
|
||||||
|
uint16_t Size;
|
||||||
|
uint64_t GDTAddress;
|
||||||
|
}__attribute__((packed));
|
||||||
|
|
||||||
|
void BridgeLoadGDT();
|
||||||
|
void PrepareGDT();
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include "terminal.hpp"
|
||||||
|
#include "../Libraries/flanterm/backends/fb.h"
|
||||||
|
#include "../Libraries/flanterm/flanterm.h"
|
||||||
|
|
||||||
|
#include "../Libraries/string.hpp"
|
||||||
|
|
||||||
|
namespace Kt {
|
||||||
|
flanterm_context *ctx;
|
||||||
|
|
||||||
|
void Initialize(std::uint32_t *framebuffer, std::size_t width, std::size_t height, std::size_t pitch,
|
||||||
|
std::uint8_t red_mask_size, std::uint8_t red_mask_shift,
|
||||||
|
std::uint8_t green_mask_size, std::uint8_t green_mask_shift,
|
||||||
|
std::uint8_t blue_mask_size, std::uint8_t blue_mask_shift
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ctx = flanterm_fb_init(
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
framebuffer,
|
||||||
|
width, height, pitch,
|
||||||
|
red_mask_size, red_mask_shift,
|
||||||
|
green_mask_size, green_mask_shift,
|
||||||
|
blue_mask_size, blue_mask_shift,
|
||||||
|
NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
NULL, NULL,
|
||||||
|
NULL, 0, 0, 1,
|
||||||
|
0, 0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Putchar(char c) {
|
||||||
|
flanterm_write(ctx, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Print(const char *text) {
|
||||||
|
flanterm_write(ctx, text, Lib::strlen(text));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <Libraries/string.hpp>
|
||||||
|
|
||||||
|
namespace Kt
|
||||||
|
{
|
||||||
|
constexpr char newline = '\n';
|
||||||
|
|
||||||
|
namespace screen
|
||||||
|
{
|
||||||
|
constexpr const char *clear = "\033[2J";
|
||||||
|
constexpr const char *cursor_reset = "\033[H";
|
||||||
|
};
|
||||||
|
|
||||||
|
void Initialize(std::uint32_t *framebuffer, std::size_t width, std::size_t height, std::size_t pitch,
|
||||||
|
std::uint8_t red_mask_size, std::uint8_t red_mask_shift,
|
||||||
|
std::uint8_t green_mask_size, std::uint8_t green_mask_shift,
|
||||||
|
std::uint8_t blue_mask_size, std::uint8_t blue_mask_shift);
|
||||||
|
void Putchar(char c);
|
||||||
|
void Print(const char *text);
|
||||||
|
|
||||||
|
enum base
|
||||||
|
{
|
||||||
|
oct = 8,
|
||||||
|
dec = 10,
|
||||||
|
hex = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
inline base base_custom(int custom)
|
||||||
|
{
|
||||||
|
return (base)custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
class KernelOutStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
base streamBaseType = base::dec;
|
||||||
|
|
||||||
|
// C++ streaming operator like cout
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, const char *string)
|
||||||
|
{
|
||||||
|
Print(string);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// C++ streaming operator like cout
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, const char chr)
|
||||||
|
{
|
||||||
|
Putchar(chr);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, int number)
|
||||||
|
{
|
||||||
|
Print(Lib::int2basestr(number, t.streamBaseType));
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, std::uint32_t number)
|
||||||
|
{
|
||||||
|
Print(Lib::uint2basestr(number, t.streamBaseType));
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, std::uint64_t number)
|
||||||
|
{
|
||||||
|
Print(Lib::u64_2_basestr(number, t.streamBaseType));
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend KernelOutStream &operator<<(KernelOutStream &t, base newBase)
|
||||||
|
{
|
||||||
|
t.streamBaseType = newBase;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will be on the kernel entry point's stack. Which is totally fine since we don't ever exit from that function
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Kt::KernelOutStream kout;
|
||||||
|
|
||||||
|
namespace Kt
|
||||||
|
{
|
||||||
|
class KernelErrorStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
friend KernelErrorStream &operator<<(KernelErrorStream &t, T value)
|
||||||
|
{
|
||||||
|
kout << "\e[0;31m" << value << "\e[0m";
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Kt::KernelErrorStream kerr;
|
||||||
Submodule
+1
Submodule kernel/src/Libraries/flanterm added at 201100c968
@@ -0,0 +1,81 @@
|
|||||||
|
#include "string.hpp"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace Lib
|
||||||
|
{
|
||||||
|
char output[1024];
|
||||||
|
|
||||||
|
// TODO make this buffer safe
|
||||||
|
char *int2basestr(int num, size_t radix)
|
||||||
|
{
|
||||||
|
char * str = (char *)&output;
|
||||||
|
|
||||||
|
if (!num) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
char base[] = "0123456789ABCDEFGH"; // IJKLMN ....
|
||||||
|
if (radix < 2 || radix > (sizeof(base) - 1))
|
||||||
|
{ // radix supported?
|
||||||
|
str[0] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int si = 0;
|
||||||
|
if (num < 0)
|
||||||
|
{
|
||||||
|
str[si++] = '-';
|
||||||
|
num = -num;
|
||||||
|
}
|
||||||
|
char tmp[256];
|
||||||
|
int rdi = -1;
|
||||||
|
while (num)
|
||||||
|
{
|
||||||
|
tmp[++rdi] = base[num % radix];
|
||||||
|
num /= radix;
|
||||||
|
}
|
||||||
|
while (rdi >= 0)
|
||||||
|
str[si++] = tmp[rdi--];
|
||||||
|
str[si] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *u64_2_basestr(uint64_t num, size_t radix)
|
||||||
|
{
|
||||||
|
char * str = (char *)&output;
|
||||||
|
|
||||||
|
if (!num) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
char base[] = "0123456789ABCDEFGH"; // IJKLMN ....
|
||||||
|
|
||||||
|
if (radix < 2 || radix > (sizeof(base) - 1))
|
||||||
|
{ // radix supported?
|
||||||
|
str[0] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int si = 0;
|
||||||
|
|
||||||
|
char tmp[256];
|
||||||
|
int rdi = -1;
|
||||||
|
while (num)
|
||||||
|
{
|
||||||
|
tmp[++rdi] = base[num % radix];
|
||||||
|
num /= radix;
|
||||||
|
}
|
||||||
|
while (rdi >= 0)
|
||||||
|
str[si++] = tmp[rdi--];
|
||||||
|
str[si] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *uint2basestr(uint32_t num, size_t radix)
|
||||||
|
{
|
||||||
|
return u64_2_basestr((uint64_t)num, radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace Lib {
|
||||||
|
inline int strlen(const char *string) {
|
||||||
|
int c = 0;
|
||||||
|
|
||||||
|
while (*string != '\0') {
|
||||||
|
string++;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *int2basestr(int num, size_t radix);
|
||||||
|
char *u64_2_basestr(uint64_t num, size_t radix);
|
||||||
|
char *uint2basestr(uint32_t num, size_t radix);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
extern std::uint64_t HHDMBase;
|
||||||
|
|
||||||
|
inline uint64_t HHDM(uint64_t address) {
|
||||||
|
return HHDMBase + address;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t HHDM(void* address) {
|
||||||
|
return HHDMBase + (uint64_t)address;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t SubHHDM(uint64_t address) {
|
||||||
|
return address - HHDMBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t SubHHDM(void* address) {
|
||||||
|
return SubHHDM((uint64_t)address);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t IsHDDMVirtAddr(uint64_t address) {
|
||||||
|
if (address > HHDMBase) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#include "Memmap.hpp"
|
||||||
|
#include <KernelTerminal/terminal.hpp>
|
||||||
|
#include <Common/Panic.hpp>
|
||||||
|
|
||||||
|
#include "PageAllocator.hpp"
|
||||||
|
|
||||||
|
using namespace Kt;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
LargestSection Scan(limine_memmap_response* mmap) {
|
||||||
|
LargestSection currentLargestSection{};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mmap->entry_count; i++) {
|
||||||
|
auto entry = mmap->entries[i];
|
||||||
|
|
||||||
|
if (entry->base == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->type == LIMINE_MEMMAP_USABLE) {
|
||||||
|
kout << "[Mem] Found conventional memory section (size = " << base::dec << entry->length << " bytes, address = 0x" << base::hex << (uint64_t)entry->base << ")" << newline;
|
||||||
|
|
||||||
|
if (entry->length > currentLargestSection.size) {
|
||||||
|
currentLargestSection = {
|
||||||
|
.address = (uint64_t)entry->base,
|
||||||
|
.size = entry->length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[unlikely]] if (currentLargestSection.address == 0) {
|
||||||
|
Panic("Couldn't find a usable memory section.", System::Registers{});
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentLargestSection;
|
||||||
|
|
||||||
|
// PageAllocator pa(currentLargestSection);
|
||||||
|
|
||||||
|
// uint64_t alloc1 = (uint64_t)pa.Allocate();
|
||||||
|
// uint64_t alloc2 = (uint64_t)pa.Allocate();
|
||||||
|
// pa.Free((void *)alloc2);
|
||||||
|
// uint64_t alloc3 = (uint64_t)pa.Allocate();
|
||||||
|
|
||||||
|
// kout << "0x" << base::hex << alloc1 << "\n";
|
||||||
|
// kout << "0x" << base::hex << alloc2 << "\n";
|
||||||
|
// kout << "0x" << base::hex << alloc3 << "\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <limine.h>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
// Shared
|
||||||
|
struct LargestSection {
|
||||||
|
uint64_t address;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
LargestSection Scan(limine_memmap_response* mmap);
|
||||||
|
};
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
#include "PageAllocator.hpp"
|
||||||
|
#include "Memmap.hpp"
|
||||||
|
#include "HHDM.hpp"
|
||||||
|
|
||||||
|
#include <KernelTerminal/terminal.hpp>
|
||||||
|
|
||||||
|
namespace Memory
|
||||||
|
{
|
||||||
|
#if defined(__x86_64__) || defined(__aarch64__)
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#else
|
||||||
|
#error Sorry, Unimplemented!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PageAllocator::PageAllocator(LargestSection section)
|
||||||
|
{
|
||||||
|
g_section = section;
|
||||||
|
|
||||||
|
size_t pages = g_section.size / PAGE_SIZE;
|
||||||
|
Block *current_ref{&head};
|
||||||
|
Block *start_block_ptr {(Block *)HHDM(section.address)};
|
||||||
|
Block& start_block = *start_block_ptr;
|
||||||
|
|
||||||
|
start_block = Block {
|
||||||
|
.size = section.size,
|
||||||
|
.next = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
*start_block_ptr = start_block;
|
||||||
|
|
||||||
|
current_ref->next = start_block_ptr;
|
||||||
|
|
||||||
|
kout << "[Mem] PageAllocator created for memory section starting at 0x" << Kt::base::hex << section.address << Kt::newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* PageAllocator::RequestPage(bool phys) {
|
||||||
|
bool found_block = false;
|
||||||
|
|
||||||
|
Block* current_block_ptr{head.next};
|
||||||
|
Block* current_prev_ptr{(Block *)&head};
|
||||||
|
|
||||||
|
while (!found_block) {
|
||||||
|
if (current_block_ptr == nullptr) {
|
||||||
|
kerr << "A PageAllocator was forced to return a Null pointer. (1)" << Kt::newline;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_prev_ptr == nullptr) {
|
||||||
|
kerr << "A PageAllocator was forced to return a Null pointer. (2)" << Kt::newline;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_block_ptr->size >= 0x1000) { // 0x1000 == 4096
|
||||||
|
current_block_ptr->size -= 0x1000;
|
||||||
|
|
||||||
|
if (!current_block_ptr->size) {
|
||||||
|
current_prev_ptr->next = current_block_ptr->next;
|
||||||
|
return (void *)current_block_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block block_copy = *current_block_ptr;
|
||||||
|
|
||||||
|
current_prev_ptr->next = (Block *)(uint64_t)current_block_ptr + 0x1000;
|
||||||
|
*current_prev_ptr->next = block_copy;
|
||||||
|
|
||||||
|
if (phys) {
|
||||||
|
return (void *)SubHHDM(current_block_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *)current_block_ptr;
|
||||||
|
} else {
|
||||||
|
if (current_block_ptr->next != nullptr) {
|
||||||
|
current_prev_ptr = current_block_ptr;
|
||||||
|
current_block_ptr = current_block_ptr->next;
|
||||||
|
} else {
|
||||||
|
kerr << "A PageAllocator was forced to return a Null pointer. (3)" << Kt::newline;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_block_ptr != nullptr) {
|
||||||
|
if (current_block_ptr->next == nullptr) {
|
||||||
|
kerr << "A PageAllocator was forced to return a Null pointer. (4)" << Kt::newline;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_block_ptr = current_block_ptr->next;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
kerr << "A PageAllocator was forced to return a Null pointer. (5)" << Kt::newline;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageAllocator::Free(void *pagePtr) {
|
||||||
|
if (!IsHDDMVirtAddr((uint64_t)pagePtr)) {
|
||||||
|
pagePtr = (void *)HHDM(pagePtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Block* fmrNext = head.next;
|
||||||
|
|
||||||
|
Block* blockPtr = (Block *)pagePtr;
|
||||||
|
|
||||||
|
head.next = blockPtr;
|
||||||
|
head.next->size = 0x1000;
|
||||||
|
|
||||||
|
head.next->next = fmrNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageAllocator::Stress() {
|
||||||
|
// ~410 MiB
|
||||||
|
for (size_t i = 0; i < 100000; i++) {
|
||||||
|
kout << "[Mem] Stress allocation " << Kt::base::dec << i << ": " << "0x" << Kt::base::hex << (uint64_t)Memory::KernelPFA->RequestPage(false) << Kt::newline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traverses the PageAllocator's linked list for debugging
|
||||||
|
void PageAllocator::Walk() {
|
||||||
|
Block* current = {head.next};
|
||||||
|
size_t i{0};
|
||||||
|
|
||||||
|
while (current != nullptr) {
|
||||||
|
kout << "Block " << Kt::base::dec << i << " {" << current->size << " bytes & address 0x" << Kt::base::hex << (uint64_t)current << "}" << Kt::newline;
|
||||||
|
current = current->next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Memmap.hpp"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class PageAllocator {
|
||||||
|
LargestSection g_section;
|
||||||
|
|
||||||
|
struct Block {
|
||||||
|
size_t size;
|
||||||
|
Block* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
Block head;
|
||||||
|
public:
|
||||||
|
PageAllocator(LargestSection section);
|
||||||
|
void* RequestPage(bool phys = false);
|
||||||
|
void Free(void *pagePtr);
|
||||||
|
|
||||||
|
void Stress();
|
||||||
|
void Walk();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PageAllocator* KernelPFA;
|
||||||
|
};
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
namespace System {
|
||||||
|
struct Registers {
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <limine.h>
|
||||||
|
|
||||||
|
#include <Hal/GDT.hpp>
|
||||||
|
#include <KernelTerminal/terminal.hpp>
|
||||||
|
#include <Libraries/string.hpp>
|
||||||
|
#include <Efi/UEFI.hpp>
|
||||||
|
#include <Common/Panic.hpp>
|
||||||
|
#include <Memory/Memmap.hpp>
|
||||||
|
#include <Memory/PageAllocator.hpp>
|
||||||
|
|
||||||
|
using namespace Kt;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
PageAllocator* KernelPFA;
|
||||||
|
uint64_t HHDMBase;
|
||||||
|
};
|
||||||
|
|
||||||
|
KernelOutStream kout;
|
||||||
|
KernelErrorStream kerr;
|
||||||
|
|
||||||
|
// Set the base revision to 3, this is recommended as this is the latest
|
||||||
|
// base revision described by the Limine boot protocol specification.
|
||||||
|
// See specification for further info.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile LIMINE_BASE_REVISION(3);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Limine requests can be placed anywhere, but it is important that
|
||||||
|
// the compiler does not optimise them away, so, usually, they should
|
||||||
|
// be made volatile or equivalent, _and_ they should be accessed at least
|
||||||
|
// once or marked as used with the "used" attribute as done here.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile limine_framebuffer_request framebuffer_request = {
|
||||||
|
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||||
|
.revision = 0,
|
||||||
|
.response = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile limine_efi_system_table_request system_table_request = {
|
||||||
|
.id = LIMINE_EFI_SYSTEM_TABLE_REQUEST,
|
||||||
|
.revision = 0,
|
||||||
|
.response = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile limine_hhdm_request hhdm_request = {
|
||||||
|
.id = LIMINE_HHDM_REQUEST,
|
||||||
|
.revision = 0,
|
||||||
|
.response = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests")))
|
||||||
|
volatile limine_memmap_request memmap_request = {
|
||||||
|
.id = LIMINE_MEMMAP_REQUEST,
|
||||||
|
.revision = 0,
|
||||||
|
.response = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, define the start and end markers for the Limine requests.
|
||||||
|
// These can also be moved anywhere, to any .cpp file, as seen fit.
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests_start")))
|
||||||
|
volatile LIMINE_REQUESTS_START_MARKER;
|
||||||
|
|
||||||
|
__attribute__((used, section(".limine_requests_end")))
|
||||||
|
volatile LIMINE_REQUESTS_END_MARKER;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCC and Clang reserve the right to generate calls to the following
|
||||||
|
// 4 functions even if they are not directly called.
|
||||||
|
// Implement them as the C specification mandates.
|
||||||
|
// DO NOT remove or rename these functions, or stuff will eventually break!
|
||||||
|
// They CAN be moved to a different .cpp file.
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void *memcpy(void *dest, const void *src, std::size_t n) {
|
||||||
|
std::uint8_t *pdest = static_cast<std::uint8_t *>(dest);
|
||||||
|
const std::uint8_t *psrc = static_cast<const std::uint8_t *>(src);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < n; i++) {
|
||||||
|
pdest[i] = psrc[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memset(void *s, int c, std::size_t n) {
|
||||||
|
std::uint8_t *p = static_cast<std::uint8_t *>(s);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < n; i++) {
|
||||||
|
p[i] = static_cast<uint8_t>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, std::size_t n) {
|
||||||
|
std::uint8_t *pdest = static_cast<std::uint8_t *>(dest);
|
||||||
|
const std::uint8_t *psrc = static_cast<const std::uint8_t *>(src);
|
||||||
|
|
||||||
|
if (src > dest) {
|
||||||
|
for (std::size_t i = 0; i < n; i++) {
|
||||||
|
pdest[i] = psrc[i];
|
||||||
|
}
|
||||||
|
} else if (src < dest) {
|
||||||
|
for (std::size_t i = n; i > 0; i--) {
|
||||||
|
pdest[i-1] = psrc[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *s1, const void *s2, std::size_t n) {
|
||||||
|
const std::uint8_t *p1 = static_cast<const std::uint8_t *>(s1);
|
||||||
|
const std::uint8_t *p2 = static_cast<const std::uint8_t *>(s2);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < n; i++) {
|
||||||
|
if (p1[i] != p2[i]) {
|
||||||
|
return p1[i] < p2[i] ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Halt and catch fire function.
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void hcf() {
|
||||||
|
for (;;) {
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
asm ("hlt");
|
||||||
|
#elif defined (__aarch64__) || defined (__riscv)
|
||||||
|
asm ("wfi");
|
||||||
|
#elif defined (__loongarch64)
|
||||||
|
asm ("idle 0");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following stubs are required by the Itanium C++ ABI (the one we use,
|
||||||
|
// regardless of the "Itanium" nomenclature).
|
||||||
|
// Like the memory functions above, these stubs can be moved to a different .cpp file,
|
||||||
|
// but should not be removed, unless you know what you are doing.
|
||||||
|
extern "C" {
|
||||||
|
int __cxa_atexit(void (*)(void *), void *, void *) { return 0; }
|
||||||
|
void __cxa_pure_virtual() { hcf(); }
|
||||||
|
void *__dso_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extern declarations for global constructors array.
|
||||||
|
extern void (*__init_array[])();
|
||||||
|
extern void (*__init_array_end[])();
|
||||||
|
|
||||||
|
// The following will be our kernel's entry point.
|
||||||
|
// If renaming kmain() to something else, make sure to change the
|
||||||
|
// linker script accordingly.
|
||||||
|
extern "C" void kmain() {
|
||||||
|
// Ensure the bootloader actually understands our base revision (see spec).
|
||||||
|
if (LIMINE_BASE_REVISION_SUPPORTED == false) {
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call global constructors.
|
||||||
|
for (std::size_t i = 0; &__init_array[i] != __init_array_end; i++) {
|
||||||
|
__init_array[i]();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we got a framebuffer.
|
||||||
|
if (framebuffer_request.response == nullptr
|
||||||
|
|| framebuffer_request.response->framebuffer_count < 1) {
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the first framebuffer.
|
||||||
|
limine_framebuffer *framebuffer{framebuffer_request.response->framebuffers[0]};
|
||||||
|
|
||||||
|
// Initialize the terminal
|
||||||
|
Kt::Initialize((uint32_t*)framebuffer->address, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->red_mask_size, framebuffer->red_mask_shift,
|
||||||
|
framebuffer->green_mask_size, framebuffer->green_mask_shift,
|
||||||
|
framebuffer->blue_mask_size, framebuffer->blue_mask_shift);
|
||||||
|
|
||||||
|
#if defined (__x86_64__)
|
||||||
|
Hal::PrepareGDT();
|
||||||
|
Hal::BridgeLoadGDT();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RGB lines
|
||||||
|
for (std::size_t i = 500; i < 800; i++) {
|
||||||
|
volatile std::uint32_t *fb_ptr = static_cast<volatile std::uint32_t *>(framebuffer->address);
|
||||||
|
fb_ptr[i * (framebuffer->pitch / 4) + (i - 5*5)] = 0xFF0000; // Red
|
||||||
|
fb_ptr[i * (framebuffer->pitch / 4) + (i - 10*5)] = 0x00FF00; // Green
|
||||||
|
fb_ptr[i * (framebuffer->pitch / 4) + (i - 15*5)] = 0x0000FF; // Blue
|
||||||
|
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 20*5)] = 0xFF0000; // Red
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 25*5)] = 0x00FF00; // Green
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 30*5)] = 0x0000FF; // Blue
|
||||||
|
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 35*5)] = 0xFF0000; // Red
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 40*5)] = 0x00FF00; // Green
|
||||||
|
// fb_ptr[i * (framebuffer->pitch / 4) + (i - 45*5)] = 0x0000FF; // Blue
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t hhdm_offset = hhdm_request.response->offset;
|
||||||
|
|
||||||
|
kout << "[Mem] HHDM offset: 0x" << base::hex << hhdm_offset << newline;
|
||||||
|
|
||||||
|
Memory::HHDMBase = hhdm_offset;
|
||||||
|
|
||||||
|
if (!system_table_request. response || !system_table_request.response->address) {
|
||||||
|
kerr << "[Efi] EFI System Table not supported" << newline;
|
||||||
|
} else {
|
||||||
|
kout << "[Efi] EFI system table at 0x" << base::hex << (uint64_t)system_table_request.response->address << newline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memmap_request.response != nullptr) {
|
||||||
|
auto result = Memory::Scan(memmap_request.response);
|
||||||
|
auto allocator = Memory::PageAllocator(result);
|
||||||
|
|
||||||
|
kout << "[Mem] Creating PageAllocator for system conventional memory" << newline;
|
||||||
|
Memory::KernelPFA = &allocator;
|
||||||
|
} else {
|
||||||
|
Panic("Guru Meditation Error: System memory map missing!", System::Registers{});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hcf();
|
||||||
|
}
|
||||||
+10
@@ -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 Template
|
||||||
|
# We use the Limine boot protocol.
|
||||||
|
protocol: limine
|
||||||
|
|
||||||
|
# Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located.
|
||||||
|
path: boot():/boot/kernel
|
||||||
Reference in New Issue
Block a user