Add LoongArch support
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("");
