mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
Merge tag 'kvmarm-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 updates for 6.12 * New features: - Add a Stage-2 page table dumper, reusing the main ptdump infrastructure, and allowing easier debugging of the our page-table infrastructure - Add FP8 support to the KVM/arm64 floating point handling. - Add NV support for the AT family of instructions, which mostly results in adding a page table walker that deals with most of the complexity of the architecture. * Improvements, fixes and cleanups: - Add selftest checks for a bunch of timer emulation corner cases - Fix the multiple of cases where KVM/arm64 doesn't correctly handle the guest trying to use a GICv3 that isn't advertised - Remove REG_HIDDEN_USER from the sysreg infrastructure, making things little more simple - Prevent MTE tags being restored by userspace if we are actively logging writes, as that's a recipe for disaster - Correct the refcount on a page that is not considered for MTE tag copying (such as a device) - Relax the synchronisation when walking a page table to split block mappings, moving it at the end the walk, as there is no need to perform it on every store. - Fix boundary check when transfering memory using FFA - Fix pKVM TLB invalidation, only affecting currently out of tree code but worth addressing for peace of mind
This commit is contained in:
commit
091b2ecaa3
@ -562,7 +562,8 @@ Description: Control Symmetric Multi Threading (SMT)
|
||||
================ =========================================
|
||||
|
||||
If control status is "forceoff" or "notsupported" writes
|
||||
are rejected.
|
||||
are rejected. Note that enabling SMT on PowerPC skips
|
||||
offline cores.
|
||||
|
||||
What: /sys/devices/system/cpu/cpuX/power/energy_perf_bias
|
||||
Date: March 2019
|
||||
|
@ -162,13 +162,14 @@ iv_large_sectors
|
||||
|
||||
|
||||
Module parameters::
|
||||
max_read_size
|
||||
max_write_size
|
||||
Maximum size of read or write requests. When a request larger than this size
|
||||
is received, dm-crypt will split the request. The splitting improves
|
||||
concurrency (the split requests could be encrypted in parallel by multiple
|
||||
cores), but it also causes overhead. The user should tune these parameters to
|
||||
fit the actual workload.
|
||||
|
||||
max_read_size
|
||||
max_write_size
|
||||
Maximum size of read or write requests. When a request larger than this size
|
||||
is received, dm-crypt will split the request. The splitting improves
|
||||
concurrency (the split requests could be encrypted in parallel by multiple
|
||||
cores), but it also causes overhead. The user should tune these parameters to
|
||||
fit the actual workload.
|
||||
|
||||
|
||||
Example scripts
|
||||
|
@ -239,25 +239,33 @@ The following keys are defined:
|
||||
ratified in commit 98918c844281 ("Merge pull request #1217 from
|
||||
riscv/zawrs") of riscv-isa-manual.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance
|
||||
information about the selected set of processors.
|
||||
* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to
|
||||
:c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
|
||||
mistakenly classified as a bitmask rather than a value.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_UNKNOWN`: The performance of misaligned
|
||||
accesses is unknown.
|
||||
* :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`: An enum value describing
|
||||
the performance of misaligned scalar native word accesses on the selected set
|
||||
of processors.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_EMULATED`: Misaligned accesses are
|
||||
emulated via software, either in or below the kernel. These accesses are
|
||||
always extremely slow.
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN`: The performance of
|
||||
misaligned scalar accesses is unknown.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SLOW`: Misaligned accesses are slower
|
||||
than equivalent byte accesses. Misaligned accesses may be supported
|
||||
directly in hardware, or trapped and emulated by software.
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED`: Misaligned scalar
|
||||
accesses are emulated via software, either in or below the kernel. These
|
||||
accesses are always extremely slow.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_FAST`: Misaligned accesses are faster
|
||||
than equivalent byte accesses.
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW`: Misaligned scalar native
|
||||
word sized accesses are slower than the equivalent quantity of byte
|
||||
accesses. Misaligned accesses may be supported directly in hardware, or
|
||||
trapped and emulated by software.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_UNSUPPORTED`: Misaligned accesses are
|
||||
not supported at all and will generate a misaligned address fault.
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_FAST`: Misaligned scalar native
|
||||
word sized accesses are faster than the equivalent quantity of byte
|
||||
accesses.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED`: Misaligned scalar
|
||||
accesses are not supported at all and will generate a misaligned address
|
||||
fault.
|
||||
|
||||
* :c:macro:`RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE`: An unsigned int which
|
||||
represents the size of the Zicboz block in bytes.
|
||||
|
@ -260,7 +260,7 @@ Some users depend on strict execution ordering where only one work item
|
||||
is in flight at any given time and the work items are processed in
|
||||
queueing order. While the combination of ``@max_active`` of 1 and
|
||||
``WQ_UNBOUND`` used to achieve this behavior, this is no longer the
|
||||
case. Use ``alloc_ordered_queue()`` instead.
|
||||
case. Use alloc_ordered_workqueue() instead.
|
||||
|
||||
|
||||
Example Execution Scenarios
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Display Clock & Reset Controller on SM6350
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Global Clock & Reset Controller on MSM8994
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Global Clock & Reset Controller on SM6125
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Global Clock & Reset Controller on SM6350
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Graphics Clock & Reset Controller on SM6115
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module provides clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Graphics Clock & Reset Controller on SM6125
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module provides clocks and power domains on
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Camera Clock & Reset Controller on SM6350
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm camera clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Display Clock & Reset Controller on SM6375
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm display clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Global Clock & Reset Controller on SM6375
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Graphics Clock & Reset Controller on SM6375
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module provides clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm SM8350 Video Clock & Reset Controller
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm video clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Graphics Clock & Reset Controller on SM8450
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm graphics clock control module provides the clocks, resets and power
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm SM6375 Display MDSS
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description:
|
||||
SM6375 MSM Mobile Display Subsystem (MDSS), which encapsulates sub-blocks
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: ASUS Z00T TM5P5 NT35596 5.5" 1080×1920 LCD Panel
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konradybcio@gmail.com>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |+
|
||||
This panel seems to only be found in the Asus Z00T
|
||||
|
@ -18,12 +18,12 @@ properties:
|
||||
# Samsung 13.3" FHD (1920x1080 pixels) eDP AMOLED panel
|
||||
- const: samsung,atna33xc20
|
||||
- items:
|
||||
- enum:
|
||||
# Samsung 14.5" WQXGA+ (2880x1800 pixels) eDP AMOLED panel
|
||||
- samsung,atna45af01
|
||||
# Samsung 14.5" 3K (2944x1840 pixels) eDP AMOLED panel
|
||||
- samsung,atna45dc02
|
||||
- const: samsung,atna33xc20
|
||||
- enum:
|
||||
# Samsung 14.5" WQXGA+ (2880x1800 pixels) eDP AMOLED panel
|
||||
- samsung,atna45af01
|
||||
# Samsung 14.5" 3K (2944x1840 pixels) eDP AMOLED panel
|
||||
- samsung,atna45dc02
|
||||
- const: samsung,atna33xc20
|
||||
|
||||
enable-gpios: true
|
||||
port: true
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Sony TD4353 JDI 5 / 5.7" 2160x1080 MIPI-DSI Panel
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
The Sony TD4353 JDI is a 5 (XZ2c) / 5.7 (XZ2) inch 2160x1080
|
||||
|
@ -28,6 +28,7 @@ properties:
|
||||
- anvo,anv32e61w
|
||||
- atmel,at25256B
|
||||
- fujitsu,mb85rs1mt
|
||||
- fujitsu,mb85rs256
|
||||
- fujitsu,mb85rs64
|
||||
- microchip,at25160bn
|
||||
- microchip,25lc040
|
||||
|
@ -42,6 +42,7 @@ properties:
|
||||
- focaltech,ft5426
|
||||
- focaltech,ft5452
|
||||
- focaltech,ft6236
|
||||
- focaltech,ft8201
|
||||
- focaltech,ft8719
|
||||
|
||||
reg:
|
||||
|
@ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect on SC7280
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
RPMh interconnect providers support system bandwidth requirements through
|
||||
|
@ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect on SC8280XP
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
RPMh interconnect providers support system bandwidth requirements through
|
||||
|
@ -8,7 +8,7 @@ title: Qualcomm RPMh Network-On-Chip Interconnect on SM8450
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
RPMh interconnect providers support system bandwidth requirements through
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies legacy IOMMU implementations
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm "B" family devices which are not compatible with arm-smmu have
|
||||
|
@ -38,6 +38,10 @@ properties:
|
||||
|
||||
managed: true
|
||||
|
||||
phys:
|
||||
description: A reference to the SerDes lane(s)
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies, Inc. MDM9607 TLMM block
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description:
|
||||
Top Level Mode Multiplexer pin controller in Qualcomm MDM9607 SoC.
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies, Inc. SM6350 TLMM block
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description:
|
||||
Top Level Mode Multiplexer pin controller in Qualcomm SM6350 SoC.
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies, Inc. SM6375 TLMM block
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@somainline.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description:
|
||||
Top Level Mode Multiplexer pin controller in Qualcomm SM6375 SoC.
|
||||
|
@ -8,7 +8,7 @@ title: Qualcomm Resource Power Manager (RPM) Processor/Subsystem
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
- Stephan Gerhold <stephan@gerhold.net>
|
||||
|
||||
description: |
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Qualcomm Technologies, Inc. (QTI) RPM Master Stats
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
description: |
|
||||
The Qualcomm RPM (Resource Power Manager) architecture includes a concept
|
||||
|
@ -318,10 +318,10 @@ where the columns are:
|
||||
Debugging
|
||||
=========
|
||||
|
||||
If CONFIG_FSCACHE_DEBUG is enabled, the FS-Cache facility can have runtime
|
||||
debugging enabled by adjusting the value in::
|
||||
If CONFIG_NETFS_DEBUG is enabled, the FS-Cache facility and NETFS support can
|
||||
have runtime debugging enabled by adjusting the value in::
|
||||
|
||||
/sys/module/fscache/parameters/debug
|
||||
/sys/module/netfs/parameters/debug
|
||||
|
||||
This is a bitmask of debugging streams to enable:
|
||||
|
||||
@ -343,6 +343,6 @@ This is a bitmask of debugging streams to enable:
|
||||
The appropriate set of values should be OR'd together and the result written to
|
||||
the control file. For example::
|
||||
|
||||
echo $((1|8|512)) >/sys/module/fscache/parameters/debug
|
||||
echo $((1|8|512)) >/sys/module/netfs/parameters/debug
|
||||
|
||||
will turn on all function entry debugging.
|
||||
|
@ -75,7 +75,7 @@ Here are the main features of EROFS:
|
||||
|
||||
- Support merging tail-end data into a special inode as fragments.
|
||||
|
||||
- Support large folios for uncompressed files.
|
||||
- Support large folios to make use of THPs (Transparent Hugepages);
|
||||
|
||||
- Support direct I/O on uncompressed files to avoid double caching for loop
|
||||
devices;
|
||||
|
@ -13,7 +13,7 @@ KSMBD architecture
|
||||
The subset of performance related operations belong in kernelspace and
|
||||
the other subset which belong to operations which are not really related with
|
||||
performance in userspace. So, DCE/RPC management that has historically resulted
|
||||
into number of buffer overflow issues and dangerous security bugs and user
|
||||
into a number of buffer overflow issues and dangerous security bugs and user
|
||||
account management are implemented in user space as ksmbd.mountd.
|
||||
File operations that are related with performance (open/read/write/close etc.)
|
||||
in kernel space (ksmbd). This also allows for easier integration with VFS
|
||||
@ -24,8 +24,8 @@ ksmbd (kernel daemon)
|
||||
|
||||
When the server daemon is started, It starts up a forker thread
|
||||
(ksmbd/interface name) at initialization time and open a dedicated port 445
|
||||
for listening to SMB requests. Whenever new clients make request, Forker
|
||||
thread will accept the client connection and fork a new thread for dedicated
|
||||
for listening to SMB requests. Whenever new clients make a request, the Forker
|
||||
thread will accept the client connection and fork a new thread for a dedicated
|
||||
communication channel between the client and the server. It allows for parallel
|
||||
processing of SMB requests(commands) from clients as well as allowing for new
|
||||
clients to make new connections. Each instance is named ksmbd/1~n(port number)
|
||||
@ -34,12 +34,12 @@ thread can decide to pass through the commands to the user space (ksmbd.mountd),
|
||||
currently DCE/RPC commands are identified to be handled through the user space.
|
||||
To further utilize the linux kernel, it has been chosen to process the commands
|
||||
as workitems and to be executed in the handlers of the ksmbd-io kworker threads.
|
||||
It allows for multiplexing of the handlers as the kernel take care of initiating
|
||||
It allows for multiplexing of the handlers as the kernel takes care of initiating
|
||||
extra worker threads if the load is increased and vice versa, if the load is
|
||||
decreased it destroys the extra worker threads. So, after connection is
|
||||
established with client. Dedicated ksmbd/1..n(port number) takes complete
|
||||
decreased it destroys the extra worker threads. So, after the connection is
|
||||
established with the client. Dedicated ksmbd/1..n(port number) takes complete
|
||||
ownership of receiving/parsing of SMB commands. Each received command is worked
|
||||
in parallel i.e., There can be multiple clients commands which are worked in
|
||||
in parallel i.e., there can be multiple client commands which are worked in
|
||||
parallel. After receiving each command a separated kernel workitem is prepared
|
||||
for each command which is further queued to be handled by ksmbd-io kworkers.
|
||||
So, each SMB workitem is queued to the kworkers. This allows the benefit of load
|
||||
@ -49,9 +49,9 @@ performance by handling client commands in parallel.
|
||||
ksmbd.mountd (user space daemon)
|
||||
--------------------------------
|
||||
|
||||
ksmbd.mountd is userspace process to, transfer user account and password that
|
||||
ksmbd.mountd is a userspace process to, transfer the user account and password that
|
||||
are registered using ksmbd.adduser (part of utils for user space). Further it
|
||||
allows sharing information parameters that parsed from smb.conf to ksmbd in
|
||||
allows sharing information parameters that are parsed from smb.conf to ksmbd in
|
||||
kernel. For the execution part it has a daemon which is continuously running
|
||||
and connected to the kernel interface using netlink socket, it waits for the
|
||||
requests (dcerpc and share/user info). It handles RPC calls (at a minimum few
|
||||
@ -124,7 +124,7 @@ How to run
|
||||
1. Download ksmbd-tools(https://github.com/cifsd-team/ksmbd-tools/releases) and
|
||||
compile them.
|
||||
|
||||
- Refer README(https://github.com/cifsd-team/ksmbd-tools/blob/master/README.md)
|
||||
- Refer to README(https://github.com/cifsd-team/ksmbd-tools/blob/master/README.md)
|
||||
to know how to use ksmbd.mountd/adduser/addshare/control utils
|
||||
|
||||
$ ./autogen.sh
|
||||
@ -133,7 +133,7 @@ How to run
|
||||
|
||||
2. Create /usr/local/etc/ksmbd/ksmbd.conf file, add SMB share in ksmbd.conf file.
|
||||
|
||||
- Refer ksmbd.conf.example in ksmbd-utils, See ksmbd.conf manpage
|
||||
- Refer to ksmbd.conf.example in ksmbd-utils, See ksmbd.conf manpage
|
||||
for details to configure shares.
|
||||
|
||||
$ man ksmbd.conf
|
||||
@ -145,7 +145,7 @@ How to run
|
||||
$ man ksmbd.adduser
|
||||
$ sudo ksmbd.adduser -a <Enter USERNAME for SMB share access>
|
||||
|
||||
4. Insert ksmbd.ko module after build your kernel. No need to load module
|
||||
4. Insert the ksmbd.ko module after you build your kernel. No need to load the module
|
||||
if ksmbd is built into the kernel.
|
||||
|
||||
- Set ksmbd in menuconfig(e.g. $ make menuconfig)
|
||||
@ -175,7 +175,7 @@ Each layer
|
||||
1. Enable all component prints
|
||||
# sudo ksmbd.control -d "all"
|
||||
|
||||
2. Enable one of components (smb, auth, vfs, oplock, ipc, conn, rdma)
|
||||
2. Enable one of the components (smb, auth, vfs, oplock, ipc, conn, rdma)
|
||||
# sudo ksmbd.control -d "smb"
|
||||
|
||||
3. Show what prints are enabled.
|
||||
|
@ -126,7 +126,7 @@ Ccache
|
||||
|
||||
``ccache`` can be used with ``clang`` to improve subsequent builds, (though
|
||||
KBUILD_BUILD_TIMESTAMP_ should be set to a deterministic value between builds
|
||||
in order to avoid 100% cache misses, see Reproducible_builds_ for more info):
|
||||
in order to avoid 100% cache misses, see Reproducible_builds_ for more info)::
|
||||
|
||||
KBUILD_BUILD_TIMESTAMP='' make LLVM=1 CC="ccache clang"
|
||||
|
||||
|
36
MAINTAINERS
36
MAINTAINERS
@ -3504,7 +3504,9 @@ S: Maintained
|
||||
W: http://linux-atm.sourceforge.net
|
||||
F: drivers/atm/
|
||||
F: include/linux/atm*
|
||||
F: include/linux/sonet.h
|
||||
F: include/uapi/linux/atm*
|
||||
F: include/uapi/linux/sonet.h
|
||||
|
||||
ATMEL MACB ETHERNET DRIVER
|
||||
M: Nicolas Ferre <nicolas.ferre@microchip.com>
|
||||
@ -10173,7 +10175,7 @@ F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
|
||||
F: drivers/infiniband/hw/hns/
|
||||
|
||||
HISILICON SAS Controller
|
||||
M: Xiang Chen <chenxiang66@hisilicon.com>
|
||||
M: Yihang Li <liyihang9@huawei.com>
|
||||
S: Supported
|
||||
W: http://www.hisilicon.com
|
||||
F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
|
||||
@ -11993,7 +11995,7 @@ F: fs/jfs/
|
||||
JME NETWORK DRIVER
|
||||
M: Guo-Fu Tseng <cooldavid@cooldavid.org>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Odd Fixes
|
||||
F: drivers/net/ethernet/jme.*
|
||||
|
||||
JOURNALLING FLASH FILE SYSTEM V2 (JFFS2)
|
||||
@ -15877,15 +15879,19 @@ F: drivers/net/
|
||||
F: include/dt-bindings/net/
|
||||
F: include/linux/cn_proc.h
|
||||
F: include/linux/etherdevice.h
|
||||
F: include/linux/ethtool_netlink.h
|
||||
F: include/linux/fcdevice.h
|
||||
F: include/linux/fddidevice.h
|
||||
F: include/linux/hippidevice.h
|
||||
F: include/linux/if_*
|
||||
F: include/linux/inetdevice.h
|
||||
F: include/linux/netdevice.h
|
||||
F: include/linux/netdev*
|
||||
F: include/linux/platform_data/wiznet.h
|
||||
F: include/uapi/linux/cn_proc.h
|
||||
F: include/uapi/linux/ethtool_netlink.h
|
||||
F: include/uapi/linux/if_*
|
||||
F: include/uapi/linux/netdevice.h
|
||||
F: include/uapi/linux/netdev*
|
||||
F: tools/testing/selftests/drivers/net/
|
||||
X: drivers/net/wireless/
|
||||
|
||||
NETWORKING DRIVERS (WIRELESS)
|
||||
@ -15936,14 +15942,28 @@ F: include/linux/framer/framer-provider.h
|
||||
F: include/linux/framer/framer.h
|
||||
F: include/linux/in.h
|
||||
F: include/linux/indirect_call_wrapper.h
|
||||
F: include/linux/inet.h
|
||||
F: include/linux/inet_diag.h
|
||||
F: include/linux/net.h
|
||||
F: include/linux/netdevice.h
|
||||
F: include/linux/skbuff.h
|
||||
F: include/linux/netdev*
|
||||
F: include/linux/netlink.h
|
||||
F: include/linux/netpoll.h
|
||||
F: include/linux/rtnetlink.h
|
||||
F: include/linux/seq_file_net.h
|
||||
F: include/linux/skbuff*
|
||||
F: include/net/
|
||||
F: include/uapi/linux/genetlink.h
|
||||
F: include/uapi/linux/hsr_netlink.h
|
||||
F: include/uapi/linux/in.h
|
||||
F: include/uapi/linux/inet_diag.h
|
||||
F: include/uapi/linux/nbd-netlink.h
|
||||
F: include/uapi/linux/net.h
|
||||
F: include/uapi/linux/net_namespace.h
|
||||
F: include/uapi/linux/netdevice.h
|
||||
F: include/uapi/linux/netconf.h
|
||||
F: include/uapi/linux/netdev*
|
||||
F: include/uapi/linux/netlink.h
|
||||
F: include/uapi/linux/netlink_diag.h
|
||||
F: include/uapi/linux/rtnetlink.h
|
||||
F: lib/net_utils.c
|
||||
F: lib/random32.c
|
||||
F: net/
|
||||
@ -20354,6 +20374,7 @@ F: Documentation/devicetree/bindings/scsi/
|
||||
F: drivers/scsi/
|
||||
F: drivers/ufs/
|
||||
F: include/scsi/
|
||||
F: include/uapi/scsi/
|
||||
|
||||
SCSI TAPE DRIVER
|
||||
M: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
|
||||
@ -21054,6 +21075,7 @@ SOCKET TIMESTAMPING
|
||||
M: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/networking/timestamping.rst
|
||||
F: include/linux/net_tstamp.h
|
||||
F: include/uapi/linux/net_tstamp.h
|
||||
F: tools/testing/selftests/net/so_txtime.c
|
||||
|
||||
|
6
Makefile
6
Makefile
@ -2,7 +2,7 @@
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 11
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
@ -1963,7 +1963,7 @@ tags TAGS cscope gtags: FORCE
|
||||
# Protocol).
|
||||
PHONY += rust-analyzer
|
||||
rust-analyzer:
|
||||
$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
|
||||
+$(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh
|
||||
$(Q)$(MAKE) $(build)=rust $@
|
||||
|
||||
# Script to generate missing namespace dependencies
|
||||
@ -1980,7 +1980,7 @@ nsdeps: modules
|
||||
quiet_cmd_gen_compile_commands = GEN $@
|
||||
cmd_gen_compile_commands = $(PYTHON3) $< -a $(AR) -o $@ $(filter-out $<, $(real-prereqs))
|
||||
|
||||
$(extmod_prefix)compile_commands.json: scripts/clang-tools/gen_compile_commands.py \
|
||||
$(extmod_prefix)compile_commands.json: $(srctree)/scripts/clang-tools/gen_compile_commands.py \
|
||||
$(if $(KBUILD_EXTMOD),, vmlinux.a $(KBUILD_VMLINUX_LIBS)) \
|
||||
$(if $(CONFIG_MODULES), $(MODORDER)) FORCE
|
||||
$(call if_changed,gen_compile_commands)
|
||||
|
@ -1109,7 +1109,7 @@ void ecard_remove_driver(struct ecard_driver *drv)
|
||||
driver_unregister(&drv->drv);
|
||||
}
|
||||
|
||||
static int ecard_match(struct device *_dev, struct device_driver *_drv)
|
||||
static int ecard_match(struct device *_dev, const struct device_driver *_drv)
|
||||
{
|
||||
struct expansion_card *ec = ECARD_DEV(_dev);
|
||||
struct ecard_driver *drv = ECARD_DRV(_drv);
|
||||
|
@ -122,8 +122,8 @@
|
||||
#define ESR_ELx_FSC_SECC_TTW(n) (0x1c + (n))
|
||||
|
||||
/* Status codes for individual page table levels */
|
||||
#define ESR_ELx_FSC_ACCESS_L(n) (ESR_ELx_FSC_ACCESS + n)
|
||||
#define ESR_ELx_FSC_PERM_L(n) (ESR_ELx_FSC_PERM + n)
|
||||
#define ESR_ELx_FSC_ACCESS_L(n) (ESR_ELx_FSC_ACCESS + (n))
|
||||
#define ESR_ELx_FSC_PERM_L(n) (ESR_ELx_FSC_PERM + (n))
|
||||
|
||||
#define ESR_ELx_FSC_FAULT_nL (0x2C)
|
||||
#define ESR_ELx_FSC_FAULT_L(n) (((n) < 0 ? ESR_ELx_FSC_FAULT_nL : \
|
||||
@ -161,6 +161,7 @@
|
||||
|
||||
/* ISS field definitions for exceptions taken in to Hyp */
|
||||
#define ESR_ELx_FSC_ADDRSZ (0x00)
|
||||
#define ESR_ELx_FSC_ADDRSZ_L(n) (ESR_ELx_FSC_ADDRSZ + (n))
|
||||
#define ESR_ELx_CV (UL(1) << 24)
|
||||
#define ESR_ELx_COND_SHIFT (20)
|
||||
#define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT)
|
||||
|
@ -107,6 +107,7 @@
|
||||
/* TCR_EL2 Registers bits */
|
||||
#define TCR_EL2_DS (1UL << 32)
|
||||
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
|
||||
#define TCR_EL2_HPD (1 << 24)
|
||||
#define TCR_EL2_TBI (1 << 20)
|
||||
#define TCR_EL2_PS_SHIFT 16
|
||||
#define TCR_EL2_PS_MASK (7 << TCR_EL2_PS_SHIFT)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <asm/hyp_image.h>
|
||||
#include <asm/insn.h>
|
||||
#include <asm/virt.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
||||
#define ARM_EXIT_WITH_SERROR_BIT 31
|
||||
#define ARM_EXCEPTION_CODE(x) ((x) & ~(1U << ARM_EXIT_WITH_SERROR_BIT))
|
||||
@ -235,6 +236,9 @@ extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu);
|
||||
extern int __kvm_tlbi_s1e2(struct kvm_s2_mmu *mmu, u64 va, u64 sys_encoding);
|
||||
|
||||
extern void __kvm_timer_set_cntvoff(u64 cntvoff);
|
||||
extern void __kvm_at_s1e01(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern void __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
extern void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr);
|
||||
|
||||
extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
|
||||
|
||||
@ -259,7 +263,7 @@ extern u64 __kvm_get_mdcr_el2(void);
|
||||
asm volatile( \
|
||||
" mrs %1, spsr_el2\n" \
|
||||
" mrs %2, elr_el2\n" \
|
||||
"1: at "at_op", %3\n" \
|
||||
"1: " __msr_s(at_op, "%3") "\n" \
|
||||
" isb\n" \
|
||||
" b 9f\n" \
|
||||
"2: msr spsr_el2, %1\n" \
|
||||
|
@ -446,6 +446,10 @@ enum vcpu_sysreg {
|
||||
GCR_EL1, /* Tag Control Register */
|
||||
TFSRE0_EL1, /* Tag Fault Status Register (EL0) */
|
||||
|
||||
/* FP/SIMD/SVE */
|
||||
SVCR,
|
||||
FPMR,
|
||||
|
||||
/* 32bit specific registers. */
|
||||
DACR32_EL2, /* Domain Access Control Register */
|
||||
IFSR32_EL2, /* Instruction Fault Status Register */
|
||||
@ -530,6 +534,8 @@ enum vcpu_sysreg {
|
||||
VNCR(CNTP_CVAL_EL0),
|
||||
VNCR(CNTP_CTL_EL0),
|
||||
|
||||
VNCR(ICH_HCR_EL2),
|
||||
|
||||
NR_SYS_REGS /* Nothing after this line! */
|
||||
};
|
||||
|
||||
@ -595,6 +601,16 @@ struct kvm_host_data {
|
||||
struct cpu_sve_state *sve_state;
|
||||
};
|
||||
|
||||
union {
|
||||
/* HYP VA pointer to the host storage for FPMR */
|
||||
u64 *fpmr_ptr;
|
||||
/*
|
||||
* Used by pKVM only, as it needs to provide storage
|
||||
* for the host
|
||||
*/
|
||||
u64 fpmr;
|
||||
};
|
||||
|
||||
/* Ownership of the FP regs */
|
||||
enum {
|
||||
FP_STATE_FREE,
|
||||
@ -664,8 +680,6 @@ struct kvm_vcpu_arch {
|
||||
void *sve_state;
|
||||
enum fp_type fp_type;
|
||||
unsigned int sve_max_vl;
|
||||
u64 svcr;
|
||||
u64 fpmr;
|
||||
|
||||
/* Stage 2 paging state used by the hardware on next switch */
|
||||
struct kvm_s2_mmu *hw_mmu;
|
||||
@ -1473,4 +1487,8 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
|
||||
(pa + pi + pa3) == 1; \
|
||||
})
|
||||
|
||||
#define kvm_has_fpmr(k) \
|
||||
(system_supports_fpmr() && \
|
||||
kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP))
|
||||
|
||||
#endif /* __ARM64_KVM_HOST_H__ */
|
||||
|
@ -352,5 +352,11 @@ static inline bool kvm_is_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
|
||||
return &kvm->arch.mmu != mmu;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PTDUMP_STAGE2_DEBUGFS
|
||||
void kvm_s2_ptdump_create_debugfs(struct kvm *kvm);
|
||||
#else
|
||||
static inline void kvm_s2_ptdump_create_debugfs(struct kvm *kvm) {}
|
||||
#endif /* CONFIG_PTDUMP_STAGE2_DEBUGFS */
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARM64_KVM_MMU_H__ */
|
||||
|
@ -85,7 +85,7 @@ struct kvm_s2_trans {
|
||||
bool readable;
|
||||
int level;
|
||||
u32 esr;
|
||||
u64 upper_attr;
|
||||
u64 desc;
|
||||
};
|
||||
|
||||
static inline phys_addr_t kvm_s2_trans_output(struct kvm_s2_trans *trans)
|
||||
@ -115,7 +115,7 @@ static inline bool kvm_s2_trans_writable(struct kvm_s2_trans *trans)
|
||||
|
||||
static inline bool kvm_s2_trans_executable(struct kvm_s2_trans *trans)
|
||||
{
|
||||
return !(trans->upper_attr & BIT(54));
|
||||
return !(trans->desc & BIT(54));
|
||||
}
|
||||
|
||||
extern int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
|
||||
@ -205,4 +205,40 @@ static inline u64 kvm_encode_nested_level(struct kvm_s2_trans *trans)
|
||||
return FIELD_PREP(KVM_NV_GUEST_MAP_SZ, trans->level);
|
||||
}
|
||||
|
||||
/* Adjust alignment for the contiguous bit as per StageOA() */
|
||||
#define contiguous_bit_shift(d, wi, l) \
|
||||
({ \
|
||||
u8 shift = 0; \
|
||||
\
|
||||
if ((d) & PTE_CONT) { \
|
||||
switch (BIT((wi)->pgshift)) { \
|
||||
case SZ_4K: \
|
||||
shift = 4; \
|
||||
break; \
|
||||
case SZ_16K: \
|
||||
shift = (l) == 2 ? 5 : 7; \
|
||||
break; \
|
||||
case SZ_64K: \
|
||||
shift = 5; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
shift; \
|
||||
})
|
||||
|
||||
static inline unsigned int ps_to_output_size(unsigned int ps)
|
||||
{
|
||||
switch (ps) {
|
||||
case 0: return 32;
|
||||
case 1: return 36;
|
||||
case 2: return 40;
|
||||
case 3: return 42;
|
||||
case 4: return 44;
|
||||
case 5:
|
||||
default:
|
||||
return 48;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ARM64_KVM_NESTED_H */
|
||||
|
@ -59,6 +59,48 @@ typedef u64 kvm_pte_t;
|
||||
|
||||
#define KVM_PHYS_INVALID (-1ULL)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO GENMASK(11, 2)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX GENMASK(4, 2)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP GENMASK(7, 6)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH GENMASK(9, 8)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AF BIT(10)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR GENMASK(5, 2)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R BIT(6)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W BIT(7)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_SH GENMASK(9, 8)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_SH_IS 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_AF BIT(10)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI GENMASK(63, 50)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_SW GENMASK(58, 55)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_GP BIT(50)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_S2_PERMS (KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
|
||||
KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \
|
||||
KVM_PTE_LEAF_ATTR_HI_S2_XN)
|
||||
|
||||
#define KVM_INVALID_PTE_OWNER_MASK GENMASK(9, 2)
|
||||
#define KVM_MAX_OWNER_ID 1
|
||||
|
||||
/*
|
||||
* Used to indicate a pte for which a 'break-before-make' sequence is in
|
||||
* progress.
|
||||
*/
|
||||
#define KVM_INVALID_PTE_LOCKED BIT(10)
|
||||
|
||||
static inline bool kvm_pte_valid(kvm_pte_t pte)
|
||||
{
|
||||
return pte & KVM_PTE_VALID;
|
||||
|
@ -204,6 +204,11 @@
|
||||
*/
|
||||
#define PTE_S2_MEMATTR(t) (_AT(pteval_t, (t)) << 2)
|
||||
|
||||
/*
|
||||
* Hierarchical permission for Stage-1 tables
|
||||
*/
|
||||
#define S1_TABLE_AP (_AT(pmdval_t, 3) << 61)
|
||||
|
||||
/*
|
||||
* Highest possible physical address supported.
|
||||
*/
|
||||
@ -298,6 +303,10 @@
|
||||
#define TCR_TBI1 (UL(1) << 38)
|
||||
#define TCR_HA (UL(1) << 39)
|
||||
#define TCR_HD (UL(1) << 40)
|
||||
#define TCR_HPD0_SHIFT 41
|
||||
#define TCR_HPD0 (UL(1) << TCR_HPD0_SHIFT)
|
||||
#define TCR_HPD1_SHIFT 42
|
||||
#define TCR_HPD1 (UL(1) << TCR_HPD1_SHIFT)
|
||||
#define TCR_TBID0 (UL(1) << 51)
|
||||
#define TCR_TBID1 (UL(1) << 52)
|
||||
#define TCR_NFD0 (UL(1) << 53)
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef __ASM_PTDUMP_H
|
||||
#define __ASM_PTDUMP_H
|
||||
|
||||
#include <linux/ptdump.h>
|
||||
|
||||
#ifdef CONFIG_PTDUMP_CORE
|
||||
|
||||
#include <linux/mm_types.h>
|
||||
@ -21,14 +23,53 @@ struct ptdump_info {
|
||||
unsigned long base_addr;
|
||||
};
|
||||
|
||||
struct ptdump_prot_bits {
|
||||
u64 mask;
|
||||
u64 val;
|
||||
const char *set;
|
||||
const char *clear;
|
||||
};
|
||||
|
||||
struct ptdump_pg_level {
|
||||
const struct ptdump_prot_bits *bits;
|
||||
char name[4];
|
||||
int num;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
/*
|
||||
* The page dumper groups page table entries of the same type into a single
|
||||
* description. It uses pg_state to track the range information while
|
||||
* iterating over the pte entries. When the continuity is broken it then
|
||||
* dumps out a description of the range.
|
||||
*/
|
||||
struct ptdump_pg_state {
|
||||
struct ptdump_state ptdump;
|
||||
struct ptdump_pg_level *pg_level;
|
||||
struct seq_file *seq;
|
||||
const struct addr_marker *marker;
|
||||
const struct mm_struct *mm;
|
||||
unsigned long start_address;
|
||||
int level;
|
||||
u64 current_prot;
|
||||
bool check_wx;
|
||||
unsigned long wx_pages;
|
||||
unsigned long uxn_pages;
|
||||
};
|
||||
|
||||
void ptdump_walk(struct seq_file *s, struct ptdump_info *info);
|
||||
void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
|
||||
u64 val);
|
||||
#ifdef CONFIG_PTDUMP_DEBUGFS
|
||||
#define EFI_RUNTIME_MAP_END DEFAULT_MAP_WINDOW_64
|
||||
void __init ptdump_debugfs_register(struct ptdump_info *info, const char *name);
|
||||
#else
|
||||
static inline void ptdump_debugfs_register(struct ptdump_info *info,
|
||||
const char *name) { }
|
||||
#endif
|
||||
#endif /* CONFIG_PTDUMP_DEBUGFS */
|
||||
#else
|
||||
static inline void note_page(struct ptdump_state *pt_st, unsigned long addr,
|
||||
int level, u64 val) { }
|
||||
#endif /* CONFIG_PTDUMP_CORE */
|
||||
|
||||
#endif /* __ASM_PTDUMP_H */
|
||||
|
@ -109,6 +109,9 @@
|
||||
#define set_pstate_ssbs(x) asm volatile(SET_PSTATE_SSBS(x))
|
||||
#define set_pstate_dit(x) asm volatile(SET_PSTATE_DIT(x))
|
||||
|
||||
/* Register-based PAN access, for save/restore purposes */
|
||||
#define SYS_PSTATE_PAN sys_reg(3, 0, 4, 2, 3)
|
||||
|
||||
#define __SYS_BARRIER_INSN(CRm, op2, Rt) \
|
||||
__emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f))
|
||||
|
||||
@ -325,7 +328,25 @@
|
||||
#define SYS_PAR_EL1 sys_reg(3, 0, 7, 4, 0)
|
||||
|
||||
#define SYS_PAR_EL1_F BIT(0)
|
||||
/* When PAR_EL1.F == 1 */
|
||||
#define SYS_PAR_EL1_FST GENMASK(6, 1)
|
||||
#define SYS_PAR_EL1_PTW BIT(8)
|
||||
#define SYS_PAR_EL1_S BIT(9)
|
||||
#define SYS_PAR_EL1_AssuredOnly BIT(12)
|
||||
#define SYS_PAR_EL1_TopLevel BIT(13)
|
||||
#define SYS_PAR_EL1_Overlay BIT(14)
|
||||
#define SYS_PAR_EL1_DirtyBit BIT(15)
|
||||
#define SYS_PAR_EL1_F1_IMPDEF GENMASK_ULL(63, 48)
|
||||
#define SYS_PAR_EL1_F1_RES0 (BIT(7) | BIT(10) | GENMASK_ULL(47, 16))
|
||||
#define SYS_PAR_EL1_RES1 BIT(11)
|
||||
/* When PAR_EL1.F == 0 */
|
||||
#define SYS_PAR_EL1_SH GENMASK_ULL(8, 7)
|
||||
#define SYS_PAR_EL1_NS BIT(9)
|
||||
#define SYS_PAR_EL1_F0_IMPDEF BIT(10)
|
||||
#define SYS_PAR_EL1_NSE BIT(11)
|
||||
#define SYS_PAR_EL1_PA GENMASK_ULL(51, 12)
|
||||
#define SYS_PAR_EL1_ATTR GENMASK_ULL(63, 56)
|
||||
#define SYS_PAR_EL1_F0_RES0 (GENMASK_ULL(6, 1) | GENMASK_ULL(55, 52))
|
||||
|
||||
/*** Statistical Profiling Extension ***/
|
||||
#define PMSEVFR_EL1_RES0_IMP \
|
||||
@ -652,6 +673,7 @@
|
||||
#define OP_AT_S12E1W sys_insn(AT_Op0, 4, AT_CRn, 8, 5)
|
||||
#define OP_AT_S12E0R sys_insn(AT_Op0, 4, AT_CRn, 8, 6)
|
||||
#define OP_AT_S12E0W sys_insn(AT_Op0, 4, AT_CRn, 8, 7)
|
||||
#define OP_AT_S1E2A sys_insn(AT_Op0, 4, AT_CRn, 9, 2)
|
||||
|
||||
/* TLBI instructions */
|
||||
#define TLBI_Op0 1
|
||||
|
@ -188,7 +188,7 @@ static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
|
||||
#define __get_mem_asm(load, reg, x, addr, label, type) \
|
||||
asm_goto_output( \
|
||||
"1: " load " " reg "0, [%1]\n" \
|
||||
_ASM_EXTABLE_##type##ACCESS_ERR(1b, %l2, %w0) \
|
||||
_ASM_EXTABLE_##type##ACCESS(1b, %l2) \
|
||||
: "=r" (x) \
|
||||
: "r" (addr) : : label)
|
||||
#else
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#include <asm/numa.h>
|
||||
|
||||
static int acpi_early_node_map[NR_CPUS] __initdata = { NUMA_NO_NODE };
|
||||
static int acpi_early_node_map[NR_CPUS] __initdata = { [0 ... NR_CPUS - 1] = NUMA_NO_NODE };
|
||||
|
||||
int __init acpi_numa_get_nid(unsigned int cpu)
|
||||
{
|
||||
|
@ -355,9 +355,6 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
||||
smp_init_cpus();
|
||||
smp_build_mpidr_hash();
|
||||
|
||||
/* Init percpu seeds for random tags after cpus are set up. */
|
||||
kasan_init_sw_tags();
|
||||
|
||||
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
||||
/*
|
||||
* Make sure init_thread_info.ttbr0 always generates translation
|
||||
|
@ -467,6 +467,8 @@ void __init smp_prepare_boot_cpu(void)
|
||||
init_gic_priority_masking();
|
||||
|
||||
kasan_init_hw_tags();
|
||||
/* Init percpu seeds for random tags after cpus are set up. */
|
||||
kasan_init_sw_tags();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -66,4 +66,21 @@ config PROTECTED_NVHE_STACKTRACE
|
||||
|
||||
If unsure, or not using protected nVHE (pKVM), say N.
|
||||
|
||||
config PTDUMP_STAGE2_DEBUGFS
|
||||
bool "Present the stage-2 pagetables to debugfs"
|
||||
depends on KVM
|
||||
depends on DEBUG_KERNEL
|
||||
depends on DEBUG_FS
|
||||
depends on GENERIC_PTDUMP
|
||||
select PTDUMP_CORE
|
||||
default n
|
||||
help
|
||||
Say Y here if you want to show the stage-2 kernel pagetables
|
||||
layout in a debugfs file. This information is only useful for kernel developers
|
||||
who are working in architecture specific areas of the kernel.
|
||||
It is probably not a good idea to enable this feature in a production
|
||||
kernel.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
endif # VIRTUALIZATION
|
||||
|
@ -17,7 +17,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
|
||||
inject_fault.o va_layout.o handle_exit.o \
|
||||
guest.o debug.o reset.o sys_regs.o stacktrace.o \
|
||||
vgic-sys-reg-v3.o fpsimd.o pkvm.o \
|
||||
arch_timer.o trng.o vmid.o emulate-nested.o nested.o \
|
||||
arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
|
||||
vgic/vgic.o vgic/vgic-init.o \
|
||||
vgic/vgic-irqfd.o vgic/vgic-v2.o \
|
||||
vgic/vgic-v3.o vgic/vgic-v4.o \
|
||||
@ -27,6 +27,7 @@ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
|
||||
|
||||
kvm-$(CONFIG_HW_PERF_EVENTS) += pmu-emul.o pmu.o
|
||||
kvm-$(CONFIG_ARM64_PTR_AUTH) += pauth.o
|
||||
kvm-$(CONFIG_PTDUMP_STAGE2_DEBUGFS) += ptdump.o
|
||||
|
||||
always-y := hyp_constants.h hyp-constants.s
|
||||
|
||||
|
@ -46,6 +46,8 @@
|
||||
#include <kvm/arm_pmu.h>
|
||||
#include <kvm/arm_psci.h>
|
||||
|
||||
#include "sys_regs.h"
|
||||
|
||||
static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
|
||||
|
||||
enum kvm_wfx_trap_policy {
|
||||
@ -228,6 +230,7 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
|
||||
void kvm_arch_create_vm_debugfs(struct kvm *kvm)
|
||||
{
|
||||
kvm_sys_regs_create_debugfs(kvm);
|
||||
kvm_s2_ptdump_create_debugfs(kvm);
|
||||
}
|
||||
|
||||
static void kvm_destroy_mpidr_data(struct kvm *kvm)
|
||||
@ -821,15 +824,13 @@ 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_finalize_sys_regs(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* This needs to happen after NV has imposed its own restrictions on
|
||||
* the feature set
|
||||
* This needs to happen after any restriction has been applied
|
||||
* to the feature set.
|
||||
*/
|
||||
kvm_calculate_traps(vcpu);
|
||||
|
||||
|
1101
arch/arm64/kvm/at.c
Normal file
1101
arch/arm64/kvm/at.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -83,14 +83,20 @@ enum cgt_group_id {
|
||||
CGT_CPTR_TAM,
|
||||
CGT_CPTR_TCPAC,
|
||||
|
||||
CGT_HCRX_EnFPM,
|
||||
CGT_HCRX_TCR2En,
|
||||
|
||||
CGT_ICH_HCR_TC,
|
||||
CGT_ICH_HCR_TALL0,
|
||||
CGT_ICH_HCR_TALL1,
|
||||
CGT_ICH_HCR_TDIR,
|
||||
|
||||
/*
|
||||
* Anything after this point is a combination of coarse trap
|
||||
* controls, which must all be evaluated to decide what to do.
|
||||
*/
|
||||
__MULTIPLE_CONTROL_BITS__,
|
||||
CGT_HCR_IMO_FMO = __MULTIPLE_CONTROL_BITS__,
|
||||
CGT_HCR_IMO_FMO_ICH_HCR_TC = __MULTIPLE_CONTROL_BITS__,
|
||||
CGT_HCR_TID2_TID4,
|
||||
CGT_HCR_TTLB_TTLBIS,
|
||||
CGT_HCR_TTLB_TTLBOS,
|
||||
@ -105,6 +111,8 @@ enum cgt_group_id {
|
||||
CGT_MDCR_TDE_TDRA,
|
||||
CGT_MDCR_TDCC_TDE_TDA,
|
||||
|
||||
CGT_ICH_HCR_TC_TDIR,
|
||||
|
||||
/*
|
||||
* Anything after this point requires a callback evaluating a
|
||||
* complex trap condition. Ugly stuff.
|
||||
@ -372,12 +380,42 @@ static const struct trap_bits coarse_trap_bits[] = {
|
||||
.mask = CPTR_EL2_TCPAC,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_HCRX_EnFPM] = {
|
||||
.index = HCRX_EL2,
|
||||
.value = 0,
|
||||
.mask = HCRX_EL2_EnFPM,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_HCRX_TCR2En] = {
|
||||
.index = HCRX_EL2,
|
||||
.value = 0,
|
||||
.mask = HCRX_EL2_TCR2En,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_ICH_HCR_TC] = {
|
||||
.index = ICH_HCR_EL2,
|
||||
.value = ICH_HCR_TC,
|
||||
.mask = ICH_HCR_TC,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_ICH_HCR_TALL0] = {
|
||||
.index = ICH_HCR_EL2,
|
||||
.value = ICH_HCR_TALL0,
|
||||
.mask = ICH_HCR_TALL0,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_ICH_HCR_TALL1] = {
|
||||
.index = ICH_HCR_EL2,
|
||||
.value = ICH_HCR_TALL1,
|
||||
.mask = ICH_HCR_TALL1,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
[CGT_ICH_HCR_TDIR] = {
|
||||
.index = ICH_HCR_EL2,
|
||||
.value = ICH_HCR_TDIR,
|
||||
.mask = ICH_HCR_TDIR,
|
||||
.behaviour = BEHAVE_FORWARD_ANY,
|
||||
},
|
||||
};
|
||||
|
||||
#define MCB(id, ...) \
|
||||
@ -387,7 +425,6 @@ static const struct trap_bits coarse_trap_bits[] = {
|
||||
}
|
||||
|
||||
static const enum cgt_group_id *coarse_control_combo[] = {
|
||||
MCB(CGT_HCR_IMO_FMO, CGT_HCR_IMO, CGT_HCR_FMO),
|
||||
MCB(CGT_HCR_TID2_TID4, CGT_HCR_TID2, CGT_HCR_TID4),
|
||||
MCB(CGT_HCR_TTLB_TTLBIS, CGT_HCR_TTLB, CGT_HCR_TTLBIS),
|
||||
MCB(CGT_HCR_TTLB_TTLBOS, CGT_HCR_TTLB, CGT_HCR_TTLBOS),
|
||||
@ -402,6 +439,9 @@ static const enum cgt_group_id *coarse_control_combo[] = {
|
||||
MCB(CGT_MDCR_TDE_TDOSA, CGT_MDCR_TDE, CGT_MDCR_TDOSA),
|
||||
MCB(CGT_MDCR_TDE_TDRA, CGT_MDCR_TDE, CGT_MDCR_TDRA),
|
||||
MCB(CGT_MDCR_TDCC_TDE_TDA, CGT_MDCR_TDCC, CGT_MDCR_TDE, CGT_MDCR_TDA),
|
||||
|
||||
MCB(CGT_HCR_IMO_FMO_ICH_HCR_TC, CGT_HCR_IMO, CGT_HCR_FMO, CGT_ICH_HCR_TC),
|
||||
MCB(CGT_ICH_HCR_TC_TDIR, CGT_ICH_HCR_TC, CGT_ICH_HCR_TDIR),
|
||||
};
|
||||
|
||||
typedef enum trap_behaviour (*complex_condition_check)(struct kvm_vcpu *);
|
||||
@ -536,9 +576,9 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
|
||||
SR_TRAP(SYS_CSSELR_EL1, CGT_HCR_TID2_TID4),
|
||||
SR_RANGE_TRAP(SYS_ID_PFR0_EL1,
|
||||
sys_reg(3, 0, 0, 7, 7), CGT_HCR_TID3),
|
||||
SR_TRAP(SYS_ICC_SGI0R_EL1, CGT_HCR_IMO_FMO),
|
||||
SR_TRAP(SYS_ICC_ASGI1R_EL1, CGT_HCR_IMO_FMO),
|
||||
SR_TRAP(SYS_ICC_SGI1R_EL1, CGT_HCR_IMO_FMO),
|
||||
SR_TRAP(SYS_ICC_SGI0R_EL1, CGT_HCR_IMO_FMO_ICH_HCR_TC),
|
||||
SR_TRAP(SYS_ICC_ASGI1R_EL1, CGT_HCR_IMO_FMO_ICH_HCR_TC),
|
||||
SR_TRAP(SYS_ICC_SGI1R_EL1, CGT_HCR_IMO_FMO_ICH_HCR_TC),
|
||||
SR_RANGE_TRAP(sys_reg(3, 0, 11, 0, 0),
|
||||
sys_reg(3, 0, 11, 15, 7), CGT_HCR_TIDCP),
|
||||
SR_RANGE_TRAP(sys_reg(3, 1, 11, 0, 0),
|
||||
@ -786,6 +826,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
|
||||
SR_TRAP(OP_AT_S12E1W, CGT_HCR_NV),
|
||||
SR_TRAP(OP_AT_S12E0R, CGT_HCR_NV),
|
||||
SR_TRAP(OP_AT_S12E0W, CGT_HCR_NV),
|
||||
SR_TRAP(OP_AT_S1E2A, CGT_HCR_NV),
|
||||
SR_TRAP(OP_TLBI_IPAS2E1, CGT_HCR_NV),
|
||||
SR_TRAP(OP_TLBI_RIPAS2E1, CGT_HCR_NV),
|
||||
SR_TRAP(OP_TLBI_IPAS2LE1, CGT_HCR_NV),
|
||||
@ -867,6 +908,7 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
|
||||
SR_TRAP(OP_AT_S1E0W, CGT_HCR_AT),
|
||||
SR_TRAP(OP_AT_S1E1RP, CGT_HCR_AT),
|
||||
SR_TRAP(OP_AT_S1E1WP, CGT_HCR_AT),
|
||||
SR_TRAP(OP_AT_S1E1A, CGT_HCR_AT),
|
||||
SR_TRAP(SYS_ERXPFGF_EL1, CGT_HCR_nFIEN),
|
||||
SR_TRAP(SYS_ERXPFGCTL_EL1, CGT_HCR_nFIEN),
|
||||
SR_TRAP(SYS_ERXPFGCDN_EL1, CGT_HCR_nFIEN),
|
||||
@ -1108,6 +1150,35 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
|
||||
SR_TRAP(SYS_CNTP_CTL_EL0, CGT_CNTHCTL_EL1PTEN),
|
||||
SR_TRAP(SYS_CNTPCT_EL0, CGT_CNTHCTL_EL1PCTEN),
|
||||
SR_TRAP(SYS_CNTPCTSS_EL0, CGT_CNTHCTL_EL1PCTEN),
|
||||
SR_TRAP(SYS_FPMR, CGT_HCRX_EnFPM),
|
||||
/*
|
||||
* IMPDEF choice:
|
||||
* We treat ICC_SRE_EL2.{SRE,Enable) and ICV_SRE_EL1.SRE as
|
||||
* RAO/WI. We therefore never consider ICC_SRE_EL2.Enable for
|
||||
* ICC_SRE_EL1 access, and always handle it locally.
|
||||
*/
|
||||
SR_TRAP(SYS_ICC_AP0R0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_AP0R1_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_AP0R2_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_AP0R3_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_AP1R0_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_AP1R1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_AP1R2_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_AP1R3_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_BPR0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_BPR1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_CTLR_EL1, CGT_ICH_HCR_TC),
|
||||
SR_TRAP(SYS_ICC_DIR_EL1, CGT_ICH_HCR_TC_TDIR),
|
||||
SR_TRAP(SYS_ICC_EOIR0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_EOIR1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_HPPIR0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_HPPIR1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_IAR0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_IAR1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_IGRPEN0_EL1, CGT_ICH_HCR_TALL0),
|
||||
SR_TRAP(SYS_ICC_IGRPEN1_EL1, CGT_ICH_HCR_TALL1),
|
||||
SR_TRAP(SYS_ICC_PMR_EL1, CGT_ICH_HCR_TC),
|
||||
SR_TRAP(SYS_ICC_RPR_EL1, CGT_ICH_HCR_TC),
|
||||
};
|
||||
|
||||
static DEFINE_XARRAY(sr_forward_xa);
|
||||
|
@ -63,6 +63,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
|
||||
*host_data_ptr(fpsimd_state) = kern_hyp_va(¤t->thread.uw.fpsimd_state);
|
||||
*host_data_ptr(fpmr_ptr) = kern_hyp_va(¤t->thread.uw.fpmr);
|
||||
|
||||
vcpu_clear_flag(vcpu, HOST_SVE_ENABLED);
|
||||
if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN)
|
||||
@ -134,8 +135,8 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
|
||||
fp_state.sve_state = vcpu->arch.sve_state;
|
||||
fp_state.sve_vl = vcpu->arch.sve_max_vl;
|
||||
fp_state.sme_state = NULL;
|
||||
fp_state.svcr = &vcpu->arch.svcr;
|
||||
fp_state.fpmr = &vcpu->arch.fpmr;
|
||||
fp_state.svcr = &__vcpu_sys_reg(vcpu, SVCR);
|
||||
fp_state.fpmr = &__vcpu_sys_reg(vcpu, FPMR);
|
||||
fp_state.fp_type = &vcpu->arch.fp_type;
|
||||
|
||||
if (vcpu_has_sve(vcpu))
|
||||
|
@ -1045,6 +1045,11 @@ int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
|
||||
|
||||
mutex_lock(&kvm->slots_lock);
|
||||
|
||||
if (write && atomic_read(&kvm->nr_memslots_dirty_logging)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
kvm_pfn_t pfn = gfn_to_pfn_prot(kvm, gfn, write, NULL);
|
||||
void *maddr;
|
||||
@ -1059,6 +1064,7 @@ int kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
|
||||
page = pfn_to_online_page(pfn);
|
||||
if (!page) {
|
||||
/* Reject ZONE_DEVICE memory */
|
||||
kvm_release_pfn_clean(pfn);
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar)
|
||||
* saved the guest context yet, and we may return early...
|
||||
*/
|
||||
par = read_sysreg_par();
|
||||
if (!__kvm_at("s1e1r", far))
|
||||
if (!__kvm_at(OP_AT_S1E1R, far))
|
||||
tmp = read_sysreg_par();
|
||||
else
|
||||
tmp = SYS_PAR_EL1_F; /* back to the guest */
|
||||
|
@ -403,6 +403,9 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
else
|
||||
__fpsimd_restore_state(&vcpu->arch.ctxt.fp_regs);
|
||||
|
||||
if (kvm_has_fpmr(kern_hyp_va(vcpu->kvm)))
|
||||
write_sysreg_s(__vcpu_sys_reg(vcpu, FPMR), SYS_FPMR);
|
||||
|
||||
/* Skip restoring fpexc32 for AArch64 guests */
|
||||
if (!(read_sysreg(hcr_el2) & HCR_RW))
|
||||
write_sysreg(__vcpu_sys_reg(vcpu, FPEXC32_EL2), fpexc32_el2);
|
||||
|
@ -426,9 +426,9 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
static void __do_ffa_mem_xfer(const u64 func_id,
|
||||
struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
DECLARE_REG(u32, len, ctxt, 1);
|
||||
DECLARE_REG(u32, fraglen, ctxt, 2);
|
||||
@ -440,9 +440,6 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
u32 offset, nr_ranges;
|
||||
int ret = 0;
|
||||
|
||||
BUILD_BUG_ON(func_id != FFA_FN64_MEM_SHARE &&
|
||||
func_id != FFA_FN64_MEM_LEND);
|
||||
|
||||
if (addr_mbz || npages_mbz || fraglen > len ||
|
||||
fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE) {
|
||||
ret = FFA_RET_INVALID_PARAMETERS;
|
||||
@ -461,6 +458,11 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (len > ffa_desc_buf.len) {
|
||||
ret = FFA_RET_NO_MEMORY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
buf = hyp_buffers.tx;
|
||||
memcpy(buf, host_buffers.tx, fraglen);
|
||||
|
||||
@ -512,6 +514,13 @@ err_unshare:
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
#define do_ffa_mem_xfer(fid, res, ctxt) \
|
||||
do { \
|
||||
BUILD_BUG_ON((fid) != FFA_FN64_MEM_SHARE && \
|
||||
(fid) != FFA_FN64_MEM_LEND); \
|
||||
__do_ffa_mem_xfer((fid), (res), (ctxt)); \
|
||||
} while (0);
|
||||
|
||||
static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
|
||||
struct kvm_cpu_context *ctxt)
|
||||
{
|
||||
|
@ -130,7 +130,7 @@ alternative_else_nop_endif
|
||||
|
||||
/* Invalidate the stale TLBs from Bootloader */
|
||||
tlbi alle2
|
||||
tlbi vmalls12e1
|
||||
tlbi alle1
|
||||
dsb sy
|
||||
|
||||
mov_q x0, INIT_SCTLR_EL2_MMU_ON
|
||||
|
@ -62,6 +62,8 @@ static void fpsimd_sve_flush(void)
|
||||
|
||||
static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
bool has_fpmr;
|
||||
|
||||
if (!guest_owns_fp_regs())
|
||||
return;
|
||||
|
||||
@ -73,11 +75,18 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
|
||||
else
|
||||
__fpsimd_save_state(&vcpu->arch.ctxt.fp_regs);
|
||||
|
||||
has_fpmr = kvm_has_fpmr(kern_hyp_va(vcpu->kvm));
|
||||
if (has_fpmr)
|
||||
__vcpu_sys_reg(vcpu, FPMR) = read_sysreg_s(SYS_FPMR);
|
||||
|
||||
if (system_supports_sve())
|
||||
__hyp_sve_restore_host();
|
||||
else
|
||||
__fpsimd_restore_state(*host_data_ptr(fpsimd_state));
|
||||
|
||||
if (has_fpmr)
|
||||
write_sysreg_s(*host_data_ptr(fpmr), SYS_FPMR);
|
||||
|
||||
*host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,15 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
|
||||
} else {
|
||||
__fpsimd_save_state(*host_data_ptr(fpsimd_state));
|
||||
}
|
||||
|
||||
if (kvm_has_fpmr(kern_hyp_va(vcpu->kvm))) {
|
||||
u64 val = read_sysreg_s(SYS_FPMR);
|
||||
|
||||
if (unlikely(is_protected_kvm_enabled()))
|
||||
*host_data_ptr(fpmr) = val;
|
||||
else
|
||||
**host_data_ptr(fpmr_ptr) = val;
|
||||
}
|
||||
}
|
||||
|
||||
static const exit_handler_fn hyp_exit_handlers[] = {
|
||||
|
@ -132,10 +132,10 @@ static void exit_vmid_context(struct tlb_inv_context *cxt)
|
||||
else
|
||||
__load_host_stage2();
|
||||
|
||||
if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
|
||||
/* Ensure write of the old VMID */
|
||||
isb();
|
||||
/* Ensure write of the old VMID */
|
||||
isb();
|
||||
|
||||
if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
|
||||
if (!(cxt->sctlr & SCTLR_ELx_M)) {
|
||||
write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
|
||||
isb();
|
||||
|
@ -17,48 +17,6 @@
|
||||
#define KVM_PTE_TYPE_PAGE 1
|
||||
#define KVM_PTE_TYPE_TABLE 1
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO GENMASK(11, 2)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_ATTRIDX GENMASK(4, 2)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP GENMASK(7, 6)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RO \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 2 : 3; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AP_RW \
|
||||
({ cpus_have_final_cap(ARM64_KVM_HVHE) ? 0 : 1; })
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH GENMASK(9, 8)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_SH_IS 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S1_AF BIT(10)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR GENMASK(5, 2)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R BIT(6)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W BIT(7)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_SH GENMASK(9, 8)
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_SH_IS 3
|
||||
#define KVM_PTE_LEAF_ATTR_LO_S2_AF BIT(10)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI GENMASK(63, 50)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_SW GENMASK(58, 55)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S2_XN BIT(54)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_HI_S1_GP BIT(50)
|
||||
|
||||
#define KVM_PTE_LEAF_ATTR_S2_PERMS (KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | \
|
||||
KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | \
|
||||
KVM_PTE_LEAF_ATTR_HI_S2_XN)
|
||||
|
||||
#define KVM_INVALID_PTE_OWNER_MASK GENMASK(9, 2)
|
||||
#define KVM_MAX_OWNER_ID 1
|
||||
|
||||
/*
|
||||
* Used to indicate a pte for which a 'break-before-make' sequence is in
|
||||
* progress.
|
||||
*/
|
||||
#define KVM_INVALID_PTE_LOCKED BIT(10)
|
||||
|
||||
struct kvm_pgtable_walk_data {
|
||||
struct kvm_pgtable_walker *walker;
|
||||
|
||||
@ -1547,7 +1505,6 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
*/
|
||||
new = kvm_init_table_pte(childp, mm_ops);
|
||||
stage2_make_pte(ctx, new);
|
||||
dsb(ishst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1559,8 +1516,11 @@ int kvm_pgtable_stage2_split(struct kvm_pgtable *pgt, u64 addr, u64 size,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF,
|
||||
.arg = mc,
|
||||
};
|
||||
int ret;
|
||||
|
||||
return kvm_pgtable_walk(pgt, addr, size, &walker);
|
||||
ret = kvm_pgtable_walk(pgt, addr, size, &walker);
|
||||
dsb(ishst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
|
||||
|
@ -268,8 +268,16 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
|
||||
* starting to mess with the rest of the GIC, and VMCR_EL2 in
|
||||
* particular. This logic must be called before
|
||||
* __vgic_v3_restore_state().
|
||||
*
|
||||
* However, if the vgic is disabled (ICH_HCR_EL2.EN==0), no GIC is
|
||||
* provisioned at all. In order to prevent illegal accesses to the
|
||||
* system registers to trap to EL1 (duh), force ICC_SRE_EL1.SRE to 1
|
||||
* so that the trap bits can take effect. Yes, we *loves* the GIC.
|
||||
*/
|
||||
if (!cpu_if->vgic_sre) {
|
||||
if (!(cpu_if->vgic_hcr & ICH_HCR_EN)) {
|
||||
write_gicreg(ICC_SRE_EL1_SRE, ICC_SRE_EL1);
|
||||
isb();
|
||||
} else if (!cpu_if->vgic_sre) {
|
||||
write_gicreg(0, ICC_SRE_EL1);
|
||||
isb();
|
||||
write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
|
||||
@ -288,8 +296,9 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevent the guest from touching the GIC system registers if
|
||||
* SRE isn't enabled for GICv3 emulation.
|
||||
* Prevent the guest from touching the ICC_SRE_EL1 system
|
||||
* register. Note that this may not have any effect, as
|
||||
* ICC_SRE_EL2.Enable being RAO/WI is a valid implementation.
|
||||
*/
|
||||
write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
|
||||
ICC_SRE_EL2);
|
||||
@ -297,10 +306,11 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if)
|
||||
/*
|
||||
* If we need to trap system registers, we must write
|
||||
* ICH_HCR_EL2 anyway, even if no interrupts are being
|
||||
* injected,
|
||||
* injected. Note that this also applies if we don't expect
|
||||
* any system register access (no vgic at all).
|
||||
*/
|
||||
if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
|
||||
cpu_if->its_vpe.its_vm)
|
||||
cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
|
||||
write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
|
||||
}
|
||||
|
||||
@ -326,7 +336,7 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if)
|
||||
* no interrupts were being injected, and we disable it again here.
|
||||
*/
|
||||
if (static_branch_unlikely(&vgic_v3_cpuif_trap) ||
|
||||
cpu_if->its_vpe.its_vm)
|
||||
cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre)
|
||||
write_gicreg(0, ICH_HCR_EL2);
|
||||
}
|
||||
|
||||
@ -1032,6 +1042,75 @@ static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
|
||||
write_gicreg(vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
static bool __vgic_v3_check_trap_forwarding(struct kvm_vcpu *vcpu,
|
||||
u32 sysreg, bool is_read)
|
||||
{
|
||||
u64 ich_hcr;
|
||||
|
||||
if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
|
||||
return false;
|
||||
|
||||
ich_hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2);
|
||||
|
||||
switch (sysreg) {
|
||||
case SYS_ICC_IGRPEN0_EL1:
|
||||
if (is_read &&
|
||||
(__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
|
||||
return true;
|
||||
|
||||
if (!is_read &&
|
||||
(__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
|
||||
return true;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SYS_ICC_AP0Rn_EL1(0):
|
||||
case SYS_ICC_AP0Rn_EL1(1):
|
||||
case SYS_ICC_AP0Rn_EL1(2):
|
||||
case SYS_ICC_AP0Rn_EL1(3):
|
||||
case SYS_ICC_BPR0_EL1:
|
||||
case SYS_ICC_EOIR0_EL1:
|
||||
case SYS_ICC_HPPIR0_EL1:
|
||||
case SYS_ICC_IAR0_EL1:
|
||||
return ich_hcr & ICH_HCR_TALL0;
|
||||
|
||||
case SYS_ICC_IGRPEN1_EL1:
|
||||
if (is_read &&
|
||||
(__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
|
||||
return true;
|
||||
|
||||
if (!is_read &&
|
||||
(__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
|
||||
return true;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SYS_ICC_AP1Rn_EL1(0):
|
||||
case SYS_ICC_AP1Rn_EL1(1):
|
||||
case SYS_ICC_AP1Rn_EL1(2):
|
||||
case SYS_ICC_AP1Rn_EL1(3):
|
||||
case SYS_ICC_BPR1_EL1:
|
||||
case SYS_ICC_EOIR1_EL1:
|
||||
case SYS_ICC_HPPIR1_EL1:
|
||||
case SYS_ICC_IAR1_EL1:
|
||||
return ich_hcr & ICH_HCR_TALL1;
|
||||
|
||||
case SYS_ICC_DIR_EL1:
|
||||
if (ich_hcr & ICH_HCR_TDIR)
|
||||
return true;
|
||||
|
||||
fallthrough;
|
||||
|
||||
case SYS_ICC_RPR_EL1:
|
||||
case SYS_ICC_CTLR_EL1:
|
||||
case SYS_ICC_PMR_EL1:
|
||||
return ich_hcr & ICH_HCR_TC;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int rt;
|
||||
@ -1041,6 +1120,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
||||
bool is_read;
|
||||
u32 sysreg;
|
||||
|
||||
if (kern_hyp_va(vcpu->kvm)->arch.vgic.vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
return 0;
|
||||
|
||||
esr = kvm_vcpu_get_esr(vcpu);
|
||||
if (vcpu_mode_is_32bit(vcpu)) {
|
||||
if (!kvm_condition_valid(vcpu)) {
|
||||
@ -1055,6 +1137,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
||||
|
||||
is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
|
||||
|
||||
if (__vgic_v3_check_trap_forwarding(vcpu, sysreg, is_read))
|
||||
return 0;
|
||||
|
||||
switch (sysreg) {
|
||||
case SYS_ICC_IAR0_EL1:
|
||||
case SYS_ICC_IAR1_EL1:
|
||||
|
@ -312,6 +312,9 @@ static bool kvm_hyp_handle_eret(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
__fpsimd_save_state(*host_data_ptr(fpsimd_state));
|
||||
|
||||
if (kvm_has_fpmr(vcpu->kvm))
|
||||
**host_data_ptr(fpmr_ptr) = read_sysreg_s(SYS_FPMR);
|
||||
}
|
||||
|
||||
static bool kvm_hyp_handle_tlbi_el2(struct kvm_vcpu *vcpu, u64 *exit_code)
|
||||
|
@ -1540,8 +1540,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
vma_pagesize = min(vma_pagesize, (long)max_map_size);
|
||||
}
|
||||
|
||||
if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
|
||||
/*
|
||||
* Both the canonical IPA and fault IPA must be hugepage-aligned to
|
||||
* ensure we find the right PFN and lay down the mapping in the right
|
||||
* place.
|
||||
*/
|
||||
if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) {
|
||||
fault_ipa &= ~(vma_pagesize - 1);
|
||||
ipa &= ~(vma_pagesize - 1);
|
||||
}
|
||||
|
||||
gfn = ipa >> PAGE_SHIFT;
|
||||
mte_allowed = kvm_vma_mte_allowed(vma);
|
||||
|
@ -103,20 +103,6 @@ struct s2_walk_info {
|
||||
bool be;
|
||||
};
|
||||
|
||||
static unsigned int ps_to_output_size(unsigned int ps)
|
||||
{
|
||||
switch (ps) {
|
||||
case 0: return 32;
|
||||
case 1: return 36;
|
||||
case 2: return 40;
|
||||
case 3: return 42;
|
||||
case 4: return 44;
|
||||
case 5:
|
||||
default:
|
||||
return 48;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 compute_fsc(int level, u32 fsc)
|
||||
{
|
||||
return fsc | (level & 0x3);
|
||||
@ -256,7 +242,7 @@ static int walk_nested_s2_pgd(phys_addr_t ipa,
|
||||
/* Check for valid descriptor at this point */
|
||||
if (!(desc & 1) || ((desc & 3) == 1 && level == 3)) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT);
|
||||
out->upper_attr = desc;
|
||||
out->desc = desc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -266,7 +252,7 @@ static int walk_nested_s2_pgd(phys_addr_t ipa,
|
||||
|
||||
if (check_output_size(wi, desc)) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ);
|
||||
out->upper_attr = desc;
|
||||
out->desc = desc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -278,27 +264,24 @@ static int walk_nested_s2_pgd(phys_addr_t ipa,
|
||||
|
||||
if (level < first_block_level) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_FAULT);
|
||||
out->upper_attr = desc;
|
||||
out->desc = desc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't use the contiguous bit in the stage-2 ptes, so skip check
|
||||
* for misprogramming of the contiguous bit.
|
||||
*/
|
||||
|
||||
if (check_output_size(wi, desc)) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ);
|
||||
out->upper_attr = desc;
|
||||
out->desc = desc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(desc & BIT(10))) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_ACCESS);
|
||||
out->upper_attr = desc;
|
||||
out->desc = desc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr_bottom += contiguous_bit_shift(desc, wi, level);
|
||||
|
||||
/* Calculate and return the result */
|
||||
paddr = (desc & GENMASK_ULL(47, addr_bottom)) |
|
||||
(ipa & GENMASK_ULL(addr_bottom - 1, 0));
|
||||
@ -307,7 +290,7 @@ static int walk_nested_s2_pgd(phys_addr_t ipa,
|
||||
out->readable = desc & (0b01 << 6);
|
||||
out->writable = desc & (0b10 << 6);
|
||||
out->level = level;
|
||||
out->upper_attr = desc & GENMASK_ULL(63, 52);
|
||||
out->desc = desc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -954,19 +937,16 @@ static void set_sysreg_masks(struct kvm *kvm, int sr, u64 res0, u64 res1)
|
||||
int kvm_init_nv_sysregs(struct kvm *kvm)
|
||||
{
|
||||
u64 res0, res1;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
lockdep_assert_held(&kvm->arch.config_lock);
|
||||
|
||||
if (kvm->arch.sysreg_masks)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
kvm->arch.sysreg_masks = kzalloc(sizeof(*(kvm->arch.sysreg_masks)),
|
||||
GFP_KERNEL_ACCOUNT);
|
||||
if (!kvm->arch.sysreg_masks) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!kvm->arch.sysreg_masks)
|
||||
return -ENOMEM;
|
||||
|
||||
limit_nv_id_regs(kvm);
|
||||
|
||||
@ -1195,8 +1175,13 @@ int kvm_init_nv_sysregs(struct kvm *kvm)
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, V1P1))
|
||||
res0 |= ~(res0 | res1);
|
||||
set_sysreg_masks(kvm, HAFGRTR_EL2, res0, res1);
|
||||
out:
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
|
||||
return ret;
|
||||
/* SCTLR_EL1 */
|
||||
res0 = SCTLR_EL1_RES0;
|
||||
res1 = SCTLR_EL1_RES1;
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, PAN, PAN3))
|
||||
res0 |= SCTLR_EL1_EPAN;
|
||||
set_sysreg_masks(kvm, SCTLR_EL1, res0, res1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
268
arch/arm64/kvm/ptdump.c
Normal file
268
arch/arm64/kvm/ptdump.c
Normal file
@ -0,0 +1,268 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Debug helper used to dump the stage-2 pagetables of the system and their
|
||||
* associated permissions.
|
||||
*
|
||||
* Copyright (C) Google, 2024
|
||||
* Author: Sebastian Ene <sebastianene@google.com>
|
||||
*/
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_pgtable.h>
|
||||
#include <asm/ptdump.h>
|
||||
|
||||
#define MARKERS_LEN 2
|
||||
#define KVM_PGTABLE_MAX_LEVELS (KVM_PGTABLE_LAST_LEVEL + 1)
|
||||
|
||||
struct kvm_ptdump_guest_state {
|
||||
struct kvm *kvm;
|
||||
struct ptdump_pg_state parser_state;
|
||||
struct addr_marker ipa_marker[MARKERS_LEN];
|
||||
struct ptdump_pg_level level[KVM_PGTABLE_MAX_LEVELS];
|
||||
struct ptdump_range range[MARKERS_LEN];
|
||||
};
|
||||
|
||||
static const struct ptdump_prot_bits stage2_pte_bits[] = {
|
||||
{
|
||||
.mask = PTE_VALID,
|
||||
.val = PTE_VALID,
|
||||
.set = " ",
|
||||
.clear = "F",
|
||||
}, {
|
||||
.mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID,
|
||||
.val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R | PTE_VALID,
|
||||
.set = "R",
|
||||
.clear = " ",
|
||||
}, {
|
||||
.mask = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID,
|
||||
.val = KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W | PTE_VALID,
|
||||
.set = "W",
|
||||
.clear = " ",
|
||||
}, {
|
||||
.mask = KVM_PTE_LEAF_ATTR_HI_S2_XN | PTE_VALID,
|
||||
.val = PTE_VALID,
|
||||
.set = " ",
|
||||
.clear = "X",
|
||||
}, {
|
||||
.mask = KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID,
|
||||
.val = KVM_PTE_LEAF_ATTR_LO_S2_AF | PTE_VALID,
|
||||
.set = "AF",
|
||||
.clear = " ",
|
||||
}, {
|
||||
.mask = PTE_TABLE_BIT | PTE_VALID,
|
||||
.val = PTE_VALID,
|
||||
.set = "BLK",
|
||||
.clear = " ",
|
||||
},
|
||||
};
|
||||
|
||||
static int kvm_ptdump_visitor(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
enum kvm_pgtable_walk_flags visit)
|
||||
{
|
||||
struct ptdump_pg_state *st = ctx->arg;
|
||||
struct ptdump_state *pt_st = &st->ptdump;
|
||||
|
||||
note_page(pt_st, ctx->addr, ctx->level, ctx->old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_ptdump_build_levels(struct ptdump_pg_level *level, u32 start_lvl)
|
||||
{
|
||||
u32 i;
|
||||
u64 mask;
|
||||
|
||||
if (WARN_ON_ONCE(start_lvl >= KVM_PGTABLE_LAST_LEVEL))
|
||||
return -EINVAL;
|
||||
|
||||
mask = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(stage2_pte_bits); i++)
|
||||
mask |= stage2_pte_bits[i].mask;
|
||||
|
||||
for (i = start_lvl; i < KVM_PGTABLE_MAX_LEVELS; i++) {
|
||||
snprintf(level[i].name, sizeof(level[i].name), "%u", i);
|
||||
|
||||
level[i].num = ARRAY_SIZE(stage2_pte_bits);
|
||||
level[i].bits = stage2_pte_bits;
|
||||
level[i].mask = mask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct kvm_ptdump_guest_state *kvm_ptdump_parser_create(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_ptdump_guest_state *st;
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.mmu;
|
||||
struct kvm_pgtable *pgtable = mmu->pgt;
|
||||
int ret;
|
||||
|
||||
st = kzalloc(sizeof(struct kvm_ptdump_guest_state), GFP_KERNEL_ACCOUNT);
|
||||
if (!st)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = kvm_ptdump_build_levels(&st->level[0], pgtable->start_level);
|
||||
if (ret) {
|
||||
kfree(st);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
st->ipa_marker[0].name = "Guest IPA";
|
||||
st->ipa_marker[1].start_address = BIT(pgtable->ia_bits);
|
||||
st->range[0].end = BIT(pgtable->ia_bits);
|
||||
|
||||
st->kvm = kvm;
|
||||
st->parser_state = (struct ptdump_pg_state) {
|
||||
.marker = &st->ipa_marker[0],
|
||||
.level = -1,
|
||||
.pg_level = &st->level[0],
|
||||
.ptdump.range = &st->range[0],
|
||||
.start_address = 0,
|
||||
};
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static int kvm_ptdump_guest_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
int ret;
|
||||
struct kvm_ptdump_guest_state *st = m->private;
|
||||
struct kvm *kvm = st->kvm;
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.mmu;
|
||||
struct ptdump_pg_state *parser_state = &st->parser_state;
|
||||
struct kvm_pgtable_walker walker = (struct kvm_pgtable_walker) {
|
||||
.cb = kvm_ptdump_visitor,
|
||||
.arg = parser_state,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF,
|
||||
};
|
||||
|
||||
parser_state->seq = m;
|
||||
|
||||
write_lock(&kvm->mmu_lock);
|
||||
ret = kvm_pgtable_walk(mmu->pgt, 0, BIT(mmu->pgt->ia_bits), &walker);
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_ptdump_guest_open(struct inode *m, struct file *file)
|
||||
{
|
||||
struct kvm *kvm = m->i_private;
|
||||
struct kvm_ptdump_guest_state *st;
|
||||
int ret;
|
||||
|
||||
if (!kvm_get_kvm_safe(kvm))
|
||||
return -ENOENT;
|
||||
|
||||
st = kvm_ptdump_parser_create(kvm);
|
||||
if (IS_ERR(st)) {
|
||||
ret = PTR_ERR(st);
|
||||
goto err_with_kvm_ref;
|
||||
}
|
||||
|
||||
ret = single_open(file, kvm_ptdump_guest_show, st);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
kfree(st);
|
||||
err_with_kvm_ref:
|
||||
kvm_put_kvm(kvm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_ptdump_guest_close(struct inode *m, struct file *file)
|
||||
{
|
||||
struct kvm *kvm = m->i_private;
|
||||
void *st = ((struct seq_file *)file->private_data)->private;
|
||||
|
||||
kfree(st);
|
||||
kvm_put_kvm(kvm);
|
||||
|
||||
return single_release(m, file);
|
||||
}
|
||||
|
||||
static const struct file_operations kvm_ptdump_guest_fops = {
|
||||
.open = kvm_ptdump_guest_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = kvm_ptdump_guest_close,
|
||||
};
|
||||
|
||||
static int kvm_pgtable_range_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct kvm_pgtable *pgtable = m->private;
|
||||
|
||||
seq_printf(m, "%2u\n", pgtable->ia_bits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_pgtable_levels_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct kvm_pgtable *pgtable = m->private;
|
||||
|
||||
seq_printf(m, "%1d\n", KVM_PGTABLE_MAX_LEVELS - pgtable->start_level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_pgtable_debugfs_open(struct inode *m, struct file *file,
|
||||
int (*show)(struct seq_file *, void *))
|
||||
{
|
||||
struct kvm *kvm = m->i_private;
|
||||
struct kvm_pgtable *pgtable;
|
||||
int ret;
|
||||
|
||||
if (!kvm_get_kvm_safe(kvm))
|
||||
return -ENOENT;
|
||||
|
||||
pgtable = kvm->arch.mmu.pgt;
|
||||
|
||||
ret = single_open(file, show, pgtable);
|
||||
if (ret < 0)
|
||||
kvm_put_kvm(kvm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvm_pgtable_range_open(struct inode *m, struct file *file)
|
||||
{
|
||||
return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_range_show);
|
||||
}
|
||||
|
||||
static int kvm_pgtable_levels_open(struct inode *m, struct file *file)
|
||||
{
|
||||
return kvm_pgtable_debugfs_open(m, file, kvm_pgtable_levels_show);
|
||||
}
|
||||
|
||||
static int kvm_pgtable_debugfs_close(struct inode *m, struct file *file)
|
||||
{
|
||||
struct kvm *kvm = m->i_private;
|
||||
|
||||
kvm_put_kvm(kvm);
|
||||
return single_release(m, file);
|
||||
}
|
||||
|
||||
static const struct file_operations kvm_pgtable_range_fops = {
|
||||
.open = kvm_pgtable_range_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = kvm_pgtable_debugfs_close,
|
||||
};
|
||||
|
||||
static const struct file_operations kvm_pgtable_levels_fops = {
|
||||
.open = kvm_pgtable_levels_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = kvm_pgtable_debugfs_close,
|
||||
};
|
||||
|
||||
void kvm_s2_ptdump_create_debugfs(struct kvm *kvm)
|
||||
{
|
||||
debugfs_create_file("stage2_page_tables", 0400, kvm->debugfs_dentry,
|
||||
kvm, &kvm_ptdump_guest_fops);
|
||||
debugfs_create_file("ipa_range", 0400, kvm->debugfs_dentry, kvm,
|
||||
&kvm_pgtable_range_fops);
|
||||
debugfs_create_file("stage2_levels", 0400, kvm->debugfs_dentry,
|
||||
kvm, &kvm_pgtable_levels_fops);
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
#include <trace/events/kvm.h>
|
||||
|
||||
#include "sys_regs.h"
|
||||
#include "vgic/vgic.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
@ -46,6 +47,13 @@ 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 undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool bad_trap(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *params,
|
||||
const struct sys_reg_desc *r,
|
||||
@ -53,8 +61,7 @@ static bool bad_trap(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
WARN_ONCE(1, "Unexpected %s\n", msg);
|
||||
print_sys_reg_instr(params);
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return undef_access(vcpu, params, r);
|
||||
}
|
||||
|
||||
static bool read_from_write_only(struct kvm_vcpu *vcpu,
|
||||
@ -345,10 +352,8 @@ static bool access_dcgsw(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (!kvm_has_mte(vcpu->kvm)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_has_mte(vcpu->kvm))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
/* Treat MTE S/W ops as we treat the classic ones: with contempt */
|
||||
return access_dcsw(vcpu, p, r);
|
||||
@ -385,10 +390,8 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
|
||||
u64 val, mask, shift;
|
||||
|
||||
if (reg_to_encoding(r) == SYS_TCR2_EL1 &&
|
||||
!kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
!kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, TCRX, IMP))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
BUG_ON(!p->is_write);
|
||||
|
||||
@ -435,6 +438,9 @@ static bool access_gic_sgi(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
bool g1;
|
||||
|
||||
if (!kvm_has_gicv3(vcpu->kvm))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
if (!p->is_write)
|
||||
return read_from_write_only(vcpu, p, r);
|
||||
|
||||
@ -478,6 +484,9 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (!kvm_has_gicv3(vcpu->kvm))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
if (p->is_write)
|
||||
return ignore_write(vcpu, p);
|
||||
|
||||
@ -495,14 +504,6 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
|
||||
return read_zero(vcpu, p);
|
||||
}
|
||||
|
||||
static bool trap_undef(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* ARMv8.1 mandates at least a trivial LORegion implementation, where all the
|
||||
* RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0
|
||||
@ -515,10 +516,8 @@ static bool trap_loregion(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
u32 sr = reg_to_encoding(r);
|
||||
|
||||
if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, LO, IMP)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_has_feat(vcpu->kvm, ID_AA64MMFR1_EL1, LO, IMP))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
if (p->is_write && sr == SYS_LORID_EL1)
|
||||
return write_to_read_only(vcpu, p, r);
|
||||
@ -1251,10 +1250,8 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write) {
|
||||
if (!vcpu_mode_priv(vcpu)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!vcpu_mode_priv(vcpu))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
__vcpu_sys_reg(vcpu, PMUSERENR_EL0) =
|
||||
p->regval & ARMV8_PMU_USERENR_MASK;
|
||||
@ -1338,14 +1335,6 @@ static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r,
|
||||
.reset = reset_pmevtyper, \
|
||||
.access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), }
|
||||
|
||||
static bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
kvm_inject_undefined(vcpu);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Macro to expand the AMU counter and type registers*/
|
||||
#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), undef_access }
|
||||
#define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access }
|
||||
@ -1404,8 +1393,7 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
|
||||
break;
|
||||
default:
|
||||
print_sys_reg_msg(p, "%s", "Unhandled trapped timer register");
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
return undef_access(vcpu, p, r);
|
||||
}
|
||||
|
||||
if (p->is_write)
|
||||
@ -1539,6 +1527,10 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
|
||||
|
||||
val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME);
|
||||
break;
|
||||
case SYS_ID_AA64PFR2_EL1:
|
||||
/* We only expose FPMR */
|
||||
val &= ID_AA64PFR2_EL1_FPMR;
|
||||
break;
|
||||
case SYS_ID_AA64ISAR1_EL1:
|
||||
if (!vcpu_has_ptrauth(vcpu))
|
||||
val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) |
|
||||
@ -1669,6 +1661,24 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
static unsigned int sme_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
if (kvm_has_feat(vcpu->kvm, ID_AA64PFR1_EL1, SME, IMP))
|
||||
return 0;
|
||||
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
static unsigned int fp8_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
if (kvm_has_fpmr(vcpu->kvm))
|
||||
return 0;
|
||||
|
||||
return REG_HIDDEN;
|
||||
}
|
||||
|
||||
static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
@ -2084,26 +2094,6 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu,
|
||||
#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
|
||||
* handling traps. Given that, they are always hidden from userspace.
|
||||
*/
|
||||
static unsigned int hidden_user_visibility(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *rd)
|
||||
{
|
||||
return REG_HIDDEN_USER;
|
||||
}
|
||||
|
||||
#define EL12_REG(name, acc, rst, v) { \
|
||||
SYS_DESC(SYS_##name##_EL12), \
|
||||
.access = acc, \
|
||||
.reset = rst, \
|
||||
.reg = name##_EL1, \
|
||||
.val = v, \
|
||||
.visibility = hidden_user_visibility, \
|
||||
}
|
||||
|
||||
/*
|
||||
* Since reset() callback and field val are not used for idregs, they will be
|
||||
* used for specific purposes for idregs.
|
||||
@ -2211,6 +2201,18 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool access_cntkctl_el12(struct kvm_vcpu *vcpu,
|
||||
struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (p->is_write)
|
||||
__vcpu_sys_reg(vcpu, CNTKCTL_EL1) = p->regval;
|
||||
else
|
||||
p->regval = __vcpu_sys_reg(vcpu, CNTKCTL_EL1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u64 reset_hcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
|
||||
{
|
||||
u64 val = r->val;
|
||||
@ -2301,7 +2303,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
// DBGDTR[TR]X_EL0 share the same encoding
|
||||
{ SYS_DESC(SYS_DBGDTRTX_EL0), trap_raz_wi },
|
||||
|
||||
{ SYS_DESC(SYS_DBGVCR32_EL2), trap_undef, reset_val, DBGVCR32_EL2, 0 },
|
||||
{ SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 },
|
||||
|
||||
{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
|
||||
|
||||
@ -2359,16 +2361,15 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
ID_AA64PFR0_EL1_MPAM |
|
||||
ID_AA64PFR0_EL1_SVE |
|
||||
ID_AA64PFR0_EL1_RAS |
|
||||
ID_AA64PFR0_EL1_GIC |
|
||||
ID_AA64PFR0_EL1_AdvSIMD |
|
||||
ID_AA64PFR0_EL1_FP), },
|
||||
ID_SANITISED(ID_AA64PFR1_EL1),
|
||||
ID_UNALLOCATED(4,2),
|
||||
ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR),
|
||||
ID_UNALLOCATED(4,3),
|
||||
ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0),
|
||||
ID_HIDDEN(ID_AA64SMFR0_EL1),
|
||||
ID_UNALLOCATED(4,6),
|
||||
ID_UNALLOCATED(4,7),
|
||||
ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0),
|
||||
|
||||
/* CRm=5 */
|
||||
{ SYS_DESC(SYS_ID_AA64DFR0_EL1),
|
||||
@ -2449,6 +2450,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_SPSR_EL1), access_spsr},
|
||||
{ SYS_DESC(SYS_ELR_EL1), access_elr},
|
||||
|
||||
{ SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
|
||||
|
||||
{ SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
|
||||
{ SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
|
||||
{ SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
|
||||
@ -2503,18 +2506,31 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 },
|
||||
{ SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 },
|
||||
|
||||
{ SYS_DESC(SYS_ICC_IAR0_EL1), write_to_read_only },
|
||||
{ SYS_DESC(SYS_ICC_EOIR0_EL1), read_from_write_only },
|
||||
{ SYS_DESC(SYS_ICC_HPPIR0_EL1), write_to_read_only },
|
||||
{ SYS_DESC(SYS_ICC_DIR_EL1), read_from_write_only },
|
||||
{ SYS_DESC(SYS_ICC_RPR_EL1), write_to_read_only },
|
||||
{ SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi },
|
||||
{ SYS_DESC(SYS_ICC_ASGI1R_EL1), access_gic_sgi },
|
||||
{ SYS_DESC(SYS_ICC_SGI0R_EL1), access_gic_sgi },
|
||||
{ SYS_DESC(SYS_ICC_IAR1_EL1), write_to_read_only },
|
||||
{ SYS_DESC(SYS_ICC_EOIR1_EL1), read_from_write_only },
|
||||
{ SYS_DESC(SYS_ICC_HPPIR1_EL1), write_to_read_only },
|
||||
{ SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
|
||||
{ SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
|
||||
{ SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
|
||||
|
||||
{ SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 },
|
||||
{ SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 },
|
||||
@ -2535,7 +2551,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
CTR_EL0_IDC_MASK |
|
||||
CTR_EL0_DminLine_MASK |
|
||||
CTR_EL0_IminLine_MASK),
|
||||
{ SYS_DESC(SYS_SVCR), undef_access },
|
||||
{ SYS_DESC(SYS_SVCR), undef_access, reset_val, SVCR, 0, .visibility = sme_visibility },
|
||||
{ SYS_DESC(SYS_FPMR), undef_access, reset_val, FPMR, 0, .visibility = fp8_visibility },
|
||||
|
||||
{ PMU_SYS_REG(PMCR_EL0), .access = access_pmcr, .reset = reset_pmcr,
|
||||
.reg = PMCR_EL0, .get_user = get_pmcr, .set_user = set_pmcr },
|
||||
@ -2758,7 +2775,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
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 },
|
||||
{ SYS_DESC(SYS_DACR32_EL2), undef_access, reset_unknown, DACR32_EL2 },
|
||||
EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
|
||||
EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
|
||||
@ -2767,20 +2784,16 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
{ SYS_DESC(SYS_SP_EL1), access_sp_el1},
|
||||
|
||||
/* AArch32 SPSR_* are RES0 if trapped from a NV guest */
|
||||
{ SYS_DESC(SYS_SPSR_irq), .access = trap_raz_wi,
|
||||
.visibility = hidden_user_visibility },
|
||||
{ SYS_DESC(SYS_SPSR_abt), .access = trap_raz_wi,
|
||||
.visibility = hidden_user_visibility },
|
||||
{ SYS_DESC(SYS_SPSR_und), .access = trap_raz_wi,
|
||||
.visibility = hidden_user_visibility },
|
||||
{ SYS_DESC(SYS_SPSR_fiq), .access = trap_raz_wi,
|
||||
.visibility = hidden_user_visibility },
|
||||
{ SYS_DESC(SYS_SPSR_irq), .access = trap_raz_wi },
|
||||
{ SYS_DESC(SYS_SPSR_abt), .access = trap_raz_wi },
|
||||
{ SYS_DESC(SYS_SPSR_und), .access = trap_raz_wi },
|
||||
{ SYS_DESC(SYS_SPSR_fiq), .access = trap_raz_wi },
|
||||
|
||||
{ SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 },
|
||||
{ SYS_DESC(SYS_IFSR32_EL2), undef_access, reset_unknown, IFSR32_EL2 },
|
||||
EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(AFSR1_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 },
|
||||
{ SYS_DESC(SYS_FPEXC32_EL2), undef_access, reset_val, FPEXC32_EL2, 0x700 },
|
||||
|
||||
EL2_REG_REDIR(FAR_EL2, reset_val, 0),
|
||||
EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
|
||||
@ -2790,7 +2803,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
|
||||
EL2_REG(VBAR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(RVBAR_EL2, access_rw, reset_val, 0),
|
||||
{ SYS_DESC(SYS_RMR_EL2), trap_undef },
|
||||
{ SYS_DESC(SYS_RMR_EL2), undef_access },
|
||||
|
||||
EL2_REG_VNCR(ICH_HCR_EL2, reset_val, 0),
|
||||
|
||||
EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
|
||||
EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
|
||||
@ -2798,11 +2813,48 @@ static const struct sys_reg_desc sys_reg_descs[] = {
|
||||
EL2_REG_VNCR(CNTVOFF_EL2, reset_val, 0),
|
||||
EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0),
|
||||
|
||||
EL12_REG(CNTKCTL, access_rw, reset_val, 0),
|
||||
{ SYS_DESC(SYS_CNTKCTL_EL12), access_cntkctl_el12 },
|
||||
|
||||
EL2_REG(SP_EL2, NULL, reset_unknown, 0),
|
||||
};
|
||||
|
||||
static bool handle_at_s1e01(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u32 op = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
|
||||
__kvm_at_s1e01(vcpu, op, p->regval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_at_s1e2(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u32 op = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
|
||||
/* There is no FGT associated with AT S1E2A :-( */
|
||||
if (op == OP_AT_S1E2A &&
|
||||
!kvm_has_feat(vcpu->kvm, ID_AA64ISAR2_EL1, ATS1A, IMP)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
__kvm_at_s1e2(vcpu, op, p->regval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool handle_at_s12(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
u32 op = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
|
||||
__kvm_at_s12(vcpu, op, p->regval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool kvm_supported_tlbi_s12_op(struct kvm_vcpu *vpcu, u32 instr)
|
||||
{
|
||||
struct kvm *kvm = vpcu->kvm;
|
||||
@ -2824,10 +2876,8 @@ static bool handle_alle1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
{
|
||||
u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
|
||||
if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
write_lock(&vcpu->kvm->mmu_lock);
|
||||
|
||||
@ -2896,10 +2946,8 @@ static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
u64 limit, vttbr;
|
||||
|
||||
if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_supported_tlbi_s12_op(vcpu, sys_encoding))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
|
||||
limit = BIT_ULL(kvm_get_pa_bits(vcpu->kvm));
|
||||
@ -2924,10 +2972,8 @@ static bool handle_ripas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
u64 base, range, tg, num, scale;
|
||||
int shift;
|
||||
|
||||
if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
/*
|
||||
* Because the shadow S2 structure doesn't necessarily reflect that
|
||||
@ -2995,10 +3041,8 @@ static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
u32 sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
|
||||
u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
|
||||
|
||||
if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_supported_tlbi_ipas2_op(vcpu, sys_encoding))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
|
||||
&(union tlbi_info) {
|
||||
@ -3038,10 +3082,8 @@ static bool handle_tlbi_el1(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
|
||||
|
||||
WARN_ON(!vcpu_is_el2(vcpu));
|
||||
|
||||
if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding)) {
|
||||
kvm_inject_undefined(vcpu);
|
||||
return false;
|
||||
}
|
||||
if (!kvm_supported_tlbi_s1e1_op(vcpu, sys_encoding))
|
||||
return undef_access(vcpu, p, r);
|
||||
|
||||
kvm_s2_mmu_iterate_by_vmid(vcpu->kvm, get_vmid(vttbr),
|
||||
&(union tlbi_info) {
|
||||
@ -3065,6 +3107,14 @@ static struct sys_reg_desc sys_insn_descs[] = {
|
||||
{ SYS_DESC(SYS_DC_ISW), access_dcsw },
|
||||
{ SYS_DESC(SYS_DC_IGSW), access_dcgsw },
|
||||
{ SYS_DESC(SYS_DC_IGDSW), access_dcgsw },
|
||||
|
||||
SYS_INSN(AT_S1E1R, handle_at_s1e01),
|
||||
SYS_INSN(AT_S1E1W, handle_at_s1e01),
|
||||
SYS_INSN(AT_S1E0R, handle_at_s1e01),
|
||||
SYS_INSN(AT_S1E0W, handle_at_s1e01),
|
||||
SYS_INSN(AT_S1E1RP, handle_at_s1e01),
|
||||
SYS_INSN(AT_S1E1WP, handle_at_s1e01),
|
||||
|
||||
{ SYS_DESC(SYS_DC_CSW), access_dcsw },
|
||||
{ SYS_DESC(SYS_DC_CGSW), access_dcgsw },
|
||||
{ SYS_DESC(SYS_DC_CGDSW), access_dcgsw },
|
||||
@ -3144,19 +3194,27 @@ static struct sys_reg_desc sys_insn_descs[] = {
|
||||
SYS_INSN(TLBI_VALE1NXS, handle_tlbi_el1),
|
||||
SYS_INSN(TLBI_VAALE1NXS, handle_tlbi_el1),
|
||||
|
||||
SYS_INSN(AT_S1E2R, handle_at_s1e2),
|
||||
SYS_INSN(AT_S1E2W, handle_at_s1e2),
|
||||
SYS_INSN(AT_S12E1R, handle_at_s12),
|
||||
SYS_INSN(AT_S12E1W, handle_at_s12),
|
||||
SYS_INSN(AT_S12E0R, handle_at_s12),
|
||||
SYS_INSN(AT_S12E0W, handle_at_s12),
|
||||
SYS_INSN(AT_S1E2A, handle_at_s1e2),
|
||||
|
||||
SYS_INSN(TLBI_IPAS2E1IS, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2E1IS, handle_ripas2e1is),
|
||||
SYS_INSN(TLBI_IPAS2LE1IS, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1IS, handle_ripas2e1is),
|
||||
|
||||
SYS_INSN(TLBI_ALLE2OS, trap_undef),
|
||||
SYS_INSN(TLBI_VAE2OS, trap_undef),
|
||||
SYS_INSN(TLBI_ALLE2OS, undef_access),
|
||||
SYS_INSN(TLBI_VAE2OS, undef_access),
|
||||
SYS_INSN(TLBI_ALLE1OS, handle_alle1is),
|
||||
SYS_INSN(TLBI_VALE2OS, trap_undef),
|
||||
SYS_INSN(TLBI_VALE2OS, undef_access),
|
||||
SYS_INSN(TLBI_VMALLS12E1OS, handle_vmalls12e1is),
|
||||
|
||||
SYS_INSN(TLBI_RVAE2IS, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2IS, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2IS, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2IS, undef_access),
|
||||
|
||||
SYS_INSN(TLBI_ALLE1IS, handle_alle1is),
|
||||
SYS_INSN(TLBI_VMALLS12E1IS, handle_vmalls12e1is),
|
||||
@ -3168,10 +3226,10 @@ static struct sys_reg_desc sys_insn_descs[] = {
|
||||
SYS_INSN(TLBI_IPAS2LE1, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1, handle_ripas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1OS, handle_ripas2e1is),
|
||||
SYS_INSN(TLBI_RVAE2OS, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2OS, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2OS, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2OS, undef_access),
|
||||
SYS_INSN(TLBI_RVAE2, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2, undef_access),
|
||||
SYS_INSN(TLBI_ALLE1, handle_alle1is),
|
||||
SYS_INSN(TLBI_VMALLS12E1, handle_vmalls12e1is),
|
||||
|
||||
@ -3180,19 +3238,19 @@ static struct sys_reg_desc sys_insn_descs[] = {
|
||||
SYS_INSN(TLBI_IPAS2LE1ISNXS, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1ISNXS, handle_ripas2e1is),
|
||||
|
||||
SYS_INSN(TLBI_ALLE2OSNXS, trap_undef),
|
||||
SYS_INSN(TLBI_VAE2OSNXS, trap_undef),
|
||||
SYS_INSN(TLBI_ALLE2OSNXS, undef_access),
|
||||
SYS_INSN(TLBI_VAE2OSNXS, undef_access),
|
||||
SYS_INSN(TLBI_ALLE1OSNXS, handle_alle1is),
|
||||
SYS_INSN(TLBI_VALE2OSNXS, trap_undef),
|
||||
SYS_INSN(TLBI_VALE2OSNXS, undef_access),
|
||||
SYS_INSN(TLBI_VMALLS12E1OSNXS, handle_vmalls12e1is),
|
||||
|
||||
SYS_INSN(TLBI_RVAE2ISNXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2ISNXS, trap_undef),
|
||||
SYS_INSN(TLBI_ALLE2ISNXS, trap_undef),
|
||||
SYS_INSN(TLBI_VAE2ISNXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2ISNXS, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2ISNXS, undef_access),
|
||||
SYS_INSN(TLBI_ALLE2ISNXS, undef_access),
|
||||
SYS_INSN(TLBI_VAE2ISNXS, undef_access),
|
||||
|
||||
SYS_INSN(TLBI_ALLE1ISNXS, handle_alle1is),
|
||||
SYS_INSN(TLBI_VALE2ISNXS, trap_undef),
|
||||
SYS_INSN(TLBI_VALE2ISNXS, undef_access),
|
||||
SYS_INSN(TLBI_VMALLS12E1ISNXS, handle_vmalls12e1is),
|
||||
SYS_INSN(TLBI_IPAS2E1OSNXS, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_IPAS2E1NXS, handle_ipas2e1is),
|
||||
@ -3202,14 +3260,14 @@ static struct sys_reg_desc sys_insn_descs[] = {
|
||||
SYS_INSN(TLBI_IPAS2LE1NXS, handle_ipas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1NXS, handle_ripas2e1is),
|
||||
SYS_INSN(TLBI_RIPAS2LE1OSNXS, handle_ripas2e1is),
|
||||
SYS_INSN(TLBI_RVAE2OSNXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2OSNXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2NXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVALE2NXS, trap_undef),
|
||||
SYS_INSN(TLBI_ALLE2NXS, trap_undef),
|
||||
SYS_INSN(TLBI_VAE2NXS, trap_undef),
|
||||
SYS_INSN(TLBI_RVAE2OSNXS, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2OSNXS, undef_access),
|
||||
SYS_INSN(TLBI_RVAE2NXS, undef_access),
|
||||
SYS_INSN(TLBI_RVALE2NXS, undef_access),
|
||||
SYS_INSN(TLBI_ALLE2NXS, undef_access),
|
||||
SYS_INSN(TLBI_VAE2NXS, undef_access),
|
||||
SYS_INSN(TLBI_ALLE1NXS, handle_alle1is),
|
||||
SYS_INSN(TLBI_VALE2NXS, trap_undef),
|
||||
SYS_INSN(TLBI_VALE2NXS, undef_access),
|
||||
SYS_INSN(TLBI_VMALLS12E1NXS, handle_vmalls12e1is),
|
||||
};
|
||||
|
||||
@ -3387,6 +3445,7 @@ static const struct sys_reg_desc cp15_regs[] = {
|
||||
/* TTBCR2 */
|
||||
{ AA32(HI), Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, TCR_EL1 },
|
||||
{ Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, DACR32_EL2 },
|
||||
{ CP15_SYS_DESC(SYS_ICC_PMR_EL1), undef_access },
|
||||
/* DFSR */
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, ESR_EL1 },
|
||||
{ Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, IFSR32_EL2 },
|
||||
@ -3436,8 +3495,28 @@ static const struct sys_reg_desc cp15_regs[] = {
|
||||
/* AMAIR1 */
|
||||
{ AA32(HI), Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, AMAIR_EL1 },
|
||||
|
||||
/* ICC_SRE */
|
||||
{ Op1( 0), CRn(12), CRm(12), Op2( 5), access_gic_sre },
|
||||
{ CP15_SYS_DESC(SYS_ICC_IAR0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_EOIR0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_HPPIR0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_BPR0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP0R0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP0R1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP0R2_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP0R3_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP1R0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_DIR_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_RPR_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_IAR1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_HPPIR1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_BPR1_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_CTLR_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre },
|
||||
{ CP15_SYS_DESC(SYS_ICC_IGRPEN0_EL1), undef_access },
|
||||
{ CP15_SYS_DESC(SYS_ICC_IGRPEN1_EL1), undef_access },
|
||||
|
||||
{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, CONTEXTIDR_EL1 },
|
||||
|
||||
@ -4274,7 +4353,7 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
|
||||
int ret;
|
||||
|
||||
r = id_to_sys_reg_desc(vcpu, reg->id, table, num);
|
||||
if (!r || sysreg_hidden_user(vcpu, r))
|
||||
if (!r || sysreg_hidden(vcpu, r))
|
||||
return -ENOENT;
|
||||
|
||||
if (r->get_user) {
|
||||
@ -4318,7 +4397,7 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
|
||||
return -EFAULT;
|
||||
|
||||
r = id_to_sys_reg_desc(vcpu, reg->id, table, num);
|
||||
if (!r || sysreg_hidden_user(vcpu, r))
|
||||
if (!r || sysreg_hidden(vcpu, r))
|
||||
return -ENOENT;
|
||||
|
||||
if (sysreg_user_write_ignore(vcpu, r))
|
||||
@ -4404,7 +4483,7 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
|
||||
if (!(rd->reg || rd->get_user))
|
||||
return 0;
|
||||
|
||||
if (sysreg_hidden_user(vcpu, rd))
|
||||
if (sysreg_hidden(vcpu, rd))
|
||||
return 0;
|
||||
|
||||
if (!copy_reg_to_user(rd, uind))
|
||||
@ -4545,6 +4624,7 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
|
||||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
vcpu_set_hcr(vcpu);
|
||||
vcpu_set_ich_hcr(vcpu);
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_HCX)) {
|
||||
/*
|
||||
@ -4560,6 +4640,9 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (kvm_has_feat(kvm, ID_AA64MMFR3_EL1, TCRX, IMP))
|
||||
vcpu->arch.hcrx_el2 |= HCRX_EL2_TCR2En;
|
||||
|
||||
if (kvm_has_fpmr(kvm))
|
||||
vcpu->arch.hcrx_el2 |= HCRX_EL2_EnFPM;
|
||||
}
|
||||
|
||||
if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags))
|
||||
@ -4600,6 +4683,13 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
|
||||
HFGITR_EL2_TLBIRVAAE1OS |
|
||||
HFGITR_EL2_TLBIRVAE1OS);
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, ATS1A, IMP))
|
||||
kvm->arch.fgu[HFGITR_GROUP] |= HFGITR_EL2_ATS1E1A;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, PAN, PAN2))
|
||||
kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_ATS1E1RP |
|
||||
HFGITR_EL2_ATS1E1WP);
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1PIE, IMP))
|
||||
kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPIRE0_EL1 |
|
||||
HFGxTR_EL2_nPIR_EL1);
|
||||
@ -4613,6 +4703,36 @@ out:
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform last adjustments to the ID registers that are implied by the
|
||||
* configuration outside of the ID regs themselves, as well as any
|
||||
* initialisation that directly depend on these ID registers (such as
|
||||
* RES0/RES1 behaviours). This is not the place to configure traps though.
|
||||
*
|
||||
* Because this can be called once per CPU, changes must be idempotent.
|
||||
*/
|
||||
int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
|
||||
guard(mutex)(&kvm->arch.config_lock);
|
||||
|
||||
if (!(static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) &&
|
||||
irqchip_in_kernel(kvm) &&
|
||||
kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)) {
|
||||
kvm->arch.id_regs[IDREG_IDX(SYS_ID_AA64PFR0_EL1)] &= ~ID_AA64PFR0_EL1_GIC_MASK;
|
||||
kvm->arch.id_regs[IDREG_IDX(SYS_ID_PFR1_EL1)] &= ~ID_PFR1_EL1_GIC_MASK;
|
||||
}
|
||||
|
||||
if (vcpu_has_nv(vcpu)) {
|
||||
int ret = kvm_init_nv_sysregs(kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init kvm_sys_reg_table_init(void)
|
||||
{
|
||||
bool valid = true;
|
||||
|
@ -95,9 +95,8 @@ struct sys_reg_desc {
|
||||
};
|
||||
|
||||
#define REG_HIDDEN (1 << 0) /* hidden from userspace and guest */
|
||||
#define REG_HIDDEN_USER (1 << 1) /* hidden from userspace only */
|
||||
#define REG_RAZ (1 << 2) /* RAZ from userspace and guest */
|
||||
#define REG_USER_WI (1 << 3) /* WI from userspace only */
|
||||
#define REG_RAZ (1 << 1) /* RAZ from userspace and guest */
|
||||
#define REG_USER_WI (1 << 2) /* WI from userspace only */
|
||||
|
||||
static __printf(2, 3)
|
||||
inline void print_sys_reg_msg(const struct sys_reg_params *p,
|
||||
@ -165,15 +164,6 @@ static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
|
||||
return sysreg_visibility(vcpu, r) & REG_HIDDEN;
|
||||
}
|
||||
|
||||
static inline bool sysreg_hidden_user(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
if (likely(!r->visibility))
|
||||
return false;
|
||||
|
||||
return r->visibility(vcpu, r) & (REG_HIDDEN | REG_HIDDEN_USER);
|
||||
}
|
||||
|
||||
static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
|
||||
const struct sys_reg_desc *r)
|
||||
{
|
||||
@ -235,6 +225,8 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
|
||||
|
||||
bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index);
|
||||
|
||||
int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
|
||||
|
||||
#define AA32(_x) .aarch32_map = AA32_##_x
|
||||
#define Op0(_x) .Op0 = _x
|
||||
#define Op1(_x) .Op1 = _x
|
||||
@ -248,4 +240,11 @@ bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index);
|
||||
CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \
|
||||
Op2(sys_reg_Op2(reg))
|
||||
|
||||
#define CP15_SYS_DESC(reg) \
|
||||
.name = #reg, \
|
||||
.aarch32_map = AA32_DIRECT, \
|
||||
Op0(0), Op1(sys_reg_Op1(reg)), \
|
||||
CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \
|
||||
Op2(sys_reg_Op2(reg))
|
||||
|
||||
#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
|
||||
|
@ -85,7 +85,7 @@ static void iter_unmark_lpis(struct kvm *kvm)
|
||||
struct vgic_irq *irq;
|
||||
unsigned long intid;
|
||||
|
||||
xa_for_each(&dist->lpi_xa, intid, irq) {
|
||||
xa_for_each_marked(&dist->lpi_xa, intid, irq, LPI_XA_MARK_DEBUG_ITER) {
|
||||
xa_clear_mark(&dist->lpi_xa, intid, LPI_XA_MARK_DEBUG_ITER);
|
||||
vgic_put_irq(kvm, irq);
|
||||
}
|
||||
|
@ -417,10 +417,8 @@ static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
kfree(vgic_cpu->private_irqs);
|
||||
vgic_cpu->private_irqs = NULL;
|
||||
|
||||
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
|
||||
vgic_unregister_redist_iodev(vcpu);
|
||||
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
|
||||
}
|
||||
}
|
||||
|
||||
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
|
||||
@ -448,6 +446,11 @@ void kvm_vgic_destroy(struct kvm *kvm)
|
||||
kvm_vgic_dist_destroy(kvm);
|
||||
|
||||
mutex_unlock(&kvm->arch.config_lock);
|
||||
|
||||
if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
kvm_for_each_vcpu(i, vcpu, kvm)
|
||||
vgic_unregister_redist_iodev(vcpu);
|
||||
|
||||
mutex_unlock(&kvm->slots_lock);
|
||||
}
|
||||
|
||||
|
@ -292,6 +292,18 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
|
||||
|
||||
/* Get the show on the road... */
|
||||
vgic_v3->vgic_hcr = ICH_HCR_EN;
|
||||
}
|
||||
|
||||
void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
||||
/* Hide GICv3 sysreg if necessary */
|
||||
if (!kvm_has_gicv3(vcpu->kvm)) {
|
||||
vgic_v3->vgic_hcr |= ICH_HCR_TALL0 | ICH_HCR_TALL1 | ICH_HCR_TC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (group0_trap)
|
||||
vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
|
||||
if (group1_trap)
|
||||
|
@ -36,6 +36,11 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = {
|
||||
* we have to disable IRQs before taking this lock and everything lower
|
||||
* than it.
|
||||
*
|
||||
* The config_lock has additional ordering requirements:
|
||||
* kvm->slots_lock
|
||||
* kvm->srcu
|
||||
* kvm->arch.config_lock
|
||||
*
|
||||
* If you need to take multiple locks, always take the upper lock first,
|
||||
* then the lower ones, e.g. first take the its_lock, then the irq_lock.
|
||||
* If you are already holding a lock and need to take a higher one, you
|
||||
@ -917,10 +922,13 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
|
||||
void kvm_vgic_load(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
|
||||
if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
|
||||
__vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
|
||||
vgic_v2_load(vcpu);
|
||||
else
|
||||
vgic_v3_load(vcpu);
|
||||
@ -928,10 +936,13 @@ void kvm_vgic_load(struct kvm_vcpu *vcpu)
|
||||
|
||||
void kvm_vgic_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
if (unlikely(!irqchip_in_kernel(vcpu->kvm) || !vgic_initialized(vcpu->kvm))) {
|
||||
if (has_vhe() && static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
|
||||
__vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
|
||||
vgic_v2_put(vcpu);
|
||||
else
|
||||
vgic_v3_put(vcpu);
|
||||
|
@ -346,4 +346,11 @@ void vgic_v4_configure_vsgis(struct kvm *kvm);
|
||||
void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val);
|
||||
int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq);
|
||||
|
||||
void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline bool kvm_has_gicv3(struct kvm *kvm)
|
||||
{
|
||||
return kvm_has_feat(kvm, ID_AA64PFR0_EL1, GIC, IMP);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -38,33 +38,7 @@
|
||||
seq_printf(m, fmt); \
|
||||
})
|
||||
|
||||
/*
|
||||
* The page dumper groups page table entries of the same type into a single
|
||||
* description. It uses pg_state to track the range information while
|
||||
* iterating over the pte entries. When the continuity is broken it then
|
||||
* dumps out a description of the range.
|
||||
*/
|
||||
struct pg_state {
|
||||
struct ptdump_state ptdump;
|
||||
struct seq_file *seq;
|
||||
const struct addr_marker *marker;
|
||||
const struct mm_struct *mm;
|
||||
unsigned long start_address;
|
||||
int level;
|
||||
u64 current_prot;
|
||||
bool check_wx;
|
||||
unsigned long wx_pages;
|
||||
unsigned long uxn_pages;
|
||||
};
|
||||
|
||||
struct prot_bits {
|
||||
u64 mask;
|
||||
u64 val;
|
||||
const char *set;
|
||||
const char *clear;
|
||||
};
|
||||
|
||||
static const struct prot_bits pte_bits[] = {
|
||||
static const struct ptdump_prot_bits pte_bits[] = {
|
||||
{
|
||||
.mask = PTE_VALID,
|
||||
.val = PTE_VALID,
|
||||
@ -143,14 +117,7 @@ static const struct prot_bits pte_bits[] = {
|
||||
}
|
||||
};
|
||||
|
||||
struct pg_level {
|
||||
const struct prot_bits *bits;
|
||||
char name[4];
|
||||
int num;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
static struct pg_level pg_level[] __ro_after_init = {
|
||||
static struct ptdump_pg_level kernel_pg_levels[] __ro_after_init = {
|
||||
{ /* pgd */
|
||||
.name = "PGD",
|
||||
.bits = pte_bits,
|
||||
@ -174,7 +141,7 @@ static struct pg_level pg_level[] __ro_after_init = {
|
||||
},
|
||||
};
|
||||
|
||||
static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
|
||||
static void dump_prot(struct ptdump_pg_state *st, const struct ptdump_prot_bits *bits,
|
||||
size_t num)
|
||||
{
|
||||
unsigned i;
|
||||
@ -192,7 +159,7 @@ static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
|
||||
}
|
||||
}
|
||||
|
||||
static void note_prot_uxn(struct pg_state *st, unsigned long addr)
|
||||
static void note_prot_uxn(struct ptdump_pg_state *st, unsigned long addr)
|
||||
{
|
||||
if (!st->check_wx)
|
||||
return;
|
||||
@ -206,7 +173,7 @@ static void note_prot_uxn(struct pg_state *st, unsigned long addr)
|
||||
st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
|
||||
}
|
||||
|
||||
static void note_prot_wx(struct pg_state *st, unsigned long addr)
|
||||
static void note_prot_wx(struct ptdump_pg_state *st, unsigned long addr)
|
||||
{
|
||||
if (!st->check_wx)
|
||||
return;
|
||||
@ -221,16 +188,17 @@ static void note_prot_wx(struct pg_state *st, unsigned long addr)
|
||||
st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
|
||||
}
|
||||
|
||||
static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
|
||||
u64 val)
|
||||
void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
|
||||
u64 val)
|
||||
{
|
||||
struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
|
||||
struct ptdump_pg_state *st = container_of(pt_st, struct ptdump_pg_state, ptdump);
|
||||
struct ptdump_pg_level *pg_level = st->pg_level;
|
||||
static const char units[] = "KMGTPE";
|
||||
u64 prot = 0;
|
||||
|
||||
/* check if the current level has been folded dynamically */
|
||||
if ((level == 1 && mm_p4d_folded(st->mm)) ||
|
||||
(level == 2 && mm_pud_folded(st->mm)))
|
||||
if (st->mm && ((level == 1 && mm_p4d_folded(st->mm)) ||
|
||||
(level == 2 && mm_pud_folded(st->mm))))
|
||||
level = 0;
|
||||
|
||||
if (level >= 0)
|
||||
@ -286,15 +254,16 @@ static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
|
||||
void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
|
||||
{
|
||||
unsigned long end = ~0UL;
|
||||
struct pg_state st;
|
||||
struct ptdump_pg_state st;
|
||||
|
||||
if (info->base_addr < TASK_SIZE_64)
|
||||
end = TASK_SIZE_64;
|
||||
|
||||
st = (struct pg_state){
|
||||
st = (struct ptdump_pg_state){
|
||||
.seq = s,
|
||||
.marker = info->markers,
|
||||
.mm = info->mm,
|
||||
.pg_level = &kernel_pg_levels[0],
|
||||
.level = -1,
|
||||
.ptdump = {
|
||||
.note_page = note_page,
|
||||
@ -312,10 +281,10 @@ static void __init ptdump_initialize(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pg_level); i++)
|
||||
if (pg_level[i].bits)
|
||||
for (j = 0; j < pg_level[i].num; j++)
|
||||
pg_level[i].mask |= pg_level[i].bits[j].mask;
|
||||
for (i = 0; i < ARRAY_SIZE(kernel_pg_levels); i++)
|
||||
if (kernel_pg_levels[i].bits)
|
||||
for (j = 0; j < kernel_pg_levels[i].num; j++)
|
||||
kernel_pg_levels[i].mask |= kernel_pg_levels[i].bits[j].mask;
|
||||
}
|
||||
|
||||
static struct ptdump_info kernel_ptdump_info __ro_after_init = {
|
||||
@ -324,12 +293,13 @@ static struct ptdump_info kernel_ptdump_info __ro_after_init = {
|
||||
|
||||
bool ptdump_check_wx(void)
|
||||
{
|
||||
struct pg_state st = {
|
||||
struct ptdump_pg_state st = {
|
||||
.seq = NULL,
|
||||
.marker = (struct addr_marker[]) {
|
||||
{ 0, NULL},
|
||||
{ -1, NULL},
|
||||
},
|
||||
.pg_level = &kernel_pg_levels[0],
|
||||
.level = -1,
|
||||
.check_wx = true,
|
||||
.ptdump = {
|
||||
|
@ -303,13 +303,6 @@ int r4k_clockevent_init(void)
|
||||
if (!c0_compare_int_usable())
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* With vectored interrupts things are getting platform specific.
|
||||
* get_c0_compare_int is a hook to allow a platform to return the
|
||||
* interrupt number of its liking.
|
||||
*/
|
||||
irq = get_c0_compare_int();
|
||||
|
||||
cd = &per_cpu(mips_clockevent_device, cpu);
|
||||
|
||||
cd->name = "MIPS";
|
||||
@ -320,7 +313,6 @@ int r4k_clockevent_init(void)
|
||||
min_delta = calculate_min_delta();
|
||||
|
||||
cd->rating = 300;
|
||||
cd->irq = irq;
|
||||
cd->cpumask = cpumask_of(cpu);
|
||||
cd->set_next_event = mips_next_event;
|
||||
cd->event_handler = mips_event_handler;
|
||||
@ -332,6 +324,13 @@ int r4k_clockevent_init(void)
|
||||
|
||||
cp0_timer_irq_installed = 1;
|
||||
|
||||
/*
|
||||
* With vectored interrupts things are getting platform specific.
|
||||
* get_c0_compare_int is a hook to allow a platform to return the
|
||||
* interrupt number of its liking.
|
||||
*/
|
||||
irq = get_c0_compare_int();
|
||||
|
||||
if (request_irq(irq, c0_compare_interrupt, flags, "timer",
|
||||
c0_compare_interrupt))
|
||||
pr_err("Failed to request irq %d (timer)\n", irq);
|
||||
|
@ -1724,12 +1724,16 @@ static inline void cpu_probe_loongson(struct cpuinfo_mips *c, unsigned int cpu)
|
||||
c->ases |= (MIPS_ASE_LOONGSON_MMI | MIPS_ASE_LOONGSON_CAM |
|
||||
MIPS_ASE_LOONGSON_EXT | MIPS_ASE_LOONGSON_EXT2);
|
||||
c->ases &= ~MIPS_ASE_VZ; /* VZ of Loongson-3A2000/3000 is incomplete */
|
||||
change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER,
|
||||
LOONGSON_CONF6_INTIMER);
|
||||
break;
|
||||
case PRID_IMP_LOONGSON_64G:
|
||||
__cpu_name[cpu] = "ICT Loongson-3";
|
||||
set_elf_platform(cpu, "loongson3a");
|
||||
set_isa(c, MIPS_CPU_ISA_M64R2);
|
||||
decode_cpucfg(c);
|
||||
change_c0_config6(LOONGSON_CONF6_EXTIMER | LOONGSON_CONF6_INTIMER,
|
||||
LOONGSON_CONF6_INTIMER);
|
||||
break;
|
||||
default:
|
||||
panic("Unknown Loongson Processor ID!");
|
||||
|
@ -111,7 +111,7 @@ void gio_device_unregister(struct gio_device *giodev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gio_device_unregister);
|
||||
|
||||
static int gio_bus_match(struct device *dev, struct device_driver *drv)
|
||||
static int gio_bus_match(struct device *dev, const struct device_driver *drv)
|
||||
{
|
||||
struct gio_device *gio_dev = to_gio_device(dev);
|
||||
struct gio_driver *gio_drv = to_gio_driver(drv);
|
||||
|
@ -145,6 +145,7 @@ static inline int cpu_to_coregroup_id(int cpu)
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
#include <linux/cpu_smt.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <asm/cputhreads.h>
|
||||
|
||||
static inline bool topology_is_primary_thread(unsigned int cpu)
|
||||
@ -156,6 +157,18 @@ static inline bool topology_smt_thread_allowed(unsigned int cpu)
|
||||
{
|
||||
return cpu_thread_in_core(cpu) < cpu_smt_num_threads;
|
||||
}
|
||||
|
||||
#define topology_is_core_online topology_is_core_online
|
||||
static inline bool topology_is_core_online(unsigned int cpu)
|
||||
{
|
||||
int i, first_cpu = cpu_first_thread_sibling(cpu);
|
||||
|
||||
for (i = first_cpu; i < first_cpu + threads_per_core; ++i) {
|
||||
if (cpu_online(i))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
@ -959,6 +959,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
mem_topology_setup();
|
||||
/* Set max_mapnr before paging_init() */
|
||||
set_max_mapnr(max_pfn);
|
||||
high_memory = (void *)__va(max_low_pfn * PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Release secondary cpus out of their spinloops at 0x60 now that
|
||||
|
@ -73,7 +73,7 @@ void setup_kup(void)
|
||||
|
||||
#define CTOR(shift) static void ctor_##shift(void *addr) \
|
||||
{ \
|
||||
memset(addr, 0, sizeof(void *) << (shift)); \
|
||||
memset(addr, 0, sizeof(pgd_t) << (shift)); \
|
||||
}
|
||||
|
||||
CTOR(0); CTOR(1); CTOR(2); CTOR(3); CTOR(4); CTOR(5); CTOR(6); CTOR(7);
|
||||
@ -117,7 +117,7 @@ EXPORT_SYMBOL_GPL(pgtable_cache); /* used by kvm_hv module */
|
||||
void pgtable_cache_add(unsigned int shift)
|
||||
{
|
||||
char *name;
|
||||
unsigned long table_size = sizeof(void *) << shift;
|
||||
unsigned long table_size = sizeof(pgd_t) << shift;
|
||||
unsigned long align = table_size;
|
||||
|
||||
/* When batching pgtable pointers for RCU freeing, we store
|
||||
|
@ -290,8 +290,6 @@ void __init mem_init(void)
|
||||
swiotlb_init(ppc_swiotlb_enable, ppc_swiotlb_flags);
|
||||
#endif
|
||||
|
||||
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
|
||||
|
||||
kasan_late_init();
|
||||
|
||||
memblock_free_all();
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include <uapi/asm/hwprobe.h>
|
||||
|
||||
#define RISCV_HWPROBE_MAX_KEY 8
|
||||
#define RISCV_HWPROBE_MAX_KEY 9
|
||||
|
||||
static inline bool riscv_hwprobe_key_is_valid(__s64 key)
|
||||
{
|
||||
|
@ -82,6 +82,12 @@ struct riscv_hwprobe {
|
||||
#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
|
||||
#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7
|
||||
#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8
|
||||
#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9
|
||||
#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0
|
||||
#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1
|
||||
#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2
|
||||
#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3
|
||||
#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4
|
||||
/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
|
||||
|
||||
/* Flags */
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include <asm/numa.h>
|
||||
|
||||
static int acpi_early_node_map[NR_CPUS] __initdata = { NUMA_NO_NODE };
|
||||
static int acpi_early_node_map[NR_CPUS] __initdata = { [0 ... NR_CPUS - 1] = NUMA_NO_NODE };
|
||||
|
||||
int __init acpi_numa_get_nid(unsigned int cpu)
|
||||
{
|
||||
|
@ -205,6 +205,8 @@ int patch_text_set_nosync(void *addr, u8 c, size_t len)
|
||||
int ret;
|
||||
|
||||
ret = patch_insn_set(addr, c, len);
|
||||
if (!ret)
|
||||
flush_icache_range((uintptr_t)addr, (uintptr_t)addr + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -239,6 +241,8 @@ int patch_text_nosync(void *addr, const void *insns, size_t len)
|
||||
int ret;
|
||||
|
||||
ret = patch_insn_write(addr, insns, len);
|
||||
if (!ret)
|
||||
flush_icache_range((uintptr_t)addr, (uintptr_t)addr + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -178,13 +178,13 @@ static u64 hwprobe_misaligned(const struct cpumask *cpus)
|
||||
perf = this_perf;
|
||||
|
||||
if (perf != this_perf) {
|
||||
perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN;
|
||||
perf = RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (perf == -1ULL)
|
||||
return RISCV_HWPROBE_MISALIGNED_UNKNOWN;
|
||||
return RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN;
|
||||
|
||||
return perf;
|
||||
}
|
||||
@ -192,12 +192,12 @@ static u64 hwprobe_misaligned(const struct cpumask *cpus)
|
||||
static u64 hwprobe_misaligned(const struct cpumask *cpus)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS))
|
||||
return RISCV_HWPROBE_MISALIGNED_FAST;
|
||||
return RISCV_HWPROBE_MISALIGNED_SCALAR_FAST;
|
||||
|
||||
if (IS_ENABLED(CONFIG_RISCV_EMULATED_UNALIGNED_ACCESS) && unaligned_ctl_available())
|
||||
return RISCV_HWPROBE_MISALIGNED_EMULATED;
|
||||
return RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED;
|
||||
|
||||
return RISCV_HWPROBE_MISALIGNED_SLOW;
|
||||
return RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -225,6 +225,7 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
|
||||
break;
|
||||
|
||||
case RISCV_HWPROBE_KEY_CPUPERF_0:
|
||||
case RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF:
|
||||
pair->value = hwprobe_misaligned(cpus);
|
||||
break;
|
||||
|
||||
|
@ -319,6 +319,7 @@ void do_trap_ecall_u(struct pt_regs *regs)
|
||||
|
||||
regs->epc += 4;
|
||||
regs->orig_a0 = regs->a0;
|
||||
regs->a0 = -ENOSYS;
|
||||
|
||||
riscv_v_vstate_discard(regs);
|
||||
|
||||
@ -328,8 +329,7 @@ void do_trap_ecall_u(struct pt_regs *regs)
|
||||
|
||||
if (syscall >= 0 && syscall < NR_syscalls)
|
||||
syscall_handler(regs, syscall);
|
||||
else if (syscall != -1)
|
||||
regs->a0 = -ENOSYS;
|
||||
|
||||
/*
|
||||
* Ultimately, this value will get limited by KSTACK_OFFSET_MAX(),
|
||||
* so the maximum stack offset is 1k bytes (10 bits).
|
||||
|
@ -338,7 +338,7 @@ int handle_misaligned_load(struct pt_regs *regs)
|
||||
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
|
||||
|
||||
#ifdef CONFIG_RISCV_PROBE_UNALIGNED_ACCESS
|
||||
*this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_EMULATED;
|
||||
*this_cpu_ptr(&misaligned_access_speed) = RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED;
|
||||
#endif
|
||||
|
||||
if (!unaligned_enabled)
|
||||
@ -532,13 +532,13 @@ static bool check_unaligned_access_emulated(int cpu)
|
||||
unsigned long tmp_var, tmp_val;
|
||||
bool misaligned_emu_detected;
|
||||
|
||||
*mas_ptr = RISCV_HWPROBE_MISALIGNED_UNKNOWN;
|
||||
*mas_ptr = RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
" "REG_L" %[tmp], 1(%[ptr])\n"
|
||||
: [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory");
|
||||
|
||||
misaligned_emu_detected = (*mas_ptr == RISCV_HWPROBE_MISALIGNED_EMULATED);
|
||||
misaligned_emu_detected = (*mas_ptr == RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED);
|
||||
/*
|
||||
* If unaligned_ctl is already set, this means that we detected that all
|
||||
* CPUS uses emulated misaligned access at boot time. If that changed
|
||||
|
@ -34,9 +34,9 @@ static int check_unaligned_access(void *param)
|
||||
struct page *page = param;
|
||||
void *dst;
|
||||
void *src;
|
||||
long speed = RISCV_HWPROBE_MISALIGNED_SLOW;
|
||||
long speed = RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW;
|
||||
|
||||
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
|
||||
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN)
|
||||
return 0;
|
||||
|
||||
/* Make an unaligned destination buffer. */
|
||||
@ -95,14 +95,14 @@ static int check_unaligned_access(void *param)
|
||||
}
|
||||
|
||||
if (word_cycles < byte_cycles)
|
||||
speed = RISCV_HWPROBE_MISALIGNED_FAST;
|
||||
speed = RISCV_HWPROBE_MISALIGNED_SCALAR_FAST;
|
||||
|
||||
ratio = div_u64((byte_cycles * 100), word_cycles);
|
||||
pr_info("cpu%d: Ratio of byte access time to unaligned word access is %d.%02d, unaligned accesses are %s\n",
|
||||
cpu,
|
||||
ratio / 100,
|
||||
ratio % 100,
|
||||
(speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow");
|
||||
(speed == RISCV_HWPROBE_MISALIGNED_SCALAR_FAST) ? "fast" : "slow");
|
||||
|
||||
per_cpu(misaligned_access_speed, cpu) = speed;
|
||||
|
||||
@ -110,7 +110,7 @@ static int check_unaligned_access(void *param)
|
||||
* Set the value of fast_misaligned_access of a CPU. These operations
|
||||
* are atomic to avoid race conditions.
|
||||
*/
|
||||
if (speed == RISCV_HWPROBE_MISALIGNED_FAST)
|
||||
if (speed == RISCV_HWPROBE_MISALIGNED_SCALAR_FAST)
|
||||
cpumask_set_cpu(cpu, &fast_misaligned_access);
|
||||
else
|
||||
cpumask_clear_cpu(cpu, &fast_misaligned_access);
|
||||
@ -188,7 +188,7 @@ static int riscv_online_cpu(unsigned int cpu)
|
||||
static struct page *buf;
|
||||
|
||||
/* We are already set since the last check */
|
||||
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
|
||||
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN)
|
||||
goto exit;
|
||||
|
||||
buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
|
||||
|
@ -38,7 +38,7 @@ bool __riscv_isa_vendor_extension_available(int cpu, unsigned long vendor, unsig
|
||||
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_ANDES
|
||||
case ANDES_VENDOR_ID:
|
||||
bmap = &riscv_isa_vendor_ext_list_andes.all_harts_isa_bitmap;
|
||||
cpu_bmap = &riscv_isa_vendor_ext_list_andes.per_hart_isa_bitmap[cpu];
|
||||
cpu_bmap = riscv_isa_vendor_ext_list_andes.per_hart_isa_bitmap;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -927,7 +927,7 @@ static void __init create_kernel_page_table(pgd_t *pgdir,
|
||||
PMD_SIZE, PAGE_KERNEL_EXEC);
|
||||
|
||||
/* Map the data in RAM */
|
||||
end_va = kernel_map.virt_addr + XIP_OFFSET + kernel_map.size;
|
||||
end_va = kernel_map.virt_addr + kernel_map.size;
|
||||
for (va = kernel_map.virt_addr + XIP_OFFSET; va < end_va; va += PMD_SIZE)
|
||||
create_pgd_mapping(pgdir, va,
|
||||
kernel_map.phys_addr + (va - (kernel_map.virt_addr + XIP_OFFSET)),
|
||||
@ -1096,7 +1096,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
||||
|
||||
phys_ram_base = CONFIG_PHYS_RAM_BASE;
|
||||
kernel_map.phys_addr = (uintptr_t)CONFIG_PHYS_RAM_BASE;
|
||||
kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_sdata);
|
||||
kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_start);
|
||||
|
||||
kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom;
|
||||
#else
|
||||
|
@ -604,6 +604,19 @@ config RANDOMIZE_BASE
|
||||
as a security feature that deters exploit attempts relying on
|
||||
knowledge of the location of kernel internals.
|
||||
|
||||
config RANDOMIZE_IDENTITY_BASE
|
||||
bool "Randomize the address of the identity mapping base"
|
||||
depends on RANDOMIZE_BASE
|
||||
default DEBUG_VM
|
||||
help
|
||||
The identity mapping base address is pinned to zero by default.
|
||||
Allow randomization of that base to expose otherwise missed
|
||||
notion of physical and virtual addresses of data structures.
|
||||
That does not have any impact on the base address at which the
|
||||
kernel image is loaded.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config KERNEL_IMAGE_BASE
|
||||
hex "Kernel image base address"
|
||||
range 0x100000 0x1FFFFFE0000000 if !KASAN
|
||||
|
@ -162,7 +162,7 @@ static void kaslr_adjust_relocs(unsigned long min_addr, unsigned long max_addr,
|
||||
loc = (long)*reloc + phys_offset;
|
||||
if (loc < min_addr || loc > max_addr)
|
||||
error("64-bit relocation outside of kernel!\n");
|
||||
*(u64 *)loc += offset - __START_KERNEL;
|
||||
*(u64 *)loc += offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ static void kaslr_adjust_got(unsigned long offset)
|
||||
*/
|
||||
for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++) {
|
||||
if (*entry)
|
||||
*entry += offset - __START_KERNEL;
|
||||
*entry += offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +252,7 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
|
||||
vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page);
|
||||
|
||||
/* choose kernel address space layout: 4 or 3 levels. */
|
||||
BUILD_BUG_ON(!IS_ALIGNED(__START_KERNEL, THREAD_SIZE));
|
||||
BUILD_BUG_ON(!IS_ALIGNED(TEXT_OFFSET, THREAD_SIZE));
|
||||
BUILD_BUG_ON(!IS_ALIGNED(__NO_KASLR_START_KERNEL, THREAD_SIZE));
|
||||
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > _REGION1_SIZE);
|
||||
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION3_SIZE);
|
||||
@ -341,7 +341,8 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
|
||||
BUILD_BUG_ON(MAX_DCSS_ADDR > (1UL << MAX_PHYSMEM_BITS));
|
||||
max_mappable = max(ident_map_size, MAX_DCSS_ADDR);
|
||||
max_mappable = min(max_mappable, vmemmap_start);
|
||||
__identity_base = round_down(vmemmap_start - max_mappable, rte_size);
|
||||
if (IS_ENABLED(CONFIG_RANDOMIZE_IDENTITY_BASE))
|
||||
__identity_base = round_down(vmemmap_start - max_mappable, rte_size);
|
||||
|
||||
return asce_limit;
|
||||
}
|
||||
@ -388,31 +389,25 @@ static void kaslr_adjust_vmlinux_info(long offset)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fixup_vmlinux_info(void)
|
||||
{
|
||||
vmlinux.entry -= __START_KERNEL;
|
||||
kaslr_adjust_vmlinux_info(-__START_KERNEL);
|
||||
}
|
||||
|
||||
void startup_kernel(void)
|
||||
{
|
||||
unsigned long kernel_size = vmlinux.image_size + vmlinux.bss_size;
|
||||
unsigned long nokaslr_offset_phys, kaslr_large_page_offset;
|
||||
unsigned long amode31_lma = 0;
|
||||
unsigned long vmlinux_size = vmlinux.image_size + vmlinux.bss_size;
|
||||
unsigned long nokaslr_text_lma, text_lma = 0, amode31_lma = 0;
|
||||
unsigned long kernel_size = TEXT_OFFSET + vmlinux_size;
|
||||
unsigned long kaslr_large_page_offset;
|
||||
unsigned long max_physmem_end;
|
||||
unsigned long asce_limit;
|
||||
unsigned long safe_addr;
|
||||
psw_t psw;
|
||||
|
||||
fixup_vmlinux_info();
|
||||
setup_lpp();
|
||||
|
||||
/*
|
||||
* Non-randomized kernel physical start address must be _SEGMENT_SIZE
|
||||
* aligned (see blow).
|
||||
*/
|
||||
nokaslr_offset_phys = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
|
||||
safe_addr = PAGE_ALIGN(nokaslr_offset_phys + kernel_size);
|
||||
nokaslr_text_lma = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
|
||||
safe_addr = PAGE_ALIGN(nokaslr_text_lma + vmlinux_size);
|
||||
|
||||
/*
|
||||
* Reserve decompressor memory together with decompression heap,
|
||||
@ -456,16 +451,27 @@ void startup_kernel(void)
|
||||
*/
|
||||
kaslr_large_page_offset = __kaslr_offset & ~_SEGMENT_MASK;
|
||||
if (kaslr_enabled()) {
|
||||
unsigned long end = ident_map_size - kaslr_large_page_offset;
|
||||
unsigned long size = vmlinux_size + kaslr_large_page_offset;
|
||||
|
||||
__kaslr_offset_phys = randomize_within_range(kernel_size, _SEGMENT_SIZE, 0, end);
|
||||
text_lma = randomize_within_range(size, _SEGMENT_SIZE, TEXT_OFFSET, ident_map_size);
|
||||
}
|
||||
if (!__kaslr_offset_phys)
|
||||
__kaslr_offset_phys = nokaslr_offset_phys;
|
||||
__kaslr_offset_phys |= kaslr_large_page_offset;
|
||||
if (!text_lma)
|
||||
text_lma = nokaslr_text_lma;
|
||||
text_lma |= kaslr_large_page_offset;
|
||||
|
||||
/*
|
||||
* [__kaslr_offset_phys..__kaslr_offset_phys + TEXT_OFFSET] region is
|
||||
* never accessed via the kernel image mapping as per the linker script:
|
||||
*
|
||||
* . = TEXT_OFFSET;
|
||||
*
|
||||
* Therefore, this region could be used for something else and does
|
||||
* not need to be reserved. See how it is skipped in setup_vmem().
|
||||
*/
|
||||
__kaslr_offset_phys = text_lma - TEXT_OFFSET;
|
||||
kaslr_adjust_vmlinux_info(__kaslr_offset_phys);
|
||||
physmem_reserve(RR_VMLINUX, __kaslr_offset_phys, kernel_size);
|
||||
deploy_kernel((void *)__kaslr_offset_phys);
|
||||
physmem_reserve(RR_VMLINUX, text_lma, vmlinux_size);
|
||||
deploy_kernel((void *)text_lma);
|
||||
|
||||
/* vmlinux decompression is done, shrink reserved low memory */
|
||||
physmem_reserve(RR_DECOMPRESSOR, 0, (unsigned long)_decompressor_end);
|
||||
@ -488,7 +494,7 @@ void startup_kernel(void)
|
||||
amode31_lma = randomize_within_range(vmlinux.amode31_size, PAGE_SIZE, amode31_min, SZ_2G);
|
||||
}
|
||||
if (!amode31_lma)
|
||||
amode31_lma = __kaslr_offset_phys - vmlinux.amode31_size;
|
||||
amode31_lma = text_lma - vmlinux.amode31_size;
|
||||
physmem_reserve(RR_AMODE31, amode31_lma, vmlinux.amode31_size);
|
||||
|
||||
/*
|
||||
@ -504,8 +510,8 @@ void startup_kernel(void)
|
||||
* - copy_bootdata() must follow setup_vmem() to propagate changes
|
||||
* to bootdata made by setup_vmem()
|
||||
*/
|
||||
clear_bss_section(__kaslr_offset_phys);
|
||||
kaslr_adjust_relocs(__kaslr_offset_phys, __kaslr_offset_phys + vmlinux.image_size,
|
||||
clear_bss_section(text_lma);
|
||||
kaslr_adjust_relocs(text_lma, text_lma + vmlinux.image_size,
|
||||
__kaslr_offset, __kaslr_offset_phys);
|
||||
kaslr_adjust_got(__kaslr_offset);
|
||||
setup_vmem(__kaslr_offset, __kaslr_offset + kernel_size, asce_limit);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user