From d9a2fb95a9705385af7af2048fa33259dbb713d1 Mon Sep 17 00:00:00 2001 From: Keegan Saunders <77407552+ksaunders@users.noreply.github.com> Date: Wed, 31 Jul 2024 23:03:09 -0400 Subject: [PATCH] Add LoongArch support --- .gitignore | 1 + CONFIG.md | 3 +- GNUmakefile.in | 34 +++++++- PROTOCOL.md | 44 +++++++++++ README.md | 3 +- bootstrap | 6 +- common/GNUmakefile | 93 ++++++++++++++++++++++ common/efi_thunk.asm_uefi_loongarch64 | 10 +++ common/lib/config.c | 2 + common/lib/elf.c | 18 +++++ common/lib/misc.c | 2 + common/lib/misc.h | 3 + common/lib/panic.s2.c | 2 + common/lib/spinup.asm_loongarch64 | 110 ++++++++++++++++++++++++++ common/lib/trace.s2.c | 4 +- common/linker_uefi_loongarch64.ld.in | 77 ++++++++++++++++++ common/menu.c | 7 ++ common/menu_thunk.asm_loongarch64 | 25 ++++++ common/mm/vmm.c | 92 +++++++++++++++++++++ common/mm/vmm.h | 35 ++++++++ common/protos/limine.c | 30 ++++++- common/sys/cpu.h | 10 +++ common/sys/smp.c | 1 + common/sys/smp.h | 1 + configure.ac | 28 +++++++ host/Makefile | 1 + limine.h | 16 ++++ test.mk | 28 +++++++ test/GNUmakefile | 12 +++ test/limine.c | 7 ++ 30 files changed, 695 insertions(+), 10 deletions(-) create mode 100644 common/efi_thunk.asm_uefi_loongarch64 create mode 100644 common/lib/spinup.asm_loongarch64 create mode 100644 common/linker_uefi_loongarch64.ld.in create mode 100644 common/menu_thunk.asm_loongarch64 diff --git a/.gitignore b/.gitignore index a9c925ed..d7369b8e 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ /common-uefi-x86-64 /common-uefi-aarch64 /common-uefi-riscv64 +/common-uefi-loongarch64 /decompressor-build /stage1.stamp diff --git a/CONFIG.md b/CONFIG.md index 1ed6a49e..204c398b 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -126,6 +126,7 @@ Editor control options: * `MAX_PAGING_MODE`, `MIN_PAGING_MODE` - Limit the maximum and minimum paging modes to one of the following: - x86-64 and aarch64: `4level`, `5level`. - riscv64: `sv39`, `sv48`, `sv57`. + - loongarch64: `4level`. * `PAGING_MODE` - Equivalent to setting both `MAX_PAGING_MODE` and `MIN_PAGING_MODE` to the same value. * multiboot1 and multiboot2 protocols: @@ -194,4 +195,4 @@ Macros must always be placed inside `${...}` where `...` is the arbitrary macro Limine automatically defines these macros: -* `ARCH` - This built-in macro expands to the architecture of the machine. Possible values are: `x86-64`, `ia-32`, `aarch64`, `riscv64`. In the case of IA-32, BIOS or UEFI, the macro will always expand to `x86-64` if the 64-bit extensions are available, else `ia-32`. +* `ARCH` - This built-in macro expands to the architecture of the machine. Possible values are: `x86-64`, `ia-32`, `aarch64`, `riscv64`, `loongarch64`. In the case of IA-32, BIOS or UEFI, the macro will always expand to `x86-64` if the 64-bit extensions are available, else `ia-32`. diff --git a/GNUmakefile.in b/GNUmakefile.in index 07971667..64988416 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -54,6 +54,7 @@ override BUILD_UEFI_X86_64 := @BUILD_UEFI_X86_64@ override BUILD_UEFI_IA32 := @BUILD_UEFI_IA32@ override BUILD_UEFI_AARCH64 := @BUILD_UEFI_AARCH64@ override BUILD_UEFI_RISCV64 := @BUILD_UEFI_RISCV64@ +override BUILD_UEFI_LOONGARCH64 := @BUILD_UEFI_LOONGARCH64@ override BUILD_UEFI_CD := @BUILD_UEFI_CD@ override BUILD_BIOS_PXE := @BUILD_BIOS_PXE@ override BUILD_BIOS_CD := @BUILD_BIOS_CD@ @@ -124,7 +125,7 @@ all: $(call MKESCAPE,$(BINDIR))/Makefile $(MAKE) all1 .PHONY: all1 -all1: $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_UEFI_RISCV64) $(BUILD_BIOS) +all1: $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_UEFI_RISCV64) $(BUILD_UEFI_LOONGARCH64) $(BUILD_BIOS) $(MAKE) '$(call SHESCAPE,$(BINDIR))/limine' $(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' @@ -151,7 +152,7 @@ limine: $(MAKE) '$(call SHESCAPE,$(BINDIR))/limine' .PHONY: clean -clean: limine-bios-clean limine-uefi-ia32-clean limine-uefi-x86-64-clean limine-uefi-aarch64-clean limine-uefi-riscv64-clean +clean: limine-bios-clean limine-uefi-ia32-clean limine-uefi-x86-64-clean limine-uefi-aarch64-clean limine-uefi-riscv64-clean limine-uefi-loongarch64-clean rm -rf '$(call SHESCAPE,$(BINDIR))' '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp' .PHONY: install @@ -184,6 +185,9 @@ endif ifeq ($(BUILD_UEFI_RISCV64),limine-uefi-riscv64) $(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTRISCV64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/' endif +ifeq ($(BUILD_UEFI_LOONGARCH64),limine-uefi-loongarch64) + $(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTLOONGARCH64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/' +endif ifeq ($(BUILD_UEFI_X86_64),limine-uefi-x86-64) $(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTX64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/' endif @@ -227,7 +231,7 @@ endif limine-bios: common-bios decompressor $(MAKE) '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp' -$(call MKESCAPE,$(BINDIR))/limine-uefi-cd.bin: $(if $(BUILD_UEFI_IA32),$(call MKESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI) $(if $(BUILD_UEFI_X86_64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI) $(if $(BUILD_UEFI_AARCH64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI) $(if $(BUILD_UEFI_RISCV64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI) +$(call MKESCAPE,$(BINDIR))/limine-uefi-cd.bin: $(if $(BUILD_UEFI_IA32),$(call MKESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI) $(if $(BUILD_UEFI_X86_64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI) $(if $(BUILD_UEFI_AARCH64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI) $(if $(BUILD_UEFI_RISCV64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI) $(if $(BUILD_UEFI_LOONGARCH64),$(call MKESCAPE,$(BUILDDIR))/common-uefi-loongarch64/BOOTLOONGARCH64.EFI) ifneq ($(BUILD_UEFI_CD),no) $(MKDIR_P) '$(call SHESCAPE,$(BINDIR))' rm -f '$(call SHESCAPE,$(BINDIR))/limine-uefi-cd.bin' @@ -237,6 +241,7 @@ ifneq ($(BUILD_UEFI_CD),no) mkdir -p "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ + cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-loongarch64/BOOTLOONGARCH64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI' "$$LIMINE_UEFI_CD_TMP"/EFI/BOOT/ 2>/dev/null; \ find "$$LIMINE_UEFI_CD_TMP" -exec touch -t $(SOURCE_DATE_EPOCH_TOUCH) '{}' + && \ @@ -284,6 +289,15 @@ limine-uefi-riscv64: $(MAKE) common-uefi-riscv64 $(MAKE) '$(call SHESCAPE,$(BINDIR))/BOOTRISCV64.EFI' +$(call MKESCAPE,$(BINDIR))/BOOTLOONGARCH64.EFI: $(call MKESCAPE,$(BUILDDIR))/common-uefi-loongarch64/BOOTLOONGARCH64.EFI + $(MKDIR_P) '$(call SHESCAPE,$(BINDIR))' + cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-loongarch64/BOOTLOONGARCH64.EFI' '$(call SHESCAPE,$(BINDIR))/' + +.PHONY: limine-uefi-loongarch64 +limine-uefi-loongarch64: + $(MAKE) common-uefi-loongarch64 + $(MAKE) '$(call SHESCAPE,$(BINDIR))/BOOTLOONGARCH64.EFI' + .PHONY: limine-bios-clean limine-bios-clean: common-bios-clean decompressor-clean @@ -299,6 +313,9 @@ limine-uefi-aarch64-clean: common-uefi-aarch64-clean .PHONY: limine-uefi-riscv64-clean limine-uefi-riscv64-clean: common-uefi-riscv64-clean +.PHONY: limine-uefi-loongarch64-clean +limine-uefi-loongarch64-clean: common-uefi-loongarch64-clean + .PHONY: dist dist: rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)" @@ -377,6 +394,17 @@ common-uefi-riscv64: common-uefi-riscv64-clean: rm -rf '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64' +.PHONY: common-uefi-loongarch64 +common-uefi-loongarch64: + $(MAKE) -C '$(call SHESCAPE,$(SRCDIR))/common' all \ + TOOLCHAIN_FILE='$(call SHESCAPE,$(BUILDDIR))/toolchain-files/uefi-loongarch64-toolchain.mk' \ + TARGET=uefi-loongarch64 \ + BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/common-uefi-loongarch64' + +.PHONY: common-uefi-loongarch64-clean +common-uefi-loongarch64-clean: + rm -rf '$(call SHESCAPE,$(BUILDDIR))/common-uefi-loongarch64' + .PHONY: common-uefi-ia32 common-uefi-ia32: $(MAKE) -C '$(call SHESCAPE,$(SRCDIR))/common' all \ diff --git a/PROTOCOL.md b/PROTOCOL.md index c7f5b238..f7bc43ca 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -247,6 +247,15 @@ with the default `PBMT=PMA`. If the `Svpbmt` extension is not available, no PMAs can be overridden (effectively, everything is mapped with `PBMT=PMA`). +### loongarch64 + +The kernel executable, loaded at or above `0xffffffff80000000`, sees all of its +segments mapped using the Coherent Cached (CC) memory access type (MAT). + +All HHDM and identity map memory regions are mapped using the Coherent Cached (CC) +MAT, except for the framebuffer regions, which are mapped in using the +Weakly-ordered UnCached (WUC) MAT. + ## Machine state at entry ### x86-64 @@ -368,6 +377,30 @@ Paging is enabled with the paging mode specified by the Paging Mode feature (see The (A)PLIC, if present, is in an undefined state. +### loongarch64 + +At entry the machine is executing in PLV0. + +`$pc` will be the entry point as defined as part of the executable file format, +unless the Entry Point feature is requested (see below), in which case, the +value of `$pc` is going to be taken from there. + +`$r1`(`$ra`) is set to 0, the kernel must not return from the entry point. + +`$r3`(`$sp`) is set to point to a stack, in bootloader-reclaimable memory, which is +at least 64KiB (65536 bytes) in size, or the size specified in the Stack +Size Request (see below). + +All other general purpose registers, with the exception of `$r12`(`$t0`), are set to 0. + +If booted by EFI/UEFI, boot services are exited. + +`CSR.EENTRY`, `CSR.MERRENTRY` and `CSR.DWM0-3` are in an undefined state. + +`PG` in `CSR.CRMD` is 1, `DA` is 0, `IE` is 0 and `PLV` is 0 but is otherwise unspecified. + +`CSR.TLBRENTRY` is filled with a provided TLB refill handler. + ## Feature List Request IDs are composed of 4 64-bit unsigned integers, but the first 2 are @@ -664,6 +697,17 @@ Values for `mode`, `max_mode`, and `min_mode`: #define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_RISCV_SV57 ``` +### loongarch64 + +Values for `mode`, `max_mode`, and `min_mode`: +```c +#define LIMINE_PAGING_MODE_LOONGARCH64_4LVL 0 + +#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_LOONGARCH64_4LVL +``` + ### SMP (multiprocessor) Feature ID: diff --git a/README.md b/README.md index acf15eb2..b6a626f1 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Donations welcome, but absolutely not mandatory! * x86-64 * aarch64 (arm64) * riscv64 +* loongarch64 ### Supported boot protocols * Linux @@ -53,7 +54,7 @@ opening issues or pull requests related to this. For 32-bit x86 systems, support is only ensured starting with those with Pentium Pro (i686) class CPUs. -All x86-64, aarch64, and riscv64 (UEFI) systems are supported. +All x86-64, aarch64, riscv64 and loongarch64 (UEFI) systems are supported. ## Packaging status diff --git a/bootstrap b/bootstrap index a309776e..bbe976f3 100755 --- a/bootstrap +++ b/bootstrap @@ -76,15 +76,15 @@ if ! test -f version; then done download_by_hash \ - https://github.com/osdev0/freestanding-toolchain/raw/18a5e52483344e117d45738c9afb2b34792cbced/freestanding-toolchain \ + https://github.com/osdev0/freestanding-toolchain/raw/a8b871c2a952f7efe89bd38658f8356bc00d4d29/freestanding-toolchain \ build-aux/freestanding-toolchain \ - b5b66c4e94d463116e549b10e78fb96cdb97530cc165f9b5babe31a97a78e90c + 6e167855d2ea68ebaf1e3d7450f3297bec2ab3f425e56ed11ed7c72396f6b540 chmod +x build-aux/freestanding-toolchain clone_repo_commit \ https://github.com/limine-bootloader/limine-efi.git \ limine-efi \ - d8257094947b0edefe9fa4dcb15255235e3c5193 + f31f942b6f1390777102af28ad0aabde7695a466 clone_repo_commit \ https://github.com/jibsen/tinf.git \ diff --git a/common/GNUmakefile b/common/GNUmakefile index ac5ee3d8..3074e16d 100644 --- a/common/GNUmakefile +++ b/common/GNUmakefile @@ -157,6 +157,21 @@ ifeq ($(TARGET),uefi-riscv64) -D__riscv64 endif +ifeq ($(TARGET),uefi-loongarch64) + override CFLAGS_FOR_TARGET += \ + -fPIE \ + -fshort-wchar \ + -march=loongarch64 \ + -mabi=lp64s + + override CPPFLAGS_FOR_TARGET := \ + -I'$(call SHESCAPE,$(BUILDDIR))/limine-efi/inc' \ + -I'$(call SHESCAPE,$(BUILDDIR))/limine-efi/inc/loongarch64' \ + $(CPPFLAGS_FOR_TARGET) \ + -DUEFI \ + -D__loongarch64 +endif + override LDFLAGS_FOR_TARGET += \ -nostdlib \ -z max-page-size=0x1000 \ @@ -202,6 +217,14 @@ ifeq ($(TARGET),uefi-riscv64) -z text endif +ifeq ($(TARGET),uefi-loongarch64) + override LDFLAGS_FOR_TARGET += \ + -m elf64loongarch \ + --no-relax \ + -pie \ + -z text +endif + override C_FILES := $(shell find . -type f -name '*.c' | LC_ALL=C sort) ifeq ($(TARGET),bios) override ASMX86_FILES := $(shell find . -type f -name '*.asm_x86' | LC_ALL=C sort) @@ -237,6 +260,12 @@ ifeq ($(TARGET),uefi-riscv64) override OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.o) $(ASM64_FILES:.asm_riscv64=.o) $(ASM64U_FILES:.asm_uefi_riscv64=.o)) endif +ifeq ($(TARGET),uefi-loongarch64) + override ASM64_FILES := $(shell find . -type f -name '*.asm_loongarch64' | LC_ALL=C sort) + override ASM64U_FILES := $(shell find . -type f -name '*.asm_uefi_loongarch64' | LC_ALL=C sort) + + override OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.o) $(ASM64_FILES:.asm_loongarch64=.o) $(ASM64U_FILES:.asm_uefi_loongarch64=.o)) +endif override HEADER_DEPS := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.d)) @@ -252,6 +281,8 @@ else ifeq ($(TARGET),uefi-aarch64) all: $(call MKESCAPE,$(BUILDDIR))/BOOTAA64.EFI else ifeq ($(TARGET),uefi-riscv64) all: $(call MKESCAPE,$(BUILDDIR))/BOOTRISCV64.EFI +else ifeq ($(TARGET),uefi-loongarch64) +all: $(call MKESCAPE,$(BUILDDIR))/BOOTLOONGARCH64.EFI endif ifeq ($(TARGET),bios) @@ -490,6 +521,52 @@ $(call MKESCAPE,$(BUILDDIR))/limine.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi '$(call OBJESCAPE,$^)' $(LDFLAGS_FOR_TARGET) -o '$(call SHESCAPE,$@)' endif +ifeq ($(TARGET),uefi-loongarch64) + +$(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf + cd '$(call SHESCAPE,$(BUILDDIR))' && \ + '$(call SHESCAPE,$(SRCDIR))/gensyms.sh' '$(call SHESCAPE,$<)' full 64 '\.text' + $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -c '$(call SHESCAPE,$(BUILDDIR))/full.map.S' -o '$(call SHESCAPE,$@)' + rm -f '$(call SHESCAPE,$(BUILDDIR))/full.map.S' '$(call SHESCAPE,$(BUILDDIR))/full.map.d' + +$(call MKESCAPE,$(BUILDDIR))/BOOTLOONGARCH64.EFI: $(call MKESCAPE,$(BUILDDIR))/limine.elf + $(OBJCOPY_FOR_TARGET) -O binary '$(call SHESCAPE,$<)' '$(call SHESCAPE,$@)' + chmod -x '$(call SHESCAPE,$@)' + dd if=/dev/zero of='$(call SHESCAPE,$@)' bs=4096 count=0 seek=$$(( ($$(wc -c < '$(call SHESCAPE,$@)') + 4095) / 4096 )) + +$(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-loongarch64.S.o: limine-efi + +$(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_loongarch64.c.o: limine-efi + +.PHONY: limine-efi +limine-efi: $(call MKESCAPE,$(BUILDDIR))/limine-efi + $(MAKE) -C '$(call SHESCAPE,$(BUILDDIR))/limine-efi/gnuefi' \ + CC="$(CC_FOR_TARGET)" \ + CFLAGS="$(BASE_CFLAGS)" \ + CPPFLAGS='-nostdinc -isystem $(call SHESCAPE,$(SRCDIR))/../freestanding-headers' \ + ARCH=loongarch64 + +$(call MKESCAPE,$(BUILDDIR))/linker_nomap.ld: linker_uefi_loongarch64.ld.in + $(MKDIR_P) '$(call SHESCAPE,$(BUILDDIR))' + $(CC_FOR_TARGET) -x c -E -P -undef -DLINKER_NOMAP linker_uefi_loongarch64.ld.in -o '$(call SHESCAPE,$(BUILDDIR))/linker_nomap.ld' + +$(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-loongarch64.S.o $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_loongarch64.c.o $(OBJ) + $(MAKE) '$(call SHESCAPE,$(BUILDDIR))/linker_nomap.ld' + $(LD_FOR_TARGET) \ + -T'$(call SHESCAPE,$(BUILDDIR))/linker_nomap.ld' \ + '$(call OBJESCAPE,$^)' $(LDFLAGS_FOR_TARGET) -o '$(call SHESCAPE,$@)' + +$(call MKESCAPE,$(BUILDDIR))/linker.ld: linker_uefi_loongarch64.ld.in + $(MKDIR_P) '$(call SHESCAPE,$(BUILDDIR))' + $(CC_FOR_TARGET) -x c -E -P -undef linker_uefi_loongarch64.ld.in -o '$(call SHESCAPE,$(BUILDDIR))/linker.ld' + +$(call MKESCAPE,$(BUILDDIR))/limine.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-loongarch64.S.o $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_loongarch64.c.o $(OBJ) $(call MKESCAPE,$(BUILDDIR))/full.map.o + $(MAKE) '$(call SHESCAPE,$(BUILDDIR))/linker.ld' + $(LD_FOR_TARGET) \ + -T'$(call SHESCAPE,$(BUILDDIR))/linker.ld' \ + '$(call OBJESCAPE,$^)' $(LDFLAGS_FOR_TARGET) -o '$(call SHESCAPE,$@)' +endif + ifeq ($(TARGET),uefi-ia32) $(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf @@ -557,6 +634,12 @@ $(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/limine-efi $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)' endif +ifeq ($(TARGET),uefi-loongarch64) +$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/limine-efi + $(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')" + $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)' +endif + ifeq ($(TARGET),uefi-ia32) $(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/limine-efi $(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')" @@ -627,6 +710,16 @@ $(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_uefi_riscv64 $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -x assembler-with-cpp -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)' endif +ifeq ($(TARGET),uefi-loongarch64) +$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_loongarch64 + $(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')" + $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -x assembler-with-cpp -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)' + +$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_uefi_loongarch64 + $(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')" + $(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -x assembler-with-cpp -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)' +endif + ifeq ($(TARGET),uefi-ia32) $(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_ia32 $(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')" diff --git a/common/efi_thunk.asm_uefi_loongarch64 b/common/efi_thunk.asm_uefi_loongarch64 new file mode 100644 index 00000000..3184c674 --- /dev/null +++ b/common/efi_thunk.asm_uefi_loongarch64 @@ -0,0 +1,10 @@ +.section .text + +.global efi_main +.extern uefi_entry +efi_main: + move $fp, $r0 + move $ra, $r0 + b uefi_entry + +.section .note.GNU-stack,"",%progbits diff --git a/common/lib/config.c b/common/lib/config.c index 968191c7..6c292d36 100644 --- a/common/lib/config.c +++ b/common/lib/config.c @@ -208,6 +208,8 @@ skip_loop: strcpy(arch_macro->value, "aarch64"); #elif defined (__riscv64) strcpy(arch_macro->value, "riscv64"); +#elif defined (__loongarch64) + strcpy(arch_macro->value, "loongarch64"); #else #error "Unspecified architecture" #endif diff --git a/common/lib/elf.c b/common/lib/elf.c index 0ef2405a..3720d9d7 100644 --- a/common/lib/elf.c +++ b/common/lib/elf.c @@ -42,6 +42,7 @@ #define ARCH_X86_32 0x03 #define ARCH_AARCH64 0xb7 #define ARCH_RISCV 0xf3 +#define ARCH_LOONGARCH 0x102 #define BITS_LE 0x01 #define ELFCLASS64 0x02 #define SHT_RELA 0x00000004 @@ -50,16 +51,20 @@ #define R_X86_64_NONE 0x00000000 #define R_AARCH64_NONE 0x00000000 #define R_RISCV_NONE 0x00000000 +#define R_LARCH_NONE 0x00000000 #define R_X86_64_RELATIVE 0x00000008 #define R_AARCH64_RELATIVE 0x00000403 #define R_RISCV_RELATIVE 0x00000003 +#define R_LARCH_RELATIVE 0x00000003 #define R_X86_64_GLOB_DAT 0x00000006 #define R_AARCH64_GLOB_DAT 0x00000401 #define R_X86_64_JUMP_SLOT 0x00000007 #define R_AARCH64_JUMP_SLOT 0x00000402 #define R_RISCV_JUMP_SLOT 0x00000005 +#define R_LARCH_JUMP_SLOT 0x00000005 #define R_X86_64_64 0x00000001 #define R_RISCV_64 0x00000002 +#define R_LARCH_64 0x00000002 #define R_AARCH64_ABS64 0x00000101 #define R_INTERNAL_RELR 0xfffffff0 @@ -163,6 +168,10 @@ static bool elf64_validate(struct elf64_hdr *hdr) { if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) { panic(true, "elf: Not a riscv64 ELF file."); } +#elif defined (__loongarch64) + if (hdr->machine != ARCH_LOONGARCH && hdr->ident[EI_CLASS] == ELFCLASS64) { + panic(true, "elf: Not a loongarch64 ELF file."); + } #else #error Unknown architecture #endif @@ -183,6 +192,7 @@ int elf_bits(uint8_t *elf) { case ARCH_AARCH64: return 64; case ARCH_RISCV: + case ARCH_LOONGARCH: return (hdr->ident[EI_CLASS] == ELFCLASS64) ? 64 : 32; case ARCH_X86_32: return 32; @@ -465,6 +475,8 @@ end_of_pt_segment: case R_AARCH64_NONE: #elif defined (__riscv64) case R_RISCV_NONE: +#elif defined (__loongarch64) + case R_LARCH_NONE: #endif { break; @@ -475,6 +487,8 @@ end_of_pt_segment: case R_AARCH64_RELATIVE: #elif defined (__riscv64) case R_RISCV_RELATIVE: +#elif defined (__loongarch64) + case R_LARCH_RELATIVE: #endif { *ptr = slide + relocation->r_addend; @@ -493,6 +507,8 @@ end_of_pt_segment: case R_AARCH64_JUMP_SLOT: #elif defined (__riscv64) case R_RISCV_JUMP_SLOT: +#elif defined (__loongarch64) + case R_LARCH_JUMP_SLOT: #endif { struct elf64_sym *s = (void *)elf + symtab_offset + symtab_ent * relocation->r_symbol; @@ -516,6 +532,8 @@ end_of_pt_segment: case R_AARCH64_ABS64: #elif defined (__riscv64) case R_RISCV_64: +#elif defined (__loongarch64) + case R_LARCH_64: #endif { struct elf64_sym *s = (void *)elf + symtab_offset + symtab_ent * relocation->r_symbol; diff --git a/common/lib/misc.c b/common/lib/misc.c index ff47a4a2..8bbbec74 100644 --- a/common/lib/misc.c +++ b/common/lib/misc.c @@ -253,6 +253,8 @@ retry: asm volatile ("msr daifset, #15" ::: "memory"); #elif defined (__riscv64) asm volatile ("csrci sstatus, 0x2" ::: "memory"); +#elif defined (__loongarch64) + asm volatile ("csrxchg $r0, %0, 0x0" :: "r" (0x4) : "memory"); #else #error Unknown architecture #endif diff --git a/common/lib/misc.h b/common/lib/misc.h index 612423c0..ba5e72d2 100644 --- a/common/lib/misc.h +++ b/common/lib/misc.h @@ -95,6 +95,9 @@ noreturn void riscv_spinup(uint64_t entry, uint64_t sp, uint64_t satp, uint64_t #if defined (UEFI) RISCV_EFI_BOOT_PROTOCOL *get_riscv_boot_protocol(void); #endif +#elif defined (__loongarch64) +noreturn void loongarch_spinup(uint64_t entry, uint64_t sp, uint64_t pgdl, + uint64_t pgdh, uint64_t direct_map_offset); #else #error Unknown architecture #endif diff --git a/common/lib/panic.s2.c b/common/lib/panic.s2.c index 7c57315d..dcd76979 100644 --- a/common/lib/panic.s2.c +++ b/common/lib/panic.s2.c @@ -78,6 +78,8 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) { asm ("hlt"); #elif defined (__aarch64__) || defined (__riscv64) asm ("wfi"); +#elif defined (__loongarch64) + asm ("idle 0"); #else #error Unknown architecture #endif diff --git a/common/lib/spinup.asm_loongarch64 b/common/lib/spinup.asm_loongarch64 new file mode 100644 index 00000000..8f7752b8 --- /dev/null +++ b/common/lib/spinup.asm_loongarch64 @@ -0,0 +1,110 @@ +.section .text + +#define PAGE_SHIFT 12 +#define PT_SHIFT (PAGE_SHIFT - 3) +#define PT_BASE(level) (PAGE_SHIFT + PT_SHIFT * (level)) + +#define MAKE_PWCL(Dir2_width, Dir2_base, Dirl_width, Dirl_base, PTwidth, PTbase) \ + ((Dir2_width) << 25) | ((Dir2_base) << 20) | ((Dirl_width) << 15) | \ + ((Dirl_base) << 10) | ((PTwidth) << 5) | ((PTbase) << 0) + +#define MAKE_PWCH(Dir4_width, Dir4_base, Dir3_width, Dir3_base) \ + ((Dir4_width) << 18) | ((Dir4_base) << 12) | ((Dir3_width) << 6) | \ + ((Dir3_base) << 0) + +#define CSR_CRMD 0x00 +#define CSR_EENTRY 0xc +#define CSR_PGDL 0x19 +#define CSR_PGDH 0x1a +#define CSR_PGD 0x1b +#define CSR_PWCL 0x1c +#define CSR_PWCH 0x1d +#define CSR_STLBPS 0x1e +#define CSR_TLBRENTRY 0x88 +#define CSR_TLBRSAVE 0x8b +#define CSR_TLBREHI 0x8e +#define CSR_MERRENTRY 0x93 +#define CSR_DMW0 0x180 +#define CSR_DMW1 0x181 +#define CSR_DMW2 0x182 +#define CSR_DMW3 0x183 + +.global loongarch_spinup +loongarch_spinup: + li.d $t0, 0b010001 // MAT=01, PLV1..3=0, PLV0=1 + csrwr $t0, CSR_DMW0 + csrwr $zero, CSR_DMW1 + csrwr $zero, CSR_DMW2 + csrwr $zero, CSR_DMW3 + + li.d $t0, 0b010110000 // DATF=01, DATM=01, PG=1, DA=0, IE=0, PLV=00 + csrwr $t0, CSR_CRMD + + invtlb 0, $zero, $zero + li.d $t0, PAGE_SHIFT + csrwr $t0, CSR_STLBPS + csrwr $t0, CSR_TLBREHI + + csrwr $a2, CSR_PGDL + csrwr $a3, CSR_PGDH + + li.d $t0, MAKE_PWCL(PT_SHIFT, PT_BASE(2), PT_SHIFT, PT_BASE(1), PT_SHIFT, PT_BASE(0)) + csrwr $t0, CSR_PWCL + li.d $t0, MAKE_PWCH(0, 0, PT_SHIFT, PT_BASE(3)) + csrwr $t0, CSR_PWCH + + la $t0, loongarch_handle_refill + csrwr $t0, CSR_TLBRENTRY + + csrwr $zero, CSR_EENTRY + csrwr $zero, CSR_MERRENTRY + + move $t0, $a0 + move $sp, $a1 + + move $ra, $zero + move $tp, $zero + move $a0, $zero + move $a1, $zero + move $a2, $zero + move $a3, $zero + move $a4, $zero + move $a5, $zero + move $a6, $zero + move $a7, $zero + move $t1, $zero + move $t2, $zero + move $t3, $zero + move $t4, $zero + move $t5, $zero + move $t6, $zero + move $t7, $zero + move $t8, $zero + move $fp, $zero + move $s0, $zero + move $s1, $zero + move $s2, $zero + move $s3, $zero + move $s4, $zero + move $s5, $zero + move $s6, $zero + move $s7, $zero + move $s8, $zero + + jirl $zero, $t0, 0 + +.global loongarch_handle_refill +.align 4 +loongarch_handle_refill: + csrwr $t0, CSR_TLBRSAVE + csrrd $t0, CSR_PGD + lddir $t0, $t0, 3 + lddir $t0, $t0, 2 + lddir $t0, $t0, 1 + ldpte $t0, 0 + ldpte $t0, 1 + tlbfill + csrrd $t0, CSR_TLBRSAVE + ertn + +.section .note.GNU-stack,"",%progbits diff --git a/common/lib/trace.s2.c b/common/lib/trace.s2.c index 2ce6e18e..56885e9a 100644 --- a/common/lib/trace.s2.c +++ b/common/lib/trace.s2.c @@ -56,6 +56,8 @@ void print_stacktrace(size_t *base_ptr) { "mov %0, x29" #elif defined (__riscv64) "mv %0, fp; addi %0, %0, -16" +#elif defined (__loongarch64) + "move %0, $fp; addi.d %0, %0, -16" #endif : "=r"(base_ptr) :: "memory" @@ -75,7 +77,7 @@ void print_stacktrace(size_t *base_ptr) { print(" [%p]\n", ret_addr); if (!old_bp) break; -#if defined (__riscv) +#if defined (__riscv) || defined (__loongarch64) base_ptr = (void *)(old_bp - 16); #else base_ptr = (void*)old_bp; diff --git a/common/linker_uefi_loongarch64.ld.in b/common/linker_uefi_loongarch64.ld.in new file mode 100644 index 00000000..52987702 --- /dev/null +++ b/common/linker_uefi_loongarch64.ld.in @@ -0,0 +1,77 @@ +OUTPUT_FORMAT("elf64-loongarch", "elf64-loongarch", "elf64-loongarch") +OUTPUT_ARCH(loongarch) +ENTRY(_start) + +PHDRS +{ + text PT_LOAD FLAGS(0x05); + rodata PT_LOAD FLAGS(0x04); + data PT_LOAD FLAGS(0x06); + dynamic PT_DYNAMIC FLAGS(0x06); +} + +SECTIONS +{ + . = 0; + __slide = .; + __image_base = ABSOLUTE(.); + __image_size = ABSOLUTE(__image_end - __image_base); + + .text : { + KEEP(*(.pe_header)) + + . = ALIGN(0x1000); + + __text_start = ABSOLUTE(.); + *(.text .text.*) + } :text + + . = ALIGN(0x1000); + __text_end = ABSOLUTE(.); + __text_size = ABSOLUTE(__text_end - __text_start); + + .rodata : { + __reloc_start = ABSOLUTE(.); + *(.dummy_reloc) + + . = ALIGN(0x1000); + __reloc_end = ABSOLUTE(.); + __reloc_size = ABSOLUTE(__reloc_end - __reloc_start); + + __data_start = ABSOLUTE(.); + *(.rodata .rodata.*) + +#ifdef LINKER_NOMAP + full_map = .; +#else + *(.full_map) +#endif + } :rodata + + .data : { + data_begin = .; + *(.data .data.*) + *(.sdata .sdata.*) + *(.sbss .sbss.*) + *(.bss .bss.*) + *(COMMON) + data_end = .; + + *(.no_unwind) + } :data + + .dynamic : { + *(.dynamic) + } :data :dynamic + + __data_end = ABSOLUTE(ALIGN(0x1000)); + __data_size = ABSOLUTE(__data_end - __data_start); + + __image_end = ABSOLUTE(ALIGN(0x1000)); + + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + *(.interp) + } +} diff --git a/common/menu.c b/common/menu.c index 79af29a3..be2a0256 100644 --- a/common/menu.c +++ b/common/menu.c @@ -794,6 +794,8 @@ noreturn void _menu(bool first_run) { "riscv64" #elif defined (__aarch64__) "aarch64" +#elif defined (__loongarch64) + "loongarch64" #endif ", UEFI)"; #endif @@ -1132,7 +1134,12 @@ noreturn void boot(char *config) { if (!strcmp(proto, "limine")) { limine_load(config, cmdline); } else if (!strcmp(proto, "linux")) { +#if defined (__loongarch64) + quiet = false; + print("TODO: Linux is not available on LoongArch64.\n\n"); +#else linux_load(config, cmdline); +#endif } else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) { #if defined (__x86_64__) || defined (__i386__) multiboot1_load(config, cmdline); diff --git a/common/menu_thunk.asm_loongarch64 b/common/menu_thunk.asm_loongarch64 new file mode 100644 index 00000000..831c5663 --- /dev/null +++ b/common/menu_thunk.asm_loongarch64 @@ -0,0 +1,25 @@ +.section .data + +.align 3 +stack_at_first_entry: + .quad 0 + +.section .text + +.global menu +.extern _menu + +menu: + la $t0, stack_at_first_entry + ld.d $t1, $t0, 0 + beqz $t1, 1f + move $sp, $t1 + b 2f +1: + st.d $sp, $t0, 0 +2: + move $fp, $r0 + move $ra, $r0 + b _menu + +.section .note.GNU-stack,"",%progbits diff --git a/common/mm/vmm.c b/common/mm/vmm.c index 2029a7e8..9ce4e8f6 100644 --- a/common/mm/vmm.c +++ b/common/mm/vmm.c @@ -389,6 +389,98 @@ void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_ } } +#elif defined (__loongarch64) + +#define INVALID_PAGE 0 + +#define PT_FLAG_VALID ((uint64_t)1 << 0) +#define PT_FLAG_DIRTY ((uint64_t)1 << 1) +#define PT_FLAG_MAT_CC ((uint64_t)1 << 4) +#define PT_FLAG_MAT_WUC ((uint64_t)1 << 5) +#define PT_FLAG_GLOBAL ((uint64_t)1 << 6) +#define PT_FLAG_HUGE ((uint64_t)1 << 6) +#define PT_FLAG_WRITE ((uint64_t)1 << 8) +#define PT_FLAG_HGLOBAL ((uint64_t)1 << 12) +#define PT_FLAG_NX ((uint64_t)1 << 62) +#define PT_PADDR_MASK ((uint64_t)0x0000FFFFFFFFF000) +#define PT_PADDR_HMASK ((uint64_t)0x0000FFFFFF000000) + +#define PT_TABLE_FLAGS 0 +#define PT_IS_TABLE(x) ((level_idx > 0) && (((x) & PT_FLAG_VALID) == 0) && ((x) != INVALID_PAGE)) +#define PT_IS_LARGE(x) (((x) & (PT_FLAG_HGLOBAL | PT_FLAG_HUGE)) == (PT_FLAG_HGLOBAL | PT_FLAG_HUGE)) +#define PT_TO_VMM_FLAGS(x) (pt_to_vmm_flags_internal(x)) + +#define pte_new(addr, flags) (pt_entry_t)((addr) | (flags)) + +static inline uint64_t pte_addr(uint64_t pte) { + if (PT_IS_LARGE(pte)) { + return pte & PT_PADDR_HMASK; + } + return pte & PT_PADDR_MASK; +} + +static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) { + uint64_t flags = 0; + + if (entry & PT_FLAG_WRITE) + flags |= VMM_FLAG_WRITE; + if (entry & PT_FLAG_NX) + flags |= VMM_FLAG_NOEXEC; + if (entry & PT_FLAG_MAT_WUC) + flags |= VMM_FLAG_FB; + + return flags; +} + +pagemap_t new_pagemap(int paging_mode) { + (void)paging_mode; + pagemap_t pagemap; + pagemap.pgd[0] = ext_mem_alloc(PT_SIZE); + pagemap.pgd[1] = ext_mem_alloc(PT_SIZE); + return pagemap; +} + +void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags, enum page_size pg_size) { + size_t pml4_entry = (virt_addr & ((uint64_t)0x1ff << 39)) >> 39; + size_t pml3_entry = (virt_addr & ((uint64_t)0x1ff << 30)) >> 30; + size_t pml2_entry = (virt_addr & ((uint64_t)0x1ff << 21)) >> 21; + size_t pml1_entry = (virt_addr & ((uint64_t)0x1ff << 12)) >> 12; + + pt_entry_t *pml4, *pml3, *pml2, *pml1; + + bool is_higher_half = virt_addr & ((uint64_t)1 << 63); + + uint64_t real_flags = PT_FLAG_VALID | PT_FLAG_GLOBAL; + if (flags & VMM_FLAG_WRITE) + real_flags |= PT_FLAG_DIRTY | PT_FLAG_WRITE; + if (flags & VMM_FLAG_NOEXEC) + real_flags |= PT_FLAG_NX; + if (flags & VMM_FLAG_FB) + real_flags |= PT_FLAG_MAT_WUC; + else + real_flags |= PT_FLAG_MAT_CC; + + pml4 = pagemap.pgd[is_higher_half]; + + pml3 = get_next_level(pagemap, pml4, virt_addr, pg_size, 3, pml4_entry); + + if (pg_size == Size1GiB) { + pml3[pml3_entry] = pte_new(phys_addr, real_flags | PT_FLAG_HGLOBAL | PT_FLAG_HUGE); + return; + } + + pml2 = get_next_level(pagemap, pml3, virt_addr, pg_size, 2, pml3_entry); + + if (pg_size == Size2MiB) { + pml2[pml2_entry] = pte_new(phys_addr, real_flags | PT_FLAG_HGLOBAL | PT_FLAG_HUGE); + return; + } + + pml1 = get_next_level(pagemap, pml2, virt_addr, pg_size, 1, pml2_entry); + + pml1[pml1_entry] = pte_new(phys_addr, real_flags); +} + #else #error Unknown architecture #endif diff --git a/common/mm/vmm.h b/common/mm/vmm.h index f3ef4d38..144dc24c 100644 --- a/common/mm/vmm.h +++ b/common/mm/vmm.h @@ -121,6 +121,41 @@ int vmm_max_paging_mode(void); pagemap_t new_pagemap(int paging_mode); void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags, enum page_size page_size); +#elif defined (__loongarch64) + +#define paging_mode_va_bits(mode) 48 + +static inline uint64_t paging_mode_higher_half(int paging_mode) { + (void)paging_mode; + return 0xffff000000000000; +} + +// We use fake flags here because these don't properly map onto the +// LoongArch flags. +#define VMM_FLAG_WRITE ((uint64_t)1 << 0) +#define VMM_FLAG_NOEXEC ((uint64_t)1 << 1) +#define VMM_FLAG_FB ((uint64_t)1 << 2) + +#define VMM_MAX_LEVEL 3 + +#define PAGING_MODE_LOONGARCH64_4LVL 0 + +#define PAGING_MODE_MIN PAGING_MODE_LOONGARCH64_4LVL +#define PAGING_MODE_MAX PAGING_MODE_LOONGARCH64_4LVL + +enum page_size { + Size4KiB, + Size2MiB, + Size1GiB +}; + +typedef struct { + void *pgd[2]; +} pagemap_t; + +pagemap_t new_pagemap(int paging_mode); +void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags, enum page_size page_size); + #else #error Unknown architecture #endif diff --git a/common/protos/limine.c b/common/protos/limine.c index 8dc92ba3..e5130d6e 100644 --- a/common/protos/limine.c +++ b/common/protos/limine.c @@ -288,7 +288,9 @@ extern symbol limine_spinup_32; | ((uint64_t)1 << 8) /* TTBR0 Inner WB RW-Allocate */ \ | ((uint64_t)(tsz) << 0)) /* Address bits in TTBR0 */ -#elif !defined (__riscv64) +#elif defined (__riscv64) +#elif defined (__loongarch64) +#else #error Unknown architecture #endif @@ -612,6 +614,12 @@ noreturn void limine_load(char *config, char *cmdline) { if (hhdm_span_top >= ((uint64_t)1 << paging_mode_va_bits(min_supported_paging_mode)) - 2) { goto hhdm_fail; } +#elif defined (__loongarch64) + max_supported_paging_mode = PAGING_MODE_LOONGARCH64_4LVL; + min_supported_paging_mode = PAGING_MODE_LOONGARCH64_4LVL; + if (hhdm_span_top >= ((uint64_t)1 << paging_mode_va_bits(min_supported_paging_mode)) - 2) { + goto hhdm_fail; + } #else #error Unknown architecture #endif @@ -652,6 +660,10 @@ hhdm_fail: } else if (strcasecmp(user_max_paging_mode_s, "sv57") == 0) { user_max_paging_mode = PAGING_MODE_RISCV_SV57; } +#elif defined (__loongarch64) + if (strcasecmp(user_max_paging_mode_s, "4level") == 0) { + user_max_paging_mode = PAGING_MODE_LOONGARCH64_4LVL; + } #endif else { panic(true, "limine: Invalid MAX_PAGING_MODE: `%s`", user_max_paging_mode_s); @@ -687,6 +699,10 @@ hhdm_fail: } else if (strcasecmp(user_min_paging_mode_s, "sv57") == 0) { user_min_paging_mode = PAGING_MODE_RISCV_SV57; } +#elif defined (__loongarch64) + if (strcasecmp(user_min_paging_mode_s, "4level") == 0) { + user_min_paging_mode = PAGING_MODE_LOONGARCH64_4LVL; + } #endif else { panic(true, "limine: Invalid MIN_PAGING_MODE: `%s`", user_min_paging_mode_s); @@ -716,6 +732,8 @@ hhdm_fail: paging_mode = max_supported_paging_mode >= PAGING_MODE_RISCV_SV48 ? PAGING_MODE_RISCV_SV48 : PAGING_MODE_RISCV_SV39; #elif defined (__aarch64__) paging_mode = PAGING_MODE_AARCH64_4LVL; +#elif defined (__loongarch64) + paging_mode = PAGING_MODE_LOONGARCH64_4LVL; #endif #if defined (__riscv64) @@ -1327,6 +1345,9 @@ FEAT_START direct_map_offset); #elif defined (__riscv64) smp_info = init_smp(&cpu_count, pagemap, direct_map_offset); +#elif defined (__loongarch64) + cpu_count = 0; + smp_info = NULL; // TODO: LoongArch SMP #else #error Unknown architecture #endif @@ -1348,6 +1369,7 @@ FEAT_START if (smp_info[i].hartid == bsp_hartid) { continue; } +#elif defined (__loongarch64) #else #error Unknown architecture #endif @@ -1366,6 +1388,7 @@ FEAT_START smp_response->bsp_mpidr = bsp_mpidr; #elif defined (__riscv64) smp_response->bsp_hartid = bsp_hartid; +#elif defined (__loongarch64) #else #error Unknown architecture #endif @@ -1498,6 +1521,11 @@ FEAT_END uint64_t satp = make_satp(pagemap.paging_mode, pagemap.top_level); riscv_spinup(entry_point, reported_stack, satp, direct_map_offset); +#elif defined (__loongarch64) + uint64_t reported_stack = reported_addr(stack); + + loongarch_spinup(entry_point, reported_stack, (uint64_t)pagemap.pgd[0], (uint64_t)pagemap.pgd[1], + direct_map_offset); #else #error Unknown architecture #endif diff --git a/common/sys/cpu.h b/common/sys/cpu.h index fae2ae4a..72a63666 100644 --- a/common/sys/cpu.h +++ b/common/sys/cpu.h @@ -344,6 +344,16 @@ static inline bool riscv_check_isa_extension(const char *ext, size_t *maj, size_ void init_riscv(void); +#elif defined (__loongarch64) + +#define LOONGARCH_CSR_TVAL 0x42 + +static inline uint64_t rdtsc(void) { + uint64_t v; + asm volatile ("csrrd %0, %1" : "=r" (v) : "i" (LOONGARCH_CSR_TVAL)); + return v; +} + #else #error Unknown architecture #endif diff --git a/common/sys/smp.c b/common/sys/smp.c index a8767174..70578fbe 100644 --- a/common/sys/smp.c +++ b/common/sys/smp.c @@ -799,6 +799,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count, pagemap_t pagemap, uint64_t return ret; } +#elif defined (__loongarch64) #else #error Unknown architecture #endif diff --git a/common/sys/smp.h b/common/sys/smp.h index 29960977..b0269f8a 100644 --- a/common/sys/smp.h +++ b/common/sys/smp.h @@ -35,6 +35,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count, pagemap_t pagemap, uint64_t hhdm_offset); +#elif defined (__loongarch64) #else #error Unknown architecture #endif diff --git a/configure.ac b/configure.ac index 300d2009..52c0db14 100644 --- a/configure.ac +++ b/configure.ac @@ -296,6 +296,34 @@ fi AC_SUBST([BUILD_UEFI_RISCV64]) +BUILD_UEFI_LOONGARCH64="$BUILD_ALL" + +AC_ARG_ENABLE([uefi-loongarch64], + [AS_HELP_STRING([--enable-uefi-loongarch64], [enable building the loongarch64 UEFI port])], + [BUILD_UEFI_LOONGARCH64="$enableval"]) + +if test "x$BUILD_UEFI_LOONGARCH64" = "xno"; then + BUILD_UEFI_LOONGARCH64="" +else + mkdir -p toolchain-files + CC="$CC" \ + ARCHITECTURE=loongarch64 \ + FREESTANDING_TOOLCHAIN_SUFFIX="_FOR_TARGET" \ + FREESTANDING_TOOLCHAIN="$TOOLCHAIN_FOR_TARGET" \ + WANT_FREESTANDING_CC=yes \ + FREESTANDING_CC="$CC_FOR_TARGET" \ + WANT_FREESTANDING_LD=yes \ + FREESTANDING_LD="$LD_FOR_TARGET" \ + WANT_FREESTANDING_OBJCOPY=yes \ + FREESTANDING_OBJCOPY="$OBJCOPY_FOR_TARGET" \ + WANT_FREESTANDING_OBJDUMP=yes \ + FREESTANDING_OBJDUMP="$OBJDUMP_FOR_TARGET" \ + "$SRCDIR/build-aux/freestanding-toolchain" 2>"toolchain-files/uefi-loongarch64-toolchain.mk" || exit 1 + BUILD_UEFI_LOONGARCH64="limine-uefi-loongarch64" +fi + +AC_SUBST([BUILD_UEFI_LOONGARCH64]) + BUILD_UEFI_CD="$BUILD_ALL" AC_ARG_ENABLE([uefi-cd], diff --git a/host/Makefile b/host/Makefile index 5544143c..26e60279 100644 --- a/host/Makefile +++ b/host/Makefile @@ -21,6 +21,7 @@ install: all $(INSTALL) -m 644 BOOTIA32.EFI '$(DESTDIR)$(PREFIX)/share/limine/' $(INSTALL) -m 644 BOOTAA64.EFI '$(DESTDIR)$(PREFIX)/share/limine/' $(INSTALL) -m 644 BOOTRISCV64.EFI '$(DESTDIR)$(PREFIX)/share/limine/' + $(INSTALL) -m 644 BOOTLOONGARCH64.EFI '$(DESTDIR)$(PREFIX)/share/limine/' $(INSTALL) -d '$(DESTDIR)$(PREFIX)/include' $(INSTALL) -m 644 limine.h '$(DESTDIR)$(PREFIX)/include/' $(INSTALL) -d '$(DESTDIR)$(PREFIX)/bin' diff --git a/limine.h b/limine.h index 63e8422f..099b6d1e 100644 --- a/limine.h +++ b/limine.h @@ -288,6 +288,11 @@ LIMINE_DEPRECATED_IGNORE_END #define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_RISCV_SV57 #define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_RISCV_SV39 #define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48 +#elif defined (__loongarch__) && (__loongarch_grlen == 64) +#define LIMINE_PAGING_MODE_LOONGARCH64_4LVL 0 +#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#define LIMINE_PAGING_MODE_MIN LIMINE_PAGING_MODE_LOONGARCH64_4LVL +#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_LOONGARCH64_4LVL #else #error Unknown architecture #endif @@ -389,6 +394,17 @@ struct limine_smp_response { LIMINE_PTR(struct limine_smp_info **) cpus; }; +#elif defined (__loongarch__) && (__loongarch_grlen == 64) + +struct limine_smp_info { + uint64_t reserved; +}; + +struct limine_smp_response { + uint64_t cpu_count; + LIMINE_PTR(struct limine_smp_info **) cpus; +}; + #else #error Unknown architecture #endif diff --git a/test.mk b/test.mk index 993e6d4f..334a4fa8 100644 --- a/test.mk +++ b/test.mk @@ -19,6 +19,10 @@ ovmf-ia32: $(MKDIR_P) ovmf-ia32 cd ovmf-ia32 && curl -o OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASEIa32_OVMF.fd +ovmf-loongarch64: + $(MKDIR_P) ovmf-loongarch64 + cd ovmf-loongarch64 && curl -o OVMF.fd https://raw.githubusercontent.com/limine-bootloader/firmware/trunk/loongarch64/QEMU_EFI.fd + .PHONY: test.hdd test.hdd: rm -f test.hdd @@ -264,6 +268,30 @@ uefi-rv64-test: rm -rf test_image loopback_dev qemu-system-riscv64 -m 512M -M virt -cpu rv64 -drive if=pflash,unit=0,format=raw,file=ovmf-rv64/OVMF.fd -net none -smp 4 -device ramfb -device qemu-xhci -device usb-kbd -device virtio-blk-device,drive=hd0 -drive id=hd0,format=raw,file=test.hdd -serial stdio +.PHONY: uefi-loongarch64-test +uefi-loongarch64-test: + $(MAKE) ovmf-loongarch64 + $(MAKE) test-clean + $(MAKE) test.hdd + $(MAKE) limine-uefi-loongarch64 + $(MAKE) -C test TOOLCHAIN_FILE='$(call SHESCAPE,$(BUILDDIR))/toolchain-files/uefi-loongarch64-toolchain.mk' + rm -rf test_image/ + mkdir test_image + sudo losetup -Pf --show test.hdd > loopback_dev + sudo partprobe `cat loopback_dev` + sudo mkfs.fat -F 32 `cat loopback_dev`p1 + sudo mount `cat loopback_dev`p1 test_image + sudo mkdir test_image/boot + sudo cp -rv $(BINDIR)/* test_image/boot/ + sudo cp -rv test/* test_image/boot/ + sudo $(MKDIR_P) test_image/EFI/BOOT + sudo cp $(BINDIR)/BOOTLOONGARCH64.EFI test_image/EFI/BOOT/ + sync + sudo umount test_image/ + sudo losetup -d `cat loopback_dev` + rm -rf test_image loopback_dev + qemu-system-loongarch64 -m 1G -net none -M virt -cpu la464 -device ramfb -device qemu-xhci -device usb-kbd -bios ovmf-loongarch64/OVMF.fd -hda test.hdd -serial stdio + .PHONY: uefi-ia32-test uefi-ia32-test: $(MAKE) ovmf-ia32 diff --git a/test/GNUmakefile b/test/GNUmakefile index 555a676e..a0904780 100644 --- a/test/GNUmakefile +++ b/test/GNUmakefile @@ -24,6 +24,10 @@ ifneq ($(findstring riscv64,$(shell $(CC_FOR_TARGET) -dumpmachine)),) override LDFLAGS += \ -m elf64lriscv endif +ifneq ($(findstring loongarch64,$(shell $(CC_FOR_TARGET) -dumpmachine)),) +override LDFLAGS += \ + -m elf64loongarch +endif override LDFLAGS += \ -Tlinker.ld \ @@ -80,6 +84,14 @@ override LDFLAGS += \ --no-relax endif +ifneq ($(findstring loongarch64,$(shell $(CC_FOR_TARGET) -dumpmachine)),) +override CFLAGS += \ + -march=loongarch64 \ + -mabi=lp64s +override LDFLAGS += \ + --no-relax +endif + override CFLAGS_MB := \ -std=c11 \ -nostdinc \ diff --git a/test/limine.c b/test/limine.c index 38e6e71e..fb4facce 100644 --- a/test/limine.c +++ b/test/limine.c @@ -124,11 +124,13 @@ static volatile struct limine_kernel_address_request kernel_address_request = { .revision = 0, .response = NULL }; +#ifndef __loongarch__ __attribute__((section(".limine_requests"))) static volatile struct limine_smp_request _smp_request = { .id = LIMINE_SMP_REQUEST, .revision = 0, .response = NULL }; +#endif __attribute__((section(".limine_requests"))) static volatile struct limine_dtb_request _dtb_request = { @@ -231,6 +233,8 @@ void ap_entry(struct limine_smp_info *info) { e9_printf("My MPIDR: %x", info->mpidr); #elif defined (__riscv) e9_printf("My Hart ID: %x", info->hartid); +#elif defined (__loongarch__) + (void)info; #endif __atomic_fetch_add(&ctr, 1, __ATOMIC_SEQ_CST); @@ -455,6 +459,8 @@ FEAT_START e9_printf("Boot time: %d", boot_time_response->boot_time); FEAT_END +// TODO: LoongArch SMP +#ifndef __loongarch__ FEAT_START e9_printf(""); if (_smp_request.response == NULL) { @@ -500,6 +506,7 @@ FEAT_START } } FEAT_END +#endif FEAT_START e9_printf("");