mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
Linux 7.3-rc6
-----BEGIN PGP SIGNATURE----- iQFSBAABCgA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAmrCuuUeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiGfEQIAKPMeNxF+q9oTZRD RpIstLSujzELIrCYuvZYGkSQElb8XA+Jor9+DeXF+zP4dkcpLri1BjY+WJojF0ng 6S3qiMQ7T8Z6KW72c5oI/U4IYs8G2D44EZS4e0CPjh+jbvwXEyvft5+TxVnmdIbo cx1DpHzaKWx7swvnknKaLLNSmVBE2Nm0CqCyLf7dUAPvSLTlaC94tJwN21ZjvLlv LIf4GO6J0lAV6ldO8UvTkkVy+cye3iCgZ1xhFnq3MsCqBaIUveff8o9o9xrx4j0x lxSynWezHKzFSZ2+hAL8yx44RdOqKBK1vLVFVDvWXPxKS0+irlcEvh/zSj6V45Ow 7Kcz6nM= =IxpV -----END PGP SIGNATURE----- BackMerge tag 'v7.3-rc6' into drm-next Linux 7.3-rc6 This was requested by Thomas to have a new base to start some branch from Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
commit
a486b8b80d
7
.mailmap
7
.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>
|
||||
|
|
@ -355,6 +357,8 @@ Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>
|
|||
Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
|
||||
Hans Verkuil <hverkuil@kernel.org> <hans.verkuil@cisco.com>
|
||||
Hao Ge <hao.ge@linux.dev> <gehao@kylinos.cn>
|
||||
Haowen Bai <baihaowen88@gmail.com> <baihaowen@meizu.com>
|
||||
Haowen Bai <baihaowen88@gmail.com> <calvin.bai@ugreen.com>
|
||||
Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
|
||||
Harry Yoo <harry@kernel.org> <harry.yoo@oracle.com>
|
||||
Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
|
||||
|
|
@ -975,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>
|
||||
|
|
@ -982,6 +987,8 @@ Wesley Cheng <quic_wcheng@quicinc.com> <wcheng@codeaurora.org>
|
|||
Will Deacon <will@kernel.org> <will.deacon@arm.com>
|
||||
Wolfram Sang <wsa@kernel.org> <w.sang@pengutronix.de>
|
||||
Wolfram Sang <wsa@kernel.org> <wsa@the-dreams.de>
|
||||
Xu Xin <xu.xin@linux.dev> <xu.xin16@zte.com.cn>
|
||||
Xu Xin <xu.xin@linux.dev> xu xin <cgel.zte@gmail.com>
|
||||
Yakir Yang <kuankuan.y@gmail.com> <ykk@rock-chips.com>
|
||||
Yanteng Si <si.yanteng@linux.dev> <siyanteng@loongson.cn>
|
||||
Ying Huang <huang.ying.caritas@gmail.com> <ying.huang@intel.com>
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ stable kernels.
|
|||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A725 | #3456106 | ARM64_ERRATUM_3194386 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-A725 | #3821522 | ARM64_ERRATUM_3821522 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X1 | #1502854 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| ARM | Cortex-X1 | #3324344 | ARM64_ERRATUM_3194386 |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -12,19 +12,19 @@ maintainers:
|
|||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: rockchip,saradc
|
||||
- const: rockchip,rk3066-tsadc
|
||||
- const: rockchip,rk3399-saradc
|
||||
- const: rockchip,rk3528-saradc
|
||||
- enum:
|
||||
- rockchip,saradc
|
||||
- rockchip,rk3066-tsadc
|
||||
- rockchip,rk3399-saradc
|
||||
- rockchip,rk3528-saradc
|
||||
- rockchip,rk3562-saradc
|
||||
- rockchip,rk3588-saradc
|
||||
- rockchip,rv1106-saradc
|
||||
- items:
|
||||
- const: rockchip,rk3506-saradc
|
||||
- const: rockchip,rk3528-saradc
|
||||
- const: rockchip,rk3562-saradc
|
||||
- const: rockchip,rk3588-saradc
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3576-saradc
|
||||
- rockchip,rv1106-saradc
|
||||
- const: rockchip,rk3576-saradc
|
||||
- const: rockchip,rk3588-saradc
|
||||
- items:
|
||||
- enum:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -451,6 +451,32 @@ one.
|
|||
The inode should be marked ``NETFS_ICTX_SINGLE_NO_UPLOAD`` if this API is to be
|
||||
used. The writeback function requires the buffer to be of ITER_FOLIOQ type.
|
||||
|
||||
Clearing Stale Post-EOF Pagecache
|
||||
---------------------------------
|
||||
|
||||
When a file is extended, data left in the pagecache past the old EOF by a write
|
||||
through an mmap must not be exposed as file content. Netfslib clears this on
|
||||
its own write paths, and exports a helper so a filesystem can do the same from
|
||||
a resize path (truncate, setattr, fallocate and the like) that holds the
|
||||
inode's ``i_rwsem`` exclusively across the whole resize::
|
||||
|
||||
void netfs_clear_stale_post_isize(struct inode *inode, uoff_t from,
|
||||
uoff_t to);
|
||||
|
||||
This zeroes any such data within the ``[from, to)`` hole to be made, where
|
||||
@from is the old EOF and @to is the new one, and the caller must have already
|
||||
updated ``i_size`` to @to before calling it. Only the folio straddling @from
|
||||
can hold data written past the EOF through an mmap, as pages wholly beyond the
|
||||
EOF can't be faulted in, so the zeroing is limited to that folio. The folio is
|
||||
zeroed rather than dropped so that a concurrent extending write can't lose
|
||||
data.
|
||||
|
||||
This overlaps with ``pagecache_isize_extended()`` but can't reuse it: that
|
||||
helper is keyed on a sub-page block size and is a no-op when the block size is
|
||||
``>= PAGE_SIZE`` (as on network filesystems), and it doesn't wait for
|
||||
writeback. As both address the same problem, a change to one should probably
|
||||
be reflected in the other to keep them in sync.
|
||||
|
||||
High-Level VM API
|
||||
==================
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
===========================
|
||||
|
|
|
|||
92
MAINTAINERS
92
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
|
||||
|
|
@ -14944,7 +14946,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/
|
||||
|
|
@ -17233,7 +17235,7 @@ F: tools/testing/selftests/mm/gup_test.c
|
|||
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: David Hildenbrand <david@kernel.org>
|
||||
R: Xu Xin <xu.xin16@zte.com.cn>
|
||||
R: Xu Xin <xu.xin@linux.dev>
|
||||
R: Chengming Zhou <chengming.zhou@linux.dev>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
|
|
@ -17247,31 +17249,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>
|
||||
|
|
@ -17281,6 +17258,8 @@ R: Barry Song <baohua@kernel.org>
|
|||
R: Axel Rasmussen <axelrasmussen@google.com>
|
||||
R: Yuanchu Xie <yuanchu@google.com>
|
||||
R: Wei Xu <weixugc@google.com>
|
||||
R: Baoquan He <baoquan.he@linux.dev>
|
||||
R: Baolin Wang <baolin.wang@linux.alibaba.com>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
W: http://www.linux-mm.org
|
||||
|
|
@ -17292,6 +17271,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>
|
||||
|
|
@ -17307,7 +17305,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/
|
||||
|
|
@ -17315,7 +17312,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
|
||||
|
|
@ -17327,7 +17323,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
|
||||
|
|
@ -17344,6 +17339,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>
|
||||
|
|
@ -18921,7 +18937,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
|
||||
|
|
@ -19038,7 +19054,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>
|
||||
|
|
@ -19264,7 +19280,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
|
||||
|
|
@ -19297,7 +19313,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>
|
||||
|
|
@ -20593,6 +20609,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
|
||||
|
|
@ -24511,6 +24528,11 @@ R: Marc Murphy <marc.murphy@sancloud.com>
|
|||
S: Supported
|
||||
F: arch/arm/boot/dts/ti/omap/am335x-sancloud*
|
||||
|
||||
SB1250-DUART BROADCOM SOC SERIAL DRIVER
|
||||
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
|
||||
S: Maintained
|
||||
F: drivers/tty/serial/sb1250-duart.c
|
||||
|
||||
SBOM
|
||||
M: Luis Augenstein <luis.augenstein@tngtech.com>
|
||||
M: Maximilian Huber <maximilian.huber@tngtech.com>
|
||||
|
|
@ -25221,7 +25243,7 @@ R: David Rientjes <rientjes@google.com>
|
|||
R: Roman Gushchin <roman.gushchin@linux.dev>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mm/slab.git
|
||||
F: Documentation/admin-guide/mm/slab.rst
|
||||
F: Documentation/mm/slab.rst
|
||||
F: include/linux/mempool.h
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 7
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc6
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -1040,9 +1040,17 @@ config ARM64_ERRATUM_1902691
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
bool
|
||||
# Targeting errata affecting AMEVCNTR01, the AMU constant counter.
|
||||
# On affected CPUs the counter may not increment at the expected rate,
|
||||
# making it unreliable. As a result, AMU users should treat it as
|
||||
# unavailable rather than relying on misleading counter values.
|
||||
|
||||
config ARM64_ERRATUM_2457168
|
||||
bool "Cortex-A510: 2457168: workaround for AMEVCNTR01 incrementing incorrectly"
|
||||
depends on ARM64_AMU_EXTN
|
||||
select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Cortex-A510 erratum 2457168.
|
||||
|
|
@ -1073,6 +1081,28 @@ config ARM64_ERRATUM_2645198
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_ERRATUM_3821522
|
||||
bool "Cortex-A725: 3821522: workaround for possible CNT_CYCLES increment error due to WFE/WFI"
|
||||
depends on ARM64_AMU_EXTN
|
||||
select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
default y
|
||||
help
|
||||
This option adds the workaround for ARM Cortex-A725 erratum 3821522.
|
||||
|
||||
On affected A725 cores, the CNT_CYCLES event may incur a significant
|
||||
increment error when entering and subsequently exiting WFx.
|
||||
As a result, the CNT_CYCLES may diverge from the system counter
|
||||
frequency at which it is expected to increment.
|
||||
This renders the AMU counter AMEVCNTR01, that implements CNT_CYCLES,
|
||||
being unreliable and unsuitable for use.
|
||||
|
||||
Since there is no hardware workaround, reads of the affected CNT_CYCLES
|
||||
counter return 0 in the relevant paths. This causes users of the counter
|
||||
to treat it as unavailable and is functionally equivalent to firmware
|
||||
disabling the affected counter.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD
|
||||
bool
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -381,6 +384,20 @@ static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
static const struct midr_range workaround_amu_constcnt_list[] = {
|
||||
#ifdef CONFIG_ARM64_ERRATUM_2457168
|
||||
/* Cortex-A510 r0p0-r1p1 */
|
||||
MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1),
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_ERRATUM_3821522
|
||||
/* Cortex-A725 r0p0 - r0p2 */
|
||||
MIDR_RANGE(MIDR_CORTEX_A725, 0, 0, 0, 2),
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
#endif /* CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT */
|
||||
|
||||
#ifdef CONFIG_CAVIUM_ERRATUM_23154
|
||||
static const struct midr_range cavium_erratum_23154_cpus[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_THUNDERX),
|
||||
|
|
@ -916,14 +933,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
|
|||
ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2)
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_ERRATUM_2457168
|
||||
#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
{
|
||||
.desc = "ARM erratum 2457168",
|
||||
.capability = ARM64_WORKAROUND_2457168,
|
||||
.desc = "Broken AMU AMEVCNTR01 (const counter)",
|
||||
.capability = ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT,
|
||||
.type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
|
||||
|
||||
/* Cortex-A510 r0p0-r1p1 */
|
||||
CAP_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1)
|
||||
CAP_MIDR_RANGE_LIST(workaround_amu_constcnt_list)
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM64_ERRATUM_2038923
|
||||
|
|
|
|||
|
|
@ -2089,7 +2089,7 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)
|
|||
cpumask_set_cpu(smp_processor_id(), &amu_cpus);
|
||||
|
||||
/* 0 reference values signal broken/disabled counters */
|
||||
if (!this_cpu_has_cap(ARM64_WORKAROUND_2457168))
|
||||
if (!this_cpu_has_cap(ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT))
|
||||
update_freq_counters_refs();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
|
|
|
|||
|
|
@ -433,6 +433,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
|||
unsigned int vl, vq;
|
||||
struct user_fpsimd_state fpsimd;
|
||||
u16 user_vl, flags;
|
||||
bool fpsimd_only;
|
||||
bool sm;
|
||||
|
||||
if (user->sve_size < sizeof(*user->sve))
|
||||
|
|
@ -443,19 +444,33 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
fpsimd_only = (user->sve_size == sizeof(*user->sve));
|
||||
sm = flags & SVE_SIG_FLAG_SM;
|
||||
|
||||
if (sm) {
|
||||
if (!system_supports_sme())
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Streaming SVE state is always preserved with an SVE payload.
|
||||
* Only accept streaming state which has an SVE payload.
|
||||
*/
|
||||
if (fpsimd_only)
|
||||
return -EINVAL;
|
||||
|
||||
vl = task_get_sme_vl(current);
|
||||
} else {
|
||||
/*
|
||||
* A SME only system use SVE for streaming mode so can
|
||||
* have a SVE formatted context with a zero VL and no
|
||||
* payload data.
|
||||
* Non-streaming SVE state may be preserved without an SVE
|
||||
* payload, in which case all state is saved in the FPSIMD
|
||||
* context.
|
||||
*
|
||||
* On SME-only systems, non-streaming (FPSIMD-only) state is
|
||||
* always preserved without an SVE payload, and with VL==0. On
|
||||
* such systems, only accept non-streaming state without an SVE
|
||||
* payload.
|
||||
*/
|
||||
if (!system_supports_sve() && !system_supports_sme())
|
||||
if (!system_supports_sve() && !fpsimd_only)
|
||||
return -EINVAL;
|
||||
|
||||
vl = task_get_sve_vl(current);
|
||||
|
|
@ -464,16 +479,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
|
|||
if (user_vl != vl)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Non-streaming SVE state may be preserved without an SVE payload, in
|
||||
* which case the SVE context only has a header with VL==0, and all
|
||||
* state can be restored from the FPSIMD context.
|
||||
*
|
||||
* Streaming SVE state is always preserved with an SVE payload. For
|
||||
* consistency and robustness, reject restoring streaming SVE state
|
||||
* without an SVE payload.
|
||||
*/
|
||||
if (!sm && user->sve_size == sizeof(*user->sve))
|
||||
if (fpsimd_only)
|
||||
return restore_fpsimd_context(user);
|
||||
|
||||
vq = sve_vq_from_vl(vl);
|
||||
|
|
|
|||
|
|
@ -186,7 +186,6 @@ int arch_freq_get_on_cpu(int cpu)
|
|||
struct amu_cntr_sample *amu_sample;
|
||||
unsigned int start_cpu = cpu;
|
||||
unsigned long last_update;
|
||||
unsigned int freq = 0;
|
||||
u64 scale;
|
||||
|
||||
if (!amu_fie_cpu_supported(cpu) || !arch_scale_freq_ref(cpu))
|
||||
|
|
@ -245,9 +244,8 @@ int arch_freq_get_on_cpu(int cpu)
|
|||
* (see amu_scale_freq_tick for details)
|
||||
*/
|
||||
scale = arch_scale_freq_capacity(cpu);
|
||||
freq = scale * arch_scale_freq_ref(cpu);
|
||||
freq >>= SCHED_CAPACITY_SHIFT;
|
||||
return freq;
|
||||
|
||||
return (scale * arch_scale_freq_ref(cpu)) >> SCHED_CAPACITY_SHIFT;
|
||||
}
|
||||
|
||||
static void amu_fie_setup(const struct cpumask *cpus)
|
||||
|
|
@ -397,12 +395,13 @@ static void cpu_read_corecnt(void *val)
|
|||
static void cpu_read_constcnt(void *val)
|
||||
{
|
||||
/*
|
||||
* Return 0 if the current CPU is affected by erratum 2457168. A value
|
||||
* of 0 is also returned if the current CPU does not support AMUs or if
|
||||
* the counter is disabled. A return value of 0 at counter read is
|
||||
* properly handled as an error case by the users of the counter.
|
||||
* Return 0 if the current CPU is affected by a HW erratum.
|
||||
* A value of 0 is also returned if the current CPU does not
|
||||
* support AMUs or if the counter is disabled. A return
|
||||
* value of 0 at counter read is properly handled as an error
|
||||
* case by the users of the counter.
|
||||
*/
|
||||
*(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_2457168) ?
|
||||
*(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT) ?
|
||||
0UL : read_constcnt();
|
||||
}
|
||||
|
||||
|
|
@ -463,8 +462,9 @@ static void amu_read_core_const_ctrs(void *val)
|
|||
|
||||
/*
|
||||
* cpu_read_constcnt() incurs slight latency due to the
|
||||
* ARM64_WORKAROUND_2457168 check. Read it first to minimize
|
||||
* the sampling skew between the const and core counters.
|
||||
* ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT check.
|
||||
* Read it first to minimize the sampling skew between the const
|
||||
* and core counters.
|
||||
*/
|
||||
cpu_read_constcnt(&ctrs->constcnt);
|
||||
cpu_read_corecnt(&ctrs->corecnt);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
|
|||
$(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
|
||||
-Wmissing-prototypes -Wmissing-declarations
|
||||
|
||||
CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
|
||||
CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables $(CONFIG_CC_OPT_INLINE_MEMSET)
|
||||
|
||||
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
|
||||
CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2295,7 +2295,7 @@ pte_t modify_prot_start_ptes(struct vm_area_struct *vma, unsigned long addr,
|
|||
* in cases where cpu is affected with errata #2645198.
|
||||
*/
|
||||
if (pte_accessible(vma->vm_mm, pte) && pte_user_exec(pte))
|
||||
__flush_tlb_range(vma, addr, nr * PAGE_SIZE,
|
||||
__flush_tlb_range(vma, addr, addr + nr * PAGE_SIZE,
|
||||
PAGE_SIZE, 3, TLBF_NOWALKCACHE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -2416,10 +2418,11 @@ bool bpf_jit_supports_subprog_tailcalls(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_node *node,
|
||||
int bargs_off, int retval_off, int run_ctx_off,
|
||||
bool save_ret)
|
||||
static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
struct bpf_tramp_node *node, int bargs_off,
|
||||
int retval_off, int run_ctx_off, bool save_ret)
|
||||
{
|
||||
void *skip;
|
||||
__le32 *branch;
|
||||
u64 enter_prog;
|
||||
u64 exit_prog;
|
||||
|
|
@ -2429,6 +2432,10 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_node *node,
|
|||
enter_prog = (u64)bpf_trampoline_enter(p);
|
||||
exit_prog = (u64)bpf_trampoline_exit(p);
|
||||
|
||||
/* nop, patched to skip this prog when it is detached */
|
||||
skip = ctx->ro_image + ctx->idx;
|
||||
emit(A64_NOP, ctx);
|
||||
|
||||
if (node->cookie == 0) {
|
||||
/* if cookie is zero, one instruction is enough to store it */
|
||||
emit(A64_STR64I(A64_ZR, A64_SP, run_ctx_off + cookie_off), ctx);
|
||||
|
|
@ -2481,11 +2488,13 @@ static void invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_node *node,
|
|||
emit(A64_ADD_I(1, A64_R(2), A64_SP, run_ctx_off), ctx);
|
||||
|
||||
emit_call(exit_prog, ctx);
|
||||
|
||||
bpf_tramp_image_add_skip(im, p, skip, ctx->ro_image + ctx->idx);
|
||||
}
|
||||
|
||||
static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn,
|
||||
int bargs_off, int retval_off, int run_ctx_off,
|
||||
__le32 **branches)
|
||||
static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
struct bpf_tramp_nodes *tn, int bargs_off,
|
||||
int retval_off, int run_ctx_off, __le32 **branches)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -2494,7 +2503,7 @@ static void invoke_bpf_mod_ret(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn,
|
|||
*/
|
||||
emit(A64_STR64I(A64_ZR, A64_SP, retval_off), ctx);
|
||||
for (i = 0; i < tn->nr_nodes; i++) {
|
||||
invoke_bpf_prog(ctx, tn->nodes[i], bargs_off, retval_off,
|
||||
invoke_bpf_prog(ctx, im, tn->nodes[i], bargs_off, retval_off,
|
||||
run_ctx_off, true);
|
||||
/* if (*(u64 *)(sp + retval_off) != 0)
|
||||
* goto do_fexit;
|
||||
|
|
@ -2880,7 +2889,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
store_func_meta(ctx, meta, func_meta_off);
|
||||
cookie_bargs_off--;
|
||||
}
|
||||
invoke_bpf_prog(ctx, fentry->nodes[i], bargs_off,
|
||||
invoke_bpf_prog(ctx, im, fentry->nodes[i], bargs_off,
|
||||
retval_off, run_ctx_off,
|
||||
flags & BPF_TRAMP_F_RET_FENTRY_RET);
|
||||
}
|
||||
|
|
@ -2891,7 +2900,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
if (!branches)
|
||||
return -ENOMEM;
|
||||
|
||||
invoke_bpf_mod_ret(ctx, fmod_ret, bargs_off, retval_off,
|
||||
invoke_bpf_mod_ret(ctx, im, fmod_ret, bargs_off, retval_off,
|
||||
run_ctx_off, branches);
|
||||
}
|
||||
|
||||
|
|
@ -2904,9 +2913,6 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
emit(A64_RET(A64_R(10)), ctx);
|
||||
/* store return value */
|
||||
emit(A64_STR64I(A64_R(0), A64_SP, retval_off), ctx);
|
||||
/* reserve a nop for bpf_tramp_image_put */
|
||||
im->ip_after_call = ctx->ro_image + ctx->idx;
|
||||
emit(A64_NOP, ctx);
|
||||
}
|
||||
|
||||
/* update the branches saved in invoke_bpf_mod_ret with cbnz */
|
||||
|
|
@ -2928,12 +2934,11 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
|||
store_func_meta(ctx, meta, func_meta_off);
|
||||
cookie_bargs_off--;
|
||||
}
|
||||
invoke_bpf_prog(ctx, fexit->nodes[i], bargs_off, retval_off,
|
||||
invoke_bpf_prog(ctx, im, fexit->nodes[i], bargs_off, retval_off,
|
||||
run_ctx_off, false);
|
||||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = ctx->ro_image + ctx->idx;
|
||||
/* for the first pass, assume the worst case */
|
||||
if (!ctx->image)
|
||||
ctx->idx += 4;
|
||||
|
|
@ -2992,7 +2997,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
|||
.image = NULL,
|
||||
.idx = 0,
|
||||
};
|
||||
struct bpf_tramp_image im;
|
||||
struct bpf_tramp_image im = {};
|
||||
struct arg_aux aaux;
|
||||
int ret;
|
||||
|
||||
|
|
@ -3279,6 +3284,10 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
|
|||
* longer reachable, since bpf_tramp_image_put() function already
|
||||
* uses percpu_ref and task-based rcu to do the sync, no need to call
|
||||
* the sync version here, see bpf_tramp_image_put() for details.
|
||||
*
|
||||
* 3. when a detached prog is patched out of a trampoline, a CPU that
|
||||
* still executes the old nop calls the prog before it went through
|
||||
* a quiescent state, and the prog is freed after grace periods.
|
||||
*/
|
||||
ret = aarch64_insn_patch_text_nosync(ip, new_insn);
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ WORKAROUND_1902691
|
|||
WORKAROUND_2038923
|
||||
WORKAROUND_2064142
|
||||
WORKAROUND_2077057
|
||||
WORKAROUND_2457168
|
||||
WORKAROUND_2645198
|
||||
WORKAROUND_2658417
|
||||
WORKAROUND_4193714
|
||||
|
|
@ -132,3 +131,4 @@ WORKAROUND_REPEAT_TLBI_SYNC
|
|||
WORKAROUND_SPECULATIVE_AT
|
||||
WORKAROUND_SPECULATIVE_SSBS
|
||||
WORKAROUND_SPECULATIVE_UNPRIV_LOAD
|
||||
WORKAROUND_BROKEN_AMU_CONSTCNT
|
||||
|
|
|
|||
|
|
@ -1578,6 +1578,24 @@ void *bpf_arch_text_copy(void *dst, void *src, size_t len)
|
|||
return ret ? ERR_PTR(-EINVAL) : dst;
|
||||
}
|
||||
|
||||
int arch_bpf_trampoline_skip(void *nop, void *target)
|
||||
{
|
||||
u32 old_insn = INSN_NOP;
|
||||
u32 new_insn = larch_insn_gen_b((unsigned long)nop, (unsigned long)target);
|
||||
int ret;
|
||||
|
||||
if (memcmp(nop, &old_insn, LOONGARCH_INSN_SIZE))
|
||||
return -EFAULT;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
ret = larch_insn_text_copy(nop, &new_insn, LOONGARCH_INSN_SIZE);
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
|
||||
enum bpf_text_poke_type new_t, void *old_addr,
|
||||
void *new_addr)
|
||||
|
|
@ -1696,13 +1714,18 @@ static void restore_stk_args(struct jit_ctx *ctx, int nr_stk_args, int args_off,
|
|||
}
|
||||
}
|
||||
|
||||
static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_node *n,
|
||||
int args_off, int retval_off, int run_ctx_off, bool save_ret)
|
||||
static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
struct bpf_tramp_node *n, int args_off, int retval_off,
|
||||
int run_ctx_off, bool save_ret)
|
||||
{
|
||||
int ret;
|
||||
u32 *branch;
|
||||
struct bpf_prog *p = n->link->prog;
|
||||
int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
|
||||
void *skip = ctx->ro_image + ctx->idx;
|
||||
|
||||
/* nop, patched to a b over this prog when it is detached */
|
||||
emit_insn(ctx, nop);
|
||||
|
||||
if (n->cookie)
|
||||
emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1,
|
||||
|
|
@ -1755,13 +1778,17 @@ static int invoke_bpf_prog(struct jit_ctx *ctx, struct bpf_tramp_node *n,
|
|||
/* arg3: &run_ctx */
|
||||
emit_insn(ctx, addid, LOONGARCH_GPR_A2, LOONGARCH_GPR_FP, -run_ctx_off);
|
||||
ret = emit_call(ctx, (const u64)bpf_trampoline_exit(p));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
bpf_tramp_image_add_skip(im, p, skip, ctx->ro_image + ctx->idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn,
|
||||
int args_off, int retval_off, int run_ctx_off,
|
||||
int func_meta_off, bool save_ret, u64 func_meta, int cookie_off)
|
||||
static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_image *im,
|
||||
struct bpf_tramp_nodes *tn, int args_off, int retval_off,
|
||||
int run_ctx_off, int func_meta_off, bool save_ret,
|
||||
u64 func_meta, int cookie_off)
|
||||
{
|
||||
int i, cur_cookie = (cookie_off - args_off) / 8;
|
||||
|
||||
|
|
@ -1774,7 +1801,8 @@ static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn,
|
|||
emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, meta);
|
||||
cur_cookie--;
|
||||
}
|
||||
err = invoke_bpf_prog(ctx, tn->nodes[i], args_off, retval_off, run_ctx_off, save_ret);
|
||||
err = invoke_bpf_prog(ctx, im, tn->nodes[i], args_off, retval_off,
|
||||
run_ctx_off, save_ret);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
|
@ -2017,7 +2045,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
}
|
||||
|
||||
if (fentry->nr_nodes) {
|
||||
ret = invoke_bpf(ctx, fentry, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
ret = invoke_bpf(ctx, im, fentry, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
flags & BPF_TRAMP_F_RET_FENTRY_RET, func_meta, cookie_off);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -2029,7 +2057,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
|
||||
emit_insn(ctx, std, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_FP, -retval_off);
|
||||
for (i = 0; i < fmod_ret->nr_nodes; i++) {
|
||||
ret = invoke_bpf_prog(ctx, fmod_ret->nodes[i],
|
||||
ret = invoke_bpf_prog(ctx, im, fmod_ret->nodes[i],
|
||||
args_off, retval_off, run_ctx_off, true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
@ -2051,10 +2079,6 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
goto out;
|
||||
emit_insn(ctx, std, LOONGARCH_GPR_A0, LOONGARCH_GPR_FP, -retval_off);
|
||||
emit_insn(ctx, std, regmap[BPF_REG_0], LOONGARCH_GPR_FP, -(retval_off - 8));
|
||||
im->ip_after_call = ctx->ro_image + ctx->idx;
|
||||
/* Reserve space for the move_imm + jirl instruction */
|
||||
for (i = 0; i < LOONGARCH_LONG_JUMP_NINSNS; i++)
|
||||
emit_insn(ctx, nop);
|
||||
}
|
||||
|
||||
for (i = 0; ctx->image && i < fmod_ret->nr_nodes; i++) {
|
||||
|
|
@ -2068,14 +2092,13 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i
|
|||
emit_store_stack_imm64(ctx, LOONGARCH_GPR_T1, -func_meta_off, func_meta);
|
||||
|
||||
if (fexit->nr_nodes) {
|
||||
ret = invoke_bpf(ctx, fexit, args_off, retval_off, run_ctx_off,
|
||||
ret = invoke_bpf(ctx, im, fexit, args_off, retval_off, run_ctx_off,
|
||||
func_meta_off, false, func_meta, cookie_off);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = ctx->ro_image + ctx->idx;
|
||||
move_addr(ctx, LOONGARCH_GPR_A0, (const u64)im);
|
||||
ret = emit_call(ctx, (const u64)__bpf_tramp_exit);
|
||||
if (ret)
|
||||
|
|
@ -2177,11 +2200,8 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
|||
struct bpf_tramp_nodes *tnodes, void *func_addr)
|
||||
{
|
||||
int ret;
|
||||
struct jit_ctx ctx;
|
||||
struct bpf_tramp_image im;
|
||||
|
||||
ctx.image = NULL;
|
||||
ctx.idx = 0;
|
||||
struct jit_ctx ctx = {};
|
||||
struct bpf_tramp_image im = {};
|
||||
|
||||
ret = __arch_prepare_bpf_trampoline(&ctx, &im, m, tnodes, func_addr, flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ ccflags-vdso := \
|
|||
$(filter -m64,$(KBUILD_CFLAGS)) \
|
||||
$(filter -march=%,$(KBUILD_CFLAGS)) \
|
||||
$(filter -m%-float,$(KBUILD_CFLAGS)) \
|
||||
$(CONFIG_CC_OPT_INLINE_MEMSET) \
|
||||
$(CLANG_FLAGS) \
|
||||
-D__VDSO__
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ ccflags-y := -fno-common -fno-builtin -DBUILD_VDSO
|
|||
ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN)
|
||||
ccflags-y += $(call cc-option, -fno-stack-protector)
|
||||
ccflags-y += -DDISABLE_BRANCH_PROFILING
|
||||
ccflags-y += $(CONFIG_CC_OPT_INLINE_MEMSET)
|
||||
ccflags-y += -ffreestanding -fasynchronous-unwind-tables
|
||||
ccflags-remove-y := $(CC_FLAGS_FTRACE)
|
||||
ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -602,14 +602,18 @@ int arch_protect_bpf_trampoline(void *image, unsigned int size)
|
|||
}
|
||||
|
||||
static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ctx,
|
||||
struct bpf_tramp_node *n, int regs_off, int retval_off,
|
||||
int run_ctx_off, bool save_ret)
|
||||
struct bpf_tramp_image *im, struct bpf_tramp_node *n,
|
||||
int regs_off, int retval_off, int run_ctx_off, bool save_ret)
|
||||
{
|
||||
struct bpf_prog *p = n->link->prog;
|
||||
ppc_inst_t branch_insn;
|
||||
u32 jmp_idx;
|
||||
u32 jmp_idx, skip_idx;
|
||||
int ret = 0;
|
||||
|
||||
/* nop, patched to skip this prog when it is detached */
|
||||
skip_idx = ctx->idx;
|
||||
EMIT(PPC_RAW_NOP());
|
||||
|
||||
/* Save cookie */
|
||||
if (IS_ENABLED(CONFIG_PPC64)) {
|
||||
PPC_LI64(_R3, n->cookie);
|
||||
|
|
@ -679,13 +683,17 @@ static int invoke_bpf_prog(u32 *image, u32 *ro_image, struct codegen_context *ct
|
|||
EMIT(PPC_RAW_ADDI(_R5, _R1, run_ctx_off));
|
||||
ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx,
|
||||
(unsigned long)bpf_trampoline_exit(p));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
if (ro_image) /* image is NULL for dummy pass */
|
||||
bpf_tramp_image_add_skip(im, p, &ro_image[skip_idx], &ro_image[ctx->idx]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_bpf_mod_ret(u32 *image, u32 *ro_image, struct codegen_context *ctx,
|
||||
struct bpf_tramp_nodes *tn, int regs_off, int retval_off,
|
||||
int run_ctx_off, u32 *branches)
|
||||
struct bpf_tramp_image *im, struct bpf_tramp_nodes *tn,
|
||||
int regs_off, int retval_off, int run_ctx_off, u32 *branches)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -696,8 +704,8 @@ static int invoke_bpf_mod_ret(u32 *image, u32 *ro_image, struct codegen_context
|
|||
EMIT(PPC_RAW_LI(_R3, 0));
|
||||
EMIT(PPC_RAW_STL(_R3, _R1, retval_off));
|
||||
for (i = 0; i < tn->nr_nodes; i++) {
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, tn->nodes[i], regs_off, retval_off,
|
||||
run_ctx_off, true))
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, im, tn->nodes[i], regs_off,
|
||||
retval_off, run_ctx_off, true))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
|
@ -1043,8 +1051,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
|||
cookie_ctx_off--;
|
||||
}
|
||||
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, fentry->nodes[i], regs_off, retval_off,
|
||||
run_ctx_off, flags & BPF_TRAMP_F_RET_FENTRY_RET))
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, im, fentry->nodes[i], regs_off,
|
||||
retval_off, run_ctx_off, flags & BPF_TRAMP_F_RET_FENTRY_RET))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1053,7 +1061,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
|||
if (!branches)
|
||||
return -ENOMEM;
|
||||
|
||||
if (invoke_bpf_mod_ret(image, ro_image, ctx, fmod_ret, regs_off, retval_off,
|
||||
if (invoke_bpf_mod_ret(image, ro_image, ctx, im, fmod_ret, regs_off, retval_off,
|
||||
run_ctx_off, branches)) {
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
|
|
@ -1090,11 +1098,6 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
|||
/* Restore updated tail_call_cnt */
|
||||
if (flags & BPF_TRAMP_F_TAIL_CALL_CTX)
|
||||
bpf_trampoline_restore_tail_call_cnt(image, ctx, bpf_frame_size, r4_off);
|
||||
|
||||
/* Reserve space to patch branch instruction to skip fexit progs */
|
||||
if (ro_image) /* image is NULL for dummy pass */
|
||||
im->ip_after_call = &((u32 *)ro_image)[ctx->idx];
|
||||
EMIT(PPC_RAW_NOP());
|
||||
}
|
||||
|
||||
/* Update branches saved in invoke_bpf_mod_ret with address of do_fexit */
|
||||
|
|
@ -1123,16 +1126,14 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
|||
cookie_ctx_off--;
|
||||
}
|
||||
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, fexit->nodes[i], regs_off, retval_off,
|
||||
run_ctx_off, false)) {
|
||||
if (invoke_bpf_prog(image, ro_image, ctx, im, fexit->nodes[i], regs_off,
|
||||
retval_off, run_ctx_off, false)) {
|
||||
ret = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
if (ro_image) /* image is NULL for dummy pass */
|
||||
im->ip_epilogue = &((u32 *)ro_image)[ctx->idx];
|
||||
PPC_LI_ADDR(_R3, im);
|
||||
ret = bpf_jit_emit_func_call_rel(image, ro_image, ctx,
|
||||
(unsigned long)__bpf_tramp_exit);
|
||||
|
|
@ -1192,7 +1193,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im
|
|||
int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
struct bpf_tramp_nodes *tnodes, void *func_addr)
|
||||
{
|
||||
struct bpf_tramp_image im;
|
||||
struct bpf_tramp_image im = {};
|
||||
int ret;
|
||||
|
||||
ret = __arch_prepare_bpf_trampoline(&im, NULL, NULL, NULL, m, flags, tnodes, func_addr);
|
||||
|
|
@ -1320,7 +1321,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
|
|||
|
||||
/*
|
||||
* If we are not poking at bpf prog entry, then we are simply patching in/out
|
||||
* an unconditional branch instruction at im->ip_after_call
|
||||
* an unconditional branch instruction in a trampoline image
|
||||
*/
|
||||
if (offset) {
|
||||
if (old_t == BPF_MOD_CALL || new_t == BPF_MOD_CALL) {
|
||||
|
|
|
|||
|
|
@ -1275,6 +1275,8 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
|
|||
struct perf_event_header *header,
|
||||
struct perf_event *event)
|
||||
{
|
||||
u16 misc = 0;
|
||||
|
||||
/* Sanity checks for a valid record */
|
||||
if (be64_to_cpu(READ_ONCE(mem->tb1)) > *prev_tb)
|
||||
*prev_tb = be64_to_cpu(READ_ONCE(mem->tb1));
|
||||
|
|
@ -1289,23 +1291,19 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
|
|||
data->ip = be64_to_cpu(READ_ONCE(mem->ip));
|
||||
data->period = event->hw.last_period;
|
||||
|
||||
header->type = PERF_RECORD_SAMPLE;
|
||||
header->size = sizeof(*header) + event->header_size;
|
||||
header->misc = 0;
|
||||
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_31)) {
|
||||
switch (IMC_TRACE_RECORD_VAL_HVPR(be64_to_cpu(READ_ONCE(mem->val)))) {
|
||||
case 0:/* when MSR HV and PR not set in the trace-record */
|
||||
header->misc |= PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
misc |= PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
break;
|
||||
case 1: /* MSR HV is 0 and PR is 1 */
|
||||
header->misc |= PERF_RECORD_MISC_GUEST_USER;
|
||||
misc |= PERF_RECORD_MISC_GUEST_USER;
|
||||
break;
|
||||
case 2: /* MSR HV is 1 and PR is 0 */
|
||||
header->misc |= PERF_RECORD_MISC_KERNEL;
|
||||
misc |= PERF_RECORD_MISC_KERNEL;
|
||||
break;
|
||||
case 3: /* MSR HV is 1 and PR is 1 */
|
||||
header->misc |= PERF_RECORD_MISC_USER;
|
||||
misc |= PERF_RECORD_MISC_USER;
|
||||
break;
|
||||
default:
|
||||
pr_info("IMC: Unable to set the flag based on MSR bits\n");
|
||||
|
|
@ -1313,11 +1311,14 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem,
|
|||
}
|
||||
} else {
|
||||
if (is_kernel_addr(data->ip))
|
||||
header->misc |= PERF_RECORD_MISC_KERNEL;
|
||||
misc |= PERF_RECORD_MISC_KERNEL;
|
||||
else
|
||||
header->misc |= PERF_RECORD_MISC_USER;
|
||||
misc |= PERF_RECORD_MISC_USER;
|
||||
}
|
||||
perf_event_header__init_id(header, data, event);
|
||||
perf_event_header__init(header, data,
|
||||
PERF_RECORD_SAMPLE, misc,
|
||||
sizeof(*header) + event->header_size,
|
||||
event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ endif
|
|||
ccflags-y := -fno-stack-protector
|
||||
ccflags-y += -DDISABLE_BRANCH_PROFILING
|
||||
ccflags-y += -fno-builtin
|
||||
ccflags-y += $(CONFIG_CC_OPT_INLINE_MEMSET)
|
||||
ccflags-y += $(KBUILD_BASE_ISA)$(CFI_MARCH)
|
||||
ccflags-y += $(CFI_FULL)
|
||||
asflags-y += $(KBUILD_BASE_ISA)$(CFI_MARCH)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -822,6 +822,24 @@ static int gen_jump_or_nops(void *target, void *ip, u32 *insns, bool is_call)
|
|||
return emit_jump_and_link(is_call ? RV_REG_T0 : RV_REG_ZERO, rvoff, false, &ctx);
|
||||
}
|
||||
|
||||
int arch_bpf_trampoline_skip(void *nop, void *target)
|
||||
{
|
||||
u32 old_insn = rv_nop();
|
||||
u32 new_insn = rv_jal(RV_REG_ZERO, (target - nop) >> 1);
|
||||
int ret;
|
||||
|
||||
if (memcmp(nop, &old_insn, sizeof(old_insn)))
|
||||
return -EFAULT;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
ret = patch_text(nop, &new_insn, sizeof(new_insn));
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
|
||||
enum bpf_text_poke_type new_t, void *old_addr,
|
||||
void *new_addr)
|
||||
|
|
@ -904,12 +922,17 @@ static void emit_store_stack_imm64(u8 reg, int stack_off, u64 imm64,
|
|||
emit_sd(RV_REG_FP, stack_off, reg, ctx);
|
||||
}
|
||||
|
||||
static int invoke_bpf_prog(struct bpf_tramp_node *node, int args_off, int retval_off,
|
||||
int run_ctx_off, bool save_ret, struct rv_jit_context *ctx)
|
||||
static int invoke_bpf_prog(struct bpf_tramp_image *im, struct bpf_tramp_node *node,
|
||||
int args_off, int retval_off, int run_ctx_off, bool save_ret,
|
||||
struct rv_jit_context *ctx)
|
||||
{
|
||||
int ret, branch_off;
|
||||
struct bpf_prog *p = node->link->prog;
|
||||
int cookie_off = offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
|
||||
void *skip = ctx->ro_insns + ctx->ninsns;
|
||||
|
||||
/* nop, patched to a jal over this prog when it is detached */
|
||||
emit(rv_nop(), ctx);
|
||||
|
||||
if (node->cookie)
|
||||
emit_store_stack_imm64(RV_REG_T1, -run_ctx_off + cookie_off, node->cookie, ctx);
|
||||
|
|
@ -962,13 +985,17 @@ static int invoke_bpf_prog(struct bpf_tramp_node *node, int args_off, int retval
|
|||
/* arg3: &run_ctx */
|
||||
emit_addi(RV_REG_A2, RV_REG_FP, -run_ctx_off, ctx);
|
||||
ret = emit_call((const u64)bpf_trampoline_exit(p), true, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
bpf_tramp_image_add_skip(im, p, skip, ctx->ro_insns + ctx->ninsns);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_bpf(struct bpf_tramp_nodes *tn, int args_off, int retval_off,
|
||||
int run_ctx_off, int func_meta_off, bool save_ret, u64 func_meta,
|
||||
int cookie_off, struct rv_jit_context *ctx)
|
||||
static int invoke_bpf(struct bpf_tramp_image *im, struct bpf_tramp_nodes *tn,
|
||||
int args_off, int retval_off, int run_ctx_off, int func_meta_off,
|
||||
bool save_ret, u64 func_meta, int cookie_off,
|
||||
struct rv_jit_context *ctx)
|
||||
{
|
||||
int i, cur_cookie = (cookie_off - args_off) / 8;
|
||||
|
||||
|
|
@ -981,8 +1008,8 @@ static int invoke_bpf(struct bpf_tramp_nodes *tn, int args_off, int retval_off,
|
|||
emit_store_stack_imm64(RV_REG_T1, -func_meta_off, meta, ctx);
|
||||
cur_cookie--;
|
||||
}
|
||||
err = invoke_bpf_prog(tn->nodes[i], args_off, retval_off, run_ctx_off,
|
||||
save_ret, ctx);
|
||||
err = invoke_bpf_prog(im, tn->nodes[i], args_off, retval_off,
|
||||
run_ctx_off, save_ret, ctx);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1170,7 +1197,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
}
|
||||
|
||||
if (fentry->nr_nodes) {
|
||||
ret = invoke_bpf(fentry, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
ret = invoke_bpf(im, fentry, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
flags & BPF_TRAMP_F_RET_FENTRY_RET, func_meta, cookie_off, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1184,7 +1211,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
/* cleanup to avoid garbage return value confusion */
|
||||
emit_sd(RV_REG_FP, -retval_off, RV_REG_ZERO, ctx);
|
||||
for (i = 0; i < fmod_ret->nr_nodes; i++) {
|
||||
ret = invoke_bpf_prog(fmod_ret->nodes[i], args_off, retval_off,
|
||||
ret = invoke_bpf_prog(im, fmod_ret->nodes[i], args_off, retval_off,
|
||||
run_ctx_off, true, ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
|
@ -1211,10 +1238,6 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
emit_sd(RV_REG_FP, -tcc_off, RV_REG_TCC, ctx);
|
||||
emit_sd(RV_REG_FP, -retval_off, RV_REG_A0, ctx);
|
||||
emit_sd(RV_REG_FP, -(retval_off - 8), regmap[BPF_REG_0], ctx);
|
||||
im->ip_after_call = ctx->ro_insns + ctx->ninsns;
|
||||
/* 2 nops reserved for auipc+jalr pair */
|
||||
emit(rv_nop(), ctx);
|
||||
emit(rv_nop(), ctx);
|
||||
}
|
||||
|
||||
/* update branches saved in invoke_bpf_mod_ret with bnez */
|
||||
|
|
@ -1230,14 +1253,13 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
emit_store_stack_imm64(RV_REG_T1, -func_meta_off, func_meta, ctx);
|
||||
|
||||
if (fexit->nr_nodes) {
|
||||
ret = invoke_bpf(fexit, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
ret = invoke_bpf(im, fexit, args_off, retval_off, run_ctx_off, func_meta_off,
|
||||
false, func_meta, cookie_off, ctx);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = ctx->ro_insns + ctx->ninsns;
|
||||
emit_imm(RV_REG_A0, ctx->insns ? (const s64)im : RV_MAX_COUNT_IMM, ctx);
|
||||
ret = emit_call((const u64)__bpf_tramp_exit, true, ctx);
|
||||
if (ret)
|
||||
|
|
@ -1299,7 +1321,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
struct bpf_tramp_nodes *tnodes, void *func_addr)
|
||||
{
|
||||
struct bpf_tramp_image im;
|
||||
struct bpf_tramp_image im = {};
|
||||
struct rv_jit_context ctx;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,10 @@ static int hash_data(const u8 *in, unsigned int inlen,
|
|||
|
||||
#undef PARAM_INIT
|
||||
|
||||
cpacf_klmd(func, ¶m, in, inlen);
|
||||
if (final)
|
||||
cpacf_klmd(func, ¶m, in, inlen);
|
||||
else
|
||||
cpacf_kimd(func, ¶m, in, inlen);
|
||||
|
||||
memcpy(digest, ¶m, digestsize);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ KBUILD_CFLAGS_VDSO := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_VDSO))
|
|||
KBUILD_CFLAGS_VDSO := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_VDSO))
|
||||
KBUILD_CFLAGS_VDSO += -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables
|
||||
KBUILD_CFLAGS_VDSO += -fno-stack-protector $(DISABLE_KSTACK_ERASE)
|
||||
KBUILD_CFLAGS_VDSO += $(CONFIG_CC_OPT_INLINE_MEMSET)
|
||||
ldflags-y := -shared -soname=linux-vdso.so.1 \
|
||||
--hash-style=both --build-id=sha1 \
|
||||
$(call ld-option, --eh-frame-hdr) -T
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2566,6 +2566,8 @@ struct bpf_tramp_jit {
|
|||
int r14_off; /* Offset of saved %r14, has to be at the
|
||||
* bottom */
|
||||
int do_fexit; /* do_fexit: label */
|
||||
int skip[BPF_MAX_TRAMP_LINKS]; /* skip: labels after each prog */
|
||||
int nr_progs;
|
||||
};
|
||||
|
||||
static void load_imm64(struct bpf_jit *jit, int dst_reg, u64 val)
|
||||
|
|
@ -2584,6 +2586,7 @@ static void emit_store_stack_imm64(struct bpf_jit *jit, int tmp_reg, int stack_o
|
|||
}
|
||||
|
||||
static int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
|
||||
struct bpf_tramp_image *im,
|
||||
const struct btf_func_model *m,
|
||||
struct bpf_tramp_node *node, bool save_ret)
|
||||
{
|
||||
|
|
@ -2591,8 +2594,20 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
|
|||
int cookie_off = tjit->run_ctx_off +
|
||||
offsetof(struct bpf_tramp_run_ctx, bpf_cookie);
|
||||
struct bpf_prog *p = node->link->prog;
|
||||
void *skip = jit->prg_buf + jit->prg;
|
||||
int idx = tjit->nr_progs++;
|
||||
int patch;
|
||||
|
||||
if (idx >= ARRAY_SIZE(tjit->skip))
|
||||
return -E2BIG;
|
||||
|
||||
/*
|
||||
* nop, patched to skip this prog when it is detached
|
||||
*/
|
||||
|
||||
/* brcl 0,skip */
|
||||
EMIT6_PCREL_RILC(0xc0040000, 0, tjit->skip[idx]);
|
||||
|
||||
/*
|
||||
* run_ctx.cookie = node->cookie;
|
||||
*/
|
||||
|
|
@ -2652,10 +2667,15 @@ static int invoke_bpf_prog(struct bpf_tramp_jit *tjit,
|
|||
/* brasl %r14,__bpf_prog_exit */
|
||||
EMIT6_PCREL_RILB_PTR(0xc0050000, REG_14, bpf_trampoline_exit(p));
|
||||
|
||||
/* skip: */
|
||||
tjit->skip[idx] = jit->prg;
|
||||
bpf_tramp_image_add_skip(im, p, skip, jit->prg_buf + jit->prg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invoke_bpf(struct bpf_tramp_jit *tjit,
|
||||
struct bpf_tramp_image *im,
|
||||
const struct btf_func_model *m,
|
||||
struct bpf_tramp_nodes *tn, bool save_ret,
|
||||
u64 func_meta, int cookie_off)
|
||||
|
|
@ -2670,7 +2690,7 @@ static int invoke_bpf(struct bpf_tramp_jit *tjit,
|
|||
emit_store_stack_imm64(jit, REG_0, tjit->func_meta_off, meta);
|
||||
cur_cookie--;
|
||||
}
|
||||
if (invoke_bpf_prog(tjit, m, tn->nodes[i], save_ret))
|
||||
if (invoke_bpf_prog(tjit, im, m, tn->nodes[i], save_ret))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -2712,6 +2732,11 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
u64 func_meta;
|
||||
int i, j;
|
||||
|
||||
/* The skip labels are taken from the previous pass. */
|
||||
tjit->nr_progs = 0;
|
||||
if (im)
|
||||
im->nr_skips = 0;
|
||||
|
||||
/* Support as many stack arguments as "mvc" instruction can handle. */
|
||||
nr_reg_args = min_t(int, m->nr_args, MAX_NR_REG_ARGS);
|
||||
nr_stack_args = m->nr_args - nr_reg_args;
|
||||
|
|
@ -2875,7 +2900,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
emit_store_stack_imm64(jit, REG_0, tjit->retval_off, 0);
|
||||
}
|
||||
|
||||
if (invoke_bpf(tjit, m, fentry, flags & BPF_TRAMP_F_RET_FENTRY_RET,
|
||||
if (invoke_bpf(tjit, im, m, fentry, flags & BPF_TRAMP_F_RET_FENTRY_RET,
|
||||
func_meta, cookie_off))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -2889,7 +2914,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
0xf000 | tjit->retval_off);
|
||||
|
||||
for (i = 0; i < fmod_ret->nr_nodes; i++) {
|
||||
if (invoke_bpf_prog(tjit, m, fmod_ret->nodes[i], true))
|
||||
if (invoke_bpf_prog(tjit, im, m, fmod_ret->nodes[i], true))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
|
@ -2943,15 +2968,6 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
/* mvc tccnt_off(%r15),tail_call_cnt(4,%r15) */
|
||||
_EMIT6(0xd203f000 | tjit->tccnt_off,
|
||||
0xf000 | offsetof(struct prog_frame, tail_call_cnt));
|
||||
|
||||
im->ip_after_call = jit->prg_buf + jit->prg;
|
||||
|
||||
/*
|
||||
* The following nop will be patched by bpf_tramp_image_put().
|
||||
*/
|
||||
|
||||
/* brcl 0,im->ip_epilogue */
|
||||
EMIT6_PCREL_RILC(0xc0040000, 0, (u64)im->ip_epilogue);
|
||||
}
|
||||
|
||||
/* Set the "is_return" flag for fsession. */
|
||||
|
|
@ -2962,12 +2978,10 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
|
||||
/* do_fexit: */
|
||||
tjit->do_fexit = jit->prg;
|
||||
if (invoke_bpf(tjit, m, fexit, false, func_meta, cookie_off))
|
||||
if (invoke_bpf(tjit, im, m, fexit, false, func_meta, cookie_off))
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & BPF_TRAMP_F_CALL_ORIG) {
|
||||
im->ip_epilogue = jit->prg_buf + jit->prg;
|
||||
|
||||
/*
|
||||
* __bpf_tramp_exit(im);
|
||||
*/
|
||||
|
|
@ -3016,7 +3030,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
|
|||
int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags,
|
||||
struct bpf_tramp_nodes *tnodes, void *orig_call)
|
||||
{
|
||||
struct bpf_tramp_image im;
|
||||
struct bpf_tramp_image im = {};
|
||||
struct bpf_tramp_jit tjit;
|
||||
int ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ vobjs-$(CONFIG_X86_SGX) += vsgx.o
|
|||
vobjs-$(CONFIG_FUTEX_ROBUST_UNLOCK) += vfutex.o
|
||||
|
||||
# Compilation flags
|
||||
flags-y := -DBUILD_VDSO64 -m64 -mcmodel=small
|
||||
flags-y := -DBUILD_VDSO64 -m64 -mcmodel=small $(CONFIG_CC_OPT_INLINE_MEMSET)
|
||||
|
||||
# The location of this include matters!
|
||||
include $(src)/../common/Makefile.include
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user