Merge e88481f74f ("Merge tag 'rproc-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux") into android-mainline
Steps on the way to v6.8-rc1 Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: I258f6bcee2aac7c911fd5f8c7d6801a9998b1d9e
This commit is contained in:
@@ -75,4 +75,4 @@ taking two different snapshots of feedback counters at time T1 and T2.
|
||||
delivered_counter_delta = fbc_t2[del] - fbc_t1[del]
|
||||
reference_counter_delta = fbc_t2[ref] - fbc_t1[ref]
|
||||
|
||||
delivered_perf = (refernce_perf x delivered_counter_delta) / reference_counter_delta
|
||||
delivered_perf = (reference_perf x delivered_counter_delta) / reference_counter_delta
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features
|
||||
.. kernel-feat:: features
|
||||
|
||||
@@ -14,10 +14,9 @@ into that core.
|
||||
|
||||
To make the most effective use of these mechanisms, you
|
||||
should download the support software as well. Download the
|
||||
latest version of the "rng-tools" package from the
|
||||
hw_random driver's official Web site:
|
||||
latest version of the "rng-tools" package from:
|
||||
|
||||
http://sourceforge.net/projects/gkernel/
|
||||
https://github.com/nhorman/rng-tools
|
||||
|
||||
Those tools use /dev/hwrng to fill the kernel entropy pool,
|
||||
which is used internally and exported by the /dev/urandom and
|
||||
|
||||
@@ -4000,9 +4000,9 @@
|
||||
vulnerability. System may allow data leaks with this
|
||||
option.
|
||||
|
||||
no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES] Disable paravirtualized
|
||||
steal time accounting. steal time is computed, but
|
||||
won't influence scheduler behaviour
|
||||
no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV] Disable
|
||||
paravirtualized steal time accounting. steal time is
|
||||
computed, but won't influence scheduler behaviour
|
||||
|
||||
nosync [HW,M68K] Disables sync negotiation for all devices.
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ Global Attributes
|
||||
|
||||
``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
|
||||
control its functionality at the system level. They are located in the
|
||||
``/sys/devices/system/cpu/amd-pstate/`` directory and affect all CPUs.
|
||||
``/sys/devices/system/cpu/amd_pstate/`` directory and affect all CPUs.
|
||||
|
||||
``status``
|
||||
Operation mode of the driver: "active", "passive" or "disable".
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features arc
|
||||
.. kernel-feat:: features arc
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features arm
|
||||
.. kernel-feat:: features arm
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features arm64
|
||||
.. kernel-feat:: features arm64
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features loongarch
|
||||
.. kernel-feat:: features loongarch
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features m68k
|
||||
.. kernel-feat:: features m68k
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features mips
|
||||
.. kernel-feat:: features mips
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features nios2
|
||||
.. kernel-feat:: features nios2
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features openrisc
|
||||
.. kernel-feat:: features openrisc
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features parisc
|
||||
.. kernel-feat:: features parisc
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features powerpc
|
||||
.. kernel-feat:: features powerpc
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features riscv
|
||||
.. kernel-feat:: features riscv
|
||||
|
||||
@@ -12,7 +12,7 @@ is defined in <asm/hwprobe.h>::
|
||||
};
|
||||
|
||||
long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
|
||||
size_t cpu_count, cpu_set_t *cpus,
|
||||
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
|
||||
@@ -20,12 +20,26 @@ 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). For value-like keys (eg. vendor/arch/impl), the returned value will
|
||||
be 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 cpu_count as a shortcut for all online CPUs. There are currently no flags,
|
||||
this value must be zero for future compatibility.
|
||||
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.
|
||||
|
||||
@@ -80,6 +94,100 @@ The following keys are defined:
|
||||
* :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_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_KEY_CPUPERF_0`: A bitmask that contains performance
|
||||
information about the selected set of processors.
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features s390
|
||||
.. kernel-feat:: features s390
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features sh
|
||||
.. kernel-feat:: features sh
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features sparc
|
||||
.. kernel-feat:: features sparc
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features x86
|
||||
.. kernel-feat:: features x86
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features xtensa
|
||||
.. kernel-feat:: features xtensa
|
||||
|
||||
@@ -446,7 +446,7 @@ The command used: ::
|
||||
|
||||
There are 24 issuers, each issuing 64 IOs concurrently. ``--verify=sha512``
|
||||
makes ``fio`` generate and read back the content each time which makes
|
||||
execution locality matter between the issuer and ``kcryptd``. The followings
|
||||
execution locality matter between the issuer and ``kcryptd``. The following
|
||||
are the read bandwidths and CPU utilizations depending on different affinity
|
||||
scope settings on ``kcryptd`` measured over five runs. Bandwidths are in
|
||||
MiBps, and CPU util in percents.
|
||||
|
||||
@@ -139,6 +139,17 @@ If your installed version of gcc doesn't work, you can tweak the steps:
|
||||
$ ./tools/testing/kunit/kunit.py run --make_options=CC=/usr/bin/gcc-6
|
||||
$ lcov -t "my_kunit_tests" -o coverage.info -c -d .kunit/ --gcov-tool=/usr/bin/gcov-6
|
||||
|
||||
Alternatively, LLVM-based toolchains can also be used:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Build with LLVM and append coverage options to the current config
|
||||
$ ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --kunitconfig=.kunit/ --kunitconfig=tools/testing/kunit/configs/coverage_uml.config
|
||||
$ llvm-profdata merge -sparse default.profraw -o default.profdata
|
||||
$ llvm-cov export --format=lcov .kunit/vmlinux -instr-profile default.profdata > coverage.info
|
||||
# The coverage.info file is in lcov-compatible format and it can be used to e.g. generate HTML report
|
||||
$ genhtml -o /tmp/coverage_html coverage.info
|
||||
|
||||
|
||||
Running tests manually
|
||||
======================
|
||||
|
||||
@@ -18,7 +18,10 @@ properties:
|
||||
enum:
|
||||
- qcom,sc7180-adsp-pas
|
||||
- qcom,sc7180-mpss-pas
|
||||
- qcom,sc7280-adsp-pas
|
||||
- qcom,sc7280-cdsp-pas
|
||||
- qcom,sc7280-mpss-pas
|
||||
- qcom,sc7280-wpss-pas
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@@ -75,6 +78,7 @@ allOf:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7180-adsp-pas
|
||||
- qcom,sc7280-adsp-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
@@ -109,6 +113,23 @@ allOf:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7280-mpss-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
items:
|
||||
- description: CX power domain
|
||||
- description: MSS power domain
|
||||
power-domain-names:
|
||||
items:
|
||||
- const: cx
|
||||
- const: mss
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sc7280-cdsp-pas
|
||||
- qcom,sc7280-wpss-pas
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
|
||||
@@ -32,6 +32,7 @@ properties:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- amd,mbv32
|
||||
- andestech,ax45mp
|
||||
- canaan,k210
|
||||
- sifive,bullet0
|
||||
|
||||
@@ -171,6 +171,12 @@ properties:
|
||||
memory types as ratified in the 20191213 version of the privileged
|
||||
ISA specification.
|
||||
|
||||
- const: zacas
|
||||
description: |
|
||||
The Zacas extension for Atomic Compare-and-Swap (CAS) instructions
|
||||
is supported as ratified at commit 5059e0ca641c ("update to
|
||||
ratified") of the riscv-zacas.
|
||||
|
||||
- const: zba
|
||||
description: |
|
||||
The standard Zba bit-manipulation extension for address generation
|
||||
@@ -190,12 +196,111 @@ properties:
|
||||
multiplication as ratified at commit 6d33919 ("Merge pull request
|
||||
#158 from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip.
|
||||
|
||||
- const: zbkb
|
||||
description:
|
||||
The standard Zbkb bitmanip instructions for cryptography as ratified
|
||||
in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zbkc
|
||||
description:
|
||||
The standard Zbkc carry-less multiply instructions as ratified
|
||||
in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zbkx
|
||||
description:
|
||||
The standard Zbkx crossbar permutation instructions as ratified
|
||||
in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zbs
|
||||
description: |
|
||||
The standard Zbs bit-manipulation extension for single-bit
|
||||
instructions as ratified at commit 6d33919 ("Merge pull request #158
|
||||
from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip.
|
||||
|
||||
- const: zfa
|
||||
description:
|
||||
The standard Zfa extension for additional floating point
|
||||
instructions, as ratified in commit 056b6ff ("Zfa is ratified") of
|
||||
riscv-isa-manual.
|
||||
|
||||
- const: zfh
|
||||
description:
|
||||
The standard Zfh extension for 16-bit half-precision binary
|
||||
floating-point instructions, as ratified in commit 64074bc ("Update
|
||||
version numbers for Zfh/Zfinx") of riscv-isa-manual.
|
||||
|
||||
- const: zfhmin
|
||||
description:
|
||||
The standard Zfhmin extension which provides minimal support for
|
||||
16-bit half-precision binary floating-point instructions, as ratified
|
||||
in commit 64074bc ("Update version numbers for Zfh/Zfinx") of
|
||||
riscv-isa-manual.
|
||||
|
||||
- const: zk
|
||||
description:
|
||||
The standard Zk Standard Scalar cryptography extension as ratified
|
||||
in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zkn
|
||||
description:
|
||||
The standard Zkn NIST algorithm suite extensions as ratified in
|
||||
version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zknd
|
||||
description: |
|
||||
The standard Zknd for NIST suite: AES decryption instructions as
|
||||
ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zkne
|
||||
description: |
|
||||
The standard Zkne for NIST suite: AES encryption instructions as
|
||||
ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zknh
|
||||
description: |
|
||||
The standard Zknh for NIST suite: hash function instructions as
|
||||
ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zkr
|
||||
description:
|
||||
The standard Zkr entropy source extension as ratified in version
|
||||
1.0 of RISC-V Cryptography Extensions Volume I specification.
|
||||
This string being present means that the CSR associated to this
|
||||
extension is accessible at the privilege level to which that
|
||||
device-tree has been provided.
|
||||
|
||||
- const: zks
|
||||
description:
|
||||
The standard Zks ShangMi algorithm suite extensions as ratified in
|
||||
version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zksed
|
||||
description: |
|
||||
The standard Zksed for ShangMi suite: SM4 block cipher instructions
|
||||
as ratified in version 1.0 of RISC-V Cryptography Extensions
|
||||
Volume I specification.
|
||||
|
||||
- const: zksh
|
||||
description: |
|
||||
The standard Zksh for ShangMi suite: SM3 hash function instructions
|
||||
as ratified in version 1.0 of RISC-V Cryptography Extensions
|
||||
Volume I specification.
|
||||
|
||||
- const: zkt
|
||||
description:
|
||||
The standard Zkt for data independent execution latency as ratified
|
||||
in version 1.0 of RISC-V Cryptography Extensions Volume I
|
||||
specification.
|
||||
|
||||
- const: zicbom
|
||||
description:
|
||||
The standard Zicbom extension for base cache management operations as
|
||||
@@ -246,6 +351,12 @@ properties:
|
||||
The standard Zihintpause extension for pause hints, as ratified in
|
||||
commit d8ab5c7 ("Zihintpause is ratified") of the riscv-isa-manual.
|
||||
|
||||
- const: zihintntl
|
||||
description:
|
||||
The standard Zihintntl extension for non-temporal locality hints, as
|
||||
ratified in commit 0dc91f5 ("Zihintntl is ratified") of the
|
||||
riscv-isa-manual.
|
||||
|
||||
- const: zihpm
|
||||
description:
|
||||
The standard Zihpm extension for hardware performance counters, as
|
||||
@@ -258,5 +369,113 @@ properties:
|
||||
in commit 2e5236 ("Ztso is now ratified.") of the
|
||||
riscv-isa-manual.
|
||||
|
||||
- const: zvbb
|
||||
description:
|
||||
The standard Zvbb extension for vectored basic bit-manipulation
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvbc
|
||||
description:
|
||||
The standard Zvbc extension for vectored carryless multiplication
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvfh
|
||||
description:
|
||||
The standard Zvfh extension for vectored half-precision
|
||||
floating-point instructions, as ratified in commit e2ccd05
|
||||
("Remove draft warnings from Zvfh[min]") of riscv-v-spec.
|
||||
|
||||
- const: zvfhmin
|
||||
description:
|
||||
The standard Zvfhmin extension for vectored minimal half-precision
|
||||
floating-point instructions, as ratified in commit e2ccd05
|
||||
("Remove draft warnings from Zvfh[min]") of riscv-v-spec.
|
||||
|
||||
- const: zvkb
|
||||
description:
|
||||
The standard Zvkb extension for vector cryptography bit-manipulation
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvkg
|
||||
description:
|
||||
The standard Zvkg extension for vector GCM/GMAC instructions, as
|
||||
ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc")
|
||||
of riscv-crypto.
|
||||
|
||||
- const: zvkn
|
||||
description:
|
||||
The standard Zvkn extension for NIST algorithm suite instructions, as
|
||||
ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc")
|
||||
of riscv-crypto.
|
||||
|
||||
- const: zvknc
|
||||
description:
|
||||
The standard Zvknc extension for NIST algorithm suite with carryless
|
||||
multiply instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvkned
|
||||
description:
|
||||
The standard Zvkned extension for Vector AES block cipher
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvkng
|
||||
description:
|
||||
The standard Zvkng extension for NIST algorithm suite with GCM
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvknha
|
||||
description: |
|
||||
The standard Zvknha extension for NIST suite: vector SHA-2 secure,
|
||||
hash (SHA-256 only) instructions, as ratified in commit
|
||||
56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvknhb
|
||||
description: |
|
||||
The standard Zvknhb extension for NIST suite: vector SHA-2 secure,
|
||||
hash (SHA-256 and SHA-512) instructions, as ratified in commit
|
||||
56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvks
|
||||
description:
|
||||
The standard Zvks extension for ShangMi algorithm suite
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvksc
|
||||
description:
|
||||
The standard Zvksc extension for ShangMi algorithm suite with
|
||||
carryless multiplication instructions, as ratified in commit 56ed795
|
||||
("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvksed
|
||||
description: |
|
||||
The standard Zvksed extension for ShangMi suite: SM4 block cipher
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvksh
|
||||
description: |
|
||||
The standard Zvksh extension for ShangMi suite: SM3 secure hash
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvksg
|
||||
description:
|
||||
The standard Zvksg extension for ShangMi algorithm suite with GCM
|
||||
instructions, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
- const: zvkt
|
||||
description:
|
||||
The standard Zvkt extension for vector data-independent execution
|
||||
latency, as ratified in commit 56ed795 ("Update
|
||||
riscv-crypto-spec-vector.adoc") of riscv-crypto.
|
||||
|
||||
additionalProperties: true
|
||||
...
|
||||
|
||||
@@ -37,8 +37,6 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from os import path
|
||||
|
||||
from docutils import nodes, statemachine
|
||||
from docutils.statemachine import ViewList
|
||||
from docutils.parsers.rst import directives, Directive
|
||||
@@ -76,33 +74,26 @@ class KernelFeat(Directive):
|
||||
self.state.document.settings.env.app.warn(message, prefix="")
|
||||
|
||||
def run(self):
|
||||
|
||||
doc = self.state.document
|
||||
if not doc.settings.file_insertion_enabled:
|
||||
raise self.warning("docutils: file insertion disabled")
|
||||
|
||||
env = doc.settings.env
|
||||
cwd = path.dirname(doc.current_source)
|
||||
cmd = "get_feat.pl rest --enable-fname --dir "
|
||||
cmd += self.arguments[0]
|
||||
|
||||
srctree = os.path.abspath(os.environ["srctree"])
|
||||
|
||||
args = [
|
||||
os.path.join(srctree, 'scripts/get_feat.pl'),
|
||||
'rest',
|
||||
'--enable-fname',
|
||||
'--dir',
|
||||
os.path.join(srctree, 'Documentation', self.arguments[0]),
|
||||
]
|
||||
|
||||
if len(self.arguments) > 1:
|
||||
cmd += " --arch " + self.arguments[1]
|
||||
args.extend(['--arch', self.arguments[1]])
|
||||
|
||||
srctree = path.abspath(os.environ["srctree"])
|
||||
|
||||
fname = cmd
|
||||
|
||||
# extend PATH with $(srctree)/scripts
|
||||
path_env = os.pathsep.join([
|
||||
srctree + os.sep + "scripts",
|
||||
os.environ["PATH"]
|
||||
])
|
||||
shell_env = os.environ.copy()
|
||||
shell_env["PATH"] = path_env
|
||||
shell_env["srctree"] = srctree
|
||||
|
||||
lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
|
||||
lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
|
||||
|
||||
line_regex = re.compile(r"^\.\. FILE (\S+)$")
|
||||
|
||||
@@ -121,30 +112,6 @@ class KernelFeat(Directive):
|
||||
nodeList = self.nestedParse(out_lines, fname)
|
||||
return nodeList
|
||||
|
||||
def runCmd(self, cmd, **kwargs):
|
||||
u"""Run command ``cmd`` and return its stdout as unicode."""
|
||||
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
cmd
|
||||
, stdout = subprocess.PIPE
|
||||
, stderr = subprocess.PIPE
|
||||
, **kwargs
|
||||
)
|
||||
out, err = proc.communicate()
|
||||
|
||||
out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise self.severe(
|
||||
u"command '%s' failed with return code %d"
|
||||
% (cmd, proc.returncode)
|
||||
)
|
||||
except OSError as exc:
|
||||
raise self.severe(u"problems with '%s' directive: %s."
|
||||
% (self.name, ErrorString(exc)))
|
||||
return out
|
||||
|
||||
def nestedParse(self, lines, fname):
|
||||
content = ViewList()
|
||||
node = nodes.section()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# jinja2>=3.1 is not compatible with Sphinx<4.0
|
||||
jinja2<3.1
|
||||
# alabaster>=0.7.14 is not compatible with Sphinx<=3.3
|
||||
alabaster<0.7.14
|
||||
Sphinx==2.4.4
|
||||
pyyaml
|
||||
|
||||
@@ -68,13 +68,14 @@ User API
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
|
||||
int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
|
||||
|
||||
sends a message across to the remote processor on a given channel.
|
||||
The caller should specify the channel, the data it wants to send,
|
||||
sends a message across to the remote processor from the given endpoint.
|
||||
The caller should specify the endpoint, the data it wants to send,
|
||||
and its length (in bytes). The message will be sent on the specified
|
||||
channel, i.e. its source and destination address fields will be
|
||||
set to the channel's src and dst addresses.
|
||||
endpoint's channel, i.e. its source and destination address fields will be
|
||||
respectively set to the endpoint's src address and its parent channel
|
||||
dst addresses.
|
||||
|
||||
In case there are no TX buffers available, the function will block until
|
||||
one becomes available (i.e. until the remote processor consumes
|
||||
@@ -87,17 +88,18 @@ Returns 0 on success and an appropriate error value on failure.
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
|
||||
int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
|
||||
|
||||
sends a message across to the remote processor on a given channel,
|
||||
sends a message across to the remote processor from a given endpoint,
|
||||
to a destination address provided by the caller.
|
||||
|
||||
The caller should specify the channel, the data it wants to send,
|
||||
The caller should specify the endpoint, the data it wants to send,
|
||||
its length (in bytes), and an explicit destination address.
|
||||
|
||||
The message will then be sent to the remote processor to which the
|
||||
channel belongs, using the channel's src address, and the user-provided
|
||||
dst address (thus the channel's dst address will be ignored).
|
||||
endpoints's channel belongs, using the endpoints's src address,
|
||||
and the user-provided dst address (thus the channel's dst address
|
||||
will be ignored).
|
||||
|
||||
In case there are no TX buffers available, the function will block until
|
||||
one becomes available (i.e. until the remote processor consumes
|
||||
@@ -110,18 +112,19 @@ Returns 0 on success and an appropriate error value on failure.
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
|
||||
int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
|
||||
void *data, int len);
|
||||
|
||||
|
||||
sends a message across to the remote processor, using the src and dst
|
||||
addresses provided by the user.
|
||||
|
||||
The caller should specify the channel, the data it wants to send,
|
||||
The caller should specify the endpoint, the data it wants to send,
|
||||
its length (in bytes), and explicit source and destination addresses.
|
||||
The message will then be sent to the remote processor to which the
|
||||
channel belongs, but the channel's src and dst addresses will be
|
||||
ignored (and the user-provided addresses will be used instead).
|
||||
endpoint's channel belongs, but the endpoint's src and channel dst
|
||||
addresses will be ignored (and the user-provided addresses will
|
||||
be used instead).
|
||||
|
||||
In case there are no TX buffers available, the function will block until
|
||||
one becomes available (i.e. until the remote processor consumes
|
||||
@@ -134,13 +137,14 @@ Returns 0 on success and an appropriate error value on failure.
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
|
||||
int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
|
||||
|
||||
sends a message across to the remote processor on a given channel.
|
||||
The caller should specify the channel, the data it wants to send,
|
||||
sends a message across to the remote processor from a given endpoint.
|
||||
The caller should specify the endpoint, the data it wants to send,
|
||||
and its length (in bytes). The message will be sent on the specified
|
||||
channel, i.e. its source and destination address fields will be
|
||||
set to the channel's src and dst addresses.
|
||||
endpoint's channel, i.e. its source and destination address fields will be
|
||||
respectively set to the endpoint's src address and its parent channel
|
||||
dst addresses.
|
||||
|
||||
In case there are no TX buffers available, the function will immediately
|
||||
return -ENOMEM without waiting until one becomes available.
|
||||
@@ -150,10 +154,10 @@ Returns 0 on success and an appropriate error value on failure.
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
|
||||
int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
|
||||
|
||||
|
||||
sends a message across to the remote processor on a given channel,
|
||||
sends a message across to the remote processor from a given endoint,
|
||||
to a destination address provided by the user.
|
||||
|
||||
The user should specify the channel, the data it wants to send,
|
||||
@@ -171,7 +175,7 @@ Returns 0 on success and an appropriate error value on failure.
|
||||
|
||||
::
|
||||
|
||||
int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
|
||||
int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
|
||||
void *data, int len);
|
||||
|
||||
|
||||
@@ -284,7 +288,7 @@ content to the console.
|
||||
dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
|
||||
|
||||
/* send a message on our channel */
|
||||
err = rpmsg_send(rpdev, "hello!", 6);
|
||||
err = rpmsg_send(rpdev->ept, "hello!", 6);
|
||||
if (err) {
|
||||
pr_err("rpmsg_send failed: %d\n", err);
|
||||
return err;
|
||||
|
||||
@@ -4,7 +4,7 @@ Kernel Probes (Kprobes)
|
||||
|
||||
:Author: Jim Keniston <jkenisto@us.ibm.com>
|
||||
:Author: Prasanna S Panchamukhi <prasanna.panchamukhi@gmail.com>
|
||||
:Author: Masami Hiramatsu <mhiramat@redhat.com>
|
||||
:Author: Masami Hiramatsu <mhiramat@kernel.org>
|
||||
|
||||
.. CONTENTS
|
||||
|
||||
@@ -321,6 +321,7 @@ architectures:
|
||||
- mips
|
||||
- s390
|
||||
- parisc
|
||||
- loongarch
|
||||
|
||||
Configuring Kprobes
|
||||
===================
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
:Original: Documentation/arch/loongarch/features.rst
|
||||
:Translator: Huacai Chen <chenhuacai@loongson.cn>
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features loongarch
|
||||
.. kernel-feat:: features loongarch
|
||||
|
||||
@@ -10,4 +10,4 @@
|
||||
|
||||
.. _cn_features:
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features mips
|
||||
.. kernel-feat:: features mips
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
:Original: Documentation/arch/loongarch/features.rst
|
||||
:Translator: Huacai Chen <chenhuacai@loongson.cn>
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features loongarch
|
||||
.. kernel-feat:: features loongarch
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
|
||||
.. _tw_features:
|
||||
|
||||
.. kernel-feat:: $srctree/Documentation/features mips
|
||||
.. kernel-feat:: features mips
|
||||
|
||||
|
||||
+207
-12
@@ -147,10 +147,29 @@ described as 'basic' will be available.
|
||||
The new VM has no virtual cpus and no memory.
|
||||
You probably want to use 0 as machine type.
|
||||
|
||||
X86:
|
||||
^^^^
|
||||
|
||||
Supported X86 VM types can be queried via KVM_CAP_VM_TYPES.
|
||||
|
||||
S390:
|
||||
^^^^^
|
||||
|
||||
In order to create user controlled virtual machines on S390, check
|
||||
KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
|
||||
privileged user (CAP_SYS_ADMIN).
|
||||
|
||||
MIPS:
|
||||
^^^^^
|
||||
|
||||
To use hardware assisted virtualization on MIPS (VZ ASE) rather than
|
||||
the default trap & emulate implementation (which changes the virtual
|
||||
memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
|
||||
flag KVM_VM_MIPS_VZ.
|
||||
|
||||
ARM64:
|
||||
^^^^^^
|
||||
|
||||
On arm64, the physical address size for a VM (IPA Size limit) is limited
|
||||
to 40bits by default. The limit can be configured if the host supports the
|
||||
extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
|
||||
@@ -608,18 +627,6 @@ interrupt number dequeues the interrupt.
|
||||
This is an asynchronous vcpu ioctl and can be invoked from any thread.
|
||||
|
||||
|
||||
4.17 KVM_DEBUG_GUEST
|
||||
--------------------
|
||||
|
||||
:Capability: basic
|
||||
:Architectures: none
|
||||
:Type: vcpu ioctl
|
||||
:Parameters: none)
|
||||
:Returns: -1 on error
|
||||
|
||||
Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
|
||||
|
||||
|
||||
4.18 KVM_GET_MSRS
|
||||
-----------------
|
||||
|
||||
@@ -6192,6 +6199,130 @@ to know what fields can be changed for the system register described by
|
||||
``op0, op1, crn, crm, op2``. KVM rejects ID register values that describe a
|
||||
superset of the features supported by the system.
|
||||
|
||||
4.140 KVM_SET_USER_MEMORY_REGION2
|
||||
---------------------------------
|
||||
|
||||
:Capability: KVM_CAP_USER_MEMORY2
|
||||
:Architectures: all
|
||||
:Type: vm ioctl
|
||||
:Parameters: struct kvm_userspace_memory_region2 (in)
|
||||
:Returns: 0 on success, -1 on error
|
||||
|
||||
KVM_SET_USER_MEMORY_REGION2 is an extension to KVM_SET_USER_MEMORY_REGION that
|
||||
allows mapping guest_memfd memory into a guest. All fields shared with
|
||||
KVM_SET_USER_MEMORY_REGION identically. Userspace can set KVM_MEM_GUEST_MEMFD
|
||||
in flags to have KVM bind the memory region to a given guest_memfd range of
|
||||
[guest_memfd_offset, guest_memfd_offset + memory_size]. The target guest_memfd
|
||||
must point at a file created via KVM_CREATE_GUEST_MEMFD on the current VM, and
|
||||
the target range must not be bound to any other memory region. All standard
|
||||
bounds checks apply (use common sense).
|
||||
|
||||
::
|
||||
|
||||
struct kvm_userspace_memory_region2 {
|
||||
__u32 slot;
|
||||
__u32 flags;
|
||||
__u64 guest_phys_addr;
|
||||
__u64 memory_size; /* bytes */
|
||||
__u64 userspace_addr; /* start of the userspace allocated memory */
|
||||
__u64 guest_memfd_offset;
|
||||
__u32 guest_memfd;
|
||||
__u32 pad1;
|
||||
__u64 pad2[14];
|
||||
};
|
||||
|
||||
A KVM_MEM_GUEST_MEMFD region _must_ have a valid guest_memfd (private memory) and
|
||||
userspace_addr (shared memory). However, "valid" for userspace_addr simply
|
||||
means that the address itself must be a legal userspace address. The backing
|
||||
mapping for userspace_addr is not required to be valid/populated at the time of
|
||||
KVM_SET_USER_MEMORY_REGION2, e.g. shared memory can be lazily mapped/allocated
|
||||
on-demand.
|
||||
|
||||
When mapping a gfn into the guest, KVM selects shared vs. private, i.e consumes
|
||||
userspace_addr vs. guest_memfd, based on the gfn's KVM_MEMORY_ATTRIBUTE_PRIVATE
|
||||
state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute
|
||||
is '0' for all gfns. Userspace can control whether memory is shared/private by
|
||||
toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed.
|
||||
|
||||
4.141 KVM_SET_MEMORY_ATTRIBUTES
|
||||
-------------------------------
|
||||
|
||||
:Capability: KVM_CAP_MEMORY_ATTRIBUTES
|
||||
:Architectures: x86
|
||||
:Type: vm ioctl
|
||||
:Parameters: struct kvm_memory_attributes (in)
|
||||
:Returns: 0 on success, <0 on error
|
||||
|
||||
KVM_SET_MEMORY_ATTRIBUTES allows userspace to set memory attributes for a range
|
||||
of guest physical memory.
|
||||
|
||||
::
|
||||
|
||||
struct kvm_memory_attributes {
|
||||
__u64 address;
|
||||
__u64 size;
|
||||
__u64 attributes;
|
||||
__u64 flags;
|
||||
};
|
||||
|
||||
#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
|
||||
|
||||
The address and size must be page aligned. The supported attributes can be
|
||||
retrieved via ioctl(KVM_CHECK_EXTENSION) on KVM_CAP_MEMORY_ATTRIBUTES. If
|
||||
executed on a VM, KVM_CAP_MEMORY_ATTRIBUTES precisely returns the attributes
|
||||
supported by that VM. If executed at system scope, KVM_CAP_MEMORY_ATTRIBUTES
|
||||
returns all attributes supported by KVM. The only attribute defined at this
|
||||
time is KVM_MEMORY_ATTRIBUTE_PRIVATE, which marks the associated gfn as being
|
||||
guest private memory.
|
||||
|
||||
Note, there is no "get" API. Userspace is responsible for explicitly tracking
|
||||
the state of a gfn/page as needed.
|
||||
|
||||
The "flags" field is reserved for future extensions and must be '0'.
|
||||
|
||||
4.142 KVM_CREATE_GUEST_MEMFD
|
||||
----------------------------
|
||||
|
||||
:Capability: KVM_CAP_GUEST_MEMFD
|
||||
:Architectures: none
|
||||
:Type: vm ioctl
|
||||
:Parameters: struct kvm_create_guest_memfd(in)
|
||||
:Returns: 0 on success, <0 on error
|
||||
|
||||
KVM_CREATE_GUEST_MEMFD creates an anonymous file and returns a file descriptor
|
||||
that refers to it. guest_memfd files are roughly analogous to files created
|
||||
via memfd_create(), e.g. guest_memfd files live in RAM, have volatile storage,
|
||||
and are automatically released when the last reference is dropped. Unlike
|
||||
"regular" memfd_create() files, guest_memfd files are bound to their owning
|
||||
virtual machine (see below), cannot be mapped, read, or written by userspace,
|
||||
and cannot be resized (guest_memfd files do however support PUNCH_HOLE).
|
||||
|
||||
::
|
||||
|
||||
struct kvm_create_guest_memfd {
|
||||
__u64 size;
|
||||
__u64 flags;
|
||||
__u64 reserved[6];
|
||||
};
|
||||
|
||||
Conceptually, the inode backing a guest_memfd file represents physical memory,
|
||||
i.e. is coupled to the virtual machine as a thing, not to a "struct kvm". The
|
||||
file itself, which is bound to a "struct kvm", is that instance's view of the
|
||||
underlying memory, e.g. effectively provides the translation of guest addresses
|
||||
to host memory. This allows for use cases where multiple KVM structures are
|
||||
used to manage a single virtual machine, e.g. when performing intrahost
|
||||
migration of a virtual machine.
|
||||
|
||||
KVM currently only supports mapping guest_memfd via KVM_SET_USER_MEMORY_REGION2,
|
||||
and more specifically via the guest_memfd and guest_memfd_offset fields in
|
||||
"struct kvm_userspace_memory_region2", where guest_memfd_offset is the offset
|
||||
into the guest_memfd instance. For a given guest_memfd file, there can be at
|
||||
most one mapping per page, i.e. binding multiple memory regions to a single
|
||||
guest_memfd range is not allowed (any number of memory regions can be bound to
|
||||
a single guest_memfd file, but the bound ranges must not overlap).
|
||||
|
||||
See KVM_SET_USER_MEMORY_REGION2 for additional details.
|
||||
|
||||
5. The kvm_run structure
|
||||
========================
|
||||
|
||||
@@ -6824,6 +6955,30 @@ array field represents return values. The userspace should update the return
|
||||
values of SBI call before resuming the VCPU. For more details on RISC-V SBI
|
||||
spec refer, https://github.com/riscv/riscv-sbi-doc.
|
||||
|
||||
::
|
||||
|
||||
/* KVM_EXIT_MEMORY_FAULT */
|
||||
struct {
|
||||
#define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3)
|
||||
__u64 flags;
|
||||
__u64 gpa;
|
||||
__u64 size;
|
||||
} memory_fault;
|
||||
|
||||
KVM_EXIT_MEMORY_FAULT indicates the vCPU has encountered a memory fault that
|
||||
could not be resolved by KVM. The 'gpa' and 'size' (in bytes) describe the
|
||||
guest physical address range [gpa, gpa + size) of the fault. The 'flags' field
|
||||
describes properties of the faulting access that are likely pertinent:
|
||||
|
||||
- KVM_MEMORY_EXIT_FLAG_PRIVATE - When set, indicates the memory fault occurred
|
||||
on a private memory access. When clear, indicates the fault occurred on a
|
||||
shared access.
|
||||
|
||||
Note! KVM_EXIT_MEMORY_FAULT is unique among all KVM exit reasons in that it
|
||||
accompanies a return code of '-1', not '0'! errno will always be set to EFAULT
|
||||
or EHWPOISON when KVM exits with KVM_EXIT_MEMORY_FAULT, userspace should assume
|
||||
kvm_run.exit_reason is stale/undefined for all other error numbers.
|
||||
|
||||
::
|
||||
|
||||
/* KVM_EXIT_NOTIFY */
|
||||
@@ -7858,6 +8013,27 @@ This capability is aimed to mitigate the threat that malicious VMs can
|
||||
cause CPU stuck (due to event windows don't open up) and make the CPU
|
||||
unavailable to host or other VMs.
|
||||
|
||||
7.34 KVM_CAP_MEMORY_FAULT_INFO
|
||||
------------------------------
|
||||
|
||||
:Architectures: x86
|
||||
:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP.
|
||||
|
||||
The presence of this capability indicates that KVM_RUN will fill
|
||||
kvm_run.memory_fault if KVM cannot resolve a guest page fault VM-Exit, e.g. if
|
||||
there is a valid memslot but no backing VMA for the corresponding host virtual
|
||||
address.
|
||||
|
||||
The information in kvm_run.memory_fault is valid if and only if KVM_RUN returns
|
||||
an error with errno=EFAULT or errno=EHWPOISON *and* kvm_run.exit_reason is set
|
||||
to KVM_EXIT_MEMORY_FAULT.
|
||||
|
||||
Note: Userspaces which attempt to resolve memory faults so that they can retry
|
||||
KVM_RUN are encouraged to guard against repeatedly receiving the same
|
||||
error/annotated fault.
|
||||
|
||||
See KVM_EXIT_MEMORY_FAULT for more information.
|
||||
|
||||
8. Other capabilities.
|
||||
======================
|
||||
|
||||
@@ -8374,6 +8550,7 @@ PVHVM guests. Valid flags are::
|
||||
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
|
||||
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
|
||||
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
|
||||
#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
|
||||
|
||||
The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG
|
||||
ioctl is available, for the guest to set its hypercall page.
|
||||
@@ -8417,6 +8594,11 @@ behave more correctly, not using the XEN_RUNSTATE_UPDATE flag until/unless
|
||||
specifically enabled (by the guest making the hypercall, causing the VMM
|
||||
to enable the KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG attribute).
|
||||
|
||||
The KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag indicates that KVM supports
|
||||
clearing the PVCLOCK_TSC_STABLE_BIT flag in Xen pvclock sources. This will be
|
||||
done when the KVM_CAP_XEN_HVM ioctl sets the
|
||||
KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag.
|
||||
|
||||
8.31 KVM_CAP_PPC_MULTITCE
|
||||
-------------------------
|
||||
|
||||
@@ -8596,6 +8778,19 @@ block sizes is exposed in KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES as a
|
||||
64-bit bitmap (each bit describing a block size). The default value is
|
||||
0, to disable the eager page splitting.
|
||||
|
||||
8.41 KVM_CAP_VM_TYPES
|
||||
---------------------
|
||||
|
||||
:Capability: KVM_CAP_MEMORY_ATTRIBUTES
|
||||
:Architectures: x86
|
||||
:Type: system ioctl
|
||||
|
||||
This capability returns a bitmap of support VM types. The 1-setting of bit @n
|
||||
means the VM type with value @n is supported. Possible values of @n are::
|
||||
|
||||
#define KVM_X86_DEFAULT_VM 0
|
||||
#define KVM_X86_SW_PROTECTED_VM 1
|
||||
|
||||
9. Known KVM API problems
|
||||
=========================
|
||||
|
||||
|
||||
@@ -43,10 +43,9 @@ On x86:
|
||||
|
||||
- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock and kvm->arch.xen.xen_lock
|
||||
|
||||
- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock and
|
||||
kvm->arch.mmu_unsync_pages_lock are taken inside kvm->arch.mmu_lock, and
|
||||
cannot be taken without already holding kvm->arch.mmu_lock (typically with
|
||||
``read_lock`` for the TDP MMU, thus the need for additional spinlocks).
|
||||
- kvm->arch.mmu_lock is an rwlock; critical sections for
|
||||
kvm->arch.tdp_mmu_pages_lock and kvm->arch.mmu_unsync_pages_lock must
|
||||
also take kvm->arch.mmu_lock
|
||||
|
||||
Everything else is a leaf: no other lock is taken inside the critical
|
||||
sections.
|
||||
|
||||
@@ -18203,6 +18203,7 @@ F: drivers/media/cec/usb/rainshadow/
|
||||
|
||||
RALINK MIPS ARCHITECTURE
|
||||
M: John Crispin <john@phrozen.org>
|
||||
M: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||
L: linux-mips@vger.kernel.org
|
||||
S: Maintained
|
||||
F: arch/mips/ralink
|
||||
|
||||
@@ -35,6 +35,7 @@ config ARM
|
||||
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE
|
||||
select ARCH_SUPPORTS_PER_VMA_LOCK
|
||||
select ARCH_USE_BUILTIN_BSWAP
|
||||
select ARCH_USE_CMPXCHG_LOCKREF
|
||||
select ARCH_USE_MEMTEST
|
||||
|
||||
@@ -151,6 +151,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
||||
|
||||
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
|
||||
|
||||
#define pgdp_get(pgpd) READ_ONCE(*pgdp)
|
||||
|
||||
#define pud_page(pud) pmd_page(__pmd(pud_val(pud)))
|
||||
#define pud_write(pud) pmd_write(__pmd(pud_val(pud)))
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ menuconfig ARCH_DAVINCI
|
||||
select PM_GENERIC_DOMAINS_OF if PM && OF
|
||||
select REGMAP_MMIO
|
||||
select RESET_CONTROLLER
|
||||
select PINCTRL
|
||||
select PINCTRL_SINGLE
|
||||
|
||||
if ARCH_DAVINCI
|
||||
|
||||
@@ -859,10 +859,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
|
||||
int i = 0;
|
||||
int order_idx = 0;
|
||||
|
||||
if (array_size <= PAGE_SIZE)
|
||||
pages = kzalloc(array_size, GFP_KERNEL);
|
||||
else
|
||||
pages = vzalloc(array_size);
|
||||
pages = kvzalloc(array_size, GFP_KERNEL);
|
||||
if (!pages)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -278,6 +278,35 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
|
||||
|
||||
if (!(flags & FAULT_FLAG_USER))
|
||||
goto lock_mmap;
|
||||
|
||||
vma = lock_vma_under_rcu(mm, addr);
|
||||
if (!vma)
|
||||
goto lock_mmap;
|
||||
|
||||
if (!(vma->vm_flags & vm_flags)) {
|
||||
vma_end_read(vma);
|
||||
goto lock_mmap;
|
||||
}
|
||||
fault = handle_mm_fault(vma, addr, flags | FAULT_FLAG_VMA_LOCK, regs);
|
||||
if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED)))
|
||||
vma_end_read(vma);
|
||||
|
||||
if (!(fault & VM_FAULT_RETRY)) {
|
||||
count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
|
||||
goto done;
|
||||
}
|
||||
count_vm_vma_lock_event(VMA_LOCK_RETRY);
|
||||
|
||||
/* Quick path to respond to signals */
|
||||
if (fault_signal_pending(fault, regs)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return 0;
|
||||
}
|
||||
lock_mmap:
|
||||
|
||||
retry:
|
||||
vma = lock_mm_and_find_vma(mm, addr, regs);
|
||||
if (unlikely(!vma)) {
|
||||
@@ -316,6 +345,7 @@ retry:
|
||||
}
|
||||
|
||||
mmap_read_unlock(mm);
|
||||
done:
|
||||
|
||||
/*
|
||||
* Handle the "normal" case first - VM_FAULT_MAJOR
|
||||
|
||||
@@ -28,6 +28,12 @@ static pgd_t tmp_pgd_table[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
|
||||
|
||||
pmd_t tmp_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
|
||||
|
||||
static __init void *kasan_alloc_block_raw(size_t size)
|
||||
{
|
||||
return memblock_alloc_try_nid_raw(size, size, __pa(MAX_DMA_ADDRESS),
|
||||
MEMBLOCK_ALLOC_NOLEAKTRACE, NUMA_NO_NODE);
|
||||
}
|
||||
|
||||
static __init void *kasan_alloc_block(size_t size)
|
||||
{
|
||||
return memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS),
|
||||
@@ -50,7 +56,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
|
||||
if (!pte_none(READ_ONCE(*ptep)))
|
||||
continue;
|
||||
|
||||
p = kasan_alloc_block(PAGE_SIZE);
|
||||
p = kasan_alloc_block_raw(PAGE_SIZE);
|
||||
if (!p) {
|
||||
panic("%s failed to allocate shadow page for address 0x%lx\n",
|
||||
__func__, addr);
|
||||
|
||||
@@ -800,6 +800,24 @@ static struct undef_hook neon_support_hook[] = {{
|
||||
.cpsr_mask = PSR_T_BIT,
|
||||
.cpsr_val = PSR_T_BIT,
|
||||
.fn = vfp_support_entry,
|
||||
}, {
|
||||
.instr_mask = 0xff000800,
|
||||
.instr_val = 0xfc000800,
|
||||
.cpsr_mask = 0,
|
||||
.cpsr_val = 0,
|
||||
.fn = vfp_support_entry,
|
||||
}, {
|
||||
.instr_mask = 0xff000800,
|
||||
.instr_val = 0xfd000800,
|
||||
.cpsr_mask = 0,
|
||||
.cpsr_val = 0,
|
||||
.fn = vfp_support_entry,
|
||||
}, {
|
||||
.instr_mask = 0xff000800,
|
||||
.instr_val = 0xfe000800,
|
||||
.cpsr_mask = 0,
|
||||
.cpsr_val = 0,
|
||||
.fn = vfp_support_entry,
|
||||
}};
|
||||
|
||||
static struct undef_hook vfp_support_hook = {
|
||||
|
||||
@@ -137,6 +137,28 @@
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
dsp_vdev0vring0: vdev0vring0@942f0000 {
|
||||
reg = <0 0x942f0000 0 0x8000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
dsp_vdev0vring1: vdev0vring1@942f8000 {
|
||||
reg = <0 0x942f8000 0 0x8000>;
|
||||
no-map;
|
||||
};
|
||||
|
||||
dsp_vdev0buffer: vdev0buffer@94300000 {
|
||||
compatible = "shared-dma-pool";
|
||||
reg = <0 0x94300000 0 0x100000>;
|
||||
no-map;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&flexspi {
|
||||
|
||||
@@ -392,6 +392,21 @@ static inline bool esr_is_data_abort(unsigned long esr)
|
||||
return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_permission_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
|
||||
}
|
||||
|
||||
static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
|
||||
{
|
||||
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
|
||||
}
|
||||
|
||||
const char *esr_get_class_string(unsigned long esr);
|
||||
#endif /* __ASSEMBLY */
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)
|
||||
|
||||
/* TCR_EL2 Registers bits */
|
||||
#define TCR_EL2_DS (1UL << 32)
|
||||
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
|
||||
#define TCR_EL2_TBI (1 << 20)
|
||||
#define TCR_EL2_PS_SHIFT 16
|
||||
@@ -122,6 +123,7 @@
|
||||
TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK)
|
||||
|
||||
/* VTCR_EL2 Registers bits */
|
||||
#define VTCR_EL2_DS TCR_EL2_DS
|
||||
#define VTCR_EL2_RES1 (1U << 31)
|
||||
#define VTCR_EL2_HD (1 << 22)
|
||||
#define VTCR_EL2_HA (1 << 21)
|
||||
@@ -344,36 +346,47 @@
|
||||
* Once we get to a point where the two describe the same thing, we'll
|
||||
* merge the definitions. One day.
|
||||
*/
|
||||
#define __HFGRTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51))
|
||||
#define __HFGRTR_EL2_RES0 HFGxTR_EL2_RES0
|
||||
#define __HFGRTR_EL2_MASK GENMASK(49, 0)
|
||||
#define __HFGRTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
|
||||
#define __HFGRTR_EL2_nMASK ~(__HFGRTR_EL2_RES0 | __HFGRTR_EL2_MASK)
|
||||
|
||||
#define __HFGWTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51) | \
|
||||
BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
|
||||
GENMASK(26, 25) | BIT(21) | BIT(18) | \
|
||||
/*
|
||||
* The HFGWTR bits are a subset of HFGRTR bits. To ensure we don't miss any
|
||||
* future additions, define __HFGWTR* macros relative to __HFGRTR* ones.
|
||||
*/
|
||||
#define __HFGRTR_ONLY_MASK (BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
|
||||
GENMASK(26, 25) | BIT(21) | BIT(18) | \
|
||||
GENMASK(15, 14) | GENMASK(10, 9) | BIT(2))
|
||||
#define __HFGWTR_EL2_MASK GENMASK(49, 0)
|
||||
#define __HFGWTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
|
||||
#define __HFGWTR_EL2_RES0 (__HFGRTR_EL2_RES0 | __HFGRTR_ONLY_MASK)
|
||||
#define __HFGWTR_EL2_MASK (__HFGRTR_EL2_MASK & ~__HFGRTR_ONLY_MASK)
|
||||
#define __HFGWTR_EL2_nMASK ~(__HFGWTR_EL2_RES0 | __HFGWTR_EL2_MASK)
|
||||
|
||||
#define __HFGITR_EL2_RES0 GENMASK(63, 57)
|
||||
#define __HFGITR_EL2_MASK GENMASK(54, 0)
|
||||
#define __HFGITR_EL2_nMASK GENMASK(56, 55)
|
||||
#define __HFGITR_EL2_RES0 HFGITR_EL2_RES0
|
||||
#define __HFGITR_EL2_MASK (BIT(62) | BIT(60) | GENMASK(54, 0))
|
||||
#define __HFGITR_EL2_nMASK ~(__HFGITR_EL2_RES0 | __HFGITR_EL2_MASK)
|
||||
|
||||
#define __HDFGRTR_EL2_RES0 (BIT(49) | BIT(42) | GENMASK(39, 38) | \
|
||||
GENMASK(21, 20) | BIT(8))
|
||||
#define __HDFGRTR_EL2_MASK ~__HDFGRTR_EL2_nMASK
|
||||
#define __HDFGRTR_EL2_nMASK GENMASK(62, 59)
|
||||
#define __HDFGRTR_EL2_RES0 HDFGRTR_EL2_RES0
|
||||
#define __HDFGRTR_EL2_MASK (BIT(63) | GENMASK(58, 50) | GENMASK(48, 43) | \
|
||||
GENMASK(41, 40) | GENMASK(37, 22) | \
|
||||
GENMASK(19, 9) | GENMASK(7, 0))
|
||||
#define __HDFGRTR_EL2_nMASK ~(__HDFGRTR_EL2_RES0 | __HDFGRTR_EL2_MASK)
|
||||
|
||||
#define __HDFGWTR_EL2_RES0 (BIT(63) | GENMASK(59, 58) | BIT(51) | BIT(47) | \
|
||||
BIT(43) | GENMASK(40, 38) | BIT(34) | BIT(30) | \
|
||||
BIT(22) | BIT(9) | BIT(6))
|
||||
#define __HDFGWTR_EL2_MASK ~__HDFGWTR_EL2_nMASK
|
||||
#define __HDFGWTR_EL2_nMASK GENMASK(62, 60)
|
||||
#define __HDFGWTR_EL2_RES0 HDFGWTR_EL2_RES0
|
||||
#define __HDFGWTR_EL2_MASK (GENMASK(57, 52) | GENMASK(50, 48) | \
|
||||
GENMASK(46, 44) | GENMASK(42, 41) | \
|
||||
GENMASK(37, 35) | GENMASK(33, 31) | \
|
||||
GENMASK(29, 23) | GENMASK(21, 10) | \
|
||||
GENMASK(8, 7) | GENMASK(5, 0))
|
||||
#define __HDFGWTR_EL2_nMASK ~(__HDFGWTR_EL2_RES0 | __HDFGWTR_EL2_MASK)
|
||||
|
||||
#define __HAFGRTR_EL2_RES0 HAFGRTR_EL2_RES0
|
||||
#define __HAFGRTR_EL2_MASK (GENMASK(49, 17) | GENMASK(4, 0))
|
||||
#define __HAFGRTR_EL2_nMASK ~(__HAFGRTR_EL2_RES0 | __HAFGRTR_EL2_MASK)
|
||||
|
||||
/* Similar definitions for HCRX_EL2 */
|
||||
#define __HCRX_EL2_RES0 (GENMASK(63, 16) | GENMASK(13, 12))
|
||||
#define __HCRX_EL2_MASK (0)
|
||||
#define __HCRX_EL2_nMASK (GENMASK(15, 14) | GENMASK(4, 0))
|
||||
#define __HCRX_EL2_RES0 HCRX_EL2_RES0
|
||||
#define __HCRX_EL2_MASK (BIT(6))
|
||||
#define __HCRX_EL2_nMASK ~(__HCRX_EL2_RES0 | __HCRX_EL2_MASK)
|
||||
|
||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||
#define HPFAR_MASK (~UL(0xf))
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <asm/esr.h>
|
||||
#include <asm/kvm_arm.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
#include <asm/kvm_nested.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/virt.h>
|
||||
@@ -54,11 +55,6 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
|
||||
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
|
||||
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline bool vcpu_has_feature(const struct kvm_vcpu *vcpu, int feature)
|
||||
{
|
||||
return test_bit(feature, vcpu->kvm->arch.vcpu_features);
|
||||
}
|
||||
|
||||
#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
|
||||
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -248,7 +244,7 @@ static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
|
||||
|
||||
static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return __is_hyp_ctxt(&vcpu->arch.ctxt);
|
||||
return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -404,14 +400,25 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
|
||||
}
|
||||
|
||||
static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
|
||||
static inline
|
||||
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
|
||||
return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(vcpu));
|
||||
}
|
||||
|
||||
static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
|
||||
static inline
|
||||
bool kvm_vcpu_trap_is_translation_fault(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
|
||||
return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu));
|
||||
}
|
||||
|
||||
static inline
|
||||
u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
BUG_ON(!esr_fsc_is_permission_fault(esr));
|
||||
return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL));
|
||||
}
|
||||
|
||||
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
|
||||
@@ -454,12 +461,7 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
|
||||
* first), then a permission fault to allow the flags
|
||||
* to be set.
|
||||
*/
|
||||
switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
|
||||
case ESR_ELx_FSC_PERM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return kvm_vcpu_trap_is_permission_fault(vcpu);
|
||||
}
|
||||
|
||||
if (kvm_vcpu_trap_is_iabt(vcpu))
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <asm/fpsimd.h>
|
||||
#include <asm/kvm.h>
|
||||
#include <asm/kvm_asm.h>
|
||||
#include <asm/vncr_mapping.h>
|
||||
|
||||
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||
|
||||
@@ -306,6 +307,7 @@ struct kvm_arch {
|
||||
* Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
|
||||
*/
|
||||
#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
|
||||
#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask)
|
||||
#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)])
|
||||
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
|
||||
u64 id_regs[KVM_ARM_ID_REG_NUM];
|
||||
@@ -324,33 +326,33 @@ struct kvm_vcpu_fault_info {
|
||||
u64 disr_el1; /* Deferred [SError] Status Register */
|
||||
};
|
||||
|
||||
/*
|
||||
* VNCR() just places the VNCR_capable registers in the enum after
|
||||
* __VNCR_START__, and the value (after correction) to be an 8-byte offset
|
||||
* from the VNCR base. As we don't require the enum to be otherwise ordered,
|
||||
* we need the terrible hack below to ensure that we correctly size the
|
||||
* sys_regs array, no matter what.
|
||||
*
|
||||
* The __MAX__ macro has been lifted from Sean Eron Anderson's wonderful
|
||||
* treasure trove of bit hacks:
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
|
||||
*/
|
||||
#define __MAX__(x,y) ((x) ^ (((x) ^ (y)) & -((x) < (y))))
|
||||
#define VNCR(r) \
|
||||
__before_##r, \
|
||||
r = __VNCR_START__ + ((VNCR_ ## r) / 8), \
|
||||
__after_##r = __MAX__(__before_##r - 1, r)
|
||||
|
||||
enum vcpu_sysreg {
|
||||
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
|
||||
MPIDR_EL1, /* MultiProcessor Affinity Register */
|
||||
CLIDR_EL1, /* Cache Level ID Register */
|
||||
CSSELR_EL1, /* Cache Size Selection Register */
|
||||
SCTLR_EL1, /* System Control Register */
|
||||
ACTLR_EL1, /* Auxiliary Control Register */
|
||||
CPACR_EL1, /* Coprocessor Access Control */
|
||||
ZCR_EL1, /* SVE Control */
|
||||
TTBR0_EL1, /* Translation Table Base Register 0 */
|
||||
TTBR1_EL1, /* Translation Table Base Register 1 */
|
||||
TCR_EL1, /* Translation Control Register */
|
||||
TCR2_EL1, /* Extended Translation Control Register */
|
||||
ESR_EL1, /* Exception Syndrome Register */
|
||||
AFSR0_EL1, /* Auxiliary Fault Status Register 0 */
|
||||
AFSR1_EL1, /* Auxiliary Fault Status Register 1 */
|
||||
FAR_EL1, /* Fault Address Register */
|
||||
MAIR_EL1, /* Memory Attribute Indirection Register */
|
||||
VBAR_EL1, /* Vector Base Address Register */
|
||||
CONTEXTIDR_EL1, /* Context ID Register */
|
||||
TPIDR_EL0, /* Thread ID, User R/W */
|
||||
TPIDRRO_EL0, /* Thread ID, User R/O */
|
||||
TPIDR_EL1, /* Thread ID, Privileged */
|
||||
AMAIR_EL1, /* Aux Memory Attribute Indirection Register */
|
||||
CNTKCTL_EL1, /* Timer Control Register (EL1) */
|
||||
PAR_EL1, /* Physical Address Register */
|
||||
MDSCR_EL1, /* Monitor Debug System Control Register */
|
||||
MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
|
||||
OSLSR_EL1, /* OS Lock Status Register */
|
||||
DISR_EL1, /* Deferred Interrupt Status Register */
|
||||
@@ -381,26 +383,11 @@ enum vcpu_sysreg {
|
||||
APGAKEYLO_EL1,
|
||||
APGAKEYHI_EL1,
|
||||
|
||||
ELR_EL1,
|
||||
SP_EL1,
|
||||
SPSR_EL1,
|
||||
|
||||
CNTVOFF_EL2,
|
||||
CNTV_CVAL_EL0,
|
||||
CNTV_CTL_EL0,
|
||||
CNTP_CVAL_EL0,
|
||||
CNTP_CTL_EL0,
|
||||
|
||||
/* Memory Tagging Extension registers */
|
||||
RGSR_EL1, /* Random Allocation Tag Seed Register */
|
||||
GCR_EL1, /* Tag Control Register */
|
||||
TFSR_EL1, /* Tag Fault Status Register (EL1) */
|
||||
TFSRE0_EL1, /* Tag Fault Status Register (EL0) */
|
||||
|
||||
/* Permission Indirection Extension registers */
|
||||
PIR_EL1, /* Permission Indirection Register 1 (EL1) */
|
||||
PIRE0_EL1, /* Permission Indirection Register 0 (EL1) */
|
||||
|
||||
/* 32bit specific registers. */
|
||||
DACR32_EL2, /* Domain Access Control Register */
|
||||
IFSR32_EL2, /* Instruction Fault Status Register */
|
||||
@@ -408,21 +395,14 @@ enum vcpu_sysreg {
|
||||
DBGVCR32_EL2, /* Debug Vector Catch Register */
|
||||
|
||||
/* EL2 registers */
|
||||
VPIDR_EL2, /* Virtualization Processor ID Register */
|
||||
VMPIDR_EL2, /* Virtualization Multiprocessor ID Register */
|
||||
SCTLR_EL2, /* System Control Register (EL2) */
|
||||
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
|
||||
HCR_EL2, /* Hypervisor Configuration Register */
|
||||
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
|
||||
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
|
||||
HSTR_EL2, /* Hypervisor System Trap Register */
|
||||
HACR_EL2, /* Hypervisor Auxiliary Control Register */
|
||||
HCRX_EL2, /* Extended Hypervisor Configuration Register */
|
||||
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
|
||||
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
|
||||
TCR_EL2, /* Translation Control Register (EL2) */
|
||||
VTTBR_EL2, /* Virtualization Translation Table Base Register */
|
||||
VTCR_EL2, /* Virtualization Translation Control Register */
|
||||
SPSR_EL2, /* EL2 saved program status register */
|
||||
ELR_EL2, /* EL2 exception link register */
|
||||
AFSR0_EL2, /* Auxiliary Fault Status Register 0 (EL2) */
|
||||
@@ -435,19 +415,62 @@ enum vcpu_sysreg {
|
||||
VBAR_EL2, /* Vector Base Address Register (EL2) */
|
||||
RVBAR_EL2, /* Reset Vector Base Address Register */
|
||||
CONTEXTIDR_EL2, /* Context ID Register (EL2) */
|
||||
TPIDR_EL2, /* EL2 Software Thread ID Register */
|
||||
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
|
||||
SP_EL2, /* EL2 Stack Pointer */
|
||||
HFGRTR_EL2,
|
||||
HFGWTR_EL2,
|
||||
HFGITR_EL2,
|
||||
HDFGRTR_EL2,
|
||||
HDFGWTR_EL2,
|
||||
CNTHP_CTL_EL2,
|
||||
CNTHP_CVAL_EL2,
|
||||
CNTHV_CTL_EL2,
|
||||
CNTHV_CVAL_EL2,
|
||||
|
||||
__VNCR_START__, /* Any VNCR-capable reg goes after this point */
|
||||
|
||||
VNCR(SCTLR_EL1),/* System Control Register */
|
||||
VNCR(ACTLR_EL1),/* Auxiliary Control Register */
|
||||
VNCR(CPACR_EL1),/* Coprocessor Access Control */
|
||||
VNCR(ZCR_EL1), /* SVE Control */
|
||||
VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */
|
||||
VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */
|
||||
VNCR(TCR_EL1), /* Translation Control Register */
|
||||
VNCR(TCR2_EL1), /* Extended Translation Control Register */
|
||||
VNCR(ESR_EL1), /* Exception Syndrome Register */
|
||||
VNCR(AFSR0_EL1),/* Auxiliary Fault Status Register 0 */
|
||||
VNCR(AFSR1_EL1),/* Auxiliary Fault Status Register 1 */
|
||||
VNCR(FAR_EL1), /* Fault Address Register */
|
||||
VNCR(MAIR_EL1), /* Memory Attribute Indirection Register */
|
||||
VNCR(VBAR_EL1), /* Vector Base Address Register */
|
||||
VNCR(CONTEXTIDR_EL1), /* Context ID Register */
|
||||
VNCR(AMAIR_EL1),/* Aux Memory Attribute Indirection Register */
|
||||
VNCR(MDSCR_EL1),/* Monitor Debug System Control Register */
|
||||
VNCR(ELR_EL1),
|
||||
VNCR(SP_EL1),
|
||||
VNCR(SPSR_EL1),
|
||||
VNCR(TFSR_EL1), /* Tag Fault Status Register (EL1) */
|
||||
VNCR(VPIDR_EL2),/* Virtualization Processor ID Register */
|
||||
VNCR(VMPIDR_EL2),/* Virtualization Multiprocessor ID Register */
|
||||
VNCR(HCR_EL2), /* Hypervisor Configuration Register */
|
||||
VNCR(HSTR_EL2), /* Hypervisor System Trap Register */
|
||||
VNCR(VTTBR_EL2),/* Virtualization Translation Table Base Register */
|
||||
VNCR(VTCR_EL2), /* Virtualization Translation Control Register */
|
||||
VNCR(TPIDR_EL2),/* EL2 Software Thread ID Register */
|
||||
VNCR(HCRX_EL2), /* Extended Hypervisor Configuration Register */
|
||||
|
||||
/* Permission Indirection Extension registers */
|
||||
VNCR(PIR_EL1), /* Permission Indirection Register 1 (EL1) */
|
||||
VNCR(PIRE0_EL1), /* Permission Indirection Register 0 (EL1) */
|
||||
|
||||
VNCR(HFGRTR_EL2),
|
||||
VNCR(HFGWTR_EL2),
|
||||
VNCR(HFGITR_EL2),
|
||||
VNCR(HDFGRTR_EL2),
|
||||
VNCR(HDFGWTR_EL2),
|
||||
VNCR(HAFGRTR_EL2),
|
||||
|
||||
VNCR(CNTVOFF_EL2),
|
||||
VNCR(CNTV_CVAL_EL0),
|
||||
VNCR(CNTV_CTL_EL0),
|
||||
VNCR(CNTP_CVAL_EL0),
|
||||
VNCR(CNTP_CTL_EL0),
|
||||
|
||||
NR_SYS_REGS /* Nothing after this line! */
|
||||
};
|
||||
|
||||
@@ -464,6 +487,9 @@ struct kvm_cpu_context {
|
||||
u64 sys_regs[NR_SYS_REGS];
|
||||
|
||||
struct kvm_vcpu *__hyp_running_vcpu;
|
||||
|
||||
/* This pointer has to be 4kB aligned. */
|
||||
u64 *vncr_array;
|
||||
};
|
||||
|
||||
struct kvm_host_data {
|
||||
@@ -826,8 +852,19 @@ struct kvm_vcpu_arch {
|
||||
* accessed by a running VCPU. For example, for userspace access or
|
||||
* for system registers that are never context switched, but only
|
||||
* emulated.
|
||||
*
|
||||
* Don't bother with VNCR-based accesses in the nVHE code, it has no
|
||||
* business dealing with NV.
|
||||
*/
|
||||
#define __ctxt_sys_reg(c,r) (&(c)->sys_regs[(r)])
|
||||
static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)
|
||||
{
|
||||
#if !defined (__KVM_NVHE_HYPERVISOR__)
|
||||
if (unlikely(cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
|
||||
r >= __VNCR_START__ && ctxt->vncr_array))
|
||||
return &ctxt->vncr_array[r - __VNCR_START__];
|
||||
#endif
|
||||
return (u64 *)&ctxt->sys_regs[r];
|
||||
}
|
||||
|
||||
#define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r))
|
||||
|
||||
@@ -871,6 +908,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
|
||||
case AMAIR_EL1: *val = read_sysreg_s(SYS_AMAIR_EL12); break;
|
||||
case CNTKCTL_EL1: *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
|
||||
case ELR_EL1: *val = read_sysreg_s(SYS_ELR_EL12); break;
|
||||
case SPSR_EL1: *val = read_sysreg_s(SYS_SPSR_EL12); break;
|
||||
case PAR_EL1: *val = read_sysreg_par(); break;
|
||||
case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break;
|
||||
@@ -915,6 +953,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
|
||||
case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break;
|
||||
case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break;
|
||||
case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break;
|
||||
case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break;
|
||||
case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break;
|
||||
case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break;
|
||||
case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break;
|
||||
@@ -954,8 +993,6 @@ int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
|
||||
int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu_events *events);
|
||||
|
||||
#define KVM_ARCH_WANT_MMU_NOTIFIER
|
||||
|
||||
void kvm_arm_halt_guest(struct kvm *kvm);
|
||||
void kvm_arm_resume_guest(struct kvm *kvm);
|
||||
|
||||
@@ -1177,6 +1214,13 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
|
||||
#define kvm_vm_has_ran_once(kvm) \
|
||||
(test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags))
|
||||
|
||||
static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
|
||||
{
|
||||
return test_bit(feature, ka->vcpu_features);
|
||||
}
|
||||
|
||||
#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
|
||||
|
||||
int kvm_trng_call(struct kvm_vcpu *vcpu);
|
||||
#ifdef CONFIG_KVM
|
||||
extern phys_addr_t hyp_mem_base;
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
#ifndef __ARM64_KVM_NESTED_H
|
||||
#define __ARM64_KVM_NESTED_H
|
||||
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_emulate.h>
|
||||
|
||||
static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -12,12 +13,55 @@ static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
|
||||
vcpu_has_feature(vcpu, KVM_ARM_VCPU_HAS_EL2));
|
||||
}
|
||||
|
||||
/* Translation helpers from non-VHE EL2 to EL1 */
|
||||
static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2)
|
||||
{
|
||||
return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT;
|
||||
}
|
||||
|
||||
static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
|
||||
{
|
||||
return TCR_EPD1_MASK | /* disable TTBR1_EL1 */
|
||||
((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
|
||||
tcr_el2_ps_to_tcr_el1_ips(tcr) |
|
||||
(tcr & TCR_EL2_TG0_MASK) |
|
||||
(tcr & TCR_EL2_ORGN0_MASK) |
|
||||
(tcr & TCR_EL2_IRGN0_MASK) |
|
||||
(tcr & TCR_EL2_T0SZ_MASK);
|
||||
}
|
||||
|
||||
static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
|
||||
{
|
||||
u64 cpacr_el1 = 0;
|
||||
|
||||
if (cptr_el2 & CPTR_EL2_TTA)
|
||||
cpacr_el1 |= CPACR_ELx_TTA;
|
||||
if (!(cptr_el2 & CPTR_EL2_TFP))
|
||||
cpacr_el1 |= CPACR_ELx_FPEN;
|
||||
if (!(cptr_el2 & CPTR_EL2_TZ))
|
||||
cpacr_el1 |= CPACR_ELx_ZEN;
|
||||
|
||||
return cpacr_el1;
|
||||
}
|
||||
|
||||
static inline u64 translate_sctlr_el2_to_sctlr_el1(u64 val)
|
||||
{
|
||||
/* Only preserve the minimal set of bits we support */
|
||||
val &= (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | SCTLR_ELx_SA |
|
||||
SCTLR_ELx_I | SCTLR_ELx_IESB | SCTLR_ELx_WXN | SCTLR_ELx_EE);
|
||||
val |= SCTLR_EL1_RES1;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
|
||||
{
|
||||
/* Clear the ASID field */
|
||||
return ttbr0 & ~GENMASK_ULL(63, 48);
|
||||
}
|
||||
|
||||
extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu);
|
||||
|
||||
struct sys_reg_params;
|
||||
struct sys_reg_desc;
|
||||
|
||||
void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r);
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm);
|
||||
|
||||
#endif /* __ARM64_KVM_NESTED_H */
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define KVM_PGTABLE_MAX_LEVELS 4U
|
||||
#define KVM_PGTABLE_FIRST_LEVEL -1
|
||||
#define KVM_PGTABLE_LAST_LEVEL 3
|
||||
|
||||
/*
|
||||
* The largest supported block sizes for KVM (no 52-bit PA support):
|
||||
@@ -20,19 +21,29 @@
|
||||
* - 64K (level 2): 512MB
|
||||
*/
|
||||
#ifdef CONFIG_ARM64_4K_PAGES
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1
|
||||
#else
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U
|
||||
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define kvm_lpa2_is_enabled() false
|
||||
#define kvm_lpa2_is_enabled() system_supports_lpa2()
|
||||
|
||||
static inline u64 kvm_get_parange_max(void)
|
||||
{
|
||||
if (kvm_lpa2_is_enabled() ||
|
||||
(IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SHIFT == 16))
|
||||
return ID_AA64MMFR0_EL1_PARANGE_52;
|
||||
else
|
||||
return ID_AA64MMFR0_EL1_PARANGE_48;
|
||||
}
|
||||
|
||||
static inline u64 kvm_get_parange(u64 mmfr0)
|
||||
{
|
||||
u64 parange_max = kvm_get_parange_max();
|
||||
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
|
||||
if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX)
|
||||
parange = ID_AA64MMFR0_EL1_PARANGE_MAX;
|
||||
if (parange > parange_max)
|
||||
parange = parange_max;
|
||||
|
||||
return parange;
|
||||
}
|
||||
@@ -43,6 +54,8 @@ typedef u64 kvm_pte_t;
|
||||
|
||||
#define KVM_PTE_ADDR_MASK GENMASK(47, PAGE_SHIFT)
|
||||
#define KVM_PTE_ADDR_51_48 GENMASK(15, 12)
|
||||
#define KVM_PTE_ADDR_MASK_LPA2 GENMASK(49, PAGE_SHIFT)
|
||||
#define KVM_PTE_ADDR_51_50_LPA2 GENMASK(9, 8)
|
||||
|
||||
#define KVM_PHYS_INVALID (-1ULL)
|
||||
|
||||
@@ -53,21 +66,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte)
|
||||
|
||||
static inline u64 kvm_pte_to_phys(kvm_pte_t pte)
|
||||
{
|
||||
u64 pa = pte & KVM_PTE_ADDR_MASK;
|
||||
u64 pa;
|
||||
|
||||
if (PAGE_SHIFT == 16)
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
|
||||
if (kvm_lpa2_is_enabled()) {
|
||||
pa = pte & KVM_PTE_ADDR_MASK_LPA2;
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50;
|
||||
} else {
|
||||
pa = pte & KVM_PTE_ADDR_MASK;
|
||||
if (PAGE_SHIFT == 16)
|
||||
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
static inline kvm_pte_t kvm_phys_to_pte(u64 pa)
|
||||
{
|
||||
kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK;
|
||||
kvm_pte_t pte;
|
||||
|
||||
if (PAGE_SHIFT == 16) {
|
||||
pa &= GENMASK(51, 48);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
|
||||
if (kvm_lpa2_is_enabled()) {
|
||||
pte = pa & KVM_PTE_ADDR_MASK_LPA2;
|
||||
pa &= GENMASK(51, 50);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50);
|
||||
} else {
|
||||
pte = pa & KVM_PTE_ADDR_MASK;
|
||||
if (PAGE_SHIFT == 16) {
|
||||
pa &= GENMASK(51, 48);
|
||||
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
|
||||
}
|
||||
}
|
||||
|
||||
return pte;
|
||||
@@ -78,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
|
||||
return __phys_to_pfn(kvm_pte_to_phys(pte));
|
||||
}
|
||||
|
||||
static inline u64 kvm_granule_shift(u32 level)
|
||||
static inline u64 kvm_granule_shift(s8 level)
|
||||
{
|
||||
/* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
|
||||
/* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
|
||||
return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
|
||||
}
|
||||
|
||||
static inline u64 kvm_granule_size(u32 level)
|
||||
static inline u64 kvm_granule_size(s8 level)
|
||||
{
|
||||
return BIT(kvm_granule_shift(level));
|
||||
}
|
||||
|
||||
static inline bool kvm_level_supports_block_mapping(u32 level)
|
||||
static inline bool kvm_level_supports_block_mapping(s8 level)
|
||||
{
|
||||
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
}
|
||||
|
||||
static inline u32 kvm_supported_block_sizes(void)
|
||||
{
|
||||
u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
|
||||
u32 r = 0;
|
||||
|
||||
for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
|
||||
for (; level <= KVM_PGTABLE_LAST_LEVEL; level++)
|
||||
r |= BIT(kvm_granule_shift(level));
|
||||
|
||||
return r;
|
||||
@@ -144,7 +170,7 @@ struct kvm_pgtable_mm_ops {
|
||||
void* (*zalloc_page)(void *arg);
|
||||
void* (*zalloc_pages_exact)(size_t size);
|
||||
void (*free_pages_exact)(void *addr, size_t size);
|
||||
void (*free_unlinked_table)(void *addr, u32 level);
|
||||
void (*free_unlinked_table)(void *addr, s8 level);
|
||||
void (*get_page)(void *addr);
|
||||
void (*put_page)(void *addr);
|
||||
int (*page_count)(void *addr);
|
||||
@@ -240,7 +266,7 @@ struct kvm_pgtable_visit_ctx {
|
||||
u64 start;
|
||||
u64 addr;
|
||||
u64 end;
|
||||
u32 level;
|
||||
s8 level;
|
||||
enum kvm_pgtable_walk_flags flags;
|
||||
};
|
||||
|
||||
@@ -343,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
|
||||
*/
|
||||
struct kvm_pgtable {
|
||||
u32 ia_bits;
|
||||
u32 start_level;
|
||||
s8 start_level;
|
||||
kvm_pteref_t pgd;
|
||||
struct kvm_pgtable_mm_ops *mm_ops;
|
||||
|
||||
@@ -477,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
|
||||
* The page-table is assumed to be unreachable by any hardware walkers prior to
|
||||
* freeing and therefore no TLB invalidation is performed.
|
||||
*/
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level);
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure.
|
||||
@@ -501,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p
|
||||
* an ERR_PTR(error) on failure.
|
||||
*/
|
||||
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
u64 phys, u32 level,
|
||||
u64 phys, s8 level,
|
||||
enum kvm_pgtable_prot prot,
|
||||
void *mc, bool force_pte);
|
||||
|
||||
@@ -727,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
* Return: 0 on success, negative error code on failure.
|
||||
*/
|
||||
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
|
||||
kvm_pte_t *ptep, u32 *level);
|
||||
kvm_pte_t *ptep, s8 *level);
|
||||
|
||||
/**
|
||||
* kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a
|
||||
|
||||
@@ -56,10 +56,11 @@ static inline unsigned long hyp_vm_table_pages(void)
|
||||
|
||||
static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
|
||||
{
|
||||
unsigned long total = 0, i;
|
||||
unsigned long total = 0;
|
||||
int i;
|
||||
|
||||
/* Provision the worst case scenario */
|
||||
for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) {
|
||||
for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) {
|
||||
nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE);
|
||||
total += nr_pages;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* System register offsets in the VNCR page
|
||||
* All offsets are *byte* displacements!
|
||||
*/
|
||||
|
||||
#ifndef __ARM64_VNCR_MAPPING_H__
|
||||
#define __ARM64_VNCR_MAPPING_H__
|
||||
|
||||
#define VNCR_VTTBR_EL2 0x020
|
||||
#define VNCR_VTCR_EL2 0x040
|
||||
#define VNCR_VMPIDR_EL2 0x050
|
||||
#define VNCR_CNTVOFF_EL2 0x060
|
||||
#define VNCR_HCR_EL2 0x078
|
||||
#define VNCR_HSTR_EL2 0x080
|
||||
#define VNCR_VPIDR_EL2 0x088
|
||||
#define VNCR_TPIDR_EL2 0x090
|
||||
#define VNCR_HCRX_EL2 0x0A0
|
||||
#define VNCR_VNCR_EL2 0x0B0
|
||||
#define VNCR_CPACR_EL1 0x100
|
||||
#define VNCR_CONTEXTIDR_EL1 0x108
|
||||
#define VNCR_SCTLR_EL1 0x110
|
||||
#define VNCR_ACTLR_EL1 0x118
|
||||
#define VNCR_TCR_EL1 0x120
|
||||
#define VNCR_AFSR0_EL1 0x128
|
||||
#define VNCR_AFSR1_EL1 0x130
|
||||
#define VNCR_ESR_EL1 0x138
|
||||
#define VNCR_MAIR_EL1 0x140
|
||||
#define VNCR_AMAIR_EL1 0x148
|
||||
#define VNCR_MDSCR_EL1 0x158
|
||||
#define VNCR_SPSR_EL1 0x160
|
||||
#define VNCR_CNTV_CVAL_EL0 0x168
|
||||
#define VNCR_CNTV_CTL_EL0 0x170
|
||||
#define VNCR_CNTP_CVAL_EL0 0x178
|
||||
#define VNCR_CNTP_CTL_EL0 0x180
|
||||
#define VNCR_SCXTNUM_EL1 0x188
|
||||
#define VNCR_TFSR_EL1 0x190
|
||||
#define VNCR_HFGRTR_EL2 0x1B8
|
||||
#define VNCR_HFGWTR_EL2 0x1C0
|
||||
#define VNCR_HFGITR_EL2 0x1C8
|
||||
#define VNCR_HDFGRTR_EL2 0x1D0
|
||||
#define VNCR_HDFGWTR_EL2 0x1D8
|
||||
#define VNCR_ZCR_EL1 0x1E0
|
||||
#define VNCR_HAFGRTR_EL2 0x1E8
|
||||
#define VNCR_TTBR0_EL1 0x200
|
||||
#define VNCR_TTBR1_EL1 0x210
|
||||
#define VNCR_FAR_EL1 0x220
|
||||
#define VNCR_ELR_EL1 0x230
|
||||
#define VNCR_SP_EL1 0x240
|
||||
#define VNCR_VBAR_EL1 0x250
|
||||
#define VNCR_TCR2_EL1 0x270
|
||||
#define VNCR_PIRE0_EL1 0x290
|
||||
#define VNCR_PIRE0_EL2 0x298
|
||||
#define VNCR_PIR_EL1 0x2A0
|
||||
#define VNCR_ICH_LR0_EL2 0x400
|
||||
#define VNCR_ICH_LR1_EL2 0x408
|
||||
#define VNCR_ICH_LR2_EL2 0x410
|
||||
#define VNCR_ICH_LR3_EL2 0x418
|
||||
#define VNCR_ICH_LR4_EL2 0x420
|
||||
#define VNCR_ICH_LR5_EL2 0x428
|
||||
#define VNCR_ICH_LR6_EL2 0x430
|
||||
#define VNCR_ICH_LR7_EL2 0x438
|
||||
#define VNCR_ICH_LR8_EL2 0x440
|
||||
#define VNCR_ICH_LR9_EL2 0x448
|
||||
#define VNCR_ICH_LR10_EL2 0x450
|
||||
#define VNCR_ICH_LR11_EL2 0x458
|
||||
#define VNCR_ICH_LR12_EL2 0x460
|
||||
#define VNCR_ICH_LR13_EL2 0x468
|
||||
#define VNCR_ICH_LR14_EL2 0x470
|
||||
#define VNCR_ICH_LR15_EL2 0x478
|
||||
#define VNCR_ICH_AP0R0_EL2 0x480
|
||||
#define VNCR_ICH_AP0R1_EL2 0x488
|
||||
#define VNCR_ICH_AP0R2_EL2 0x490
|
||||
#define VNCR_ICH_AP0R3_EL2 0x498
|
||||
#define VNCR_ICH_AP1R0_EL2 0x4A0
|
||||
#define VNCR_ICH_AP1R1_EL2 0x4A8
|
||||
#define VNCR_ICH_AP1R2_EL2 0x4B0
|
||||
#define VNCR_ICH_AP1R3_EL2 0x4B8
|
||||
#define VNCR_ICH_HCR_EL2 0x4C0
|
||||
#define VNCR_ICH_VMCR_EL2 0x4C8
|
||||
#define VNCR_VDISR_EL2 0x500
|
||||
#define VNCR_PMBLIMITR_EL1 0x800
|
||||
#define VNCR_PMBPTR_EL1 0x810
|
||||
#define VNCR_PMBSR_EL1 0x820
|
||||
#define VNCR_PMSCR_EL1 0x828
|
||||
#define VNCR_PMSEVFR_EL1 0x830
|
||||
#define VNCR_PMSICR_EL1 0x838
|
||||
#define VNCR_PMSIRR_EL1 0x840
|
||||
#define VNCR_PMSLATFR_EL1 0x848
|
||||
#define VNCR_TRFCR_EL1 0x880
|
||||
#define VNCR_MPAM1_EL1 0x900
|
||||
#define VNCR_MPAMHCR_EL2 0x930
|
||||
#define VNCR_MPAMVPMV_EL2 0x938
|
||||
#define VNCR_MPAMVPM0_EL2 0x940
|
||||
#define VNCR_MPAMVPM1_EL2 0x948
|
||||
#define VNCR_MPAMVPM2_EL2 0x950
|
||||
#define VNCR_MPAMVPM3_EL2 0x958
|
||||
#define VNCR_MPAMVPM4_EL2 0x960
|
||||
#define VNCR_MPAMVPM5_EL2 0x968
|
||||
#define VNCR_MPAMVPM6_EL2 0x970
|
||||
#define VNCR_MPAMVPM7_EL2 0x978
|
||||
|
||||
#endif /* __ARM64_VNCR_MAPPING_H__ */
|
||||
@@ -2342,7 +2342,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
|
||||
.capability = ARM64_HAS_NESTED_VIRT,
|
||||
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
|
||||
.matches = has_nested_virt_support,
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, IMP)
|
||||
ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, NV2)
|
||||
},
|
||||
{
|
||||
.capability = ARM64_HAS_32BIT_EL0_DO_NOT_USE,
|
||||
|
||||
@@ -21,16 +21,14 @@ if VIRTUALIZATION
|
||||
menuconfig KVM
|
||||
bool "Kernel-based Virtual Machine (KVM) support"
|
||||
depends on HAVE_KVM
|
||||
select KVM_COMMON
|
||||
select KVM_GENERIC_HARDWARE_ENABLING
|
||||
select MMU_NOTIFIER
|
||||
select PREEMPT_NOTIFIERS
|
||||
select KVM_GENERIC_MMU_NOTIFIER
|
||||
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||
select KVM_MMIO
|
||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||
select KVM_XFER_TO_GUEST_WORK
|
||||
select KVM_VFIO
|
||||
select HAVE_KVM_EVENTFD
|
||||
select HAVE_KVM_IRQFD
|
||||
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
select NEED_KVM_DIRTY_RING_WITH_BITMAP
|
||||
select HAVE_KVM_MSI
|
||||
@@ -41,7 +39,6 @@ menuconfig KVM
|
||||
select HAVE_KVM_VCPU_RUN_PID_CHANGE
|
||||
select SCHED_INFO
|
||||
select GUEST_PERF_EVENTS if PERF_EVENTS
|
||||
select INTERVAL_TREE
|
||||
select XARRAY_MULTI
|
||||
help
|
||||
Support hosting virtualized guest machines.
|
||||
|
||||
@@ -295,8 +295,7 @@ static u64 wfit_delay_ns(struct kvm_vcpu *vcpu)
|
||||
u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu));
|
||||
struct arch_timer_context *ctx;
|
||||
|
||||
ctx = (vcpu_has_nv(vcpu) && is_hyp_ctxt(vcpu)) ? vcpu_hvtimer(vcpu)
|
||||
: vcpu_vtimer(vcpu);
|
||||
ctx = is_hyp_ctxt(vcpu) ? vcpu_hvtimer(vcpu) : vcpu_vtimer(vcpu);
|
||||
|
||||
return kvm_counter_compute_delta(ctx, val);
|
||||
}
|
||||
|
||||
+11
-1
@@ -221,7 +221,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
r = vgic_present;
|
||||
break;
|
||||
case KVM_CAP_IOEVENTFD:
|
||||
case KVM_CAP_DEVICE_CTRL:
|
||||
case KVM_CAP_USER_MEMORY:
|
||||
case KVM_CAP_SYNC_MMU:
|
||||
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
|
||||
@@ -669,6 +668,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vcpu_has_nv(vcpu)) {
|
||||
ret = kvm_init_nv_sysregs(vcpu->kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_timer_enable(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1837,6 +1842,7 @@ static int kvm_init_vector_slots(void)
|
||||
static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
||||
{
|
||||
struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
|
||||
u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
|
||||
unsigned long tcr;
|
||||
|
||||
/*
|
||||
@@ -1859,6 +1865,10 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
|
||||
}
|
||||
tcr &= ~TCR_T0SZ_MASK;
|
||||
tcr |= TCR_T0SZ(hyp_va_bits);
|
||||
tcr &= ~TCR_EL2_PS_MASK;
|
||||
tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0));
|
||||
if (kvm_lpa2_is_enabled())
|
||||
tcr |= TCR_EL2_DS;
|
||||
params->tcr_el2 = tcr;
|
||||
|
||||
params->pgd_pa = kvm_mmu_get_httbr();
|
||||
|
||||
@@ -1012,6 +1012,7 @@ enum fgt_group_id {
|
||||
HDFGRTR_GROUP,
|
||||
HDFGWTR_GROUP,
|
||||
HFGITR_GROUP,
|
||||
HAFGRTR_GROUP,
|
||||
|
||||
/* Must be last */
|
||||
__NR_FGT_GROUP_IDS__
|
||||
@@ -1042,10 +1043,20 @@ enum fg_filter_id {
|
||||
|
||||
static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
/* HFGRTR_EL2, HFGWTR_EL2 */
|
||||
SR_FGT(SYS_AMAIR2_EL1, HFGxTR, nAMAIR2_EL1, 0),
|
||||
SR_FGT(SYS_MAIR2_EL1, HFGxTR, nMAIR2_EL1, 0),
|
||||
SR_FGT(SYS_S2POR_EL1, HFGxTR, nS2POR_EL1, 0),
|
||||
SR_FGT(SYS_POR_EL1, HFGxTR, nPOR_EL1, 0),
|
||||
SR_FGT(SYS_POR_EL0, HFGxTR, nPOR_EL0, 0),
|
||||
SR_FGT(SYS_PIR_EL1, HFGxTR, nPIR_EL1, 0),
|
||||
SR_FGT(SYS_PIRE0_EL1, HFGxTR, nPIRE0_EL1, 0),
|
||||
SR_FGT(SYS_RCWMASK_EL1, HFGxTR, nRCWMASK_EL1, 0),
|
||||
SR_FGT(SYS_TPIDR2_EL0, HFGxTR, nTPIDR2_EL0, 0),
|
||||
SR_FGT(SYS_SMPRI_EL1, HFGxTR, nSMPRI_EL1, 0),
|
||||
SR_FGT(SYS_GCSCR_EL1, HFGxTR, nGCS_EL1, 0),
|
||||
SR_FGT(SYS_GCSPR_EL1, HFGxTR, nGCS_EL1, 0),
|
||||
SR_FGT(SYS_GCSCRE0_EL1, HFGxTR, nGCS_EL0, 0),
|
||||
SR_FGT(SYS_GCSPR_EL0, HFGxTR, nGCS_EL0, 0),
|
||||
SR_FGT(SYS_ACCDATA_EL1, HFGxTR, nACCDATA_EL1, 0),
|
||||
SR_FGT(SYS_ERXADDR_EL1, HFGxTR, ERXADDR_EL1, 1),
|
||||
SR_FGT(SYS_ERXPFGCDN_EL1, HFGxTR, ERXPFGCDN_EL1, 1),
|
||||
@@ -1107,6 +1118,11 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
SR_FGT(SYS_AFSR1_EL1, HFGxTR, AFSR1_EL1, 1),
|
||||
SR_FGT(SYS_AFSR0_EL1, HFGxTR, AFSR0_EL1, 1),
|
||||
/* HFGITR_EL2 */
|
||||
SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1),
|
||||
SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1),
|
||||
SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0),
|
||||
SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0),
|
||||
SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0),
|
||||
SR_FGT(SYS_DC_CVAC, HFGITR, DCCVAC, 1),
|
||||
@@ -1674,6 +1690,49 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
||||
SR_FGT(SYS_PMCR_EL0, HDFGWTR, PMCR_EL0, 1),
|
||||
SR_FGT(SYS_PMSWINC_EL0, HDFGWTR, PMSWINC_EL0, 1),
|
||||
SR_FGT(SYS_OSLAR_EL1, HDFGWTR, OSLAR_EL1, 1),
|
||||
/*
|
||||
* HAFGRTR_EL2
|
||||
*/
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(15), HAFGRTR, AMEVTYPER115_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(14), HAFGRTR, AMEVTYPER114_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(13), HAFGRTR, AMEVTYPER113_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(12), HAFGRTR, AMEVTYPER112_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(11), HAFGRTR, AMEVTYPER111_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(10), HAFGRTR, AMEVTYPER110_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(9), HAFGRTR, AMEVTYPER19_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(8), HAFGRTR, AMEVTYPER18_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(7), HAFGRTR, AMEVTYPER17_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(6), HAFGRTR, AMEVTYPER16_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(5), HAFGRTR, AMEVTYPER15_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(4), HAFGRTR, AMEVTYPER14_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(3), HAFGRTR, AMEVTYPER13_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(2), HAFGRTR, AMEVTYPER12_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(1), HAFGRTR, AMEVTYPER11_EL0, 1),
|
||||
SR_FGT(SYS_AMEVTYPER1_EL0(0), HAFGRTR, AMEVTYPER10_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(15), HAFGRTR, AMEVCNTR115_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(14), HAFGRTR, AMEVCNTR114_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(13), HAFGRTR, AMEVCNTR113_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(12), HAFGRTR, AMEVCNTR112_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(11), HAFGRTR, AMEVCNTR111_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(10), HAFGRTR, AMEVCNTR110_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(9), HAFGRTR, AMEVCNTR19_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(8), HAFGRTR, AMEVCNTR18_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(7), HAFGRTR, AMEVCNTR17_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(6), HAFGRTR, AMEVCNTR16_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(5), HAFGRTR, AMEVCNTR15_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(4), HAFGRTR, AMEVCNTR14_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(3), HAFGRTR, AMEVCNTR13_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(2), HAFGRTR, AMEVCNTR12_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(1), HAFGRTR, AMEVCNTR11_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR1_EL0(0), HAFGRTR, AMEVCNTR10_EL0, 1),
|
||||
SR_FGT(SYS_AMCNTENCLR1_EL0, HAFGRTR, AMCNTEN1, 1),
|
||||
SR_FGT(SYS_AMCNTENSET1_EL0, HAFGRTR, AMCNTEN1, 1),
|
||||
SR_FGT(SYS_AMCNTENCLR0_EL0, HAFGRTR, AMCNTEN0, 1),
|
||||
SR_FGT(SYS_AMCNTENSET0_EL0, HAFGRTR, AMCNTEN0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(3), HAFGRTR, AMEVCNTR03_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(2), HAFGRTR, AMEVCNTR02_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(1), HAFGRTR, AMEVCNTR01_EL0, 1),
|
||||
SR_FGT(SYS_AMEVCNTR0_EL0(0), HAFGRTR, AMEVCNTR00_EL0, 1),
|
||||
};
|
||||
|
||||
static union trap_config get_trap_config(u32 sysreg)
|
||||
@@ -1894,6 +1953,10 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu)
|
||||
val = sanitised_sys_reg(vcpu, HDFGWTR_EL2);
|
||||
break;
|
||||
|
||||
case HAFGRTR_GROUP:
|
||||
val = sanitised_sys_reg(vcpu, HAFGRTR_EL2);
|
||||
break;
|
||||
|
||||
case HFGITR_GROUP:
|
||||
val = sanitised_sys_reg(vcpu, HFGITR_EL2);
|
||||
switch (tc.fgf) {
|
||||
|
||||
@@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault)
|
||||
*/
|
||||
if (!(esr & ESR_ELx_S1PTW) &&
|
||||
(cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
|
||||
(esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) {
|
||||
esr_fsc_is_permission_fault(esr))) {
|
||||
if (!__translate_far_to_hpfar(far, &hpfar))
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -79,6 +79,45 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
|
||||
clr |= ~hfg & __ ## reg ## _nMASK; \
|
||||
} while(0)
|
||||
|
||||
#define update_fgt_traps_cs(vcpu, reg, clr, set) \
|
||||
do { \
|
||||
struct kvm_cpu_context *hctxt = \
|
||||
&this_cpu_ptr(&kvm_host_data)->host_ctxt; \
|
||||
u64 c = 0, s = 0; \
|
||||
\
|
||||
ctxt_sys_reg(hctxt, reg) = read_sysreg_s(SYS_ ## reg); \
|
||||
compute_clr_set(vcpu, reg, c, s); \
|
||||
s |= set; \
|
||||
c |= clr; \
|
||||
if (c || s) { \
|
||||
u64 val = __ ## reg ## _nMASK; \
|
||||
val |= s; \
|
||||
val &= ~c; \
|
||||
write_sysreg_s(val, SYS_ ## reg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define update_fgt_traps(vcpu, reg) \
|
||||
update_fgt_traps_cs(vcpu, reg, 0, 0)
|
||||
|
||||
/*
|
||||
* Validate the fine grain trap masks.
|
||||
* Check that the masks do not overlap and that all bits are accounted for.
|
||||
*/
|
||||
#define CHECK_FGT_MASKS(reg) \
|
||||
do { \
|
||||
BUILD_BUG_ON((__ ## reg ## _MASK) & (__ ## reg ## _nMASK)); \
|
||||
BUILD_BUG_ON(~((__ ## reg ## _RES0) ^ (__ ## reg ## _MASK) ^ \
|
||||
(__ ## reg ## _nMASK))); \
|
||||
} while(0)
|
||||
|
||||
static inline bool cpu_has_amu(void)
|
||||
{
|
||||
u64 pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
|
||||
|
||||
return cpuid_feature_extract_unsigned_field(pfr0,
|
||||
ID_AA64PFR0_EL1_AMU_SHIFT);
|
||||
}
|
||||
|
||||
static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@@ -86,6 +125,14 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp;
|
||||
u64 r_val, w_val;
|
||||
|
||||
CHECK_FGT_MASKS(HFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HFGWTR_EL2);
|
||||
CHECK_FGT_MASKS(HFGITR_EL2);
|
||||
CHECK_FGT_MASKS(HDFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HDFGWTR_EL2);
|
||||
CHECK_FGT_MASKS(HAFGRTR_EL2);
|
||||
CHECK_FGT_MASKS(HCRX_EL2);
|
||||
|
||||
if (!cpus_have_final_cap(ARM64_HAS_FGT))
|
||||
return;
|
||||
|
||||
@@ -110,12 +157,15 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set);
|
||||
}
|
||||
|
||||
/* The default is not to trap anything but ACCDATA_EL1 */
|
||||
r_val = __HFGRTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
|
||||
/* The default to trap everything not handled or supported in KVM. */
|
||||
tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 |
|
||||
HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1;
|
||||
|
||||
r_val = __HFGRTR_EL2_nMASK & ~tmp;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
w_val = __HFGWTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
|
||||
w_val = __HFGWTR_EL2_nMASK & ~tmp;
|
||||
w_val |= w_set;
|
||||
w_val &= ~w_clr;
|
||||
|
||||
@@ -125,34 +175,12 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
|
||||
return;
|
||||
|
||||
ctxt_sys_reg(hctxt, HFGITR_EL2) = read_sysreg_s(SYS_HFGITR_EL2);
|
||||
update_fgt_traps(vcpu, HFGITR_EL2);
|
||||
update_fgt_traps(vcpu, HDFGRTR_EL2);
|
||||
update_fgt_traps(vcpu, HDFGWTR_EL2);
|
||||
|
||||
r_set = r_clr = 0;
|
||||
compute_clr_set(vcpu, HFGITR_EL2, r_clr, r_set);
|
||||
r_val = __HFGITR_EL2_nMASK;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
write_sysreg_s(r_val, SYS_HFGITR_EL2);
|
||||
|
||||
ctxt_sys_reg(hctxt, HDFGRTR_EL2) = read_sysreg_s(SYS_HDFGRTR_EL2);
|
||||
ctxt_sys_reg(hctxt, HDFGWTR_EL2) = read_sysreg_s(SYS_HDFGWTR_EL2);
|
||||
|
||||
r_clr = r_set = w_clr = w_set = 0;
|
||||
|
||||
compute_clr_set(vcpu, HDFGRTR_EL2, r_clr, r_set);
|
||||
compute_clr_set(vcpu, HDFGWTR_EL2, w_clr, w_set);
|
||||
|
||||
r_val = __HDFGRTR_EL2_nMASK;
|
||||
r_val |= r_set;
|
||||
r_val &= ~r_clr;
|
||||
|
||||
w_val = __HDFGWTR_EL2_nMASK;
|
||||
w_val |= w_set;
|
||||
w_val &= ~w_clr;
|
||||
|
||||
write_sysreg_s(r_val, SYS_HDFGRTR_EL2);
|
||||
write_sysreg_s(w_val, SYS_HDFGWTR_EL2);
|
||||
if (cpu_has_amu())
|
||||
update_fgt_traps(vcpu, HAFGRTR_EL2);
|
||||
}
|
||||
|
||||
static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
@@ -171,6 +199,9 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HFGITR_EL2), SYS_HFGITR_EL2);
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGRTR_EL2), SYS_HDFGRTR_EL2);
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGWTR_EL2), SYS_HDFGWTR_EL2);
|
||||
|
||||
if (cpu_has_amu())
|
||||
write_sysreg_s(ctxt_sys_reg(hctxt, HAFGRTR_EL2), SYS_HAFGRTR_EL2);
|
||||
}
|
||||
|
||||
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
|
||||
@@ -591,7 +622,7 @@ static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
if (static_branch_unlikely(&vgic_v2_cpuif_trap)) {
|
||||
bool valid;
|
||||
|
||||
valid = kvm_vcpu_trap_get_fault_type(vcpu) == ESR_ELx_FSC_FAULT &&
|
||||
valid = kvm_vcpu_trap_is_translation_fault(vcpu) &&
|
||||
kvm_vcpu_dabt_isvalid(vcpu) &&
|
||||
!kvm_vcpu_abt_issea(vcpu) &&
|
||||
!kvm_vcpu_abt_iss1tw(vcpu);
|
||||
|
||||
@@ -69,6 +69,8 @@
|
||||
ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SSBS) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64PFR2_ALLOW 0ULL
|
||||
|
||||
/*
|
||||
* Allow for protected VMs:
|
||||
* - Mixed-endian
|
||||
@@ -101,6 +103,7 @@
|
||||
* - Privileged Access Never
|
||||
* - SError interrupt exceptions from speculative reads
|
||||
* - Enhanced Translation Synchronization
|
||||
* - Control for cache maintenance permission
|
||||
*/
|
||||
#define PVM_ID_AA64MMFR1_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HAFDBS) | \
|
||||
@@ -108,7 +111,8 @@
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HPDS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_PAN) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_SpecSEI) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_CMOW) \
|
||||
)
|
||||
|
||||
/*
|
||||
@@ -133,6 +137,8 @@
|
||||
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_E0PD) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64MMFR3_ALLOW (0ULL)
|
||||
|
||||
/*
|
||||
* No support for Scalable Vectors for protected VMs:
|
||||
* Requires additional support from KVM, e.g., context-switching and
|
||||
@@ -178,10 +184,18 @@
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_RNDR) \
|
||||
)
|
||||
|
||||
/* Restrict pointer authentication to the basic version. */
|
||||
#define PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), ID_AA64ISAR1_EL1_APA_PAuth) | \
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), ID_AA64ISAR1_EL1_API_PAuth) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR2_RESTRICT_UNSIGNED (\
|
||||
FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3), ID_AA64ISAR2_EL1_APA3_PAuth) \
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR1_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DPB) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \
|
||||
@@ -196,8 +210,8 @@
|
||||
)
|
||||
|
||||
#define PVM_ID_AA64ISAR2_ALLOW (\
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_ATS1A)| \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | \
|
||||
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \
|
||||
)
|
||||
|
||||
|
||||
@@ -122,11 +122,7 @@ alternative_if ARM64_HAS_CNP
|
||||
alternative_else_nop_endif
|
||||
msr ttbr0_el2, x2
|
||||
|
||||
/*
|
||||
* Set the PS bits in TCR_EL2.
|
||||
*/
|
||||
ldr x0, [x0, #NVHE_INIT_TCR_EL2]
|
||||
tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2
|
||||
msr tcr_el2, x0
|
||||
|
||||
isb
|
||||
@@ -292,6 +288,8 @@ alternative_else_nop_endif
|
||||
mov sp, x0
|
||||
|
||||
/* And turn the MMU back on! */
|
||||
dsb nsh
|
||||
isb
|
||||
set_sctlr_el2 x2
|
||||
ret x1
|
||||
SYM_FUNC_END(__pkvm_init_switch_pgd)
|
||||
|
||||
@@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr)
|
||||
hyp_put_page(&host_s2_pool, addr);
|
||||
}
|
||||
|
||||
static void host_s2_free_unlinked_table(void *addr, u32 level)
|
||||
static void host_s2_free_unlinked_table(void *addr, s8 level)
|
||||
{
|
||||
kvm_pgtable_stage2_free_unlinked(&host_mmu.mm_ops, addr, level);
|
||||
}
|
||||
@@ -443,7 +443,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
{
|
||||
struct kvm_mem_range cur;
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
int ret;
|
||||
|
||||
hyp_assert_lock_held(&host_mmu.lock);
|
||||
@@ -462,7 +462,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
cur.start = ALIGN_DOWN(addr, granule);
|
||||
cur.end = cur.start + granule;
|
||||
level++;
|
||||
} while ((level < KVM_PGTABLE_MAX_LEVELS) &&
|
||||
} while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
|
||||
!(kvm_level_supports_block_mapping(level) &&
|
||||
range_included(&cur, range)));
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
|
||||
* https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
|
||||
*/
|
||||
dsb(ishst);
|
||||
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1));
|
||||
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL);
|
||||
dsb(ish);
|
||||
isb();
|
||||
}
|
||||
@@ -275,7 +275,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
{
|
||||
struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg);
|
||||
|
||||
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
slot->addr = ctx->addr;
|
||||
|
||||
@@ -136,6 +136,10 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
|
||||
cptr_set |= CPTR_EL2_TTA;
|
||||
}
|
||||
|
||||
/* Trap External Trace */
|
||||
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids))
|
||||
mdcr_clear |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT;
|
||||
|
||||
vcpu->arch.mdcr_el2 |= mdcr_set;
|
||||
vcpu->arch.mdcr_el2 &= ~mdcr_clear;
|
||||
vcpu->arch.cptr_el2 |= cptr_set;
|
||||
|
||||
@@ -181,7 +181,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (!kvm_pte_valid(ctx->old))
|
||||
return 0;
|
||||
|
||||
if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (ctx->level != KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
phys = kvm_pte_to_phys(ctx->old);
|
||||
|
||||
@@ -79,7 +79,10 @@ static bool kvm_pgtable_walk_skip_cmo(const struct kvm_pgtable_visit_ctx *ctx)
|
||||
|
||||
static bool kvm_phys_is_valid(u64 phys)
|
||||
{
|
||||
return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_EL1_PARANGE_MAX));
|
||||
u64 parange_max = kvm_get_parange_max();
|
||||
u8 shift = id_aa64mmfr0_parange_to_phys_shift(parange_max);
|
||||
|
||||
return phys < BIT(shift);
|
||||
}
|
||||
|
||||
static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, u64 phys)
|
||||
@@ -98,7 +101,7 @@ static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
return IS_ALIGNED(ctx->addr, granule);
|
||||
}
|
||||
|
||||
static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, u32 level)
|
||||
static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, s8 level)
|
||||
{
|
||||
u64 shift = kvm_granule_shift(level);
|
||||
u64 mask = BIT(PAGE_SHIFT - 3) - 1;
|
||||
@@ -114,7 +117,7 @@ static u32 kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
|
||||
return (addr & mask) >> shift;
|
||||
}
|
||||
|
||||
static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
|
||||
static u32 kvm_pgd_pages(u32 ia_bits, s8 start_level)
|
||||
{
|
||||
struct kvm_pgtable pgt = {
|
||||
.ia_bits = ia_bits,
|
||||
@@ -124,9 +127,9 @@ static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
|
||||
return kvm_pgd_page_idx(&pgt, -1ULL) + 1;
|
||||
}
|
||||
|
||||
static bool kvm_pte_table(kvm_pte_t pte, u32 level)
|
||||
static bool kvm_pte_table(kvm_pte_t pte, s8 level)
|
||||
{
|
||||
if (level == KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (level == KVM_PGTABLE_LAST_LEVEL)
|
||||
return false;
|
||||
|
||||
if (!kvm_pte_valid(pte))
|
||||
@@ -154,11 +157,11 @@ static kvm_pte_t kvm_init_table_pte(kvm_pte_t *childp, struct kvm_pgtable_mm_ops
|
||||
return pte;
|
||||
}
|
||||
|
||||
static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, u32 level)
|
||||
static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, s8 level)
|
||||
{
|
||||
kvm_pte_t pte = kvm_phys_to_pte(pa);
|
||||
u64 type = (level == KVM_PGTABLE_MAX_LEVELS - 1) ? KVM_PTE_TYPE_PAGE :
|
||||
KVM_PTE_TYPE_BLOCK;
|
||||
u64 type = (level == KVM_PGTABLE_LAST_LEVEL) ? KVM_PTE_TYPE_PAGE :
|
||||
KVM_PTE_TYPE_BLOCK;
|
||||
|
||||
pte |= attr & (KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI);
|
||||
pte |= FIELD_PREP(KVM_PTE_TYPE, type);
|
||||
@@ -203,11 +206,11 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker,
|
||||
}
|
||||
|
||||
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level);
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level);
|
||||
|
||||
static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops,
|
||||
kvm_pteref_t pteref, u32 level)
|
||||
kvm_pteref_t pteref, s8 level)
|
||||
{
|
||||
enum kvm_pgtable_walk_flags flags = data->walker->flags;
|
||||
kvm_pte_t *ptep = kvm_dereference_pteref(data->walker, pteref);
|
||||
@@ -272,12 +275,13 @@ out:
|
||||
}
|
||||
|
||||
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level)
|
||||
struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level)
|
||||
{
|
||||
u32 idx;
|
||||
int ret = 0;
|
||||
|
||||
if (WARN_ON_ONCE(level >= KVM_PGTABLE_MAX_LEVELS))
|
||||
if (WARN_ON_ONCE(level < KVM_PGTABLE_FIRST_LEVEL ||
|
||||
level > KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
for (idx = kvm_pgtable_idx(data, level); idx < PTRS_PER_PTE; ++idx) {
|
||||
@@ -340,7 +344,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
|
||||
struct leaf_walk_data {
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
};
|
||||
|
||||
static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
@@ -355,7 +359,7 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
}
|
||||
|
||||
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
|
||||
kvm_pte_t *ptep, u32 *level)
|
||||
kvm_pte_t *ptep, s8 *level)
|
||||
{
|
||||
struct leaf_walk_data data;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
@@ -408,7 +412,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
|
||||
}
|
||||
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
|
||||
if (!kvm_lpa2_is_enabled())
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
|
||||
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
|
||||
*ptep = attr;
|
||||
@@ -467,7 +472,7 @@ static int hyp_map_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (hyp_map_walker_try_leaf(ctx, data))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
childp = (kvm_pte_t *)mm_ops->zalloc_page(NULL);
|
||||
@@ -563,14 +568,19 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
|
||||
int kvm_pgtable_hyp_init(struct kvm_pgtable *pgt, u32 va_bits,
|
||||
struct kvm_pgtable_mm_ops *mm_ops)
|
||||
{
|
||||
u64 levels = ARM64_HW_PGTABLE_LEVELS(va_bits);
|
||||
s8 start_level = KVM_PGTABLE_LAST_LEVEL + 1 -
|
||||
ARM64_HW_PGTABLE_LEVELS(va_bits);
|
||||
|
||||
if (start_level < KVM_PGTABLE_FIRST_LEVEL ||
|
||||
start_level > KVM_PGTABLE_LAST_LEVEL)
|
||||
return -EINVAL;
|
||||
|
||||
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_page(NULL);
|
||||
if (!pgt->pgd)
|
||||
return -ENOMEM;
|
||||
|
||||
pgt->ia_bits = va_bits;
|
||||
pgt->start_level = KVM_PGTABLE_MAX_LEVELS - levels;
|
||||
pgt->start_level = start_level;
|
||||
pgt->mm_ops = mm_ops;
|
||||
pgt->mmu = NULL;
|
||||
pgt->force_pte_cb = NULL;
|
||||
@@ -624,7 +634,7 @@ struct stage2_map_data {
|
||||
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
{
|
||||
u64 vtcr = VTCR_EL2_FLAGS;
|
||||
u8 lvls;
|
||||
s8 lvls;
|
||||
|
||||
vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
|
||||
vtcr |= VTCR_EL2_T0SZ(phys_shift);
|
||||
@@ -635,6 +645,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
lvls = stage2_pgtable_levels(phys_shift);
|
||||
if (lvls < 2)
|
||||
lvls = 2;
|
||||
|
||||
/*
|
||||
* When LPA2 is enabled, the HW supports an extra level of translation
|
||||
* (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
|
||||
* to as an addition to SL0 to enable encoding this extra start level.
|
||||
* However, since we always use concatenated pages for the first level
|
||||
* lookup, we will never need this extra level and therefore do not need
|
||||
* to touch SL2.
|
||||
*/
|
||||
vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
|
||||
|
||||
#ifdef CONFIG_ARM64_HW_AFDBM
|
||||
@@ -654,6 +673,9 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
|
||||
vtcr |= VTCR_EL2_HA;
|
||||
#endif /* CONFIG_ARM64_HW_AFDBM */
|
||||
|
||||
if (kvm_lpa2_is_enabled())
|
||||
vtcr |= VTCR_EL2_DS;
|
||||
|
||||
/* Set the vmid bits */
|
||||
vtcr |= (get_vmid_bits(mmfr1) == 16) ?
|
||||
VTCR_EL2_VS_16BIT :
|
||||
@@ -711,7 +733,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
|
||||
if (prot & KVM_PGTABLE_PROT_W)
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
|
||||
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
|
||||
if (!kvm_lpa2_is_enabled())
|
||||
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
|
||||
|
||||
attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF;
|
||||
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
|
||||
*ptep = attr;
|
||||
@@ -902,7 +926,7 @@ static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
{
|
||||
u64 phys = stage2_map_walker_phys_addr(ctx, data);
|
||||
|
||||
if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1)))
|
||||
if (data->force_pte && ctx->level < KVM_PGTABLE_LAST_LEVEL)
|
||||
return false;
|
||||
|
||||
return kvm_block_mapping_supported(ctx, phys);
|
||||
@@ -981,7 +1005,7 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
if (ret != -E2BIG)
|
||||
return ret;
|
||||
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
|
||||
if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
if (!data->memcache)
|
||||
@@ -1151,7 +1175,7 @@ struct stage2_attr_data {
|
||||
kvm_pte_t attr_set;
|
||||
kvm_pte_t attr_clr;
|
||||
kvm_pte_t pte;
|
||||
u32 level;
|
||||
s8 level;
|
||||
};
|
||||
|
||||
static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
@@ -1194,7 +1218,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
|
||||
u64 size, kvm_pte_t attr_set,
|
||||
kvm_pte_t attr_clr, kvm_pte_t *orig_pte,
|
||||
u32 *level, enum kvm_pgtable_walk_flags flags)
|
||||
s8 *level, enum kvm_pgtable_walk_flags flags)
|
||||
{
|
||||
int ret;
|
||||
kvm_pte_t attr_mask = KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI;
|
||||
@@ -1296,7 +1320,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
|
||||
enum kvm_pgtable_prot prot)
|
||||
{
|
||||
int ret;
|
||||
u32 level;
|
||||
s8 level;
|
||||
kvm_pte_t set = 0, clr = 0;
|
||||
|
||||
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
|
||||
@@ -1349,7 +1373,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size)
|
||||
}
|
||||
|
||||
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
u64 phys, u32 level,
|
||||
u64 phys, s8 level,
|
||||
enum kvm_pgtable_prot prot,
|
||||
void *mc, bool force_pte)
|
||||
{
|
||||
@@ -1407,7 +1431,7 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
|
||||
* fully populated tree up to the PTE entries. Note that @level is
|
||||
* interpreted as in "level @level entry".
|
||||
*/
|
||||
static int stage2_block_get_nr_page_tables(u32 level)
|
||||
static int stage2_block_get_nr_page_tables(s8 level)
|
||||
{
|
||||
switch (level) {
|
||||
case 1:
|
||||
@@ -1418,7 +1442,7 @@ static int stage2_block_get_nr_page_tables(u32 level)
|
||||
return 0;
|
||||
default:
|
||||
WARN_ON_ONCE(level < KVM_PGTABLE_MIN_BLOCK_LEVEL ||
|
||||
level >= KVM_PGTABLE_MAX_LEVELS);
|
||||
level > KVM_PGTABLE_LAST_LEVEL);
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
@@ -1431,13 +1455,13 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
struct kvm_s2_mmu *mmu;
|
||||
kvm_pte_t pte = ctx->old, new, *childp;
|
||||
enum kvm_pgtable_prot prot;
|
||||
u32 level = ctx->level;
|
||||
s8 level = ctx->level;
|
||||
bool force_pte;
|
||||
int nr_pages;
|
||||
u64 phys;
|
||||
|
||||
/* No huge-pages exist at the last level */
|
||||
if (level == KVM_PGTABLE_MAX_LEVELS - 1)
|
||||
if (level == KVM_PGTABLE_LAST_LEVEL)
|
||||
return 0;
|
||||
|
||||
/* We only split valid block mappings */
|
||||
@@ -1514,7 +1538,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
|
||||
u64 vtcr = mmu->vtcr;
|
||||
u32 ia_bits = VTCR_EL2_IPA(vtcr);
|
||||
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
|
||||
u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
|
||||
pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
|
||||
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_pages_exact(pgd_sz);
|
||||
@@ -1537,7 +1561,7 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
|
||||
{
|
||||
u32 ia_bits = VTCR_EL2_IPA(vtcr);
|
||||
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
|
||||
u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
|
||||
|
||||
return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
|
||||
}
|
||||
@@ -1573,7 +1597,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
|
||||
pgt->pgd = NULL;
|
||||
}
|
||||
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level)
|
||||
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
|
||||
{
|
||||
kvm_pteref_t ptep = (kvm_pteref_t)pgtable;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
|
||||
+25
-24
@@ -223,12 +223,12 @@ static void stage2_free_unlinked_table_rcu_cb(struct rcu_head *head)
|
||||
{
|
||||
struct page *page = container_of(head, struct page, rcu_head);
|
||||
void *pgtable = page_to_virt(page);
|
||||
u32 level = page_private(page);
|
||||
s8 level = page_private(page);
|
||||
|
||||
kvm_pgtable_stage2_free_unlinked(&kvm_s2_mm_ops, pgtable, level);
|
||||
}
|
||||
|
||||
static void stage2_free_unlinked_table(void *addr, u32 level)
|
||||
static void stage2_free_unlinked_table(void *addr, s8 level)
|
||||
{
|
||||
struct page *page = virt_to_page(addr);
|
||||
|
||||
@@ -804,13 +804,13 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
|
||||
struct kvm_pgtable pgt = {
|
||||
.pgd = (kvm_pteref_t)kvm->mm->pgd,
|
||||
.ia_bits = vabits_actual,
|
||||
.start_level = (KVM_PGTABLE_MAX_LEVELS -
|
||||
CONFIG_PGTABLE_LEVELS),
|
||||
.start_level = (KVM_PGTABLE_LAST_LEVEL -
|
||||
CONFIG_PGTABLE_LEVELS + 1),
|
||||
.mm_ops = &kvm_user_mm_ops,
|
||||
};
|
||||
unsigned long flags;
|
||||
kvm_pte_t pte = 0; /* Keep GCC quiet... */
|
||||
u32 level = ~0;
|
||||
s8 level = S8_MAX;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -829,7 +829,9 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
|
||||
* Not seeing an error, but not updating level? Something went
|
||||
* deeply wrong...
|
||||
*/
|
||||
if (WARN_ON(level >= KVM_PGTABLE_MAX_LEVELS))
|
||||
if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EFAULT;
|
||||
if (WARN_ON(level < KVM_PGTABLE_FIRST_LEVEL))
|
||||
return -EFAULT;
|
||||
|
||||
/* Oops, the userspace PTs are gone... Replay the fault */
|
||||
@@ -1374,7 +1376,7 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
|
||||
|
||||
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
struct kvm_memory_slot *memslot, unsigned long hva,
|
||||
unsigned long fault_status)
|
||||
bool fault_is_perm)
|
||||
{
|
||||
int ret = 0;
|
||||
bool write_fault, writable, force_pte = false;
|
||||
@@ -1388,17 +1390,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
gfn_t gfn;
|
||||
kvm_pfn_t pfn;
|
||||
bool logging_active = memslot_is_logging(memslot);
|
||||
unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
|
||||
long vma_pagesize, fault_granule;
|
||||
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
|
||||
struct kvm_pgtable *pgt;
|
||||
|
||||
fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
|
||||
if (fault_is_perm)
|
||||
fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu);
|
||||
write_fault = kvm_is_write_fault(vcpu);
|
||||
exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
|
||||
VM_BUG_ON(write_fault && exec_fault);
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_PERM && !write_fault && !exec_fault) {
|
||||
if (fault_is_perm && !write_fault && !exec_fault) {
|
||||
kvm_err("Unexpected L2 read permission error\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -1409,8 +1411,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* only exception to this is when dirty logging is enabled at runtime
|
||||
* and a write fault needs to collapse a block entry into a table.
|
||||
*/
|
||||
if (fault_status != ESR_ELx_FSC_PERM ||
|
||||
(logging_active && write_fault)) {
|
||||
if (!fault_is_perm || (logging_active && write_fault)) {
|
||||
ret = kvm_mmu_topup_memory_cache(memcache,
|
||||
kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu));
|
||||
if (ret)
|
||||
@@ -1527,8 +1528,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* backed by a THP and thus use block mapping if possible.
|
||||
*/
|
||||
if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
|
||||
if (fault_status == ESR_ELx_FSC_PERM &&
|
||||
fault_granule > PAGE_SIZE)
|
||||
if (fault_is_perm && fault_granule > PAGE_SIZE)
|
||||
vma_pagesize = fault_granule;
|
||||
else
|
||||
vma_pagesize = transparent_hugepage_adjust(kvm, memslot,
|
||||
@@ -1541,7 +1541,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
}
|
||||
}
|
||||
|
||||
if (fault_status != ESR_ELx_FSC_PERM && !device && kvm_has_mte(kvm)) {
|
||||
if (!fault_is_perm && !device && kvm_has_mte(kvm)) {
|
||||
/* Check the VMM hasn't introduced a new disallowed VMA */
|
||||
if (mte_allowed) {
|
||||
sanitise_mte_tags(kvm, pfn, vma_pagesize);
|
||||
@@ -1567,7 +1567,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
* permissions only if vma_pagesize equals fault_granule. Otherwise,
|
||||
* kvm_pgtable_stage2_map() should be called to change block size.
|
||||
*/
|
||||
if (fault_status == ESR_ELx_FSC_PERM && vma_pagesize == fault_granule)
|
||||
if (fault_is_perm && vma_pagesize == fault_granule)
|
||||
ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
|
||||
else
|
||||
ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
|
||||
@@ -1618,7 +1618,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
||||
*/
|
||||
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long fault_status;
|
||||
unsigned long esr;
|
||||
phys_addr_t fault_ipa;
|
||||
struct kvm_memory_slot *memslot;
|
||||
unsigned long hva;
|
||||
@@ -1626,12 +1626,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
gfn_t gfn;
|
||||
int ret, idx;
|
||||
|
||||
fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
|
||||
esr = kvm_vcpu_get_esr(vcpu);
|
||||
|
||||
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
|
||||
is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_FAULT) {
|
||||
if (esr_fsc_is_permission_fault(esr)) {
|
||||
/* Beyond sanitised PARange (which is the IPA limit) */
|
||||
if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
|
||||
kvm_inject_size_fault(vcpu);
|
||||
@@ -1666,9 +1666,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
kvm_vcpu_get_hfar(vcpu), fault_ipa);
|
||||
|
||||
/* Check the stage-2 fault is trans. fault or write fault */
|
||||
if (fault_status != ESR_ELx_FSC_FAULT &&
|
||||
fault_status != ESR_ELx_FSC_PERM &&
|
||||
fault_status != ESR_ELx_FSC_ACCESS) {
|
||||
if (!esr_fsc_is_translation_fault(esr) &&
|
||||
!esr_fsc_is_permission_fault(esr) &&
|
||||
!esr_fsc_is_access_flag_fault(esr)) {
|
||||
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
|
||||
kvm_vcpu_trap_get_class(vcpu),
|
||||
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
|
||||
@@ -1730,13 +1730,14 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
|
||||
/* Userspace should not be able to register out-of-bounds IPAs */
|
||||
VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu));
|
||||
|
||||
if (fault_status == ESR_ELx_FSC_ACCESS) {
|
||||
if (esr_fsc_is_access_flag_fault(esr)) {
|
||||
handle_access_fault(vcpu, fault_ipa);
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
|
||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva,
|
||||
esr_fsc_is_permission_fault(esr));
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
out:
|
||||
|
||||
+15
-7
@@ -23,13 +23,9 @@
|
||||
* This list should get updated as new features get added to the NV
|
||||
* support, and new extension to the architecture.
|
||||
*/
|
||||
void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
static u64 limit_nv_id_reg(u32 id, u64 val)
|
||||
{
|
||||
u32 id = reg_to_encoding(r);
|
||||
u64 val, tmp;
|
||||
|
||||
val = p->regval;
|
||||
u64 tmp;
|
||||
|
||||
switch (id) {
|
||||
case SYS_ID_AA64ISAR0_EL1:
|
||||
@@ -158,5 +154,17 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
|
||||
break;
|
||||
}
|
||||
|
||||
p->regval = val;
|
||||
return val;
|
||||
}
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm)
|
||||
{
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++)
|
||||
kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i),
|
||||
kvm->arch.id_regs[i]);
|
||||
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -280,12 +280,11 @@ int __init kvm_set_ipa_limit(void)
|
||||
parange = cpuid_feature_extract_unsigned_field(mmfr0,
|
||||
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
|
||||
/*
|
||||
* IPA size beyond 48 bits could not be supported
|
||||
* on either 4K or 16K page size. Hence let's cap
|
||||
* it to 48 bits, in case it's reported as larger
|
||||
* on the system.
|
||||
* IPA size beyond 48 bits for 4K and 16K page size is only supported
|
||||
* when LPA2 is available. So if we have LPA2, enable it, else cap to 48
|
||||
* bits, in case it's reported as larger on the system.
|
||||
*/
|
||||
if (PAGE_SIZE != SZ_64K)
|
||||
if (!kvm_lpa2_is_enabled() && PAGE_SIZE != SZ_64K)
|
||||
parange = min(parange, (unsigned int)ID_AA64MMFR0_EL1_PARANGE_48);
|
||||
|
||||
/*
|
||||
|
||||
+187
-48
@@ -45,44 +45,170 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
|
||||
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
|
||||
u64 val);
|
||||
|
||||
static bool bad_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r,
|
||||
const char *msg)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected %s\n", msg);
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool read_from_write_only(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected sys_reg read to write-only register\n");
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return bad_trap(vcpu, params, r,
|
||||
"sys_reg read to write-only register");
|
||||
}
|
||||
|
||||
static bool write_to_read_only(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n");
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return bad_trap(vcpu, params, r,
|
||||
"sys_reg write to read-only register");
|
||||
}
|
||||
|
||||
#define PURE_EL2_SYSREG(el2) \
|
||||
case el2: { \
|
||||
*el1r = el2; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
#define MAPPED_EL2_SYSREG(el2, el1, fn) \
|
||||
case el2: { \
|
||||
*xlate = fn; \
|
||||
*el1r = el1; \
|
||||
return true; \
|
||||
}
|
||||
|
||||
static bool get_el2_to_el1_mapping(unsigned int reg,
|
||||
unsigned int *el1r, u64 (**xlate)(u64))
|
||||
{
|
||||
switch (reg) {
|
||||
PURE_EL2_SYSREG( VPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( VMPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( ACTLR_EL2 );
|
||||
PURE_EL2_SYSREG( HCR_EL2 );
|
||||
PURE_EL2_SYSREG( MDCR_EL2 );
|
||||
PURE_EL2_SYSREG( HSTR_EL2 );
|
||||
PURE_EL2_SYSREG( HACR_EL2 );
|
||||
PURE_EL2_SYSREG( VTTBR_EL2 );
|
||||
PURE_EL2_SYSREG( VTCR_EL2 );
|
||||
PURE_EL2_SYSREG( RVBAR_EL2 );
|
||||
PURE_EL2_SYSREG( TPIDR_EL2 );
|
||||
PURE_EL2_SYSREG( HPFAR_EL2 );
|
||||
PURE_EL2_SYSREG( CNTHCTL_EL2 );
|
||||
MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1,
|
||||
translate_sctlr_el2_to_sctlr_el1 );
|
||||
MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1,
|
||||
translate_cptr_el2_to_cpacr_el1 );
|
||||
MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1,
|
||||
translate_ttbr0_el2_to_ttbr0_el1 );
|
||||
MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(TCR_EL2, TCR_EL1,
|
||||
translate_tcr_el2_to_tcr_el1 );
|
||||
MAPPED_EL2_SYSREG(VBAR_EL2, VBAR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AFSR0_EL2, AFSR0_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AFSR1_EL2, AFSR1_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL );
|
||||
MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL );
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
|
||||
{
|
||||
u64 val = 0x8badf00d8badf00d;
|
||||
u64 (*xlate)(u64) = NULL;
|
||||
unsigned int el1r;
|
||||
|
||||
if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
|
||||
__vcpu_read_sys_reg_from_cpu(reg, &val))
|
||||
if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
goto memory_read;
|
||||
|
||||
if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
|
||||
if (!is_hyp_ctxt(vcpu))
|
||||
goto memory_read;
|
||||
|
||||
/*
|
||||
* If this register does not have an EL1 counterpart,
|
||||
* then read the stored EL2 version.
|
||||
*/
|
||||
if (reg == el1r)
|
||||
goto memory_read;
|
||||
|
||||
/*
|
||||
* If we have a non-VHE guest and that the sysreg
|
||||
* requires translation to be used at EL1, use the
|
||||
* in-memory copy instead.
|
||||
*/
|
||||
if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
|
||||
goto memory_read;
|
||||
|
||||
/* Get the current version of the EL1 counterpart. */
|
||||
WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val));
|
||||
return val;
|
||||
}
|
||||
|
||||
/* EL1 register can't be on the CPU if the guest is in vEL2. */
|
||||
if (unlikely(is_hyp_ctxt(vcpu)))
|
||||
goto memory_read;
|
||||
|
||||
if (__vcpu_read_sys_reg_from_cpu(reg, &val))
|
||||
return val;
|
||||
|
||||
memory_read:
|
||||
return __vcpu_sys_reg(vcpu, reg);
|
||||
}
|
||||
|
||||
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
|
||||
{
|
||||
if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
|
||||
__vcpu_write_sys_reg_to_cpu(val, reg))
|
||||
u64 (*xlate)(u64) = NULL;
|
||||
unsigned int el1r;
|
||||
|
||||
if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
|
||||
goto memory_write;
|
||||
|
||||
if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
|
||||
if (!is_hyp_ctxt(vcpu))
|
||||
goto memory_write;
|
||||
|
||||
/*
|
||||
* Always store a copy of the write to memory to avoid having
|
||||
* to reverse-translate virtual EL2 system registers for a
|
||||
* non-VHE guest hypervisor.
|
||||
*/
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
|
||||
/* No EL1 counterpart? We're done here.? */
|
||||
if (reg == el1r)
|
||||
return;
|
||||
|
||||
if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
|
||||
val = xlate(val);
|
||||
|
||||
/* Redirect this to the EL1 version of the register. */
|
||||
WARN_ON(!__vcpu_write_sys_reg_to_cpu(val, el1r));
|
||||
return;
|
||||
}
|
||||
|
||||
/* EL1 register can't be on the CPU if the guest is in vEL2. */
|
||||
if (unlikely(is_hyp_ctxt(vcpu)))
|
||||
goto memory_write;
|
||||
|
||||
if (__vcpu_write_sys_reg_to_cpu(val, reg))
|
||||
return;
|
||||
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
memory_write:
|
||||
__vcpu_sys_reg(vcpu, reg) = val;
|
||||
}
|
||||
|
||||
/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
|
||||
@@ -1505,8 +1631,6 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
|
||||
return write_to_read_only(vcpu, p, r);
|
||||
|
||||
p->regval = read_id_reg(vcpu, r);
|
||||
if (vcpu_has_nv(vcpu))
|
||||
access_nested_id_reg(vcpu, p, r);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1885,6 +2009,32 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
static bool bad_vncr_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
/*
|
||||
* We really shouldn't be here, and this is likely the result
|
||||
* of a misconfigured trap, as this register should target the
|
||||
* VNCR page, and nothing else.
|
||||
*/
|
||||
return bad_trap(vcpu, p, r,
|
||||
"trap of VNCR-backed register");
|
||||
}
|
||||
|
||||
static bool bad_redir_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
/*
|
||||
* We really shouldn't be here, and this is likely the result
|
||||
* of a misconfigured trap, as this register should target the
|
||||
* corresponding EL1, and nothing else.
|
||||
*/
|
||||
return bad_trap(vcpu, p, r,
|
||||
"trap of EL2 register redirected to EL1");
|
||||
}
|
||||
|
||||
#define EL2_REG(name, acc, rst, v) { \
|
||||
SYS_DESC(SYS_##name), \
|
||||
.access = acc, \
|
||||
@@ -1894,6 +2044,9 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
|
||||
.val = v, \
|
||||
}
|
||||
|
||||
#define EL2_REG_VNCR(name, rst, v) EL2_REG(name, bad_vncr_trap, rst, v)
|
||||
#define EL2_REG_REDIR(name, rst, v) EL2_REG(name, bad_redir_trap, rst, v)
|
||||
|
||||
/*
|
||||
* EL{0,1}2 registers are the EL2 view on an EL0 or EL1 register when
|
||||
* HCR_EL2.E2H==1, and only in the sysreg table for convenience of
|
||||
@@ -2508,32 +2661,33 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ PMU_SYS_REG(PMCCFILTR_EL0), .access = access_pmu_evtyper,
|
||||
.reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 },
|
||||
|
||||
EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0),
|
||||
EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0),
|
||||
EL2_REG_VNCR(VPIDR_EL2, reset_unknown, 0),
|
||||
EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0),
|
||||
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
|
||||
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HCR_EL2, reset_val, 0),
|
||||
EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
|
||||
EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGRTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGWTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HFGITR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HACR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGWTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HFGITR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HACR_EL2, reset_val, 0),
|
||||
|
||||
EL2_REG(HCRX_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
|
||||
|
||||
EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),
|
||||
EL2_REG(VTTBR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(VTCR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(VTTBR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(VTCR_EL2, reset_val, 0),
|
||||
|
||||
{ SYS_DESC(SYS_DACR32_EL2), trap_undef, reset_unknown, DACR32_EL2 },
|
||||
EL2_REG(HDFGRTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(HDFGWTR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(SPSR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(ELR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_REDIR(SPSR_EL2, reset_val, 0),
|
||||
EL2_REG_REDIR(ELR_EL2, reset_val, 0),
|
||||
{ SYS_DESC(SYS_SP_EL1), access_sp_el1},
|
||||
|
||||
/* AArch32 SPSR_* are RES0 if trapped from a NV guest */
|
||||
@@ -2549,10 +2703,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 },
|
||||
EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(AFSR1_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(ESR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_REDIR(ESR_EL2, reset_val, 0),
|
||||
{ SYS_DESC(SYS_FPEXC32_EL2), trap_undef, reset_val, FPEXC32_EL2, 0x700 },
|
||||
|
||||
EL2_REG(FAR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_REDIR(FAR_EL2, reset_val, 0),
|
||||
EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(MAIR_EL2, access_rw, reset_val, 0),
|
||||
@@ -2565,24 +2719,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG_VNCR(CNTVOFF_EL2, reset_val, 0),
|
||||
EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL12_REG(SCTLR, access_vm_reg, reset_val, 0x00C50078),
|
||||
EL12_REG(CPACR, access_rw, reset_val, 0),
|
||||
EL12_REG(TTBR0, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(TTBR1, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(TCR, access_vm_reg, reset_val, 0),
|
||||
{ SYS_DESC(SYS_SPSR_EL12), access_spsr},
|
||||
{ SYS_DESC(SYS_ELR_EL12), access_elr},
|
||||
EL12_REG(AFSR0, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(AFSR1, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(ESR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(FAR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(MAIR, access_vm_reg, reset_unknown, 0),
|
||||
EL12_REG(AMAIR, access_vm_reg, reset_amair_el1, 0),
|
||||
EL12_REG(VBAR, access_rw, reset_val, 0),
|
||||
EL12_REG(CONTEXTIDR, access_vm_reg, reset_val, 0),
|
||||
EL12_REG(CNTKCTL, access_rw, reset_val, 0),
|
||||
|
||||
EL2_REG(SP_EL2, NULL, reset_unknown, 0),
|
||||
|
||||
@@ -590,7 +590,11 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
|
||||
|
||||
irq = __vgic_its_check_cache(dist, db, devid, eventid);
|
||||
if (irq)
|
||||
vgic_get_irq_kref(irq);
|
||||
|
||||
raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
|
||||
|
||||
return irq;
|
||||
@@ -769,6 +773,7 @@ int vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi)
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
irq->pending_latch = true;
|
||||
vgic_queue_irq_unlock(kvm, irq, flags);
|
||||
vgic_put_irq(kvm, irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -357,31 +357,13 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < len * 8; i++) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
ret = vgic_uaccess_write_spending(vcpu, addr, len, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
if (test_bit(i, &val)) {
|
||||
/*
|
||||
* pending_latch is set irrespective of irq type
|
||||
* (level or edge) to avoid dependency that VM should
|
||||
* restore irq config before pending info.
|
||||
*/
|
||||
irq->pending_latch = true;
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
} else {
|
||||
irq->pending_latch = false;
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
}
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return vgic_uaccess_write_cpending(vcpu, addr, len, ~val);
|
||||
}
|
||||
|
||||
/* We want to avoid outer shareable. */
|
||||
|
||||
@@ -301,9 +301,8 @@ static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
|
||||
vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||
}
|
||||
|
||||
void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
static void __set_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
|
||||
unsigned long val, bool is_user)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
@@ -312,14 +311,22 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
/* GICD_ISPENDR0 SGI bits are WI */
|
||||
if (is_vgic_v2_sgi(vcpu, irq)) {
|
||||
/* GICD_ISPENDR0 SGI bits are WI when written from the guest. */
|
||||
if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
|
||||
/*
|
||||
* GICv2 SGIs are terribly broken. We can't restore
|
||||
* the source of the interrupt, so just pick the vcpu
|
||||
* itself as the source...
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source |= BIT(vcpu->vcpu_id);
|
||||
|
||||
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
|
||||
/* HW SGI? Ask the GIC to inject it */
|
||||
int err;
|
||||
@@ -335,7 +342,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
|
||||
irq->pending_latch = true;
|
||||
if (irq->hw)
|
||||
if (irq->hw && !is_user)
|
||||
vgic_irq_set_phys_active(irq, true);
|
||||
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
@@ -343,33 +350,18 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__set_pending(vcpu, addr, len, val, false);
|
||||
}
|
||||
|
||||
int vgic_uaccess_write_spending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
irq->pending_latch = true;
|
||||
|
||||
/*
|
||||
* GICv2 SGIs are terribly broken. We can't restore
|
||||
* the source of the interrupt, so just pick the vcpu
|
||||
* itself as the source...
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source |= BIT(vcpu->vcpu_id);
|
||||
|
||||
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
__set_pending(vcpu, addr, len, val, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -394,9 +386,9 @@ static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
|
||||
vgic_irq_set_phys_active(irq, false);
|
||||
}
|
||||
|
||||
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
static void __clear_pending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val, bool is_user)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
@@ -405,14 +397,22 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
/* GICD_ICPENDR0 SGI bits are WI */
|
||||
if (is_vgic_v2_sgi(vcpu, irq)) {
|
||||
/* GICD_ICPENDR0 SGI bits are WI when written from the guest. */
|
||||
if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
continue;
|
||||
}
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
|
||||
/*
|
||||
* More fun with GICv2 SGIs! If we're clearing one of them
|
||||
* from userspace, which source vcpu to clear? Let's not
|
||||
* even think of it, and blow the whole set.
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source = 0;
|
||||
|
||||
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
|
||||
/* HW SGI? Ask the GIC to clear its pending bit */
|
||||
int err;
|
||||
@@ -427,7 +427,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (irq->hw)
|
||||
if (irq->hw && !is_user)
|
||||
vgic_hw_irq_cpending(vcpu, irq);
|
||||
else
|
||||
irq->pending_latch = false;
|
||||
@@ -437,33 +437,18 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
}
|
||||
}
|
||||
|
||||
void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
__clear_pending(vcpu, addr, len, val, false);
|
||||
}
|
||||
|
||||
int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu,
|
||||
gpa_t addr, unsigned int len,
|
||||
unsigned long val)
|
||||
{
|
||||
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
for_each_set_bit(i, &val, len * 8) {
|
||||
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
|
||||
|
||||
raw_spin_lock_irqsave(&irq->irq_lock, flags);
|
||||
/*
|
||||
* More fun with GICv2 SGIs! If we're clearing one of them
|
||||
* from userspace, which source vcpu to clear? Let's not
|
||||
* even think of it, and blow the whole set.
|
||||
*/
|
||||
if (is_vgic_v2_sgi(vcpu, irq))
|
||||
irq->source = 0;
|
||||
|
||||
irq->pending_latch = false;
|
||||
|
||||
raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
|
||||
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
__clear_pending(vcpu, addr, len, val, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,10 @@ struct kvm_vcpu_stat {
|
||||
u64 signal_exits;
|
||||
};
|
||||
|
||||
#define KVM_MEM_HUGEPAGE_CAPABLE (1UL << 0)
|
||||
#define KVM_MEM_HUGEPAGE_INCAPABLE (1UL << 1)
|
||||
struct kvm_arch_memory_slot {
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct kvm_context {
|
||||
@@ -92,8 +95,10 @@ enum emulation_result {
|
||||
};
|
||||
|
||||
#define KVM_LARCH_FPU (0x1 << 0)
|
||||
#define KVM_LARCH_SWCSR_LATEST (0x1 << 1)
|
||||
#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
|
||||
#define KVM_LARCH_LSX (0x1 << 1)
|
||||
#define KVM_LARCH_LASX (0x1 << 2)
|
||||
#define KVM_LARCH_SWCSR_LATEST (0x1 << 3)
|
||||
#define KVM_LARCH_HWCSR_USABLE (0x1 << 4)
|
||||
|
||||
struct kvm_vcpu_arch {
|
||||
/*
|
||||
@@ -175,6 +180,21 @@ static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned
|
||||
csr->csrs[reg] = val;
|
||||
}
|
||||
|
||||
static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
|
||||
{
|
||||
return arch->cpucfg[2] & CPUCFG2_FP;
|
||||
}
|
||||
|
||||
static inline bool kvm_guest_has_lsx(struct kvm_vcpu_arch *arch)
|
||||
{
|
||||
return arch->cpucfg[2] & CPUCFG2_LSX;
|
||||
}
|
||||
|
||||
static inline bool kvm_guest_has_lasx(struct kvm_vcpu_arch *arch)
|
||||
{
|
||||
return arch->cpucfg[2] & CPUCFG2_LASX;
|
||||
}
|
||||
|
||||
/* Debug: dump vcpu state */
|
||||
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -183,7 +203,6 @@ void kvm_flush_tlb_all(void);
|
||||
void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
|
||||
int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
|
||||
|
||||
#define KVM_ARCH_WANT_MMU_NOTIFIER
|
||||
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
|
||||
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, bool blockable);
|
||||
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
|
||||
|
||||
@@ -55,7 +55,26 @@ void kvm_save_fpu(struct loongarch_fpu *fpu);
|
||||
void kvm_restore_fpu(struct loongarch_fpu *fpu);
|
||||
void kvm_restore_fcsr(struct loongarch_fpu *fpu);
|
||||
|
||||
void kvm_acquire_timer(struct kvm_vcpu *vcpu);
|
||||
#ifdef CONFIG_CPU_HAS_LSX
|
||||
int kvm_own_lsx(struct kvm_vcpu *vcpu);
|
||||
void kvm_save_lsx(struct loongarch_fpu *fpu);
|
||||
void kvm_restore_lsx(struct loongarch_fpu *fpu);
|
||||
#else
|
||||
static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { }
|
||||
static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { }
|
||||
static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_LASX
|
||||
int kvm_own_lasx(struct kvm_vcpu *vcpu);
|
||||
void kvm_save_lasx(struct loongarch_fpu *fpu);
|
||||
void kvm_restore_lasx(struct loongarch_fpu *fpu);
|
||||
#else
|
||||
static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { }
|
||||
static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { }
|
||||
static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { }
|
||||
#endif
|
||||
|
||||
void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
|
||||
void kvm_reset_timer(struct kvm_vcpu *vcpu);
|
||||
void kvm_save_timer(struct kvm_vcpu *vcpu);
|
||||
|
||||
@@ -79,6 +79,7 @@ struct kvm_fpu {
|
||||
#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
|
||||
#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
|
||||
#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
|
||||
#define KVM_LOONGARCH_VCPU_CPUCFG 0
|
||||
|
||||
struct kvm_debug_exit_arch {
|
||||
};
|
||||
|
||||
@@ -349,6 +349,7 @@ SYM_FUNC_START(_restore_lsx_upper)
|
||||
lsx_restore_all_upper a0 t0 t1
|
||||
jr ra
|
||||
SYM_FUNC_END(_restore_lsx_upper)
|
||||
EXPORT_SYMBOL(_restore_lsx_upper)
|
||||
|
||||
SYM_FUNC_START(_init_lsx_upper)
|
||||
lsx_init_all_upper t1
|
||||
@@ -384,6 +385,7 @@ SYM_FUNC_START(_restore_lasx_upper)
|
||||
lasx_restore_all_upper a0 t0 t1
|
||||
jr ra
|
||||
SYM_FUNC_END(_restore_lasx_upper)
|
||||
EXPORT_SYMBOL(_restore_lasx_upper)
|
||||
|
||||
SYM_FUNC_START(_init_lasx_upper)
|
||||
lasx_init_all_upper t1
|
||||
|
||||
@@ -22,14 +22,13 @@ config KVM
|
||||
depends on AS_HAS_LVZ_EXTENSION
|
||||
depends on HAVE_KVM
|
||||
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
select HAVE_KVM_EVENTFD
|
||||
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||
select KVM_COMMON
|
||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||
select KVM_GENERIC_HARDWARE_ENABLING
|
||||
select KVM_GENERIC_MMU_NOTIFIER
|
||||
select KVM_MMIO
|
||||
select KVM_XFER_TO_GUEST_WORK
|
||||
select MMU_NOTIFIER
|
||||
select PREEMPT_NOTIFIERS
|
||||
help
|
||||
Support hosting virtualized guest machines using
|
||||
hardware virtualization extensions. You will need
|
||||
|
||||
+39
-11
@@ -200,17 +200,8 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu)
|
||||
++vcpu->stat.idle_exits;
|
||||
trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE);
|
||||
|
||||
if (!kvm_arch_vcpu_runnable(vcpu)) {
|
||||
/*
|
||||
* Switch to the software timer before halt-polling/blocking as
|
||||
* the guest's timer may be a break event for the vCPU, and the
|
||||
* hypervisor timer runs only when the CPU is in guest mode.
|
||||
* Switch before halt-polling so that KVM recognizes an expired
|
||||
* timer before blocking.
|
||||
*/
|
||||
kvm_save_timer(vcpu);
|
||||
kvm_vcpu_block(vcpu);
|
||||
}
|
||||
if (!kvm_arch_vcpu_runnable(vcpu))
|
||||
kvm_vcpu_halt(vcpu);
|
||||
|
||||
return EMULATE_DONE;
|
||||
}
|
||||
@@ -643,6 +634,11 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_run *run = vcpu->run;
|
||||
|
||||
if (!kvm_guest_has_fpu(&vcpu->arch)) {
|
||||
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
||||
/*
|
||||
* If guest FPU not present, the FPU operation should have been
|
||||
* treated as a reserved instruction!
|
||||
@@ -659,6 +655,36 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
||||
/*
|
||||
* kvm_handle_lsx_disabled() - Guest used LSX while disabled in root.
|
||||
* @vcpu: Virtual CPU context.
|
||||
*
|
||||
* Handle when the guest attempts to use LSX when it is disabled in the root
|
||||
* context.
|
||||
*/
|
||||
static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_own_lsx(vcpu))
|
||||
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
|
||||
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
||||
/*
|
||||
* kvm_handle_lasx_disabled() - Guest used LASX while disabled in root.
|
||||
* @vcpu: Virtual CPU context.
|
||||
*
|
||||
* Handle when the guest attempts to use LASX when it is disabled in the root
|
||||
* context.
|
||||
*/
|
||||
static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_own_lasx(vcpu))
|
||||
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
|
||||
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
|
||||
/*
|
||||
* LoongArch KVM callback handling for unimplemented guest exiting
|
||||
*/
|
||||
@@ -687,6 +713,8 @@ static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = {
|
||||
[EXCCODE_TLBS] = kvm_handle_write_fault,
|
||||
[EXCCODE_TLBM] = kvm_handle_write_fault,
|
||||
[EXCCODE_FPDIS] = kvm_handle_fpu_disabled,
|
||||
[EXCCODE_LSXDIS] = kvm_handle_lsx_disabled,
|
||||
[EXCCODE_LASXDIS] = kvm_handle_lasx_disabled,
|
||||
[EXCCODE_GSPR] = kvm_handle_gspr,
|
||||
};
|
||||
|
||||
|
||||
@@ -287,7 +287,6 @@ int kvm_arch_hardware_enable(void)
|
||||
if (env & CSR_GCFG_MATC_ROOT)
|
||||
gcfg |= CSR_GCFG_MATC_ROOT;
|
||||
|
||||
gcfg |= CSR_GCFG_TIT;
|
||||
write_csr_gcfg(gcfg);
|
||||
|
||||
kvm_flush_tlb_all();
|
||||
|
||||
+83
-41
@@ -13,6 +13,16 @@
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
|
||||
static inline bool kvm_hugepage_capable(struct kvm_memory_slot *slot)
|
||||
{
|
||||
return slot->arch.flags & KVM_MEM_HUGEPAGE_CAPABLE;
|
||||
}
|
||||
|
||||
static inline bool kvm_hugepage_incapable(struct kvm_memory_slot *slot)
|
||||
{
|
||||
return slot->arch.flags & KVM_MEM_HUGEPAGE_INCAPABLE;
|
||||
}
|
||||
|
||||
static inline void kvm_ptw_prepare(struct kvm *kvm, kvm_ptw_ctx *ctx)
|
||||
{
|
||||
ctx->level = kvm->arch.root_level;
|
||||
@@ -365,6 +375,69 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
|
||||
kvm_ptw_top(kvm->arch.pgd, start << PAGE_SHIFT, end << PAGE_SHIFT, &ctx);
|
||||
}
|
||||
|
||||
int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old,
|
||||
struct kvm_memory_slot *new, enum kvm_mr_change change)
|
||||
{
|
||||
gpa_t gpa_start;
|
||||
hva_t hva_start;
|
||||
size_t size, gpa_offset, hva_offset;
|
||||
|
||||
if ((change != KVM_MR_MOVE) && (change != KVM_MR_CREATE))
|
||||
return 0;
|
||||
/*
|
||||
* Prevent userspace from creating a memory region outside of the
|
||||
* VM GPA address space
|
||||
*/
|
||||
if ((new->base_gfn + new->npages) > (kvm->arch.gpa_size >> PAGE_SHIFT))
|
||||
return -ENOMEM;
|
||||
|
||||
new->arch.flags = 0;
|
||||
size = new->npages * PAGE_SIZE;
|
||||
gpa_start = new->base_gfn << PAGE_SHIFT;
|
||||
hva_start = new->userspace_addr;
|
||||
if (IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(gpa_start, PMD_SIZE)
|
||||
&& IS_ALIGNED(hva_start, PMD_SIZE))
|
||||
new->arch.flags |= KVM_MEM_HUGEPAGE_CAPABLE;
|
||||
else {
|
||||
/*
|
||||
* Pages belonging to memslots that don't have the same
|
||||
* alignment within a PMD for userspace and GPA cannot be
|
||||
* mapped with PMD entries, because we'll end up mapping
|
||||
* the wrong pages.
|
||||
*
|
||||
* Consider a layout like the following:
|
||||
*
|
||||
* memslot->userspace_addr:
|
||||
* +-----+--------------------+--------------------+---+
|
||||
* |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
|
||||
* +-----+--------------------+--------------------+---+
|
||||
*
|
||||
* memslot->base_gfn << PAGE_SIZE:
|
||||
* +---+--------------------+--------------------+-----+
|
||||
* |abc|def Stage-2 block | Stage-2 block |tvxyz|
|
||||
* +---+--------------------+--------------------+-----+
|
||||
*
|
||||
* If we create those stage-2 blocks, we'll end up with this
|
||||
* incorrect mapping:
|
||||
* d -> f
|
||||
* e -> g
|
||||
* f -> h
|
||||
*/
|
||||
gpa_offset = gpa_start & (PMD_SIZE - 1);
|
||||
hva_offset = hva_start & (PMD_SIZE - 1);
|
||||
if (gpa_offset != hva_offset) {
|
||||
new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE;
|
||||
} else {
|
||||
if (gpa_offset == 0)
|
||||
gpa_offset = PMD_SIZE;
|
||||
if ((size + gpa_offset) < (PMD_SIZE * 2))
|
||||
new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *old,
|
||||
const struct kvm_memory_slot *new,
|
||||
@@ -562,47 +635,23 @@ out:
|
||||
}
|
||||
|
||||
static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
|
||||
unsigned long hva, unsigned long map_size, bool write)
|
||||
unsigned long hva, bool write)
|
||||
{
|
||||
size_t size;
|
||||
gpa_t gpa_start;
|
||||
hva_t uaddr_start, uaddr_end;
|
||||
hva_t start, end;
|
||||
|
||||
/* Disable dirty logging on HugePages */
|
||||
if (kvm_slot_dirty_track_enabled(memslot) && write)
|
||||
return false;
|
||||
|
||||
size = memslot->npages * PAGE_SIZE;
|
||||
gpa_start = memslot->base_gfn << PAGE_SHIFT;
|
||||
uaddr_start = memslot->userspace_addr;
|
||||
uaddr_end = uaddr_start + size;
|
||||
if (kvm_hugepage_capable(memslot))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Pages belonging to memslots that don't have the same alignment
|
||||
* within a PMD for userspace and GPA cannot be mapped with stage-2
|
||||
* PMD entries, because we'll end up mapping the wrong pages.
|
||||
*
|
||||
* Consider a layout like the following:
|
||||
*
|
||||
* memslot->userspace_addr:
|
||||
* +-----+--------------------+--------------------+---+
|
||||
* |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
|
||||
* +-----+--------------------+--------------------+---+
|
||||
*
|
||||
* memslot->base_gfn << PAGE_SIZE:
|
||||
* +---+--------------------+--------------------+-----+
|
||||
* |abc|def Stage-2 block | Stage-2 block |tvxyz|
|
||||
* +---+--------------------+--------------------+-----+
|
||||
*
|
||||
* If we create those stage-2 blocks, we'll end up with this incorrect
|
||||
* mapping:
|
||||
* d -> f
|
||||
* e -> g
|
||||
* f -> h
|
||||
*/
|
||||
if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
|
||||
if (kvm_hugepage_incapable(memslot))
|
||||
return false;
|
||||
|
||||
start = memslot->userspace_addr;
|
||||
end = start + memslot->npages * PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* Next, let's make sure we're not trying to map anything not covered
|
||||
* by the memslot. This means we have to prohibit block size mappings
|
||||
@@ -615,8 +664,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
|
||||
* userspace_addr or the base_gfn, as both are equally aligned (per
|
||||
* the check above) and equally sized.
|
||||
*/
|
||||
return (hva & ~(map_size - 1)) >= uaddr_start &&
|
||||
(hva & ~(map_size - 1)) + map_size <= uaddr_end;
|
||||
return (hva >= ALIGN(start, PMD_SIZE)) && (hva < ALIGN_DOWN(end, PMD_SIZE));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -842,7 +890,7 @@ retry:
|
||||
|
||||
/* Disable dirty logging on HugePages */
|
||||
level = 0;
|
||||
if (!fault_supports_huge_mapping(memslot, hva, PMD_SIZE, write)) {
|
||||
if (!fault_supports_huge_mapping(memslot, hva, write)) {
|
||||
level = 0;
|
||||
} else {
|
||||
level = host_pfn_mapping_level(kvm, gfn, memslot);
|
||||
@@ -901,12 +949,6 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old,
|
||||
struct kvm_memory_slot *new, enum kvm_mr_change change)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
|
||||
const struct kvm_memory_slot *memslot)
|
||||
{
|
||||
|
||||
@@ -245,6 +245,37 @@ SYM_FUNC_START(kvm_restore_fpu)
|
||||
jr ra
|
||||
SYM_FUNC_END(kvm_restore_fpu)
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_LSX
|
||||
SYM_FUNC_START(kvm_save_lsx)
|
||||
fpu_save_csr a0 t1
|
||||
fpu_save_cc a0 t1 t2
|
||||
lsx_save_data a0 t1
|
||||
jr ra
|
||||
SYM_FUNC_END(kvm_save_lsx)
|
||||
|
||||
SYM_FUNC_START(kvm_restore_lsx)
|
||||
lsx_restore_data a0 t1
|
||||
fpu_restore_cc a0 t1 t2
|
||||
fpu_restore_csr a0 t1 t2
|
||||
jr ra
|
||||
SYM_FUNC_END(kvm_restore_lsx)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_LASX
|
||||
SYM_FUNC_START(kvm_save_lasx)
|
||||
fpu_save_csr a0 t1
|
||||
fpu_save_cc a0 t1 t2
|
||||
lasx_save_data a0 t1
|
||||
jr ra
|
||||
SYM_FUNC_END(kvm_save_lasx)
|
||||
|
||||
SYM_FUNC_START(kvm_restore_lasx)
|
||||
lasx_restore_data a0 t1
|
||||
fpu_restore_cc a0 t1 t2
|
||||
fpu_restore_csr a0 t1 t2
|
||||
jr ra
|
||||
SYM_FUNC_END(kvm_restore_lasx)
|
||||
#endif
|
||||
.section ".rodata"
|
||||
SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
|
||||
SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
|
||||
|
||||
+75
-52
@@ -64,41 +64,24 @@ void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long timer_hz)
|
||||
kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TVAL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore hard timer state and enable guest to access timer registers
|
||||
* without trap, should be called with irq disabled
|
||||
*/
|
||||
void kvm_acquire_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cfg;
|
||||
|
||||
cfg = read_csr_gcfg();
|
||||
if (!(cfg & CSR_GCFG_TIT))
|
||||
return;
|
||||
|
||||
/* Enable guest access to hard timer */
|
||||
write_csr_gcfg(cfg & ~CSR_GCFG_TIT);
|
||||
|
||||
/*
|
||||
* Freeze the soft-timer and sync the guest stable timer with it. We do
|
||||
* this with interrupts disabled to avoid latency.
|
||||
*/
|
||||
hrtimer_cancel(&vcpu->arch.swtimer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore soft timer state from saved context.
|
||||
*/
|
||||
void kvm_restore_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cfg, delta, period;
|
||||
unsigned long cfg, estat;
|
||||
unsigned long ticks, delta, period;
|
||||
ktime_t expire, now;
|
||||
struct loongarch_csrs *csr = vcpu->arch.csr;
|
||||
|
||||
/*
|
||||
* Set guest stable timer cfg csr
|
||||
* Disable timer before restore estat CSR register, avoid to
|
||||
* get invalid timer interrupt for old timer cfg
|
||||
*/
|
||||
cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
|
||||
|
||||
write_gcsr_timercfg(0);
|
||||
kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
|
||||
kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
|
||||
if (!(cfg & CSR_TCFG_EN)) {
|
||||
@@ -107,24 +90,56 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Freeze the soft-timer and sync the guest stable timer with it.
|
||||
*/
|
||||
hrtimer_cancel(&vcpu->arch.swtimer);
|
||||
|
||||
/*
|
||||
* From LoongArch Reference Manual Volume 1 Chapter 7.6.2
|
||||
* If oneshot timer is fired, CSR TVAL will be -1, there are two
|
||||
* conditions:
|
||||
* 1) timer is fired during exiting to host
|
||||
* 2) timer is fired and vm is doing timer irq, and then exiting to
|
||||
* host. Host should not inject timer irq to avoid spurious
|
||||
* timer interrupt again
|
||||
*/
|
||||
ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
|
||||
estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT);
|
||||
if (!(cfg & CSR_TCFG_PERIOD) && (ticks > cfg)) {
|
||||
/*
|
||||
* Writing 0 to LOONGARCH_CSR_TVAL will inject timer irq
|
||||
* and set CSR TVAL with -1
|
||||
*/
|
||||
write_gcsr_timertick(0);
|
||||
|
||||
/*
|
||||
* Writing CSR_TINTCLR_TI to LOONGARCH_CSR_TINTCLR will clear
|
||||
* timer interrupt, and CSR TVAL keeps unchanged with -1, it
|
||||
* avoids spurious timer interrupt
|
||||
*/
|
||||
if (!(estat & CPU_TIMER))
|
||||
gcsr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set remainder tick value if not expired
|
||||
*/
|
||||
delta = 0;
|
||||
now = ktime_get();
|
||||
expire = vcpu->arch.expire;
|
||||
if (ktime_before(now, expire))
|
||||
delta = ktime_to_tick(vcpu, ktime_sub(expire, now));
|
||||
else {
|
||||
if (cfg & CSR_TCFG_PERIOD) {
|
||||
period = cfg & CSR_TCFG_VAL;
|
||||
delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
|
||||
delta = period - (delta % period);
|
||||
} else
|
||||
delta = 0;
|
||||
else if (cfg & CSR_TCFG_PERIOD) {
|
||||
period = cfg & CSR_TCFG_VAL;
|
||||
delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
|
||||
delta = period - (delta % period);
|
||||
|
||||
/*
|
||||
* Inject timer here though sw timer should inject timer
|
||||
* interrupt async already, since sw timer may be cancelled
|
||||
* during injecting intr async in function kvm_acquire_timer
|
||||
* during injecting intr async
|
||||
*/
|
||||
kvm_queue_irq(vcpu, INT_TI);
|
||||
}
|
||||
@@ -139,27 +154,41 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
static void _kvm_save_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long ticks, delta;
|
||||
unsigned long ticks, delta, cfg;
|
||||
ktime_t expire;
|
||||
struct loongarch_csrs *csr = vcpu->arch.csr;
|
||||
|
||||
cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
|
||||
ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
|
||||
delta = tick_to_ns(vcpu, ticks);
|
||||
expire = ktime_add_ns(ktime_get(), delta);
|
||||
vcpu->arch.expire = expire;
|
||||
if (ticks) {
|
||||
|
||||
/*
|
||||
* From LoongArch Reference Manual Volume 1 Chapter 7.6.2
|
||||
* If period timer is fired, CSR TVAL will be reloaded from CSR TCFG
|
||||
* If oneshot timer is fired, CSR TVAL will be -1
|
||||
* Here judge one-shot timer fired by checking whether TVAL is larger
|
||||
* than TCFG
|
||||
*/
|
||||
if (ticks < cfg) {
|
||||
delta = tick_to_ns(vcpu, ticks);
|
||||
expire = ktime_add_ns(ktime_get(), delta);
|
||||
vcpu->arch.expire = expire;
|
||||
|
||||
/*
|
||||
* Update hrtimer to use new timeout
|
||||
* HRTIMER_MODE_PINNED is suggested since vcpu may run in
|
||||
* the same physical cpu in next time
|
||||
*/
|
||||
hrtimer_cancel(&vcpu->arch.swtimer);
|
||||
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
|
||||
} else
|
||||
} else if (vcpu->stat.generic.blocking) {
|
||||
/*
|
||||
* Inject timer interrupt so that hall polling can dectect and exit
|
||||
* Inject timer interrupt so that halt polling can dectect and exit.
|
||||
* VCPU is scheduled out already and sleeps in rcuwait queue and
|
||||
* will not poll pending events again. kvm_queue_irq() is not enough,
|
||||
* hrtimer swtimer should be used here.
|
||||
*/
|
||||
kvm_queue_irq(vcpu, INT_TI);
|
||||
expire = ktime_add_ns(ktime_get(), 10);
|
||||
vcpu->arch.expire = expire;
|
||||
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -168,21 +197,15 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
void kvm_save_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
unsigned long cfg;
|
||||
struct loongarch_csrs *csr = vcpu->arch.csr;
|
||||
|
||||
preempt_disable();
|
||||
cfg = read_csr_gcfg();
|
||||
if (!(cfg & CSR_GCFG_TIT)) {
|
||||
/* Disable guest use of hard timer */
|
||||
write_csr_gcfg(cfg | CSR_GCFG_TIT);
|
||||
|
||||
/* Save hard timer state */
|
||||
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
|
||||
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
|
||||
if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
|
||||
_kvm_save_timer(vcpu);
|
||||
}
|
||||
/* Save hard timer state */
|
||||
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
|
||||
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
|
||||
if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
|
||||
_kvm_save_timer(vcpu);
|
||||
|
||||
/* Save timer-related state to vCPU context */
|
||||
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
|
||||
|
||||
@@ -102,6 +102,8 @@ TRACE_EVENT(kvm_exit_gspr,
|
||||
#define KVM_TRACE_AUX_DISCARD 4
|
||||
|
||||
#define KVM_TRACE_AUX_FPU 1
|
||||
#define KVM_TRACE_AUX_LSX 2
|
||||
#define KVM_TRACE_AUX_LASX 3
|
||||
|
||||
#define kvm_trace_symbol_aux_op \
|
||||
{ KVM_TRACE_AUX_SAVE, "save" }, \
|
||||
@@ -111,7 +113,9 @@ TRACE_EVENT(kvm_exit_gspr,
|
||||
{ KVM_TRACE_AUX_DISCARD, "discard" }
|
||||
|
||||
#define kvm_trace_symbol_aux_state \
|
||||
{ KVM_TRACE_AUX_FPU, "FPU" }
|
||||
{ KVM_TRACE_AUX_FPU, "FPU" }, \
|
||||
{ KVM_TRACE_AUX_LSX, "LSX" }, \
|
||||
{ KVM_TRACE_AUX_LASX, "LASX" }
|
||||
|
||||
TRACE_EVENT(kvm_aux,
|
||||
TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
|
||||
|
||||
+272
-35
@@ -95,7 +95,6 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
|
||||
* check vmid before vcpu enter guest
|
||||
*/
|
||||
local_irq_disable();
|
||||
kvm_acquire_timer(vcpu);
|
||||
kvm_deliver_intr(vcpu);
|
||||
kvm_deliver_exception(vcpu);
|
||||
/* Make sure the vcpu mode has been written */
|
||||
@@ -187,8 +186,15 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
|
||||
|
||||
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return kvm_pending_timer(vcpu) ||
|
||||
int ret;
|
||||
|
||||
/* Protect from TOD sync and vcpu_load/put() */
|
||||
preempt_disable();
|
||||
ret = kvm_pending_timer(vcpu) ||
|
||||
kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) & (1 << INT_TI);
|
||||
preempt_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
|
||||
@@ -244,23 +250,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_migrate_count() - Migrate timer.
|
||||
* @vcpu: Virtual CPU.
|
||||
*
|
||||
* Migrate hrtimer to the current CPU by cancelling and restarting it
|
||||
* if the hrtimer is active.
|
||||
*
|
||||
* Must be called when the vCPU is migrated to a different CPU, so that
|
||||
* the timer can interrupt the guest at the new CPU, and the timer irq can
|
||||
* be delivered to the vCPU.
|
||||
*/
|
||||
static void kvm_migrate_count(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (hrtimer_cancel(&vcpu->arch.swtimer))
|
||||
hrtimer_restart(&vcpu->arch.swtimer);
|
||||
}
|
||||
|
||||
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
|
||||
{
|
||||
unsigned long gintc;
|
||||
@@ -309,6 +298,76 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _kvm_get_cpucfg(int id, u64 *v)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
|
||||
return -EINVAL;
|
||||
|
||||
switch (id) {
|
||||
case 2:
|
||||
/* Return CPUCFG2 features which have been supported by KVM */
|
||||
*v = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP |
|
||||
CPUCFG2_FPVERS | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV |
|
||||
CPUCFG2_LAM;
|
||||
/*
|
||||
* If LSX is supported by CPU, it is also supported by KVM,
|
||||
* as we implement it.
|
||||
*/
|
||||
if (cpu_has_lsx)
|
||||
*v |= CPUCFG2_LSX;
|
||||
/*
|
||||
* if LASX is supported by CPU, it is also supported by KVM,
|
||||
* as we implement it.
|
||||
*/
|
||||
if (cpu_has_lasx)
|
||||
*v |= CPUCFG2_LASX;
|
||||
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_check_cpucfg(int id, u64 val)
|
||||
{
|
||||
u64 mask;
|
||||
int ret = 0;
|
||||
|
||||
if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
|
||||
return -EINVAL;
|
||||
|
||||
if (_kvm_get_cpucfg(id, &mask))
|
||||
return ret;
|
||||
|
||||
switch (id) {
|
||||
case 2:
|
||||
/* CPUCFG2 features checking */
|
||||
if (val & ~mask)
|
||||
/* The unsupported features should not be set */
|
||||
ret = -EINVAL;
|
||||
else if (!(val & CPUCFG2_LLFTP))
|
||||
/* The LLFTP must be set, as guest must has a constant timer */
|
||||
ret = -EINVAL;
|
||||
else if ((val & CPUCFG2_FP) && (!(val & CPUCFG2_FPSP) || !(val & CPUCFG2_FPDP)))
|
||||
/* Single and double float point must both be set when enable FP */
|
||||
ret = -EINVAL;
|
||||
else if ((val & CPUCFG2_LSX) && !(val & CPUCFG2_FP))
|
||||
/* FP should be set when enable LSX */
|
||||
ret = -EINVAL;
|
||||
else if ((val & CPUCFG2_LASX) && !(val & CPUCFG2_LSX))
|
||||
/* LSX, FP should be set when enable LASX, and FP has been checked before. */
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
|
||||
const struct kvm_one_reg *reg, u64 *v)
|
||||
{
|
||||
@@ -378,10 +437,10 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
|
||||
break;
|
||||
case KVM_REG_LOONGARCH_CPUCFG:
|
||||
id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
|
||||
if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
|
||||
vcpu->arch.cpucfg[id] = (u32)v;
|
||||
else
|
||||
ret = -EINVAL;
|
||||
ret = kvm_check_cpucfg(id, v);
|
||||
if (ret)
|
||||
break;
|
||||
vcpu->arch.cpucfg[id] = (u32)v;
|
||||
break;
|
||||
case KVM_REG_LOONGARCH_KVM:
|
||||
switch (reg->id) {
|
||||
@@ -471,10 +530,94 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->attr) {
|
||||
case 2:
|
||||
return 0;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret = -ENXIO;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_LOONGARCH_VCPU_CPUCFG:
|
||||
ret = kvm_loongarch_cpucfg_has_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t val;
|
||||
uint64_t __user *uaddr = (uint64_t __user *)attr->addr;
|
||||
|
||||
ret = _kvm_get_cpucfg(attr->attr, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
put_user(val, uaddr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret = -ENXIO;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_LOONGARCH_VCPU_CPUCFG:
|
||||
ret = kvm_loongarch_get_cpucfg_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
int ret = -ENXIO;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_LOONGARCH_VCPU_CPUCFG:
|
||||
ret = kvm_loongarch_cpucfg_set_attr(vcpu, attr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
unsigned int ioctl, unsigned long arg)
|
||||
{
|
||||
long r;
|
||||
struct kvm_device_attr attr;
|
||||
void __user *argp = (void __user *)arg;
|
||||
struct kvm_vcpu *vcpu = filp->private_data;
|
||||
|
||||
@@ -514,6 +657,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
|
||||
break;
|
||||
}
|
||||
case KVM_HAS_DEVICE_ATTR: {
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&attr, argp, sizeof(attr)))
|
||||
break;
|
||||
r = kvm_loongarch_vcpu_has_attr(vcpu, &attr);
|
||||
break;
|
||||
}
|
||||
case KVM_GET_DEVICE_ATTR: {
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&attr, argp, sizeof(attr)))
|
||||
break;
|
||||
r = kvm_loongarch_vcpu_get_attr(vcpu, &attr);
|
||||
break;
|
||||
}
|
||||
case KVM_SET_DEVICE_ATTR: {
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&attr, argp, sizeof(attr)))
|
||||
break;
|
||||
r = kvm_loongarch_vcpu_set_attr(vcpu, &attr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r = -ENOIOCTLCMD;
|
||||
break;
|
||||
@@ -561,12 +725,96 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu)
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_LSX
|
||||
/* Enable LSX and restore context */
|
||||
int kvm_own_lsx(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch))
|
||||
return -EINVAL;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
/* Enable LSX for guest */
|
||||
set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN);
|
||||
switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
|
||||
case KVM_LARCH_FPU:
|
||||
/*
|
||||
* Guest FPU state already loaded,
|
||||
* only restore upper LSX state
|
||||
*/
|
||||
_restore_lsx_upper(&vcpu->arch.fpu);
|
||||
break;
|
||||
default:
|
||||
/* Neither FP or LSX already active,
|
||||
* restore full LSX state
|
||||
*/
|
||||
kvm_restore_lsx(&vcpu->arch.fpu);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX);
|
||||
vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU;
|
||||
preempt_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_HAS_LASX
|
||||
/* Enable LASX and restore context */
|
||||
int kvm_own_lasx(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch) || !kvm_guest_has_lasx(&vcpu->arch))
|
||||
return -EINVAL;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
|
||||
switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) {
|
||||
case KVM_LARCH_LSX:
|
||||
case KVM_LARCH_LSX | KVM_LARCH_FPU:
|
||||
/* Guest LSX state already loaded, only restore upper LASX state */
|
||||
_restore_lasx_upper(&vcpu->arch.fpu);
|
||||
break;
|
||||
case KVM_LARCH_FPU:
|
||||
/* Guest FP state already loaded, only restore upper LSX & LASX state */
|
||||
_restore_lsx_upper(&vcpu->arch.fpu);
|
||||
_restore_lasx_upper(&vcpu->arch.fpu);
|
||||
break;
|
||||
default:
|
||||
/* Neither FP or LSX already active, restore full LASX state */
|
||||
kvm_restore_lasx(&vcpu->arch.fpu);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
|
||||
vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
|
||||
preempt_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Save context and disable FPU */
|
||||
void kvm_lose_fpu(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
preempt_disable();
|
||||
|
||||
if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
|
||||
if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) {
|
||||
kvm_save_lasx(&vcpu->arch.fpu);
|
||||
vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX);
|
||||
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LASX);
|
||||
|
||||
/* Disable LASX & LSX & FPU */
|
||||
clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
|
||||
} else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) {
|
||||
kvm_save_lsx(&vcpu->arch.fpu);
|
||||
vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU);
|
||||
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LSX);
|
||||
|
||||
/* Disable LSX & FPU */
|
||||
clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN);
|
||||
} else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
|
||||
kvm_save_fpu(&vcpu->arch.fpu);
|
||||
vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
|
||||
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
|
||||
@@ -789,17 +1037,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (vcpu->arch.last_sched_cpu != cpu) {
|
||||
kvm_debug("[%d->%d]KVM vCPU[%d] switch\n",
|
||||
vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
|
||||
/*
|
||||
* Migrate the timer interrupt to the current CPU so that it
|
||||
* always interrupts the guest and synchronously triggers a
|
||||
* guest timer interrupt.
|
||||
*/
|
||||
kvm_migrate_count(vcpu);
|
||||
}
|
||||
|
||||
/* Restore guest state to registers */
|
||||
_kvm_vcpu_load(vcpu, cpu);
|
||||
local_irq_restore(flags);
|
||||
|
||||
@@ -3,11 +3,9 @@ CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_SYSFS_DEPRECATED=y
|
||||
CONFIG_SYSFS_DEPRECATED_V2=y
|
||||
CONFIG_EXPERT=y
|
||||
# CONFIG_BASE_FULL is not set
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EXPERT=y
|
||||
CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
|
||||
CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
|
||||
CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
|
||||
@@ -20,7 +18,6 @@ CONFIG_CMDLINE_FORCE=y
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
CONFIG_PARTITION_ADVANCED=y
|
||||
# CONFIG_EFI_PARTITION is not set
|
||||
CONFIG_CMA=y
|
||||
@@ -28,6 +25,10 @@ CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_PNP=y
|
||||
CONFIG_IP_PNP_DHCP=y
|
||||
CONFIG_IP_PNP_BOOTP=y
|
||||
CONFIG_IP_PNP_RARP=y
|
||||
# CONFIG_IPV6 is not set
|
||||
CONFIG_BRIDGE=m
|
||||
CONFIG_PCI=y
|
||||
@@ -43,6 +44,7 @@ CONFIG_NETDEVICES=y
|
||||
CONFIG_XILINX_EMACLITE=y
|
||||
CONFIG_XILINX_AXI_EMAC=y
|
||||
CONFIG_XILINX_LL_TEMAC=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
# CONFIG_INPUT is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
@@ -77,14 +79,13 @@ CONFIG_TMPFS=y
|
||||
CONFIG_CRAMFS=y
|
||||
CONFIG_ROMFS_FS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_CIFS=y
|
||||
CONFIG_CIFS_STATS2=y
|
||||
CONFIG_ENCRYPTED_KEYS=y
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
CONFIG_KGDB=y
|
||||
CONFIG_KGDB_TESTS=y
|
||||
CONFIG_KGDB_KDB=y
|
||||
CONFIG_DEBUG_SLAB=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_DEBUG_SPINLOCK=y
|
||||
|
||||
@@ -847,7 +847,7 @@ int __init db1200_dev_setup(void)
|
||||
i2c_register_board_info(0, db1200_i2c_devs,
|
||||
ARRAY_SIZE(db1200_i2c_devs));
|
||||
spi_register_board_info(db1200_spi_devs,
|
||||
ARRAY_SIZE(db1200_i2c_devs));
|
||||
ARRAY_SIZE(db1200_spi_devs));
|
||||
|
||||
/* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI)
|
||||
* S6.7 AC97/I2S selector (OFF=AC97 ON=I2S)
|
||||
|
||||
@@ -589,7 +589,7 @@ int __init db1550_dev_setup(void)
|
||||
i2c_register_board_info(0, db1550_i2c_devs,
|
||||
ARRAY_SIZE(db1550_i2c_devs));
|
||||
spi_register_board_info(db1550_spi_devs,
|
||||
ARRAY_SIZE(db1550_i2c_devs));
|
||||
ARRAY_SIZE(db1550_spi_devs));
|
||||
|
||||
c = clk_get(NULL, "psc0_intclk");
|
||||
if (!IS_ERR(c)) {
|
||||
|
||||
@@ -147,21 +147,21 @@ static const struct gpio_keys_button
|
||||
bcm47xx_buttons_buffalo_whr_g125[] __initconst = {
|
||||
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
|
||||
BCM47XX_GPIO_KEY(4, KEY_RESTART),
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
|
||||
};
|
||||
|
||||
static const struct gpio_keys_button
|
||||
bcm47xx_buttons_buffalo_whr_g54s[] __initconst = {
|
||||
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
|
||||
BCM47XX_GPIO_KEY_H(4, KEY_RESTART),
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
|
||||
};
|
||||
|
||||
static const struct gpio_keys_button
|
||||
bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = {
|
||||
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
|
||||
BCM47XX_GPIO_KEY(4, KEY_RESTART),
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
|
||||
BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
|
||||
};
|
||||
|
||||
static const struct gpio_keys_button
|
||||
|
||||
@@ -174,7 +174,7 @@ static void enetsw_set(struct clk *clk, int enable)
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
/* reset switch core afer clock change */
|
||||
/* reset switch core after clock change */
|
||||
bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
|
||||
msleep(10);
|
||||
bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
|
||||
@@ -304,7 +304,7 @@ static void xtm_set(struct clk *clk, int enable)
|
||||
bcm_hwclock_set(CKCTL_6368_SAR_EN, enable);
|
||||
|
||||
if (enable) {
|
||||
/* reset sar core afer clock change */
|
||||
/* reset sar core after clock change */
|
||||
bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
|
||||
mdelay(1);
|
||||
bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* MIPS-specific debug support for pre-boot environment
|
||||
*
|
||||
* NOTE: putc() is board specific, if your board have a 16550 compatible uart,
|
||||
* please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. othewise, you
|
||||
* please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. otherwise, you
|
||||
* need to implement your own putc().
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
/* Clear BSS */
|
||||
PTR_LA a0, _edata
|
||||
PTR_LA a2, _end
|
||||
1: sw zero, 0(a0)
|
||||
addiu a0, a0, 4
|
||||
1: PTR_S zero, 0(a0)
|
||||
PTR_ADDIU a0, a0, PTRSIZE
|
||||
bne a2, a0, 1b
|
||||
|
||||
PTR_LA a0, (.heap) /* heap address */
|
||||
|
||||
@@ -443,7 +443,7 @@ int main(int argc, char *argv[])
|
||||
efh.f_symptr = 0;
|
||||
efh.f_nsyms = 0;
|
||||
efh.f_opthdr = sizeof eah;
|
||||
efh.f_flags = 0x100f; /* Stripped, not sharable. */
|
||||
efh.f_flags = 0x100f; /* Stripped, not shareable. */
|
||||
|
||||
memset(esecs, 0, sizeof esecs);
|
||||
strcpy(esecs[0].s_name, ".text");
|
||||
|
||||
@@ -113,7 +113,7 @@ static struct clocksource clocksource_mips = {
|
||||
|
||||
unsigned long long notrace sched_clock(void)
|
||||
{
|
||||
/* 64-bit arithmatic can overflow, so use 128-bit. */
|
||||
/* 64-bit arithmetic can overflow, so use 128-bit. */
|
||||
u64 t1, t2, t3;
|
||||
unsigned long long rv;
|
||||
u64 mult = clocksource_mips.mult;
|
||||
|
||||
@@ -143,7 +143,7 @@ static void cvmx_boot_vector_init(void *mem)
|
||||
uint64_t v = _cvmx_bootvector_data[i];
|
||||
|
||||
if (OCTEON_IS_OCTEON1PLUS() && (i == 0 || i == 7))
|
||||
v &= 0xffffffff00000000ull; /* KScratch not availble. */
|
||||
v &= 0xffffffff00000000ull; /* KScratch not available */
|
||||
cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
|
||||
cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, v);
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min,
|
||||
* Convert !0 address_min and 0 address_max to special case of
|
||||
* range that specifies an exact memory block to allocate. Do
|
||||
* this before other checks and adjustments so that this
|
||||
* tranformation will be validated.
|
||||
* transformation will be validated.
|
||||
*/
|
||||
if (address_min && !address_max)
|
||||
address_max = address_min + req_size;
|
||||
|
||||
@@ -192,7 +192,7 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown a queue a free it's command buffers to the FPA. The
|
||||
* Shutdown a queue and free its command buffers to the FPA. The
|
||||
* hardware connected to the queue must be stopped before this
|
||||
* function is called.
|
||||
*
|
||||
@@ -285,7 +285,7 @@ int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id)
|
||||
|
||||
/*
|
||||
* Return the command buffer to be written to. The purpose of this
|
||||
* function is to allow CVMX routine access t othe low level buffer
|
||||
* function is to allow CVMX routine access to the low level buffer
|
||||
* for initial hardware setup. User applications should not call this
|
||||
* function directly.
|
||||
*
|
||||
|
||||
@@ -103,7 +103,7 @@ uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data)
|
||||
/**
|
||||
* Shift long sequences of zeros into the QLM JTAG chain. It is
|
||||
* common to need to shift more than 32 bits of zeros into the
|
||||
* chain. This function is a convience wrapper around
|
||||
* chain. This function is a convenience wrapper around
|
||||
* cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of
|
||||
* zeros at a time.
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user