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
|
@ -10,7 +10,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Install dependencies
|
- 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
|
- name: Checkout code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
@ -26,3 +26,6 @@ jobs:
|
||||||
|
|
||||||
- name: Build the bootloader (GNU, aarch64)
|
- 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
|
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
|
||||||
|
|
|
@ -40,5 +40,6 @@
|
||||||
/common-uefi-ia32
|
/common-uefi-ia32
|
||||||
/common-uefi-x86-64
|
/common-uefi-x86-64
|
||||||
/common-uefi-aarch64
|
/common-uefi-aarch64
|
||||||
|
/common-uefi-riscv64
|
||||||
/decompressor-build
|
/decompressor-build
|
||||||
/stage1.stamp
|
/stage1.stamp
|
||||||
|
|
|
@ -40,6 +40,7 @@ override BUILD_BIOS := @BUILD_BIOS@
|
||||||
override BUILD_UEFI_X86_64 := @BUILD_UEFI_X86_64@
|
override BUILD_UEFI_X86_64 := @BUILD_UEFI_X86_64@
|
||||||
override BUILD_UEFI_IA32 := @BUILD_UEFI_IA32@
|
override BUILD_UEFI_IA32 := @BUILD_UEFI_IA32@
|
||||||
override BUILD_UEFI_AARCH64 := @BUILD_UEFI_AARCH64@
|
override BUILD_UEFI_AARCH64 := @BUILD_UEFI_AARCH64@
|
||||||
|
override BUILD_UEFI_RISCV64 := @BUILD_UEFI_RISCV64@
|
||||||
override BUILD_CD_EFI := @BUILD_CD_EFI@
|
override BUILD_CD_EFI := @BUILD_CD_EFI@
|
||||||
override BUILD_PXE := @BUILD_PXE@
|
override BUILD_PXE := @BUILD_PXE@
|
||||||
override BUILD_CD := @BUILD_CD@
|
override BUILD_CD := @BUILD_CD@
|
||||||
|
@ -104,7 +105,7 @@ all: $(call MKESCAPE,$(BINDIR))/Makefile
|
||||||
$(MAKE) all1
|
$(MAKE) all1
|
||||||
|
|
||||||
.PHONY: 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'
|
||||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
|
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
|
||||||
|
|
||||||
|
@ -131,7 +132,7 @@ limine:
|
||||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine'
|
$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine'
|
||||||
|
|
||||||
.PHONY: clean
|
.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'
|
rm -rf '$(call SHESCAPE,$(BINDIR))' '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp'
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
|
@ -161,6 +162,9 @@ endif
|
||||||
ifeq ($(BUILD_UEFI_AARCH64),limine-uefi-aarch64)
|
ifeq ($(BUILD_UEFI_AARCH64),limine-uefi-aarch64)
|
||||||
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTAA64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/'
|
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTAA64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/'
|
||||||
endif
|
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)
|
ifeq ($(BUILD_UEFI_X86_64),limine-uefi-x86-64)
|
||||||
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTX64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/'
|
$(INSTALL_DATA) '$(call SHESCAPE,$(BINDIR))/BOOTX64.EFI' '$(call SHESCAPE,$(DESTDIR)$(datarootdir))/limine/'
|
||||||
endif
|
endif
|
||||||
|
@ -204,7 +208,7 @@ endif
|
||||||
limine-bios: common-bios decompressor
|
limine-bios: common-bios decompressor
|
||||||
$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp'
|
$(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)
|
ifneq ($(BUILD_CD_EFI),no)
|
||||||
$(MKDIR_P) '$(call SHESCAPE,$(BINDIR))'
|
$(MKDIR_P) '$(call SHESCAPE,$(BINDIR))'
|
||||||
rm -f '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
|
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 && \
|
mmd -D s -i '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin' ::/EFI/BOOT && \
|
||||||
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64/BOOTAA64.EFI' ] && \
|
( ( [ -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 ) && \
|
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' ] && \
|
( ( [ -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 ) && \
|
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' ] && \
|
( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/common-uefi-ia32/BOOTIA32.EFI' ] && \
|
||||||
|
@ -252,6 +258,15 @@ limine-uefi-aarch64:
|
||||||
$(MAKE) common-uefi-aarch64
|
$(MAKE) common-uefi-aarch64
|
||||||
$(MAKE) '$(call SHESCAPE,$(BINDIR))/BOOTAA64.EFI'
|
$(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
|
.PHONY: limine-bios-clean
|
||||||
limine-bios-clean: common-bios-clean decompressor-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
|
.PHONY: limine-uefi-aarch64-clean
|
||||||
limine-uefi-aarch64-clean: common-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
|
.PHONY: dist
|
||||||
dist:
|
dist:
|
||||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)"
|
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)/freestanding-headers/.git"
|
||||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.git"
|
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.git"
|
||||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))'/"limine-$(LIMINE_VERSION)/libgcc-binaries/.gitignore"
|
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 \
|
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"; \
|
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; \
|
done; \
|
||||||
|
@ -328,6 +346,17 @@ common-uefi-aarch64:
|
||||||
common-uefi-aarch64-clean:
|
common-uefi-aarch64-clean:
|
||||||
rm -rf '$(call SHESCAPE,$(BUILDDIR))/common-uefi-aarch64'
|
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
|
.PHONY: common-uefi-ia32
|
||||||
common-uefi-ia32:
|
common-uefi-ia32:
|
||||||
$(MAKE) -C '$(call SHESCAPE,$(SRCDIR))/common' all \
|
$(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.
|
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
|
## Feature List
|
||||||
|
|
||||||
Request IDs are composed of 4 64-bit unsigned integers, but the first 2 are
|
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
|
### 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:
|
ID:
|
||||||
```c
|
```c
|
||||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
#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.
|
processor.
|
||||||
* `extra_argument` - A free for use field.
|
* `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
|
### Memory Map Feature
|
||||||
|
|
||||||
ID:
|
ID:
|
||||||
|
|
|
@ -15,6 +15,7 @@ as the reference implementation for the [Limine boot protocol](/PROTOCOL.md).
|
||||||
* IA-32 (32-bit x86)
|
* IA-32 (32-bit x86)
|
||||||
* x86_64
|
* x86_64
|
||||||
* aarch64 (arm64)
|
* aarch64 (arm64)
|
||||||
|
* riscv64
|
||||||
|
|
||||||
### Supported boot protocols
|
### Supported boot protocols
|
||||||
* Linux
|
* 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
|
For 32-bit x86 systems, support is only ensured starting with those with
|
||||||
Pentium Pro (i686) class CPUs.
|
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
|
## Packaging status
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ else ifeq ($(TARGET),uefi-ia32)
|
||||||
override OBJCOPY2ELF_FLAGS := -B i386 -O elf32-i386
|
override OBJCOPY2ELF_FLAGS := -B i386 -O elf32-i386
|
||||||
else ifeq ($(TARGET),uefi-aarch64)
|
else ifeq ($(TARGET),uefi-aarch64)
|
||||||
override OBJCOPY2ELF_FLAGS := -B aarch64 -O elf64-littleaarch64
|
override OBJCOPY2ELF_FLAGS := -B aarch64 -O elf64-littleaarch64
|
||||||
|
else ifeq ($(TARGET),uefi-riscv64)
|
||||||
|
override OBJCOPY2ELF_FLAGS := -B riscv64 -O elf64-littleriscv
|
||||||
else
|
else
|
||||||
$(error Invalid target)
|
$(error Invalid target)
|
||||||
endif
|
endif
|
||||||
|
@ -127,6 +129,26 @@ ifeq ($(TARGET),uefi-aarch64)
|
||||||
-DUEFI
|
-DUEFI
|
||||||
endif
|
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 += \
|
override LDFLAGS_FOR_TARGET += \
|
||||||
-nostdlib \
|
-nostdlib \
|
||||||
-z max-page-size=0x1000
|
-z max-page-size=0x1000
|
||||||
|
@ -169,6 +191,15 @@ ifeq ($(TARGET),uefi-aarch64)
|
||||||
-z text
|
-z text
|
||||||
endif
|
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')
|
override C_FILES := $(shell find . -type f -name '*.c')
|
||||||
ifeq ($(TARGET),bios)
|
ifeq ($(TARGET),bios)
|
||||||
override ASMX86_FILES := $(shell find . -type f -name '*.asm_x86')
|
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))
|
override OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.o) $(ASM64_FILES:.asm_aarch64=.o) $(ASM64U_FILES:.asm_uefi_aarch64=.o))
|
||||||
endif
|
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))
|
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
|
all: $(call MKESCAPE,$(BUILDDIR))/BOOTIA32.EFI
|
||||||
else ifeq ($(TARGET),uefi-aarch64)
|
else ifeq ($(TARGET),uefi-aarch64)
|
||||||
all: $(call MKESCAPE,$(BUILDDIR))/BOOTAA64.EFI
|
all: $(call MKESCAPE,$(BUILDDIR))/BOOTAA64.EFI
|
||||||
|
else ifeq ($(TARGET),uefi-riscv64)
|
||||||
|
all: $(call MKESCAPE,$(BUILDDIR))/BOOTRISCV64.EFI
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(TARGET),bios)
|
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,$@)'
|
'$(call OBJESCAPE,$^)' $(LDFLAGS_FOR_TARGET) -o '$(call SHESCAPE,$@)'
|
||||||
endif
|
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)
|
ifeq ($(TARGET),uefi-ia32)
|
||||||
|
|
||||||
$(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf
|
$(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,$@)'
|
$(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
|
||||||
endif
|
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)
|
ifeq ($(TARGET),uefi-ia32)
|
||||||
$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/limine-efi
|
$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/limine-efi
|
||||||
$(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')"
|
$(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,$@)'
|
$(CC_FOR_TARGET) $(CFLAGS_FOR_TARGET) $(CPPFLAGS_FOR_TARGET) -x assembler-with-cpp -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
|
||||||
endif
|
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)
|
ifeq ($(TARGET),uefi-ia32)
|
||||||
$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_ia32
|
$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm_ia32
|
||||||
$(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')"
|
$(MKDIR_P) "$$(dirname '$(call SHESCAPE,$@)')"
|
||||||
|
|
|
@ -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_64 0x3e
|
||||||
#define ARCH_X86_32 0x03
|
#define ARCH_X86_32 0x03
|
||||||
#define ARCH_AARCH64 0xb7
|
#define ARCH_AARCH64 0xb7
|
||||||
|
#define ARCH_RISCV 0xf3
|
||||||
#define BITS_LE 0x01
|
#define BITS_LE 0x01
|
||||||
|
#define ELFCLASS64 0x02
|
||||||
#define ET_DYN 0x0003
|
#define ET_DYN 0x0003
|
||||||
#define SHT_RELA 0x00000004
|
#define SHT_RELA 0x00000004
|
||||||
#define R_X86_64_RELATIVE 0x00000008
|
#define R_X86_64_RELATIVE 0x00000008
|
||||||
#define R_AARCH64_RELATIVE 0x00000403
|
#define R_AARCH64_RELATIVE 0x00000403
|
||||||
|
#define R_RISCV_RELATIVE 0x00000003
|
||||||
|
|
||||||
/* Indices into identification array */
|
/* Indices into identification array */
|
||||||
#define EI_CLASS 4
|
#define EI_CLASS 4
|
||||||
|
@ -103,6 +106,8 @@ int elf_bits(uint8_t *elf) {
|
||||||
case ARCH_X86_64:
|
case ARCH_X86_64:
|
||||||
case ARCH_AARCH64:
|
case ARCH_AARCH64:
|
||||||
return 64;
|
return 64;
|
||||||
|
case ARCH_RISCV:
|
||||||
|
return (hdr->ident[EI_CLASS] == ELFCLASS64) ? 64 : 32;
|
||||||
case ARCH_X86_32:
|
case ARCH_X86_32:
|
||||||
return 32;
|
return 32;
|
||||||
default:
|
default:
|
||||||
|
@ -226,6 +231,8 @@ static bool elf64_apply_relocations(uint8_t *elf, struct elf64_hdr *hdr, void *b
|
||||||
case R_X86_64_RELATIVE:
|
case R_X86_64_RELATIVE:
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
case R_AARCH64_RELATIVE:
|
case R_AARCH64_RELATIVE:
|
||||||
|
#elif defined (__riscv64)
|
||||||
|
case R_RISCV_RELATIVE:
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#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");
|
printv("elf: Not an aarch64 ELF file.\n");
|
||||||
return false;
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#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) {
|
if (hdr->machine != ARCH_AARCH64) {
|
||||||
panic(true, "elf: Not an aarch64 ELF file.\n");
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -109,6 +109,46 @@ uint32_t hex2bin(uint8_t *str, uint32_t size) {
|
||||||
|
|
||||||
#if defined (UEFI)
|
#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;
|
no_unwind bool efi_boot_services_exited = false;
|
||||||
|
|
||||||
bool efi_exit_boot_services(void) {
|
bool efi_exit_boot_services(void) {
|
||||||
|
@ -162,6 +202,8 @@ retry:
|
||||||
asm volatile ("cli" ::: "memory");
|
asm volatile ("cli" ::: "memory");
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
asm volatile ("msr daifset, #15" ::: "memory");
|
asm volatile ("msr daifset, #15" ::: "memory");
|
||||||
|
#elif defined (__riscv64)
|
||||||
|
asm volatile ("csrci sstatus, 0x2" ::: "memory");
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
#include <lib/libc.h>
|
#include <lib/libc.h>
|
||||||
#if defined (UEFI)
|
#if defined (UEFI)
|
||||||
# include <efi.h>
|
# include <efi.h>
|
||||||
|
# if defined (__riscv64)
|
||||||
|
# include <protocol/riscv/efiboot.h>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (UEFI)
|
#if defined (UEFI)
|
||||||
|
@ -57,7 +60,7 @@ uint64_t strtoui(const char *s, const char **end, int base);
|
||||||
|
|
||||||
#if defined (__i386__)
|
#if defined (__i386__)
|
||||||
void memcpy32to64(uint64_t, uint64_t, uint64_t);
|
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)
|
# define memcpy32to64(X, Y, Z) memcpy((void *)(uintptr_t)(X), (void *)(uintptr_t)(Y), Z)
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#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,
|
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 mair, uint64_t tcr, uint64_t ttbr0,
|
||||||
uint64_t ttbr1, uint64_t target_x0);
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -74,7 +74,7 @@ noreturn void panic(bool allow_menu, const char *fmt, ...) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
#if defined (__x86_64__) || defined (__i386__)
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
asm ("hlt");
|
asm ("hlt");
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__) || defined (__riscv64)
|
||||||
asm ("wfi");
|
asm ("wfi");
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
|
|
|
@ -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;
|
bool native = false;
|
||||||
#if defined (__x86_64__) || defined (__aarch64__)
|
#if defined (__x86_64__) || defined (__aarch64__) || defined (__riscv64)
|
||||||
native = true;
|
native = true;
|
||||||
#elif !defined (__i386__)
|
#elif !defined (__i386__)
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
|
|
|
@ -54,6 +54,8 @@ void print_stacktrace(size_t *base_ptr) {
|
||||||
"movq %%rbp, %0"
|
"movq %%rbp, %0"
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
"mov %0, x29"
|
"mov %0, x29"
|
||||||
|
#elif defined (__riscv64)
|
||||||
|
"mv %0, fp; addi %0, %0, -16"
|
||||||
#endif
|
#endif
|
||||||
: "=r"(base_ptr)
|
: "=r"(base_ptr)
|
||||||
:: "memory"
|
:: "memory"
|
||||||
|
@ -73,7 +75,11 @@ void print_stacktrace(size_t *base_ptr) {
|
||||||
print(" [%p]\n", ret_addr);
|
print(" [%p]\n", ret_addr);
|
||||||
if (!old_bp)
|
if (!old_bp)
|
||||||
break;
|
break;
|
||||||
|
#if defined (__riscv)
|
||||||
|
base_ptr = (void *)(old_bp - 16);
|
||||||
|
#else
|
||||||
base_ptr = (void*)old_bp;
|
base_ptr = (void*)old_bp;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
print("End of trace. ");
|
print("End of trace. ");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
linux_load(config, cmdline);
|
||||||
#else
|
#else
|
||||||
quiet = false;
|
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
|
#endif
|
||||||
} else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
|
} else if (!strcmp(proto, "multiboot1") || !strcmp(proto, "multiboot")) {
|
||||||
#if defined (__x86_64__) || defined (__i386__)
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
multiboot1_load(config, cmdline);
|
multiboot1_load(config, cmdline);
|
||||||
#else
|
#else
|
||||||
quiet = false;
|
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
|
#endif
|
||||||
} else if (!strcmp(proto, "multiboot2")) {
|
} else if (!strcmp(proto, "multiboot2")) {
|
||||||
#if defined (__x86_64__) || defined (__i386__)
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
multiboot2_load(config, cmdline);
|
multiboot2_load(config, cmdline);
|
||||||
#else
|
#else
|
||||||
quiet = false;
|
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
|
#endif
|
||||||
} else if (!strcmp(proto, "chainload_next")) {
|
} else if (!strcmp(proto, "chainload_next")) {
|
||||||
chainload_next(config, cmdline);
|
chainload_next(config, cmdline);
|
||||||
|
|
|
@ -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;
|
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,
|
static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||||
uint64_t virt, enum page_size desired_sz,
|
uint64_t virt, enum page_size desired_sz,
|
||||||
size_t level_idx, size_t entry);
|
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_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))
|
#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_t pagemap;
|
||||||
pagemap.levels = lv;
|
pagemap.levels = paging_mode == PAGING_MODE_X86_64_5LVL ? 5 : 4;
|
||||||
pagemap.top_level = ext_mem_alloc(PT_SIZE);
|
pagemap.top_level = ext_mem_alloc(PT_SIZE);
|
||||||
return pagemap;
|
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_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 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) {
|
static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) {
|
||||||
uint64_t flags = 0;
|
uint64_t flags = 0;
|
||||||
|
|
||||||
|
@ -159,9 +166,9 @@ static uint64_t pt_to_vmm_flags_internal(pt_entry_t entry) {
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
pagemap_t new_pagemap(int lv) {
|
pagemap_t new_pagemap(int paging_mode) {
|
||||||
pagemap_t pagemap;
|
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[0] = ext_mem_alloc(PT_SIZE);
|
||||||
pagemap.top_level[1] = ext_mem_alloc(PT_SIZE);
|
pagemap.top_level[1] = ext_mem_alloc(PT_SIZE);
|
||||||
return pagemap;
|
return pagemap;
|
||||||
|
@ -221,57 +228,165 @@ level4:
|
||||||
pml1[pml1_entry] = (pt_entry_t)(phys_addr | real_flags | PT_FLAG_4K_PAGE);
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#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,
|
static pt_entry_t *get_next_level(pagemap_t pagemap, pt_entry_t *current_level,
|
||||||
uint64_t virt, enum page_size desired_sz,
|
uint64_t virt, enum page_size desired_sz,
|
||||||
size_t level_idx, size_t entry) {
|
size_t level_idx, size_t entry) {
|
||||||
pt_entry_t *ret;
|
pt_entry_t *ret;
|
||||||
|
|
||||||
if (PT_IS_TABLE(current_level[entry])) {
|
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 {
|
} else {
|
||||||
if (PT_IS_LARGE(current_level[entry])) {
|
if (PT_IS_LARGE(current_level[entry])) {
|
||||||
// We are replacing an existing large page with a smaller page.
|
// We are replacing an existing large page with a smaller page.
|
||||||
// Split the previous mapping into mappings of the newly requested size
|
// Split the previous mapping into mappings of the newly requested size
|
||||||
// before performing the requested map operation.
|
// 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:
|
if ((level_idx >= VMM_MAX_LEVEL) || (level_idx == 0))
|
||||||
old_page_size = 0x200000;
|
panic(false, "Unexpected level in get_next_level");
|
||||||
break;
|
if (desired_sz >= VMM_MAX_LEVEL)
|
||||||
|
panic(false, "Unexpected page size in get_next_level");
|
||||||
|
|
||||||
default:
|
uint64_t old_page_size = page_sizes[level_idx];
|
||||||
panic(false, "Unexpected level in get_next_level");
|
uint64_t new_page_size = page_sizes[desired_sz];
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save all the information from the old entry at this level
|
// 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_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);
|
uint64_t old_virt = virt & ~(old_page_size - 1);
|
||||||
|
|
||||||
if (old_phys & (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
|
// Allocate a table for the next level
|
||||||
ret = ext_mem_alloc(PT_SIZE);
|
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
|
// Recreate the old mapping with smaller pages
|
||||||
for (uint64_t i = 0; i < old_page_size; i += new_page_size) {
|
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 {
|
} else {
|
||||||
// Allocate a table for the next level
|
// Allocate a table for the next level
|
||||||
ret = ext_mem_alloc(PT_SIZE);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,19 @@
|
||||||
#define VMM_FLAG_NOEXEC ((uint64_t)1 << 63)
|
#define VMM_FLAG_NOEXEC ((uint64_t)1 << 63)
|
||||||
#define VMM_FLAG_FB ((uint64_t)0)
|
#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 {
|
typedef struct {
|
||||||
int levels;
|
int levels;
|
||||||
void *top_level;
|
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_NOEXEC ((uint64_t)1 << 1)
|
||||||
#define VMM_FLAG_FB ((uint64_t)1 << 2)
|
#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 {
|
typedef struct {
|
||||||
int levels;
|
int levels;
|
||||||
void *top_level[2];
|
void *top_level[2];
|
||||||
|
@ -47,8 +75,43 @@ void vmm_assert_4k_pages(void);
|
||||||
pagemap_t new_pagemap(int lv);
|
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);
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int vmm_max_paging_mode(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,10 +35,10 @@
|
||||||
#define MAX_REQUESTS 128
|
#define MAX_REQUESTS 128
|
||||||
#define MAX_MEMMAP 256
|
#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 physical_base, uint64_t virtual_base,
|
||||||
uint64_t direct_map_offset) {
|
uint64_t direct_map_offset) {
|
||||||
pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
|
pagemap_t pagemap = new_pagemap(paging_mode);
|
||||||
|
|
||||||
if (ranges_count == 0) {
|
if (ranges_count == 0) {
|
||||||
// Map 0 to 2GiB at 0xffffffff80000000
|
// 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)1 << 8) /* TTBR0 Inner WB RW-Allocate */ \
|
||||||
| ((uint64_t)(tsz) << 0)) /* Address bits in TTBR0 */
|
| ((uint64_t)(tsz) << 0)) /* Address bits in TTBR0 */
|
||||||
|
|
||||||
#else
|
#elif !defined (__riscv64)
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -191,6 +191,13 @@ static uint64_t physical_base, virtual_base, slide, direct_map_offset;
|
||||||
static size_t requests_count;
|
static size_t requests_count;
|
||||||
static void **requests;
|
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) {
|
static uint64_t reported_addr(void *addr) {
|
||||||
return (uint64_t)(uintptr_t)addr + direct_map_offset;
|
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: ELF entry point: %X\n", entry_point);
|
||||||
printv("limine: Requests count: %u\n", requests_count);
|
printv("limine: Requests count: %u\n", requests_count);
|
||||||
|
|
||||||
// 5 level paging feature & HHDM slide
|
// Paging Mode
|
||||||
bool want_5lv;
|
int paging_mode, max_paging_mode;
|
||||||
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
|
|
||||||
#if defined (__x86_64__) || defined (__i386__)
|
#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))) {
|
if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
|
||||||
printv("limine: CPU has 5-level paging support\n");
|
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
|
#endif
|
||||||
|
|
||||||
struct limine_5_level_paging_request *lv5pg_request = get_request(LIMINE_5_LEVEL_PAGING_REQUEST);
|
#if defined (__riscv64)
|
||||||
want_5lv = lv5pg_request != NULL && level5pg;
|
#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) {
|
if (pm_request->mode > LIMINE_PAGING_MODE_MAX) {
|
||||||
direct_map_offset += (rand64() & ~((uint64_t)0x40000000 - 1)) & 0xfffffffffff;
|
print("warning: ignoring invalid mode in paging mode request\n");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (want_5lv) {
|
paging_mode = paging_mode_limine_to_vmm(pm_request->mode);
|
||||||
void *lv5pg_response = ext_mem_alloc(sizeof(struct limine_5_level_paging_response));
|
if (paging_mode > max_paging_mode)
|
||||||
lv5pg_request->response = reported_addr(lv5pg_response);
|
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
|
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__)
|
#if defined (__aarch64__)
|
||||||
uint64_t aa64mmfr0;
|
uint64_t aa64mmfr0;
|
||||||
asm volatile ("mrs %0, id_aa64mmfr0_el1" : "=r" (aa64mmfr0));
|
asm volatile ("mrs %0, id_aa64mmfr0_el1" : "=r" (aa64mmfr0));
|
||||||
|
|
||||||
uint64_t pa = aa64mmfr0 & 0xF;
|
uint64_t pa = aa64mmfr0 & 0xF;
|
||||||
|
|
||||||
uint64_t tsz = 64 - (want_5lv ? 57 : 48);
|
uint64_t tsz = 64 - paging_mode_va_bits(paging_mode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct limine_file *kf = ext_mem_alloc(sizeof(struct limine_file));
|
struct limine_file *kf = ext_mem_alloc(sizeof(struct limine_file));
|
||||||
|
@ -795,7 +867,7 @@ term_fail:
|
||||||
#if defined (__i386__)
|
#if defined (__i386__)
|
||||||
actual_callback = (void *)limine_term_callback;
|
actual_callback = (void *)limine_term_callback;
|
||||||
limine_term_callback_ptr = terminal_request->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;
|
actual_callback = (void *)terminal_request->callback;
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
|
@ -811,7 +883,7 @@ term_fail:
|
||||||
|
|
||||||
limine_term_write_ptr = (uintptr_t)term_write_shim;
|
limine_term_write_ptr = (uintptr_t)term_write_shim;
|
||||||
terminal_response->write = (uintptr_t)(void *)limine_term_write_entry;
|
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;
|
terminal_response->write = (uintptr_t)term_write_shim;
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
|
@ -1003,9 +1075,22 @@ FEAT_END
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pagemap_t pagemap = {0};
|
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);
|
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)
|
#if defined (UEFI)
|
||||||
efi_exit_boot_services();
|
efi_exit_boot_services();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1022,7 +1107,7 @@ FEAT_START
|
||||||
#if defined (__x86_64__) || defined (__i386__)
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
uint32_t bsp_lapic_id;
|
uint32_t bsp_lapic_id;
|
||||||
smp_info = init_smp(&cpu_count, &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,
|
pagemap, smp_request->flags & LIMINE_SMP_X2APIC, nx_available,
|
||||||
direct_map_offset, true);
|
direct_map_offset, true);
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
|
@ -1030,6 +1115,13 @@ FEAT_START
|
||||||
|
|
||||||
smp_info = init_smp(&cpu_count, &bsp_mpidr,
|
smp_info = init_smp(&cpu_count, &bsp_mpidr,
|
||||||
pagemap, LIMINE_MAIR(fb_attr), LIMINE_TCR(tsz, pa), LIMINE_SCTLR);
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
@ -1051,6 +1143,8 @@ FEAT_START
|
||||||
smp_response->bsp_lapic_id = bsp_lapic_id;
|
smp_response->bsp_lapic_id = bsp_lapic_id;
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
smp_response->bsp_mpidr = bsp_mpidr;
|
smp_response->bsp_mpidr = bsp_mpidr;
|
||||||
|
#elif defined (__riscv64)
|
||||||
|
smp_response->bsp_hartid = bsp_hartid;
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
@ -1155,7 +1249,7 @@ FEAT_END
|
||||||
uint64_t reported_stack = reported_addr(stack);
|
uint64_t reported_stack = reported_addr(stack);
|
||||||
|
|
||||||
common_spinup(limine_spinup_32, 8,
|
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)entry_point, (uint32_t)(entry_point >> 32),
|
||||||
(uint32_t)reported_stack, (uint32_t)(reported_stack >> 32),
|
(uint32_t)reported_stack, (uint32_t)(reported_stack >> 32),
|
||||||
(uint32_t)(uintptr_t)local_gdt, nx_available);
|
(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),
|
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[0],
|
||||||
(uint64_t)pagemap.top_level[1], 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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -287,6 +287,39 @@ inline int current_el(void) {
|
||||||
return v;
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
#include <mm/pmm.h>
|
||||||
#define LIMINE_NO_POINTERS
|
#define LIMINE_NO_POINTERS
|
||||||
#include <limine.h>
|
#include <limine.h>
|
||||||
|
#if defined (__riscv64)
|
||||||
|
#include <sys/sbi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct madt {
|
struct madt {
|
||||||
struct sdt header;
|
struct sdt header;
|
||||||
|
@ -64,6 +67,16 @@ struct madt_gicc {
|
||||||
uint16_t spe_overflow_gsiv;
|
uint16_t spe_overflow_gsiv;
|
||||||
} __attribute__((packed));
|
} __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__)
|
#if defined (__x86_64__) || defined (__i386__)
|
||||||
|
|
||||||
struct trampoline_passed_info {
|
struct trampoline_passed_info {
|
||||||
|
@ -77,7 +90,7 @@ struct trampoline_passed_info {
|
||||||
|
|
||||||
static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
|
||||||
struct limine_smp_info *info_struct,
|
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) {
|
bool x2apic, bool nx, uint64_t hhdm, bool wp) {
|
||||||
// Prepare the trampoline
|
// Prepare the trampoline
|
||||||
static void *trampoline = NULL;
|
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_booted_flag = 0;
|
||||||
passed_info->smp_tpl_pagemap = pagemap;
|
passed_info->smp_tpl_pagemap = pagemap;
|
||||||
passed_info->smp_tpl_target_mode = ((uint32_t)x2apic << 2)
|
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)nx << 3)
|
||||||
| ((uint32_t)wp << 4)
|
| ((uint32_t)wp << 4)
|
||||||
| ((uint32_t)longmode << 0);
|
| ((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,
|
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
uint32_t *_bsp_lapic_id,
|
uint32_t *_bsp_lapic_id,
|
||||||
bool longmode,
|
bool longmode,
|
||||||
bool lv5,
|
int paging_mode,
|
||||||
pagemap_t pagemap,
|
pagemap_t pagemap,
|
||||||
bool x2apic,
|
bool x2apic,
|
||||||
bool nx,
|
bool nx,
|
||||||
|
@ -244,7 +257,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
|
|
||||||
// Try to start the AP
|
// Try to start the AP
|
||||||
if (!smp_start_ap(lapic->lapic_id, &gdtr, info_struct,
|
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)) {
|
x2apic, nx, hhdm, wp)) {
|
||||||
print("smp: FAILED to bring-up AP\n");
|
print("smp: FAILED to bring-up AP\n");
|
||||||
continue;
|
continue;
|
||||||
|
@ -281,7 +294,7 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
|
|
||||||
// Try to start the AP
|
// Try to start the AP
|
||||||
if (!smp_start_ap(x2lapic->x2apic_id, &gdtr, info_struct,
|
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)) {
|
true, nx, hhdm, wp)) {
|
||||||
print("smp: FAILED to bring-up AP\n");
|
print("smp: FAILED to bring-up AP\n");
|
||||||
continue;
|
continue;
|
||||||
|
@ -556,6 +569,110 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
return NULL;
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
struct limine_smp_info *init_smp(size_t *cpu_count,
|
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
uint32_t *_bsp_lapic_id,
|
uint32_t *_bsp_lapic_id,
|
||||||
bool longmode,
|
bool longmode,
|
||||||
bool lv5,
|
int paging_mode,
|
||||||
pagemap_t pagemap,
|
pagemap_t pagemap,
|
||||||
bool x2apic,
|
bool x2apic,
|
||||||
bool nx,
|
bool nx,
|
||||||
|
@ -28,6 +28,13 @@ struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
uint64_t mair,
|
uint64_t mair,
|
||||||
uint64_t tcr,
|
uint64_t tcr,
|
||||||
uint64_t sctlr);
|
uint64_t sctlr);
|
||||||
|
|
||||||
|
#elif defined (__riscv64)
|
||||||
|
|
||||||
|
struct limine_smp_info *init_smp(size_t *cpu_count,
|
||||||
|
uint64_t bsp_hartid,
|
||||||
|
pagemap_t pagemap);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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])
|
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"
|
BUILD_CD_EFI="$BUILD_ALL"
|
||||||
|
|
||||||
AC_ARG_ENABLE([uefi-cd],
|
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
|
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 */
|
/* 5-level paging */
|
||||||
|
|
||||||
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
|
#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;
|
uint64_t revision;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct limine_5_level_paging_request {
|
struct LIMINE_DEPRECATED limine_5_level_paging_request {
|
||||||
uint64_t id[4];
|
uint64_t id[4];
|
||||||
uint64_t revision;
|
uint64_t revision;
|
||||||
LIMINE_PTR(struct limine_5_level_paging_response *) response;
|
LIMINE_PTR(struct limine_5_level_paging_response *) response;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LIMINE_DEPRECATED_IGNORE_END
|
||||||
|
|
||||||
/* SMP */
|
/* SMP */
|
||||||
|
|
||||||
#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
|
||||||
|
@ -294,6 +336,24 @@ struct limine_smp_response {
|
||||||
LIMINE_PTR(struct limine_smp_info **) cpus;
|
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
|
#else
|
||||||
#error Unknown architecture
|
#error Unknown architecture
|
||||||
#endif
|
#endif
|
||||||
|
|
28
test.mk
28
test.mk
|
@ -11,6 +11,10 @@ ovmf-aa64:
|
||||||
mkdir -p 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
|
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:
|
ovmf-ia32:
|
||||||
$(MKDIR_P) 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
|
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
|
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
|
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
|
.PHONY: uefi-ia32-test
|
||||||
uefi-ia32-test:
|
uefi-ia32-test:
|
||||||
$(MAKE) ovmf-ia32
|
$(MAKE) ovmf-ia32
|
||||||
|
|
|
@ -151,6 +151,16 @@ struct limine_dtb_request _dtb_request = {
|
||||||
__attribute__((section(".limine_reqs")))
|
__attribute__((section(".limine_reqs")))
|
||||||
void *dtb_req = &_dtb_request;
|
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) {
|
static char *get_memmap_type(uint64_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LIMINE_MEMMAP_USABLE:
|
case LIMINE_MEMMAP_USABLE:
|
||||||
|
@ -216,6 +226,8 @@ void ap_entry(struct limine_smp_info *info) {
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
e9_printf("My GIC CPU Interface no.: %x", info->gic_iface_no);
|
e9_printf("My GIC CPU Interface no.: %x", info->gic_iface_no);
|
||||||
e9_printf("My MPIDR: %x", info->mpidr);
|
e9_printf("My MPIDR: %x", info->mpidr);
|
||||||
|
#elif defined (__riscv)
|
||||||
|
e9_printf("My Hart ID: %x", info->hartid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__atomic_fetch_add(&ctr, 1, __ATOMIC_SEQ_CST);
|
__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);
|
e9_printf("BSP LAPIC ID: %x", smp_response->bsp_lapic_id);
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
e9_printf("BSP MPIDR: %x", smp_response->bsp_mpidr);
|
e9_printf("BSP MPIDR: %x", smp_response->bsp_mpidr);
|
||||||
|
#elif defined (__riscv)
|
||||||
|
e9_printf("BSP Hart ID: %x", smp_response->bsp_hartid);
|
||||||
#endif
|
#endif
|
||||||
e9_printf("CPU count: %d", smp_response->cpu_count);
|
e9_printf("CPU count: %d", smp_response->cpu_count);
|
||||||
for (size_t i = 0; i < smp_response->cpu_count; i++) {
|
for (size_t i = 0; i < smp_response->cpu_count; i++) {
|
||||||
|
@ -422,6 +436,8 @@ FEAT_START
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
e9_printf("GIC CPU Interface no.: %x", cpu->gic_iface_no);
|
e9_printf("GIC CPU Interface no.: %x", cpu->gic_iface_no);
|
||||||
e9_printf("MPIDR: %x", cpu->mpidr);
|
e9_printf("MPIDR: %x", cpu->mpidr);
|
||||||
|
#elif defined (__riscv)
|
||||||
|
e9_printf("Hart ID: %x", cpu->hartid);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,6 +445,8 @@ FEAT_START
|
||||||
if (cpu->lapic_id != smp_response->bsp_lapic_id) {
|
if (cpu->lapic_id != smp_response->bsp_lapic_id) {
|
||||||
#elif defined (__aarch64__)
|
#elif defined (__aarch64__)
|
||||||
if (cpu->mpidr != smp_response->bsp_mpidr) {
|
if (cpu->mpidr != smp_response->bsp_mpidr) {
|
||||||
|
#elif defined (__riscv)
|
||||||
|
if (cpu->hartid != smp_response->bsp_hartid) {
|
||||||
#endif
|
#endif
|
||||||
uint32_t old_ctr = __atomic_load_n(&ctr, __ATOMIC_SEQ_CST);
|
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);
|
e9_printf("Device tree blob pointer: %x", dtb_response->dtb_ptr);
|
||||||
FEAT_END
|
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 (;;);
|
for (;;);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue