mirror of
https://github.com/limine-bootloader/limine
synced 2025-01-21 03:52:04 +03:00
Initial riscv64 port (#274)
* initial riscv64 port * enable Paging Mode feature for all architectures * riscv: add missing protocol docs * riscv: fix tests * docs: clarify `LIMINE_PAGING_MODE_DEFAULT` macro * build: fix whitespace in common/GNUmakefile * riscv: default to Sv48 paging when supported * vmm: make `VMM_MAX_LEVEL` 1-indexed * limine: do not call `reported_addr()` before finaling paging mode smp/riscv: do not overwrite the argument passed to APs * limine/riscv: update default paging mode in limine.h * test/riscv: pad OVMF.fd when downloading it
This commit is contained in:
parent
e91196d452
commit
9274ee656e
5
.github/workflows/check.yml
vendored
5
.github/workflows/check.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: pacman --noconfirm -Syu && pacman --needed --noconfirm -S base-devel git autoconf automake nasm curl mtools llvm clang lld aarch64-linux-gnu-gcc
|
||||
run: pacman --noconfirm -Syu && pacman --needed --noconfirm -S base-devel git autoconf automake nasm curl mtools llvm clang lld aarch64-linux-gnu-gcc riscv64-linux-gnu-gcc
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
@ -26,3 +26,6 @@ jobs:
|
||||
|
||||
- name: Build the bootloader (GNU, aarch64)
|
||||
run: ./bootstrap && ./configure TOOLCHAIN_FOR_TARGET=aarch64-linux-gnu --enable-werror --enable-uefi-aarch64 && make all && make maintainer-clean
|
||||
|
||||
- name: Build the bootloader (GNU, riscv64)
|
||||
run: ./bootstrap && ./configure TOOLCHAIN_FOR_TARGET=riscv64-linux-gnu --enable-werror --enable-uefi-riscv64 && make all && make maintainer-clean
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,5 +40,6 @@
|
||||
/common-uefi-ia32
|
||||
/common-uefi-x86-64
|
||||
/common-uefi-aarch64
|
||||
/common-uefi-riscv64
|
||||
/decompressor-build
|
||||
/stage1.stamp
|
||||
|
@ -40,6 +40,7 @@ override BUILD_BIOS := @BUILD_BIOS@
|
||||
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_CD_EFI := @BUILD_CD_EFI@
|
||||
override BUILD_PXE := @BUILD_PXE@
|
||||
override BUILD_CD := @BUILD_CD@
|
||||
@ -104,7 +105,7 @@ all: $(call MKESCAPE,$(BINDIR))/Makefile
|
||||
$(MAKE) all1
|
||||
|
||||
.PHONY: all1
|
||||
all1: $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_BIOS)
|
||||
all1: $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_UEFI_RISCV64) $(BUILD_BIOS)
|
||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine'
|
||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
|
||||
|
||||
@ -131,7 +132,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
|
||||
clean: limine-bios-clean limine-uefi-ia32-clean limine-uefi-x86-64-clean limine-uefi-aarch64-clean limine-uefi-riscv64-clean
|
||||
rm -rf '$(call SHESCAPE,$(BINDIR))' '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp'
|
||||
|
||||
.PHONY: install
|
||||
@ -161,6 +162,9 @@ endif
|
||||
ifeq ($(BUILD_UEFI_AARCH64),limine-uefi-aarch64)
|
||||
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTAA64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/'
|
||||
endif
|
||||
ifeq ($(BUILD_UEFI_RISCV64),limine-uefi-riscv64)
|
||||
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTRISCV64.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
|
||||
@ -204,7 +208,7 @@ endif
|
||||
limine-bios: common-bios decompressor
|
||||
$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp'
|
||||
|
||||
$(call MKESCAPE,$(BINDIR))/limine-cd-efi.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)
|
||||
$(call MKESCAPE,$(BINDIR))/limine-cd-efi.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)
|
||||
ifneq ($(BUILD_CD_EFI),no)
|
||||
$(MKDIR_P) '$(call SHESCAPE,$(BINDIR))'
|
||||
rm -f '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
|
||||
@ -214,6 +218,8 @@ ifneq ($(BUILD_CD_EFI),no)
|
||||
mmd -D s -i '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin' ::/EFI/BOOT && \
|
||||
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI' ] && \
|
||||
mcopy -D o -i '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin' '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI' ::/EFI/BOOT ) || true ) && \
|
||||
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI' ] && \
|
||||
mcopy -D o -i '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin' '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI' ::/EFI/BOOT ) || true ) && \
|
||||
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI' ] && \
|
||||
mcopy -D o -i '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin' '$(call SHESCAPE,$(BUILDDIR))/common-uefi-x86-64/BOOTX64.EFI' ::/EFI/BOOT ) || true ) && \
|
||||
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI' ] && \
|
||||
@ -252,6 +258,15 @@ limine-uefi-aarch64:
|
||||
$(MAKE) common-uefi-aarch64
|
||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/BOOTAA64.EFI'
|
||||
|
||||
$(call MKESCAPE,$(BINDIR))/BOOTRISCV64.EFI: $(call MKESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI
|
||||
$(MKDIR_P) '$(call SHESCAPE,$(BINDIR))'
|
||||
cp '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64/BOOTRISCV64.EFI' '$(call SHESCAPE,$(BINDIR))/'
|
||||
|
||||
.PHONY: limine-uefi-riscv64
|
||||
limine-uefi-riscv64:
|
||||
$(MAKE) common-uefi-riscv64
|
||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/BOOTRISCV64.EFI'
|
||||
|
||||
.PHONY: limine-bios-clean
|
||||
limine-bios-clean: common-bios-clean decompressor-clean
|
||||
|
||||
@ -264,6 +279,9 @@ limine-uefi-ia32-clean: common-uefi-ia32-clean
|
||||
.PHONY: limine-uefi-aarch64-clean
|
||||
limine-uefi-aarch64-clean: common-uefi-aarch64-clean
|
||||
|
||||
.PHONY: limine-uefi-riscv64-clean
|
||||
limine-uefi-riscv64-clean: common-uefi-riscv64-clean
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)"
|
||||
@ -275,7 +293,7 @@ dist:
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/freestanding-headers/.git"
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.git"
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.gitignore"
|
||||
libgcc_needed="i686 x86_64-no-red-zone aarch64"; \
|
||||
libgcc_needed="i686 x86_64-no-red-zone aarch64 riscv64"; \
|
||||
for f in $$libgcc_needed; do \
|
||||
mv '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/libgcc-$$f.a" '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/libgcc-$$f.a.save"; \
|
||||
done; \
|
||||
@ -328,6 +346,17 @@ common-uefi-aarch64:
|
||||
common-uefi-aarch64-clean:
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64'
|
||||
|
||||
.PHONY: common-uefi-riscv64
|
||||
common-uefi-riscv64:
|
||||
$(MAKE) -C '$(call SHESCAPE,$(SRCDIR))/common' all \
|
||||
TOOLCHAIN_FILE='$(call SHESCAPE,$(BUILDDIR))/toolchain-files/uefi-riscv64-toolchain.mk' \
|
||||
TARGET=uefi-riscv64 \
|
||||
BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64'
|
||||
|
||||
.PHONY: common-uefi-riscv64-clean
|
||||
common-uefi-riscv64-clean:
|
||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))/common-uefi-riscv64'
|
||||
|
||||
.PHONY: common-uefi-ia32
|
||||
common-uefi-ia32:
|
||||
$(MAKE) -C '$(call SHESCAPE,$(SRCDIR))/common' all \
|
||||
|
160
PROTOCOL.md
160
PROTOCOL.md
@ -197,6 +197,34 @@ Size Request (see below).
|
||||
|
||||
All other general purpose registers (including `X29` and `X30`) are set to 0. Vector registers are in an undefined state.
|
||||
|
||||
### riscv64
|
||||
|
||||
At entry the machine is executing in Supervisor mode.
|
||||
|
||||
`pc` will be the entry point as defined as part of the executable file format,
|
||||
unless the an Entry Point feature is requested (see below), in which case,
|
||||
the value of `pc` is going to be taken from there.
|
||||
|
||||
`x1`(`ra`) is undefined, the kernel must not return from the entry point.
|
||||
|
||||
`x2`(`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).
|
||||
|
||||
`x3`(`gp`) is undefined, kernel must load its own global pointer if needed.
|
||||
|
||||
All other general purpose registers, with the exception of `x5`(`t0`), are set to 0.
|
||||
|
||||
If booted by EFI/UEFI, boot services are exited.
|
||||
|
||||
`stvec` is in an undefined state. `sstatus.SIE` and `sie` are set to 0.
|
||||
|
||||
`sstatus.FS` and `sstatus.XS` are both set to `Off`.
|
||||
|
||||
Paging is enable with the paging mode specified by the Paging Mode feature (see below).
|
||||
|
||||
The (A)PLIC, if present, is in an undefined state.
|
||||
|
||||
## Feature List
|
||||
|
||||
Request IDs are composed of 4 64-bit unsigned integers, but the first 2 are
|
||||
@ -632,8 +660,93 @@ struct limine_video_mode {
|
||||
};
|
||||
```
|
||||
|
||||
### Paging Mode Feature
|
||||
|
||||
The Paging Mode feature allows the kernel to control which paging mode is enabled
|
||||
before control is passed to it.
|
||||
|
||||
ID:
|
||||
```c
|
||||
#define LIMINE_PAGING_MODE_REQUEST { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a }
|
||||
```
|
||||
|
||||
Request:
|
||||
```c
|
||||
struct limine_paging_mode_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
struct limine_paging_mode_response *response;
|
||||
uint64_t mode;
|
||||
uint64_t flags;
|
||||
};
|
||||
```
|
||||
|
||||
Both the `mode` and `flags` fields are architecture-specific.
|
||||
|
||||
The `LIMINE_PAGING_MODE_DEFAULT` macro is provided by all architectures to select
|
||||
the default paging mode (see below).
|
||||
|
||||
Response:
|
||||
```c
|
||||
struct limine_paging_mode_response {
|
||||
uint64_t revision;
|
||||
uint64_t mode;
|
||||
uint64_t flags;
|
||||
};
|
||||
```
|
||||
|
||||
The response indicates which paging mode was actually enabled by the bootloader.
|
||||
Kernels must be prepared to handle the case where the requested paging mode is
|
||||
not supported by the hardware.
|
||||
|
||||
#### x86_64
|
||||
|
||||
Values for `mode`:
|
||||
```c
|
||||
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
||||
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
```
|
||||
|
||||
No `flags` are currently defined.
|
||||
|
||||
The default mode (when this request is not provided) is `LIMINE_PAGING_MODE_X86_64_4LVL`.
|
||||
|
||||
#### aarch64
|
||||
|
||||
Values for `mode`:
|
||||
```c
|
||||
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
||||
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
```
|
||||
|
||||
No `flags` are currently defined.
|
||||
|
||||
The default mode (when this request is not provided) is `LIMINE_PAGING_MODE_AARCH64_4LVL`.
|
||||
|
||||
#### riscv64
|
||||
|
||||
Values for `mode`:
|
||||
```c
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
||||
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
||||
```
|
||||
|
||||
No `flags` are currently defined.
|
||||
|
||||
The default mode (when this request is not provided) is `LIMINE_PAGING_MODE_RISCV_SV48`.
|
||||
|
||||
### 5-Level Paging Feature
|
||||
|
||||
Note: *This feature has been deprecated in favor of the [Paging Mode feature](#paging-mode-feature)
|
||||
and will be removed entirely in a future release.*
|
||||
|
||||
ID:
|
||||
```c
|
||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
||||
@ -775,6 +888,53 @@ processor. This field is unused for the structure describing the bootstrap
|
||||
processor.
|
||||
* `extra_argument` - A free for use field.
|
||||
|
||||
#### riscv64
|
||||
|
||||
Response:
|
||||
|
||||
```c
|
||||
struct limine_smp_response {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint64_t bsp_hartid;
|
||||
uint64_t cpu_count;
|
||||
struct limine_smp_info **cpus;
|
||||
};
|
||||
```
|
||||
|
||||
* `flags` - Always zero
|
||||
* `bsp_hartid` - Hart ID of the bootstrap processor as reported by the UEFI RISC-V Boot Protocol or the SBI.
|
||||
* `cpu_count` - How many CPUs are present. It includes the bootstrap processor.
|
||||
* `cpus` - Pointer to an array of `cpu_count` pointers to
|
||||
`struct limine_smp_info` structures.
|
||||
|
||||
Notes: The presence of this request will prompt the bootloader to bootstrap
|
||||
the secondary processors. This will not be done if this request is not present.
|
||||
|
||||
```c
|
||||
struct limine_smp_info;
|
||||
|
||||
typedef void (*limine_goto_address)(struct limine_smp_info *);
|
||||
|
||||
struct limine_smp_info {
|
||||
uint32_t processor_id;
|
||||
uint64_t hartid;
|
||||
uint64_t reserved;
|
||||
limine_goto_address goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
```
|
||||
|
||||
* `processor_id` - ACPI Processor UID as specified by the MADT (always 0 on non-ACPI systems).
|
||||
* `hartid` - Hart ID of the processor as specified by the MADT or Device Tree.
|
||||
* `goto_address` - An atomic write to this field causes the parked CPU to
|
||||
jump to the written address, on a 64KiB (or Stack Size Request size) stack. A pointer to the
|
||||
`struct limine_smp_info` structure of the CPU is passed in `x10`(`a0`). Other than
|
||||
that, the CPU state will be the same as described for the bootstrap
|
||||
processor. This field is unused for the structure describing the bootstrap
|
||||
processor.
|
||||
* `extra_argument` - A free for use field.
|
||||
|
||||
### Memory Map Feature
|
||||
|
||||
ID:
|
||||
|
@ -15,6 +15,7 @@ as the reference implementation for the [Limine boot protocol](/PROTOCOL.md).
|
||||
* IA-32 (32-bit x86)
|
||||
* x86_64
|
||||
* aarch64 (arm64)
|
||||
* riscv64
|
||||
|
||||
### Supported boot protocols
|
||||
* Linux
|
||||
@ -40,7 +41,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 and aarch64 (UEFI) systems are supported.
|
||||
All x86_64, aarch64, and riscv64 (UEFI) systems are supported.
|
||||
|
||||
## Packaging status
|
||||
|
||||
|
@ -30,6 +30,8 @@ else ifeq ($(TARGET),uefi-ia32)
|
||||
override OBJCOPY2ELF_FLAGS := -B i386 -O elf32-i386
|
||||
else ifeq ($(TARGET),uefi-aarch64)
|
||||
override OBJCOPY2ELF_FLAGS := -B aarch64 -O elf64-littleaarch64
|
||||
else ifeq ($(TARGET),uefi-riscv64)
|
||||
override OBJCOPY2ELF_FLAGS := -B riscv64 -O elf64-littleriscv
|
||||
else
|
||||
$(error Invalid target)
|
||||
endif
|
||||
@ -127,6 +129,26 @@ ifeq ($(TARGET),uefi-aarch64)
|
||||
-DUEFI
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),uefi-riscv64)
|
||||
ifeq ($(CC_FOR_TARGET_IS_CLANG),yes)
|
||||
override RISCV_CFLAGS += -march=rv64imac -mabi=lp64
|
||||
else
|
||||
override RISCV_CFLAGS += -march=rv64imac_zicsr_zifencei -mabi=lp64
|
||||
endif
|
||||
|
||||
override CFLAGS_FOR_TARGET += \
|
||||
-fPIE \
|
||||
-fshort-wchar \
|
||||
$(RISCV_CFLAGS)
|
||||
|
||||
override CPPFLAGS_FOR_TARGET := \
|
||||
-I'$(call SHESCAPE,$(BUILDDIR))/limine-efi/inc' \
|
||||
-I'$(call SHESCAPE,$(BUILDDIR))/limine-efi/inc/riscv64' \
|
||||
$(CPPFLAGS_FOR_TARGET) \
|
||||
-DUEFI \
|
||||
-D__riscv64
|
||||
endif
|
||||
|
||||
override LDFLAGS_FOR_TARGET += \
|
||||
-nostdlib \
|
||||
-z max-page-size=0x1000
|
||||
@ -169,6 +191,15 @@ ifeq ($(TARGET),uefi-aarch64)
|
||||
-z text
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),uefi-riscv64)
|
||||
override LDFLAGS_FOR_TARGET += \
|
||||
-m elf64lriscv \
|
||||
-static \
|
||||
-pie \
|
||||
--no-dynamic-linker \
|
||||
-z text
|
||||
endif
|
||||
|
||||
override C_FILES := $(shell find . -type f -name '*.c')
|
||||
ifeq ($(TARGET),bios)
|
||||
override ASMX86_FILES := $(shell find . -type f -name '*.asm_x86')
|
||||
@ -198,6 +229,12 @@ ifeq ($(TARGET),uefi-aarch64)
|
||||
|
||||
override OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.o) $(ASM64_FILES:.asm_aarch64=.o) $(ASM64U_FILES:.asm_uefi_aarch64=.o))
|
||||
endif
|
||||
ifeq ($(TARGET),uefi-riscv64)
|
||||
override ASM64_FILES := $(shell find . -type f -name '*.asm_riscv64')
|
||||
override ASM64U_FILES := $(shell find . -type f -name '*.asm_uefi_riscv64')
|
||||
|
||||
override OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.o) $(ASM64_FILES:.asm_riscv64=.o) $(ASM64U_FILES:.asm_uefi_riscv64=.o))
|
||||
endif
|
||||
|
||||
override HEADER_DEPS := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.d))
|
||||
|
||||
@ -211,6 +248,8 @@ else ifeq ($(TARGET),uefi-ia32)
|
||||
all: $(call MKESCAPE,$(BUILDDIR))/BOOTIA32.EFI
|
||||
else ifeq ($(TARGET),uefi-aarch64)
|
||||
all: $(call MKESCAPE,$(BUILDDIR))/BOOTAA64.EFI
|
||||
else ifeq ($(TARGET),uefi-riscv64)
|
||||
all: $(call MKESCAPE,$(BUILDDIR))/BOOTRISCV64.EFI
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),bios)
|
||||
@ -376,6 +415,45 @@ $(call MKESCAPE,$(BUILDDIR))/limine.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi
|
||||
'$(call OBJESCAPE,$^)' $(LDFLAGS_FOR_TARGET) -o '$(call SHESCAPE,$@)'
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),uefi-riscv64)
|
||||
|
||||
$(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))/BOOTRISCV64.EFI: $(call MKESCAPE,$(BUILDDIR))/limine.elf
|
||||
$(OBJCOPY_FOR_TARGET) -O binary '$(call SHESCAPE,$<)' '$(call SHESCAPE,$@)'
|
||||
|
||||
$(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-riscv64.o $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_riscv64.o: $(call MKESCAPE,$(BUILDDIR))/limine-efi
|
||||
$(MAKE) -C '$(call SHESCAPE,$(BUILDDIR))/limine-efi/gnuefi' \
|
||||
CC="$(CC_FOR_TARGET)" \
|
||||
CFLAGS="$(BASE_CFLAGS) $(RISCV_CFLAGS)" \
|
||||
CPPFLAGS='-nostdinc -I$(call SHESCAPE,$(SRCDIR))/../freestanding-headers' \
|
||||
ARCH=riscv64
|
||||
|
||||
$(call MKESCAPE,$(BUILDDIR))/linker_nomap.ld: linker_uefi_riscv64.ld.in
|
||||
$(MKDIR_P) '$(call SHESCAPE,$(BUILDDIR))'
|
||||
$(CC_FOR_TARGET) -x c -E -P -undef -DLINKER_NOMAP linker_uefi_riscv64.ld.in -o '$(call SHESCAPE,$(BUILDDIR))/linker_nomap.ld'
|
||||
|
||||
$(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-riscv64.o $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_riscv64.o $(OBJ) ../libgcc-binaries/libgcc-riscv64.a
|
||||
$(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_riscv64.ld.in
|
||||
$(MKDIR_P) '$(call SHESCAPE,$(BUILDDIR))'
|
||||
$(CC_FOR_TARGET) -x c -E -P -undef linker_uefi_riscv64.ld.in -o '$(call SHESCAPE,$(BUILDDIR))/linker.ld'
|
||||
|
||||
$(call MKESCAPE,$(BUILDDIR))/limine.elf: $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/crt0-efi-riscv64.o $(call MKESCAPE,$(BUILDDIR))/limine-efi/gnuefi/reloc_riscv64.o $(OBJ) ../libgcc-binaries/libgcc-riscv64.a $(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
|
||||
@ -430,6 +508,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-riscv64)
|
||||
$(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,$@)')"
|
||||
@ -490,6 +574,16 @@ $(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_uefi_aarch64
|
||||
$(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -x assembler-with-cpp -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),uefi-riscv64)
|
||||
$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_riscv64
|
||||
$(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_riscv64
|
||||
$(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,$@)')"
|
||||
|
11
common/efi_thunk.asm_uefi_riscv64
Normal file
11
common/efi_thunk.asm_uefi_riscv64
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
.global efi_main
|
||||
.extern uefi_entry
|
||||
efi_main:
|
||||
.option push
|
||||
.option norelax
|
||||
lla gp, __global_pointer$
|
||||
.option pop
|
||||
mv fp, zero
|
||||
mv ra, zero
|
||||
j uefi_entry
|
@ -28,11 +28,14 @@
|
||||
#define ARCH_X86_64 0x3e
|
||||
#define ARCH_X86_32 0x03
|
||||
#define ARCH_AARCH64 0xb7
|
||||
#define ARCH_RISCV 0xf3
|
||||
#define BITS_LE 0x01
|
||||
#define ELFCLASS64 0x02
|
||||
#define ET_DYN 0x0003
|
||||
#define SHT_RELA 0x00000004
|
||||
#define R_X86_64_RELATIVE 0x00000008
|
||||
#define R_AARCH64_RELATIVE 0x00000403
|
||||
#define R_RISCV_RELATIVE 0x00000003
|
||||
|
||||
/* Indices into identification array */
|
||||
#define EI_CLASS 4
|
||||
@ -103,6 +106,8 @@ int elf_bits(uint8_t *elf) {
|
||||
case ARCH_X86_64:
|
||||
case ARCH_AARCH64:
|
||||
return 64;
|
||||
case ARCH_RISCV:
|
||||
return (hdr->ident[EI_CLASS] == ELFCLASS64) ? 64 : 32;
|
||||
case ARCH_X86_32:
|
||||
return 32;
|
||||
default:
|
||||
@ -226,6 +231,8 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
|
||||
case R_X86_64_RELATIVE:
|
||||
#elif defined (__aarch64__)
|
||||
case R_AARCH64_RELATIVE:
|
||||
#elif defined (__riscv64)
|
||||
case R_RISCV_RELATIVE:
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
@ -281,6 +288,11 @@ bool elf64_load_section(uint8_t *elf, void *buffer, const char *name, size_t lim
|
||||
printv("elf: Not an aarch64 ELF file.\n");
|
||||
return false;
|
||||
}
|
||||
#elif defined (__riscv64)
|
||||
if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
|
||||
printv("elf: Not a riscv64 ELF file.\n");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
@ -416,6 +428,10 @@ bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t
|
||||
if (hdr->machine != ARCH_AARCH64) {
|
||||
panic(true, "elf: Not an aarch64 ELF file.\n");
|
||||
}
|
||||
#elif defined (__riscv64)
|
||||
if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
|
||||
panic(true, "elf: Not a riscv64 ELF file.\n");
|
||||
}
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -109,6 +109,46 @@ uint32_t hex2bin(uint8_t *str, uint32_t size) {
|
||||
|
||||
#if defined (UEFI)
|
||||
|
||||
#if defined (__riscv)
|
||||
|
||||
RISCV_EFI_BOOT_PROTOCOL *get_riscv_boot_protocol(void) {
|
||||
EFI_GUID boot_proto_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
|
||||
RISCV_EFI_BOOT_PROTOCOL *proto;
|
||||
|
||||
// LocateProtocol() is available from EFI version 1.1
|
||||
if (gBS->Hdr.Revision >= ((1 << 16) | 10)) {
|
||||
if (gBS->LocateProtocol(&boot_proto_guid, NULL, (void **)&proto) == EFI_SUCCESS) {
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
|
||||
UINTN bufsz = 0;
|
||||
if (gBS->LocateHandle(ByProtocol, &boot_proto_guid, NULL, &bufsz, NULL) != EFI_BUFFER_TOO_SMALL)
|
||||
return NULL;
|
||||
|
||||
EFI_HANDLE *handles_buf = ext_mem_alloc(bufsz);
|
||||
if (handles_buf == NULL)
|
||||
return NULL;
|
||||
|
||||
if (bufsz < sizeof(EFI_HANDLE))
|
||||
goto error;
|
||||
|
||||
if (gBS->LocateHandle(ByProtocol, &boot_proto_guid, NULL, &bufsz, handles_buf) != EFI_SUCCESS)
|
||||
goto error;
|
||||
|
||||
if (gBS->HandleProtocol(handles_buf[0], &boot_proto_guid, (void **)&proto) != EFI_SUCCESS)
|
||||
goto error;
|
||||
|
||||
pmm_free(handles_buf, bufsz);
|
||||
return proto;
|
||||
|
||||
error:
|
||||
pmm_free(handles_buf, bufsz);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
no_unwind bool efi_boot_services_exited = false;
|
||||
|
||||
bool efi_exit_boot_services(void) {
|
||||
@ -162,6 +202,8 @@ retry:
|
||||
asm volatile ("cli" ::: "memory");
|
||||
#elif defined (__aarch64__)
|
||||
asm volatile ("msr daifset, #15" ::: "memory");
|
||||
#elif defined (__riscv64)
|
||||
asm volatile ("csrci sstatus, 0x2" ::: "memory");
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include <lib/libc.h>
|
||||
#if defined (UEFI)
|
||||
# include <efi.h>
|
||||
# if defined (__riscv64)
|
||||
# include <protocol/riscv/efiboot.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (UEFI)
|
||||
@ -57,7 +60,7 @@ uint64_t strtoui(const char *s, const char **end, int base);
|
||||
|
||||
#if defined (__i386__)
|
||||
void memcpy32to64(uint64_t, uint64_t, uint64_t);
|
||||
#elif defined (__x86_64__) || defined (__aarch64__)
|
||||
#elif defined (__x86_64__) || defined (__aarch64__) || defined(__riscv64)
|
||||
# define memcpy32to64(X, Y, Z) memcpy((void *)(uintptr_t)(X), (void *)(uintptr_t)(Y), Z)
|
||||
#else
|
||||
#error Unknown architecture
|
||||
@ -98,6 +101,11 @@ noreturn void enter_in_current_el(uint64_t entry, uint64_t sp, uint64_t sctlr,
|
||||
noreturn void enter_in_el1(uint64_t entry, uint64_t sp, uint64_t sctlr,
|
||||
uint64_t mair, uint64_t tcr, uint64_t ttbr0,
|
||||
uint64_t ttbr1, uint64_t target_x0);
|
||||
#elif defined (__riscv64)
|
||||
noreturn void riscv_spinup(uint64_t entry, uint64_t sp, uint64_t satp);
|
||||
#if defined (UEFI)
|
||||
RISCV_EFI_BOOT_PROTOCOL *get_riscv_boot_protocol(void);
|
||||
#endif
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -74,7 +74,7 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
|
||||
for (;;) {
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
asm ("hlt");
|
||||
#elif defined (__aarch64__)
|
||||
#elif defined (__aarch64__) || defined (__riscv64)
|
||||
asm ("wfi");
|
||||
#else
|
||||
#error Unknown architecture
|
||||
|
45
common/lib/spinup.asm_riscv64
Normal file
45
common/lib/spinup.asm_riscv64
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
.section .text
|
||||
|
||||
.global riscv_spinup
|
||||
riscv_spinup:
|
||||
|
||||
csrci sstatus, 0x2
|
||||
csrw sie, zero
|
||||
csrw stvec, zero
|
||||
|
||||
mv t0, a0
|
||||
mv sp, a1
|
||||
csrw satp, a2
|
||||
|
||||
mv a0, zero
|
||||
mv a1, zero
|
||||
mv a2, zero
|
||||
mv a3, zero
|
||||
mv a4, zero
|
||||
mv a5, zero
|
||||
mv a6, zero
|
||||
mv a7, zero
|
||||
mv s0, zero
|
||||
mv s1, zero
|
||||
mv s2, zero
|
||||
mv s3, zero
|
||||
mv s4, zero
|
||||
mv s5, zero
|
||||
mv s6, zero
|
||||
mv s7, zero
|
||||
mv s8, zero
|
||||
mv s9, zero
|
||||
mv s10, zero
|
||||
mv s11, zero
|
||||
mv t1, zero
|
||||
mv t2, zero
|
||||
mv t3, zero
|
||||
mv t4, zero
|
||||
mv t5, zero
|
||||
mv t6, zero
|
||||
mv tp, zero
|
||||
mv gp, zero
|
||||
mv ra, zero
|
||||
|
||||
jr t0
|
@ -346,7 +346,7 @@ void _term_write(struct flanterm_context *term, uint64_t buf, uint64_t count) {
|
||||
}
|
||||
|
||||
bool native = false;
|
||||
#if defined (__x86_64__) || defined (__aarch64__)
|
||||
#if defined (__x86_64__) || defined (__aarch64__) || defined (__riscv64)
|
||||
native = true;
|
||||
#elif !defined (__i386__)
|
||||
#error Unknown architecture
|
||||
|
@ -54,6 +54,8 @@ void print_stacktrace(size_t *base_ptr) {
|
||||
"movq %%rbp, %0"
|
||||
#elif defined (__aarch64__)
|
||||
"mov %0, x29"
|
||||
#elif defined (__riscv64)
|
||||
"mv %0, fp; addi %0, %0, -16"
|
||||
#endif
|
||||
: "=r"(base_ptr)
|
||||
:: "memory"
|
||||
@ -73,7 +75,11 @@ void print_stacktrace(size_t *base_ptr) {
|
||||
print(" [%p]\n", ret_addr);
|
||||
if (!old_bp)
|
||||
break;
|
||||
#if defined (__riscv)
|
||||
base_ptr = (void *)(old_bp - 16);
|
||||
#else
|
||||
base_ptr = (void*)old_bp;
|
||||
#endif
|
||||
}
|
||||
print("End of trace. ");
|
||||
}
|
||||
|
94
common/linker_uefi_riscv64.ld.in
Normal file
94
common/linker_uefi_riscv64.ld.in
Normal file
@ -0,0 +1,94 @@
|
||||
OUTPUT_FORMAT(elf64-littleriscv)
|
||||
OUTPUT_ARCH(riscv)
|
||||
ENTRY(_start)
|
||||
|
||||
PHDRS
|
||||
{
|
||||
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ;
|
||||
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ;
|
||||
dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0;
|
||||
__image_base = .;
|
||||
__image_size = __image_end - __image_base;
|
||||
|
||||
.text : {
|
||||
*(.pe_header)
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
*(.text .text.*)
|
||||
. = ALIGN(0x1000);
|
||||
} :text
|
||||
|
||||
__text_start = __image_base + 0x1000;
|
||||
__text_size = SIZEOF(.text) - 0x1000;
|
||||
__text_end = __text_start + __text_size;
|
||||
|
||||
.data.sbat : {
|
||||
*(.data.sbat)
|
||||
. = ALIGN(0x1000);
|
||||
} :data
|
||||
|
||||
PROVIDE(__sbat_sizev = 1);
|
||||
|
||||
__sbat_start = __text_end;
|
||||
__sbat_size = SIZEOF(.data.sbat);
|
||||
__sbat_end = __sbat_start + __sbat_size;
|
||||
|
||||
.data.reloc : {
|
||||
*(.data.reloc)
|
||||
. = ALIGN(0x1000);
|
||||
} :data
|
||||
|
||||
__reloc_start = __sbat_end;
|
||||
__reloc_size = SIZEOF(.data.reloc);
|
||||
__reloc_end = __reloc_start + __reloc_size;
|
||||
|
||||
.data : {
|
||||
*(.rodata .rodata.*)
|
||||
|
||||
#ifdef LINKER_NOMAP
|
||||
full_map = .;
|
||||
#else
|
||||
*(.full_map)
|
||||
#endif
|
||||
|
||||
*(.no_unwind)
|
||||
|
||||
data_begin = .;
|
||||
*(.data .data.*)
|
||||
*(.sdata .sdata.*)
|
||||
__global_pointer$ = .;
|
||||
*(.sbss .sbss.*)
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
data_end = .;
|
||||
} :data
|
||||
|
||||
.rela : {
|
||||
*(.rela .rela.*)
|
||||
} :data
|
||||
|
||||
.got : {
|
||||
*(.got .got.*)
|
||||
} :data
|
||||
|
||||
.dynamic : {
|
||||
*(.dynamic)
|
||||
. = ALIGN(0x1000);
|
||||
} :data :dynamic
|
||||
|
||||
__data_start = __reloc_end;
|
||||
__data_size = SIZEOF(.data) + SIZEOF(.rela) + SIZEOF(.got) + SIZEOF(.dynamic);
|
||||
__data_end = __data_start + __data_size;
|
||||
|
||||
__image_end = __data_end;
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
@ -958,21 +958,21 @@ noreturn void boot(char *config) {
|
||||
linux_load(config, cmdline);
|
||||
#else
|
||||
quiet = false;
|
||||
print("TODO: Linux is not available on aarch64.\n\n");
|
||||
print("TODO: Linux is not available on aarch64 or riscv64.\n\n");
|
||||
#endif
|
||||
} else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
multiboot1_load(config, cmdline);
|
||||
#else
|
||||
quiet = false;
|
||||
print("Multiboot 1 is not available on aarch64.\n\n");
|
||||
print("Multiboot 1 is not available on aarch64 or riscv64.\n\n");
|
||||
#endif
|
||||
} else if (!strcmp(proto, "multiboot2")) {
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
multiboot2_load(config, cmdline);
|
||||
#else
|
||||
quiet = false;
|
||||
print("Multiboot 2 is not available on aarch64.\n\n");
|
||||
print("Multiboot 2 is not available on aarch64 or riscv64.\n\n");
|
||||
#endif
|
||||
} else if (!strcmp(proto, "chainload_next")) {
|
||||
chainload_next(config, cmdline);
|
||||
|
21
common/menu_thunk.asm_riscv64
Normal file
21
common/menu_thunk.asm_riscv64
Normal file
@ -0,0 +1,21 @@
|
||||
.section .data
|
||||
|
||||
.p2align 3
|
||||
stack_at_first_entry:
|
||||
.8byte 0
|
||||
|
||||
.section .text
|
||||
|
||||
.global menu
|
||||
.extern _menu
|
||||
|
||||
menu:
|
||||
lla t0, stack_at_first_entry
|
||||
ld t1, (t0)
|
||||
beqz t1, 1f
|
||||
mv sp, t1
|
||||
j 2f
|
||||
1: sd sp, (t0)
|
||||
2: mv fp, zero
|
||||
mv ra, zero
|
||||
j _menu
|
189
common/mm/vmm.c
189
common/mm/vmm.c
@ -10,6 +10,7 @@
|
||||
|
||||
typedef uint64_t pt_entry_t;
|
||||
|
||||
static uint64_t page_sizes[5];
|
||||
static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||
uint64_t virt, enum page_size desired_sz,
|
||||
size_t level_idx, size_t entry);
|
||||
@ -28,9 +29,12 @@ static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||
#define PT_IS_LARGE(x) (((x) & (PT_FLAG_VALID | PT_FLAG_LARGE)) == (PT_FLAG_VALID | PT_FLAG_LARGE))
|
||||
#define PT_TO_VMM_FLAGS(x) ((x) & (PT_FLAG_WRITE | PT_FLAG_NX))
|
||||
|
||||
pagemap_t new_pagemap(int lv) {
|
||||
#define pte_new(addr, flags) ((pt_entry_t)(addr) | (flags))
|
||||
#define pte_addr(pte) ((pte) & PT_PADDR_MASK)
|
||||
|
||||
pagemap_t new_pagemap(int paging_mode) {
|
||||
pagemap_t pagemap;
|
||||
pagemap.levels = lv;
|
||||
pagemap.levels = paging_mode == PAGING_MODE_X86_64_5LVL ? 5 : 4;
|
||||
pagemap.top_level = ext_mem_alloc(PT_SIZE);
|
||||
return pagemap;
|
||||
}
|
||||
@ -146,6 +150,9 @@ void vmm_assert_4k_pages(void) {
|
||||
#define PT_IS_LARGE(x) (((x) & (PT_FLAG_VALID | PT_FLAG_TABLE)) == PT_FLAG_VALID)
|
||||
#define PT_TO_VMM_FLAGS(x) (pt_to_vmm_flags_internal(x))
|
||||
|
||||
#define pte_new(addr, flags) ((pt_entry_t)(addr) | (flags))
|
||||
#define pte_addr(pte) ((pte) & PT_PADDR_MASK)
|
||||
|
||||
static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) {
|
||||
uint64_t flags = 0;
|
||||
|
||||
@ -159,9 +166,9 @@ static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) {
|
||||
return flags;
|
||||
}
|
||||
|
||||
pagemap_t new_pagemap(int lv) {
|
||||
pagemap_t new_pagemap(int paging_mode) {
|
||||
pagemap_t pagemap;
|
||||
pagemap.levels = lv;
|
||||
pagemap.levels = paging_mode == PAGING_MODE_AARCH64_5LVL ? 5 : 4;
|
||||
pagemap.top_level[0] = ext_mem_alloc(PT_SIZE);
|
||||
pagemap.top_level[1] = ext_mem_alloc(PT_SIZE);
|
||||
return pagemap;
|
||||
@ -221,57 +228,165 @@ level4:
|
||||
pml1[pml1_entry] = (pt_entry_t)(phys_addr | real_flags | PT_FLAG_4K_PAGE);
|
||||
}
|
||||
|
||||
#elif defined (__riscv64)
|
||||
|
||||
#define PT_FLAG_VALID ((uint64_t)1 << 0)
|
||||
#define PT_FLAG_READ ((uint64_t)1 << 1)
|
||||
#define PT_FLAG_WRITE ((uint64_t)1 << 2)
|
||||
#define PT_FLAG_EXEC ((uint64_t)1 << 3)
|
||||
#define PT_FLAG_USER ((uint64_t)1 << 4)
|
||||
#define PT_FLAG_ACCESSED ((uint64_t)1 << 6)
|
||||
#define PT_FLAG_DIRTY ((uint64_t)1 << 7)
|
||||
#define PT_PADDR_MASK ((uint64_t)0x003ffffffffffc00)
|
||||
|
||||
#define PT_FLAG_RWX (PT_FLAG_READ | PT_FLAG_WRITE | PT_FLAG_EXEC)
|
||||
|
||||
#define PT_TABLE_FLAGS PT_FLAG_VALID
|
||||
#define PT_IS_TABLE(x) (((x) & (PT_FLAG_VALID | PT_FLAG_RWX)) == PT_FLAG_VALID)
|
||||
#define PT_IS_LARGE(x) (((x) & (PT_FLAG_VALID | PT_FLAG_RWX)) > PT_FLAG_VALID)
|
||||
#define PT_TO_VMM_FLAGS(x) (pt_to_vmm_flags_internal(x))
|
||||
|
||||
#define pte_new(addr, flags) (((pt_entry_t)(addr) >> 2) | (flags))
|
||||
#define pte_addr(pte) (((pte) & PT_PADDR_MASK) << 2)
|
||||
|
||||
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_EXEC))
|
||||
flags |= VMM_FLAG_NOEXEC;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
uint64_t paging_mode_higher_half(int paging_mode) {
|
||||
switch (paging_mode) {
|
||||
case PAGING_MODE_RISCV_SV39:
|
||||
return 0xffffffc000000000;
|
||||
case PAGING_MODE_RISCV_SV48:
|
||||
return 0xffff800000000000;
|
||||
case PAGING_MODE_RISCV_SV57:
|
||||
return 0xff00000000000000;
|
||||
default:
|
||||
panic(false, "paging_mode_higher_half: invalid mode");
|
||||
}
|
||||
}
|
||||
|
||||
int vmm_max_paging_mode(void)
|
||||
{
|
||||
static int max_level;
|
||||
if (max_level > 0)
|
||||
goto done;
|
||||
|
||||
pt_entry_t *table = ext_mem_alloc(PT_SIZE);
|
||||
|
||||
// Test each paging mode starting with Sv57.
|
||||
// Since writes to `satp` with an invalid MODE have no effect, and pages can be mapped at
|
||||
// any level, we can identity map the entire lower half (very likely guaranteeing everything
|
||||
// this code needs will be mapped) and check if enabling the paging mode succeeds.
|
||||
int lvl = 4;
|
||||
for (; lvl >= 2; lvl--) {
|
||||
pt_entry_t entry = PT_FLAG_ACCESSED | PT_FLAG_DIRTY | PT_FLAG_RWX | PT_FLAG_VALID;
|
||||
for (int i = 0; i < 256; i++) {
|
||||
table[i] = entry;
|
||||
entry += page_sizes[lvl];
|
||||
}
|
||||
|
||||
uint64_t satp = ((uint64_t)(6 + lvl) << 60) | ((uint64_t)table >> 12);
|
||||
csr_write("satp", satp);
|
||||
if (csr_read("satp") == satp) {
|
||||
max_level = lvl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
csr_write("satp", 0);
|
||||
pmm_free(table, PT_SIZE);
|
||||
|
||||
if (max_level == 0)
|
||||
panic(false, "vmm: paging is not supported");
|
||||
done:
|
||||
return 6 + max_level;
|
||||
}
|
||||
|
||||
pagemap_t new_pagemap(int paging_mode) {
|
||||
pagemap_t pagemap;
|
||||
pagemap.paging_mode = paging_mode;
|
||||
pagemap.max_page_size = paging_mode - 6;
|
||||
pagemap.top_level = 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 page_size) {
|
||||
// Truncate the requested page size to the maximum supported.
|
||||
if (page_size > pagemap.max_page_size)
|
||||
page_size = pagemap.max_page_size;
|
||||
|
||||
// Convert VMM_FLAG_* into PT_FLAG_*.
|
||||
// Set the ACCESSED and DIRTY flags to avoid faults.
|
||||
pt_entry_t ptflags = PT_FLAG_VALID | PT_FLAG_READ | PT_FLAG_ACCESSED | PT_FLAG_DIRTY;
|
||||
if (flags & VMM_FLAG_WRITE)
|
||||
ptflags |= PT_FLAG_WRITE;
|
||||
if (!(flags & VMM_FLAG_NOEXEC))
|
||||
ptflags |= PT_FLAG_EXEC;
|
||||
|
||||
// Start at the highest level.
|
||||
// The values of `enum page_size` map to the level index at which that size is mapped.
|
||||
int level = pagemap.max_page_size;
|
||||
pt_entry_t *table = pagemap.top_level;
|
||||
for (;;) {
|
||||
int index = (virt_addr >> (12 + 9 * level)) & 0x1ff;
|
||||
|
||||
// Stop when we reach the level for the requested page size.
|
||||
if (level == (int)page_size) {
|
||||
table[index] = pte_new(phys_addr, ptflags);
|
||||
break;
|
||||
}
|
||||
|
||||
table = get_next_level(pagemap, table, virt_addr, page_size, level, index);
|
||||
level--;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
// Maps level indexes to the page size for that level.
|
||||
_Static_assert(VMM_MAX_LEVEL <= 5, "6-level paging not supported");
|
||||
static uint64_t page_sizes[5] = {
|
||||
0x1000,
|
||||
0x200000,
|
||||
0x40000000,
|
||||
0x800000000000,
|
||||
0x100000000000000,
|
||||
};
|
||||
|
||||
static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||
uint64_t virt, enum page_size desired_sz,
|
||||
size_t level_idx, size_t entry) {
|
||||
pt_entry_t *ret;
|
||||
|
||||
if (PT_IS_TABLE(current_level[entry])) {
|
||||
ret = (pt_entry_t *)(size_t)(current_level[entry] & PT_PADDR_MASK);
|
||||
ret = (pt_entry_t *)(size_t)pte_addr(current_level[entry]);
|
||||
} else {
|
||||
if (PT_IS_LARGE(current_level[entry])) {
|
||||
// We are replacing an existing large page with a smaller page.
|
||||
// Split the previous mapping into mappings of the newly requested size
|
||||
// before performing the requested map operation.
|
||||
|
||||
uint64_t old_page_size, new_page_size;
|
||||
switch (level_idx) {
|
||||
case 2:
|
||||
old_page_size = 0x40000000;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
old_page_size = 0x200000;
|
||||
break;
|
||||
if ((level_idx >= VMM_MAX_LEVEL) || (level_idx == 0))
|
||||
panic(false, "Unexpected level in get_next_level");
|
||||
if (desired_sz >= VMM_MAX_LEVEL)
|
||||
panic(false, "Unexpected page size in get_next_level");
|
||||
|
||||
default:
|
||||
panic(false, "Unexpected level in get_next_level");
|
||||
}
|
||||
|
||||
switch (desired_sz) {
|
||||
case Size1GiB:
|
||||
new_page_size = 0x40000000;
|
||||
break;
|
||||
|
||||
case Size2MiB:
|
||||
new_page_size = 0x200000;
|
||||
break;
|
||||
|
||||
case Size4KiB:
|
||||
new_page_size = 0x1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic(false, "Unexpected page size in get_next_level");
|
||||
}
|
||||
uint64_t old_page_size = page_sizes[level_idx];
|
||||
uint64_t new_page_size = page_sizes[desired_sz];
|
||||
|
||||
// Save all the information from the old entry at this level
|
||||
uint64_t old_flags = PT_TO_VMM_FLAGS(current_level[entry]);
|
||||
uint64_t old_phys = current_level[entry] & PT_PADDR_MASK;
|
||||
uint64_t old_phys = pte_addr(current_level[entry]);
|
||||
uint64_t old_virt = virt & ~(old_page_size - 1);
|
||||
|
||||
if (old_phys & (old_page_size - 1))
|
||||
@ -279,7 +394,7 @@ static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||
|
||||
// Allocate a table for the next level
|
||||
ret = ext_mem_alloc(PT_SIZE);
|
||||
current_level[entry] = (pt_entry_t)(size_t)ret | PT_TABLE_FLAGS;
|
||||
current_level[entry] = pte_new((size_t)ret, PT_TABLE_FLAGS);
|
||||
|
||||
// Recreate the old mapping with smaller pages
|
||||
for (uint64_t i = 0; i < old_page_size; i += new_page_size) {
|
||||
@ -288,11 +403,9 @@ static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||
} else {
|
||||
// Allocate a table for the next level
|
||||
ret = ext_mem_alloc(PT_SIZE);
|
||||
current_level[entry] = (pt_entry_t)(size_t)ret | PT_TABLE_FLAGS;
|
||||
current_level[entry] = pte_new((size_t)ret, PT_TABLE_FLAGS);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,6 +10,19 @@
|
||||
#define VMM_FLAG_NOEXEC ((uint64_t)1 << 63)
|
||||
#define VMM_FLAG_FB ((uint64_t)0)
|
||||
|
||||
#define VMM_MAX_LEVEL 3
|
||||
|
||||
#define PAGING_MODE_X86_64_4LVL 0
|
||||
#define PAGING_MODE_X86_64_5LVL 1
|
||||
|
||||
static inline uint64_t paging_mode_higher_half(int paging_mode) {
|
||||
if (paging_mode == PAGING_MODE_X86_64_5LVL) {
|
||||
return 0xff00000000000000;
|
||||
} else {
|
||||
return 0xffff800000000000;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int levels;
|
||||
void *top_level;
|
||||
@ -32,6 +45,21 @@ void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_
|
||||
#define VMM_FLAG_NOEXEC ((uint64_t)1 << 1)
|
||||
#define VMM_FLAG_FB ((uint64_t)1 << 2)
|
||||
|
||||
#define VMM_MAX_LEVEL 3
|
||||
|
||||
#define PAGING_MODE_AARCH64_4LVL 0
|
||||
#define PAGING_MODE_AARCH64_5LVL 1
|
||||
|
||||
#define paging_mode_va_bits(mode) ((mode) ? 57 : 48)
|
||||
|
||||
static inline uint64_t paging_mode_higher_half(int paging_mode) {
|
||||
if (paging_mode == PAGING_MODE_AARCH64_5LVL) {
|
||||
return 0xff00000000000000;
|
||||
} else {
|
||||
return 0xffff800000000000;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int levels;
|
||||
void *top_level[2];
|
||||
@ -47,8 +75,43 @@ void vmm_assert_4k_pages(void);
|
||||
pagemap_t new_pagemap(int lv);
|
||||
void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags, enum page_size page_size);
|
||||
|
||||
#elif defined (__riscv64)
|
||||
|
||||
// We use fake flags here because these don't properly map onto the
|
||||
// RISC-V 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 5
|
||||
|
||||
#define PAGING_MODE_RISCV_SV39 8
|
||||
#define PAGING_MODE_RISCV_SV48 9
|
||||
#define PAGING_MODE_RISCV_SV57 10
|
||||
|
||||
enum page_size {
|
||||
Size4KiB,
|
||||
Size2MiB,
|
||||
Size1GiB,
|
||||
Size512GiB,
|
||||
Size256TiB
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
enum page_size max_page_size;
|
||||
int paging_mode;
|
||||
void *top_level;
|
||||
} pagemap_t;
|
||||
|
||||
uint64_t paging_mode_higher_half(int paging_mode);
|
||||
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);
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
int vmm_max_paging_mode(void);
|
||||
|
||||
#endif
|
||||
|
@ -35,10 +35,10 @@
|
||||
#define MAX_REQUESTS 128
|
||||
#define MAX_MEMMAP 256
|
||||
|
||||
static pagemap_t build_pagemap(bool level5pg, bool nx, struct elf_range *ranges, size_t ranges_count,
|
||||
static pagemap_t build_pagemap(int paging_mode, bool nx, struct elf_range *ranges, size_t ranges_count,
|
||||
uint64_t physical_base, uint64_t virtual_base,
|
||||
uint64_t direct_map_offset) {
|
||||
pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
|
||||
pagemap_t pagemap = new_pagemap(paging_mode);
|
||||
|
||||
if (ranges_count == 0) {
|
||||
// Map 0 to 2GiB at 0xffffffff80000000
|
||||
@ -183,7 +183,7 @@ extern symbol limine_spinup_32;
|
||||
| ((uint64_t)1 << 8) /* TTBR0 Inner WB RW-Allocate */ \
|
||||
| ((uint64_t)(tsz) << 0)) /* Address bits in TTBR0 */
|
||||
|
||||
#else
|
||||
#elif !defined (__riscv64)
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
@ -191,6 +191,13 @@ static uint64_t physical_base, virtual_base, slide, direct_map_offset;
|
||||
static size_t requests_count;
|
||||
static void **requests;
|
||||
|
||||
static void set_paging_mode(int paging_mode, bool kaslr) {
|
||||
direct_map_offset = paging_mode_higher_half(paging_mode);
|
||||
if (kaslr) {
|
||||
direct_map_offset += (rand64() & ~((uint64_t)0x40000000 - 1)) & 0xfffffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t reported_addr(void *addr) {
|
||||
return (uint64_t)(uintptr_t)addr + direct_map_offset;
|
||||
}
|
||||
@ -408,41 +415,106 @@ noreturn void limine_load(char *config, char *cmdline) {
|
||||
printv("limine: ELF entry point: %X\n", entry_point);
|
||||
printv("limine: Requests count: %u\n", requests_count);
|
||||
|
||||
// 5 level paging feature & HHDM slide
|
||||
bool want_5lv;
|
||||
FEAT_START
|
||||
// Check if 5-level paging is available
|
||||
bool level5pg = false;
|
||||
// TODO(qookie): aarch64 also has optional 5 level paging when using 4K pages
|
||||
// Paging Mode
|
||||
int paging_mode, max_paging_mode;
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
paging_mode = max_paging_mode = PAGING_MODE_X86_64_4LVL;
|
||||
if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
|
||||
printv("limine: CPU has 5-level paging support\n");
|
||||
level5pg = true;
|
||||
max_paging_mode = PAGING_MODE_X86_64_5LVL;
|
||||
}
|
||||
|
||||
#elif defined (__aarch64__)
|
||||
paging_mode = max_paging_mode = PAGING_MODE_AARCH64_4LVL;
|
||||
// TODO(qookie): aarch64 also has optional 5 level paging when using 4K pages
|
||||
|
||||
#elif defined (__riscv64)
|
||||
max_paging_mode = vmm_max_paging_mode();
|
||||
paging_mode = max_paging_mode >= PAGING_MODE_RISCV_SV48 ? PAGING_MODE_RISCV_SV48 : PAGING_MODE_RISCV_SV39;
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
struct limine_5_level_paging_request *lv5pg_request = get_request(LIMINE_5_LEVEL_PAGING_REQUEST);
|
||||
want_5lv = lv5pg_request != NULL && level5pg;
|
||||
#if defined (__riscv64)
|
||||
#define paging_mode_limine_to_vmm(x) (PAGING_MODE_RISCV_SV39 + (x))
|
||||
#define paging_mode_vmm_to_limine(x) ((x) - PAGING_MODE_RISCV_SV39)
|
||||
#else
|
||||
#define paging_mode_limine_to_vmm(x) (x)
|
||||
#define paging_mode_vmm_to_limine(x) (x)
|
||||
#endif
|
||||
|
||||
direct_map_offset = want_5lv ? 0xff00000000000000 : 0xffff800000000000;
|
||||
bool have_paging_mode_request = false;
|
||||
bool paging_mode_set = false;
|
||||
FEAT_START
|
||||
struct limine_paging_mode_request *pm_request = get_request(LIMINE_PAGING_MODE_REQUEST);
|
||||
if (pm_request == NULL)
|
||||
break;
|
||||
have_paging_mode_request = true;
|
||||
|
||||
if (kaslr) {
|
||||
direct_map_offset += (rand64() & ~((uint64_t)0x40000000 - 1)) & 0xfffffffffff;
|
||||
if (pm_request->mode > LIMINE_PAGING_MODE_MAX) {
|
||||
print("warning: ignoring invalid mode in paging mode request\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (want_5lv) {
|
||||
void *lv5pg_response = ext_mem_alloc(sizeof(struct limine_5_level_paging_response));
|
||||
lv5pg_request->response = reported_addr(lv5pg_response);
|
||||
}
|
||||
paging_mode = paging_mode_limine_to_vmm(pm_request->mode);
|
||||
if (paging_mode > max_paging_mode)
|
||||
paging_mode = max_paging_mode;
|
||||
|
||||
set_paging_mode(paging_mode, kaslr);
|
||||
paging_mode_set = true;
|
||||
|
||||
struct limine_paging_mode_response *pm_response =
|
||||
ext_mem_alloc(sizeof(struct limine_paging_mode_response));
|
||||
|
||||
pm_response->mode = paging_mode_vmm_to_limine(paging_mode);
|
||||
pm_request->response = reported_addr(pm_response);
|
||||
|
||||
FEAT_END
|
||||
|
||||
// 5 level paging feature & HHDM slide
|
||||
FEAT_START
|
||||
struct limine_5_level_paging_request *lv5pg_request = get_request(LIMINE_5_LEVEL_PAGING_REQUEST);
|
||||
if (lv5pg_request == NULL)
|
||||
break;
|
||||
|
||||
if (have_paging_mode_request) {
|
||||
print("paging: ignoring 5-level paging request in favor of paging mode request\n");
|
||||
break;
|
||||
}
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
if (max_paging_mode < PAGING_MODE_X86_64_5LVL)
|
||||
break;
|
||||
paging_mode = PAGING_MODE_X86_64_5LVL;
|
||||
#elif defined (__aarch64__)
|
||||
if (max_paging_mode < PAGING_MODE_AARCH64_5LVL)
|
||||
break;
|
||||
paging_mode = PAGING_MODE_AARCH64_5LVL;
|
||||
#elif defined (__riscv64)
|
||||
print("warning: the 5-level paging request is not supported on RISC-V\n");
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
set_paging_mode(paging_mode, kaslr);
|
||||
paging_mode_set = true;
|
||||
|
||||
void *lv5pg_response = ext_mem_alloc(sizeof(struct limine_5_level_paging_response));
|
||||
lv5pg_request->response = reported_addr(lv5pg_response);
|
||||
FEAT_END
|
||||
|
||||
if (!paging_mode_set) {
|
||||
set_paging_mode(paging_mode, kaslr);
|
||||
}
|
||||
|
||||
#if defined (__aarch64__)
|
||||
uint64_t aa64mmfr0;
|
||||
asm volatile ("mrs %0, id_aa64mmfr0_el1" : "=r" (aa64mmfr0));
|
||||
|
||||
uint64_t pa = aa64mmfr0 & 0xF;
|
||||
|
||||
uint64_t tsz = 64 - (want_5lv ? 57 : 48);
|
||||
uint64_t tsz = 64 - paging_mode_va_bits(paging_mode);
|
||||
#endif
|
||||
|
||||
struct limine_file *kf = ext_mem_alloc(sizeof(struct limine_file));
|
||||
@ -795,7 +867,7 @@ term_fail:
|
||||
#if defined (__i386__)
|
||||
actual_callback = (void *)limine_term_callback;
|
||||
limine_term_callback_ptr = terminal_request->callback;
|
||||
#elif defined (__x86_64__) || defined (__aarch64__)
|
||||
#elif defined (__x86_64__) || defined (__aarch64__) || defined (__riscv64)
|
||||
actual_callback = (void *)terminal_request->callback;
|
||||
#else
|
||||
#error Unknown architecture
|
||||
@ -811,7 +883,7 @@ term_fail:
|
||||
|
||||
limine_term_write_ptr = (uintptr_t)term_write_shim;
|
||||
terminal_response->write = (uintptr_t)(void *)limine_term_write_entry;
|
||||
#elif defined (__x86_64__) || defined (__aarch64__)
|
||||
#elif defined (__x86_64__) || defined (__aarch64__) || defined (__riscv64)
|
||||
terminal_response->write = (uintptr_t)term_write_shim;
|
||||
#else
|
||||
#error Unknown architecture
|
||||
@ -1003,9 +1075,22 @@ FEAT_END
|
||||
#endif
|
||||
|
||||
pagemap_t pagemap = {0};
|
||||
pagemap = build_pagemap(want_5lv, nx_available, ranges, ranges_count,
|
||||
pagemap = build_pagemap(paging_mode, nx_available, ranges, ranges_count,
|
||||
physical_base, virtual_base, direct_map_offset);
|
||||
|
||||
#if defined (__riscv64)
|
||||
// Fetch the BSP's Hart ID before exiting boot services.
|
||||
size_t bsp_hartid;
|
||||
bool have_bsp_hartid = false;
|
||||
|
||||
RISCV_EFI_BOOT_PROTOCOL *riscv_boot_proto = get_riscv_boot_protocol();
|
||||
if (riscv_boot_proto != NULL) {
|
||||
if (riscv_boot_proto->GetBootHartId(riscv_boot_proto, &bsp_hartid) == EFI_SUCCESS) {
|
||||
have_bsp_hartid = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (UEFI)
|
||||
efi_exit_boot_services();
|
||||
#endif
|
||||
@ -1022,7 +1107,7 @@ FEAT_START
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
uint32_t bsp_lapic_id;
|
||||
smp_info = init_smp(&cpu_count, &bsp_lapic_id,
|
||||
true, want_5lv,
|
||||
true, paging_mode,
|
||||
pagemap, smp_request->flags & LIMINE_SMP_X2APIC, nx_available,
|
||||
direct_map_offset, true);
|
||||
#elif defined (__aarch64__)
|
||||
@ -1030,6 +1115,13 @@ FEAT_START
|
||||
|
||||
smp_info = init_smp(&cpu_count, &bsp_mpidr,
|
||||
pagemap, LIMINE_MAIR(fb_attr), LIMINE_TCR(tsz, pa), LIMINE_SCTLR);
|
||||
#elif defined (__riscv64)
|
||||
if (!have_bsp_hartid) {
|
||||
printv("smp: failed to get bsp's hart id\n");
|
||||
break;
|
||||
}
|
||||
|
||||
smp_info = init_smp(&cpu_count, bsp_hartid, pagemap);
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
@ -1051,6 +1143,8 @@ FEAT_START
|
||||
smp_response->bsp_lapic_id = bsp_lapic_id;
|
||||
#elif defined (__aarch64__)
|
||||
smp_response->bsp_mpidr = bsp_mpidr;
|
||||
#elif defined (__riscv64)
|
||||
smp_response->bsp_hartid = bsp_hartid;
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
@ -1155,7 +1249,7 @@ FEAT_END
|
||||
uint64_t reported_stack = reported_addr(stack);
|
||||
|
||||
common_spinup(limine_spinup_32, 8,
|
||||
want_5lv, (uint32_t)(uintptr_t)pagemap.top_level,
|
||||
paging_mode, (uint32_t)(uintptr_t)pagemap.top_level,
|
||||
(uint32_t)entry_point, (uint32_t)(entry_point >> 32),
|
||||
(uint32_t)reported_stack, (uint32_t)(reported_stack >> 32),
|
||||
(uint32_t)(uintptr_t)local_gdt, nx_available);
|
||||
@ -1165,6 +1259,11 @@ FEAT_END
|
||||
enter_in_el1(entry_point, (uint64_t)stack, LIMINE_SCTLR, LIMINE_MAIR(fb_attr), LIMINE_TCR(tsz, pa),
|
||||
(uint64_t)pagemap.top_level[0],
|
||||
(uint64_t)pagemap.top_level[1], 0);
|
||||
#elif defined (__riscv64)
|
||||
uint64_t reported_stack = reported_addr(stack);
|
||||
uint64_t satp = make_satp(pagemap.paging_mode, pagemap.top_level);
|
||||
|
||||
riscv_spinup(entry_point, reported_stack, satp);
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -287,6 +287,39 @@ inline int current_el(void) {
|
||||
return v;
|
||||
}
|
||||
|
||||
#elif defined (__riscv64)
|
||||
|
||||
inline uint64_t rdtsc(void) {
|
||||
uint64_t v;
|
||||
asm ("rdtime %0" : "=r"(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
#define csr_read(csr) ({\
|
||||
size_t v;\
|
||||
asm volatile ("csrr %0, " csr : "=r"(v));\
|
||||
v;\
|
||||
})
|
||||
|
||||
#define csr_write(csr, v) ({\
|
||||
size_t old;\
|
||||
asm volatile ("csrrw %0, " csr ", %1" : "=r"(old) : "r"(v));\
|
||||
old;\
|
||||
})
|
||||
|
||||
#define make_satp(mode, ppn) (((size_t)(mode) << 60) | ((size_t)(ppn) >> 12))
|
||||
|
||||
#define locked_read(var) ({ \
|
||||
typeof(*var) locked_read__ret; \
|
||||
asm volatile ( \
|
||||
"ld %0, (%1); fence r, rw" \
|
||||
: "=r"(locked_read__ret) \
|
||||
: "r"(var) \
|
||||
: "memory" \
|
||||
); \
|
||||
locked_read__ret; \
|
||||
})
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
15
common/sys/sbi.asm_riscv64
Normal file
15
common/sys/sbi.asm_riscv64
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
.global sbicall
|
||||
sbicall:
|
||||
mv t0, a0
|
||||
mv t1, a1
|
||||
mv a0, a2
|
||||
mv a1, a3
|
||||
mv a2, a4
|
||||
mv a3, a5
|
||||
mv a4, a6
|
||||
mv a5, a7
|
||||
mv a7, t0
|
||||
mv a6, t1
|
||||
ecall
|
||||
ret
|
32
common/sys/sbi.h
Normal file
32
common/sys/sbi.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef __SYS__SBI_H__
|
||||
#define __SYS__SBI_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct sbiret {
|
||||
long error;
|
||||
long value;
|
||||
};
|
||||
|
||||
#define SBI_SUCCESS ((long)0)
|
||||
#define SBI_ERR_FAILED ((long)-1)
|
||||
#define SBI_ERR_NOT_SUPPORTED ((long)-2)
|
||||
#define SBI_ERR_INVALID_PARAM ((long)-3)
|
||||
#define SBI_ERR_DENIED ((long)-4)
|
||||
#define SBI_ERR_INVALID_ADDRESS ((long)-5)
|
||||
#define SBI_ERR_ALREADY_AVAILABLE ((long)-6)
|
||||
#define SBI_ERR_ALREADY_STARTED ((long)-7)
|
||||
#define SBI_ERR_ALREADY_STOPPED ((long)-8)
|
||||
|
||||
extern struct sbiret sbicall(int eid, int fid, ...);
|
||||
|
||||
#define SBI_EID_HSM 0x48534d
|
||||
|
||||
static inline struct sbiret sbi_hart_start(unsigned long hartid,
|
||||
unsigned long start_addr,
|
||||
unsigned long opaque) {
|
||||
return sbicall(SBI_EID_HSM, 0, hartid, start_addr, opaque);
|
||||
}
|
||||
|
||||
#endif
|
127
common/sys/smp.c
127
common/sys/smp.c
@ -13,6 +13,9 @@
|
||||
#include <mm/pmm.h>
|
||||
#define LIMINE_NO_POINTERS
|
||||
#include <limine.h>
|
||||
#if defined (__riscv64)
|
||||
#include <sys/sbi.h>
|
||||
#endif
|
||||
|
||||
struct madt {
|
||||
struct sdt header;
|
||||
@ -64,6 +67,16 @@ struct madt_gicc {
|
||||
uint16_t spe_overflow_gsiv;
|
||||
} __attribute__((packed));
|
||||
|
||||
// Reference: https://github.com/riscv-non-isa/riscv-acpi/issues/15
|
||||
struct madt_riscv_intc {
|
||||
struct madt_header header;
|
||||
uint8_t version;
|
||||
uint8_t reserved;
|
||||
uint32_t flags;
|
||||
uint64_t hartid;
|
||||
uint32_t acpi_processor_uid;
|
||||
} __attribute__((packed));
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
|
||||
struct trampoline_passed_info {
|
||||
@ -77,7 +90,7 @@ struct trampoline_passed_info {
|
||||
|
||||
static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
||||
struct limine_smp_info *info_struct,
|
||||
bool longmode, bool lv5, uint32_t pagemap,
|
||||
bool longmode, int paging_mode, uint32_t pagemap,
|
||||
bool x2apic, bool nx, uint64_t hhdm, bool wp) {
|
||||
// Prepare the trampoline
|
||||
static void *trampoline = NULL;
|
||||
@ -97,7 +110,7 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
||||
passed_info->smp_tpl_booted_flag = 0;
|
||||
passed_info->smp_tpl_pagemap = pagemap;
|
||||
passed_info->smp_tpl_target_mode = ((uint32_t)x2apic << 2)
|
||||
| ((uint32_t)lv5 << 1)
|
||||
| ((uint32_t)paging_mode << 1)
|
||||
| ((uint32_t)nx << 3)
|
||||
| ((uint32_t)wp << 4)
|
||||
| ((uint32_t)longmode << 0);
|
||||
@ -137,7 +150,7 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
uint32_t *_bsp_lapic_id,
|
||||
bool longmode,
|
||||
bool lv5,
|
||||
int paging_mode,
|
||||
pagemap_t pagemap,
|
||||
bool x2apic,
|
||||
bool nx,
|
||||
@ -244,7 +257,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
|
||||
// Try to start the AP
|
||||
if (!smp_start_ap(lapic->lapic_id, &gdtr, info_struct,
|
||||
longmode, lv5, (uintptr_t)pagemap.top_level,
|
||||
longmode, paging_mode, (uintptr_t)pagemap.top_level,
|
||||
x2apic, nx, hhdm, wp)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
continue;
|
||||
@ -281,7 +294,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
|
||||
// Try to start the AP
|
||||
if (!smp_start_ap(x2lapic->x2apic_id, &gdtr, info_struct,
|
||||
longmode, lv5, (uintptr_t)pagemap.top_level,
|
||||
longmode, paging_mode, (uintptr_t)pagemap.top_level,
|
||||
true, nx, hhdm, wp)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
continue;
|
||||
@ -556,6 +569,110 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif defined (__riscv64)
|
||||
|
||||
struct trampoline_passed_info {
|
||||
uint64_t smp_tpl_booted_flag;
|
||||
uint64_t smp_tpl_satp;
|
||||
uint64_t smp_tpl_info_struct;
|
||||
};
|
||||
|
||||
static bool smp_start_ap(size_t hartid, size_t satp, struct limine_smp_info *info_struct) {
|
||||
static struct trampoline_passed_info passed_info;
|
||||
|
||||
passed_info.smp_tpl_booted_flag = 0;
|
||||
passed_info.smp_tpl_satp = satp;
|
||||
passed_info.smp_tpl_info_struct = (uint64_t)info_struct;
|
||||
|
||||
asm volatile ("" ::: "memory");
|
||||
|
||||
struct sbiret ret = sbi_hart_start(hartid, (size_t)smp_trampoline_start, (size_t)&passed_info);
|
||||
if (ret.error != SBI_SUCCESS)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
if (locked_read(&passed_info.smp_tpl_booted_flag) == 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
size_t bsp_hartid,
|
||||
pagemap_t pagemap) {
|
||||
// No RSDP means no ACPI.
|
||||
// Parsing the Device Tree is the only other method for detecting APs.
|
||||
if (acpi_get_rsdp() == NULL) {
|
||||
printv("smp: ACPI is required to detect APs.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct madt *madt = acpi_get_table("APIC", 0);
|
||||
if (madt == NULL)
|
||||
return NULL;
|
||||
|
||||
size_t max_cpus = 0;
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->header.length;
|
||||
madt_ptr += *(madt_ptr + 1)) {
|
||||
switch (*madt_ptr) {
|
||||
case 0x18: {
|
||||
struct madt_riscv_intc *intc = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
if ((intc->flags & 1) ^ ((intc->flags >> 1) & 1))
|
||||
max_cpus++;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct limine_smp_info *ret = ext_mem_alloc(max_cpus * sizeof(struct limine_smp_info));
|
||||
*cpu_count = 0;
|
||||
|
||||
// Try to start all APs
|
||||
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
|
||||
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->header.length;
|
||||
madt_ptr += *(madt_ptr + 1)) {
|
||||
switch (*madt_ptr) {
|
||||
case 0x18: {
|
||||
struct madt_riscv_intc *intc = (void *)madt_ptr;
|
||||
|
||||
// Check if we can actually try to start the AP
|
||||
if (!((intc->flags & 1) ^ ((intc->flags >> 1) & 1)))
|
||||
continue;
|
||||
|
||||
struct limine_smp_info *info_struct = &ret[*cpu_count];
|
||||
|
||||
info_struct->processor_id = intc->acpi_processor_uid;
|
||||
info_struct->hartid = intc->hartid;
|
||||
|
||||
// Do not try to restart the BSP
|
||||
if (intc->hartid == bsp_hartid) {
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
|
||||
printv("smp: Found candidate AP for bring-up. Hart ID: %u\n", intc->hartid);
|
||||
|
||||
// Try to start the AP.
|
||||
size_t satp = make_satp(pagemap.paging_mode, pagemap.top_level);
|
||||
if (!smp_start_ap(intc->hartid, satp, info_struct)) {
|
||||
print("smp: FAILED to bring-up AP\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
(*cpu_count)++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
@ -13,7 +13,7 @@
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
uint32_t *_bsp_lapic_id,
|
||||
bool longmode,
|
||||
bool lv5,
|
||||
int paging_mode,
|
||||
pagemap_t pagemap,
|
||||
bool x2apic,
|
||||
bool nx,
|
||||
@ -28,6 +28,13 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
uint64_t mair,
|
||||
uint64_t tcr,
|
||||
uint64_t sctlr);
|
||||
|
||||
#elif defined (__riscv64)
|
||||
|
||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||
uint64_t bsp_hartid,
|
||||
pagemap_t pagemap);
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
63
common/sys/smp_trampoline.asm_riscv64
Normal file
63
common/sys/smp_trampoline.asm_riscv64
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
.global smp_trampoline_start
|
||||
smp_trampoline_start:
|
||||
// The AP begins executing here with the following state:
|
||||
// satp = 0
|
||||
// sstatus.SIE = 0
|
||||
// a0 = hartid
|
||||
// a1 = struct trampoline_passed_info *
|
||||
//
|
||||
// All other registers are undefined.
|
||||
|
||||
ld a0, 16(a1)
|
||||
ld t0, 8(a1)
|
||||
csrw satp, t0
|
||||
|
||||
// Tell the BSP we've started.
|
||||
li t0, 1
|
||||
fence rw, w
|
||||
sd t0, (a1)
|
||||
|
||||
// Zero all the things.
|
||||
// Preserve a0
|
||||
mv a1, zero
|
||||
mv a2, zero
|
||||
mv a3, zero
|
||||
mv a4, zero
|
||||
mv a5, zero
|
||||
mv a6, zero
|
||||
mv a7, zero
|
||||
mv s0, zero
|
||||
mv s1, zero
|
||||
mv s2, zero
|
||||
mv s3, zero
|
||||
mv s4, zero
|
||||
mv s5, zero
|
||||
mv s6, zero
|
||||
mv s7, zero
|
||||
mv s8, zero
|
||||
mv s9, zero
|
||||
mv s10, zero
|
||||
mv s11, zero
|
||||
mv t1, zero
|
||||
mv t2, zero
|
||||
mv t3, zero
|
||||
mv t4, zero
|
||||
mv t5, zero
|
||||
mv t6, zero
|
||||
mv tp, zero
|
||||
mv ra, zero
|
||||
|
||||
csrw sie, zero
|
||||
csrw stvec, zero
|
||||
|
||||
// Wait for kernel to tell us where to go.
|
||||
0: .insn i 0x0F, 0, x0, x0, 0x010 // pause
|
||||
ld t0, 24(a0)
|
||||
fence r, rw
|
||||
beqz t0, 0b
|
||||
|
||||
// Load sp from reserved field of info struct
|
||||
ld sp, 16(a0)
|
||||
|
||||
jr t0
|
28
configure.ac
28
configure.ac
@ -212,6 +212,34 @@ fi
|
||||
|
||||
AC_SUBST([BUILD_UEFI_AARCH64])
|
||||
|
||||
BUILD_UEFI_RISCV64="$BUILD_ALL"
|
||||
|
||||
AC_ARG_ENABLE([uefi-riscv64],
|
||||
[AS_HELP_STRING([--enable-uefi-riscv64], [enable building the riscv64 UEFI port])],
|
||||
[BUILD_UEFI_RISCV64="$enableval"])
|
||||
|
||||
if test "x$BUILD_UEFI_RISCV64" = "xno"; then
|
||||
BUILD_UEFI_RISCV64=""
|
||||
else
|
||||
mkdir -p "$BUILDDIR/toolchain-files"
|
||||
CC="$CC" \
|
||||
ARCHITECTURE=riscv64 \
|
||||
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/freestanding-toolchain" >"$BUILDDIR/toolchain-files/uefi-riscv64-toolchain.mk" || exit 1
|
||||
BUILD_UEFI_RISCV64="limine-uefi-riscv64"
|
||||
fi
|
||||
|
||||
AC_SUBST([BUILD_UEFI_RISCV64])
|
||||
|
||||
BUILD_CD_EFI="$BUILD_ALL"
|
||||
|
||||
AC_ARG_ENABLE([uefi-cd],
|
||||
|
64
limine.h
64
limine.h
@ -233,20 +233,62 @@ struct LIMINE_DEPRECATED limine_terminal_request {
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_END
|
||||
|
||||
/* Paging mode */
|
||||
|
||||
#define LIMINE_PAGING_MODE_REQUEST { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a }
|
||||
|
||||
#if defined (__x86_64__) || defined (__i386__)
|
||||
#define LIMINE_PAGING_MODE_X86_64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_X86_64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_X86_64_5LVL
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL
|
||||
#elif defined (__aarch64__)
|
||||
#define LIMINE_PAGING_MODE_AARCH64_4LVL 0
|
||||
#define LIMINE_PAGING_MODE_AARCH64_5LVL 1
|
||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_AARCH64_5LVL
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL
|
||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV39 0
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV48 1
|
||||
#define LIMINE_PAGING_MODE_RISCV_SV57 2
|
||||
#define LIMINE_PAGING_MODE_MAX LIMINE_PAGING_MODE_RISCV_SV57
|
||||
#define LIMINE_PAGING_MODE_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
||||
struct limine_paging_mode_response {
|
||||
uint64_t revision;
|
||||
uint64_t mode;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
struct limine_paging_mode_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_paging_mode_response *) response;
|
||||
uint64_t mode;
|
||||
uint64_t flags;
|
||||
};
|
||||
|
||||
/* 5-level paging */
|
||||
|
||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
||||
|
||||
struct limine_5_level_paging_response {
|
||||
LIMINE_DEPRECATED_IGNORE_START
|
||||
|
||||
struct LIMINE_DEPRECATED limine_5_level_paging_response {
|
||||
uint64_t revision;
|
||||
};
|
||||
|
||||
struct limine_5_level_paging_request {
|
||||
struct LIMINE_DEPRECATED limine_5_level_paging_request {
|
||||
uint64_t id[4];
|
||||
uint64_t revision;
|
||||
LIMINE_PTR(struct limine_5_level_paging_response *) response;
|
||||
};
|
||||
|
||||
LIMINE_DEPRECATED_IGNORE_END
|
||||
|
||||
/* SMP */
|
||||
|
||||
#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||
@ -294,6 +336,24 @@ struct limine_smp_response {
|
||||
LIMINE_PTR(struct limine_smp_info **) cpus;
|
||||
};
|
||||
|
||||
#elif defined (__riscv) && (__riscv_xlen == 64)
|
||||
|
||||
struct limine_smp_info {
|
||||
uint32_t processor_id;
|
||||
uint64_t hartid;
|
||||
uint64_t reserved;
|
||||
LIMINE_PTR(limine_goto_address) goto_address;
|
||||
uint64_t extra_argument;
|
||||
};
|
||||
|
||||
struct limine_smp_response {
|
||||
uint64_t revision;
|
||||
uint32_t flags;
|
||||
uint64_t bsp_hartid;
|
||||
uint64_t cpu_count;
|
||||
LIMINE_PTR(struct limine_smp_info **) cpus;
|
||||
};
|
||||
|
||||
#else
|
||||
#error Unknown architecture
|
||||
#endif
|
||||
|
28
test.mk
28
test.mk
@ -11,6 +11,10 @@ ovmf-aa64:
|
||||
mkdir -p ovmf-aa64
|
||||
cd ovmf-aa64 && curl -o OVMF-AA64.zip https://efi.akeo.ie/OVMF/OVMF-AA64.zip && 7z x OVMF-AA64.zip
|
||||
|
||||
ovmf-rv64:
|
||||
mkdir -p ovmf-rv64
|
||||
cd ovmf-rv64 && curl -o OVMF.fd https://retrage.github.io/edk2-nightly/bin/RELEASERISCV64_VIRT.fd && dd if=/dev/zero of=OVMF.fd bs=1 count=0 seek=33554432
|
||||
|
||||
ovmf-ia32:
|
||||
$(MKDIR_P) ovmf-ia32
|
||||
cd ovmf-ia32 && curl -o OVMF-IA32.zip https://efi.akeo.ie/OVMF/OVMF-IA32.zip && 7z x OVMF-IA32.zip
|
||||
@ -236,6 +240,30 @@ uefi-aa64-test:
|
||||
rm -rf test_image loopback_dev
|
||||
qemu-system-aarch64 -m 512M -M virt -cpu cortex-a72 -bios ovmf-aa64/OVMF.fd -net none -smp 4 -device ramfb -device qemu-xhci -device usb-kbd -hda test.hdd -serial stdio
|
||||
|
||||
.PHONY: uefi-rv64-test
|
||||
uefi-rv64-test:
|
||||
$(MAKE) ovmf-rv64
|
||||
$(MAKE) test-clean
|
||||
$(MAKE) test.hdd
|
||||
$(MAKE) limine-uefi-riscv64
|
||||
$(MAKE) -C test TOOLCHAIN_FILE='$(call SHESCAPE,$(BUILDDIR))/toolchain-files/uefi-riscv64-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)/BOOTRISCV64.EFI test_image/EFI/BOOT/
|
||||
sync
|
||||
sudo umount test_image/
|
||||
sudo losetup -d `cat loopback_dev`
|
||||
rm -rf test_image loopback_dev
|
||||
qemu-system-riscv64 -m 512M -M virt -cpu rv64 -drive if=pflash,unit=1,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-ia32-test
|
||||
uefi-ia32-test:
|
||||
$(MAKE) ovmf-ia32
|
||||
|
@ -151,6 +151,16 @@ struct limine_dtb_request _dtb_request = {
|
||||
__attribute__((section(".limine_reqs")))
|
||||
void *dtb_req = &_dtb_request;
|
||||
|
||||
struct limine_paging_mode_request _pm_request = {
|
||||
.id = LIMINE_PAGING_MODE_REQUEST,
|
||||
.revision = 0, .response = NULL,
|
||||
.mode = LIMINE_PAGING_MODE_DEFAULT,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
__attribute__((section(".limine_reqs")))
|
||||
void *pm_req = &_pm_request;
|
||||
|
||||
static char *get_memmap_type(uint64_t type) {
|
||||
switch (type) {
|
||||
case LIMINE_MEMMAP_USABLE:
|
||||
@ -216,6 +226,8 @@ void ap_entry(struct limine_smp_info *info) {
|
||||
#elif defined (__aarch64__)
|
||||
e9_printf("My GIC CPU Interface no.: %x", info->gic_iface_no);
|
||||
e9_printf("My MPIDR: %x", info->mpidr);
|
||||
#elif defined (__riscv)
|
||||
e9_printf("My Hart ID: %x", info->hartid);
|
||||
#endif
|
||||
|
||||
__atomic_fetch_add(&ctr, 1, __ATOMIC_SEQ_CST);
|
||||
@ -412,6 +424,8 @@ FEAT_START
|
||||
e9_printf("BSP LAPIC ID: %x", smp_response->bsp_lapic_id);
|
||||
#elif defined (__aarch64__)
|
||||
e9_printf("BSP MPIDR: %x", smp_response->bsp_mpidr);
|
||||
#elif defined (__riscv)
|
||||
e9_printf("BSP Hart ID: %x", smp_response->bsp_hartid);
|
||||
#endif
|
||||
e9_printf("CPU count: %d", smp_response->cpu_count);
|
||||
for (size_t i = 0; i < smp_response->cpu_count; i++) {
|
||||
@ -422,6 +436,8 @@ FEAT_START
|
||||
#elif defined (__aarch64__)
|
||||
e9_printf("GIC CPU Interface no.: %x", cpu->gic_iface_no);
|
||||
e9_printf("MPIDR: %x", cpu->mpidr);
|
||||
#elif defined (__riscv)
|
||||
e9_printf("Hart ID: %x", cpu->hartid);
|
||||
#endif
|
||||
|
||||
|
||||
@ -429,6 +445,8 @@ FEAT_START
|
||||
if (cpu->lapic_id != smp_response->bsp_lapic_id) {
|
||||
#elif defined (__aarch64__)
|
||||
if (cpu->mpidr != smp_response->bsp_mpidr) {
|
||||
#elif defined (__riscv)
|
||||
if (cpu->hartid != smp_response->bsp_hartid) {
|
||||
#endif
|
||||
uint32_t old_ctr = __atomic_load_n(&ctr, __ATOMIC_SEQ_CST);
|
||||
|
||||
@ -469,5 +487,17 @@ FEAT_START
|
||||
e9_printf("Device tree blob pointer: %x", dtb_response->dtb_ptr);
|
||||
FEAT_END
|
||||
|
||||
FEAT_START
|
||||
e9_printf("");
|
||||
if (_pm_request.response == NULL) {
|
||||
e9_printf("Paging mode not passed");
|
||||
break;
|
||||
}
|
||||
struct limine_paging_mode_response *pm_response = _pm_request.response;
|
||||
e9_printf("Paging mode feature, revision %d", pm_response->revision);
|
||||
e9_printf(" mode: %d", pm_response->mode);
|
||||
e9_printf(" flags: %x", pm_response->flags);
|
||||
FEAT_END
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user