Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,10 @@
.. SPDX-License-Identifier: GPL-2.0
==============
ACPI on RISC-V
==============
The ISA string parsing rules for ACPI are defined by `Version ASCIIDOC
Conversion, 12/2022 of the RISC-V specifications, as defined by tag
"riscv-isa-release-1239329-2023-05-23" (commit 1239329
) <https://github.com/riscv/riscv-isa-manual/releases/tag/riscv-isa-release-1239329-2023-05-23>`_
@@ -0,0 +1,59 @@
=================================
Boot image header in RISC-V Linux
=================================
:Author: Atish Patra <atish.patra@wdc.com>
:Date: 20 May 2019
This document only describes the boot image header details for RISC-V Linux.
The following 64-byte header is present in decompressed Linux kernel image::
u32 code0; /* Executable code */
u32 code1; /* Executable code */
u64 text_offset; /* Image load offset, little endian */
u64 image_size; /* Effective Image size, little endian */
u64 flags; /* kernel flags, little endian */
u32 version; /* Version of this header */
u32 res1 = 0; /* Reserved */
u64 res2 = 0; /* Reserved */
u64 magic = 0x5643534952; /* Magic number, little endian, "RISCV" */
u32 magic2 = 0x05435352; /* Magic number 2, little endian, "RSC\x05" */
u32 res3; /* Reserved for PE COFF offset */
This header format is compliant with PE/COFF header and largely inspired from
ARM64 header. Thus, both ARM64 & RISC-V header can be combined into one common
header in future.
Notes
=====
- This header is also reused to support EFI stub for RISC-V. EFI specification
needs PE/COFF image header in the beginning of the kernel image in order to
load it as an EFI application. In order to support EFI stub, code0 is replaced
with "MZ" magic string and res3(at offset 0x3c) points to the rest of the
PE/COFF header.
- version field indicate header version number
========== =============
Bits 0:15 Minor version
Bits 16:31 Major version
========== =============
This preserves compatibility across newer and older version of the header.
The current version is defined as 0.2.
- The "magic" field is deprecated as of version 0.2. In a future
release, it may be removed. This originally should have matched up
with the ARM64 header "magic" field, but unfortunately does not.
The "magic2" field replaces it, matching up with the ARM64 header.
- In current header, the flags field has only one field.
===== ====================================
Bit 0 Kernel endianness. 1 if BE, 0 if LE.
===== ====================================
- Image size is mandatory for boot loader to load kernel image. Booting will
fail otherwise.
@@ -0,0 +1,169 @@
.. SPDX-License-Identifier: GPL-2.0
===============================================
RISC-V Kernel Boot Requirements and Constraints
===============================================
:Author: Alexandre Ghiti <alexghiti@rivosinc.com>
:Date: 23 May 2023
This document describes what the RISC-V kernel expects from bootloaders and
firmware, and also the constraints that any developer must have in mind when
touching the early boot process. For the purposes of this document, the
``early boot process`` refers to any code that runs before the final virtual
mapping is set up.
Pre-kernel Requirements and Constraints
=======================================
The RISC-V kernel expects the following of bootloaders and platform firmware:
Register state
--------------
The RISC-V kernel expects:
* ``$a0`` to contain the hartid of the current core.
* ``$a1`` to contain the address of the devicetree in memory.
CSR state
---------
The RISC-V kernel expects:
* ``$satp = 0``: the MMU, if present, must be disabled.
Reserved memory for resident firmware
-------------------------------------
The RISC-V kernel must not map any resident memory, or memory protected with
PMPs, in the direct mapping, so the firmware must correctly mark those regions
as per the devicetree specification and/or the UEFI specification.
Kernel location
---------------
The RISC-V kernel expects to be placed at a PMD boundary (2MB aligned for rv64
and 4MB aligned for rv32). Note that the EFI stub will physically relocate the
kernel if that's not the case.
Hardware description
--------------------
The firmware can pass either a devicetree or ACPI tables to the RISC-V kernel.
The devicetree is either passed directly to the kernel from the previous stage
using the ``$a1`` register, or when booting with UEFI, it can be passed using the
EFI configuration table.
The ACPI tables are passed to the kernel using the EFI configuration table. In
this case, a tiny devicetree is still created by the EFI stub. Please refer to
"EFI stub and devicetree" section below for details about this devicetree.
Kernel entry
------------
On SMP systems, there are 2 methods to enter the kernel:
- ``RISCV_BOOT_SPINWAIT``: the firmware releases all harts in the kernel, one hart
wins a lottery and executes the early boot code while the other harts are
parked waiting for the initialization to finish. This method is mostly used to
support older firmwares without SBI HSM extension and M-mode RISC-V kernel.
- ``Ordered booting``: the firmware releases only one hart that will execute the
initialization phase and then will start all other harts using the SBI HSM
extension. The ordered booting method is the preferred booting method for
booting the RISC-V kernel because it can support CPU hotplug and kexec.
UEFI
----
UEFI memory map
~~~~~~~~~~~~~~~
When booting with UEFI, the RISC-V kernel will use only the EFI memory map to
populate the system memory.
The UEFI firmware must parse the subnodes of the ``/reserved-memory`` devicetree
node and abide by the devicetree specification to convert the attributes of
those subnodes (``no-map`` and ``reusable``) into their correct EFI equivalent
(refer to section "3.5.4 /reserved-memory and UEFI" of the devicetree
specification v0.4-rc1).
RISCV_EFI_BOOT_PROTOCOL
~~~~~~~~~~~~~~~~~~~~~~~
When booting with UEFI, the EFI stub requires the boot hartid in order to pass
it to the RISC-V kernel in ``$a1``. The EFI stub retrieves the boot hartid using
one of the following methods:
- ``RISCV_EFI_BOOT_PROTOCOL`` (**preferred**).
- ``boot-hartid`` devicetree subnode (**deprecated**).
Any new firmware must implement ``RISCV_EFI_BOOT_PROTOCOL`` as the devicetree
based approach is deprecated now.
Early Boot Requirements and Constraints
=======================================
The RISC-V kernel's early boot process operates under the following constraints:
EFI stub and devicetree
-----------------------
When booting with UEFI, the devicetree is supplemented (or created) by the EFI
stub with the same parameters as arm64 which are described at the paragraph
"UEFI kernel support on ARM" in Documentation/arch/arm/uefi.rst.
Virtual mapping installation
----------------------------
The installation of the virtual mapping is done in 2 steps in the RISC-V kernel:
1. ``setup_vm()`` installs a temporary kernel mapping in ``early_pg_dir`` which
allows discovery of the system memory. Only the kernel text/data are mapped
at this point. When establishing this mapping, no allocation can be done
(since the system memory is not known yet), so ``early_pg_dir`` page table is
statically allocated (using only one table for each level).
2. ``setup_vm_final()`` creates the final kernel mapping in ``swapper_pg_dir``
and takes advantage of the discovered system memory to create the linear
mapping. When establishing this mapping, the kernel can allocate memory but
cannot access it directly (since the direct mapping is not present yet), so
it uses temporary mappings in the fixmap region to be able to access the
newly allocated page table levels.
For ``virt_to_phys()`` and ``phys_to_virt()`` to be able to correctly convert
direct mapping addresses to physical addresses, they need to know the start of
the DRAM. This happens after step 1, right before step 2 installs the direct
mapping (see ``setup_bootmem()`` function in arch/riscv/mm/init.c). Any usage of
those macros before the final virtual mapping is installed must be carefully
examined.
Devicetree mapping via fixmap
-----------------------------
As the ``reserved_mem`` array is initialized with virtual addresses established
by ``setup_vm()``, and used with the mapping established by
``setup_vm_final()``, the RISC-V kernel uses the fixmap region to map the
devicetree. This ensures that the devicetree remains accessible by both virtual
mappings.
Pre-MMU execution
-----------------
A few pieces of code need to run before even the first virtual mapping is
established. These are the installation of the first virtual mapping itself,
patching of early alternatives and the early parsing of the kernel command line.
That code must be very carefully compiled as:
- ``-fno-pie``: This is needed for relocatable kernels which use ``-fPIE``,
since otherwise, any access to a global symbol would go through the GOT which
is only relocated virtually.
- ``-mcmodel=medany``: Any access to a global symbol must be PC-relative to
avoid any relocations to happen before the MMU is setup.
- *all* instrumentation must also be disabled (that includes KASAN, ftrace and
others).
As using a symbol from a different compilation unit requires this unit to be
compiled with those flags, we advise, as much as possible, not to use external
symbols.
@@ -0,0 +1,130 @@
.. SPDX-License-Identifier: GPL-2.0
==============================================================================
Concurrent Modification and Execution of Instructions (CMODX) for RISC-V Linux
==============================================================================
CMODX is a programming technique where a program executes instructions that were
modified by the program itself. Instruction storage and the instruction cache
(icache) are not guaranteed to be synchronized on RISC-V hardware. Therefore, the
program must enforce its own synchronization with the unprivileged fence.i
instruction.
CMODX in the Kernel Space
-------------------------
Dynamic ftrace
---------------------
Essentially, dynamic ftrace directs the control flow by inserting a function
call at each patchable function entry, and patches it dynamically at runtime to
enable or disable the redirection. In the case of RISC-V, 2 instructions,
AUIPC + JALR, are required to compose a function call. However, it is impossible
to patch 2 instructions and expect that a concurrent read-side executes them
without a race condition. This series makes atomic code patching possible in
RISC-V ftrace. Kernel preemption makes things even worse as it allows the old
state to persist across the patching process with stop_machine().
In order to get rid of stop_machine() and run dynamic ftrace with full kernel
preemption, we partially initialize each patchable function entry at boot-time,
setting the first instruction to AUIPC, and the second to NOP. Now, atomic
patching is possible because the kernel only has to update one instruction.
According to Ziccif, as long as an instruction is naturally aligned, the ISA
guarantee an atomic update.
By fixing down the first instruction, AUIPC, the range of the ftrace trampoline
is limited to +-2K from the predetermined target, ftrace_caller, due to the lack
of immediate encoding space in RISC-V. To address the issue, we introduce
CALL_OPS, where an 8B naturally align metadata is added in front of each
patchable function. The metadata is resolved at the first trampoline, then the
execution can be directed to another custom trampoline.
CMODX in the User Space
-----------------------
Though fence.i is an unprivileged instruction, the default Linux ABI prohibits
the use of fence.i in userspace applications. At any point the scheduler may
migrate a task onto a new hart. If migration occurs after the userspace
synchronized the icache and instruction storage with fence.i, the icache on the
new hart will no longer be clean. This is due to the behavior of fence.i only
affecting the hart that it is called on. Thus, the hart that the task has been
migrated to may not have synchronized instruction storage and icache.
There are two ways to solve this problem: use the riscv_flush_icache() syscall,
or use the ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` prctl() and emit fence.i in
userspace. The syscall performs a one-off icache flushing operation. The prctl
changes the Linux ABI to allow userspace to emit icache flushing operations.
As an aside, "deferred" icache flushes can sometimes be triggered in the kernel.
At the time of writing, this only occurs during the riscv_flush_icache() syscall
and when the kernel uses copy_to_user_page(). These deferred flushes happen only
when the memory map being used by a hart changes. If the prctl() context caused
an icache flush, this deferred icache flush will be skipped as it is redundant.
Therefore, there will be no additional flush when using the riscv_flush_icache()
syscall inside of the prctl() context.
prctl() Interface
---------------------
Call prctl() with ``PR_RISCV_SET_ICACHE_FLUSH_CTX`` as the first argument. The
remaining arguments will be delegated to the riscv_set_icache_flush_ctx
function detailed below.
.. kernel-doc:: arch/riscv/mm/cacheflush.c
:identifiers: riscv_set_icache_flush_ctx
Example usage:
The following files are meant to be compiled and linked with each other. The
modify_instruction() function replaces an add with 0 with an add with one,
causing the instruction sequence in get_value() to change from returning a zero
to returning a one.
cmodx.c::
#include <stdio.h>
#include <sys/prctl.h>
extern int get_value();
extern void modify_instruction();
int main()
{
int value = get_value();
printf("Value before cmodx: %d\n", value);
// Call prctl before first fence.i is called inside modify_instruction
prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS);
modify_instruction();
// Call prctl after final fence.i is called in process
prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_OFF, PR_RISCV_SCOPE_PER_PROCESS);
value = get_value();
printf("Value after cmodx: %d\n", value);
return 0;
}
cmodx.S::
.option norvc
.text
.global modify_instruction
modify_instruction:
lw a0, new_insn
lui a5,%hi(old_insn)
sw a0,%lo(old_insn)(a5)
fence.i
ret
.section modifiable, "awx"
.global get_value
get_value:
li a0, 0
old_insn:
addi a0, a0, 0
ret
.data
new_insn:
addi a0, a0, 1
@@ -0,0 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
.. kernel-feat:: features riscv
@@ -0,0 +1,403 @@
.. SPDX-License-Identifier: GPL-2.0
RISC-V Hardware Probing Interface
---------------------------------
The RISC-V hardware probing interface is based around a single syscall, which
is defined in <asm/hwprobe.h>::
struct riscv_hwprobe {
__s64 key;
__u64 value;
};
long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
size_t cpusetsize, cpu_set_t *cpus,
unsigned int flags);
The arguments are split into three groups: an array of key-value pairs, a CPU
set, and some flags. The key-value pairs are supplied with a count. Userspace
must prepopulate the key field for each element, and the kernel will fill in the
value if the key is recognized. If a key is unknown to the kernel, its key field
will be cleared to -1, and its value set to 0. The CPU set is defined by
CPU_SET(3) with size ``cpusetsize`` bytes. For value-like keys (eg. vendor,
arch, impl), the returned value will only be valid if all CPUs in the given set
have the same value. Otherwise -1 will be returned. For boolean-like keys, the
value returned will be a logical AND of the values for the specified CPUs.
Usermode can supply NULL for ``cpus`` and 0 for ``cpusetsize`` as a shortcut for
all online CPUs. The currently supported flags are:
* :c:macro:`RISCV_HWPROBE_WHICH_CPUS`: This flag basically reverses the behavior
of sys_riscv_hwprobe(). Instead of populating the values of keys for a given
set of CPUs, the values of each key are given and the set of CPUs is reduced
by sys_riscv_hwprobe() to only those which match each of the key-value pairs.
How matching is done depends on the key type. For value-like keys, matching
means to be the exact same as the value. For boolean-like keys, matching
means the result of a logical AND of the pair's value with the CPU's value is
exactly the same as the pair's value. Additionally, when ``cpus`` is an empty
set, then it is initialized to all online CPUs which fit within it, i.e. the
CPU set returned is the reduction of all the online CPUs which can be
represented with a CPU set of size ``cpusetsize``.
All other flags are reserved for future compatibility and must be zero.
On success 0 is returned, on failure a negative error code is returned.
The following keys are defined:
* :c:macro:`RISCV_HWPROBE_KEY_MVENDORID`: Contains the value of ``mvendorid``,
as defined by the RISC-V privileged architecture specification.
* :c:macro:`RISCV_HWPROBE_KEY_MARCHID`: Contains the value of ``marchid``, as
defined by the RISC-V privileged architecture specification.
* :c:macro:`RISCV_HWPROBE_KEY_MIMPID`: Contains the value of ``mimpid``, as
defined by the RISC-V privileged architecture specification.
* :c:macro:`RISCV_HWPROBE_KEY_BASE_BEHAVIOR`: A bitmask containing the base
user-visible behavior that this kernel supports. The following base user ABIs
are defined:
* :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: Support for rv32ima or
rv64ima, as defined by version 2.2 of the user ISA and version 1.10 of the
privileged ISA, with the following known exceptions (more exceptions may be
added, but only if it can be demonstrated that the user ABI is not broken):
* The ``fence.i`` instruction cannot be directly executed by userspace
programs (it may still be executed in userspace via a
kernel-controlled mechanism such as the vDSO).
* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing extensions
that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`:
base system behavior.
* :c:macro:`RISCV_HWPROBE_IMA_FD`: The F and D extensions are supported, as
defined by commit cd20cee ("FMIN/FMAX now implement
minimumNumber/maximumNumber, not minNum/maxNum") of the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_IMA_C`: The C extension is supported, as defined
by version 2.2 of the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_IMA_V`: The V extension is supported, as defined by
version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZBA`: The Zba address generation extension is
supported, as defined in version 1.0 of the Bit-Manipulation ISA
extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZBB`: The Zbb extension is supported, as defined
in version 1.0 of the Bit-Manipulation ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined
in version 1.0 of the Bit-Manipulation ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as
ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
* :c:macro:`RISCV_HWPROBE_EXT_ZBC` The Zbc extension is supported, as defined
in version 1.0 of the Bit-Manipulation ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZBKB` The Zbkb extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZBKC` The Zbkc extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZBKX` The Zbkx extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKND` The Zknd extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKNE` The Zkne extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKNH` The Zknh extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKSED` The Zksed extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKSH` The Zksh extension is supported, as
defined in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZKT` The Zkt extension is supported, as defined
in version 1.0 of the Scalar Crypto ISA extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZVBB`: The Zvbb extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVBC`: The Zvbc extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKB`: The Zvkb extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKG`: The Zvkg extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKNED`: The Zvkned extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKNHA`: The Zvknha extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKNHB`: The Zvknhb extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKSED`: The Zvksed extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKSH`: The Zvksh extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZVKT`: The Zvkt extension is supported as
defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
* :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
supported as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZIHINTNTL`: The Zihintntl extension version 1.0
is supported as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
("Remove draft warnings from Zvfh[min]").
* :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
("Remove draft warnings from Zvfh[min]").
* :c:macro:`RISCV_HWPROBE_EXT_ZFA`: The Zfa extension is supported as
defined in the RISC-V ISA manual starting from commit 056b6ff467c7
("Zfa is ratified").
* :c:macro:`RISCV_HWPROBE_EXT_ZTSO`: The Ztso extension is supported as
defined in the RISC-V ISA manual starting from commit 5618fb5a216b
("Ztso is now ratified.")
* :c:macro:`RISCV_HWPROBE_EXT_ZACAS`: The Zacas extension is supported as
defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
from commit 5059e0ca641c ("update to ratified").
* :c:macro:`RISCV_HWPROBE_EXT_ZICNTR`: The Zicntr extension version 2.0
is supported as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZICOND`: The Zicond extension is supported as
defined in the RISC-V Integer Conditional (Zicond) operations extension
manual starting from commit 95cf1f9 ("Add changes requested by Ved
during signoff")
* :c:macro:`RISCV_HWPROBE_EXT_ZIHINTPAUSE`: The Zihintpause extension is
supported as defined in the RISC-V ISA manual starting from commit
d8ab5c78c207 ("Zihintpause is ratified").
* :c:macro:`RISCV_HWPROBE_EXT_ZIHPM`: The Zihpm extension version 2.0
is supported as defined in the RISC-V ISA manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVE32X`: The Vector sub-extension Zve32x is
supported, as defined by version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVE32F`: The Vector sub-extension Zve32f is
supported, as defined by version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVE64X`: The Vector sub-extension Zve64x is
supported, as defined by version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVE64F`: The Vector sub-extension Zve64f is
supported, as defined by version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZVE64D`: The Vector sub-extension Zve64d is
supported, as defined by version 1.0 of the RISC-V Vector extension manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZIMOP`: The Zimop May-Be-Operations extension is
supported as defined in the RISC-V ISA manual starting from commit
58220614a5f ("Zimop is ratified/1.0").
* :c:macro:`RISCV_HWPROBE_EXT_ZCA`: The Zca extension part of Zc* standard
extensions for code size reduction, as ratified in commit 8be3419c1c0
("Zcf doesn't exist on RV64 as it contains no instructions") of
riscv-code-size-reduction.
* :c:macro:`RISCV_HWPROBE_EXT_ZCB`: The Zcb extension part of Zc* standard
extensions for code size reduction, as ratified in commit 8be3419c1c0
("Zcf doesn't exist on RV64 as it contains no instructions") of
riscv-code-size-reduction.
* :c:macro:`RISCV_HWPROBE_EXT_ZCD`: The Zcd extension part of Zc* standard
extensions for code size reduction, as ratified in commit 8be3419c1c0
("Zcf doesn't exist on RV64 as it contains no instructions") of
riscv-code-size-reduction.
* :c:macro:`RISCV_HWPROBE_EXT_ZCF`: The Zcf extension part of Zc* standard
extensions for code size reduction, as ratified in commit 8be3419c1c0
("Zcf doesn't exist on RV64 as it contains no instructions") of
riscv-code-size-reduction.
* :c:macro:`RISCV_HWPROBE_EXT_ZCMOP`: The Zcmop May-Be-Operations extension is
supported as defined in the RISC-V ISA manual starting from commit
c732a4f39a4 ("Zcmop is ratified/1.0").
* :c:macro:`RISCV_HWPROBE_EXT_ZAWRS`: The Zawrs extension is supported as
ratified in commit 98918c844281 ("Merge pull request #1217 from
riscv/zawrs") of riscv-isa-manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZAAMO`: The Zaamo extension is supported as
defined in the in the RISC-V ISA manual starting from commit e87412e621f1
("integrate Zaamo and Zalrsc text (#1304)").
* :c:macro:`RISCV_HWPROBE_EXT_ZALASR`: The Zalasr extension is supported as
frozen at commit 194f0094 ("Version 0.9 for freeze") of riscv-zalasr.
* :c:macro:`RISCV_HWPROBE_EXT_ZALRSC`: The Zalrsc extension is supported as
defined in the in the RISC-V ISA manual starting from commit e87412e621f1
("integrate Zaamo and Zalrsc text (#1304)").
* :c:macro:`RISCV_HWPROBE_EXT_SUPM`: The Supm extension is supported as
defined in version 1.0 of the RISC-V Pointer Masking extensions.
* :c:macro:`RISCV_HWPROBE_EXT_ZFBFMIN`: The Zfbfmin extension is supported as
defined in the RISC-V ISA manual starting from commit 4dc23d6229de
("Added Chapter title to BF16").
* :c:macro:`RISCV_HWPROBE_EXT_ZVFBFMIN`: The Zvfbfmin extension is supported as
defined in the RISC-V ISA manual starting from commit 4dc23d6229de
("Added Chapter title to BF16").
* :c:macro:`RISCV_HWPROBE_EXT_ZVFBFWMA`: The Zvfbfwma extension is supported as
defined in the RISC-V ISA manual starting from commit 4dc23d6229de
("Added Chapter title to BF16").
* :c:macro:`RISCV_HWPROBE_EXT_ZICBOM`: The Zicbom extension is supported, as
ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
* :c:macro:`RISCV_HWPROBE_EXT_ZABHA`: The Zabha extension is supported as
ratified in commit 49f49c842ff9 ("Update to Rafified state") of
riscv-zabha.
* :c:macro:`RISCV_HWPROBE_EXT_ZICBOP`: The Zicbop extension is supported, as
ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
* :c:macro:`RISCV_HWPROBE_EXT_ZILSD`: The Zilsd extension is supported as
defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
load/store pair for RV32 with the main manual") of the riscv-isa-manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZCLSD`: The Zclsd extension is supported as
defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
load/store pair for RV32 with the main manual") of the riscv-isa-manual.
* :c:macro:`RISCV_HWPROBE_EXT_ZICFILP`: The Zicfilp extension is supported,
as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
extensions specification, ratified in commit 302a2d45c243
("Update build-pdf.yml") of riscv-cfi.
* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to
:c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
mistakenly classified as a bitmask rather than a value.
* :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`: An enum value describing
the performance of misaligned scalar native word accesses on the selected set
of processors.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN`: The performance of
misaligned scalar accesses is unknown.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED`: Misaligned scalar
accesses are emulated via software, either in or below the kernel. These
accesses are always extremely slow.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW`: Misaligned scalar native
word sized accesses are slower than the equivalent quantity of byte
accesses. Misaligned accesses may be supported directly in hardware, or
trapped and emulated by software.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_FAST`: Misaligned scalar native
word sized accesses are faster than the equivalent quantity of byte
accesses.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED`: Misaligned scalar
accesses are not supported at all and will generate a misaligned address
fault.
* :c:macro:`RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE`: An unsigned int which
represents the size of the Zicboz block in bytes.
* :c:macro:`RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS`: An unsigned long which
represent the highest userspace virtual address usable.
* :c:macro:`RISCV_HWPROBE_KEY_TIME_CSR_FREQ`: Frequency (in Hz) of `time CSR`.
* :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF`: An enum value describing the
performance of misaligned vector accesses on the selected set of processors.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN`: The performance of misaligned
vector accesses is unknown.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW`: 32-bit misaligned accesses using vector
registers are slower than the equivalent quantity of byte accesses via vector registers.
Misaligned accesses may be supported directly in hardware, or trapped and emulated by software.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_FAST`: 32-bit misaligned accesses using vector
registers are faster than the equivalent quantity of byte accesses via vector registers.
* :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED`: Misaligned vector accesses are
not supported at all and will generate a misaligned address fault.
* :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_MIPS_0`: A bitmask containing the
mips vendor extensions that are compatible with the
:c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
* MIPS
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL`: The xmipsexectl vendor
extension is supported in the MIPS ISA extensions spec.
* :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0`: A bitmask containing the
thead vendor extensions that are compatible with the
:c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
* T-HEAD
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR`: The xtheadvector vendor
extension is supported in the T-Head ISA extensions spec starting from
commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
* :c:macro:`RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE`: An unsigned int which
represents the size of the Zicbom block in bytes.
* :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0`: A bitmask containing the
sifive vendor extensions that are compatible with the
:c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
* SIFIVE
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD`: The Xsfqmaccdod vendor
extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
Extensions Specification.
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ`: The Xsfqmaccqoq vendor
extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
Instruction Extensions Specification.
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF`: The Xsfvfnrclipxfqf
vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged
Clip Instructions Extensions Specification.
* :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq
vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
Instruction Extensions Specification.
* :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which
represents the size of the Zicbop block in bytes.
* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional
extensions that are compatible with the
:c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
* :c:macro:`RISCV_HWPROBE_EXT_ZICFISS`: The Zicfiss extension is supported,
as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
extensions specification, ratified in commit 302a2d45c243
("Update build-pdf.yml") of riscv-cfi.
@@ -0,0 +1,20 @@
===================
RISC-V architecture
===================
.. toctree::
:maxdepth: 1
acpi
boot
boot-image-header
vm-layout
hwprobe
patch-acceptance
uabi
vector
cmodx
zicfilp
zicfiss
features
@@ -0,0 +1,59 @@
.. SPDX-License-Identifier: GPL-2.0
arch/riscv maintenance guidelines for developers
================================================
Overview
--------
The RISC-V instruction set architecture is developed in the open:
in-progress drafts are available for all to review and to experiment
with implementations. New module or extension drafts can change
during the development process - sometimes in ways that are
incompatible with previous drafts. This flexibility can present a
challenge for RISC-V Linux maintenance. Linux maintainers disapprove
of churn, and the Linux development process prefers well-reviewed and
tested code over experimental code. We wish to extend these same
principles to the RISC-V-related code that will be accepted for
inclusion in the kernel.
Patchwork
---------
RISC-V has a patchwork instance, where the status of patches can be checked:
https://patchwork.kernel.org/project/linux-riscv/list/
If your patch does not appear in the default view, the RISC-V maintainers have
likely either requested changes, or expect it to be applied to another tree.
Automation runs against this patchwork instance, building/testing patches as
they arrive. The automation applies patches against the current HEAD of the
RISC-V `for-next` and `fixes` branches, depending on whether the patch has been
detected as a fix. Failing those, it will use the RISC-V `master` branch.
The exact commit to which a series has been applied will be noted on patchwork.
Patches for which any of the checks fail are unlikely to be applied and in most
cases will need to be resubmitted.
Submit Checklist Addendum
-------------------------
We'll only accept patches for new modules or extensions if the
specifications for those modules or extensions are listed as being
unlikely to be incompatibly changed in the future. For
specifications from the RISC-V foundation this means "Frozen" or
"Ratified", for the UEFI forum specifications this means a published
ECR. (Developers may, of course, maintain their own Linux kernel trees
that contain code for any draft extensions that they wish.)
Additionally, the RISC-V specification allows implementers to create
their own custom extensions. These custom extensions aren't required
to go through any review or ratification process by the RISC-V
Foundation. To avoid the maintenance complexity and potential
performance impact of adding kernel code for implementor-specific
RISC-V extensions, we'll only consider patches for extensions that either:
- Have been officially frozen or ratified by the RISC-V Foundation, or
- Have been implemented in hardware that is widely available, per standard
Linux practice.
(Implementers, may, of course, maintain their own Linux kernel trees containing
code for any custom extensions that they wish.)
@@ -0,0 +1,88 @@
.. SPDX-License-Identifier: GPL-2.0
RISC-V Linux User ABI
=====================
ISA string ordering in /proc/cpuinfo
------------------------------------
The canonical order of ISA extension names in the ISA string is defined in
Chapter 27 of the RISC-V Instruction Set Manual Volume I Unprivileged ISA
(Document Version 20191213).
The specification uses vague wording, such as should, when it comes to ordering,
so for our purposes the following rules apply:
#. Single-letter extensions come first, in canonical order.
The canonical order is "IMAFDQLCBKJTPVH".
#. All multi-letter extensions will be separated from other extensions by an
underscore.
#. Additional standard extensions (starting with 'Z') will be sorted after
single-letter extensions and before any higher-privileged extensions.
#. For additional standard extensions, the first letter following the 'Z'
conventionally indicates the most closely related alphabetical
extension category. If multiple 'Z' extensions are named, they will be
ordered first by category, in canonical order, as listed above, then
alphabetically within a category.
#. Standard supervisor-level extensions (starting with 'S') will be listed
after standard unprivileged extensions. If multiple supervisor-level
extensions are listed, they will be ordered alphabetically.
#. Standard machine-level extensions (starting with 'Zxm') will be listed
after any lower-privileged, standard extensions. If multiple machine-level
extensions are listed, they will be ordered alphabetically.
#. Non-standard extensions (starting with 'X') will be listed after all standard
extensions. If multiple non-standard extensions are listed, they will be
ordered alphabetically.
An example string following the order is::
rv64imadc_zifoo_zigoo_zafoo_sbar_scar_zxmbaz_xqux_xrux
"isa" and "hart isa" lines in /proc/cpuinfo
-------------------------------------------
The "isa" line in /proc/cpuinfo describes the lowest common denominator of
RISC-V ISA extensions recognized by the kernel and implemented on all harts. The
"hart isa" line, in contrast, describes the set of extensions recognized by the
kernel on the particular hart being described, even if those extensions may not
be present on all harts in the system.
In both lines, the presence of an extension guarantees only that the hardware
has the described capability. Additional kernel support or policy changes may be
required before an extension's capability is fully usable by userspace programs.
Similarly, for S-mode extensions, presence in one of these lines does not
guarantee that the kernel is taking advantage of the extension, or that the
feature will be visible in guest VMs managed by this kernel.
Inversely, the absence of an extension in these lines does not necessarily mean
the hardware does not support that feature. The running kernel may not recognize
the extension, or may have deliberately removed it from the listing.
Misaligned accesses
-------------------
Misaligned scalar accesses are supported in userspace, but they may perform
poorly. Misaligned vector accesses are only supported if the Zicclsm extension
is supported.
Pointer masking
---------------
Support for pointer masking in userspace (the Supm extension) is provided via
the ``PR_SET_TAGGED_ADDR_CTRL`` and ``PR_GET_TAGGED_ADDR_CTRL`` ``prctl()``
operations. Pointer masking is disabled by default. To enable it, userspace
must call ``PR_SET_TAGGED_ADDR_CTRL`` with the ``PR_PMLEN`` field set to the
number of mask/tag bits needed by the application. ``PR_PMLEN`` is interpreted
as a lower bound; if the kernel is unable to satisfy the request, the
``PR_SET_TAGGED_ADDR_CTRL`` operation will fail. The actual number of tag bits
is returned in ``PR_PMLEN`` by the ``PR_GET_TAGGED_ADDR_CTRL`` operation.
Additionally, when pointer masking is enabled (``PR_PMLEN`` is greater than 0),
a tagged address ABI is supported, with the same interface and behavior as
documented for AArch64 (Documentation/arch/arm64/tagged-address-abi.rst).
@@ -0,0 +1,140 @@
.. SPDX-License-Identifier: GPL-2.0
=========================================
Vector Extension Support for RISC-V Linux
=========================================
This document briefly outlines the interface provided to userspace by Linux in
order to support the use of the RISC-V Vector Extension.
1. prctl() Interface
---------------------
Two new prctl() calls are added to allow programs to manage the enablement
status for the use of Vector in userspace. The intended usage guideline for
these interfaces is to give init systems a way to modify the availability of V
for processes running under its domain. Calling these interfaces is not
recommended in libraries routines because libraries should not override policies
configured from the parent process. Also, users must note that these interfaces
are not portable to non-Linux, nor non-RISC-V environments, so it is discourage
to use in a portable code. To get the availability of V in an ELF program,
please read :c:macro:`COMPAT_HWCAP_ISA_V` bit of :c:macro:`ELF_HWCAP` in the
auxiliary vector.
* prctl(PR_RISCV_V_SET_CONTROL, unsigned long arg)
Sets the Vector enablement status of the calling thread, where the control
argument consists of two 2-bit enablement statuses and a bit for inheritance
mode. Other threads of the calling process are unaffected.
Enablement status is a tri-state value each occupying 2-bit of space in
the control argument:
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_DEFAULT`: Use the system-wide default
enablement status on execve(). The system-wide default setting can be
controlled via sysctl interface (see sysctl section below).
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_ON`: Allow Vector to be run for the
thread.
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_OFF`: Disallow Vector. Executing Vector
instructions under such condition will trap and casuse the termination of the thread.
arg: The control argument is a 5-bit value consisting of 3 parts, and
accessed by 3 masks respectively.
The 3 masks, PR_RISCV_V_VSTATE_CTRL_CUR_MASK,
PR_RISCV_V_VSTATE_CTRL_NEXT_MASK, and PR_RISCV_V_VSTATE_CTRL_INHERIT
represents bit[1:0], bit[3:2], and bit[4]. bit[1:0] accounts for the
enablement status of current thread, and the setting at bit[3:2] takes place
at next execve(). bit[4] defines the inheritance mode of the setting in
bit[3:2].
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_CUR_MASK`: bit[1:0]: Account for the
Vector enablement status for the calling thread. The calling thread is
not able to turn off Vector once it has been enabled. The prctl() call
fails with EPERM if the value in this mask is PR_RISCV_V_VSTATE_CTRL_OFF
but the current enablement status is not off. Setting
PR_RISCV_V_VSTATE_CTRL_DEFAULT here takes no effect but to set back
the original enablement status.
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_NEXT_MASK`: bit[3:2]: Account for the
Vector enablement setting for the calling thread at the next execve()
system call. If PR_RISCV_V_VSTATE_CTRL_DEFAULT is used in this mask,
then the enablement status will be decided by the system-wide
enablement status when execve() happen.
* :c:macro:`PR_RISCV_V_VSTATE_CTRL_INHERIT`: bit[4]: the inheritance
mode for the setting at PR_RISCV_V_VSTATE_CTRL_NEXT_MASK. If the bit
is set then the following execve() will not clear the setting in both
PR_RISCV_V_VSTATE_CTRL_NEXT_MASK and PR_RISCV_V_VSTATE_CTRL_INHERIT.
This setting persists across changes in the system-wide default value.
Return value:
* 0 on success;
* EINVAL: Vector not supported, invalid enablement status for current or
next mask;
* EPERM: Turning off Vector in PR_RISCV_V_VSTATE_CTRL_CUR_MASK if Vector
was enabled for the calling thread.
On success:
* A valid setting for PR_RISCV_V_VSTATE_CTRL_CUR_MASK takes place
immediately. The enablement status specified in
PR_RISCV_V_VSTATE_CTRL_NEXT_MASK happens at the next execve() call, or
all following execve() calls if PR_RISCV_V_VSTATE_CTRL_INHERIT bit is
set.
* Every successful call overwrites a previous setting for the calling
thread.
* prctl(PR_RISCV_V_GET_CONTROL)
Gets the same Vector enablement status for the calling thread. Setting for
next execve() call and the inheritance bit are all OR-ed together.
Note that ELF programs are able to get the availability of V for itself by
reading :c:macro:`COMPAT_HWCAP_ISA_V` bit of :c:macro:`ELF_HWCAP` in the
auxiliary vector.
Return value:
* a nonnegative value on success;
* EINVAL: Vector not supported.
2. System runtime configuration (sysctl)
-----------------------------------------
To mitigate the ABI impact of expansion of the signal stack, a
policy mechanism is provided to the administrators, distro maintainers, and
developers to control the default Vector enablement status for userspace
processes in form of sysctl knob:
* /proc/sys/abi/riscv_v_default_allow
Writing the text representation of 0 or 1 to this file sets the default
system enablement status for new starting userspace programs. Valid values
are:
* 0: Do not allow Vector code to be executed as the default for new processes.
* 1: Allow Vector code to be executed as the default for new processes.
Reading this file returns the current system default enablement status.
At every execve() call, a new enablement status of the new process is set to
the system default, unless:
* PR_RISCV_V_VSTATE_CTRL_INHERIT is set for the calling process, and the
setting in PR_RISCV_V_VSTATE_CTRL_NEXT_MASK is not
PR_RISCV_V_VSTATE_CTRL_DEFAULT. Or,
* The setting in PR_RISCV_V_VSTATE_CTRL_NEXT_MASK is not
PR_RISCV_V_VSTATE_CTRL_DEFAULT.
Modifying the system default enablement status does not affect the enablement
status of any existing process of thread that do not make an execve() call.
3. Vector Register State Across System Calls
---------------------------------------------
As indicated by version 1.0 of the V extension [1], vector registers are
clobbered by system calls.
1: https://github.com/riscv/riscv-v-spec/blob/master/calling-convention.adoc
@@ -0,0 +1,136 @@
.. SPDX-License-Identifier: GPL-2.0
=====================================
Virtual Memory Layout on RISC-V Linux
=====================================
:Author: Alexandre Ghiti <alex@ghiti.fr>
:Date: 12 February 2021
This document describes the virtual memory layout used by the RISC-V Linux
Kernel.
RISC-V Linux Kernel 32bit
=========================
RISC-V Linux Kernel SV32
------------------------
TODO
RISC-V Linux Kernel 64bit
=========================
The RISC-V privileged architecture document states that the 64bit addresses
"must have bits 63–48 all equal to bit 47, or else a page-fault exception will
occur.": that splits the virtual address space into 2 halves separated by a very
big hole, the lower half is where the userspace resides, the upper half is where
the RISC-V Linux Kernel resides.
RISC-V Linux Kernel SV39
------------------------
::
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 0000003fffffffff | 256 GB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000004000000000 | +256 GB | ffffffbfffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -256 GB
| | | | starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
| | | |
ffffffc4fea00000 | -236 GB | ffffffc4feffffff | 6 MB | fixmap
ffffffc4ff000000 | -236 GB | ffffffc4ffffffff | 16 MB | PCI io
ffffffc500000000 | -236 GB | ffffffc5ffffffff | 4 GB | vmemmap
ffffffc600000000 | -232 GB | ffffffd5ffffffff | 64 GB | vmalloc/ioremap space
ffffffd600000000 | -168 GB | fffffff5ffffffff | 128 GB | direct mapping of all physical memory
| | | |
fffffff700000000 | -36 GB | fffffffeffffffff | 32 GB | kasan
__________________|____________|__________________|_________|____________________________________________________________
|
|
____________________________________________________________|____________________________________________________________
| | | |
ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
__________________|____________|__________________|_________|____________________________________________________________
RISC-V Linux Kernel SV48
------------------------
::
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00007fffffffffff | 128 TB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0000800000000000 | +128 TB | ffff7fffffffffff | ~16M TB | ... huge, almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -128 TB
| | | | starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
| | | |
ffff8d7ffea00000 | -114.5 TB | ffff8d7ffeffffff | 6 MB | fixmap
ffff8d7fff000000 | -114.5 TB | ffff8d7fffffffff | 16 MB | PCI io
ffff8d8000000000 | -114.5 TB | ffff8f7fffffffff | 2 TB | vmemmap
ffff8f8000000000 | -112.5 TB | ffffaf7fffffffff | 32 TB | vmalloc/ioremap space
ffffaf8000000000 | -80.5 TB | ffffef7fffffffff | 64 TB | direct mapping of all physical memory
ffffef8000000000 | -16.5 TB | fffffffeffffffff | 16.5 TB | kasan
__________________|____________|__________________|_________|____________________________________________________________
|
| Identical layout to the 39-bit one from here on:
____________________________________________________________|____________________________________________________________
| | | |
ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
__________________|____________|__________________|_________|____________________________________________________________
RISC-V Linux Kernel SV57
------------------------
::
========================================================================================================================
Start addr | Offset | End addr | Size | VM area description
========================================================================================================================
| | | |
0000000000000000 | 0 | 00ffffffffffffff | 64 PB | user-space virtual memory, different per mm
__________________|____________|__________________|_________|___________________________________________________________
| | | |
0100000000000000 | +64 PB | feffffffffffffff | ~16K PB | ... huge, almost 64 bits wide hole of non-canonical
| | | | virtual memory addresses up to the -64 PB
| | | | starting offset of kernel mappings.
__________________|____________|__________________|_________|___________________________________________________________
|
| Kernel-space virtual memory, shared between all processes:
____________________________________________________________|___________________________________________________________
| | | |
ff1bfffffea00000 | -57 PB | ff1bfffffeffffff | 6 MB | fixmap
ff1bffffff000000 | -57 PB | ff1bffffffffffff | 16 MB | PCI io
ff1c000000000000 | -57 PB | ff1fffffffffffff | 1 PB | vmemmap
ff20000000000000 | -56 PB | ff5fffffffffffff | 16 PB | vmalloc/ioremap space
ff60000000000000 | -40 PB | ffdeffffffffffff | 32 PB | direct mapping of all physical memory
ffdf000000000000 | -8 PB | fffffffeffffffff | 8 PB | kasan
__________________|____________|__________________|_________|____________________________________________________________
|
| Identical layout to the 39-bit one from here on:
____________________________________________________________|____________________________________________________________
| | | |
ffffffff00000000 | -4 GB | ffffffff7fffffff | 2 GB | modules, BPF
ffffffff80000000 | -2 GB | ffffffffffffffff | 2 GB | kernel
__________________|____________|__________________|_________|____________________________________________________________
@@ -0,0 +1,137 @@
.. SPDX-License-Identifier: GPL-2.0
:Author: Deepak Gupta <debug@rivosinc.com>
:Date: 12 January 2024
====================================================
Tracking indirect control transfers on RISC-V Linux
====================================================
This document briefly describes the interface provided to userspace by Linux
to enable indirect branch tracking for user mode applications on RISC-V.
1. Feature Overview
--------------------
Memory corruption issues usually result in crashes. However, in the
hands of a creative adversary, these can result in a variety of
security issues.
Some of those security issues can be code re-use attacks, where an
adversary can use corrupt function pointers, chaining them together to
perform jump oriented programming (JOP) or call oriented programming
(COP) and thus compromise control flow integrity (CFI) of the program.
Function pointers live in read-write memory and thus are susceptible
to corruption. This can allow an adversary to control the program
counter (PC) value. On RISC-V, the zicfilp extension enforces a
restriction on such indirect control transfers:
- Indirect control transfers must land on a landing pad instruction ``lpad``.
There are two exceptions to this rule:
- rs1 = x1 or rs1 = x5, i.e. a return from a function and returns are
protected using shadow stack (see zicfiss.rst)
- rs1 = x7. On RISC-V, the compiler usually does the following to reach a
function which is beyond the offset of possible J-type instruction::
auipc x7, <imm>
jalr (x7)
This form of indirect control transfer is immutable and doesn't
rely on memory. Thus rs1=x7 is exempted from tracking and
these are considered software guarded jumps.
The ``lpad`` instruction is a pseudo-op of ``auipc rd, <imm_20bit>``
with ``rd=x0``. This is a HINT op. The ``lpad`` instruction must be
aligned on a 4 byte boundary. It compares the 20 bit immediate with
x7. If ``imm_20bit`` == 0, the CPU doesn't perform any comparison with
``x7``. If ``imm_20bit`` != 0, then ``imm_20bit`` must match ``x7``
else CPU will raise ``software check exception`` (``cause=18``) with
``*tval = 2``.
The compiler can generate a hash over function signatures and set them
up (truncated to 20 bits) in x7 at callsites. Function prologues can
have ``lpad`` instructions encoded with the same function hash. This
further reduces the number of valid program counter addresses a call
site can reach.
2. ELF and psABI
-----------------
The toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_FCFI` for
property :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in the notes
section of the object file.
3. Linux enabling
------------------
User space programs can have multiple shared objects loaded in their
address spaces. It's a difficult task to make sure all the
dependencies have been compiled with indirect branch support. Thus
it's left to the dynamic loader to enable indirect branch tracking for
the program.
4. prctl() enabling
--------------------
Per-task indirect branch tracking state can be monitored and
controlled via the :c:macro:`PR_GET_CFI` and :c:macro:`PR_SET_CFI`
``prctl()`` arguments (respectively), by supplying
:c:macro:`PR_CFI_BRANCH_LANDING_PADS` as the second argument. These
are architecture-agnostic, and will return -EINVAL if the underlying
functionality is not supported.
* prctl(:c:macro:`PR_SET_CFI`, :c:macro:`PR_CFI_BRANCH_LANDING_PADS`, unsigned long arg)
arg is a bitmask.
If :c:macro:`PR_CFI_ENABLE` is set in arg, and the CPU supports
``zicfilp``, then the kernel will enable indirect branch tracking for
the task. The dynamic loader can issue this ``prctl()`` once it has
determined that all the objects loaded in the address space support
indirect branch tracking.
Indirect branch tracking state can also be locked once enabled. This
prevents the task from subsequently disabling it. This is done by
setting the bit :c:macro:`PR_CFI_LOCK` in arg. Either indirect branch
tracking must already be enabled for the task, or the bit
:c:macro:`PR_CFI_ENABLE` must also be set in arg. This is intended
for environments that wish to run with a strict security posture that
do not wish to load objects without ``zicfilp`` support.
Indirect branch tracking can also be disabled for the task, assuming
that it has not previously been enabled and locked. If there is a
``dlopen()`` to an object which wasn't compiled with ``zicfilp``, the
dynamic loader can issue this ``prctl()`` with arg set to
:c:macro:`PR_CFI_DISABLE`. Disabling indirect branch tracking for the
task is not possible if it has previously been enabled and locked.
* prctl(:c:macro:`PR_GET_CFI`, :c:macro:`PR_CFI_BRANCH_LANDING_PADS`, unsigned long * arg)
Returns the current status of indirect branch tracking into a bitmask
stored into the memory location pointed to by arg. The bitmask will
have the :c:macro:`PR_CFI_ENABLE` bit set if indirect branch tracking
is currently enabled for the task, and if it is locked, will
additionally have the :c:macro:`PR_CFI_LOCK` bit set. If indirect
branch tracking is currently disabled for the task, the
:c:macro:`PR_CFI_DISABLE` bit will be set.
5. violations related to indirect branch tracking
--------------------------------------------------
Pertaining to indirect branch tracking, the CPU raises a software
check exception in the following conditions:
- missing ``lpad`` after indirect call / jmp
- ``lpad`` not on 4 byte boundary
- ``imm_20bit`` embedded in ``lpad`` instruction doesn't match with ``x7``
In all 3 cases, ``*tval = 2`` is captured and software check exception is
raised (``cause=18``).
The kernel will treat this as :c:macro:`SIGSEGV` with code =
:c:macro:`SEGV_CPERR` and follow the normal course of signal delivery.
@@ -0,0 +1,194 @@
.. SPDX-License-Identifier: GPL-2.0
:Author: Deepak Gupta <debug@rivosinc.com>
:Date: 12 January 2024
=========================================================
Shadow stack to protect function returns on RISC-V Linux
=========================================================
This document briefly describes the interface provided to userspace by Linux
to enable shadow stacks for user mode applications on RISC-V.
1. Feature Overview
--------------------
Memory corruption issues usually result in crashes. However, in the
hands of a creative adversary, these issues can result in a variety of
security problems.
Some of those security issues can be code re-use attacks on programs
where an adversary can use corrupt return addresses present on the
stack. chaining them together to perform return oriented programming
(ROP) and thus compromising the control flow integrity (CFI) of the
program.
Return addresses live on the stack in read-write memory. Therefore
they are susceptible to corruption, which allows an adversary to
control the program counter. On RISC-V, the ``zicfiss`` extension
provides an alternate stack (the "shadow stack") on which return
addresses can be safely placed in the prologue of the function and
retrieved in the epilogue. The ``zicfiss`` extension makes the
following changes:
- PTE encodings for shadow stack virtual memory
An earlier reserved encoding in first stage translation i.e.
PTE.R=0, PTE.W=1, PTE.X=0 becomes the PTE encoding for shadow stack pages.
- The ``sspush x1/x5`` instruction pushes (stores) ``x1/x5`` to shadow stack.
- The ``sspopchk x1/x5`` instruction pops (loads) from shadow stack and compares
with ``x1/x5`` and if not equal, the CPU raises a ``software check exception``
with ``*tval = 3``
The compiler toolchain ensures that function prologues have ``sspush
x1/x5`` to save the return address on shadow stack in addition to the
regular stack. Similarly, function epilogues have ``ld x5,
offset(x2)`` followed by ``sspopchk x5`` to ensure that a popped value
from the regular stack matches with the popped value from the shadow
stack.
2. Shadow stack protections and linux memory manager
-----------------------------------------------------
As mentioned earlier, shadow stacks get new page table encodings that
have some special properties assigned to them, along with instructions
that operate on the shadow stacks:
- Regular stores to shadow stack memory raise store access faults. This
protects shadow stack memory from stray writes.
- Regular loads from shadow stack memory are allowed. This allows
stack trace utilities or backtrace functions to read the true call
stack and ensure that it has not been tampered with.
- Only shadow stack instructions can generate shadow stack loads or
shadow stack stores.
- Shadow stack loads and stores on read-only memory raise AMO/store
page faults. Thus both ``sspush x1/x5`` and ``sspopchk x1/x5`` will
raise AMO/store page fault. This simplies COW handling in kernel
during fork(). The kernel can convert shadow stack pages into
read-only memory (as it does for regular read-write memory). As
soon as subsequent ``sspush`` or ``sspopchk`` instructions in
userspace are encountered, the kernel can perform COW.
- Shadow stack loads and stores on read-write or read-write-execute
memory raise an access fault. This is a fatal condition because
shadow stack loads and stores should never be operating on
read-write or read-write-execute memory.
3. ELF and psABI
-----------------
The toolchain sets up :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_BCFI` for
property :c:macro:`GNU_PROPERTY_RISCV_FEATURE_1_AND` in the notes
section of the object file.
4. Linux enabling
------------------
User space programs can have multiple shared objects loaded in their
address space. It's a difficult task to make sure all the
dependencies have been compiled with shadow stack support. Thus
it's left to the dynamic loader to enable shadow stacks for the
program.
5. prctl() enabling
--------------------
:c:macro:`PR_SET_SHADOW_STACK_STATUS` / :c:macro:`PR_GET_SHADOW_STACK_STATUS` /
:c:macro:`PR_LOCK_SHADOW_STACK_STATUS` are three prctls added to manage shadow
stack enabling for tasks. These prctls are architecture-agnostic and return
-EINVAL if not implemented.
* prctl(PR_SET_SHADOW_STACK_STATUS, unsigned long arg)
If arg = :c:macro:`PR_SHADOW_STACK_ENABLE` and if CPU supports
``zicfiss`` then the kernel will enable shadow stacks for the task.
The dynamic loader can issue this :c:macro:`prctl` once it has
determined that all the objects loaded in address space have support
for shadow stacks. Additionally, if there is a :c:macro:`dlopen` to
an object which wasn't compiled with ``zicfiss``, the dynamic loader
can issue this prctl with arg set to 0 (i.e.
:c:macro:`PR_SHADOW_STACK_ENABLE` being clear)
* prctl(PR_GET_SHADOW_STACK_STATUS, unsigned long * arg)
Returns the current status of indirect branch tracking. If enabled
it'll return :c:macro:`PR_SHADOW_STACK_ENABLE`.
* prctl(PR_LOCK_SHADOW_STACK_STATUS, unsigned long arg)
Locks the current status of shadow stack enabling on the
task. Userspace may want to run with a strict security posture and
wouldn't want loading of objects without ``zicfiss`` support. In this
case userspace can use this prctl to disallow disabling of shadow
stacks on the current task.
5. violations related to returns with shadow stack enabled
-----------------------------------------------------------
Pertaining to shadow stacks, the CPU raises a ``software check
exception`` upon executing ``sspopchk x1/x5`` if ``x1/x5`` doesn't
match the top of shadow stack. If a mismatch happens, then the CPU
sets ``*tval = 3`` and raises the exception.
The Linux kernel will treat this as a :c:macro:`SIGSEGV` with code =
:c:macro:`SEGV_CPERR` and follow the normal course of signal delivery.
6. Shadow stack tokens
-----------------------
Regular stores on shadow stacks are not allowed and thus can't be
tampered with via arbitrary stray writes. However, one method of
pivoting / switching to a shadow stack is simply writing to the CSR
``CSR_SSP``. This will change the active shadow stack for the
program. Writes to ``CSR_SSP`` in the program should be mostly
limited to context switches, stack unwinds, or longjmp or similar
mechanisms (like context switching of Green Threads) in languages like
Go and Rust. CSR_SSP writes can be problematic because an attacker can
use memory corruption bugs and leverage context switching routines to
pivot to any shadow stack. Shadow stack tokens can help mitigate this
problem by making sure that:
- When software is switching away from a shadow stack, the shadow
stack pointer should be saved on the shadow stack itself (this is
called the ``shadow stack token``).
- When software is switching to a shadow stack, it should read the
``shadow stack token`` from the shadow stack pointer and verify that
the ``shadow stack token`` itself is a pointer to the shadow stack
itself.
- Once the token verification is done, software can perform the write
to ``CSR_SSP`` to switch shadow stacks.
Here "software" could refer to the user mode task runtime itself,
managing various contexts as part of a single thread. Or "software"
could refer to the kernel, when the kernel has to deliver a signal to
a user task and must save the shadow stack pointer. The kernel can
perform similar procedure itself by saving a token on the user mode
task's shadow stack. This way, whenever :c:macro:`sigreturn` happens,
the kernel can read and verify the token and then switch to the shadow
stack. Using this mechanism, the kernel helps the user task so that
any corruption issue in the user task is not exploited by adversaries
arbitrarily using :c:macro:`sigreturn`. Adversaries will have to make
sure that there is a valid ``shadow stack token`` in addition to
invoking :c:macro:`sigreturn`.
7. Signal shadow stack
-----------------------
The following structure has been added to sigcontext for RISC-V::
struct __sc_riscv_cfi_state {
unsigned long ss_ptr;
};
As part of signal delivery, the shadow stack token is saved on the
current shadow stack itself. The updated pointer is saved away in the
:c:macro:`ss_ptr` field in :c:macro:`__sc_riscv_cfi_state` under
:c:macro:`sigcontext`. The existing shadow stack allocation is used
for signal delivery. During :c:macro:`sigreturn`, kernel will obtain
:c:macro:`ss_ptr` from :c:macro:`sigcontext`, verify the saved
token on the shadow stack, and switch the shadow stack.