mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
Merge branch 'for-7.4/roccat' into for-linus
- fixed handling of short reports (Jiale Yao)
This commit is contained in:
commit
c5e50af20f
3
.mailmap
3
.mailmap
|
|
@ -286,6 +286,8 @@ Ed L. Cashin <ecashin@coraid.com>
|
|||
Elliot Berman <quic_eberman@quicinc.com> <eberman@codeaurora.org>
|
||||
Enric Balletbo i Serra <eballetbo@kernel.org> <enric.balletbo@collabora.com>
|
||||
Enric Balletbo i Serra <eballetbo@kernel.org> <eballetbo@iseebcn.com>
|
||||
Eric Dumazet <edumazet@kernel.org> <edumazet@google.com>
|
||||
Eric Dumazet <edumazet@kernel.org> <eric.dumazet@gmail.com>
|
||||
Erik Kaneda <erik.kaneda@intel.com> <erik.schmauss@intel.com>
|
||||
Ethan Carter Edwards <ethan@ethancedwards.com> Ethan Edwards <ethancarteredwards@gmail.com>
|
||||
Eugen Hristev <ehristev@kernel.org> <eugen.hristev@microchip.com>
|
||||
|
|
@ -977,6 +979,7 @@ Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
|
|||
Vlastimil Babka <vbabka@kernel.org> <vbabka@suse.cz>
|
||||
WangYuli <wangyuli@aosc.io> <wangyl5933@chinaunicom.cn>
|
||||
WangYuli <wangyuli@aosc.io> <wangyuli@deepin.org>
|
||||
Wei Wang <weiwan@google.com> <weibunny@fb.com>
|
||||
Weiwen Hu <huweiwen@linux.alibaba.com> <sehuww@mail.scut.edu.cn>
|
||||
WeiXiong Liao <gmpy.liaowx@gmail.com> <liaoweixiong@allwinnertech.com>
|
||||
Wen Gong <quic_wgong@quicinc.com> <wgong@codeaurora.org>
|
||||
|
|
|
|||
|
|
@ -589,6 +589,9 @@ Kernel parameters
|
|||
arm64.nosve [ARM64] Unconditionally disable Scalable Vector
|
||||
Extension support
|
||||
|
||||
arm64.nowfxt [ARM64] Unconditionally disable Wait For Event with
|
||||
Timeout and Wait For Interrupt with Timeout support
|
||||
|
||||
ataflop= [HW,M68k]
|
||||
|
||||
atarimouse= [HW,MOUSE] Atari Mouse
|
||||
|
|
@ -3491,7 +3494,7 @@ Kernel parameters
|
|||
|
||||
* SATA link speed limit: 1.5Gbps or 3.0Gbps.
|
||||
|
||||
* Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7].
|
||||
* Transfer mode: pio[0-6], mwdma[0-4] and udma[0-7].
|
||||
udma[/][16,25,33,44,66,100,133] notation is also
|
||||
allowed.
|
||||
|
||||
|
|
@ -3509,7 +3512,7 @@ Kernel parameters
|
|||
|
||||
* [no]ncqtrim: Enable or disable queued DSM TRIM.
|
||||
|
||||
* [no]ncqati: Enable or disable NCQ trim on ATI chipset.
|
||||
* [no]ncqati: Enable or disable NCQ on ATI chipsets.
|
||||
|
||||
* [no]trim: Enable or disable (unqueued) TRIM.
|
||||
|
||||
|
|
@ -3540,11 +3543,9 @@ Kernel parameters
|
|||
|
||||
* max_sec_128: Set transfer size limit to 128 sectors.
|
||||
|
||||
* max_sec_1024: Set or clear transfer size limit to
|
||||
1024 sectors.
|
||||
* max_sec_1024: Set transfer size limit to 1024 sectors.
|
||||
|
||||
* max_sec_lba48: Set or clear transfer size limit to
|
||||
65535 sectors.
|
||||
* max_sec_lba48: Set transfer size limit to 65535 sectors.
|
||||
|
||||
* external: Mark port as external (hotplug-capable).
|
||||
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ Before jumping into the kernel, the following conditions must be met:
|
|||
- HDFGWTR2_EL2.nPMICNTR_EL0 (bit 2) must be initialised to 0b1.
|
||||
- HDFGWTR2_EL2.nPMICFILTR_EL0 (bit 3) must be initialised to 0b1.
|
||||
- HDFGWTR2_EL2.nPMUACR_EL1 (bit 4) must be initialised to 0b1.
|
||||
- HDFGWTR2_EL2.nPMZR_EL0 (bit 21) must be initialised to 0b1.
|
||||
|
||||
For CPUs with SPE data source filtering (FEAT_SPE_FDS):
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Entries specific to zPCI functions and entries that hold zPCI information.
|
|||
|
||||
A physical function that currently supports a virtual function cannot be
|
||||
powered off until all virtual functions are removed with:
|
||||
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf
|
||||
echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvfs
|
||||
|
||||
* /sys/bus/pci/devices/DDDD:BB:dd.f/:
|
||||
|
||||
|
|
|
|||
|
|
@ -486,6 +486,16 @@ Example usage in BPF program:
|
|||
/* note that the last argument is omitted */
|
||||
bpf_task_work_schedule_signal(task, &work->tw, &arrmap, task_work_callback);
|
||||
|
||||
2.5.10 KF_PERFMON flag
|
||||
----------------------
|
||||
|
||||
The KF_PERFMON flag is used for kfuncs that can expose kernel memory or kernel
|
||||
addresses to the BPF program, for example by reading through a pointer that the
|
||||
verifier does not check. Calling such a kfunc requires CAP_PERFMON, or
|
||||
CAP_SYS_ADMIN, in the same way that the equivalent BPF helpers are gated in
|
||||
bpf_base_func_proto(). A program loaded with CAP_BPF alone is rejected at load
|
||||
time.
|
||||
|
||||
2.6 Registering the kfuncs
|
||||
--------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ $defs:
|
|||
Specify the alternative function to be configured for the specified
|
||||
pins.
|
||||
|
||||
enum: [ aoss_cti, atest_char, atest_usb20, atest_usb21,
|
||||
enum: [ gpio, aoss_cti, atest_char, atest_usb20, atest_usb21,
|
||||
aud_intfc0_clk, aud_intfc0_data, aud_intfc0_ws,
|
||||
aud_intfc10_clk, aud_intfc10_data, aud_intfc10_ws,
|
||||
aud_intfc1_clk, aud_intfc1_data, aud_intfc1_ws,
|
||||
|
|
@ -98,9 +98,10 @@ $defs:
|
|||
pcie3_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux,
|
||||
prng_rosc0, prng_rosc1, pwrbrk_i_n, qdss, qdss_cti, qspi,
|
||||
qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5,
|
||||
qup1_se0, qup1_se1, qup1_se3, qup1_se2, qup1_se4, qup1_se5,
|
||||
qup1_se0, qup1_se1, qup1_se2_01, qup1_se2_23, qup1_se3_01,
|
||||
qup1_se3_23, qup1_se4, qup1_se5,
|
||||
qup1_se6, qup2_se0, qup2_se1, qup2_se2, qup2_se3, qup2_se4,
|
||||
qup2_se5, qup2_se6,
|
||||
qup2_se5, qup2_se6, qup3_se0_mira, qup3_se0_mirb,
|
||||
sailss_ospi, sdc4_clk, sdc4_cmd, sdc4_data, smb_alert,
|
||||
smb_alert_n, smb_clk, smb_dat, tb_trig_sdc4, tmess_prng0,
|
||||
tmess_prng1, tsc_timer, tsense_pwm, usb0_hs,
|
||||
|
|
|
|||
|
|
@ -851,6 +851,8 @@ operations:
|
|||
name: bind-tx
|
||||
doc: Bind dmabuf to netdev for TX
|
||||
attribute-set: dmabuf
|
||||
# Intentionally unprivileged (no admin-perm / uns-admin-perm); see
|
||||
# comment above netdev_nl_bind_tx_doit().
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Landlock Trace Events
|
|||
=====================
|
||||
|
||||
:Author: Mickaël Salaün
|
||||
:Date: August 2026
|
||||
:Date: September 2026
|
||||
|
||||
Landlock emits trace events for sandbox lifecycle operations and access
|
||||
denials. These events can be consumed by ftrace (for human-readable
|
||||
|
|
@ -31,8 +31,8 @@ Landlock trace events are organized in four categories:
|
|||
**Syscall events** are emitted during Landlock system calls:
|
||||
|
||||
- ``landlock_create_ruleset``: a new ruleset is created
|
||||
- ``landlock_add_rule_fs``: a filesystem rule is added to a ruleset
|
||||
- ``landlock_add_rule_net``: a network port rule is added to a ruleset
|
||||
- ``landlock_add_rule_path_beneath``: a filesystem rule is added to a ruleset
|
||||
- ``landlock_add_rule_net_port``: a network port rule is added to a ruleset
|
||||
- ``landlock_create_domain``: a new domain is created from a ruleset
|
||||
- ``landlock_enforce_domain``: a domain is enforced on a thread
|
||||
|
||||
|
|
@ -47,8 +47,8 @@ Landlock trace events are organized in four categories:
|
|||
|
||||
**Rule evaluation events** are emitted during rule matching:
|
||||
|
||||
- ``landlock_check_rule_fs``: a filesystem rule is evaluated
|
||||
- ``landlock_check_rule_net``: a network port rule is evaluated
|
||||
- ``landlock_check_rule_inode``: an inode-keyed rule is evaluated
|
||||
- ``landlock_check_rule_net_port``: a network-port-keyed rule is evaluated
|
||||
|
||||
**Lifecycle events**:
|
||||
|
||||
|
|
@ -141,10 +141,10 @@ in some field formats:
|
|||
treated as untrusted input and escaped in the trace text output so it
|
||||
cannot inject field separators or control characters.
|
||||
|
||||
- **Other party's domain**: A scope or ptrace denial compares the
|
||||
subject's denying domain (``domain=``, always the enforcing domain and
|
||||
never the current task) with the other party's domain, so these
|
||||
tracepoints also report the other party's domain as a scalar ID:
|
||||
- **Other party's domain**: A scope or ptrace denial compares the subject's
|
||||
denying domain (``domain=``), which is the enforcing domain and not
|
||||
necessarily the current task's domain, with the other party's domain.
|
||||
These tracepoints also report the other party's domain as a scalar ID:
|
||||
``tracee_domain=`` (ptrace), ``target_domain=`` (signal), and
|
||||
``peer_domain=`` (abstract unix socket). It is ``0`` when the other
|
||||
party is unsandboxed, and otherwise a domain ID that a consumer resolves
|
||||
|
|
@ -189,7 +189,7 @@ rather than the caller's, so correlate those to the syscall by domain ID.
|
|||
Interpreting check_rule events
|
||||
==============================
|
||||
|
||||
The ``check_rule_fs`` and ``check_rule_net`` events expose the per-layer
|
||||
The ``check_rule_inode`` and ``check_rule_net_port`` events expose the per-layer
|
||||
rule evaluation, which is useful for understanding *why* a specific
|
||||
access is allowed or denied.
|
||||
|
||||
|
|
@ -231,9 +231,10 @@ contribution, not the final decision:
|
|||
through another matching rule, or the right is denied and appears in the
|
||||
``blockers=`` field of the corresponding ``deny_access`` event.
|
||||
|
||||
To reconstruct the decision for an object, aggregate the ``grants=``
|
||||
groups of all ``check_rule`` events emitted for that object during the
|
||||
check.
|
||||
For an access check that a consumer can delimit, aggregate the ``grants=``
|
||||
groups of all matching ``check_rule`` events. These events do not carry a
|
||||
request ID; use their execution context and generic tracepoints to separate
|
||||
concurrent or successive checks of the same object.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -244,29 +245,31 @@ check.
|
|||
|
||||
For example, a program sandboxed with read and execute access to the
|
||||
whole filesystem reads ``/etc/passwd``; both the ``execve()`` and the
|
||||
read match the rule covering ``/`` (inode 2), so ``check_rule_fs`` fires
|
||||
read match the rule covering ``/`` (inode 2), so ``check_rule_inode`` fires
|
||||
with the requested rights intersected against what that rule grants.
|
||||
The ``access_request=`` mask includes ``truncate`` because the file-open hook
|
||||
evaluates that optional right alongside the required access, but the
|
||||
rule does not grant it, so ``truncate`` never appears in ``grants=``::
|
||||
|
||||
cat-127 [...] landlock_check_rule_fs: domain=1e40cb56f access_request=execute|read_file|truncate dev=0:17 ino=2 grants={execute|read_file}
|
||||
cat-127 [...] landlock_check_rule_fs: domain=1e40cb56f access_request=read_file|truncate dev=0:17 ino=2 grants={read_file}
|
||||
cat-127 [...] landlock_check_rule_inode: domain=1e40cb56f access_request=execute|read_file|truncate dev=0:17 ino=2 grants={execute|read_file}
|
||||
cat-127 [...] landlock_check_rule_inode: domain=1e40cb56f access_request=read_file|truncate dev=0:17 ino=2 grants={read_file}
|
||||
|
||||
The ``[...]`` replaces the ftrace CPU, flags, and timestamp columns. A
|
||||
single ``grants=`` group means the enforcing domain has one layer. With
|
||||
two nested sandboxes that each grant the same rights, the rule spans both
|
||||
layers, so ``grants=`` has one group per layer::
|
||||
|
||||
cat-128 [...] landlock_check_rule_fs: domain=184788b52 access_request=execute|read_file|truncate dev=0:17 ino=2 grants={execute|read_file,execute|read_file}
|
||||
cat-128 [...] landlock_check_rule_fs: domain=184788b52 access_request=read_file|truncate dev=0:17 ino=2 grants={read_file,read_file}
|
||||
cat-128 [...] landlock_check_rule_inode: domain=184788b52 access_request=execute|read_file|truncate dev=0:17 ino=2 grants={execute|read_file,execute|read_file}
|
||||
cat-128 [...] landlock_check_rule_inode: domain=184788b52 access_request=read_file|truncate dev=0:17 ino=2 grants={read_file,read_file}
|
||||
|
||||
eBPF access
|
||||
===========
|
||||
|
||||
eBPF programs attached via ``BPF_RAW_TRACEPOINT`` can access the
|
||||
tracepoint arguments directly through BTF. The arguments include both
|
||||
standard kernel objects and Landlock-internal objects:
|
||||
BTF-enabled raw tracepoint programs attached through libbpf
|
||||
``SEC("tp_btf/...")`` sections receive typed callback arguments. The
|
||||
event prototypes in `Event reference`_ document their argument layouts.
|
||||
The arguments include both standard kernel objects and Landlock-internal
|
||||
objects:
|
||||
|
||||
- Standard kernel objects (``struct task_struct``, ``struct sock``,
|
||||
``struct path``, ``struct dentry``) can be used with existing BPF
|
||||
|
|
@ -277,7 +280,7 @@ standard kernel objects and Landlock-internal objects:
|
|||
Internal struct layouts may change between kernel versions; use CO-RE
|
||||
for field relocation.
|
||||
|
||||
A stateful eBPF program observes the full event stream and maintains
|
||||
A stateful eBPF program attached before sandbox construction can maintain
|
||||
per-domain state in BPF maps:
|
||||
|
||||
1. On ``landlock_create_domain``: record the domain ID and parent (the
|
||||
|
|
@ -293,7 +296,10 @@ per-domain state in BPF maps:
|
|||
final statistics.
|
||||
|
||||
This approach requires no kernel modification and no Landlock-specific
|
||||
BPF helpers. The Landlock IDs serve as correlation keys across events.
|
||||
BPF helpers. Landlock IDs serve as correlation keys within one boot.
|
||||
Records exported through tracing or BPF buffers can be lost, and records
|
||||
from different CPUs are not globally ordered, so consumers must detect and
|
||||
reconcile incomplete state.
|
||||
|
||||
Audit filtering equivalence
|
||||
===========================
|
||||
|
|
|
|||
81
MAINTAINERS
81
MAINTAINERS
|
|
@ -5143,6 +5143,7 @@ L: netdev@vger.kernel.org
|
|||
L: openwrt-devel@lists.openwrt.org (subscribers-only)
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/net/dsa/brcm,b53.yaml
|
||||
F: Documentation/networking/dsa/b53.rst
|
||||
F: drivers/net/dsa/b53/*
|
||||
F: drivers/net/dsa/bcm_sf2*
|
||||
F: include/linux/dsa/brcm.h
|
||||
|
|
@ -5454,6 +5455,7 @@ F: include/linux/brcmphy.h
|
|||
BROADCOM GENET ETHERNET DRIVER
|
||||
M: Doug Berger <opendmb@gmail.com>
|
||||
M: Florian Fainelli <florian.fainelli@broadcom.com>
|
||||
M: Nicolai Buchwitz <nb@tipi-net.de>
|
||||
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
|
@ -14905,7 +14907,7 @@ M: Damien Le Moal <dlemoal@kernel.org>
|
|||
M: Niklas Cassel <cassel@kernel.org>
|
||||
L: linux-ide@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux.git for-next
|
||||
F: Documentation/ABI/testing/sysfs-ata
|
||||
F: Documentation/devicetree/bindings/ata/
|
||||
F: drivers/ata/
|
||||
|
|
@ -17208,31 +17210,6 @@ F: include/trace/events/ksm.h
|
|||
F: mm/ksm.c
|
||||
F: mm/mm_slot.h
|
||||
|
||||
MEMORY MANAGEMENT - MEMORY POLICY AND MIGRATION
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: David Hildenbrand <david@kernel.org>
|
||||
R: Zi Yan <ziy@nvidia.com>
|
||||
R: Matthew Brost <matthew.brost@intel.com>
|
||||
R: Joshua Hahn <joshua.hahnjy@gmail.com>
|
||||
R: Rakie Kim <rakie.kim@sk.com>
|
||||
R: Byungchul Park <byungchul@sk.com>
|
||||
R: Gregory Price <gourry@gourry.net>
|
||||
R: Ying Huang <ying.huang@linux.alibaba.com>
|
||||
R: Alistair Popple <apopple@nvidia.com>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
W: http://www.linux-mm.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
|
||||
F: include/linux/mempolicy.h
|
||||
F: include/uapi/linux/mempolicy.h
|
||||
F: include/linux/migrate.h
|
||||
F: include/linux/migrate_mode.h
|
||||
F: mm/mempolicy.c
|
||||
F: mm/migrate.c
|
||||
F: mm/migrate_device.c
|
||||
|
||||
MEMORY MANAGEMENT - MGLRU (MULTI-GEN LRU)
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
R: Kairui Song <kasong@tencent.com>
|
||||
|
|
@ -17255,6 +17232,25 @@ F: include/linux/mmzone.h
|
|||
F: mm/vmscan.c
|
||||
F: mm/workingset.c
|
||||
|
||||
MEMORY MANAGEMENT - MIGRATION
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: David Hildenbrand <david@kernel.org>
|
||||
R: Zi Yan <ziy@nvidia.com>
|
||||
R: Matthew Brost <matthew.brost@intel.com>
|
||||
R: Joshua Hahn <joshua.hahnjy@gmail.com>
|
||||
R: Byungchul Park <byungchul@sk.com>
|
||||
R: Gregory Price <gourry@gourry.net>
|
||||
R: Ying Huang <ying.huang@linux.alibaba.com>
|
||||
R: Alistair Popple <apopple@nvidia.com>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
W: http://www.linux-mm.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||
F: include/linux/migrate.h
|
||||
F: include/linux/migrate_mode.h
|
||||
F: mm/migrate.c
|
||||
F: mm/migrate_device.c
|
||||
|
||||
MEMORY MANAGEMENT - MISC
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: David Hildenbrand <david@kernel.org>
|
||||
|
|
@ -17270,7 +17266,6 @@ W: http://www.linux-mm.org
|
|||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-cma
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-numa
|
||||
F: Documentation/admin-guide/mm/
|
||||
F: Documentation/mm/
|
||||
|
|
@ -17278,7 +17273,6 @@ F: drivers/char/mem.c
|
|||
F: include/linux/cma.h
|
||||
F: include/linux/dmapool.h
|
||||
F: include/linux/ioremap.h
|
||||
F: include/linux/memory-tiers.h
|
||||
F: include/linux/page_idle.h
|
||||
F: mm/backing-dev.c
|
||||
F: mm/cma.c
|
||||
|
|
@ -17290,7 +17284,6 @@ F: mm/early_ioremap.c
|
|||
F: mm/fadvise.c
|
||||
F: mm/ioremap.c
|
||||
F: mm/mapping_dirty_helpers.c
|
||||
F: mm/memory-tiers.c
|
||||
F: mm/page_idle.c
|
||||
F: mm/pgalloc-track.h
|
||||
F: mm/process_vm_access.c
|
||||
|
|
@ -17307,6 +17300,27 @@ F: mm/numa.c
|
|||
F: mm/numa_emulation.c
|
||||
F: mm/numa_memblks.c
|
||||
|
||||
MEMORY MANAGEMENT - NUMA PLACEMENT
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: David Hildenbrand <david@kernel.org>
|
||||
M: Gregory Price <gourry@gourry.net>
|
||||
R: Zi Yan <ziy@nvidia.com>
|
||||
R: Joshua Hahn <joshua.hahnjy@gmail.com>
|
||||
R: Rakie Kim <rakie.kim@sk.com>
|
||||
R: Ying Huang <ying.huang@linux.alibaba.com>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
W: http://www.linux-mm.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-memory-tiers
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy
|
||||
F: Documentation/ABI/testing/sysfs-kernel-mm-mempolicy-weighted-interleave
|
||||
F: include/linux/memory-tiers.h
|
||||
F: include/linux/mempolicy.h
|
||||
F: include/uapi/linux/mempolicy.h
|
||||
F: mm/memory-tiers.c
|
||||
F: mm/mempolicy.c
|
||||
|
||||
MEMORY MANAGEMENT - OOM KILLER
|
||||
M: Michal Hocko <mhocko@suse.com>
|
||||
R: David Rientjes <rientjes@google.com>
|
||||
|
|
@ -18884,7 +18898,7 @@ F: net/core/drop_monitor.c
|
|||
NETWORKING DRIVERS
|
||||
M: Andrew Lunn <andrew+netdev@lunn.ch>
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Eric Dumazet <edumazet@kernel.org>
|
||||
M: Jakub Kicinski <kuba@kernel.org>
|
||||
M: Paolo Abeni <pabeni@redhat.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
@ -19001,7 +19015,7 @@ K: struct\s+phy_port|phy_port_
|
|||
|
||||
NETWORKING [GENERAL]
|
||||
M: "David S. Miller" <davem@davemloft.net>
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Eric Dumazet <edumazet@kernel.org>
|
||||
M: Jakub Kicinski <kuba@kernel.org>
|
||||
M: Paolo Abeni <pabeni@redhat.com>
|
||||
R: Simon Horman <horms@kernel.org>
|
||||
|
|
@ -19227,7 +19241,7 @@ F: net/ipv6/seg6*
|
|||
F: tools/testing/selftests/net/srv6*
|
||||
|
||||
NETWORKING [TCP]
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Eric Dumazet <edumazet@kernel.org>
|
||||
M: Neal Cardwell <ncardwell@google.com>
|
||||
R: Kuniyuki Iwashima <kuniyu@google.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
|
@ -19260,7 +19274,7 @@ F: net/tls/
|
|||
F: tools/testing/selftests/net/tls.c
|
||||
|
||||
NETWORKING [SOCKETS]
|
||||
M: Eric Dumazet <edumazet@google.com>
|
||||
M: Eric Dumazet <edumazet@kernel.org>
|
||||
M: Kuniyuki Iwashima <kuniyu@google.com>
|
||||
M: Paolo Abeni <pabeni@redhat.com>
|
||||
M: Willem de Bruijn <willemb@google.com>
|
||||
|
|
@ -20556,6 +20570,7 @@ ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
|
|||
M: Mark Fasheh <mark@fasheh.com>
|
||||
M: Joel Becker <jlbec@evilplan.org>
|
||||
M: Joseph Qi <joseph.qi@linux.alibaba.com>
|
||||
R: Heming Zhao <heming.zhao@suse.com>
|
||||
L: ocfs2-devel@lists.linux.dev
|
||||
S: Supported
|
||||
W: http://ocfs2.wiki.kernel.org
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -331,13 +331,9 @@ config ARC_FPU_SAVE_RESTORE
|
|||
for floating point exceptions and rounding modes. These are
|
||||
preserved across task context switch when enabled.
|
||||
|
||||
config ARC_CANT_LLSC
|
||||
def_bool n
|
||||
|
||||
config ARC_HAS_LLSC
|
||||
bool "Insn: LLOCK/SCOND (efficient atomic ops)"
|
||||
default y
|
||||
depends on !ARC_CANT_LLSC
|
||||
|
||||
if ISA_ARCV2
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,12 @@ static inline u64 __arch_cmpxchg64_relaxed(volatile void *ptr, u64 old, u64 new)
|
|||
}
|
||||
#define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed
|
||||
|
||||
static inline s64 arch_atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new)
|
||||
{
|
||||
return arch_cmpxchg64_relaxed(&v->counter, old, new);
|
||||
}
|
||||
#define arch_atomic64_cmpxchg_relaxed arch_atomic64_cmpxchg_relaxed
|
||||
|
||||
static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new)
|
||||
{
|
||||
s64 prev;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
__typeof__(*(ptr)) _n_ = (new); \
|
||||
__typeof__(*(ptr)) _prev_; \
|
||||
\
|
||||
switch(sizeof((_p_))) { \
|
||||
switch (sizeof(*(_p_))) { \
|
||||
case 1: \
|
||||
_prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \
|
||||
break; \
|
||||
|
|
@ -102,7 +102,7 @@
|
|||
__typeof__(ptr) _p_ = (ptr); \
|
||||
__typeof__(*(ptr)) _val_ = (val); \
|
||||
\
|
||||
switch(sizeof(*(_p_))) { \
|
||||
switch (sizeof(*(_p_))) { \
|
||||
case 4: \
|
||||
_val_ = __arch_xchg(_p_, _val_); \
|
||||
break; \
|
||||
|
|
|
|||
|
|
@ -593,6 +593,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
|||
cpu_id);
|
||||
} else {
|
||||
freq = clk_get_rate(cpu_clk);
|
||||
clk_put(cpu_clk);
|
||||
}
|
||||
if (freq)
|
||||
seq_printf(m, "CPU speed\t: %lu.%02lu Mhz\n",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
|
|||
|
|
@ -418,6 +418,7 @@
|
|||
b.lt .Lskip_fgt2_\@
|
||||
|
||||
mov x0, xzr
|
||||
mov x2, xzr
|
||||
mrs x1, id_aa64dfr0_el1
|
||||
ubfx x1, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp x1, #ID_AA64DFR0_EL1_PMUVer_V3P9
|
||||
|
|
@ -426,6 +427,11 @@
|
|||
orr x0, x0, #HDFGRTR2_EL2_nPMICNTR_EL0
|
||||
orr x0, x0, #HDFGRTR2_EL2_nPMICFILTR_EL0
|
||||
orr x0, x0, #HDFGRTR2_EL2_nPMUACR_EL1
|
||||
orr x2, x2, #HDFGWTR2_EL2_nPMICNTR_EL0
|
||||
orr x2, x2, #HDFGWTR2_EL2_nPMICFILTR_EL0
|
||||
orr x2, x2, #HDFGWTR2_EL2_nPMUACR_EL1
|
||||
/* PMZR_EL0 is write-only, so it has no read trap to disable */
|
||||
orr x2, x2, #HDFGWTR2_EL2_nPMZR_EL0
|
||||
.Lskip_pmuv3p9_\@:
|
||||
/* If SPE is implemented, */
|
||||
__spe_vers_imp .Lskip_spefds_\@, ID_AA64DFR0_EL1_PMSVer_IMP, x1
|
||||
|
|
@ -436,10 +442,11 @@
|
|||
cbz x1, .Lskip_spefds_\@
|
||||
/* disable traps of PMSDSFR to EL2. */
|
||||
orr x0, x0, #HDFGRTR2_EL2_nPMSDSFR_EL1
|
||||
orr x2, x2, #HDFGWTR2_EL2_nPMSDSFR_EL1
|
||||
|
||||
.Lskip_spefds_\@:
|
||||
msr_s SYS_HDFGRTR2_EL2, x0
|
||||
msr_s SYS_HDFGWTR2_EL2, x0
|
||||
msr_s SYS_HDFGWTR2_EL2, x2
|
||||
msr_s SYS_HFGRTR2_EL2, xzr
|
||||
msr_s SYS_HFGWTR2_EL2, xzr
|
||||
msr_s SYS_HFGITR2_EL2, xzr
|
||||
|
|
|
|||
|
|
@ -280,7 +280,8 @@ static inline void __iomem *ioremap_prot(phys_addr_t phys, size_t size,
|
|||
pgprot_t prot;
|
||||
ptval_t user_prot_val = pgprot_val(user_prot);
|
||||
|
||||
if (WARN_ON_ONCE(!(user_prot_val & PTE_USER)))
|
||||
/* Reject PROT_NONE and exec-only */
|
||||
if (!(user_prot_val & PTE_USER))
|
||||
return NULL;
|
||||
|
||||
prot = __pgprot_modify(PAGE_KERNEL, PTE_ATTRINDX_MASK,
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ struct kvm_arch {
|
|||
* Stage 2 paging state for VMs with nested S2 using a virtual
|
||||
* VMID.
|
||||
*/
|
||||
struct kvm_s2_mmu *nested_mmus;
|
||||
struct kvm_s2_mmu **nested_mmus;
|
||||
size_t nested_mmus_size;
|
||||
int nested_mmus_next;
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
|
|||
|
||||
extern bool forward_smc_trap(struct kvm_vcpu *vcpu);
|
||||
extern bool forward_debug_exception(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_init_nested(struct kvm *kvm);
|
||||
extern int kvm_init_nested(struct kvm *kvm);
|
||||
extern void kvm_destroy_nested(struct kvm *kvm);
|
||||
extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu);
|
||||
extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu);
|
||||
extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu);
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ static inline bool kvm_pkvm_ioctl_allowed(struct kvm *kvm, unsigned int ioctl)
|
|||
int r;
|
||||
|
||||
r = kvm_get_cap_for_kvm_ioctl(ioctl, &ext);
|
||||
|
||||
if (WARN_ON_ONCE(r < 0))
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
return kvm_pkvm_ext_allowed(kvm, ext);
|
||||
|
|
|
|||
|
|
@ -28,18 +28,21 @@ bool cpu_errata_set_target_impl(u64 num, void *impl_cpus)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline bool __is_midr_in_range(u32 midr, struct midr_range const *range)
|
||||
{
|
||||
return midr_is_cpu_model_range(midr, range->model,
|
||||
range->rv_min, range->rv_max);
|
||||
}
|
||||
|
||||
static inline bool is_midr_in_range(struct midr_range const *range)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!target_impl_cpu_num)
|
||||
return midr_is_cpu_model_range(read_cpuid_id(), range->model,
|
||||
range->rv_min, range->rv_max);
|
||||
return __is_midr_in_range(read_cpuid_id(), range);
|
||||
|
||||
for (i = 0; i < target_impl_cpu_num; i++) {
|
||||
if (midr_is_cpu_model_range(target_impl_cpus[i].midr,
|
||||
range->model,
|
||||
range->rv_min, range->rv_max))
|
||||
if (__is_midr_in_range(target_impl_cpus[i].midr, range))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -59,7 +62,7 @@ __is_affected_midr_range(const struct arm64_cpu_capabilities *entry,
|
|||
u32 midr, u32 revidr)
|
||||
{
|
||||
const struct arm64_midr_revidr *fix;
|
||||
if (!is_midr_in_range(&entry->midr_range))
|
||||
if (!__is_midr_in_range(midr, &entry->midr_range))
|
||||
return false;
|
||||
|
||||
midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ static const struct ftr_set_desc isar2 __prel64_initconst = {
|
|||
.name = "id_aa64isar2",
|
||||
.override = &id_aa64isar2_override,
|
||||
.fields = {
|
||||
FIELD("wfxt", ID_AA64ISAR2_EL1_WFxT_SHIFT, NULL),
|
||||
FIELD("gpa3", ID_AA64ISAR2_EL1_GPA3_SHIFT, NULL),
|
||||
FIELD("apa3", ID_AA64ISAR2_EL1_APA3_SHIFT, NULL),
|
||||
FIELD("mops", ID_AA64ISAR2_EL1_MOPS_SHIFT, NULL),
|
||||
|
|
@ -254,6 +255,7 @@ static const struct {
|
|||
"id_aa64isar1.api=0 id_aa64isar1.apa=0 "
|
||||
"id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0" },
|
||||
{ "arm64.nomops", "id_aa64isar2.mops=0" },
|
||||
{ "arm64.nowfxt", "id_aa64isar2.wfxt=0" },
|
||||
{ "arm64.nomte", "id_aa64pfr1.mte=0" },
|
||||
{ "nokaslr", "arm64_sw.nokaslr=1" },
|
||||
{ "rodata=off", "arm64_sw.rodataoff=1" },
|
||||
|
|
|
|||
|
|
@ -236,8 +236,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
mutex_unlock(&kvm->lock);
|
||||
#endif
|
||||
|
||||
kvm_init_nested(kvm);
|
||||
|
||||
ret = kvm_share_hyp(kvm, kvm + 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -252,6 +250,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
if (ret)
|
||||
goto err_free_cpumask;
|
||||
|
||||
ret = kvm_init_nested(kvm);
|
||||
if (ret)
|
||||
goto err_uninit_mmu;
|
||||
|
||||
if (is_protected_kvm_enabled()) {
|
||||
/*
|
||||
* If any failures occur after this is successful, make sure to
|
||||
|
|
@ -280,6 +282,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
|||
|
||||
err_uninit_mmu:
|
||||
kvm_uninit_stage2_mmu(kvm);
|
||||
kvm_destroy_nested(kvm);
|
||||
err_free_cpumask:
|
||||
free_cpumask_var(kvm->arch.supported_cpus);
|
||||
err_unshare_kvm:
|
||||
|
|
@ -337,6 +340,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
|||
|
||||
kvm_unshare_hyp(kvm, kvm + 1);
|
||||
|
||||
kvm_destroy_nested(kvm);
|
||||
kvm_arm_teardown_hypercalls(kvm);
|
||||
}
|
||||
|
||||
|
|
@ -1129,7 +1133,7 @@ static int kvm_vcpu_suspend(struct kvm_vcpu *vcpu)
|
|||
static int check_vcpu_requests(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_request_pending(vcpu)) {
|
||||
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu))
|
||||
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu))
|
||||
return -EIO;
|
||||
|
||||
if (kvm_check_request(KVM_REQ_SLEEP, vcpu))
|
||||
|
|
|
|||
|
|
@ -1445,7 +1445,7 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
|
|||
SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1),
|
||||
SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1),
|
||||
SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPOPCX, HFGITR, nGCSEPP, 0),
|
||||
SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0),
|
||||
SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0),
|
||||
SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0),
|
||||
|
|
@ -2386,9 +2386,6 @@ int __init populate_nv_trap_config(void)
|
|||
print_nv_trap_error(fgt, "FGT bit is reserved", ret);
|
||||
}
|
||||
|
||||
if (!cpus_have_final_cap(ARM64_HAS_FGT))
|
||||
continue;
|
||||
|
||||
prev = xa_store(&sr_forward_xa, enc,
|
||||
xa_mk_value(tc.val), GFP_KERNEL);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,10 @@ int __pkvm_host_test_clear_young_guest(u64 gfn, u64 nr_pages, bool mkold, struct
|
|||
int __pkvm_host_mkyoung_guest(u64 gfn, struct pkvm_hyp_vcpu *vcpu);
|
||||
|
||||
bool addr_is_memory(phys_addr_t phys);
|
||||
bool addr_is_hyp_text(phys_addr_t phys);
|
||||
int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot);
|
||||
int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id);
|
||||
bool host_stage2_pte_is_hyp_owned(kvm_pte_t pte);
|
||||
int kvm_host_prepare_stage2(void *pgt_pool_base);
|
||||
int kvm_guest_prepare_stage2(struct pkvm_hyp_vm *vm, void *pgd);
|
||||
void kvm_guest_destroy_stage2(struct pkvm_hyp_vm *vm);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
|
|||
enum kvm_pgtable_prot prot,
|
||||
unsigned long *haddr);
|
||||
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr);
|
||||
int pkvm_check_host_ownership(void);
|
||||
int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr);
|
||||
|
||||
#endif /* __KVM_HYP_MM_H */
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@
|
|||
#include <nvhe/gfp.h>
|
||||
#include <nvhe/spinlock.h>
|
||||
|
||||
/*
|
||||
* HCR_EL2 bits EL2 takes from the host on each entry, per VM type. The rest
|
||||
* are EL2's own and nothing the host sets there reaches the guest.
|
||||
*/
|
||||
#define PKVM_HCR_EL2_HOST_PVM (HCR_EL2_TWI | HCR_EL2_TWE | HCR_EL2_VSE)
|
||||
#define PKVM_HCR_EL2_HOST_NPVM (PKVM_HCR_EL2_HOST_PVM | HCR_EL2_VI | HCR_EL2_VF | \
|
||||
HCR_EL2_TVM | HCR_EL2_TID2 | HCR_EL2_TID4 | \
|
||||
HCR_EL2_TID5 | HCR_EL2_TTLBOS)
|
||||
|
||||
/*
|
||||
* Holds the relevant data for maintaining the vcpu state completely at hyp.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ static void sync_debug_state(struct pkvm_hyp_vcpu *hyp_vcpu)
|
|||
static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
{
|
||||
struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
|
||||
u64 host_hcr_mask = PKVM_HCR_EL2_HOST_PVM;
|
||||
|
||||
fpsimd_sve_flush();
|
||||
flush_debug_state(hyp_vcpu);
|
||||
|
|
@ -228,6 +229,7 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
|||
if (!pkvm_hyp_vcpu_is_protected(hyp_vcpu)) {
|
||||
if (vcpu_get_flag(host_vcpu, PKVM_HOST_STATE_DIRTY))
|
||||
flush_hyp_vcpu_state(hyp_vcpu);
|
||||
host_hcr_mask = PKVM_HCR_EL2_HOST_NPVM;
|
||||
} else {
|
||||
hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
|
||||
}
|
||||
|
|
@ -241,9 +243,8 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
|
|||
* trap-control bit, so it must flow to the hyp vCPU alongside TWI/TWE
|
||||
* for the vSError to be delivered. sync_hyp_vcpu() reflects it back.
|
||||
*/
|
||||
hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI | HCR_TWE | HCR_VSE);
|
||||
hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) &
|
||||
(HCR_TWI | HCR_TWE | HCR_VSE);
|
||||
hyp_vcpu->vcpu.arch.hcr_el2 &= ~host_hcr_mask;
|
||||
hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) & host_hcr_mask;
|
||||
|
||||
hyp_vcpu->vcpu.arch.iflags = host_vcpu->arch.iflags;
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,14 @@ bool addr_is_memory(phys_addr_t phys)
|
|||
return !!find_mem_range(phys, &range);
|
||||
}
|
||||
|
||||
bool addr_is_hyp_text(phys_addr_t phys)
|
||||
{
|
||||
phys_addr_t start = ALIGN_DOWN(__hyp_pa(__hyp_text_start), PAGE_SIZE);
|
||||
phys_addr_t end = PAGE_ALIGN(__hyp_pa(__hyp_text_end));
|
||||
|
||||
return phys >= start && phys < end;
|
||||
}
|
||||
|
||||
static bool is_in_mem_range(u64 addr, struct kvm_mem_range *range)
|
||||
{
|
||||
return range->start <= addr && addr < range->end;
|
||||
|
|
@ -633,6 +641,18 @@ int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool host_stage2_pte_is_hyp_owned(kvm_pte_t pte)
|
||||
{
|
||||
if (kvm_pte_valid(pte))
|
||||
return false;
|
||||
|
||||
if (FIELD_GET(KVM_INVALID_PTE_TYPE_MASK, pte) !=
|
||||
KVM_HOST_INVALID_PTE_TYPE_DONATION)
|
||||
return false;
|
||||
|
||||
return FIELD_GET(KVM_HOST_DONATION_PTE_OWNER_MASK, pte) == PKVM_ID_HYP;
|
||||
}
|
||||
|
||||
#define KVM_HOST_PTE_OWNER_GUEST_HANDLE_MASK GENMASK(15, 0)
|
||||
/* We need 40 bits for the GFN to cover a 52-bit IPA with 4k pages and LPA2 */
|
||||
#define KVM_HOST_PTE_OWNER_GUEST_GFN_MASK GENMASK(55, 16)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ struct memblock_region hyp_memory[HYP_MEMBLOCK_REGIONS];
|
|||
unsigned int hyp_memblock_nr;
|
||||
|
||||
static u64 __io_map_base;
|
||||
static u64 __io_map_next;
|
||||
|
||||
struct hyp_fixmap_slot {
|
||||
u64 addr;
|
||||
|
|
@ -50,7 +51,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
|
|||
|
||||
hyp_assert_lock_held(&pkvm_pgd_lock);
|
||||
|
||||
if (!start || start < __io_map_base)
|
||||
if (!start || start < __io_map_next)
|
||||
return -EINVAL;
|
||||
|
||||
/* The allocated size is always a multiple of PAGE_SIZE */
|
||||
|
|
@ -60,7 +61,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
|
|||
if (cur > __hyp_vmemmap)
|
||||
return -ENOMEM;
|
||||
|
||||
__io_map_base = cur;
|
||||
__io_map_next = cur;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -70,7 +71,7 @@ static int __pkvm_alloc_private_va_range(unsigned long start, size_t size)
|
|||
* @size: The size of the VA range to reserve.
|
||||
* @haddr: The hypervisor virtual start address of the allocation.
|
||||
*
|
||||
* The private virtual address (VA) range is allocated above __io_map_base
|
||||
* The private virtual address (VA) range is allocated above __io_map_next
|
||||
* and aligned based on the order of @size.
|
||||
*
|
||||
* Return: 0 on success or negative error code on failure.
|
||||
|
|
@ -81,7 +82,7 @@ int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr)
|
|||
int ret;
|
||||
|
||||
hyp_spin_lock(&pkvm_pgd_lock);
|
||||
addr = __io_map_base;
|
||||
addr = __io_map_next;
|
||||
ret = __pkvm_alloc_private_va_range(addr, size);
|
||||
hyp_spin_unlock(&pkvm_pgd_lock);
|
||||
|
||||
|
|
@ -341,7 +342,7 @@ static int create_fixblock(void)
|
|||
return -EINVAL;
|
||||
|
||||
hyp_spin_lock(&pkvm_pgd_lock);
|
||||
addr = ALIGN(__io_map_base, PMD_SIZE);
|
||||
addr = ALIGN(__io_map_next, PMD_SIZE);
|
||||
ret = __pkvm_alloc_private_va_range(addr, PMD_SIZE);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
|
@ -426,6 +427,7 @@ int hyp_create_idmap(u32 hyp_va_bits)
|
|||
*/
|
||||
__io_map_base = start & BIT(hyp_va_bits - 2);
|
||||
__io_map_base ^= BIT(hyp_va_bits - 2);
|
||||
__io_map_next = __io_map_base;
|
||||
__hyp_vmemmap = __io_map_base | BIT(hyp_va_bits - 3);
|
||||
|
||||
return __pkvm_create_mappings(start, end - start, start, PAGE_HYP_EXEC);
|
||||
|
|
@ -433,19 +435,19 @@ int hyp_create_idmap(u32 hyp_va_bits)
|
|||
|
||||
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
|
||||
{
|
||||
unsigned long addr, prev_base;
|
||||
unsigned long addr, prev_next;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
hyp_spin_lock(&pkvm_pgd_lock);
|
||||
|
||||
prev_base = __io_map_base;
|
||||
prev_next = __io_map_next;
|
||||
/*
|
||||
* Efficient stack verification using the NVHE_STACK_SHIFT bit implies
|
||||
* an alignment of our allocation on the order of the size.
|
||||
*/
|
||||
size = NVHE_STACK_SIZE * 2;
|
||||
addr = ALIGN(__io_map_base, size);
|
||||
addr = ALIGN(__io_map_next, size);
|
||||
|
||||
ret = __pkvm_alloc_private_va_range(addr, size);
|
||||
if (!ret) {
|
||||
|
|
@ -461,7 +463,7 @@ int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
|
|||
ret = kvm_pgtable_hyp_map(&pkvm_pgtable, addr + NVHE_STACK_SIZE,
|
||||
NVHE_STACK_SIZE, phys, PAGE_HYP);
|
||||
if (ret)
|
||||
__io_map_base = prev_base;
|
||||
__io_map_next = prev_next;
|
||||
}
|
||||
hyp_spin_unlock(&pkvm_pgd_lock);
|
||||
|
||||
|
|
@ -470,6 +472,65 @@ int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int check_page_ownership(phys_addr_t phys)
|
||||
{
|
||||
kvm_pte_t pte;
|
||||
bool host_ok;
|
||||
int ret;
|
||||
|
||||
if (addr_is_memory(phys)) {
|
||||
struct hyp_page *page = hyp_phys_to_page(phys);
|
||||
|
||||
if (get_hyp_state(page) != PKVM_PAGE_OWNED ||
|
||||
get_host_state(page) != PKVM_NOPAGE)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Hyp text may stay host-readable, see fix_host_ownership_walker(). */
|
||||
if (kvm_pte_valid(pte) && addr_is_hyp_text(phys))
|
||||
host_ok = !(kvm_pgtable_stage2_pte_prot(pte) & KVM_PGTABLE_PROT_W);
|
||||
else
|
||||
host_ok = host_stage2_pte_is_hyp_owned(pte);
|
||||
|
||||
return host_ok ? 0 : -EPERM;
|
||||
}
|
||||
|
||||
static int check_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
||||
enum kvm_pgtable_walk_flags visit)
|
||||
{
|
||||
phys_addr_t phys, end;
|
||||
int ret;
|
||||
|
||||
if (!kvm_pte_valid(ctx->old))
|
||||
return 0;
|
||||
|
||||
phys = kvm_pte_to_phys(ctx->old);
|
||||
end = phys + kvm_granule_size(ctx->level);
|
||||
for (; phys < end; phys += PAGE_SIZE) {
|
||||
ret = check_page_ownership(phys);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pkvm_check_host_ownership(void)
|
||||
{
|
||||
struct kvm_pgtable_walker walker = {
|
||||
.cb = check_host_ownership_walker,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF,
|
||||
};
|
||||
|
||||
/* The private range and the vmemmap share one quarter of the VA space. */
|
||||
return kvm_pgtable_walk(&pkvm_pgtable, __io_map_base,
|
||||
BIT(pkvm_pgtable.ia_bits - 2), &walker);
|
||||
}
|
||||
|
||||
static void *admit_host_page(void *arg)
|
||||
{
|
||||
struct kvm_hyp_memcache *host_mc = arg;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ unsigned int kvm_host_sve_max_vl;
|
|||
*/
|
||||
static DEFINE_PER_CPU(struct pkvm_hyp_vcpu *, loaded_hyp_vcpu);
|
||||
|
||||
/* The PKVM_HCR_EL2_HOST_{PVM,NPVM} bits of this value come from the host on each entry. */
|
||||
static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
|
||||
|
|
@ -47,18 +48,17 @@ static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu)
|
|||
if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
|
||||
vcpu->arch.hcr_el2 |= HCR_FWB;
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_EVT) &&
|
||||
!cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE) &&
|
||||
kvm_read_vm_id_reg(vcpu->kvm, SYS_CTR_EL0) == read_cpuid(CTR_EL0))
|
||||
vcpu->arch.hcr_el2 |= HCR_TID4;
|
||||
else
|
||||
vcpu->arch.hcr_el2 |= HCR_TID2;
|
||||
/*
|
||||
* Without AArch32 EL1, leave RW set and let the entry fail with an
|
||||
* illegal exception return: the *32_EL2 registers EL2 would otherwise
|
||||
* switch are UNDEFINED there.
|
||||
*/
|
||||
if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT) &&
|
||||
cpus_have_final_cap(ARM64_HAS_32BIT_EL1))
|
||||
vcpu->arch.hcr_el2 &= ~HCR_EL2_RW;
|
||||
|
||||
if (vcpu_has_ptrauth(vcpu))
|
||||
vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
|
||||
|
||||
if (kvm_has_mte(vcpu->kvm))
|
||||
vcpu->arch.hcr_el2 |= HCR_ATA;
|
||||
}
|
||||
|
||||
static void pvm_init_traps_hcr(struct kvm_vcpu *vcpu)
|
||||
|
|
@ -76,6 +76,13 @@ static void pvm_init_traps_hcr(struct kvm_vcpu *vcpu)
|
|||
*/
|
||||
val |= HCR_TACR | HCR_TIDCP | HCR_TID3 | HCR_TID1;
|
||||
|
||||
if (cpus_have_final_cap(ARM64_HAS_EVT) &&
|
||||
!cpus_have_final_cap(ARM64_MISMATCHED_CACHE_TYPE) &&
|
||||
kvm_read_vm_id_reg(kvm, SYS_CTR_EL0) == read_cpuid(CTR_EL0))
|
||||
val |= HCR_EL2_TID4;
|
||||
else
|
||||
val |= HCR_EL2_TID2;
|
||||
|
||||
if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, IMP)) {
|
||||
val |= HCR_TERR | HCR_TEA;
|
||||
val &= ~(HCR_FIEN);
|
||||
|
|
@ -360,7 +367,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
|
|||
if (test_bit(KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS, &host_arch_flags))
|
||||
hyp_vm->kvm.arch.midr_el1 = host_kvm->arch.midr_el1;
|
||||
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_MTE))
|
||||
|
|
@ -379,13 +386,14 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
|
|||
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_PTRAUTH_GENERIC))
|
||||
set_bit(KVM_ARM_VCPU_PTRAUTH_GENERIC, allowed_features);
|
||||
|
||||
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE)) {
|
||||
if (kvm_pkvm_ext_allowed(kvm, KVM_CAP_ARM_SVE))
|
||||
set_bit(KVM_ARM_VCPU_SVE, allowed_features);
|
||||
kvm->arch.flags |= host_arch_flags & BIT(KVM_ARCH_FLAG_GUEST_HAS_SVE);
|
||||
}
|
||||
|
||||
bitmap_and(kvm->arch.vcpu_features, host_kvm->arch.vcpu_features,
|
||||
allowed_features, KVM_VCPU_MAX_FEATURES);
|
||||
out:
|
||||
__assign_bit(KVM_ARCH_FLAG_GUEST_HAS_SVE, &kvm->arch.flags,
|
||||
kvm_vcpu_has_feature(kvm, KVM_ARM_VCPU_SVE));
|
||||
}
|
||||
|
||||
static void unpin_host_vcpu(struct kvm_vcpu *host_vcpu)
|
||||
|
|
@ -398,10 +406,10 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
|
|||
{
|
||||
void *sve_state;
|
||||
|
||||
if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SVE))
|
||||
sve_state = hyp_vcpu->vcpu.arch.sve_state;
|
||||
if (!sve_state)
|
||||
return;
|
||||
|
||||
sve_state = hyp_vcpu->vcpu.arch.sve_state;
|
||||
hyp_unpin_shared_mem(sve_state,
|
||||
sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
|
||||
}
|
||||
|
|
@ -450,7 +458,7 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
|
|||
unsigned int sve_max_vl;
|
||||
size_t sve_state_size;
|
||||
void *sve_state;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (!vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) {
|
||||
vcpu_clear_flag(vcpu, VCPU_SVE_FINALIZED);
|
||||
|
|
@ -459,25 +467,21 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
|
|||
|
||||
/* Limit guest vector length to the maximum supported by the host. */
|
||||
sve_max_vl = min(READ_ONCE(host_vcpu->arch.sve_max_vl), kvm_host_sve_max_vl);
|
||||
sve_state_size = sve_state_size_from_vl(sve_max_vl);
|
||||
sve_state = kern_hyp_va(READ_ONCE(host_vcpu->arch.sve_state));
|
||||
|
||||
if (!sve_state || !sve_state_size) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (!sve_vl_valid(sve_max_vl) || !sve_state)
|
||||
return -EINVAL;
|
||||
|
||||
sve_state_size = sve_state_size_from_vl(sve_max_vl);
|
||||
|
||||
ret = hyp_pin_shared_mem(sve_state, sve_state + sve_state_size);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
vcpu->arch.sve_state = sve_state;
|
||||
vcpu->arch.sve_max_vl = sve_max_vl;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
clear_bit(KVM_ARM_VCPU_SVE, vcpu->kvm->arch.vcpu_features);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
|
|||
case PKVM_PAGE_OWNED:
|
||||
set_hyp_state(page, PKVM_PAGE_OWNED);
|
||||
/* hyp text is RO in the host stage-2 to be inspected on panic. */
|
||||
if (prot == PAGE_HYP_EXEC) {
|
||||
if (addr_is_hyp_text(phys)) {
|
||||
set_host_state(page, PKVM_NOPAGE);
|
||||
return host_stage2_idmap_locked(phys, PAGE_SIZE, KVM_PGTABLE_PROT_R);
|
||||
} else {
|
||||
|
|
@ -269,6 +269,16 @@ static int fix_host_ownership(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* The stacks sit in the private VA range, not the linear map. */
|
||||
for (i = 0; i < hyp_nr_cpus; i++) {
|
||||
struct kvm_nvhe_init_params *params = per_cpu_ptr(&kvm_init_params, i);
|
||||
u64 start = params->stack_hyp_va - NVHE_STACK_SIZE;
|
||||
|
||||
ret = kvm_pgtable_walk(&pkvm_pgtable, start, NVHE_STACK_SIZE, &walker);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -324,6 +334,10 @@ void __noreturn __pkvm_init_finalise(void)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = pkvm_check_host_ownership();
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = hyp_ffa_init(ffa_proxy_pages);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -185,7 +185,8 @@ static int kvm_smccc_set_filter(struct kvm *kvm, struct kvm_smccc_filter __user
|
|||
start = filter.base;
|
||||
end = start + filter.nr_functions - 1;
|
||||
|
||||
if (end < start || filter.action >= NR_SMCCC_FILTER_ACTIONS)
|
||||
if (!filter.nr_functions || end < start ||
|
||||
filter.action >= NR_SMCCC_FILTER_ACTIONS)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
|
|
|||
|
|
@ -59,27 +59,36 @@ static phys_addr_t stage2_range_addr_end(phys_addr_t addr, phys_addr_t end)
|
|||
* long will also starve other vCPUs. We have to also make sure that the page
|
||||
* tables are not freed while we released the lock.
|
||||
*/
|
||||
static int stage2_apply_range(struct kvm_s2_mmu *mmu, phys_addr_t addr,
|
||||
static int stage2_apply_range(struct kvm_s2_mmu *mmu, phys_addr_t start,
|
||||
phys_addr_t end,
|
||||
int (*fn)(struct kvm_pgtable *, u64, u64),
|
||||
bool resched)
|
||||
{
|
||||
struct kvm *kvm = kvm_s2_mmu_to_kvm(mmu);
|
||||
bool lock_dropped = false;
|
||||
phys_addr_t addr = start;
|
||||
int ret;
|
||||
u64 next;
|
||||
|
||||
do {
|
||||
struct kvm_pgtable *pgt = mmu->pgt;
|
||||
/*
|
||||
* We may be raced on PGT teardown when we release the
|
||||
* kvm->mmu_lock. That's fine as the PGT is legitimately no
|
||||
* longer present.
|
||||
*/
|
||||
if (!pgt)
|
||||
return -EINVAL;
|
||||
return lock_dropped ? 0 : -EINVAL;
|
||||
|
||||
next = stage2_range_addr_end(addr, end);
|
||||
ret = fn(pgt, addr, next - addr);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (resched && next != end)
|
||||
if (resched && next != end) {
|
||||
cond_resched_rwlock_write(&kvm->mmu_lock);
|
||||
lock_dropped = true;
|
||||
}
|
||||
} while (addr = next, addr != end);
|
||||
|
||||
return ret;
|
||||
|
|
@ -1459,32 +1468,11 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,
|
|||
return PAGE_SIZE;
|
||||
}
|
||||
|
||||
static int get_vma_page_shift(struct vm_area_struct *vma, unsigned long hva)
|
||||
static int get_vma_page_shift(struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long pa;
|
||||
|
||||
if (is_vm_hugetlb_page(vma) && !(vma->vm_flags & VM_PFNMAP))
|
||||
if (is_vm_hugetlb_page(vma))
|
||||
return huge_page_shift(hstate_vma(vma));
|
||||
|
||||
if (!(vma->vm_flags & VM_PFNMAP))
|
||||
return PAGE_SHIFT;
|
||||
|
||||
VM_BUG_ON(is_vm_hugetlb_page(vma));
|
||||
|
||||
pa = (vma->vm_pgoff << PAGE_SHIFT) + (hva - vma->vm_start);
|
||||
|
||||
#ifndef __PAGETABLE_PMD_FOLDED
|
||||
if ((hva & (PUD_SIZE - 1)) == (pa & (PUD_SIZE - 1)) &&
|
||||
ALIGN_DOWN(hva, PUD_SIZE) >= vma->vm_start &&
|
||||
ALIGN(hva, PUD_SIZE) <= vma->vm_end)
|
||||
return PUD_SHIFT;
|
||||
#endif
|
||||
|
||||
if ((hva & (PMD_SIZE - 1)) == (pa & (PMD_SIZE - 1)) &&
|
||||
ALIGN_DOWN(hva, PMD_SIZE) >= vma->vm_start &&
|
||||
ALIGN(hva, PMD_SIZE) <= vma->vm_end)
|
||||
return PMD_SHIFT;
|
||||
|
||||
return PAGE_SHIFT;
|
||||
}
|
||||
|
||||
|
|
@ -1785,7 +1773,7 @@ static short kvm_s2_resolve_vma_size(const struct kvm_s2_fault_desc *s2fd,
|
|||
vma_shift = PAGE_SHIFT;
|
||||
} else {
|
||||
s2vi->max_map_size = PUD_SIZE;
|
||||
vma_shift = get_vma_page_shift(vma, s2fd->hva);
|
||||
vma_shift = get_vma_page_shift(vma);
|
||||
}
|
||||
|
||||
switch (vma_shift) {
|
||||
|
|
@ -1943,16 +1931,6 @@ static int kvm_s2_fault_pin_pfn(const struct kvm_s2_fault_desc *s2fd,
|
|||
return -EFAULT;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If the page was identified as device early by looking at
|
||||
* the VMA flags, vma_pagesize is already representing the
|
||||
* largest quantity we can map. If instead it was mapped
|
||||
* via __kvm_faultin_pfn(), vma_pagesize is set to PAGE_SIZE
|
||||
* and must not be upgraded.
|
||||
*
|
||||
* In both cases, we don't let transparent_hugepage_adjust()
|
||||
* change things at the last minute.
|
||||
*/
|
||||
s2vi->map_non_cacheable = true;
|
||||
}
|
||||
|
||||
|
|
@ -2042,10 +2020,10 @@ static int kvm_s2_fault_map(const struct kvm_s2_fault_desc *s2fd,
|
|||
|
||||
/*
|
||||
* If we are not forced to use page mapping, check if we are
|
||||
* backed by a THP and thus use block mapping if possible.
|
||||
* backed by a huge stage-1 mapping and thus use block mapping if
|
||||
* possible.
|
||||
*/
|
||||
if (mapping_size == PAGE_SIZE &&
|
||||
!(s2vi->max_map_size == PAGE_SIZE || s2vi->map_non_cacheable)) {
|
||||
if (mapping_size == PAGE_SIZE && s2vi->max_map_size != PAGE_SIZE) {
|
||||
if (perm_fault_granule > PAGE_SIZE) {
|
||||
mapping_size = perm_fault_granule;
|
||||
} else {
|
||||
|
|
@ -2126,10 +2104,6 @@ static int user_mem_abort(const struct kvm_s2_fault_desc *s2fd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Let's check if we will get back a huge page backed by hugetlbfs, or
|
||||
* get block mapping for device MMIO region.
|
||||
*/
|
||||
ret = kvm_s2_fault_pin_pfn(s2fd, &s2vi);
|
||||
if (ret != 1)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -45,11 +45,24 @@ struct vncr_tlb {
|
|||
*/
|
||||
#define S2_MMU_PER_VCPU 2
|
||||
|
||||
void kvm_init_nested(struct kvm *kvm)
|
||||
int kvm_init_nested(struct kvm *kvm)
|
||||
{
|
||||
kvm->arch.nested_mmus = NULL;
|
||||
kvm->arch.nested_mmus = kvmalloc_objs(struct kvm_s2_mmu *,
|
||||
KVM_MAX_VCPUS * S2_MMU_PER_VCPU,
|
||||
GFP_KERNEL_ACCOUNT);
|
||||
kvm->arch.nested_mmus_size = 0;
|
||||
atomic_set(&kvm->arch.vncr_tlb_count, 0);
|
||||
|
||||
return kvm->arch.nested_mmus ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void kvm_destroy_nested(struct kvm *kvm)
|
||||
{
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i+= S2_MMU_PER_VCPU)
|
||||
kvfree(kvm->arch.nested_mmus[i]);
|
||||
|
||||
kvm->arch.nested_mmus_size = 0;
|
||||
kvfree(kvm->arch.nested_mmus);
|
||||
}
|
||||
|
||||
static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
|
||||
|
|
@ -70,8 +83,9 @@ static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
|
|||
int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_s2_mmu *tmp;
|
||||
int num_mmus, ret = 0;
|
||||
int num_mmus;
|
||||
|
||||
lockdep_assert_held(&kvm->arch.config_lock);
|
||||
|
||||
if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) &&
|
||||
!cpus_have_final_cap(ARM64_HAS_HCR_NV1))
|
||||
|
|
@ -84,51 +98,40 @@ int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu)
|
|||
if (!vcpu->arch.ctxt.vncr_array)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Let's treat memory allocation failures as benign: If we fail to
|
||||
* allocate anything, return an error and keep the allocated array
|
||||
* alive. Userspace may try to recover by initializing the vcpu
|
||||
* again, and there is no reason to affect the whole VM for this.
|
||||
*/
|
||||
num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU;
|
||||
|
||||
if (num_mmus > kvm->arch.nested_mmus_size) {
|
||||
tmp = kvzalloc_objs(*tmp, num_mmus, GFP_KERNEL_ACCOUNT);
|
||||
struct kvm_s2_mmu *tmp;
|
||||
int i, ret = 0;
|
||||
|
||||
tmp = kvzalloc_objs(*tmp, S2_MMU_PER_VCPU, GFP_KERNEL_ACCOUNT);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
|
||||
write_lock(&kvm->mmu_lock);
|
||||
|
||||
if (kvm->arch.nested_mmus_size) {
|
||||
memcpy(tmp, kvm->arch.nested_mmus,
|
||||
size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size));
|
||||
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++)
|
||||
tmp[i].pgt->mmu = &tmp[i];
|
||||
for (i = 0; !ret && i < S2_MMU_PER_VCPU; i++) {
|
||||
ret = init_nested_s2_mmu(kvm, &tmp[i]);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
swap(kvm->arch.nested_mmus, tmp);
|
||||
if (ret) {
|
||||
while (--i >= 0)
|
||||
kvm_free_stage2_pgd(&tmp[i]);
|
||||
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
kvfree(tmp);
|
||||
free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
|
||||
vcpu->arch.ctxt.vncr_array = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
kvfree(tmp);
|
||||
guard(write_lock)(&kvm->mmu_lock);
|
||||
|
||||
for (i = 0; i < S2_MMU_PER_VCPU; i++)
|
||||
kvm->arch.nested_mmus[i + kvm->arch.nested_mmus_size] = &tmp[i];
|
||||
|
||||
kvm->arch.nested_mmus_size += S2_MMU_PER_VCPU;
|
||||
}
|
||||
|
||||
for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++)
|
||||
ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]);
|
||||
|
||||
if (ret) {
|
||||
for (int i = kvm->arch.nested_mmus_size; i < num_mmus; i++)
|
||||
kvm_free_stage2_pgd(&kvm->arch.nested_mmus[i]);
|
||||
|
||||
free_page((unsigned long)vcpu->arch.ctxt.vncr_array);
|
||||
vcpu->arch.ctxt.vncr_array = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
kvm->arch.nested_mmus_size = num_mmus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -742,7 +745,7 @@ void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid,
|
|||
write_lock(&kvm->mmu_lock);
|
||||
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (!kvm_s2_mmu_valid(mmu))
|
||||
continue;
|
||||
|
|
@ -784,7 +787,7 @@ struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu)
|
|||
* if S2 translation is disabled.
|
||||
*/
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (!kvm_s2_mmu_valid(mmu))
|
||||
continue;
|
||||
|
|
@ -823,7 +826,7 @@ static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu)
|
|||
for (i = kvm->arch.nested_mmus_next;
|
||||
i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next);
|
||||
i++) {
|
||||
s2_mmu = &kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size];
|
||||
s2_mmu = kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size];
|
||||
|
||||
if (atomic_read(&s2_mmu->refcnt) == 0)
|
||||
break;
|
||||
|
|
@ -1260,6 +1263,17 @@ void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val)
|
|||
invalidate_vncr_va(vcpu->kvm, &scope);
|
||||
}
|
||||
|
||||
static void kvm_invalidate_vncr_ipa_all(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_pgtable *pgt = kvm->arch.mmu.pgt;
|
||||
|
||||
lockdep_assert_held_write(&kvm->mmu_lock);
|
||||
|
||||
/* if the mmu lock was dropped, pgt teardown may have raced. */
|
||||
if (pgt)
|
||||
kvm_invalidate_vncr_ipa(kvm, 0, BIT(pgt->ia_bits));
|
||||
}
|
||||
|
||||
void kvm_nested_s2_wp(struct kvm *kvm)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -1270,13 +1284,13 @@ void kvm_nested_s2_wp(struct kvm *kvm)
|
|||
return;
|
||||
|
||||
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (kvm_s2_mmu_valid(mmu))
|
||||
kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu));
|
||||
}
|
||||
|
||||
kvm_invalidate_vncr_ipa(kvm, 0, BIT(kvm->arch.mmu.pgt->ia_bits));
|
||||
kvm_invalidate_vncr_ipa_all(kvm);
|
||||
}
|
||||
|
||||
void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
|
||||
|
|
@ -1289,13 +1303,13 @@ void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block)
|
|||
return;
|
||||
|
||||
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (kvm_s2_mmu_valid(mmu))
|
||||
kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block);
|
||||
}
|
||||
|
||||
kvm_invalidate_vncr_ipa(kvm, 0, BIT(kvm->arch.mmu.pgt->ia_bits));
|
||||
kvm_invalidate_vncr_ipa_all(kvm);
|
||||
}
|
||||
|
||||
void kvm_nested_s2_flush(struct kvm *kvm)
|
||||
|
|
@ -1308,7 +1322,7 @@ void kvm_nested_s2_flush(struct kvm *kvm)
|
|||
return;
|
||||
|
||||
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (kvm_s2_mmu_valid(mmu))
|
||||
kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu));
|
||||
|
|
@ -1317,17 +1331,12 @@ void kvm_nested_s2_flush(struct kvm *kvm)
|
|||
|
||||
void kvm_arch_flush_shadow_all(struct kvm *kvm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i];
|
||||
for (int i = 0; i < kvm->arch.nested_mmus_size; i++) {
|
||||
struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i];
|
||||
|
||||
if (!WARN_ON(atomic_read(&mmu->refcnt)))
|
||||
kvm_free_stage2_pgd(mmu);
|
||||
}
|
||||
kvfree(kvm->arch.nested_mmus);
|
||||
kvm->arch.nested_mmus = NULL;
|
||||
kvm->arch.nested_mmus_size = 0;
|
||||
kvm_uninit_stage2_mmu(kvm);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -926,6 +926,7 @@ static u64 *demux_wb_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd)
|
|||
struct kvm_guest_debug_arch *dbg = &vcpu->arch.vcpu_debug_state;
|
||||
|
||||
switch (rd->Op2) {
|
||||
case 0b001:
|
||||
case 0b100:
|
||||
return &dbg->dbg_bvr[rd->CRm];
|
||||
case 0b101:
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
|||
/*
|
||||
* - Acquiring the vCPU mutex for every *online* vCPU to prevent
|
||||
* concurrent vCPU ioctls for vCPUs already visible to userspace.
|
||||
* This also ensures KVM isn't in the middle of creating a vCPU,
|
||||
* i.e. that there are no vCPUs that have been created but aren't
|
||||
* yet fully online.
|
||||
*/
|
||||
ret = -EBUSY;
|
||||
if (kvm_trylock_all_vcpus(kvm))
|
||||
|
|
@ -105,18 +108,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
|||
/*
|
||||
* - Taking the config_lock which protects VGIC data structures such
|
||||
* as the per-vCPU arrays of private IRQs (SGIs, PPIs).
|
||||
*/
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
/*
|
||||
* - Bailing on the entire thing if a vCPU is in the middle of creation,
|
||||
* dropped the kvm->lock, but hasn't reached kvm_arch_vcpu_create().
|
||||
*
|
||||
* The whole combination of this guarantees that no vCPU can get into
|
||||
* KVM with a VGIC configuration inconsistent with the VM's VGIC.
|
||||
*/
|
||||
if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
|
||||
goto out_unlock;
|
||||
mutex_lock(&kvm->arch.config_lock);
|
||||
|
||||
if (irqchip_in_kernel(kvm)) {
|
||||
ret = -EEXIST;
|
||||
|
|
|
|||
|
|
@ -319,12 +319,16 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int update_affinity(struct vgic_irq *irq, struct kvm_vcpu *vcpu)
|
||||
static int update_affinity(struct vgic_irq *irq,
|
||||
struct kvm_vcpu *from_vcpu, struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct its_vlpi_map map;
|
||||
int ret;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&irq->irq_lock);
|
||||
if (from_vcpu && irq->target_vcpu != from_vcpu)
|
||||
return 0;
|
||||
|
||||
irq->target_vcpu = vcpu;
|
||||
|
||||
if (!irq->hw)
|
||||
|
|
@ -362,7 +366,7 @@ static void update_affinity_ite(struct kvm *kvm, struct its_ite *ite)
|
|||
return;
|
||||
|
||||
vcpu = collection_to_vcpu(kvm, ite->collection);
|
||||
update_affinity(ite->irq, vcpu);
|
||||
update_affinity(ite->irq, NULL, vcpu);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -856,7 +860,7 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
|
|||
|
||||
vgic_its_invalidate_cache(its);
|
||||
|
||||
return update_affinity(ite->irq, vcpu);
|
||||
return update_affinity(ite->irq, NULL, vcpu);
|
||||
}
|
||||
|
||||
static bool __is_visible_gfn_locked(struct vgic_its *its, gpa_t gpa)
|
||||
|
|
@ -1383,7 +1387,7 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
|
|||
if (!irq)
|
||||
continue;
|
||||
|
||||
update_affinity(irq, vcpu2);
|
||||
update_affinity(irq, vcpu1, vcpu2);
|
||||
|
||||
vgic_put_irq(kvm, irq);
|
||||
}
|
||||
|
|
@ -1658,7 +1662,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
|
|||
unsigned long val)
|
||||
{
|
||||
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
|
||||
u64 entry_size, table_type;
|
||||
u64 old, entry_size, table_type;
|
||||
u64 reg, *regptr, clearbits = 0;
|
||||
|
||||
/* When GITS_CTLR.Enable is 1, we ignore write accesses. */
|
||||
|
|
@ -1681,7 +1685,9 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
|
|||
return;
|
||||
}
|
||||
|
||||
reg = update_64bit_reg(*regptr, addr & 7, len, val);
|
||||
old = *regptr;
|
||||
|
||||
reg = update_64bit_reg(old, addr & 7, len, val);
|
||||
reg &= ~GITS_BASER_RO_MASK;
|
||||
reg &= ~clearbits;
|
||||
|
||||
|
|
@ -1691,7 +1697,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
|
|||
|
||||
*regptr = reg;
|
||||
|
||||
if (!(reg & GITS_BASER_VALID)) {
|
||||
/* The ITS driver rewrites an unchanged GITS_BASER<n> on resume. */
|
||||
if (reg != old) {
|
||||
/* Take the its_lock to prevent a race with a save/restore */
|
||||
mutex_lock(&its->its_lock);
|
||||
switch (table_type) {
|
||||
|
|
@ -1702,6 +1709,8 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
|
|||
vgic_its_free_collection_list(kvm, its);
|
||||
break;
|
||||
}
|
||||
/* A concurrent injection may have cached a translation. */
|
||||
vgic_its_invalidate_cache(its);
|
||||
mutex_unlock(&its->its_lock);
|
||||
}
|
||||
}
|
||||
|
|
@ -2019,18 +2028,22 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 compute_next_devid_offset(struct list_head *h,
|
||||
static u32 compute_next_devid_offset(struct vgic_its *its, u64 baser,
|
||||
struct its_device *dev)
|
||||
{
|
||||
struct its_device *next;
|
||||
u32 next_offset;
|
||||
struct its_device *next = dev;
|
||||
|
||||
if (list_is_last(&dev->dev_list, h))
|
||||
return 0;
|
||||
next = list_next_entry(dev, dev_list);
|
||||
next_offset = next->device_id - dev->device_id;
|
||||
/*
|
||||
* Point at the next device vgic_its_save_device_tables() saves. It
|
||||
* sorts device_list first, so the subtraction cannot underflow.
|
||||
*/
|
||||
list_for_each_entry_continue(next, &its->device_list, dev_list) {
|
||||
if (vgic_its_check_id(its, baser, next->device_id, NULL))
|
||||
return min_t(u32, next->device_id - dev->device_id,
|
||||
VITS_DTE_MAX_DEVID_OFFSET);
|
||||
}
|
||||
|
||||
return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
|
||||
|
|
@ -2271,17 +2284,18 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
|
|||
* vgic_its_save_dte - Save a device table entry at a given GPA
|
||||
*
|
||||
* @its: ITS handle
|
||||
* @baser: GITS_BASER<dev> the caller is saving against
|
||||
* @dev: ITS device
|
||||
* @ptr: GPA
|
||||
*/
|
||||
static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
|
||||
gpa_t ptr)
|
||||
static int vgic_its_save_dte(struct vgic_its *its, u64 baser,
|
||||
struct its_device *dev, gpa_t ptr)
|
||||
{
|
||||
u64 val, itt_addr_field;
|
||||
u32 next_offset;
|
||||
|
||||
itt_addr_field = dev->itt_addr >> 8;
|
||||
next_offset = compute_next_devid_offset(&its->device_list, dev);
|
||||
next_offset = compute_next_devid_offset(its, baser, dev);
|
||||
val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
|
||||
((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
|
||||
(itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
|
||||
|
|
@ -2380,15 +2394,16 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
|
|||
int ret;
|
||||
gpa_t eaddr;
|
||||
|
||||
/* Don't fail a save that userspace must be able to issue. */
|
||||
if (!vgic_its_check_id(its, baser,
|
||||
dev->device_id, &eaddr))
|
||||
return -EINVAL;
|
||||
continue;
|
||||
|
||||
ret = vgic_its_save_itt(its, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vgic_its_save_dte(its, dev, eaddr);
|
||||
ret = vgic_its_save_dte(its, baser, dev, eaddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -2541,9 +2556,6 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
|
|||
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
|
||||
|
||||
list_for_each_entry(collection, &its->collection_list, coll_list) {
|
||||
if (!vgic_its_check_id(its, baser, collection->collection_id, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
ret = vgic_its_save_cte(its, collection, gpa);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,10 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
|||
for (int lr = 0; lr < vgic_cpu->vgic_v2.used_lrs; lr++)
|
||||
vgic_v2_fold_lr(vcpu, cpuif->vgic_lr[lr]);
|
||||
|
||||
cpuif->used_lrs = 0;
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
/* See the GICv3 equivalent for the EOIcount handling rationale */
|
||||
list_for_each_entry_continue(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
u32 lr;
|
||||
|
|
@ -144,8 +148,6 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
|||
vgic_v2_fold_lr(vcpu, lr);
|
||||
eoicount--;
|
||||
}
|
||||
|
||||
cpuif->used_lrs = 0;
|
||||
}
|
||||
|
||||
void vgic_v2_deactivate(struct kvm_vcpu *vcpu, u32 val)
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
|||
for (int lr = 0; lr < cpuif->used_lrs; lr++)
|
||||
vgic_v3_fold_lr(vcpu, cpuif->vgic_lr[lr]);
|
||||
|
||||
cpuif->used_lrs = 0;
|
||||
if (!irq)
|
||||
return;
|
||||
|
||||
/*
|
||||
* EOIMode=0: use EOIcount to emulate deactivation. We are
|
||||
* guaranteed to deactivate in reverse order of the activation, so
|
||||
|
|
@ -188,8 +192,6 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
|||
vgic_v3_fold_lr(vcpu, lr);
|
||||
eoicount--;
|
||||
}
|
||||
|
||||
cpuif->used_lrs = 0;
|
||||
}
|
||||
|
||||
void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
|
||||
|
|
|
|||
|
|
@ -853,6 +853,17 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
|
|||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix the last_lr_irq refcount which was obtained while
|
||||
* populating the LRs. This can also result in the LPI being
|
||||
* deleted.
|
||||
*/
|
||||
irq = *host_data_ptr(last_lr_irq);
|
||||
if (irq) {
|
||||
deleted_lpis |= vgic_put_irq_norelease(vcpu->kvm, irq);
|
||||
*host_data_ptr(last_lr_irq) = NULL;
|
||||
}
|
||||
|
||||
raw_spin_unlock(&vgic_cpu->ap_list_lock);
|
||||
|
||||
if (unlikely(deleted_lpis))
|
||||
|
|
@ -866,9 +877,6 @@ static void vgic_fold_state(struct kvm_vcpu *vcpu)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!*host_data_ptr(last_lr_irq))
|
||||
return;
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_fold_lr_state(vcpu);
|
||||
else
|
||||
|
|
@ -1021,11 +1029,14 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
|
|||
scoped_guard(raw_spinlock, &irq->irq_lock) {
|
||||
if (likely(vgic_target_oracle(irq) == vcpu)) {
|
||||
vgic_populate_lr(vcpu, irq, count++);
|
||||
*host_data_ptr(last_lr_irq) = irq;
|
||||
if (count == kvm_vgic_global_state.nr_lr) {
|
||||
vgic_get_irq_ref(irq);
|
||||
*host_data_ptr(last_lr_irq) = irq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == kvm_vgic_global_state.nr_lr)
|
||||
if (*host_data_ptr(last_lr_irq))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -600,6 +600,8 @@ static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
|
|||
* 12 registers are on the stack
|
||||
*/
|
||||
emit(A64_SUB_I(1, A64_SP, A64_FP, 96), ctx);
|
||||
/* The callback may use its own BPF stack, set up fp for it. */
|
||||
ctx->fp_used = true;
|
||||
}
|
||||
|
||||
/* Stack must be multiples of 16B */
|
||||
|
|
|
|||
|
|
@ -1111,7 +1111,7 @@ static void emit_jmp_i64(struct jit_context *ctx,
|
|||
emit(ctx, xor, tmp, lo(dst), tmp);
|
||||
}
|
||||
if (imm < 0) { /* Compare sign extension */
|
||||
emit(ctx, addu, MIPS_R_T9, hi(dst), 1);
|
||||
emit(ctx, addiu, MIPS_R_T9, hi(dst), 1);
|
||||
emit(ctx, or, tmp, tmp, MIPS_R_T9);
|
||||
} else { /* Compare zero extension */
|
||||
emit(ctx, or, tmp, tmp, hi(dst));
|
||||
|
|
|
|||
|
|
@ -305,8 +305,7 @@ static void emit_bswap_r64(struct jit_context *ctx, u8 dst, u32 width)
|
|||
case 16:
|
||||
emit_sext(ctx, dst, dst);
|
||||
emit_bswap_r(ctx, dst, width);
|
||||
if (cpu_has_mips64r2 || cpu_has_mips64r6)
|
||||
emit_zext(ctx, dst);
|
||||
emit_zext(ctx, dst);
|
||||
break;
|
||||
}
|
||||
clobber_reg(ctx, dst);
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_PARISC_COMPAT_UCONTEXT_H
|
||||
#define _ASM_PARISC_COMPAT_UCONTEXT_H
|
||||
|
||||
#include <linux/compat.h>
|
||||
|
||||
/* 32-bit ucontext as seen from an 64-bit kernel */
|
||||
struct compat_ucontext {
|
||||
compat_uint_t uc_flags;
|
||||
compat_uptr_t uc_link;
|
||||
compat_stack_t uc_stack; /* struct compat_sigaltstack (12 bytes)*/
|
||||
/* FIXME: Pad out to get uc_mcontext to start at an 8-byte aligned boundary */
|
||||
compat_uint_t pad[1];
|
||||
struct compat_sigcontext uc_mcontext;
|
||||
compat_sigset_t uc_sigmask; /* mask last for extensibility */
|
||||
};
|
||||
|
||||
#endif /* !_ASM_PARISC_COMPAT_UCONTEXT_H */
|
||||
|
|
@ -24,7 +24,7 @@ struct thread_info {
|
|||
|
||||
/* thread information allocation */
|
||||
|
||||
#ifdef CONFIG_IRQSTACKS
|
||||
#if defined(CONFIG_IRQSTACKS) && !defined(CONFIG_64BIT)
|
||||
#define THREAD_SIZE_ORDER 2 /* PA-RISC requires at least 16k stack */
|
||||
#else
|
||||
#define THREAD_SIZE_ORDER 3 /* PA-RISC requires at least 32k stack */
|
||||
|
|
|
|||
|
|
@ -132,6 +132,18 @@ void __init setup_arch(char **cmdline_p)
|
|||
parisc_cache_init();
|
||||
paging_init();
|
||||
|
||||
/*
|
||||
* Parse early parameters before mm_core_init_early() runs.
|
||||
* Several early_param() handlers only record data that is consumed
|
||||
* from there - for example hugepages=, hugepagesz=,
|
||||
* default_hugepagesz=, hugetlb_cma= and hugetlb_free_vmemmap= - so
|
||||
* the generic parse_early_param() call in start_kernel() is too late
|
||||
* for them. jump_label_init() must come first, since early param
|
||||
* handlers may enable or disable static keys.
|
||||
*/
|
||||
jump_label_init();
|
||||
parse_early_param();
|
||||
|
||||
#ifdef CONFIG_PA11
|
||||
dma_ops_init();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
|
@ -49,27 +50,23 @@ static DEFINE_SPINLOCK(unwind_lock);
|
|||
static struct unwind_table kernel_unwind_table __ro_after_init;
|
||||
static LIST_HEAD(unwind_tables);
|
||||
|
||||
static int cmp_unwind_entry(const void *key, const void *elt)
|
||||
{
|
||||
unsigned long addr = (unsigned long)key;
|
||||
const struct unwind_table_entry *e = elt;
|
||||
|
||||
if (addr < e->region_start)
|
||||
return -1;
|
||||
if (addr > e->region_end)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const struct unwind_table_entry *
|
||||
find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
|
||||
{
|
||||
const struct unwind_table_entry *e = NULL;
|
||||
unsigned long lo, hi, mid;
|
||||
|
||||
lo = 0;
|
||||
hi = table->length - 1;
|
||||
|
||||
while (lo <= hi) {
|
||||
mid = (hi - lo) / 2 + lo;
|
||||
e = &table->table[mid];
|
||||
if (addr < e->region_start)
|
||||
hi = mid - 1;
|
||||
else if (addr > e->region_end)
|
||||
lo = mid + 1;
|
||||
else
|
||||
return e;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return bsearch((void *)addr, table->table, table->length,
|
||||
sizeof(*table->table), cmp_unwind_entry);
|
||||
}
|
||||
|
||||
static const struct unwind_table_entry *
|
||||
|
|
|
|||
|
|
@ -3058,7 +3058,6 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu)
|
|||
|
||||
init_waitqueue_head(&vcpu->arch.cpu_run);
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
vcore = NULL;
|
||||
err = -EINVAL;
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
||||
|
|
@ -3091,7 +3090,6 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu)
|
|||
mutex_unlock(&kvm->arch.mmu_setup_lock);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
if (!vcore)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -188,12 +188,24 @@
|
|||
#define HGATP_MODE_SHIFT HGATP32_MODE_SHIFT
|
||||
#endif
|
||||
|
||||
/* VSIP & HVIP relation */
|
||||
/*
|
||||
* VSIP & HVIP relation
|
||||
*
|
||||
* The bit positions are same between VSIP and HVIP for interrupt
|
||||
* numbers 13-63, where there's a shift for the SSI, STI and SEI.
|
||||
*/
|
||||
#define VSIP_TO_HVIP_SHIFT (IRQ_VS_SOFT - IRQ_S_SOFT)
|
||||
#define VSIP_VALID_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
|
||||
#define VSIP_BIAS_MASK ((_AC(1, UL) << IRQ_S_SOFT) | \
|
||||
(_AC(1, UL) << IRQ_S_TIMER) | \
|
||||
(_AC(1, UL) << IRQ_S_EXT) | \
|
||||
(_AC(1, UL) << IRQ_PMU_OVF))
|
||||
(_AC(1, UL) << IRQ_S_EXT))
|
||||
#define VSIP_NO_BIAS_MASK (_AC(1, UL) << IRQ_PMU_OVF)
|
||||
#define VSIP_VALID_MASK (VSIP_BIAS_MASK | VSIP_NO_BIAS_MASK)
|
||||
#define vsip_to_hvip(_vsip) ((((_vsip) & VSIP_BIAS_MASK) << \
|
||||
VSIP_TO_HVIP_SHIFT) | \
|
||||
((_vsip) & VSIP_NO_BIAS_MASK))
|
||||
#define hvip_to_vsip(_hvip) ((((_hvip) >> VSIP_TO_HVIP_SHIFT) & \
|
||||
VSIP_BIAS_MASK) | \
|
||||
((_hvip) & VSIP_NO_BIAS_MASK))
|
||||
|
||||
/* AIA CSR bits */
|
||||
#define TOPI_IID_SHIFT 16
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ static int aia_init(struct kvm *kvm)
|
|||
return -EBUSY;
|
||||
|
||||
/* We might be in the middle of creating a VCPU? */
|
||||
if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
|
||||
if (kvm_is_vcpu_creation_in_progress(kvm))
|
||||
return -EBUSY;
|
||||
|
||||
/* Number of sources should be less than or equals number of IDs */
|
||||
|
|
|
|||
|
|
@ -965,9 +965,14 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
|
|||
if (!vcpu)
|
||||
return -ENODEV;
|
||||
|
||||
if (mutex_lock_killable(&vcpu->mutex))
|
||||
return -EINTR;
|
||||
|
||||
imsic = vcpu->arch.aia_context.imsic_state;
|
||||
if (!imsic)
|
||||
return -ENODEV;
|
||||
if (!imsic) {
|
||||
rc = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type);
|
||||
|
||||
read_lock_irqsave(&imsic->vsfile_lock, flags);
|
||||
|
|
@ -991,6 +996,8 @@ int kvm_riscv_aia_imsic_rw_attr(struct kvm *kvm, unsigned long type,
|
|||
rc = imsic_vsfile_rw(vsfile_hgei, vsfile_cpu, imsic->nr_eix,
|
||||
isel, write, val);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&vcpu->mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -627,6 +627,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
|
|||
int ret;
|
||||
kvm_pfn_t hfn;
|
||||
bool is_hugetlb;
|
||||
bool unused = false;
|
||||
bool writable;
|
||||
unsigned int vma_pageshift;
|
||||
gfn_t gfn = gpa >> PAGE_SHIFT;
|
||||
|
|
@ -707,6 +708,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
|
|||
vma_pageshift, current);
|
||||
return 0;
|
||||
}
|
||||
if (is_sigpending_pfn(hfn))
|
||||
return -EINTR;
|
||||
if (is_error_noslot_pfn(hfn))
|
||||
return -EFAULT;
|
||||
|
||||
|
|
@ -719,8 +722,10 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
|
|||
|
||||
write_lock(&kvm->mmu_lock);
|
||||
|
||||
if (mmu_invalidate_retry(kvm, mmu_seq))
|
||||
if (mmu_invalidate_retry(kvm, mmu_seq)) {
|
||||
unused = true;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we are backed by a THP and thus use block mapping if
|
||||
|
|
@ -743,7 +748,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
|
|||
kvm_err("Failed to map in G-stage\n");
|
||||
|
||||
out_unlock:
|
||||
kvm_release_faultin_page(kvm, page, ret && ret != -EEXIST, writable);
|
||||
kvm_release_faultin_page(kvm, page,
|
||||
unused || (ret && ret != -EEXIST), writable);
|
||||
write_unlock(&kvm->mmu_lock);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,12 +42,24 @@ void __kvm_riscv_nacl_hfence(void *shmem,
|
|||
}
|
||||
}
|
||||
|
||||
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
|
||||
*entp = cpu_to_lelong(control);
|
||||
/*
|
||||
* Per SBI v3.0 section 15.1.2, the Page_Number and Page_Count
|
||||
* words must be updated before the Config word with its Pending
|
||||
* bit set. WRITE_ONCE() stops the compiler from reordering the
|
||||
* stores and smp_wmb() makes the parameter words globally
|
||||
* visible to the SBI implementation (or NACL hardware) before
|
||||
* the Pending bit is set.
|
||||
*/
|
||||
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
|
||||
*entp = cpu_to_lelong(page_num);
|
||||
WRITE_ONCE(*entp, cpu_to_lelong(page_num));
|
||||
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
|
||||
*entp = cpu_to_lelong(page_count);
|
||||
WRITE_ONCE(*entp, cpu_to_lelong(page_count));
|
||||
|
||||
/* Ensure the parameter words are visible before the Pending bit */
|
||||
smp_wmb();
|
||||
|
||||
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
|
||||
WRITE_ONCE(*entp, cpu_to_lelong(control));
|
||||
}
|
||||
|
||||
int kvm_riscv_nacl_enable(void)
|
||||
|
|
|
|||
|
|
@ -491,8 +491,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
|
|||
bool ret;
|
||||
|
||||
raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
|
||||
ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
|
||||
<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
|
||||
ie = vsip_to_hvip(vcpu->arch.guest_csr.vsie) & (unsigned long)mask;
|
||||
ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
|
||||
(unsigned long)mask;
|
||||
ret = vcpu->arch.irqs_pending[0] & ie;
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
}
|
||||
|
||||
/* Print details in-case of error */
|
||||
if (ret < 0) {
|
||||
if (ret < 0 && ret != -EINTR) {
|
||||
kvm_err("VCPU exit error %d\n", ret);
|
||||
kvm_err("SEPC=0x%lx SSTATUS=0x%lx HSTATUS=0x%lx\n",
|
||||
vcpu->arch.guest_context.sepc,
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
|
|||
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
|
||||
kvm_riscv_vcpu_flush_interrupts(vcpu);
|
||||
*out_val = (csr->hvip >> VSIP_TO_HVIP_SHIFT) & VSIP_VALID_MASK;
|
||||
*out_val = hvip_to_vsip(csr->hvip);
|
||||
*out_val |= csr->hvip & ~IRQ_LOCAL_MASK;
|
||||
} else
|
||||
*out_val = ((unsigned long *)csr)[reg_num];
|
||||
|
|
@ -293,10 +293,8 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
|||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
|
||||
reg_val &= VSIP_VALID_MASK;
|
||||
reg_val <<= VSIP_TO_HVIP_SHIFT;
|
||||
}
|
||||
if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
|
||||
reg_val = vsip_to_hvip(reg_val);
|
||||
|
||||
((unsigned long *)csr)[reg_num] = reg_val;
|
||||
|
||||
|
|
|
|||
|
|
@ -270,12 +270,13 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
|||
return -EINVAL;
|
||||
|
||||
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
|
||||
*out_val = pmc->counter_val;
|
||||
} else if (pmc->perf_event) {
|
||||
pmc->counter_val += perf_event_read_value(pmc->perf_event, &enabled, &running);
|
||||
*out_val = pmc->counter_val +
|
||||
perf_event_read_value(pmc->perf_event, &enabled, &running);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
*out_val = pmc->counter_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -454,6 +455,14 @@ int kvm_riscv_vcpu_pmu_snapshot_set_shmem(struct kvm_vcpu *vcpu, unsigned long s
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear any previously installed snapshot area to avoid leaking
|
||||
* the old sdata and to keep sdata/snapshot_addr consistent if
|
||||
* the re-install fails below.
|
||||
*/
|
||||
if (kvpmu->snapshot_addr != INVALID_GPA)
|
||||
kvm_pmu_clear_snapshot_area(vcpu);
|
||||
|
||||
kvpmu->sdata = kzalloc(snapshot_area_size, GFP_ATOMIC | __GFP_ACCOUNT);
|
||||
if (!kvpmu->sdata) {
|
||||
sbiret = SBI_ERR_FAILURE;
|
||||
|
|
@ -645,7 +654,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
{
|
||||
struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
|
||||
int i, pmc_index, sbiret = 0;
|
||||
u64 enabled, running;
|
||||
struct kvm_pmc *pmc;
|
||||
int fevent_code;
|
||||
bool snap_flag_set = flags & SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
|
||||
|
|
@ -675,14 +683,19 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!kvpmu->fw_event[fevent_code].started)
|
||||
if (!kvpmu->fw_event[fevent_code].started) {
|
||||
sbiret = SBI_ERR_ALREADY_STOPPED;
|
||||
|
||||
kvpmu->fw_event[fevent_code].started = false;
|
||||
} else {
|
||||
kvpmu->fw_event[fevent_code].started = false;
|
||||
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
|
||||
}
|
||||
} else if (pmc->perf_event) {
|
||||
if (pmc->started) {
|
||||
/* Stop counting the counter */
|
||||
perf_event_disable(pmc->perf_event);
|
||||
/*
|
||||
* Stop the counter and fold the live count into counter_val.
|
||||
* Reset the event value to avoid redundant accumulation.
|
||||
*/
|
||||
pmc->counter_val += perf_event_pause(pmc->perf_event, true);
|
||||
pmc->started = false;
|
||||
} else {
|
||||
sbiret = SBI_ERR_ALREADY_STOPPED;
|
||||
|
|
@ -696,11 +709,6 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
}
|
||||
|
||||
if (snap_flag_set && !sbiret) {
|
||||
if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW)
|
||||
pmc->counter_val = kvpmu->fw_event[fevent_code].value;
|
||||
else if (pmc->perf_event)
|
||||
pmc->counter_val += perf_event_read_value(pmc->perf_event,
|
||||
&enabled, &running);
|
||||
/*
|
||||
* The counter and overflow indices in the snapshot region are w.r.to
|
||||
* cbase. Modify the set bit in the counter mask instead of the pmc_index
|
||||
|
|
@ -727,9 +735,10 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
|||
}
|
||||
}
|
||||
|
||||
if (shmem_needs_update)
|
||||
kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
|
||||
sizeof(struct riscv_pmu_snapshot_data));
|
||||
if (shmem_needs_update &&
|
||||
kvm_vcpu_write_guest(vcpu, kvpmu->snapshot_addr, kvpmu->sdata,
|
||||
sizeof(struct riscv_pmu_snapshot_data)))
|
||||
sbiret = SBI_ERR_FAILURE;
|
||||
|
||||
out:
|
||||
retdata->err_val = sbiret;
|
||||
|
|
|
|||
|
|
@ -95,9 +95,9 @@ static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||
ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
|
||||
if (ret >= 0) {
|
||||
retdata->out_val = ret;
|
||||
retdata->err_val = 0;
|
||||
ret = 0;
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
case SBI_EXT_HSM_HART_SUSPEND:
|
||||
switch (lower_32_bits(cp->a0)) {
|
||||
case SBI_HSM_SUSPEND_RET_DEFAULT:
|
||||
|
|
|
|||
|
|
@ -61,10 +61,13 @@ static enum hrtimer_restart kvm_riscv_vcpu_hrtimer_expired(struct hrtimer *h)
|
|||
|
||||
static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t)
|
||||
{
|
||||
if (!t->init_done || !t->next_set)
|
||||
if (!t->init_done)
|
||||
return -EINVAL;
|
||||
|
||||
hrtimer_cancel(&t->hrt);
|
||||
|
||||
if (!t->next_set)
|
||||
return -EINVAL;
|
||||
t->next_set = false;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -460,7 +460,11 @@ static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
|
|||
#define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \
|
||||
static int __init VNAME(var, reg)(void) \
|
||||
{ \
|
||||
debug_register_static(&var, (pages), (areas)); \
|
||||
int rc; \
|
||||
\
|
||||
rc = debug_register_static(&var, (pages), (areas)); \
|
||||
if (rc) \
|
||||
return rc; \
|
||||
debug_register_view(&var, (view)); \
|
||||
return 0; \
|
||||
} \
|
||||
|
|
@ -493,7 +497,7 @@ static debug_info_t __refdata var = \
|
|||
static debug_info_t __used __section(".s390dbf_info") *VNAME(var, info) = &var; \
|
||||
__REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
|
||||
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
|
||||
int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
|
||||
|
||||
#endif /* MODULE */
|
||||
|
||||
|
|
|
|||
|
|
@ -434,7 +434,8 @@ static debug_info_t *debug_info_copy(debug_info_t *in, int mode)
|
|||
debug_info_free(rc);
|
||||
} while (1);
|
||||
|
||||
if (mode == NO_AREAS)
|
||||
/* debug_register_static() failure leaves areas NULL, bounds intact */
|
||||
if (mode == NO_AREAS || !in->areas)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < in->nr_areas; i++) {
|
||||
|
|
@ -823,6 +824,9 @@ ssize_t debug_dump(debug_info_t *id, struct debug_view *view,
|
|||
file_private_info_t *p_info;
|
||||
size_t size, offset = 0;
|
||||
|
||||
if (!id)
|
||||
return -EINVAL;
|
||||
|
||||
/* Need space for '\0' byte */
|
||||
if (buf_size < 1)
|
||||
return 0;
|
||||
|
|
@ -950,8 +954,12 @@ EXPORT_SYMBOL(debug_register);
|
|||
*
|
||||
* Note: This function is called automatically via an initcall generated by
|
||||
* DEFINE_STATIC_DEBUG_INFO.
|
||||
*
|
||||
* Return:
|
||||
* - 0 on success
|
||||
* - negative error code on failure
|
||||
*/
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
||||
int debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
||||
{
|
||||
unsigned long flags;
|
||||
debug_info_t *copy;
|
||||
|
|
@ -959,7 +967,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
if (!initialized) {
|
||||
pr_err("Tried to register debug feature %s too early\n",
|
||||
id->name);
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug_get_param(id->name, &id->level, &pages_per_area, false);
|
||||
|
|
@ -975,7 +983,7 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
id->active_entries = NULL;
|
||||
raw_spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Replace static trace area with dynamic copy. */
|
||||
|
|
@ -993,6 +1001,8 @@ void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
|||
mutex_lock(&debug_mutex);
|
||||
_debug_register(id);
|
||||
mutex_unlock(&debug_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove debugfs entries. */
|
||||
|
|
|
|||
|
|
@ -825,7 +825,7 @@ static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN],
|
|||
{
|
||||
u16 i;
|
||||
|
||||
for (i = 0; i < list->total_num_secrets; i++) {
|
||||
for (i = 0; i < list->num_secr_stored; i++) {
|
||||
if (memcmp(secret_id, list->secrets[i].id, UV_SECRET_ID_LEN) == 0) {
|
||||
*secret = list->secrets[i].hdr;
|
||||
return 0;
|
||||
|
|
@ -846,11 +846,14 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
|||
struct uv_secret_list *list,
|
||||
struct uv_secret_list_item_hdr *secret)
|
||||
{
|
||||
u16 start_idx = 0;
|
||||
u16 start_idx;
|
||||
u16 list_rc;
|
||||
int ret;
|
||||
|
||||
list->next_secret_idx = 0;
|
||||
|
||||
do {
|
||||
start_idx = list->next_secret_idx;
|
||||
uv_list_secrets(list, start_idx, &list_rc, NULL);
|
||||
if (list_rc != UVC_RC_EXECUTED && list_rc != UVC_RC_MORE_DATA) {
|
||||
if (list_rc == UVC_RC_INV_CMD)
|
||||
|
|
@ -861,7 +864,6 @@ int uv_find_secret(const u8 secret_id[UV_SECRET_ID_LEN],
|
|||
ret = find_secret_in_page(secret_id, list, secret);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
start_idx = list->next_secret_idx;
|
||||
} while (list_rc == UVC_RC_MORE_DATA && start_idx < list->next_secret_idx);
|
||||
|
||||
return -ENOENT;
|
||||
|
|
|
|||
|
|
@ -621,17 +621,20 @@ int dat_get_storage_key(union asce asce, gfn_t gfn, union skey *skey)
|
|||
union pte *ptep;
|
||||
int rc;
|
||||
|
||||
again:
|
||||
skey->skey = 0;
|
||||
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!ptep) {
|
||||
union crste crste;
|
||||
union crste crste = READ_ONCE(*crstep);
|
||||
|
||||
crste = READ_ONCE(*crstep);
|
||||
if (!crste.h.fc || !crste.s.fc1.pr)
|
||||
if (!crste_leaf(crste) && !crste.h.i)
|
||||
goto again;
|
||||
if (!crste.s.fc1.pr)
|
||||
return 0;
|
||||
|
||||
skey->skey = page_get_storage_key(large_crste_to_phys(crste, gfn));
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -662,13 +665,20 @@ int dat_set_storage_key(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t gf
|
|||
union pte *ptep;
|
||||
int rc;
|
||||
|
||||
again:
|
||||
rc = dat_entry_walk(mc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
|
||||
&crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!ptep) {
|
||||
page_set_storage_key(large_crste_to_phys(*crstep, gfn), skey.skey, !nq);
|
||||
union crste crste = READ_ONCE(*crstep);
|
||||
|
||||
/* A large page has been split concurrently, try again */
|
||||
if (!crste_leaf(crste))
|
||||
goto again;
|
||||
|
||||
page_set_storage_key(large_crste_to_phys(crste, gfn), skey.skey, !nq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -718,15 +728,22 @@ int dat_cond_set_storage_key(struct kvm_s390_mmu_cache *mmc, union asce asce, gf
|
|||
union pte *ptep;
|
||||
int rc;
|
||||
|
||||
again:
|
||||
rc = dat_entry_walk(mmc, gfn, asce, DAT_WALK_LEAF_ALLOC, TABLE_TYPE_PAGE_TABLE,
|
||||
&crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!ptep) {
|
||||
union crste crste = READ_ONCE(*crstep);
|
||||
|
||||
/* A large page has been split concurrently, try again */
|
||||
if (!crste_leaf(crste))
|
||||
goto again;
|
||||
if (!oldkey)
|
||||
oldkey = &prev;
|
||||
return page_cond_set_storage_key(large_crste_to_phys(*crstep, gfn), skey, oldkey,
|
||||
|
||||
return page_cond_set_storage_key(large_crste_to_phys(crste, gfn), skey, oldkey,
|
||||
nq, mr, mc);
|
||||
}
|
||||
|
||||
|
|
@ -768,7 +785,7 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
|
|||
int rc;
|
||||
|
||||
skey->skey = 0;
|
||||
|
||||
again:
|
||||
rc = dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY, TABLE_TYPE_PAGE_TABLE, &crstep, &ptep);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -776,9 +793,12 @@ int dat_reset_reference_bit(union asce asce, gfn_t gfn, union skey *skey)
|
|||
if (!ptep) {
|
||||
union crste crste = READ_ONCE(*crstep);
|
||||
|
||||
if (!crste.h.fc || !crste.s.fc1.pr)
|
||||
/* A large page has been split concurrently, try again */
|
||||
if (!crste_leaf(crste) && !crste.h.i)
|
||||
goto again;
|
||||
if (!crste.s.fc1.pr)
|
||||
return 0;
|
||||
skey->skey = page_reset_referenced(large_crste_to_phys(*crstep, gfn)) << 1;
|
||||
skey->skey = page_reset_referenced(large_crste_to_phys(crste, gfn)) << 1;
|
||||
return 0;
|
||||
}
|
||||
old = pgste_get_lock(ptep);
|
||||
|
|
@ -846,19 +866,12 @@ long dat_reset_skeys(union asce asce, gfn_t start)
|
|||
}
|
||||
#endif /* KVM_S390_MANAGES_S390_GUEST */
|
||||
|
||||
struct slot_priv {
|
||||
unsigned long token;
|
||||
struct kvm_s390_mmu_cache *mc;
|
||||
};
|
||||
|
||||
static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
struct slot_priv *p = walk->priv;
|
||||
union crste dummy = { .val = p->token };
|
||||
union pte new_pte, pte = READ_ONCE(*ptep);
|
||||
union pgste pgste;
|
||||
|
||||
new_pte = _PTE_TOK(dummy.tok.type, dummy.tok.par);
|
||||
new_pte = walk->priv ? _PTE_EMPTY : _PTE_TOK(_DAT_TOKEN_PIC, PGM_ADDRESSING);
|
||||
|
||||
/* Table entry already in the desired state. */
|
||||
if (pte.val == new_pte.val)
|
||||
|
|
@ -875,10 +888,9 @@ static long _dat_slot_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_wal
|
|||
static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
union crste new_crste, crste = READ_ONCE(*crstep);
|
||||
struct slot_priv *p = walk->priv;
|
||||
struct kvm_s390_mmu_cache *mc = walk->priv;
|
||||
|
||||
new_crste.val = p->token;
|
||||
new_crste.h.tt = crste.h.tt;
|
||||
new_crste = mc ? _CRSTE_EMPTY(crste.h.tt) : _CRSTE_HOLE(crste.h.tt);
|
||||
|
||||
/* Table entry already in the desired state. */
|
||||
if (crste.val == new_crste.val)
|
||||
|
|
@ -902,7 +914,10 @@ static long _dat_slot_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct d
|
|||
if (!crste.h.fc && !crste.h.i)
|
||||
return 0;
|
||||
/* Split (install a lower level table), and handle things there. */
|
||||
return dat_split_crste(p->mc, crstep, gfn, walk->asce, false);
|
||||
if (mc)
|
||||
return dat_split_crste(mc, crstep, gfn, walk->asce, false);
|
||||
/* A large page should never cross memslots boundaries */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct dat_walk_ops dat_slot_ops = {
|
||||
|
|
@ -910,16 +925,10 @@ static const struct dat_walk_ops dat_slot_ops = {
|
|||
.crste_ops = { _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, _dat_slot_crste, },
|
||||
};
|
||||
|
||||
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end,
|
||||
u16 type, u16 param)
|
||||
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end)
|
||||
{
|
||||
struct slot_priv priv = {
|
||||
.token = _CRSTE_TOK(0, type, param).val,
|
||||
.mc = mc,
|
||||
};
|
||||
|
||||
return _dat_walk_gfn_range(start, end, asce, &dat_slot_ops,
|
||||
DAT_WALK_IGN_HOLES | DAT_WALK_ANY, &priv);
|
||||
DAT_WALK_IGN_HOLES | DAT_WALK_ANY, mc);
|
||||
}
|
||||
|
||||
static void pgste_set_unlock_multiple(union pte *first, int n, union pgste *pgstes)
|
||||
|
|
|
|||
|
|
@ -547,8 +547,7 @@ long dat_reset_skeys(union asce asce, gfn_t start);
|
|||
unsigned long dat_get_ptval(struct page_table *table, struct ptval_param param);
|
||||
void dat_set_ptval(struct page_table *table, struct ptval_param param, unsigned long val);
|
||||
|
||||
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end,
|
||||
u16 type, u16 param);
|
||||
int dat_set_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start, gfn_t end);
|
||||
|
||||
#if KVM_S390_MANAGES_S390_GUEST
|
||||
int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn);
|
||||
|
|
@ -973,16 +972,15 @@ static inline int get_level(union crste *crstep, union pte *ptep)
|
|||
return ptep ? TABLE_TYPE_PAGE_TABLE : crstep->h.tt;
|
||||
}
|
||||
|
||||
static inline int dat_delete_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
|
||||
unsigned long npages)
|
||||
static inline int dat_delete_slot(union asce asce, gfn_t start, unsigned long npages)
|
||||
{
|
||||
return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_PIC, PGM_ADDRESSING);
|
||||
return dat_set_slot(NULL, asce, start, start + npages);
|
||||
}
|
||||
|
||||
static inline int dat_create_slot(struct kvm_s390_mmu_cache *mc, union asce asce, gfn_t start,
|
||||
unsigned long npages)
|
||||
{
|
||||
return dat_set_slot(mc, asce, start, start + npages, _DAT_TOKEN_NONE, 0);
|
||||
return dat_set_slot(mc, asce, start, start + npages);
|
||||
}
|
||||
|
||||
static inline bool crste_is_ucas(union crste crste)
|
||||
|
|
|
|||
|
|
@ -994,11 +994,13 @@ static long _destroy_pages_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct da
|
|||
static long _destroy_pages_crste(union crste *crstep, gfn_t gfn, gfn_t next, struct dat_walk *walk)
|
||||
{
|
||||
phys_addr_t origin, cur, end;
|
||||
union crste crste;
|
||||
|
||||
if (!crstep->h.fc || !crstep->s.fc1.pr)
|
||||
crste = READ_ONCE(*crstep);
|
||||
if (!crste.h.fc || !crste.s.fc1.pr)
|
||||
return 0;
|
||||
|
||||
origin = crste_origin_large(*crstep);
|
||||
origin = crste_origin_large(crste);
|
||||
cur = ((max(gfn, walk->start) - gfn) << PAGE_SHIFT) + origin;
|
||||
end = ((min(next, walk->end) - gfn) << PAGE_SHIFT) + origin;
|
||||
for ( ; cur < end; cur += PAGE_SIZE)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
|
|||
struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (kvm_is_ucontrol(kvm) && new && new->id < KVM_USER_MEM_SLOTS)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -61,6 +64,10 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
|
|||
* and munmap() stuff in this slot after doing this call at any
|
||||
* time.
|
||||
*/
|
||||
if (change != KVM_MR_MOVE && change != KVM_MR_CREATE) {
|
||||
WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new->userspace_addr & ~PAGE_MASK)
|
||||
return -EINVAL;
|
||||
if ((new->base_gfn + new->npages) * PAGE_SIZE > kvm->arch.mem_limit)
|
||||
|
|
@ -69,65 +76,41 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!kvm_s390_is_migration_mode(kvm))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Turn off migration mode when:
|
||||
* - userspace creates a new memslot with dirty logging off,
|
||||
* - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
|
||||
* dirty logging is turned off.
|
||||
* Migration mode expects dirty page logging being enabled to store
|
||||
* its dirty bitmap.
|
||||
*/
|
||||
if (change != KVM_MR_DELETE &&
|
||||
!(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
|
||||
WARN(kvm_s390_vm_stop_migration(kvm),
|
||||
"Failed to stop migration mode");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s390_kvm_mmu_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *old,
|
||||
const struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
struct kvm_s390_mmu_cache *mc __free(kvm_s390_mmu_cache) = NULL;
|
||||
int rc = 0;
|
||||
|
||||
guard(mutex)(&kvm->slots_arch_lock);
|
||||
if (kvm->arch.migration_mode) {
|
||||
/*
|
||||
* Turn off migration mode when:
|
||||
* - userspace creates a new memslot with dirty logging off,
|
||||
* - userspace modifies an existing memslot (MOVE or FLAGS_ONLY)
|
||||
* and dirty logging is turned off.
|
||||
* Migration mode expects dirty page logging being enabled to
|
||||
* store its dirty bitmap.
|
||||
*/
|
||||
if (change != KVM_MR_DELETE &&
|
||||
!(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
|
||||
WARN(kvm_s390_vm_stop_migration(kvm),
|
||||
"Failed to stop migration mode");
|
||||
}
|
||||
|
||||
if (change == KVM_MR_FLAGS_ONLY)
|
||||
return;
|
||||
|
||||
mc = kvm_s390_new_mmu_cache();
|
||||
if (!mc) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
return 0;
|
||||
if (change != KVM_MR_DELETE) {
|
||||
/* Enough capacity to add a new memslot */
|
||||
mc = kvm_s390_new_mmu_cache();
|
||||
if (!mc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scoped_guard(write_lock, &kvm->mmu_lock) {
|
||||
kvm_s390_update_cmma_dirty(kvm, old);
|
||||
switch (change) {
|
||||
case KVM_MR_DELETE:
|
||||
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
|
||||
break;
|
||||
case KVM_MR_MOVE:
|
||||
rc = dat_delete_slot(mc, kvm->arch.gmap->asce, old->base_gfn, old->npages);
|
||||
if (rc)
|
||||
break;
|
||||
fallthrough;
|
||||
case KVM_MR_CREATE:
|
||||
if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
|
||||
rc = dat_delete_slot(kvm->arch.gmap->asce, old->base_gfn, old->npages);
|
||||
if (!rc && (change == KVM_MR_MOVE || change == KVM_MR_CREATE))
|
||||
rc = dat_create_slot(mc, kvm->arch.gmap->asce, new->base_gfn, new->npages);
|
||||
break;
|
||||
case KVM_MR_FLAGS_ONLY:
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Unknown KVM MR CHANGE: %d\n", change);
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (rc)
|
||||
pr_warn("failed to commit memory region\n");
|
||||
/*
|
||||
* Can only be triggered if dat_{create,delete}_slot() found an
|
||||
* internal inconsistency or if the mmu cache ran out of memory;
|
||||
* both should be impossible.
|
||||
*/
|
||||
KVM_BUG_ON(rc, kvm);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,9 +10,5 @@ int s390_kvm_mmu_prepare_memory_region(struct kvm *kvm,
|
|||
const struct kvm_memory_slot *old,
|
||||
struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change);
|
||||
void s390_kvm_mmu_commit_memory_region(struct kvm *kvm,
|
||||
struct kvm_memory_slot *old,
|
||||
const struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change);
|
||||
|
||||
#endif /* ARCH_KVM_GMAP_KVM_MMU_H */
|
||||
|
|
|
|||
|
|
@ -1589,12 +1589,25 @@ static inline int ___gaccess_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg
|
|||
parent = READ_ONCE(sg->parent);
|
||||
if (!parent)
|
||||
return -EAGAIN;
|
||||
retry:
|
||||
scoped_guard(spinlock, &parent->children_lock) {
|
||||
if (READ_ONCE(sg->parent) != parent)
|
||||
return -EAGAIN;
|
||||
sg->invalidated = false;
|
||||
rc = _gaccess_do_shadow(vcpu->arch.mc, sg, saddr, walk);
|
||||
}
|
||||
if (rc == -ENOENT) {
|
||||
struct kvm_memory_slot *slot;
|
||||
struct guest_fault *entries;
|
||||
|
||||
entries = get_entries(walk);
|
||||
slot = kvm_vcpu_gfn_to_memslot(vcpu, entries[LEVEL_MEM].gfn);
|
||||
if (!slot)
|
||||
return PGM_ADDRESSING;
|
||||
rc = gmap_link(vcpu->arch.mc, parent, entries + LEVEL_MEM, slot);
|
||||
if (!rc)
|
||||
goto retry;
|
||||
}
|
||||
if (!rc)
|
||||
kvm_s390_release_faultin_array(vcpu->kvm, walk->raw_entries, false);
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -2984,61 +2984,58 @@ static int adapter_indicators_set(struct kvm *kvm,
|
|||
struct s390_io_adapter *adapter,
|
||||
struct kvm_s390_adapter_int *adapter_int)
|
||||
{
|
||||
unsigned long bit;
|
||||
int summary_set, idx;
|
||||
struct s390_map_info *ind_info, *summary_info;
|
||||
void *map;
|
||||
struct page *ind_page, *summary_page;
|
||||
unsigned long flags;
|
||||
unsigned long bit;
|
||||
int summary_set;
|
||||
void *map;
|
||||
|
||||
ind_page = NULL;
|
||||
|
||||
spin_lock_irqsave(&adapter->maps_lock, flags);
|
||||
ind_info = get_map_info(adapter, adapter_int->ind_addr);
|
||||
scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
|
||||
ind_info = get_map_info(adapter, adapter_int->ind_addr);
|
||||
if (ind_info) {
|
||||
map = page_address(ind_info->page);
|
||||
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
|
||||
set_bit(bit, map);
|
||||
}
|
||||
}
|
||||
if (!ind_info) {
|
||||
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||
ind_page = pin_map_page(kvm, adapter_int->ind_addr, 0);
|
||||
if (!ind_page)
|
||||
return -1;
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
map = page_address(ind_page);
|
||||
bit = get_ind_bit(adapter_int->ind_addr,
|
||||
adapter_int->ind_offset, adapter->swap);
|
||||
set_bit(bit, map);
|
||||
mark_page_dirty(kvm, adapter_int->ind_gaddr >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(ind_page);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(ind_page);
|
||||
} else {
|
||||
map = page_address(ind_info->page);
|
||||
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
|
||||
set_bit(bit, map);
|
||||
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||
}
|
||||
scoped_guard(srcu, &kvm->srcu)
|
||||
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
|
||||
|
||||
spin_lock_irqsave(&adapter->maps_lock, flags);
|
||||
summary_info = get_map_info(adapter, adapter_int->summary_addr);
|
||||
scoped_guard(spinlock_irqsave, &adapter->maps_lock) {
|
||||
summary_info = get_map_info(adapter, adapter_int->summary_addr);
|
||||
if (summary_info) {
|
||||
map = page_address(summary_info->page);
|
||||
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
|
||||
adapter->swap);
|
||||
summary_set = test_and_set_bit(bit, map);
|
||||
}
|
||||
}
|
||||
if (!summary_info) {
|
||||
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||
summary_page = pin_map_page(kvm, adapter_int->summary_addr, 0);
|
||||
if (!summary_page)
|
||||
return -1;
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
map = page_address(summary_page);
|
||||
bit = get_ind_bit(adapter_int->summary_addr,
|
||||
adapter_int->summary_offset, adapter->swap);
|
||||
summary_set = test_and_set_bit(bit, map);
|
||||
mark_page_dirty(kvm, adapter_int->summary_gaddr >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(summary_page);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(summary_page);
|
||||
} else {
|
||||
map = page_address(summary_info->page);
|
||||
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
|
||||
adapter->swap);
|
||||
summary_set = test_and_set_bit(bit, map);
|
||||
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||
}
|
||||
scoped_guard(srcu, &kvm->srcu)
|
||||
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
|
||||
|
||||
return summary_set ? 0 : 1;
|
||||
}
|
||||
|
|
@ -3048,26 +3045,29 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
|
|||
struct kvm_s390_adapter_int *adapter_int,
|
||||
int setbit)
|
||||
{
|
||||
struct s390_map_info *ind_info, *summary_info;
|
||||
unsigned long bit;
|
||||
int summary_set;
|
||||
struct s390_map_info *ind_info, *summary_info;
|
||||
void *map;
|
||||
|
||||
spin_lock(&adapter->maps_lock);
|
||||
guard(srcu)(&kvm->srcu);
|
||||
guard(spinlock)(&adapter->maps_lock);
|
||||
|
||||
ind_info = get_map_info(adapter, adapter_int->ind_addr);
|
||||
if (!ind_info) {
|
||||
spin_unlock(&adapter->maps_lock);
|
||||
if (!ind_info)
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
map = page_address(ind_info->page);
|
||||
bit = get_ind_bit(ind_info->addr, adapter_int->ind_offset, adapter->swap);
|
||||
if (setbit)
|
||||
if (setbit) {
|
||||
set_bit(bit, map);
|
||||
summary_info = get_map_info(adapter, adapter_int->summary_addr);
|
||||
if (!summary_info) {
|
||||
spin_unlock(&adapter->maps_lock);
|
||||
return -EWOULDBLOCK;
|
||||
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->ind_gaddr));
|
||||
}
|
||||
|
||||
summary_info = get_map_info(adapter, adapter_int->summary_addr);
|
||||
if (!summary_info)
|
||||
return -EWOULDBLOCK;
|
||||
|
||||
map = page_address(summary_info->page);
|
||||
bit = get_ind_bit(summary_info->addr, adapter_int->summary_offset,
|
||||
adapter->swap);
|
||||
|
|
@ -3077,7 +3077,8 @@ static int adapter_indicators_set_fast(struct kvm *kvm,
|
|||
summary_set = test_and_set_bit(bit, map);
|
||||
else
|
||||
summary_set = test_and_clear_bit(bit, map);
|
||||
spin_unlock(&adapter->maps_lock);
|
||||
mark_page_dirty(kvm, gpa_to_gfn(adapter_int->summary_gaddr));
|
||||
|
||||
return summary_set ? 0 : 1;
|
||||
}
|
||||
|
||||
|
|
@ -3228,9 +3229,9 @@ int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu, void __user *irqstate, int len
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (storestatus) {
|
||||
n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
|
||||
scoped_guard(srcu, &vcpu->kvm->srcu)
|
||||
n = kvm_s390_store_status_unloaded(vcpu, KVM_S390_STORE_STATUS_NOADDR);
|
||||
return r ? r : n;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3579,12 +3579,11 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
|||
|
||||
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
mutex_lock(&vcpu->kvm->lock);
|
||||
preempt_disable();
|
||||
vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
|
||||
vcpu->arch.sie_block->epdx = vcpu->kvm->arch.epdx;
|
||||
preempt_enable();
|
||||
mutex_unlock(&vcpu->kvm->lock);
|
||||
|
||||
if (!kvm_is_ucontrol(vcpu->kvm)) {
|
||||
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
||||
sca_add_vcpu(vcpu);
|
||||
|
|
@ -3757,13 +3756,11 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
|
|||
|
||||
kvm_s390_vcpu_pci_setup(vcpu);
|
||||
|
||||
mutex_lock(&vcpu->kvm->lock);
|
||||
if (kvm_s390_pv_is_protected(vcpu->kvm)) {
|
||||
rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc);
|
||||
if (rc)
|
||||
kvm_s390_vcpu_unsetup_cmma(vcpu);
|
||||
}
|
||||
mutex_unlock(&vcpu->kvm->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -5766,7 +5763,7 @@ static long cmma_d_count_pte(union pte *ptep, gfn_t gfn, gfn_t next, struct dat_
|
|||
return 0;
|
||||
}
|
||||
|
||||
void kvm_s390_update_cmma_dirty(struct kvm *kvm, struct kvm_memory_slot *old)
|
||||
void kvm_s390_update_cmma_dirty(struct kvm *kvm, const struct kvm_memory_slot *old)
|
||||
{
|
||||
const struct dat_walk_ops ops = { .pte_entry = cmma_d_count_pte, };
|
||||
|
||||
|
|
@ -5781,7 +5778,6 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old,
|
|||
const struct kvm_memory_slot *new,
|
||||
enum kvm_mr_change change)
|
||||
{
|
||||
s390_kvm_mmu_commit_memory_region(kvm, old, new, change);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ int __kvm_s390_mprotect_many(struct gmap *gmap, gpa_t gpa, u8 npages, unsigned i
|
|||
unsigned long bits);
|
||||
|
||||
bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu);
|
||||
void kvm_s390_update_cmma_dirty(struct kvm *kvm, struct kvm_memory_slot *old);
|
||||
void kvm_s390_update_cmma_dirty(struct kvm *kvm, const struct kvm_memory_slot *old);
|
||||
int kvm_s390_vm_stop_migration(struct kvm *kvm);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
|
|||
device_lock(&pdev->dev);
|
||||
if (pdev->error_state == pci_channel_io_perm_failure) {
|
||||
ers_res = PCI_ERS_RESULT_DISCONNECT;
|
||||
status_str = "skipped (permanent failure)";
|
||||
goto out_unlock;
|
||||
}
|
||||
pdev->error_state = pci_channel_io_frozen;
|
||||
|
|
@ -297,8 +298,8 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev,
|
|||
driver->err_handler->resume(pdev);
|
||||
pci_uevent_ers(pdev, PCI_ERS_RESULT_RECOVERED);
|
||||
out_unlock:
|
||||
zpci_report_status(zdev, pdev, "recovery", status_str);
|
||||
device_unlock(&pdev->dev);
|
||||
zpci_report_status(zdev, "recovery", status_str);
|
||||
|
||||
return ers_res;
|
||||
}
|
||||
|
|
@ -361,8 +362,10 @@ static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
|
|||
|
||||
__zpci_event_print_error(pdev, ccdf);
|
||||
|
||||
if (!pdev)
|
||||
if (!pdev) {
|
||||
zpci_report_status(zdev, NULL, "error event", "no pdev bound");
|
||||
goto no_pdev;
|
||||
}
|
||||
|
||||
switch (ccdf->pec) {
|
||||
case 0x002a: /* Error event concerns FMB */
|
||||
|
|
|
|||
|
|
@ -87,9 +87,23 @@ static struct debug_view debug_log_view = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static ssize_t zpci_report_pdev(struct pci_dev *pdev, char *buf, size_t size)
|
||||
{
|
||||
struct pci_driver *driver;
|
||||
const char *start = buf;
|
||||
char *end = buf + size;
|
||||
|
||||
device_lock_assert(&pdev->dev);
|
||||
buf += scnprintf(buf, end - buf, "state: %s\n", zpci_state_str(pdev->error_state));
|
||||
driver = to_pci_driver(pdev->dev.driver);
|
||||
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
/**
|
||||
* zpci_report_status - Report the status of operations on a PCI device
|
||||
* @zdev: The PCI device for which to report status
|
||||
* @zdev: The zPCI device for which to report status
|
||||
* @pdev: The PCI device associated with the zdev if any, NULL otherwise
|
||||
* @operation: A string representing the operation reported
|
||||
* @status: A string representing the status of the operation
|
||||
*
|
||||
|
|
@ -103,15 +117,14 @@ static struct debug_view debug_log_view = {
|
|||
*
|
||||
* Return: 0 on success an error code < 0 otherwise.
|
||||
*/
|
||||
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status)
|
||||
int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
|
||||
const char *operation, const char *status)
|
||||
{
|
||||
struct zpci_report_error *report;
|
||||
struct pci_driver *driver = NULL;
|
||||
struct pci_dev *pdev = NULL;
|
||||
char *buf, *end;
|
||||
int ret;
|
||||
|
||||
if (!zdev || !zdev->zbus)
|
||||
if (!zdev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Protected virtualization hosts get nothing from us */
|
||||
|
|
@ -121,18 +134,13 @@ int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char
|
|||
report = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!report)
|
||||
return -ENOMEM;
|
||||
if (zdev->zbus->bus)
|
||||
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
|
||||
if (pdev)
|
||||
driver = to_pci_driver(pdev->dev.driver);
|
||||
|
||||
buf = report->data.log_data;
|
||||
end = report->data.log_data + ZPCI_REPORT_DATA_SIZE;
|
||||
buf += scnprintf(buf, end - buf, "report: %s\n", operation);
|
||||
buf += scnprintf(buf, end - buf, "status: %s\n", status);
|
||||
buf += scnprintf(buf, end - buf, "state: %s\n",
|
||||
(pdev) ? zpci_state_str(pdev->error_state) : "n/a");
|
||||
buf += scnprintf(buf, end - buf, "driver: %s\n", (driver) ? driver->name : "n/a");
|
||||
if (pdev)
|
||||
buf += zpci_report_pdev(pdev, buf, end - buf);
|
||||
ret = debug_dump(pci_debug_msg_id, &debug_log_view, buf, end - buf, true);
|
||||
if (ret < 0)
|
||||
pr_err("Reading PCI debug messages failed with code %d\n", ret);
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@
|
|||
*/
|
||||
#ifndef __S390_PCI_REPORT_H
|
||||
#define __S390_PCI_REPORT_H
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct zpci_dev;
|
||||
|
||||
int zpci_report_status(struct zpci_dev *zdev, const char *operation, const char *status);
|
||||
int zpci_report_status(struct zpci_dev *zdev, struct pci_dev *pdev,
|
||||
const char *operation, const char *status);
|
||||
|
||||
#endif /* __S390_PCI_REPORT_H */
|
||||
|
|
|
|||
|
|
@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct svsm_call *call)
|
|||
|
||||
flags = native_local_irq_save();
|
||||
|
||||
/*
|
||||
* 'caa' is a per-CPU variable. To avoid using a stale or incorrect
|
||||
* 'caa' if the task is preempted or migrated to another CPU after it
|
||||
* is fetched, always fetch 'caa' and then issue the SVSM call with
|
||||
* interrupts disabled. This ensures the correct 'caa' is used.
|
||||
*/
|
||||
call->caa = svsm_get_caa();
|
||||
|
||||
ghcb = __sev_get_ghcb(&state);
|
||||
|
||||
do {
|
||||
|
|
@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffer)
|
|||
{
|
||||
struct svsm_call call = {};
|
||||
|
||||
call.caa = svsm_get_caa();
|
||||
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_CMD);
|
||||
call.rcx = __pa(buffer);
|
||||
|
||||
|
|
@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)
|
|||
if (!snp_vmpl)
|
||||
return false;
|
||||
|
||||
call.caa = svsm_get_caa();
|
||||
call.rax = SVSM_VTPM_CALL(SVSM_VTPM_QUERY);
|
||||
|
||||
if (svsm_perform_call_protocol(&call))
|
||||
|
|
|
|||
|
|
@ -1293,6 +1293,7 @@ static void gcm_process_assoc(const struct aes_gcm_key *key, u8 ghash_acc[16],
|
|||
unsigned int len;
|
||||
const u8 *src = walk.addr;
|
||||
|
||||
assoclen -= orig_len_this_step;
|
||||
if (unlikely(pos)) {
|
||||
len = min(len_this_step, 16 - pos);
|
||||
memcpy(&buf[pos], src, len);
|
||||
|
|
@ -1320,7 +1321,6 @@ static void gcm_process_assoc(const struct aes_gcm_key *key, u8 ghash_acc[16],
|
|||
kernel_fpu_end();
|
||||
kernel_fpu_begin();
|
||||
}
|
||||
assoclen -= orig_len_this_step;
|
||||
}
|
||||
if (unlikely(pos))
|
||||
aes_gcm_aad_update(key, ghash_acc, buf, pos, flags);
|
||||
|
|
|
|||
|
|
@ -343,11 +343,10 @@ void amd_brs_drain(void)
|
|||
if (!amd_brs_match_plm(event, from, to))
|
||||
continue;
|
||||
|
||||
perf_clear_branch_entry_bitfields(br+nr);
|
||||
|
||||
br[nr].from = from;
|
||||
br[nr].to = to;
|
||||
|
||||
br[nr] = (struct perf_branch_entry){
|
||||
.from = from,
|
||||
.to = to,
|
||||
};
|
||||
nr++;
|
||||
}
|
||||
empty:
|
||||
|
|
|
|||
|
|
@ -184,13 +184,6 @@ void amd_pmu_lbr_read(void)
|
|||
entry.to.split.reserved)
|
||||
continue;
|
||||
|
||||
perf_clear_branch_entry_bitfields(br + out);
|
||||
|
||||
br[out].from = sign_ext_branch_ip(entry.from.split.ip);
|
||||
br[out].to = sign_ext_branch_ip(entry.to.split.ip);
|
||||
br[out].mispred = entry.from.split.mispredict;
|
||||
br[out].predicted = !br[out].mispred;
|
||||
|
||||
/*
|
||||
* Set branch speculation information using the status of
|
||||
* the valid and spec bits.
|
||||
|
|
@ -208,7 +201,14 @@ void amd_pmu_lbr_read(void)
|
|||
* speculative and took the correct path
|
||||
*/
|
||||
idx = (entry.to.split.valid << 1) | entry.to.split.spec;
|
||||
br[out].spec = lbr_spec_map[idx];
|
||||
|
||||
br[out] = (struct perf_branch_entry){
|
||||
.from = sign_ext_branch_ip(entry.from.split.ip),
|
||||
.to = sign_ext_branch_ip(entry.to.split.ip),
|
||||
.mispred = entry.from.split.mispredict,
|
||||
.predicted = !entry.from.split.mispredict,
|
||||
.spec = lbr_spec_map[idx],
|
||||
};
|
||||
out++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -506,6 +506,8 @@ static struct event_constraint intel_pnc_event_constraints[] = {
|
|||
INTEL_EVENT_CONSTRAINT(0xce, 0x1),
|
||||
|
||||
INTEL_UEVENT_CONSTRAINT(0x01b1, 0x8),
|
||||
INTEL_UEVENT_CONSTRAINT(0x01b2, 0xf),
|
||||
INTEL_UEVENT_CONSTRAINT(0x02b2, 0xf),
|
||||
INTEL_UEVENT_CONSTRAINT(0x0847, 0xf),
|
||||
INTEL_UEVENT_CONSTRAINT(0x0446, 0xf),
|
||||
INTEL_UEVENT_CONSTRAINT(0x0846, 0xf),
|
||||
|
|
@ -520,6 +522,14 @@ static struct extra_reg intel_pnc_extra_regs[] __read_mostly = {
|
|||
INTEL_UEVENT_EXTRA_REG(0x022a, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
|
||||
INTEL_UEVENT_EXTRA_REG(0x042a, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
|
||||
INTEL_UEVENT_EXTRA_REG(0x082a, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
|
||||
INTEL_UEVENT_EXTRA_REG(0x014f, MSR_OMR_0, 0x40ffffff0000ffffull, OMR_0),
|
||||
INTEL_UEVENT_EXTRA_REG(0x024f, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
|
||||
INTEL_UEVENT_EXTRA_REG(0x044f, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
|
||||
INTEL_UEVENT_EXTRA_REG(0x084f, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
|
||||
INTEL_UEVENT_EXTRA_REG(0x01d6, MSR_OMR_0, 0x40ffffff0000ffffull, OMR_0),
|
||||
INTEL_UEVENT_EXTRA_REG(0x02d6, MSR_OMR_1, 0x40ffffff0000ffffull, OMR_1),
|
||||
INTEL_UEVENT_EXTRA_REG(0x04d6, MSR_OMR_2, 0x40ffffff0000ffffull, OMR_2),
|
||||
INTEL_UEVENT_EXTRA_REG(0x08d6, MSR_OMR_3, 0x40ffffff0000ffffull, OMR_3),
|
||||
INTEL_UEVENT_PEBS_LDLAT_EXTRA_REG(0x01cd),
|
||||
INTEL_UEVENT_EXTRA_REG(0x02c6, MSR_PEBS_FRONTEND, 0x9, FE),
|
||||
INTEL_UEVENT_EXTRA_REG(0x03c6, MSR_PEBS_FRONTEND, 0x7fff1f, FE),
|
||||
|
|
@ -5292,12 +5302,15 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
|
|||
struct kvm_pmu *kvm_pmu = (struct kvm_pmu *)data;
|
||||
u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl);
|
||||
u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable;
|
||||
int global_ctrl, pebs_enable;
|
||||
u64 guest_pebs_mask;
|
||||
int global_ctrl;
|
||||
|
||||
/*
|
||||
* In addition to obeying exclude_guest/exclude_host, remove bits being
|
||||
* used for PEBS when running a guest, because PEBS writes to virtual
|
||||
* addresses (not physical addresses).
|
||||
* addresses (not physical addresses). If the guest wants to utilize
|
||||
* PEBS, and PEBS can be safely enabled in the guest, bits for the guest's
|
||||
* PEBS-enabled counters will be OR'd back in as appropriate.
|
||||
*/
|
||||
*nr = 0;
|
||||
global_ctrl = (*nr)++;
|
||||
|
|
@ -5327,41 +5340,68 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data)
|
|||
return arr;
|
||||
}
|
||||
|
||||
if (!kvm_pmu || !x86_pmu.pebs_ept)
|
||||
/*
|
||||
* If the CPU doesn't support PEBS in the guest, then there's nothing
|
||||
* more to do as disabling PMCs via PERF_GLOBAL_CTRL is sufficient on
|
||||
* CPUs with guest/host isolation.
|
||||
*/
|
||||
if (!x86_pmu.pebs_ept)
|
||||
return arr;
|
||||
|
||||
/*
|
||||
* Restrict guest PEBS events to counters that (a) perf supports, (b)
|
||||
* the guest wants to use for PEBS, (c) are not excluded from counting
|
||||
* in the guest, and (d) _are_ excluded from counting in the host.
|
||||
*/
|
||||
guest_pebs_mask = pebs_mask & intel_ctrl & kvm_pmu->pebs_enable &
|
||||
~cpuc->intel_ctrl_host_mask &
|
||||
cpuc->intel_ctrl_guest_mask;
|
||||
|
||||
/*
|
||||
* Disable counters where the guest PMC is different than the host PMC
|
||||
* being used on behalf of the guest, as the PEBS record includes
|
||||
* PERF_GLOBAL_STATUS, i.e. the guest will see overflow status for the
|
||||
* wrong counter(s).
|
||||
*/
|
||||
guest_pebs_mask &= ~kvm_pmu->host_cross_mapped_mask;
|
||||
|
||||
/*
|
||||
* FIXME: Allow guest and host usage of PEBS events to co-exist instead
|
||||
* of disabling guest PEBS entirely if the host is using PEBS.
|
||||
* What exactly goes wrong if guest and host are using PEBS is
|
||||
* unknown.
|
||||
*/
|
||||
if (pebs_mask & ~cpuc->intel_ctrl_guest_mask)
|
||||
guest_pebs_mask = 0;
|
||||
|
||||
/*
|
||||
* Context switch DS_AREA and PEBS_DATA_CFG if and only if PEBS will be
|
||||
* active in the guest; if no records will be generated while the guest
|
||||
* is running, then simply keep the host values resident in hardware.
|
||||
*/
|
||||
arr[(*nr)++] = (struct perf_guest_switch_msr){
|
||||
.msr = MSR_IA32_DS_AREA,
|
||||
.host = (unsigned long)cpuc->ds,
|
||||
.guest = kvm_pmu->ds_area,
|
||||
.guest = guest_pebs_mask ? kvm_pmu->ds_area : (unsigned long)cpuc->ds,
|
||||
};
|
||||
|
||||
if (x86_pmu.intel_cap.pebs_baseline) {
|
||||
arr[(*nr)++] = (struct perf_guest_switch_msr){
|
||||
.msr = MSR_PEBS_DATA_CFG,
|
||||
.host = cpuc->active_pebs_data_cfg,
|
||||
.guest = kvm_pmu->pebs_data_cfg,
|
||||
.guest = guest_pebs_mask ? kvm_pmu->pebs_data_cfg :
|
||||
cpuc->active_pebs_data_cfg,
|
||||
};
|
||||
}
|
||||
|
||||
pebs_enable = (*nr)++;
|
||||
arr[pebs_enable] = (struct perf_guest_switch_msr){
|
||||
.msr = MSR_IA32_PEBS_ENABLE,
|
||||
.host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask,
|
||||
.guest = pebs_mask & ~cpuc->intel_ctrl_host_mask & kvm_pmu->pebs_enable,
|
||||
};
|
||||
|
||||
if (arr[pebs_enable].host) {
|
||||
/* Disable guest PEBS if host PEBS is enabled. */
|
||||
arr[pebs_enable].guest = 0;
|
||||
} else {
|
||||
/* Disable guest PEBS thoroughly for cross-mapped PEBS counters. */
|
||||
arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask;
|
||||
arr[global_ctrl].guest &= ~kvm_pmu->host_cross_mapped_mask;
|
||||
/* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */
|
||||
arr[global_ctrl].guest |= arr[pebs_enable].guest;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do NOT mess with PEBS_ENABLED. As above, disabling counters via
|
||||
* PERF_GLOBAL_CTRL is sufficient, and loading a stale PEBS_ENABLED,
|
||||
* e.g. on VM-Exit, can put the system in a bad state. Simply enable
|
||||
* counters in PERF_GLOBAL_CTRL, as perf load PEBS_ENABLED with the
|
||||
* full value, i.e. perf *also* relies on PERF_GLOBAL_CTRL.
|
||||
*/
|
||||
arr[global_ctrl].guest |= guest_pebs_mask;
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
|
@ -6561,6 +6601,8 @@ static void intel_pmu_filter(struct pmu *pmu, int cpu, bool *ret)
|
|||
|
||||
PMU_FORMAT_ATTR(offcore_rsp, "config1:0-63");
|
||||
|
||||
PMU_FORMAT_ATTR(offmodule_rsp, "config1:0-63");
|
||||
|
||||
PMU_FORMAT_ATTR(ldlat, "config1:0-15");
|
||||
|
||||
PMU_FORMAT_ATTR(frontend, "config1:0-23");
|
||||
|
|
@ -6609,6 +6651,20 @@ static struct attribute *skl_format_attr[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *pnc_format_attr_rtm[] = {
|
||||
&format_attr_in_tx.attr,
|
||||
&format_attr_in_tx_cp.attr,
|
||||
&format_attr_offmodule_rsp.attr,
|
||||
&format_attr_ldlat.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *pnc_format_attr[] = {
|
||||
&format_attr_offmodule_rsp.attr,
|
||||
&format_attr_ldlat.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static __initconst const struct x86_pmu core_pmu = {
|
||||
.name = "core",
|
||||
.handle_irq = x86_pmu_handle_irq,
|
||||
|
|
@ -7474,6 +7530,7 @@ static struct attribute *adl_hybrid_tsx_attrs[] = {
|
|||
FORMAT_ATTR_HYBRID(in_tx, hybrid_big);
|
||||
FORMAT_ATTR_HYBRID(in_tx_cp, hybrid_big);
|
||||
FORMAT_ATTR_HYBRID(offcore_rsp, hybrid_big_small_tiny);
|
||||
FORMAT_ATTR_HYBRID(offmodule_rsp, hybrid_big_small_tiny);
|
||||
FORMAT_ATTR_HYBRID(ldlat, hybrid_big_small_tiny);
|
||||
FORMAT_ATTR_HYBRID(frontend, hybrid_big);
|
||||
|
||||
|
|
@ -7512,6 +7569,23 @@ static struct attribute *mtl_hybrid_extra_attr[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *nvl_hybrid_extra_attr_rtm[] = {
|
||||
ADL_HYBRID_RTM_FORMAT_ATTR,
|
||||
FORMAT_HYBRID_PTR(offmodule_rsp),
|
||||
FORMAT_HYBRID_PTR(ldlat),
|
||||
FORMAT_HYBRID_PTR(frontend),
|
||||
FORMAT_HYBRID_PTR(snoop_rsp),
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute *nvl_hybrid_extra_attr[] = {
|
||||
FORMAT_HYBRID_PTR(offmodule_rsp),
|
||||
FORMAT_HYBRID_PTR(ldlat),
|
||||
FORMAT_HYBRID_PTR(frontend),
|
||||
FORMAT_HYBRID_PTR(snoop_rsp),
|
||||
NULL
|
||||
};
|
||||
|
||||
static bool is_attr_for_this_pmu(struct kobject *kobj, struct attribute *attr)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
|
|
@ -8549,6 +8623,8 @@ __init int intel_pmu_init(void)
|
|||
case INTEL_DIAMONDRAPIDS_X:
|
||||
intel_pmu_init_pnc(NULL);
|
||||
x86_pmu.pebs_latency_data = pnc_latency_data;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
pnc_format_attr_rtm : pnc_format_attr;
|
||||
|
||||
pr_cont("Panthercove events, ");
|
||||
name = "panthercove";
|
||||
|
|
@ -8557,13 +8633,12 @@ __init int intel_pmu_init(void)
|
|||
glc_common:
|
||||
intel_pmu_init_glc(NULL);
|
||||
intel_pmu_pebs_data_source_skl(true);
|
||||
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
hsw_format_attr : nhm_format_attr;
|
||||
glc_base:
|
||||
x86_pmu.pebs_ept = 1;
|
||||
x86_pmu.hw_config = hsw_hw_config;
|
||||
x86_pmu.get_event_constraints = glc_get_event_constraints;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
hsw_format_attr : nhm_format_attr;
|
||||
extra_skl_attr = skl_format_attr;
|
||||
mem_attr = glc_events_attrs;
|
||||
td_attr = glc_td_events_attrs;
|
||||
|
|
@ -8785,7 +8860,7 @@ __init int intel_pmu_init(void)
|
|||
mem_attr = mtl_hybrid_mem_attrs;
|
||||
tsx_attr = adl_hybrid_tsx_attrs;
|
||||
extra_attr = boot_cpu_has(X86_FEATURE_RTM) ?
|
||||
mtl_hybrid_extra_attr_rtm : mtl_hybrid_extra_attr;
|
||||
nvl_hybrid_extra_attr_rtm : nvl_hybrid_extra_attr;
|
||||
|
||||
/* Initialize big core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX];
|
||||
|
|
@ -8794,8 +8869,6 @@ __init int intel_pmu_init(void)
|
|||
/* Initialize Atom core specific PerfMon capabilities.*/
|
||||
pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_ATOM_IDX];
|
||||
intel_pmu_init_arw(&pmu->pmu);
|
||||
|
||||
intel_pmu_pebs_data_source_lnl();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -277,8 +277,8 @@ static u64 pnc_pebs_l2_hit_data_source[PNC_PEBS_DATA_SOURCE_MAX] = {
|
|||
0, /* 0x06: Reserved */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HIT), /* 0x07: L2 Hit Snoop HIT */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, HITM), /* 0x08: L2 Hit Snoop Hit Modified */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, MISS), /* 0x09: Prefetch Promotion */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, MISS), /* 0x0a: Cross Core Prefetch Promotion */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x09: Prefetch Promotion */
|
||||
OP_LH | P(LVL, L2) | LEVEL(L2) | P(SNOOP, NONE), /* 0x0a: Cross Core Prefetch Promotion */
|
||||
0, /* 0x0b: Reserved */
|
||||
0, /* 0x0c: Reserved */
|
||||
0, /* 0x0d: Reserved */
|
||||
|
|
@ -455,6 +455,7 @@ static inline void pebs_set_tlb_lock(u64 *val, bool tlb, bool lock)
|
|||
static u64 __grt_latency_data(struct perf_event *event, u64 status,
|
||||
u8 dse, bool tlb, bool lock, bool blk)
|
||||
{
|
||||
union perf_mem_data_src src;
|
||||
u64 val;
|
||||
|
||||
WARN_ON_ONCE(is_hybrid() &&
|
||||
|
|
@ -470,7 +471,16 @@ static u64 __grt_latency_data(struct perf_event *event, u64 status,
|
|||
else
|
||||
val |= P(BLK, NA);
|
||||
|
||||
return val;
|
||||
src.val = val;
|
||||
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
|
||||
src.mem_op = P(OP, LOAD);
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
|
||||
src.mem_op = P(OP, STORE);
|
||||
|
||||
return src.val;
|
||||
}
|
||||
|
||||
u64 grt_latency_data(struct perf_event *event, u64 status)
|
||||
|
|
@ -528,7 +538,11 @@ static u64 arw_latency_data(struct perf_event *event, u64 status)
|
|||
val |= P(BLK, NA);
|
||||
|
||||
src.val = val;
|
||||
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
|
||||
src.mem_op = P(OP, LOAD);
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
|
||||
src.mem_op = P(OP, STORE);
|
||||
|
||||
return src.val;
|
||||
|
|
@ -563,7 +577,11 @@ static u64 lnc_latency_data(struct perf_event *event, u64 status)
|
|||
val |= P(BLK, NA);
|
||||
|
||||
src.val = val;
|
||||
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
|
||||
src.mem_op = P(OP, LOAD);
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
|
||||
src.mem_op = P(OP, STORE);
|
||||
|
||||
return src.val;
|
||||
|
|
@ -621,7 +639,11 @@ u64 pnc_latency_data(struct perf_event *event, u64 status)
|
|||
val |= P(BLK, NA);
|
||||
|
||||
src.val = val;
|
||||
if (event->hw.flags & PERF_X86_EVENT_PEBS_ST_HSW)
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_LDLAT | PERF_X86_EVENT_PEBS_LD_HSW))
|
||||
src.mem_op = P(OP, LOAD);
|
||||
if (event->hw.flags &
|
||||
(PERF_X86_EVENT_PEBS_STLAT | PERF_X86_EVENT_PEBS_ST_HSW))
|
||||
src.mem_op = P(OP, STORE);
|
||||
|
||||
return src.val;
|
||||
|
|
@ -1291,22 +1313,22 @@ struct event_constraint intel_glm_pebs_event_constraints[] = {
|
|||
|
||||
struct event_constraint intel_grt_pebs_event_constraints[] = {
|
||||
/* Allow all events as PEBS with no flags */
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3),
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0x3f),
|
||||
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
|
||||
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0x3f),
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
struct event_constraint intel_cmt_pebs_event_constraints[] = {
|
||||
/* Allow all events as PEBS with no flags */
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0x3),
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff),
|
||||
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0x3),
|
||||
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
struct event_constraint intel_dkt_pebs_event_constraints[] = {
|
||||
/* Allow all events as PEBS with no flags */
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x5d0, 0xff),
|
||||
INTEL_HYBRID_LAT_CONSTRAINT(0x6d0, 0xff),
|
||||
INTEL_HYBRID_LDLAT_CONSTRAINT(0x5d0, 0xff),
|
||||
INTEL_HYBRID_STLAT_CONSTRAINT(0x6d0, 0xff),
|
||||
EVENT_CONSTRAINT_END
|
||||
};
|
||||
|
||||
|
|
@ -1496,24 +1518,8 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = {
|
|||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x012a, 0x1), /* OCR.* events */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x012b, 0x1), /* OCR.* events */
|
||||
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x04a4, 0x1), /* TOPDOWN.BAD_SPEC_SLOTS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x08a4, 0x1), /* TOPDOWN.BR_MISPREDICT_SLOTS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x10a4, 0x8), /* TOPDOWN.MEMORY_BOUND_SLOTS */
|
||||
|
||||
INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0x3fc),
|
||||
INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3),
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_INST_RETIRED.LOCK_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_INST_RETIRED.SPLIT_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_INST_RETIRED.SPLIT_STORES */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_INST_RETIRED.ALL_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_INST_RETIRED.ALL_STORES */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT(0x87d0, 0x3ff), /* MEM_INST_RETIRED.ANY */
|
||||
|
||||
INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(0xd1, 0xd4, 0xf),
|
||||
|
||||
INTEL_FLAGS_EVENT_CONSTRAINT(0xd0, 0xf),
|
||||
|
||||
/*
|
||||
* Everything else is handled by PMU_FL_PEBS_ALL, because we
|
||||
|
|
@ -1526,18 +1532,6 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = {
|
|||
struct event_constraint intel_pnc_pebs_event_constraints[] = {
|
||||
INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0xfc),
|
||||
INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3),
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x21d0, 0xf), /* MEM_INST_RETIRED.LOCK_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x41d0, 0xf), /* MEM_INST_RETIRED.SPLIT_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x42d0, 0xf), /* MEM_INST_RETIRED.SPLIT_STORES */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x81d0, 0xf), /* MEM_INST_RETIRED.ALL_LOADS */
|
||||
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x82d0, 0xf), /* MEM_INST_RETIRED.ALL_STORES */
|
||||
|
||||
INTEL_FLAGS_EVENT_CONSTRAINT_DATALA_LD_RANGE(0xd1, 0xd4, 0xf),
|
||||
|
||||
INTEL_FLAGS_EVENT_CONSTRAINT(0xd0, 0xf),
|
||||
INTEL_FLAGS_EVENT_CONSTRAINT(0xd6, 0xf),
|
||||
|
||||
/*
|
||||
* Everything else is handled by PMU_FL_PEBS_ALL, because we
|
||||
|
|
|
|||
|
|
@ -756,10 +756,10 @@ void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
|
|||
|
||||
rdmsrq(x86_pmu.lbr_from + lbr_idx, msr_lastbranch.lbr);
|
||||
|
||||
perf_clear_branch_entry_bitfields(br);
|
||||
|
||||
br->from = msr_lastbranch.from;
|
||||
br->to = msr_lastbranch.to;
|
||||
*br = (struct perf_branch_entry){
|
||||
.from = msr_lastbranch.from,
|
||||
.to = msr_lastbranch.to,
|
||||
};
|
||||
br++;
|
||||
}
|
||||
cpuc->lbr_stack.nr = i;
|
||||
|
|
@ -847,14 +847,15 @@ void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
|
|||
if (abort && x86_pmu.lbr_double_abort && out > 0)
|
||||
out--;
|
||||
|
||||
perf_clear_branch_entry_bitfields(br+out);
|
||||
br[out].from = from;
|
||||
br[out].to = to;
|
||||
br[out].mispred = mis;
|
||||
br[out].predicted = pred;
|
||||
br[out].in_tx = in_tx;
|
||||
br[out].abort = abort;
|
||||
br[out].cycles = cycles;
|
||||
br[out] = (struct perf_branch_entry){
|
||||
.from = from,
|
||||
.to = to,
|
||||
.mispred = mis,
|
||||
.predicted = pred,
|
||||
.in_tx = in_tx,
|
||||
.abort = abort,
|
||||
.cycles = cycles,
|
||||
};
|
||||
out++;
|
||||
}
|
||||
cpuc->lbr_stack.nr = out;
|
||||
|
|
@ -905,6 +906,7 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
|
|||
struct perf_branch_entry *e;
|
||||
struct lbr_entry *lbr;
|
||||
u64 from, to, info;
|
||||
bool mispred;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < x86_pmu.lbr_nr; i++) {
|
||||
|
|
@ -921,24 +923,27 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc,
|
|||
to = rdlbr_to(i, lbr);
|
||||
info = rdlbr_info(i, lbr);
|
||||
|
||||
perf_clear_branch_entry_bitfields(e);
|
||||
mispred = get_lbr_mispred(info);
|
||||
|
||||
e->from = from;
|
||||
e->to = to;
|
||||
e->mispred = get_lbr_mispred(info);
|
||||
e->predicted = !e->mispred;
|
||||
e->in_tx = !!(info & LBR_INFO_IN_TX);
|
||||
e->abort = !!(info & LBR_INFO_ABORT);
|
||||
e->cycles = get_lbr_cycles(info);
|
||||
e->type = get_lbr_br_type(info);
|
||||
|
||||
/*
|
||||
* Leverage the reserved field of cpuc->lbr_entries[i] to
|
||||
* temporarily store the branch counters information.
|
||||
* The later code will decide what content can be disclosed
|
||||
* to the perf tool. Pleae see intel_pmu_lbr_counters_reorder().
|
||||
*/
|
||||
e->reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) & LBR_INFO_BR_CNTR_FULL_MASK;
|
||||
*e = (struct perf_branch_entry){
|
||||
.from = from,
|
||||
.to = to,
|
||||
.mispred = mispred,
|
||||
.predicted = !mispred,
|
||||
.in_tx = !!(info & LBR_INFO_IN_TX),
|
||||
.abort = !!(info & LBR_INFO_ABORT),
|
||||
.cycles = get_lbr_cycles(info),
|
||||
.type = get_lbr_br_type(info),
|
||||
/*
|
||||
* Leverage the reserved field of
|
||||
* cpuc->lbr_entries[i] to temporarily store the
|
||||
* branch counters information. The later code will
|
||||
* decide what content can be disclosed to the perf
|
||||
* tool. Pleae see intel_pmu_lbr_counters_reorder().
|
||||
*/
|
||||
.reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) &
|
||||
LBR_INFO_BR_CNTR_FULL_MASK,
|
||||
};
|
||||
}
|
||||
|
||||
cpuc->lbr_stack.nr = i;
|
||||
|
|
|
|||
|
|
@ -517,10 +517,6 @@ struct cpu_hw_events {
|
|||
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
|
||||
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_ST)
|
||||
|
||||
#define INTEL_HYBRID_LAT_CONSTRAINT(c, n) \
|
||||
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
|
||||
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID)
|
||||
|
||||
#define INTEL_HYBRID_LDLAT_CONSTRAINT(c, n) \
|
||||
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
|
||||
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LAT_HYBRID|PERF_X86_EVENT_PEBS_LD_HSW)
|
||||
|
|
|
|||
|
|
@ -2108,6 +2108,9 @@ bool filter_mce(struct mce *m)
|
|||
static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
|
||||
{
|
||||
irqentry_state_t irq_state;
|
||||
unsigned long dr7;
|
||||
|
||||
dr7 = local_db_save();
|
||||
|
||||
WARN_ON_ONCE(user_mode(regs));
|
||||
|
||||
|
|
@ -2116,20 +2119,26 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
|
|||
* mce_check_crashing_cpu() for details.
|
||||
*/
|
||||
if (mca_cfg.initialized && mce_check_crashing_cpu())
|
||||
return;
|
||||
goto out;
|
||||
|
||||
irq_state = irqentry_nmi_enter(regs);
|
||||
|
||||
do_machine_check(regs);
|
||||
|
||||
irqentry_nmi_exit(regs, irq_state);
|
||||
out:
|
||||
local_db_restore(dr7);
|
||||
}
|
||||
|
||||
static __always_inline void exc_machine_check_user(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
irqentry_enter_from_user_mode(regs);
|
||||
|
||||
dr7 = local_db_save();
|
||||
do_machine_check(regs);
|
||||
local_db_restore(dr7);
|
||||
|
||||
irqentry_exit_to_user_mode(regs);
|
||||
}
|
||||
|
|
@ -2138,21 +2147,13 @@ static __always_inline void exc_machine_check_user(struct pt_regs *regs)
|
|||
/* MCE hit kernel mode */
|
||||
DEFINE_IDTENTRY_MCE(exc_machine_check)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
dr7 = local_db_save();
|
||||
exc_machine_check_kernel(regs);
|
||||
local_db_restore(dr7);
|
||||
}
|
||||
|
||||
/* The user mode variant. */
|
||||
DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
dr7 = local_db_save();
|
||||
exc_machine_check_user(regs);
|
||||
local_db_restore(dr7);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_FRED
|
||||
|
|
@ -2169,28 +2170,20 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
|
|||
*/
|
||||
DEFINE_FREDENTRY_MCE(exc_machine_check)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
dr7 = local_db_save();
|
||||
if (user_mode(regs))
|
||||
exc_machine_check_user(regs);
|
||||
else
|
||||
exc_machine_check_kernel(regs);
|
||||
local_db_restore(dr7);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/* 32bit unified entry point */
|
||||
DEFINE_IDTENTRY_RAW(exc_machine_check)
|
||||
{
|
||||
unsigned long dr7;
|
||||
|
||||
dr7 = local_db_save();
|
||||
if (user_mode(regs))
|
||||
exc_machine_check_user(regs);
|
||||
else
|
||||
exc_machine_check_kernel(regs);
|
||||
local_db_restore(dr7);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -2512,6 +2512,12 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato
|
|||
|
||||
iterator->addr = addr;
|
||||
iterator->shadow_addr = root;
|
||||
|
||||
if (WARN_ON_ONCE(!VALID_PAGE(root)) || kvm_mmu_is_dummy_root(root)) {
|
||||
iterator->level = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iterator->level = vcpu->arch.mmu->root_role.level;
|
||||
|
||||
if (iterator->level >= PT64_ROOT_4LEVEL &&
|
||||
|
|
@ -5058,7 +5064,7 @@ static int kvm_tdp_page_prefault(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|||
if (signal_pending(current))
|
||||
return -EINTR;
|
||||
|
||||
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu))
|
||||
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu))
|
||||
return -EIO;
|
||||
|
||||
cond_resched();
|
||||
|
|
|
|||
|
|
@ -823,14 +823,6 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
|
|||
|
||||
bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
||||
{
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
return kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return kvm_pmu_call(msr_idx_to_pmc)(vcpu, msr) ||
|
||||
kvm_pmu_call(is_valid_msr)(vcpu, msr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2125,13 +2125,8 @@ static bool svm_get_nested_state_pages(struct kvm_vcpu *vcpu)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!nested_svm_merge_msrpm(vcpu)) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
if (!nested_svm_merge_msrpm(vcpu))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kvm_hv_verify_vp_assist(vcpu))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -488,6 +488,20 @@ static void snp_guest_req_cleanup(struct kvm *kvm)
|
|||
sev->guest_resp_buf = NULL;
|
||||
}
|
||||
|
||||
static int sev_alloc_have_run_cpus(struct kvm_sev_info *sev)
|
||||
{
|
||||
if (!zalloc_cpumask_var(&sev->have_run_cpus, GFP_KERNEL_ACCOUNT))
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sev_free_have_run_cpus(struct kvm_sev_info *sev)
|
||||
{
|
||||
free_cpumask_var(sev->have_run_cpus);
|
||||
memset(&sev->have_run_cpus, 0, sizeof(sev->have_run_cpus));
|
||||
}
|
||||
|
||||
static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
|
||||
struct kvm_sev_init *data,
|
||||
unsigned long vm_type)
|
||||
|
|
@ -545,10 +559,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
|
|||
if (ret)
|
||||
goto e_free_asid;
|
||||
|
||||
if (!zalloc_cpumask_var(&sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) {
|
||||
ret = -ENOMEM;
|
||||
ret = sev_alloc_have_run_cpus(sev);
|
||||
if (ret)
|
||||
goto e_free_asid;
|
||||
}
|
||||
|
||||
/* This needs to happen after SEV/SNP firmware initialization. */
|
||||
if (snp_active) {
|
||||
|
|
@ -566,7 +579,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp,
|
|||
return 0;
|
||||
|
||||
e_free:
|
||||
free_cpumask_var(sev->have_run_cpus);
|
||||
sev_free_have_run_cpus(sev);
|
||||
e_free_asid:
|
||||
argp->error = init_args.error;
|
||||
sev_asid_free(sev);
|
||||
|
|
@ -1125,9 +1138,6 @@ static int sev_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
|||
if (!sev_es_guest(kvm))
|
||||
return -ENOTTY;
|
||||
|
||||
if (kvm_is_vcpu_creation_in_progress(kvm))
|
||||
return -EBUSY;
|
||||
|
||||
ret = kvm_lock_all_vcpus(kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -2035,6 +2045,13 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm)
|
|||
struct kvm_sev_info *mirror;
|
||||
unsigned long i;
|
||||
|
||||
/*
|
||||
* Do cache maintenance on the source VM *before* clearing "SEV active",
|
||||
* as memory reclaim flows won't trigger cache maintenance on the VM
|
||||
* once it's no longer an SEV VM.
|
||||
*/
|
||||
sev_writeback_caches(src_kvm);
|
||||
|
||||
dst->active = true;
|
||||
dst->asid = src->asid;
|
||||
dst->handle = src->handle;
|
||||
|
|
@ -2115,10 +2132,6 @@ static int sev_check_source_vcpus(struct kvm *dst, struct kvm *src)
|
|||
struct kvm_vcpu *src_vcpu;
|
||||
unsigned long i;
|
||||
|
||||
if (kvm_is_vcpu_creation_in_progress(src) ||
|
||||
kvm_is_vcpu_creation_in_progress(dst))
|
||||
return -EBUSY;
|
||||
|
||||
if (!sev_es_guest(src))
|
||||
return 0;
|
||||
|
||||
|
|
@ -2187,11 +2200,14 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd)
|
|||
* the set of CPUs from the source. If a CPU was used to run a vCPU in
|
||||
* the source VM but is never used for the destination VM, then the CPU
|
||||
* can only have cached memory that was accessible to the source VM.
|
||||
* Furthermore, KVM *must* perform cache maintenance on the source VM,
|
||||
* as the source VM may have access to memory that the destination VM
|
||||
* does not, i.e. KVM could skip flushes if memory is reclaimed from
|
||||
* the old VM but not the new VM.
|
||||
*/
|
||||
if (!zalloc_cpumask_var(&dst_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) {
|
||||
ret = -ENOMEM;
|
||||
ret = sev_alloc_have_run_cpus(dst_sev);
|
||||
if (ret)
|
||||
goto out_source_vcpu;
|
||||
}
|
||||
|
||||
sev_migrate_from(kvm, source_kvm);
|
||||
kvm_vm_dead(source_kvm);
|
||||
|
|
@ -2510,9 +2526,6 @@ static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
|
|||
unsigned long i;
|
||||
int ret;
|
||||
|
||||
if (kvm_is_vcpu_creation_in_progress(kvm))
|
||||
return -EBUSY;
|
||||
|
||||
ret = kvm_lock_all_vcpus(kvm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -2888,10 +2901,9 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd)
|
|||
}
|
||||
|
||||
mirror_sev = to_kvm_sev_info(kvm);
|
||||
if (!zalloc_cpumask_var(&mirror_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) {
|
||||
ret = -ENOMEM;
|
||||
ret = sev_alloc_have_run_cpus(mirror_sev);
|
||||
if (ret)
|
||||
goto e_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* The mirror kvm holds an enc_context_owner ref so its asid can't
|
||||
|
|
@ -2980,13 +2992,17 @@ void sev_vm_destroy(struct kvm *kvm)
|
|||
struct list_head *head = &sev->regions_list;
|
||||
struct list_head *pos, *q;
|
||||
|
||||
/*
|
||||
* Free the mask even if the VM is not *currently* an SEV VM, as it may
|
||||
* have been an SEV VM prior to intra-host migration.
|
||||
*/
|
||||
sev_free_have_run_cpus(sev);
|
||||
|
||||
if (!sev_guest(kvm))
|
||||
return;
|
||||
|
||||
WARN_ON(!list_empty(&sev->mirror_vms));
|
||||
|
||||
free_cpumask_var(sev->have_run_cpus);
|
||||
|
||||
/*
|
||||
* If this is a mirror VM, remove it from the owner's list of a mirrors
|
||||
* and skip ASID cleanup (the ASID is tied to the lifetime of the owner).
|
||||
|
|
@ -3616,7 +3632,6 @@ int pre_sev_run(struct vcpu_svm *svm, int cpu)
|
|||
|
||||
sd->sev_vmcbs[asid] = svm->vmcb;
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ASID;
|
||||
vmcb_mark_dirty(svm->vmcb, VMCB_ASID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -673,16 +673,7 @@ static void clr_dr_intercepts(struct vcpu_svm *svm)
|
|||
|
||||
static bool msr_write_intercepted(struct vcpu_svm *svm, u32 msr)
|
||||
{
|
||||
/*
|
||||
* For non-nested case:
|
||||
* If the L01 MSR bitmap does not intercept the MSR, then we need to
|
||||
* save it.
|
||||
*
|
||||
* For nested case:
|
||||
* If the L02 MSR bitmap does not intercept the MSR, then we need to
|
||||
* save it.
|
||||
*/
|
||||
void *msrpm = is_guest_mode(&svm->vcpu) ? svm->nested.msrpm : svm->msrpm;
|
||||
void *msrpm = __va(__sme_clr(svm->vmcb->control.msrpm_base_pa));
|
||||
|
||||
return svm_test_msr_bitmap_write(msrpm, msr);
|
||||
}
|
||||
|
|
@ -1902,8 +1893,7 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
|
|||
if (sd->next_asid > sd->max_asid) {
|
||||
++sd->asid_generation;
|
||||
sd->next_asid = sd->min_asid;
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
|
||||
vmcb_mark_dirty(svm->vmcb, VMCB_ASID);
|
||||
sd->flush_all_asids = true;
|
||||
}
|
||||
|
||||
svm->current_vmcb->asid_generation = sd->asid_generation;
|
||||
|
|
@ -4528,6 +4518,9 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
|
|||
svm->vmcb->control.asid = svm->asid;
|
||||
vmcb_mark_dirty(svm->vmcb, VMCB_ASID);
|
||||
}
|
||||
if (this_cpu_ptr(&svm_data)->flush_all_asids)
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
|
||||
|
||||
svm->vmcb->save.cr2 = vcpu->arch.cr2;
|
||||
|
||||
if (guest_cpu_cap_has(vcpu, X86_FEATURE_ERAPS) &&
|
||||
|
|
@ -4618,16 +4611,23 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
|
|||
vcpu->arch.nested_run_pending = 0;
|
||||
}
|
||||
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
|
||||
if (!svm_is_vmrun_failure(svm->vmcb->control.exit_code)) {
|
||||
this_cpu_ptr(&svm_data)->flush_all_asids = false;
|
||||
svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
|
||||
|
||||
/*
|
||||
* Unconditionally mask off the CLEAR_RAP bit, the AND is just as cheap
|
||||
* as the TEST+Jcc to avoid it.
|
||||
*/
|
||||
if (cpu_feature_enabled(X86_FEATURE_ERAPS))
|
||||
svm->vmcb->control.erap_ctl &= ~ERAP_CONTROL_CLEAR_RAP;
|
||||
/*
|
||||
* Unconditionally mask off the CLEAR_RAP bit, the AND is just
|
||||
* as cheap as the TEST+Jcc to avoid it.
|
||||
*/
|
||||
if (cpu_feature_enabled(X86_FEATURE_ERAPS))
|
||||
svm->vmcb->control.erap_ctl &= ~ERAP_CONTROL_CLEAR_RAP;
|
||||
|
||||
vmcb_mark_all_clean(svm->vmcb);
|
||||
vmcb_mark_all_clean(svm->vmcb);
|
||||
|
||||
if (!msr_write_intercepted(svm, MSR_AMD64_PERF_CNTR_GLOBAL_CTL))
|
||||
rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
|
||||
vcpu_to_pmu(vcpu)->global_ctrl);
|
||||
}
|
||||
|
||||
/* if exit due to PF check for async PF */
|
||||
if (svm->vmcb->control.exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR)
|
||||
|
|
@ -4636,9 +4636,6 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
|
|||
|
||||
kvm_clear_available_registers(vcpu, SVM_REGS_LAZY_LOAD_SET);
|
||||
|
||||
if (!msr_write_intercepted(svm, MSR_AMD64_PERF_CNTR_GLOBAL_CTL))
|
||||
rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, vcpu_to_pmu(vcpu)->global_ctrl);
|
||||
|
||||
trace_kvm_exit(vcpu, KVM_ISA_SVM);
|
||||
|
||||
svm_complete_interrupts(vcpu);
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ struct svm_cpu_data {
|
|||
u32 next_asid;
|
||||
u32 min_asid;
|
||||
|
||||
bool flush_all_asids;
|
||||
bool bp_spec_reduce_set;
|
||||
|
||||
struct vmcb *save_area;
|
||||
|
|
|
|||
|
|
@ -1754,6 +1754,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
|
|||
static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
|
||||
{
|
||||
#ifdef CONFIG_KVM_HYPERV
|
||||
const u64 runtime_controls = HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1 |
|
||||
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 |
|
||||
HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC;
|
||||
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
|
||||
struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
|
||||
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu);
|
||||
|
|
@ -1762,6 +1765,9 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields
|
|||
vmcs12->tpr_threshold = evmcs->tpr_threshold;
|
||||
vmcs12->guest_rip = evmcs->guest_rip;
|
||||
|
||||
if ((hv_clean_fields & runtime_controls) != runtime_controls)
|
||||
vmx->nested.force_msr_bitmap_recalc = true;
|
||||
|
||||
if (unlikely(!(hv_clean_fields &
|
||||
HV_VMX_ENLIGHTENED_CLEAN_FIELD_ENLIGHTENMENTSCONTROL))) {
|
||||
hv_vcpu->nested.pa_page_gpa = evmcs->partition_assist_page;
|
||||
|
|
@ -3465,10 +3471,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
|
|||
} else {
|
||||
pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n",
|
||||
__func__);
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -3539,11 +3541,6 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
|
|||
if (!nested_get_evmcs_page(vcpu)) {
|
||||
pr_debug_ratelimited("%s: enlightened vmptrld failed\n",
|
||||
__func__);
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror =
|
||||
KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -3915,8 +3912,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
|
|||
|
||||
vmentry_failed:
|
||||
vcpu->arch.nested_run_pending = 0;
|
||||
if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR)
|
||||
if (status == NVMX_VMENTRY_KVM_INTERNAL_ERROR) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
return 0;
|
||||
}
|
||||
if (status == NVMX_VMENTRY_VMEXIT)
|
||||
return 1;
|
||||
WARN_ON_ONCE(status != NVMX_VMENTRY_VMFAIL);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,9 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
|||
int ret;
|
||||
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
case MSR_CORE_PERF_FIXED_CTR_CTRL:
|
||||
return kvm_pmu_has_perf_global_ctrl(pmu);
|
||||
case MSR_IA32_PEBS_ENABLE:
|
||||
|
|
|
|||
|
|
@ -1995,7 +1995,7 @@ static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
|
|||
if (kvm_vcpu_has_events(vcpu) || signal_pending(current))
|
||||
break;
|
||||
|
||||
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) {
|
||||
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
|
@ -2728,11 +2728,6 @@ static tdx_vm_state_guard_t tdx_acquire_vm_state_locks(struct kvm *kvm)
|
|||
|
||||
mutex_lock(&kvm->lock);
|
||||
|
||||
if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus)) {
|
||||
r = -EBUSY;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
r = kvm_lock_all_vcpus(kvm);
|
||||
if (r)
|
||||
goto out_err;
|
||||
|
|
|
|||
|
|
@ -8060,7 +8060,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|||
bool req_immediate_exit = false;
|
||||
|
||||
if (kvm_request_pending(vcpu)) {
|
||||
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) {
|
||||
if (kvm_test_request(KVM_REQ_VM_DEAD, vcpu)) {
|
||||
r = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -8072,6 +8072,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|||
|
||||
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
|
||||
if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) {
|
||||
vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
|
||||
vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
|
||||
vcpu->run->internal.ndata = 0;
|
||||
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -886,6 +886,105 @@ static void quirk_clear_strap_no_soft_reset_dev2_f0(struct pci_dev *dev)
|
|||
}
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15b8, quirk_clear_strap_no_soft_reset_dev2_f0);
|
||||
|
||||
/*
|
||||
* Enhanced atomic operations can cause corruption with 64-bit DMA
|
||||
* on these devices.
|
||||
*/
|
||||
#define RX_ENH_ATOMIC_EN BIT(8)
|
||||
|
||||
static const u32 nbio_7_7_pcie_smn_addrs[] = {
|
||||
0x111401d0,
|
||||
0x111411d0,
|
||||
0x111421d0,
|
||||
0x111431d0,
|
||||
0x111441d0,
|
||||
0x112401d0,
|
||||
0x112411d0,
|
||||
0x112421d0,
|
||||
0x112431d0,
|
||||
0x112441d0,
|
||||
0x112451d0,
|
||||
0x113401d0,
|
||||
0x114401d0,
|
||||
};
|
||||
|
||||
static const u32 nbio_7_11_pcie_smn_addrs[] = {
|
||||
0x112401d0,
|
||||
0x112411d0,
|
||||
0x112421d0,
|
||||
0x112431d0,
|
||||
0x112441d0,
|
||||
0x112451d0,
|
||||
0x113401d0,
|
||||
0x113411d0,
|
||||
0x113421d0,
|
||||
0x113431d0,
|
||||
0x113441d0,
|
||||
0x113451d0,
|
||||
};
|
||||
|
||||
static void quirk_amd_nbio_enhanced_atomic(struct pci_dev *host_bridge,
|
||||
const u32 *smn_addrs,
|
||||
size_t nr_smn_addrs)
|
||||
{
|
||||
bool changed = false;
|
||||
size_t i;
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < nr_smn_addrs; i++) {
|
||||
ret = amd_smn_read(0, smn_addrs[i], &data);
|
||||
if (ret)
|
||||
continue;
|
||||
if (!(data & RX_ENH_ATOMIC_EN))
|
||||
continue;
|
||||
data = data & ~RX_ENH_ATOMIC_EN;
|
||||
ret = amd_smn_write(0, smn_addrs[i], data);
|
||||
if (ret)
|
||||
continue;
|
||||
if (changed)
|
||||
continue;
|
||||
ret = amd_smn_read(0, smn_addrs[i], &data);
|
||||
if (ret)
|
||||
continue;
|
||||
if (data & RX_ENH_ATOMIC_EN)
|
||||
continue;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
pci_info(host_bridge, "enhanced atomics disabled\n");
|
||||
}
|
||||
|
||||
static void quirk_amd_nbio_7_7_disable_enhanced_atomic(struct pci_dev *dev)
|
||||
{
|
||||
quirk_amd_nbio_enhanced_atomic(dev, nbio_7_7_pcie_smn_addrs,
|
||||
ARRAY_SIZE(nbio_7_7_pcie_smn_addrs));
|
||||
}
|
||||
|
||||
static void quirk_amd_nbio_7_11_disable_enhanced_atomic(struct pci_dev *dev)
|
||||
{
|
||||
quirk_amd_nbio_enhanced_atomic(dev, nbio_7_11_pcie_smn_addrs,
|
||||
ARRAY_SIZE(nbio_7_11_pcie_smn_addrs));
|
||||
}
|
||||
|
||||
/* Phoenix, Hawk Point (NBIO 7.7) */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x14E8,
|
||||
quirk_amd_nbio_7_7_disable_enhanced_atomic);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x14E8,
|
||||
quirk_amd_nbio_7_7_disable_enhanced_atomic);
|
||||
|
||||
/* Strix, Krackan, Strix Halo (NBIO 7.11) */
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1507,
|
||||
quirk_amd_nbio_7_11_disable_enhanced_atomic);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1507,
|
||||
quirk_amd_nbio_7_11_disable_enhanced_atomic);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1122,
|
||||
quirk_amd_nbio_7_11_disable_enhanced_atomic);
|
||||
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, 0x1122,
|
||||
quirk_amd_nbio_7_11_disable_enhanced_atomic);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2018,12 +2018,17 @@ static int disk_revalidate_zone_resources(struct gendisk *disk,
|
|||
struct blk_revalidate_zone_args *args)
|
||||
{
|
||||
struct queue_limits *lim = &disk->queue->limits;
|
||||
unsigned long long nr_zones;
|
||||
unsigned int pool_size;
|
||||
int ret = 0;
|
||||
|
||||
args->disk = disk;
|
||||
args->nr_zones =
|
||||
DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
|
||||
nr_zones = DIV_ROUND_UP_ULL(get_capacity(disk), lim->chunk_sectors);
|
||||
if (nr_zones > UINT_MAX) {
|
||||
pr_warn("%s: Too many zones (%llu)\n", disk->disk_name, nr_zones);
|
||||
return -EINVAL;
|
||||
}
|
||||
args->nr_zones = nr_zones;
|
||||
|
||||
/* Cached zone conditions: 1 byte per zone */
|
||||
args->zones_cond = kzalloc(args->nr_zones, GFP_NOIO);
|
||||
|
|
@ -2131,6 +2136,12 @@ static int blk_revalidate_zone_cond(struct blk_zone *zone, unsigned int idx,
|
|||
{
|
||||
enum blk_zone_cond cond = zone->cond;
|
||||
|
||||
if (idx >= args->nr_zones) {
|
||||
pr_warn("%s: Zone report index %u exceeds zone count %u\n",
|
||||
args->disk->disk_name, idx, args->nr_zones);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check that the zone condition is consistent with the zone type. */
|
||||
switch (cond) {
|
||||
case BLK_ZONE_COND_NOT_WP:
|
||||
|
|
|
|||
51
crypto/aes.c
51
crypto/aes.c
|
|
@ -637,7 +637,18 @@ static struct skcipher_alg skcipher_algs[] = {
|
|||
.decrypt = crypto_aes_cbc_decrypt,
|
||||
},
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_CTS)
|
||||
/*
|
||||
* Don't register library-based "cts(cbc(aes))" on architectures where
|
||||
* it might block a "better" implementation from being instantiated via
|
||||
* the "cts" template. These exclusions are temporary and will go away
|
||||
* as the arch-optimized AES code is migrated into the library.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_CTS) && \
|
||||
!(IS_ENABLED(CONFIG_ARM) || \
|
||||
IS_ENABLED(CONFIG_ARM64) || \
|
||||
IS_ENABLED(CONFIG_PPC) || \
|
||||
IS_ENABLED(CONFIG_S390) || \
|
||||
IS_ENABLED(CONFIG_SPARC))
|
||||
{
|
||||
.base.cra_name = "cts(cbc(aes))",
|
||||
.base.cra_driver_name = "cts-cbc-aes-lib",
|
||||
|
|
@ -687,7 +698,13 @@ static struct skcipher_alg skcipher_algs[] = {
|
|||
.decrypt = crypto_aes_xctr_crypt,
|
||||
},
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_XTS)
|
||||
/*
|
||||
* Don't register library-based "xts(aes)" on architectures where it
|
||||
* might block a "better" implementation from being instantiated via the
|
||||
* "xts" template. This exclusion is temporary and will go away when
|
||||
* the library AES-XTS is optimized for SPARC.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_XTS) && !IS_ENABLED(CONFIG_SPARC)
|
||||
{
|
||||
.base.cra_name = "xts(aes)",
|
||||
.base.cra_driver_name = "xts-aes-lib",
|
||||
|
|
@ -980,7 +997,20 @@ static __maybe_unused int crypto_aes_ccm_decrypt(struct aead_request *req)
|
|||
}
|
||||
|
||||
static struct aead_alg aead_algs[] = {
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_GCM)
|
||||
/*
|
||||
* Don't register library-based "gcm(aes)" and "rfc4106(gcm(aes))" on
|
||||
* architectures where they might block a "better" implementation from
|
||||
* being instantiated via the "gcm" and "rfc4106" templates. These
|
||||
* exclusions are temporary and will go away as the arch-optimized AES
|
||||
* code is migrated into the library.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_GCM) && \
|
||||
!(IS_ENABLED(CONFIG_ARM) || \
|
||||
IS_ENABLED(CONFIG_ARM64) || \
|
||||
IS_ENABLED(CONFIG_PPC) || \
|
||||
IS_ENABLED(CONFIG_RISCV) || \
|
||||
IS_ENABLED(CONFIG_S390) || \
|
||||
IS_ENABLED(CONFIG_SPARC))
|
||||
{
|
||||
.base.cra_name = "gcm(aes)",
|
||||
.base.cra_driver_name = "gcm-aes-lib",
|
||||
|
|
@ -1012,7 +1042,20 @@ static struct aead_alg aead_algs[] = {
|
|||
.chunksize = AES_BLOCK_SIZE,
|
||||
},
|
||||
#endif /* CONFIG_CRYPTO_GCM */
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_CCM)
|
||||
/*
|
||||
* Don't register library-based "ccm(aes)" on architectures where it
|
||||
* might block a "better" implementation from being instantiated via the
|
||||
* "ccm" template. These exclusions are temporary and will go away as
|
||||
* the arch-optimized AES code is migrated into the library.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_CRYPTO_CCM) && \
|
||||
!(IS_ENABLED(CONFIG_ARM) || \
|
||||
IS_ENABLED(CONFIG_ARM64) || \
|
||||
IS_ENABLED(CONFIG_PPC) || \
|
||||
IS_ENABLED(CONFIG_RISCV) || \
|
||||
IS_ENABLED(CONFIG_S390) || \
|
||||
IS_ENABLED(CONFIG_SPARC) || \
|
||||
IS_ENABLED(CONFIG_X86))
|
||||
{
|
||||
.base.cra_name = "ccm(aes)",
|
||||
.base.cra_driver_name = "ccm-aes-lib",
|
||||
|
|
|
|||
|
|
@ -515,6 +515,7 @@ void ivpu_prepare_for_reset(struct ivpu_device *vdev)
|
|||
{
|
||||
ivpu_hw_irq_disable(vdev);
|
||||
disable_irq(vdev->irq);
|
||||
atomic_set(&vdev->job_timeout_detected, 0);
|
||||
flush_work(&vdev->irq_dct_work);
|
||||
flush_work(&vdev->context_abort_work);
|
||||
flush_work(&vdev->job_destroy_work);
|
||||
|
|
@ -710,7 +711,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev)
|
|||
vdev->context_xa_limit.max = IVPU_USER_CONTEXT_MAX_SSID;
|
||||
atomic64_set(&vdev->unique_id_counter, 0);
|
||||
atomic_set(&vdev->job_timeout_counter, 0);
|
||||
atomic_set(&vdev->faults_detected, 0);
|
||||
atomic_set(&vdev->job_timeout_detected, 0);
|
||||
xa_init_flags(&vdev->context_xa, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
|
||||
xa_init_flags(&vdev->submitted_jobs_xa, XA_FLAGS_ALLOC1);
|
||||
xa_init_flags(&vdev->db_xa, XA_FLAGS_ALLOC1);
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ struct ivpu_device {
|
|||
struct xarray submitted_jobs_xa;
|
||||
struct ivpu_ipc_consumer job_done_consumer;
|
||||
atomic_t job_timeout_counter;
|
||||
atomic_t faults_detected;
|
||||
atomic_t job_timeout_detected;
|
||||
|
||||
atomic64_t unique_id_counter;
|
||||
|
||||
|
|
|
|||
|
|
@ -621,7 +621,6 @@ bool ivpu_job_handle_engine_error(struct ivpu_device *vdev, u32 job_id, u32 job_
|
|||
* status and ensure both are handled in the same way
|
||||
*/
|
||||
job->file_priv->has_mmu_faults = true;
|
||||
atomic_set(&vdev->faults_detected, 1);
|
||||
queue_work(system_percpu_wq, &vdev->context_abort_work);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1175,10 +1174,10 @@ static int reset_engine_and_mark_faulty_contexts(struct ivpu_device *vdev)
|
|||
return ret;
|
||||
|
||||
/*
|
||||
* If faults are detected, ignore guilty contexts from engine reset as NPU may not be stuck
|
||||
* and could return currently running good context and faulty contexts are already marked
|
||||
* If job timeout is detected, read guilty context from engine reset, for other reasons
|
||||
* faulty context is already known
|
||||
*/
|
||||
if (atomic_cmpxchg(&vdev->faults_detected, 1, 0) == 1)
|
||||
if (atomic_cmpxchg(&vdev->job_timeout_detected, 1, 0) == 0)
|
||||
return 0;
|
||||
|
||||
num_impacted_contexts = resp.payload.engine_reset_done.num_impacted_contexts;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user