mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.0-rc5). net/netfilter/nft_set_rbtree.c598adea720("netfilter: revert nft_set_rbtree: validate open interval overlap")3aea466a43("netfilter: nft_set_rbtree: don't disable bh when acquiring tree lock") https://lore.kernel.org/abgaQBpeGstdN4oq@sirena.org.uk No adjacent changes. Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
1
.mailmap
1
.mailmap
@@ -327,6 +327,7 @@ Henrik Rydberg <rydberg@bitmath.org>
|
||||
Herbert Xu <herbert@gondor.apana.org.au>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhc@lemote.com>
|
||||
Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
|
||||
Ignat Korchagin <ignat@linux.win> <ignat@cloudflare.com>
|
||||
Ike Panhc <ikepanhc@gmail.com> <ike.pan@canonical.com>
|
||||
J. Bruce Fields <bfields@fieldses.org> <bfields@redhat.com>
|
||||
J. Bruce Fields <bfields@fieldses.org> <bfields@citi.umich.edu>
|
||||
|
||||
@@ -8196,6 +8196,9 @@ Kernel parameters
|
||||
p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT
|
||||
(Reduce timeout of the SET_ADDRESS
|
||||
request from 5000 ms to 500 ms);
|
||||
q = USB_QUIRK_FORCE_ONE_CONFIG (Device
|
||||
claims zero configurations,
|
||||
forcing to 1);
|
||||
Example: quirks=0781:5580:bk,0a5c:5834:gij
|
||||
|
||||
usbhid.mousepoll=
|
||||
|
||||
@@ -336,6 +336,8 @@ command line arguments:
|
||||
- ``--list_tests_attr``: If set, lists all tests that will be run and all of their
|
||||
attributes.
|
||||
|
||||
- ``--list_suites``: If set, lists all suites that will be run.
|
||||
|
||||
Command-line completion
|
||||
==============================
|
||||
|
||||
|
||||
@@ -253,7 +253,6 @@ allOf:
|
||||
enum:
|
||||
# these platforms support 2 streams MST on some interfaces,
|
||||
# others are SST only
|
||||
- qcom,glymur-dp
|
||||
- qcom,sc8280xp-dp
|
||||
- qcom,x1e80100-dp
|
||||
then:
|
||||
@@ -310,6 +309,26 @@ allOf:
|
||||
minItems: 6
|
||||
maxItems: 8
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
# these platforms support 2 streams MST on some interfaces,
|
||||
# others are SST only, but all controllers have 4 ports
|
||||
- qcom,glymur-dp
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 9
|
||||
maxItems: 9
|
||||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
clocks-names:
|
||||
minItems: 5
|
||||
maxItems: 6
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -176,13 +176,17 @@ examples:
|
||||
};
|
||||
};
|
||||
|
||||
displayport-controller@ae90000 {
|
||||
displayport-controller@af54000 {
|
||||
compatible = "qcom,glymur-dp";
|
||||
reg = <0xae90000 0x200>,
|
||||
<0xae90200 0x200>,
|
||||
<0xae90400 0x600>,
|
||||
<0xae91000 0x400>,
|
||||
<0xae91400 0x400>;
|
||||
reg = <0xaf54000 0x200>,
|
||||
<0xaf54200 0x200>,
|
||||
<0xaf55000 0xc00>,
|
||||
<0xaf56000 0x400>,
|
||||
<0xaf57000 0x400>,
|
||||
<0xaf58000 0x400>,
|
||||
<0xaf59000 0x400>,
|
||||
<0xaf5a000 0x600>,
|
||||
<0xaf5b000 0x600>;
|
||||
|
||||
interrupt-parent = <&mdss>;
|
||||
interrupts = <12>;
|
||||
|
||||
@@ -10,7 +10,7 @@ maintainers:
|
||||
- Krzysztof Kozlowski <krzk@kernel.org>
|
||||
|
||||
description:
|
||||
SM8650 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like
|
||||
SM8750 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like
|
||||
DPU display controller, DSI and DP interfaces etc.
|
||||
|
||||
$ref: /schemas/display/msm/mdss-common.yaml#
|
||||
|
||||
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Synopsys DesignWare APB I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Jarkko Nikula <jarkko.nikula@linux.intel.com>
|
||||
- Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
@@ -6,9 +6,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Allwinner A31 SPI Controller
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
@@ -82,11 +79,11 @@ patternProperties:
|
||||
|
||||
spi-rx-bus-width:
|
||||
items:
|
||||
- const: 1
|
||||
enum: [0, 1, 2, 4]
|
||||
|
||||
spi-tx-bus-width:
|
||||
items:
|
||||
- const: 1
|
||||
enum: [0, 1, 2, 4]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
@@ -95,6 +92,28 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- allwinner,sun50i-r329-spi
|
||||
- allwinner,sun55i-a523-spi
|
||||
then:
|
||||
patternProperties:
|
||||
"^.*@[0-9a-f]+":
|
||||
properties:
|
||||
spi-rx-bus-width:
|
||||
items:
|
||||
enum: [0, 1]
|
||||
|
||||
spi-tx-bus-width:
|
||||
items:
|
||||
enum: [0, 1]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -247,8 +247,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes:
|
||||
- ifindex
|
||||
@@ -278,8 +278,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes: *ns-binding
|
||||
|
||||
@@ -309,8 +309,8 @@ operations:
|
||||
flags: [admin-perm]
|
||||
|
||||
do:
|
||||
pre: net-shaper-nl-pre-doit
|
||||
post: net-shaper-nl-post-doit
|
||||
pre: net-shaper-nl-pre-doit-write
|
||||
post: net-shaper-nl-post-doit-write
|
||||
request:
|
||||
attributes:
|
||||
- ifindex
|
||||
|
||||
@@ -43,7 +43,6 @@ options should be enabled to use sched_ext:
|
||||
CONFIG_DEBUG_INFO_BTF=y
|
||||
CONFIG_BPF_JIT_ALWAYS_ON=y
|
||||
CONFIG_BPF_JIT_DEFAULT_ON=y
|
||||
CONFIG_PAHOLE_HAS_BTF_TAG=y
|
||||
|
||||
sched_ext is used only when the BPF scheduler is loaded and running.
|
||||
|
||||
@@ -58,7 +57,8 @@ in ``ops->flags``, all ``SCHED_NORMAL``, ``SCHED_BATCH``, ``SCHED_IDLE``, and
|
||||
However, when the BPF scheduler is loaded and ``SCX_OPS_SWITCH_PARTIAL`` is
|
||||
set in ``ops->flags``, only tasks with the ``SCHED_EXT`` policy are scheduled
|
||||
by sched_ext, while tasks with ``SCHED_NORMAL``, ``SCHED_BATCH`` and
|
||||
``SCHED_IDLE`` policies are scheduled by the fair-class scheduler.
|
||||
``SCHED_IDLE`` policies are scheduled by the fair-class scheduler which has
|
||||
higher sched_class precedence than ``SCHED_EXT``.
|
||||
|
||||
Terminating the sched_ext scheduler program, triggering `SysRq-S`, or
|
||||
detection of any internal error including stalled runnable tasks aborts the
|
||||
@@ -345,6 +345,8 @@ Where to Look
|
||||
The functions prefixed with ``scx_bpf_`` can be called from the BPF
|
||||
scheduler.
|
||||
|
||||
* ``kernel/sched/ext_idle.c`` contains the built-in idle CPU selection policy.
|
||||
|
||||
* ``tools/sched_ext/`` hosts example BPF scheduler implementations.
|
||||
|
||||
* ``scx_simple[.bpf].c``: Minimal global FIFO scheduler example using a
|
||||
@@ -353,13 +355,35 @@ Where to Look
|
||||
* ``scx_qmap[.bpf].c``: A multi-level FIFO scheduler supporting five
|
||||
levels of priority implemented with ``BPF_MAP_TYPE_QUEUE``.
|
||||
|
||||
* ``scx_central[.bpf].c``: A central FIFO scheduler where all scheduling
|
||||
decisions are made on one CPU, demonstrating ``LOCAL_ON`` dispatching,
|
||||
tickless operation, and kthread preemption.
|
||||
|
||||
* ``scx_cpu0[.bpf].c``: A scheduler that queues all tasks to a shared DSQ
|
||||
and only dispatches them on CPU0 in FIFO order. Useful for testing bypass
|
||||
behavior.
|
||||
|
||||
* ``scx_flatcg[.bpf].c``: A flattened cgroup hierarchy scheduler
|
||||
implementing hierarchical weight-based cgroup CPU control by compounding
|
||||
each cgroup's share at every level into a single flat scheduling layer.
|
||||
|
||||
* ``scx_pair[.bpf].c``: A core-scheduling example that always makes
|
||||
sibling CPU pairs execute tasks from the same CPU cgroup.
|
||||
|
||||
* ``scx_sdt[.bpf].c``: A variation of ``scx_simple`` demonstrating BPF
|
||||
arena memory management for per-task data.
|
||||
|
||||
* ``scx_userland[.bpf].c``: A minimal scheduler demonstrating user space
|
||||
scheduling. Tasks with CPU affinity are direct-dispatched in FIFO order;
|
||||
all others are scheduled in user space by a simple vruntime scheduler.
|
||||
|
||||
ABI Instability
|
||||
===============
|
||||
|
||||
The APIs provided by sched_ext to BPF schedulers programs have no stability
|
||||
guarantees. This includes the ops table callbacks and constants defined in
|
||||
``include/linux/sched/ext.h``, as well as the ``scx_bpf_`` kfuncs defined in
|
||||
``kernel/sched/ext.c``.
|
||||
``kernel/sched/ext.c`` and ``kernel/sched/ext_idle.c``.
|
||||
|
||||
While we will attempt to provide a relatively stable API surface when
|
||||
possible, they are subject to change without warning between kernel
|
||||
|
||||
@@ -8435,115 +8435,123 @@ KVM_CHECK_EXTENSION.
|
||||
|
||||
The valid bits in cap.args[0] are:
|
||||
|
||||
=================================== ============================================
|
||||
KVM_X86_QUIRK_LINT0_REENABLED By default, the reset value for the LVT
|
||||
LINT0 register is 0x700 (APIC_MODE_EXTINT).
|
||||
When this quirk is disabled, the reset value
|
||||
is 0x10000 (APIC_LVT_MASKED).
|
||||
======================================== ================================================
|
||||
KVM_X86_QUIRK_LINT0_REENABLED By default, the reset value for the LVT
|
||||
LINT0 register is 0x700 (APIC_MODE_EXTINT).
|
||||
When this quirk is disabled, the reset value
|
||||
is 0x10000 (APIC_LVT_MASKED).
|
||||
|
||||
KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW on
|
||||
AMD CPUs to workaround buggy guest firmware
|
||||
that runs in perpetuity with CR0.CD, i.e.
|
||||
with caches in "no fill" mode.
|
||||
KVM_X86_QUIRK_CD_NW_CLEARED By default, KVM clears CR0.CD and CR0.NW on
|
||||
AMD CPUs to workaround buggy guest firmware
|
||||
that runs in perpetuity with CR0.CD, i.e.
|
||||
with caches in "no fill" mode.
|
||||
|
||||
When this quirk is disabled, KVM does not
|
||||
change the value of CR0.CD and CR0.NW.
|
||||
When this quirk is disabled, KVM does not
|
||||
change the value of CR0.CD and CR0.NW.
|
||||
|
||||
KVM_X86_QUIRK_LAPIC_MMIO_HOLE By default, the MMIO LAPIC interface is
|
||||
available even when configured for x2APIC
|
||||
mode. When this quirk is disabled, KVM
|
||||
disables the MMIO LAPIC interface if the
|
||||
LAPIC is in x2APIC mode.
|
||||
KVM_X86_QUIRK_LAPIC_MMIO_HOLE By default, the MMIO LAPIC interface is
|
||||
available even when configured for x2APIC
|
||||
mode. When this quirk is disabled, KVM
|
||||
disables the MMIO LAPIC interface if the
|
||||
LAPIC is in x2APIC mode.
|
||||
|
||||
KVM_X86_QUIRK_OUT_7E_INC_RIP By default, KVM pre-increments %rip before
|
||||
exiting to userspace for an OUT instruction
|
||||
to port 0x7e. When this quirk is disabled,
|
||||
KVM does not pre-increment %rip before
|
||||
exiting to userspace.
|
||||
KVM_X86_QUIRK_OUT_7E_INC_RIP By default, KVM pre-increments %rip before
|
||||
exiting to userspace for an OUT instruction
|
||||
to port 0x7e. When this quirk is disabled,
|
||||
KVM does not pre-increment %rip before
|
||||
exiting to userspace.
|
||||
|
||||
KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT When this quirk is disabled, KVM sets
|
||||
CPUID.01H:ECX[bit 3] (MONITOR/MWAIT) if
|
||||
IA32_MISC_ENABLE[bit 18] (MWAIT) is set.
|
||||
Additionally, when this quirk is disabled,
|
||||
KVM clears CPUID.01H:ECX[bit 3] if
|
||||
IA32_MISC_ENABLE[bit 18] is cleared.
|
||||
KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT When this quirk is disabled, KVM sets
|
||||
CPUID.01H:ECX[bit 3] (MONITOR/MWAIT) if
|
||||
IA32_MISC_ENABLE[bit 18] (MWAIT) is set.
|
||||
Additionally, when this quirk is disabled,
|
||||
KVM clears CPUID.01H:ECX[bit 3] if
|
||||
IA32_MISC_ENABLE[bit 18] is cleared.
|
||||
|
||||
KVM_X86_QUIRK_FIX_HYPERCALL_INSN By default, KVM rewrites guest
|
||||
VMMCALL/VMCALL instructions to match the
|
||||
vendor's hypercall instruction for the
|
||||
system. When this quirk is disabled, KVM
|
||||
will no longer rewrite invalid guest
|
||||
hypercall instructions. Executing the
|
||||
incorrect hypercall instruction will
|
||||
generate a #UD within the guest.
|
||||
KVM_X86_QUIRK_FIX_HYPERCALL_INSN By default, KVM rewrites guest
|
||||
VMMCALL/VMCALL instructions to match the
|
||||
vendor's hypercall instruction for the
|
||||
system. When this quirk is disabled, KVM
|
||||
will no longer rewrite invalid guest
|
||||
hypercall instructions. Executing the
|
||||
incorrect hypercall instruction will
|
||||
generate a #UD within the guest.
|
||||
|
||||
KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS By default, KVM emulates MONITOR/MWAIT (if
|
||||
they are intercepted) as NOPs regardless of
|
||||
whether or not MONITOR/MWAIT are supported
|
||||
according to guest CPUID. When this quirk
|
||||
is disabled and KVM_X86_DISABLE_EXITS_MWAIT
|
||||
is not set (MONITOR/MWAIT are intercepted),
|
||||
KVM will inject a #UD on MONITOR/MWAIT if
|
||||
they're unsupported per guest CPUID. Note,
|
||||
KVM will modify MONITOR/MWAIT support in
|
||||
guest CPUID on writes to MISC_ENABLE if
|
||||
KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is
|
||||
disabled.
|
||||
KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS By default, KVM emulates MONITOR/MWAIT (if
|
||||
they are intercepted) as NOPs regardless of
|
||||
whether or not MONITOR/MWAIT are supported
|
||||
according to guest CPUID. When this quirk
|
||||
is disabled and KVM_X86_DISABLE_EXITS_MWAIT
|
||||
is not set (MONITOR/MWAIT are intercepted),
|
||||
KVM will inject a #UD on MONITOR/MWAIT if
|
||||
they're unsupported per guest CPUID. Note,
|
||||
KVM will modify MONITOR/MWAIT support in
|
||||
guest CPUID on writes to MISC_ENABLE if
|
||||
KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is
|
||||
disabled.
|
||||
|
||||
KVM_X86_QUIRK_SLOT_ZAP_ALL By default, for KVM_X86_DEFAULT_VM VMs, KVM
|
||||
invalidates all SPTEs in all memslots and
|
||||
address spaces when a memslot is deleted or
|
||||
moved. When this quirk is disabled (or the
|
||||
VM type isn't KVM_X86_DEFAULT_VM), KVM only
|
||||
ensures the backing memory of the deleted
|
||||
or moved memslot isn't reachable, i.e KVM
|
||||
_may_ invalidate only SPTEs related to the
|
||||
memslot.
|
||||
KVM_X86_QUIRK_SLOT_ZAP_ALL By default, for KVM_X86_DEFAULT_VM VMs, KVM
|
||||
invalidates all SPTEs in all memslots and
|
||||
address spaces when a memslot is deleted or
|
||||
moved. When this quirk is disabled (or the
|
||||
VM type isn't KVM_X86_DEFAULT_VM), KVM only
|
||||
ensures the backing memory of the deleted
|
||||
or moved memslot isn't reachable, i.e KVM
|
||||
_may_ invalidate only SPTEs related to the
|
||||
memslot.
|
||||
|
||||
KVM_X86_QUIRK_STUFF_FEATURE_MSRS By default, at vCPU creation, KVM sets the
|
||||
vCPU's MSR_IA32_PERF_CAPABILITIES (0x345),
|
||||
MSR_IA32_ARCH_CAPABILITIES (0x10a),
|
||||
MSR_PLATFORM_INFO (0xce), and all VMX MSRs
|
||||
(0x480..0x492) to the maximal capabilities
|
||||
supported by KVM. KVM also sets
|
||||
MSR_IA32_UCODE_REV (0x8b) to an arbitrary
|
||||
value (which is different for Intel vs.
|
||||
AMD). Lastly, when guest CPUID is set (by
|
||||
userspace), KVM modifies select VMX MSR
|
||||
fields to force consistency between guest
|
||||
CPUID and L2's effective ISA. When this
|
||||
quirk is disabled, KVM zeroes the vCPU's MSR
|
||||
values (with two exceptions, see below),
|
||||
i.e. treats the feature MSRs like CPUID
|
||||
leaves and gives userspace full control of
|
||||
the vCPU model definition. This quirk does
|
||||
not affect VMX MSRs CR0/CR4_FIXED1 (0x487
|
||||
and 0x489), as KVM does now allow them to
|
||||
be set by userspace (KVM sets them based on
|
||||
guest CPUID, for safety purposes).
|
||||
KVM_X86_QUIRK_STUFF_FEATURE_MSRS By default, at vCPU creation, KVM sets the
|
||||
vCPU's MSR_IA32_PERF_CAPABILITIES (0x345),
|
||||
MSR_IA32_ARCH_CAPABILITIES (0x10a),
|
||||
MSR_PLATFORM_INFO (0xce), and all VMX MSRs
|
||||
(0x480..0x492) to the maximal capabilities
|
||||
supported by KVM. KVM also sets
|
||||
MSR_IA32_UCODE_REV (0x8b) to an arbitrary
|
||||
value (which is different for Intel vs.
|
||||
AMD). Lastly, when guest CPUID is set (by
|
||||
userspace), KVM modifies select VMX MSR
|
||||
fields to force consistency between guest
|
||||
CPUID and L2's effective ISA. When this
|
||||
quirk is disabled, KVM zeroes the vCPU's MSR
|
||||
values (with two exceptions, see below),
|
||||
i.e. treats the feature MSRs like CPUID
|
||||
leaves and gives userspace full control of
|
||||
the vCPU model definition. This quirk does
|
||||
not affect VMX MSRs CR0/CR4_FIXED1 (0x487
|
||||
and 0x489), as KVM does now allow them to
|
||||
be set by userspace (KVM sets them based on
|
||||
guest CPUID, for safety purposes).
|
||||
|
||||
KVM_X86_QUIRK_IGNORE_GUEST_PAT By default, on Intel platforms, KVM ignores
|
||||
guest PAT and forces the effective memory
|
||||
type to WB in EPT. The quirk is not available
|
||||
on Intel platforms which are incapable of
|
||||
safely honoring guest PAT (i.e., without CPU
|
||||
self-snoop, KVM always ignores guest PAT and
|
||||
forces effective memory type to WB). It is
|
||||
also ignored on AMD platforms or, on Intel,
|
||||
when a VM has non-coherent DMA devices
|
||||
assigned; KVM always honors guest PAT in
|
||||
such case. The quirk is needed to avoid
|
||||
slowdowns on certain Intel Xeon platforms
|
||||
(e.g. ICX, SPR) where self-snoop feature is
|
||||
supported but UC is slow enough to cause
|
||||
issues with some older guests that use
|
||||
UC instead of WC to map the video RAM.
|
||||
Userspace can disable the quirk to honor
|
||||
guest PAT if it knows that there is no such
|
||||
guest software, for example if it does not
|
||||
expose a bochs graphics device (which is
|
||||
known to have had a buggy driver).
|
||||
=================================== ============================================
|
||||
KVM_X86_QUIRK_IGNORE_GUEST_PAT By default, on Intel platforms, KVM ignores
|
||||
guest PAT and forces the effective memory
|
||||
type to WB in EPT. The quirk is not available
|
||||
on Intel platforms which are incapable of
|
||||
safely honoring guest PAT (i.e., without CPU
|
||||
self-snoop, KVM always ignores guest PAT and
|
||||
forces effective memory type to WB). It is
|
||||
also ignored on AMD platforms or, on Intel,
|
||||
when a VM has non-coherent DMA devices
|
||||
assigned; KVM always honors guest PAT in
|
||||
such case. The quirk is needed to avoid
|
||||
slowdowns on certain Intel Xeon platforms
|
||||
(e.g. ICX, SPR) where self-snoop feature is
|
||||
supported but UC is slow enough to cause
|
||||
issues with some older guests that use
|
||||
UC instead of WC to map the video RAM.
|
||||
Userspace can disable the quirk to honor
|
||||
guest PAT if it knows that there is no such
|
||||
guest software, for example if it does not
|
||||
expose a bochs graphics device (which is
|
||||
known to have had a buggy driver).
|
||||
|
||||
KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM By default, KVM relaxes the consistency
|
||||
check for GUEST_IA32_DEBUGCTL in vmcs12
|
||||
to allow FREEZE_IN_SMM to be set. When
|
||||
this quirk is disabled, KVM requires this
|
||||
bit to be cleared. Note that the vmcs02
|
||||
bit is still completely controlled by the
|
||||
host, regardless of the quirk setting.
|
||||
======================================== ================================================
|
||||
|
||||
7.32 KVM_CAP_MAX_VCPU_ID
|
||||
------------------------
|
||||
|
||||
@@ -17,6 +17,8 @@ The acquisition orders for mutexes are as follows:
|
||||
|
||||
- kvm->lock is taken outside kvm->slots_lock and kvm->irq_lock
|
||||
|
||||
- vcpu->mutex is taken outside kvm->slots_lock and kvm->slots_arch_lock
|
||||
|
||||
- kvm->slots_lock is taken outside kvm->irq_lock, though acquiring
|
||||
them together is quite rare.
|
||||
|
||||
|
||||
13
MAINTAINERS
13
MAINTAINERS
@@ -4022,7 +4022,7 @@ F: drivers/hwmon/asus_wmi_sensors.c
|
||||
ASYMMETRIC KEYS
|
||||
M: David Howells <dhowells@redhat.com>
|
||||
M: Lukas Wunner <lukas@wunner.de>
|
||||
M: Ignat Korchagin <ignat@cloudflare.com>
|
||||
M: Ignat Korchagin <ignat@linux.win>
|
||||
L: keyrings@vger.kernel.org
|
||||
L: linux-crypto@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -4035,7 +4035,7 @@ F: include/linux/verification.h
|
||||
|
||||
ASYMMETRIC KEYS - ECDSA
|
||||
M: Lukas Wunner <lukas@wunner.de>
|
||||
M: Ignat Korchagin <ignat@cloudflare.com>
|
||||
M: Ignat Korchagin <ignat@linux.win>
|
||||
R: Stefan Berger <stefanb@linux.ibm.com>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -4045,14 +4045,14 @@ F: include/crypto/ecc*
|
||||
|
||||
ASYMMETRIC KEYS - GOST
|
||||
M: Lukas Wunner <lukas@wunner.de>
|
||||
M: Ignat Korchagin <ignat@cloudflare.com>
|
||||
M: Ignat Korchagin <ignat@linux.win>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
S: Odd fixes
|
||||
F: crypto/ecrdsa*
|
||||
|
||||
ASYMMETRIC KEYS - RSA
|
||||
M: Lukas Wunner <lukas@wunner.de>
|
||||
M: Ignat Korchagin <ignat@cloudflare.com>
|
||||
M: Ignat Korchagin <ignat@linux.win>
|
||||
L: linux-crypto@vger.kernel.org
|
||||
S: Maintained
|
||||
F: crypto/rsa*
|
||||
@@ -8626,9 +8626,8 @@ F: drivers/gpu/drm/lima/
|
||||
F: include/uapi/drm/lima_drm.h
|
||||
|
||||
DRM DRIVERS FOR LOONGSON
|
||||
M: Sui Jingfeng <suijingfeng@loongson.cn>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Supported
|
||||
S: Orphan
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
F: drivers/gpu/drm/loongson/
|
||||
|
||||
@@ -21935,7 +21934,7 @@ F: drivers/media/radio/radio-tea5777.c
|
||||
|
||||
RADOS BLOCK DEVICE (RBD)
|
||||
M: Ilya Dryomov <idryomov@gmail.com>
|
||||
R: Dongsheng Yang <dongsheng.yang@easystack.cn>
|
||||
R: Dongsheng Yang <dongsheng.yang@linux.dev>
|
||||
L: ceph-devel@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://ceph.com/
|
||||
|
||||
6
Makefile
6
Makefile
@@ -2,7 +2,7 @@
|
||||
VERSION = 7
|
||||
PATCHLEVEL = 0
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc4
|
||||
NAME = Baby Opossum Posse
|
||||
|
||||
# *DOCUMENTATION*
|
||||
@@ -476,6 +476,7 @@ KBUILD_USERLDFLAGS := $(USERLDFLAGS)
|
||||
export rust_common_flags := --edition=2021 \
|
||||
-Zbinary_dep_depinfo=y \
|
||||
-Astable_features \
|
||||
-Aunused_features \
|
||||
-Dnon_ascii_idents \
|
||||
-Dunsafe_op_in_unsafe_fn \
|
||||
-Wmissing_docs \
|
||||
@@ -1113,6 +1114,9 @@ KBUILD_CFLAGS += -fno-builtin-wcslen
|
||||
# change __FILE__ to the relative path to the source directory
|
||||
ifdef building_out_of_srctree
|
||||
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
|
||||
ifeq ($(call rustc-option-yn, --remap-path-scope=macro),y)
|
||||
KBUILD_RUSTFLAGS += --remap-path-prefix=$(srcroot)/= --remap-path-scope=macro
|
||||
endif
|
||||
endif
|
||||
|
||||
# include additional Makefiles when needed
|
||||
|
||||
@@ -279,7 +279,6 @@ CONFIG_TI_CPSW_SWITCHDEV=y
|
||||
CONFIG_TI_CPTS=y
|
||||
CONFIG_TI_KEYSTONE_NETCP=y
|
||||
CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
|
||||
CONFIG_TI_PRUSS=m
|
||||
CONFIG_TI_PRUETH=m
|
||||
CONFIG_XILINX_EMACLITE=y
|
||||
CONFIG_SFP=m
|
||||
|
||||
@@ -698,7 +698,7 @@
|
||||
compatible = "renesas,scif-r8a78000",
|
||||
"renesas,rcar-gen5-scif", "renesas,scif";
|
||||
reg = <0 0xc0700000 0 0x40>;
|
||||
interrupts = <GIC_SPI 4074 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -708,7 +708,7 @@
|
||||
compatible = "renesas,scif-r8a78000",
|
||||
"renesas,rcar-gen5-scif", "renesas,scif";
|
||||
reg = <0 0xc0704000 0 0x40>;
|
||||
interrupts = <GIC_SPI 4075 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -718,7 +718,7 @@
|
||||
compatible = "renesas,scif-r8a78000",
|
||||
"renesas,rcar-gen5-scif", "renesas,scif";
|
||||
reg = <0 0xc0708000 0 0x40>;
|
||||
interrupts = <GIC_SPI 4076 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 12 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -728,7 +728,7 @@
|
||||
compatible = "renesas,scif-r8a78000",
|
||||
"renesas,rcar-gen5-scif", "renesas,scif";
|
||||
reg = <0 0xc070c000 0 0x40>;
|
||||
interrupts = <GIC_SPI 4077 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 13 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd16>, <&dummy_clk_sgasyncd16>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -738,7 +738,7 @@
|
||||
compatible = "renesas,hscif-r8a78000",
|
||||
"renesas,rcar-gen5-hscif", "renesas,hscif";
|
||||
reg = <0 0xc0710000 0 0x60>;
|
||||
interrupts = <GIC_SPI 4078 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 14 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -748,7 +748,7 @@
|
||||
compatible = "renesas,hscif-r8a78000",
|
||||
"renesas,rcar-gen5-hscif", "renesas,hscif";
|
||||
reg = <0 0xc0714000 0 0x60>;
|
||||
interrupts = <GIC_SPI 4079 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 15 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -758,7 +758,7 @@
|
||||
compatible = "renesas,hscif-r8a78000",
|
||||
"renesas,rcar-gen5-hscif", "renesas,hscif";
|
||||
reg = <0 0xc0718000 0 0x60>;
|
||||
interrupts = <GIC_SPI 4080 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 16 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
@@ -768,7 +768,7 @@
|
||||
compatible = "renesas,hscif-r8a78000",
|
||||
"renesas,rcar-gen5-hscif", "renesas,hscif";
|
||||
reg = <0 0xc071c000 0 0x60>;
|
||||
interrupts = <GIC_SPI 4081 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <GIC_ESPI 17 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&dummy_clk_sgasyncd4>, <&dummy_clk_sgasyncd4>, <&scif_clk>;
|
||||
clock-names = "fck", "brg_int", "scif_clk";
|
||||
status = "disabled";
|
||||
|
||||
@@ -581,16 +581,6 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
wdt0: watchdog@11c00400 {
|
||||
compatible = "renesas,r9a09g057-wdt";
|
||||
reg = <0 0x11c00400 0 0x400>;
|
||||
clocks = <&cpg CPG_MOD 0x4b>, <&cpg CPG_MOD 0x4c>;
|
||||
clock-names = "pclk", "oscclk";
|
||||
resets = <&cpg 0x75>;
|
||||
power-domains = <&cpg>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
wdt1: watchdog@14400000 {
|
||||
compatible = "renesas,r9a09g057-wdt";
|
||||
reg = <0 0x14400000 0 0x400>;
|
||||
@@ -601,26 +591,6 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
wdt2: watchdog@13000000 {
|
||||
compatible = "renesas,r9a09g057-wdt";
|
||||
reg = <0 0x13000000 0 0x400>;
|
||||
clocks = <&cpg CPG_MOD 0x4f>, <&cpg CPG_MOD 0x50>;
|
||||
clock-names = "pclk", "oscclk";
|
||||
resets = <&cpg 0x77>;
|
||||
power-domains = <&cpg>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
wdt3: watchdog@13000400 {
|
||||
compatible = "renesas,r9a09g057-wdt";
|
||||
reg = <0 0x13000400 0 0x400>;
|
||||
clocks = <&cpg CPG_MOD 0x51>, <&cpg CPG_MOD 0x52>;
|
||||
clock-names = "pclk", "oscclk";
|
||||
resets = <&cpg 0x78>;
|
||||
power-domains = <&cpg>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
rtc: rtc@11c00800 {
|
||||
compatible = "renesas,r9a09g057-rtca3", "renesas,rz-rtca3";
|
||||
reg = <0 0x11c00800 0 0x400>;
|
||||
|
||||
@@ -974,8 +974,8 @@
|
||||
|
||||
cpg: clock-controller@80280000 {
|
||||
compatible = "renesas,r9a09g077-cpg-mssr";
|
||||
reg = <0 0x80280000 0 0x1000>,
|
||||
<0 0x81280000 0 0x9000>;
|
||||
reg = <0 0x80280000 0 0x10000>,
|
||||
<0 0x81280000 0 0x10000>;
|
||||
clocks = <&extal_clk>;
|
||||
clock-names = "extal";
|
||||
#clock-cells = <2>;
|
||||
|
||||
@@ -977,8 +977,8 @@
|
||||
|
||||
cpg: clock-controller@80280000 {
|
||||
compatible = "renesas,r9a09g087-cpg-mssr";
|
||||
reg = <0 0x80280000 0 0x1000>,
|
||||
<0 0x81280000 0 0x9000>;
|
||||
reg = <0 0x80280000 0 0x10000>,
|
||||
<0 0x81280000 0 0x10000>;
|
||||
clocks = <&extal_clk>;
|
||||
clock-names = "extal";
|
||||
#clock-cells = <2>;
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
<100000000>;
|
||||
renesas,settings = [
|
||||
80 00 11 19 4c 42 dc 2f 06 7d 20 1a 5f 1e f2 27
|
||||
00 40 00 00 00 00 00 00 06 0c 19 02 3f f0 90 86
|
||||
00 40 00 00 00 00 00 00 06 0c 19 02 3b f0 90 86
|
||||
a0 80 30 30 9c
|
||||
];
|
||||
};
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpios-states = <0>;
|
||||
states = <3300000 0>, <1800000 1>;
|
||||
regulator-ramp-delay = <60>;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpios-states = <0>;
|
||||
states = <3300000 0>, <1800000 1>;
|
||||
regulator-ramp-delay = <60>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -76,19 +76,24 @@ static int aesbs_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct aesbs_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct crypto_aes_ctx rk;
|
||||
struct crypto_aes_ctx *rk;
|
||||
int err;
|
||||
|
||||
err = aes_expandkey(&rk, in_key, key_len);
|
||||
rk = kmalloc(sizeof(*rk), GFP_KERNEL);
|
||||
if (!rk)
|
||||
return -ENOMEM;
|
||||
|
||||
err = aes_expandkey(rk, in_key, key_len);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
ctx->rounds = 6 + key_len / 4;
|
||||
|
||||
scoped_ksimd()
|
||||
aesbs_convert_key(ctx->rk, rk.key_enc, ctx->rounds);
|
||||
|
||||
return 0;
|
||||
aesbs_convert_key(ctx->rk, rk->key_enc, ctx->rounds);
|
||||
out:
|
||||
kfree_sensitive(rk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __ecb_crypt(struct skcipher_request *req,
|
||||
@@ -133,22 +138,26 @@ static int aesbs_cbc_ctr_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct aesbs_cbc_ctr_ctx *ctx = crypto_skcipher_ctx(tfm);
|
||||
struct crypto_aes_ctx rk;
|
||||
struct crypto_aes_ctx *rk;
|
||||
int err;
|
||||
|
||||
err = aes_expandkey(&rk, in_key, key_len);
|
||||
rk = kmalloc(sizeof(*rk), GFP_KERNEL);
|
||||
if (!rk)
|
||||
return -ENOMEM;
|
||||
|
||||
err = aes_expandkey(rk, in_key, key_len);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
ctx->key.rounds = 6 + key_len / 4;
|
||||
|
||||
memcpy(ctx->enc, rk.key_enc, sizeof(ctx->enc));
|
||||
memcpy(ctx->enc, rk->key_enc, sizeof(ctx->enc));
|
||||
|
||||
scoped_ksimd()
|
||||
aesbs_convert_key(ctx->key.rk, rk.key_enc, ctx->key.rounds);
|
||||
memzero_explicit(&rk, sizeof(rk));
|
||||
|
||||
return 0;
|
||||
aesbs_convert_key(ctx->key.rk, rk->key_enc, ctx->key.rounds);
|
||||
out:
|
||||
kfree_sensitive(rk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cbc_encrypt(struct skcipher_request *req)
|
||||
|
||||
@@ -784,6 +784,9 @@ struct kvm_host_data {
|
||||
/* Number of debug breakpoints/watchpoints for this CPU (minus 1) */
|
||||
unsigned int debug_brps;
|
||||
unsigned int debug_wrps;
|
||||
|
||||
/* Last vgic_irq part of the AP list recorded in an LR */
|
||||
struct vgic_irq *last_lr_irq;
|
||||
};
|
||||
|
||||
struct kvm_host_psci_config {
|
||||
|
||||
@@ -2345,6 +2345,15 @@ static bool can_trap_icv_dir_el1(const struct arm64_cpu_capabilities *entry,
|
||||
!is_midr_in_range_list(has_vgic_v3))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* pKVM prevents late onlining of CPUs. This means that whatever
|
||||
* state the capability is in after deprivilege cannot be affected
|
||||
* by a new CPU booting -- this is garanteed to be a CPU we have
|
||||
* already seen, and the cap is therefore unchanged.
|
||||
*/
|
||||
if (system_capabilities_finalized() && is_protected_kvm_enabled())
|
||||
return cpus_have_final_cap(ARM64_HAS_ICH_HCR_EL2_TDIR);
|
||||
|
||||
if (is_kernel_in_hyp_mode())
|
||||
res.a1 = read_sysreg_s(SYS_ICH_VTR_EL2);
|
||||
else
|
||||
|
||||
@@ -1504,8 +1504,6 @@ int __kvm_at_s1e2(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
||||
fail = true;
|
||||
}
|
||||
|
||||
isb();
|
||||
|
||||
if (!fail)
|
||||
par = read_sysreg_par();
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS()
|
||||
};
|
||||
|
||||
@@ -42,7 +42,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, hvc_exit_stat),
|
||||
STATS_DESC_COUNTER(VCPU, wfe_exit_stat),
|
||||
|
||||
@@ -518,7 +518,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
|
||||
granule = kvm_granule_size(level);
|
||||
cur.start = ALIGN_DOWN(addr, granule);
|
||||
cur.end = cur.start + granule;
|
||||
if (!range_included(&cur, range))
|
||||
if (!range_included(&cur, range) && level < KVM_PGTABLE_LAST_LEVEL)
|
||||
continue;
|
||||
*range = cur;
|
||||
return 0;
|
||||
|
||||
@@ -1751,6 +1751,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
|
||||
force_pte = (max_map_size == PAGE_SIZE);
|
||||
vma_pagesize = min_t(long, vma_pagesize, max_map_size);
|
||||
vma_shift = __ffs(vma_pagesize);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1837,10 +1838,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
if (exec_fault && s2_force_noncacheable)
|
||||
ret = -ENOEXEC;
|
||||
|
||||
if (ret) {
|
||||
kvm_release_page_unused(page);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out_put_page;
|
||||
|
||||
/*
|
||||
* Guest performs atomic/exclusive operations on memory with unsupported
|
||||
@@ -1850,7 +1849,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
||||
*/
|
||||
if (esr_fsc_is_excl_atomic_fault(kvm_vcpu_get_esr(vcpu))) {
|
||||
kvm_inject_dabt_excl_atomic(vcpu, kvm_vcpu_get_hfar(vcpu));
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto out_put_page;
|
||||
}
|
||||
|
||||
if (nested)
|
||||
@@ -1936,6 +1936,10 @@ out_unlock:
|
||||
mark_page_dirty_in_slot(kvm, memslot, gfn);
|
||||
|
||||
return ret != -EAGAIN ? ret : 0;
|
||||
|
||||
out_put_page:
|
||||
kvm_release_page_unused(page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Resolve the access fault by making the page young again. */
|
||||
|
||||
@@ -152,31 +152,31 @@ static int get_ia_size(struct s2_walk_info *wi)
|
||||
return 64 - wi->t0sz;
|
||||
}
|
||||
|
||||
static int check_base_s2_limits(struct s2_walk_info *wi,
|
||||
static int check_base_s2_limits(struct kvm_vcpu *vcpu, struct s2_walk_info *wi,
|
||||
int level, int input_size, int stride)
|
||||
{
|
||||
int start_size, ia_size;
|
||||
int start_size, pa_max;
|
||||
|
||||
ia_size = get_ia_size(wi);
|
||||
pa_max = kvm_get_pa_bits(vcpu->kvm);
|
||||
|
||||
/* Check translation limits */
|
||||
switch (BIT(wi->pgshift)) {
|
||||
case SZ_64K:
|
||||
if (level == 0 || (level == 1 && ia_size <= 42))
|
||||
if (level == 0 || (level == 1 && pa_max <= 42))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case SZ_16K:
|
||||
if (level == 0 || (level == 1 && ia_size <= 40))
|
||||
if (level == 0 || (level == 1 && pa_max <= 40))
|
||||
return -EFAULT;
|
||||
break;
|
||||
case SZ_4K:
|
||||
if (level < 0 || (level == 0 && ia_size <= 42))
|
||||
if (level < 0 || (level == 0 && pa_max <= 42))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check input size limits */
|
||||
if (input_size > ia_size)
|
||||
if (input_size > pa_max)
|
||||
return -EFAULT;
|
||||
|
||||
/* Check number of entries in starting level table */
|
||||
@@ -269,16 +269,19 @@ static int walk_nested_s2_pgd(struct kvm_vcpu *vcpu, phys_addr_t ipa,
|
||||
if (input_size > 48 || input_size < 25)
|
||||
return -EFAULT;
|
||||
|
||||
ret = check_base_s2_limits(wi, level, input_size, stride);
|
||||
if (WARN_ON(ret))
|
||||
ret = check_base_s2_limits(vcpu, wi, level, input_size, stride);
|
||||
if (WARN_ON(ret)) {
|
||||
out->esr = compute_fsc(0, ESR_ELx_FSC_FAULT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
base_lower_bound = 3 + input_size - ((3 - level) * stride +
|
||||
wi->pgshift);
|
||||
base_addr = wi->baddr & GENMASK_ULL(47, base_lower_bound);
|
||||
|
||||
if (check_output_size(wi, base_addr)) {
|
||||
out->esr = compute_fsc(level, ESR_ELx_FSC_ADDRSZ);
|
||||
/* R_BFHQH */
|
||||
out->esr = compute_fsc(0, ESR_ELx_FSC_ADDRSZ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -293,8 +296,10 @@ static int walk_nested_s2_pgd(struct kvm_vcpu *vcpu, phys_addr_t ipa,
|
||||
|
||||
paddr = base_addr | index;
|
||||
ret = read_guest_s2_desc(vcpu, paddr, &desc, wi);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
out->esr = ESR_ELx_FSC_SEA_TTW(level);
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_desc = desc;
|
||||
|
||||
|
||||
@@ -143,23 +143,6 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
||||
kvm->arch.vgic.in_kernel = true;
|
||||
kvm->arch.vgic.vgic_model = type;
|
||||
kvm->arch.vgic.implementation_rev = KVM_VGIC_IMP_REV_LATEST;
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
ret = vgic_allocate_private_irqs_locked(vcpu, type);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
kfree(vgic_cpu->private_irqs);
|
||||
vgic_cpu->private_irqs = NULL;
|
||||
}
|
||||
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
|
||||
|
||||
aa64pfr0 = kvm_read_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1) & ~ID_AA64PFR0_EL1_GIC;
|
||||
@@ -176,6 +159,23 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
|
||||
kvm_set_vm_id_reg(kvm, SYS_ID_AA64PFR0_EL1, aa64pfr0);
|
||||
kvm_set_vm_id_reg(kvm, SYS_ID_PFR1_EL1, pfr1);
|
||||
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
ret = vgic_allocate_private_irqs_locked(vcpu, type);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
kvm_for_each_vcpu(i, vcpu, kvm) {
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
kfree(vgic_cpu->private_irqs);
|
||||
vgic_cpu->private_irqs = NULL;
|
||||
}
|
||||
|
||||
kvm->arch.vgic.vgic_model = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
kvm->arch.vgic.nassgicap = system_supports_direct_sgis();
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;
|
||||
u32 eoicount = FIELD_GET(GICH_HCR_EOICOUNT, cpuif->vgic_hcr);
|
||||
struct vgic_irq *irq;
|
||||
struct vgic_irq *irq = *host_data_ptr(last_lr_irq);
|
||||
|
||||
DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
|
||||
|
||||
@@ -123,7 +123,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
vgic_v2_fold_lr(vcpu, cpuif->vgic_lr[lr]);
|
||||
|
||||
/* See the GICv3 equivalent for the EOIcount handling rationale */
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
list_for_each_entry_continue(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
u32 lr;
|
||||
|
||||
if (!eoicount) {
|
||||
|
||||
@@ -148,7 +148,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
|
||||
u32 eoicount = FIELD_GET(ICH_HCR_EL2_EOIcount, cpuif->vgic_hcr);
|
||||
struct vgic_irq *irq;
|
||||
struct vgic_irq *irq = *host_data_ptr(last_lr_irq);
|
||||
|
||||
DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
|
||||
|
||||
@@ -158,12 +158,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
/*
|
||||
* EOIMode=0: use EOIcount to emulate deactivation. We are
|
||||
* guaranteed to deactivate in reverse order of the activation, so
|
||||
* just pick one active interrupt after the other in the ap_list,
|
||||
* and replay the deactivation as if the CPU was doing it. We also
|
||||
* rely on priority drop to have taken place, and the list to be
|
||||
* sorted by priority.
|
||||
* just pick one active interrupt after the other in the tail part
|
||||
* of the ap_list, past the LRs, and replay the deactivation as if
|
||||
* the CPU was doing it. We also rely on priority drop to have taken
|
||||
* place, and the list to be sorted by priority.
|
||||
*/
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
list_for_each_entry_continue(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
u64 lr;
|
||||
|
||||
/*
|
||||
|
||||
@@ -814,6 +814,9 @@ retry:
|
||||
|
||||
static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!*host_data_ptr(last_lr_irq))
|
||||
return;
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_fold_lr_state(vcpu);
|
||||
else
|
||||
@@ -960,10 +963,13 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
|
||||
if (irqs_outside_lrs(&als))
|
||||
vgic_sort_ap_list(vcpu);
|
||||
|
||||
*host_data_ptr(last_lr_irq) = NULL;
|
||||
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -304,6 +304,9 @@ config AS_HAS_LBT_EXTENSION
|
||||
config AS_HAS_LVZ_EXTENSION
|
||||
def_bool $(as-instr,hvcl 0)
|
||||
|
||||
config AS_HAS_SCQ_EXTENSION
|
||||
def_bool $(as-instr,sc.q \$t0$(comma)\$t1$(comma)\$t2)
|
||||
|
||||
config CC_HAS_ANNOTATE_TABLEJUMP
|
||||
def_bool $(cc-option,-mannotate-tablejump)
|
||||
|
||||
|
||||
@@ -238,6 +238,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, unsigned int
|
||||
arch_cmpxchg((ptr), (o), (n)); \
|
||||
})
|
||||
|
||||
#ifdef CONFIG_AS_HAS_SCQ_EXTENSION
|
||||
|
||||
union __u128_halves {
|
||||
u128 full;
|
||||
struct {
|
||||
@@ -290,6 +292,9 @@ union __u128_halves {
|
||||
BUILD_BUG_ON(sizeof(*(ptr)) != 16); \
|
||||
__arch_cmpxchg128(ptr, o, n, ""); \
|
||||
})
|
||||
|
||||
#endif /* CONFIG_AS_HAS_SCQ_EXTENSION */
|
||||
|
||||
#else
|
||||
#include <asm-generic/cmpxchg-local.h>
|
||||
#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
|
||||
|
||||
@@ -253,8 +253,13 @@ do { \
|
||||
\
|
||||
__get_kernel_common(*((type *)(dst)), sizeof(type), \
|
||||
(__force type *)(src)); \
|
||||
if (unlikely(__gu_err)) \
|
||||
if (unlikely(__gu_err)) { \
|
||||
pr_info("%s: memory access failed, ecode 0x%x\n", \
|
||||
__func__, read_csr_excode()); \
|
||||
pr_info("%s: the caller is %pS\n", \
|
||||
__func__, __builtin_return_address(0)); \
|
||||
goto err_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define __put_kernel_nofault(dst, src, type, err_label) \
|
||||
@@ -264,8 +269,13 @@ do { \
|
||||
\
|
||||
__pu_val = *(__force type *)(src); \
|
||||
__put_kernel_common(((type *)(dst)), sizeof(type)); \
|
||||
if (unlikely(__pu_err)) \
|
||||
if (unlikely(__pu_err)) { \
|
||||
pr_info("%s: memory access failed, ecode 0x%x\n", \
|
||||
__func__, read_csr_excode()); \
|
||||
pr_info("%s: the caller is %pS\n", \
|
||||
__func__, __builtin_return_address(0)); \
|
||||
goto err_label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern unsigned long __copy_user(void *to, const void *from, __kernel_size_t n);
|
||||
|
||||
@@ -246,32 +246,51 @@ static int text_copy_cb(void *data)
|
||||
|
||||
if (smp_processor_id() == copy->cpu) {
|
||||
ret = copy_to_kernel_nofault(copy->dst, copy->src, copy->len);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pr_err("%s: operation failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
flush_icache_range((unsigned long)copy->dst, (unsigned long)copy->dst + copy->len);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int larch_insn_text_copy(void *dst, void *src, size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int err = 0;
|
||||
size_t start, end;
|
||||
struct insn_copy copy = {
|
||||
.dst = dst,
|
||||
.src = src,
|
||||
.len = len,
|
||||
.cpu = smp_processor_id(),
|
||||
.cpu = raw_smp_processor_id(),
|
||||
};
|
||||
|
||||
/*
|
||||
* Ensure copy.cpu won't be hot removed before stop_machine.
|
||||
* If it is removed nobody will really update the text.
|
||||
*/
|
||||
lockdep_assert_cpus_held();
|
||||
|
||||
start = round_down((size_t)dst, PAGE_SIZE);
|
||||
end = round_up((size_t)dst + len, PAGE_SIZE);
|
||||
|
||||
set_memory_rw(start, (end - start) / PAGE_SIZE);
|
||||
ret = stop_machine(text_copy_cb, ©, cpu_online_mask);
|
||||
set_memory_rox(start, (end - start) / PAGE_SIZE);
|
||||
err = set_memory_rw(start, (end - start) / PAGE_SIZE);
|
||||
if (err) {
|
||||
pr_info("%s: set_memory_rw() failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
ret = stop_machine_cpuslocked(text_copy_cb, ©, cpu_online_mask);
|
||||
|
||||
err = set_memory_rox(start, (end - start) / PAGE_SIZE);
|
||||
if (err) {
|
||||
pr_info("%s: set_memory_rox() failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, int_exits),
|
||||
STATS_DESC_COUNTER(VCPU, idle_exits),
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_ICOUNTER(VM, pages),
|
||||
STATS_DESC_ICOUNTER(VM, hugepages),
|
||||
@@ -49,8 +49,8 @@ static void kvm_vm_init_features(struct kvm *kvm)
|
||||
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PMU);
|
||||
|
||||
/* Enable all PV features by default */
|
||||
kvm->arch.pv_features = BIT(KVM_FEATURE_IPI);
|
||||
kvm->arch.kvm_features = BIT(KVM_LOONGARCH_VM_FEAT_PV_IPI);
|
||||
kvm->arch.pv_features |= BIT(KVM_FEATURE_IPI);
|
||||
kvm->arch.kvm_features |= BIT(KVM_LOONGARCH_VM_FEAT_PV_IPI);
|
||||
if (kvm_pvtime_supported()) {
|
||||
kvm->arch.pv_features |= BIT(KVM_FEATURE_PREEMPT);
|
||||
kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME);
|
||||
|
||||
@@ -1379,9 +1379,11 @@ void *bpf_arch_text_copy(void *dst, void *src, size_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
ret = larch_insn_text_copy(dst, src, len);
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
return ret ? ERR_PTR(-EINVAL) : dst;
|
||||
}
|
||||
@@ -1429,10 +1431,12 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type old_t,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
if (memcmp(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES))
|
||||
ret = larch_insn_text_copy(ip, new_insns, LOONGARCH_LONG_JUMP_NBYTES);
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1450,10 +1454,12 @@ int bpf_arch_text_invalidate(void *dst, size_t len)
|
||||
for (i = 0; i < (len / sizeof(u32)); i++)
|
||||
inst[i] = INSN_BREAK;
|
||||
|
||||
cpus_read_lock();
|
||||
mutex_lock(&text_mutex);
|
||||
if (larch_insn_text_copy(dst, inst, len))
|
||||
ret = -EINVAL;
|
||||
mutex_unlock(&text_mutex);
|
||||
cpus_read_unlock();
|
||||
|
||||
kvfree(inst);
|
||||
|
||||
@@ -1568,6 +1574,11 @@ void arch_free_bpf_trampoline(void *image, unsigned int size)
|
||||
bpf_prog_pack_free(image, size);
|
||||
}
|
||||
|
||||
int arch_protect_bpf_trampoline(void *image, unsigned int size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sign-extend the register if necessary
|
||||
*/
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#define VECTORSPACING 0x100 /* for EI/VI mode */
|
||||
#endif
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS()
|
||||
};
|
||||
|
||||
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, wait_exits),
|
||||
STATS_DESC_COUNTER(VCPU, cache_exits),
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#define TASK_SIZE_MAX TASK_SIZE_USER64
|
||||
#endif
|
||||
|
||||
/* Threshold above which VMX copy path is used */
|
||||
#define VMX_COPY_THRESHOLD 3328
|
||||
|
||||
#include <asm-generic/access_ok.h>
|
||||
|
||||
/*
|
||||
@@ -326,40 +329,62 @@ do { \
|
||||
extern unsigned long __copy_tofrom_user(void __user *to,
|
||||
const void __user *from, unsigned long size);
|
||||
|
||||
#ifdef __powerpc64__
|
||||
unsigned long __copy_tofrom_user_base(void __user *to,
|
||||
const void __user *from, unsigned long size);
|
||||
|
||||
unsigned long __copy_tofrom_user_power7_vmx(void __user *to,
|
||||
const void __user *from, unsigned long size);
|
||||
|
||||
static __always_inline bool will_use_vmx(unsigned long n)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_ALTIVEC) && cpu_has_feature(CPU_FTR_VMX_COPY) &&
|
||||
n > VMX_COPY_THRESHOLD;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long
|
||||
raw_copy_tofrom_user(void __user *to, const void __user *from,
|
||||
unsigned long n, unsigned long dir)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
if (will_use_vmx(n) && enter_vmx_usercopy()) {
|
||||
allow_user_access(to, dir);
|
||||
ret = __copy_tofrom_user_power7_vmx(to, from, n);
|
||||
prevent_user_access(dir);
|
||||
exit_vmx_usercopy();
|
||||
|
||||
if (unlikely(ret)) {
|
||||
allow_user_access(to, dir);
|
||||
ret = __copy_tofrom_user_base(to, from, n);
|
||||
prevent_user_access(dir);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
allow_user_access(to, dir);
|
||||
ret = __copy_tofrom_user(to, from, n);
|
||||
prevent_user_access(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
static inline unsigned long
|
||||
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
barrier_nospec();
|
||||
allow_user_access(to, KUAP_READ_WRITE);
|
||||
ret = __copy_tofrom_user(to, from, n);
|
||||
prevent_user_access(KUAP_READ_WRITE);
|
||||
return ret;
|
||||
return raw_copy_tofrom_user(to, from, n, KUAP_READ_WRITE);
|
||||
}
|
||||
#endif /* __powerpc64__ */
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
static inline unsigned long raw_copy_from_user(void *to,
|
||||
const void __user *from, unsigned long n)
|
||||
static inline unsigned long raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
allow_user_access(NULL, KUAP_READ);
|
||||
ret = __copy_tofrom_user((__force void __user *)to, from, n);
|
||||
prevent_user_access(KUAP_READ);
|
||||
return ret;
|
||||
return raw_copy_tofrom_user((__force void __user *)to, from, n, KUAP_READ);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
allow_user_access(to, KUAP_WRITE);
|
||||
ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
|
||||
prevent_user_access(KUAP_WRITE);
|
||||
return ret;
|
||||
return raw_copy_tofrom_user(to, (__force const void __user *)from, n, KUAP_WRITE);
|
||||
}
|
||||
|
||||
unsigned long __arch_clear_user(void __user *addr, unsigned long size);
|
||||
|
||||
@@ -1159,7 +1159,7 @@ spapr_tce_platform_iommu_attach_dev(struct iommu_domain *platform_domain,
|
||||
struct device *dev,
|
||||
struct iommu_domain *old)
|
||||
{
|
||||
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
|
||||
struct iommu_domain *domain = iommu_driver_get_domain_for_dev(dev);
|
||||
struct iommu_table_group *table_group;
|
||||
struct iommu_group *grp;
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <asm/kexec.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/paca.h>
|
||||
#include <asm/processor.h>
|
||||
@@ -995,15 +994,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
initmem_init();
|
||||
|
||||
/*
|
||||
* Reserve large chunks of memory for use by CMA for kdump, fadump, KVM and
|
||||
* hugetlb. These must be called after initmem_init(), so that
|
||||
* pageblock_order is initialised.
|
||||
*/
|
||||
fadump_cma_init();
|
||||
kdump_cma_reserve();
|
||||
kvm_cma_reserve();
|
||||
|
||||
early_memtest(min_low_pfn << PAGE_SHIFT, max_low_pfn << PAGE_SHIFT);
|
||||
|
||||
if (ppc_md.setup_arch)
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
/* #define EXIT_DEBUG */
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_ICOUNTER(VM, num_2M_pages),
|
||||
STATS_DESC_ICOUNTER(VM, num_1G_pages)
|
||||
@@ -53,7 +53,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, sum_exits),
|
||||
STATS_DESC_COUNTER(VCPU, mmio_exits),
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
unsigned long kvmppc_booke_handlers;
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_ICOUNTER(VM, num_2M_pages),
|
||||
STATS_DESC_ICOUNTER(VM, num_1G_pages)
|
||||
@@ -51,7 +51,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, sum_exits),
|
||||
STATS_DESC_COUNTER(VCPU, mmio_exits),
|
||||
|
||||
@@ -39,15 +39,11 @@ enum vcpu_ftr {
|
||||
/* bits [6-5] MAS2_X1 and MAS2_X0 and [4-0] bits for WIMGE */
|
||||
#define E500_TLB_MAS2_ATTR (0x7f)
|
||||
|
||||
struct tlbe_ref {
|
||||
struct tlbe_priv {
|
||||
kvm_pfn_t pfn; /* valid only for TLB0, except briefly */
|
||||
unsigned int flags; /* E500_TLB_* */
|
||||
};
|
||||
|
||||
struct tlbe_priv {
|
||||
struct tlbe_ref ref;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KVM_E500V2
|
||||
struct vcpu_id_table;
|
||||
#endif
|
||||
|
||||
@@ -920,12 +920,12 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500)
|
||||
vcpu_e500->gtlb_offset[0] = 0;
|
||||
vcpu_e500->gtlb_offset[1] = KVM_E500_TLB0_SIZE;
|
||||
|
||||
vcpu_e500->gtlb_priv[0] = kzalloc_objs(struct tlbe_ref,
|
||||
vcpu_e500->gtlb_priv[0] = kzalloc_objs(struct tlbe_priv,
|
||||
vcpu_e500->gtlb_params[0].entries);
|
||||
if (!vcpu_e500->gtlb_priv[0])
|
||||
goto free_vcpu;
|
||||
|
||||
vcpu_e500->gtlb_priv[1] = kzalloc_objs(struct tlbe_ref,
|
||||
vcpu_e500->gtlb_priv[1] = kzalloc_objs(struct tlbe_priv,
|
||||
vcpu_e500->gtlb_params[1].entries);
|
||||
if (!vcpu_e500->gtlb_priv[1])
|
||||
goto free_vcpu;
|
||||
|
||||
@@ -189,16 +189,16 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
|
||||
{
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe =
|
||||
get_entry(vcpu_e500, tlbsel, esel);
|
||||
struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref;
|
||||
struct tlbe_priv *tlbe = &vcpu_e500->gtlb_priv[tlbsel][esel];
|
||||
|
||||
/* Don't bother with unmapped entries */
|
||||
if (!(ref->flags & E500_TLB_VALID)) {
|
||||
WARN(ref->flags & (E500_TLB_BITMAP | E500_TLB_TLB0),
|
||||
"%s: flags %x\n", __func__, ref->flags);
|
||||
if (!(tlbe->flags & E500_TLB_VALID)) {
|
||||
WARN(tlbe->flags & (E500_TLB_BITMAP | E500_TLB_TLB0),
|
||||
"%s: flags %x\n", __func__, tlbe->flags);
|
||||
WARN_ON(tlbsel == 1 && vcpu_e500->g2h_tlb1_map[esel]);
|
||||
}
|
||||
|
||||
if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) {
|
||||
if (tlbsel == 1 && tlbe->flags & E500_TLB_BITMAP) {
|
||||
u64 tmp = vcpu_e500->g2h_tlb1_map[esel];
|
||||
int hw_tlb_indx;
|
||||
unsigned long flags;
|
||||
@@ -216,28 +216,28 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
|
||||
}
|
||||
mb();
|
||||
vcpu_e500->g2h_tlb1_map[esel] = 0;
|
||||
ref->flags &= ~(E500_TLB_BITMAP | E500_TLB_VALID);
|
||||
tlbe->flags &= ~(E500_TLB_BITMAP | E500_TLB_VALID);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
if (tlbsel == 1 && ref->flags & E500_TLB_TLB0) {
|
||||
if (tlbsel == 1 && tlbe->flags & E500_TLB_TLB0) {
|
||||
/*
|
||||
* TLB1 entry is backed by 4k pages. This should happen
|
||||
* rarely and is not worth optimizing. Invalidate everything.
|
||||
*/
|
||||
kvmppc_e500_tlbil_all(vcpu_e500);
|
||||
ref->flags &= ~(E500_TLB_TLB0 | E500_TLB_VALID);
|
||||
tlbe->flags &= ~(E500_TLB_TLB0 | E500_TLB_VALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* If TLB entry is still valid then it's a TLB0 entry, and thus
|
||||
* backed by at most one host tlbe per shadow pid
|
||||
*/
|
||||
if (ref->flags & E500_TLB_VALID)
|
||||
if (tlbe->flags & E500_TLB_VALID)
|
||||
kvmppc_e500_tlbil_one(vcpu_e500, gtlbe);
|
||||
|
||||
/* Mark the TLB as not backed by the host anymore */
|
||||
ref->flags = 0;
|
||||
tlbe->flags = 0;
|
||||
}
|
||||
|
||||
static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
|
||||
@@ -245,26 +245,26 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
|
||||
return tlbe->mas7_3 & (MAS3_SW|MAS3_UW);
|
||||
}
|
||||
|
||||
static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
kvm_pfn_t pfn, unsigned int wimg,
|
||||
bool writable)
|
||||
static inline void kvmppc_e500_tlbe_setup(struct tlbe_priv *tlbe,
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
kvm_pfn_t pfn, unsigned int wimg,
|
||||
bool writable)
|
||||
{
|
||||
ref->pfn = pfn;
|
||||
ref->flags = E500_TLB_VALID;
|
||||
tlbe->pfn = pfn;
|
||||
tlbe->flags = E500_TLB_VALID;
|
||||
if (writable)
|
||||
ref->flags |= E500_TLB_WRITABLE;
|
||||
tlbe->flags |= E500_TLB_WRITABLE;
|
||||
|
||||
/* Use guest supplied MAS2_G and MAS2_E */
|
||||
ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg;
|
||||
tlbe->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg;
|
||||
}
|
||||
|
||||
static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
|
||||
static inline void kvmppc_e500_tlbe_release(struct tlbe_priv *tlbe)
|
||||
{
|
||||
if (ref->flags & E500_TLB_VALID) {
|
||||
if (tlbe->flags & E500_TLB_VALID) {
|
||||
/* FIXME: don't log bogus pfn for TLB1 */
|
||||
trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
|
||||
ref->flags = 0;
|
||||
trace_kvm_booke206_ref_release(tlbe->pfn, tlbe->flags);
|
||||
tlbe->flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,11 +284,8 @@ static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
|
||||
int i;
|
||||
|
||||
for (tlbsel = 0; tlbsel <= 1; tlbsel++) {
|
||||
for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) {
|
||||
struct tlbe_ref *ref =
|
||||
&vcpu_e500->gtlb_priv[tlbsel][i].ref;
|
||||
kvmppc_e500_ref_release(ref);
|
||||
}
|
||||
for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++)
|
||||
kvmppc_e500_tlbe_release(&vcpu_e500->gtlb_priv[tlbsel][i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,18 +301,18 @@ void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
static void kvmppc_e500_setup_stlbe(
|
||||
struct kvm_vcpu *vcpu,
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
int tsize, struct tlbe_ref *ref, u64 gvaddr,
|
||||
int tsize, struct tlbe_priv *tlbe, u64 gvaddr,
|
||||
struct kvm_book3e_206_tlb_entry *stlbe)
|
||||
{
|
||||
kvm_pfn_t pfn = ref->pfn;
|
||||
kvm_pfn_t pfn = tlbe->pfn;
|
||||
u32 pr = vcpu->arch.shared->msr & MSR_PR;
|
||||
bool writable = !!(ref->flags & E500_TLB_WRITABLE);
|
||||
bool writable = !!(tlbe->flags & E500_TLB_WRITABLE);
|
||||
|
||||
BUG_ON(!(ref->flags & E500_TLB_VALID));
|
||||
BUG_ON(!(tlbe->flags & E500_TLB_VALID));
|
||||
|
||||
/* Force IPROT=0 for all guest mappings. */
|
||||
stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID;
|
||||
stlbe->mas2 = (gvaddr & MAS2_EPN) | (ref->flags & E500_TLB_MAS2_ATTR);
|
||||
stlbe->mas2 = (gvaddr & MAS2_EPN) | (tlbe->flags & E500_TLB_MAS2_ATTR);
|
||||
stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) |
|
||||
e500_shadow_mas3_attrib(gtlbe->mas7_3, writable, pr);
|
||||
}
|
||||
@@ -323,7 +320,7 @@ static void kvmppc_e500_setup_stlbe(
|
||||
static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
|
||||
u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe,
|
||||
struct tlbe_ref *ref)
|
||||
struct tlbe_priv *tlbe)
|
||||
{
|
||||
struct kvm_memory_slot *slot;
|
||||
unsigned int psize;
|
||||
@@ -455,9 +452,9 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
|
||||
}
|
||||
}
|
||||
|
||||
kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg, writable);
|
||||
kvmppc_e500_tlbe_setup(tlbe, gtlbe, pfn, wimg, writable);
|
||||
kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
|
||||
ref, gvaddr, stlbe);
|
||||
tlbe, gvaddr, stlbe);
|
||||
writable = tlbe_is_writable(stlbe);
|
||||
|
||||
/* Clear i-cache for new pages */
|
||||
@@ -474,17 +471,17 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, int esel,
|
||||
struct kvm_book3e_206_tlb_entry *stlbe)
|
||||
{
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe;
|
||||
struct tlbe_ref *ref;
|
||||
struct tlbe_priv *tlbe;
|
||||
int stlbsel = 0;
|
||||
int sesel = 0;
|
||||
int r;
|
||||
|
||||
gtlbe = get_entry(vcpu_e500, 0, esel);
|
||||
ref = &vcpu_e500->gtlb_priv[0][esel].ref;
|
||||
tlbe = &vcpu_e500->gtlb_priv[0][esel];
|
||||
|
||||
r = kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe),
|
||||
get_tlb_raddr(gtlbe) >> PAGE_SHIFT,
|
||||
gtlbe, 0, stlbe, ref);
|
||||
gtlbe, 0, stlbe, tlbe);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@@ -494,7 +491,7 @@ static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, int esel,
|
||||
}
|
||||
|
||||
static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,
|
||||
struct tlbe_ref *ref,
|
||||
struct tlbe_priv *tlbe,
|
||||
int esel)
|
||||
{
|
||||
unsigned int sesel = vcpu_e500->host_tlb1_nv++;
|
||||
@@ -507,10 +504,10 @@ static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,
|
||||
vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel);
|
||||
}
|
||||
|
||||
vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;
|
||||
vcpu_e500->gtlb_priv[1][esel].flags |= E500_TLB_BITMAP;
|
||||
vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel;
|
||||
vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1;
|
||||
WARN_ON(!(ref->flags & E500_TLB_VALID));
|
||||
WARN_ON(!(tlbe->flags & E500_TLB_VALID));
|
||||
|
||||
return sesel;
|
||||
}
|
||||
@@ -522,24 +519,24 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,
|
||||
u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
struct kvm_book3e_206_tlb_entry *stlbe, int esel)
|
||||
{
|
||||
struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[1][esel].ref;
|
||||
struct tlbe_priv *tlbe = &vcpu_e500->gtlb_priv[1][esel];
|
||||
int sesel;
|
||||
int r;
|
||||
|
||||
r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe,
|
||||
ref);
|
||||
tlbe);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Use TLB0 when we can only map a page with 4k */
|
||||
if (get_tlb_tsize(stlbe) == BOOK3E_PAGESZ_4K) {
|
||||
vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_TLB0;
|
||||
vcpu_e500->gtlb_priv[1][esel].flags |= E500_TLB_TLB0;
|
||||
write_stlbe(vcpu_e500, gtlbe, stlbe, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise map into TLB1 */
|
||||
sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, ref, esel);
|
||||
sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, tlbe, esel);
|
||||
write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel);
|
||||
|
||||
return 0;
|
||||
@@ -561,11 +558,11 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
|
||||
priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
|
||||
|
||||
/* Triggers after clear_tlb_privs or on initial mapping */
|
||||
if (!(priv->ref.flags & E500_TLB_VALID)) {
|
||||
if (!(priv->flags & E500_TLB_VALID)) {
|
||||
kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
|
||||
} else {
|
||||
kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
|
||||
&priv->ref, eaddr, &stlbe);
|
||||
priv, eaddr, &stlbe);
|
||||
write_stlbe(vcpu_e500, gtlbe, &stlbe, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -562,3 +562,4 @@ exc; std r10,32(3)
|
||||
li r5,4096
|
||||
b .Ldst_aligned
|
||||
EXPORT_SYMBOL(__copy_tofrom_user)
|
||||
EXPORT_SYMBOL(__copy_tofrom_user_base)
|
||||
|
||||
@@ -5,13 +5,9 @@
|
||||
*
|
||||
* Author: Anton Blanchard <anton@au.ibm.com>
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <asm/ppc_asm.h>
|
||||
|
||||
#ifndef SELFTEST_CASE
|
||||
/* 0 == don't use VMX, 1 == use VMX */
|
||||
#define SELFTEST_CASE 0
|
||||
#endif
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
#define LVS(VRT,RA,RB) lvsl VRT,RA,RB
|
||||
#define VPERM(VRT,VRA,VRB,VRC) vperm VRT,VRA,VRB,VRC
|
||||
@@ -47,10 +43,14 @@
|
||||
ld r15,STK_REG(R15)(r1)
|
||||
ld r14,STK_REG(R14)(r1)
|
||||
.Ldo_err3:
|
||||
bl CFUNC(exit_vmx_usercopy)
|
||||
ld r6,STK_REG(R31)(r1) /* original destination pointer */
|
||||
ld r5,STK_REG(R29)(r1) /* original number of bytes */
|
||||
subf r7,r6,r3 /* #bytes copied */
|
||||
subf r3,r7,r5 /* #bytes not copied in r3 */
|
||||
ld r0,STACKFRAMESIZE+16(r1)
|
||||
mtlr r0
|
||||
b .Lexit
|
||||
addi r1,r1,STACKFRAMESIZE
|
||||
blr
|
||||
#endif /* CONFIG_ALTIVEC */
|
||||
|
||||
.Ldo_err2:
|
||||
@@ -74,7 +74,6 @@
|
||||
|
||||
_GLOBAL(__copy_tofrom_user_power7)
|
||||
cmpldi r5,16
|
||||
cmpldi cr1,r5,3328
|
||||
|
||||
std r3,-STACKFRAMESIZE+STK_REG(R31)(r1)
|
||||
std r4,-STACKFRAMESIZE+STK_REG(R30)(r1)
|
||||
@@ -82,12 +81,6 @@ _GLOBAL(__copy_tofrom_user_power7)
|
||||
|
||||
blt .Lshort_copy
|
||||
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
test_feature = SELFTEST_CASE
|
||||
BEGIN_FTR_SECTION
|
||||
bgt cr1,.Lvmx_copy
|
||||
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
|
||||
#endif
|
||||
|
||||
.Lnonvmx_copy:
|
||||
/* Get the source 8B aligned */
|
||||
@@ -263,23 +256,14 @@ err1; stb r0,0(r3)
|
||||
15: li r3,0
|
||||
blr
|
||||
|
||||
.Lunwind_stack_nonvmx_copy:
|
||||
addi r1,r1,STACKFRAMESIZE
|
||||
b .Lnonvmx_copy
|
||||
|
||||
.Lvmx_copy:
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
_GLOBAL(__copy_tofrom_user_power7_vmx)
|
||||
mflr r0
|
||||
std r0,16(r1)
|
||||
stdu r1,-STACKFRAMESIZE(r1)
|
||||
bl CFUNC(enter_vmx_usercopy)
|
||||
cmpwi cr1,r3,0
|
||||
ld r0,STACKFRAMESIZE+16(r1)
|
||||
ld r3,STK_REG(R31)(r1)
|
||||
ld r4,STK_REG(R30)(r1)
|
||||
ld r5,STK_REG(R29)(r1)
|
||||
mtlr r0
|
||||
|
||||
std r3,STK_REG(R31)(r1)
|
||||
std r5,STK_REG(R29)(r1)
|
||||
/*
|
||||
* We prefetch both the source and destination using enhanced touch
|
||||
* instructions. We use a stream ID of 0 for the load side and
|
||||
@@ -300,8 +284,6 @@ err1; stb r0,0(r3)
|
||||
|
||||
DCBT_SETUP_STREAMS(r6, r7, r9, r10, r8)
|
||||
|
||||
beq cr1,.Lunwind_stack_nonvmx_copy
|
||||
|
||||
/*
|
||||
* If source and destination are not relatively aligned we use a
|
||||
* slower permute loop.
|
||||
@@ -478,7 +460,8 @@ err3; lbz r0,0(r4)
|
||||
err3; stb r0,0(r3)
|
||||
|
||||
15: addi r1,r1,STACKFRAMESIZE
|
||||
b CFUNC(exit_vmx_usercopy) /* tail call optimise */
|
||||
li r3,0
|
||||
blr
|
||||
|
||||
.Lvmx_unaligned_copy:
|
||||
/* Get the destination 16B aligned */
|
||||
@@ -681,5 +664,7 @@ err3; lbz r0,0(r4)
|
||||
err3; stb r0,0(r3)
|
||||
|
||||
15: addi r1,r1,STACKFRAMESIZE
|
||||
b CFUNC(exit_vmx_usercopy) /* tail call optimise */
|
||||
li r3,0
|
||||
blr
|
||||
EXPORT_SYMBOL(__copy_tofrom_user_power7_vmx)
|
||||
#endif /* CONFIG_ALTIVEC */
|
||||
|
||||
@@ -27,6 +27,7 @@ int enter_vmx_usercopy(void)
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(enter_vmx_usercopy);
|
||||
|
||||
/*
|
||||
* This function must return 0 because we tail call optimise when calling
|
||||
@@ -49,6 +50,7 @@ int exit_vmx_usercopy(void)
|
||||
set_dec(1);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(exit_vmx_usercopy);
|
||||
|
||||
int enter_vmx_ops(void)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#include <asm/fadump.h>
|
||||
#include <asm/kexec.h>
|
||||
#include <asm/kvm_ppc.h>
|
||||
|
||||
#include <mm/mmu_decl.h>
|
||||
|
||||
unsigned long long memory_limit __initdata;
|
||||
@@ -268,6 +272,16 @@ void __init paging_init(void)
|
||||
|
||||
void __init arch_mm_preinit(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Reserve large chunks of memory for use by CMA for kdump, fadump, KVM
|
||||
* and hugetlb. These must be called after pageblock_order is
|
||||
* initialised.
|
||||
*/
|
||||
fadump_cma_init();
|
||||
kdump_cma_reserve();
|
||||
kvm_cma_reserve();
|
||||
|
||||
/*
|
||||
* book3s is limited to 16 page sizes due to encoding this in
|
||||
* a 4-bit field for slices.
|
||||
|
||||
@@ -103,6 +103,11 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
|
||||
void
|
||||
perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
|
||||
{
|
||||
perf_callchain_store(entry, perf_arch_instruction_pointer(regs));
|
||||
|
||||
if (!current->mm)
|
||||
return;
|
||||
|
||||
if (!is_32bit_task())
|
||||
perf_callchain_user_64(entry, regs);
|
||||
else
|
||||
|
||||
@@ -142,7 +142,6 @@ void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry,
|
||||
next_ip = perf_arch_instruction_pointer(regs);
|
||||
lr = regs->link;
|
||||
sp = regs->gpr[1];
|
||||
perf_callchain_store(entry, next_ip);
|
||||
|
||||
while (entry->nr < entry->max_stack) {
|
||||
fp = (unsigned int __user *) (unsigned long) sp;
|
||||
|
||||
@@ -77,7 +77,6 @@ void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry,
|
||||
next_ip = perf_arch_instruction_pointer(regs);
|
||||
lr = regs->link;
|
||||
sp = regs->gpr[1];
|
||||
perf_callchain_store(entry, next_ip);
|
||||
|
||||
while (entry->nr < entry->max_stack) {
|
||||
fp = (unsigned long __user *) sp;
|
||||
|
||||
@@ -428,6 +428,7 @@
|
||||
clocks = <&clkcfg CLK_CAN0>, <&clkcfg CLK_MSSPLL3>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <56>;
|
||||
resets = <&mss_top_sysreg CLK_CAN0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -437,6 +438,7 @@
|
||||
clocks = <&clkcfg CLK_CAN1>, <&clkcfg CLK_MSSPLL3>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <57>;
|
||||
resets = <&mss_top_sysreg CLK_CAN1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/irqchip/riscv-imsic.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/cpufeature.h>
|
||||
@@ -182,9 +183,14 @@ int kvm_riscv_vcpu_aia_get_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long))
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
|
||||
return -ENOENT;
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
*out_val = 0;
|
||||
if (kvm_riscv_aia_available())
|
||||
@@ -198,9 +204,14 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long val)
|
||||
{
|
||||
struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long))
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
|
||||
return -ENOENT;
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
if (kvm_riscv_aia_available()) {
|
||||
((unsigned long *)csr)[reg_num] = val;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/irqchip/riscv-aplic.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/swab.h>
|
||||
#include <kvm/iodev.h>
|
||||
@@ -45,7 +46,7 @@ static u32 aplic_read_sourcecfg(struct aplic *aplic, u32 irq)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return 0;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
ret = irqd->sourcecfg;
|
||||
@@ -61,7 +62,7 @@ static void aplic_write_sourcecfg(struct aplic *aplic, u32 irq, u32 val)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
if (val & APLIC_SOURCECFG_D)
|
||||
val = 0;
|
||||
@@ -81,7 +82,7 @@ static u32 aplic_read_target(struct aplic *aplic, u32 irq)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return 0;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
ret = irqd->target;
|
||||
@@ -97,7 +98,7 @@ static void aplic_write_target(struct aplic *aplic, u32 irq, u32 val)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
val &= APLIC_TARGET_EIID_MASK |
|
||||
(APLIC_TARGET_HART_IDX_MASK << APLIC_TARGET_HART_IDX_SHIFT) |
|
||||
@@ -116,7 +117,7 @@ static bool aplic_read_pending(struct aplic *aplic, u32 irq)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return false;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
ret = (irqd->state & APLIC_IRQ_STATE_PENDING) ? true : false;
|
||||
@@ -132,7 +133,7 @@ static void aplic_write_pending(struct aplic *aplic, u32 irq, bool pending)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
|
||||
@@ -170,7 +171,7 @@ static bool aplic_read_enabled(struct aplic *aplic, u32 irq)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return false;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
ret = (irqd->state & APLIC_IRQ_STATE_ENABLED) ? true : false;
|
||||
@@ -186,7 +187,7 @@ static void aplic_write_enabled(struct aplic *aplic, u32 irq, bool enabled)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
if (enabled)
|
||||
@@ -205,7 +206,7 @@ static bool aplic_read_input(struct aplic *aplic, u32 irq)
|
||||
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
return false;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
|
||||
@@ -254,7 +255,7 @@ static void aplic_update_irq_range(struct kvm *kvm, u32 first, u32 last)
|
||||
for (irq = first; irq <= last; irq++) {
|
||||
if (!irq || aplic->nr_irqs <= irq)
|
||||
continue;
|
||||
irqd = &aplic->irqs[irq];
|
||||
irqd = &aplic->irqs[array_index_nospec(irq, aplic->nr_irqs)];
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
|
||||
@@ -283,7 +284,7 @@ int kvm_riscv_aia_aplic_inject(struct kvm *kvm, u32 source, bool level)
|
||||
|
||||
if (!aplic || !source || (aplic->nr_irqs <= source))
|
||||
return -ENODEV;
|
||||
irqd = &aplic->irqs[source];
|
||||
irqd = &aplic->irqs[array_index_nospec(source, aplic->nr_irqs)];
|
||||
ie = (aplic->domaincfg & APLIC_DOMAINCFG_IE) ? true : false;
|
||||
|
||||
raw_spin_lock_irqsave(&irqd->lock, flags);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/irqchip/riscv-imsic.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cpufeature.h>
|
||||
|
||||
static int aia_create(struct kvm_device *dev, u32 type)
|
||||
{
|
||||
@@ -22,6 +23,9 @@ static int aia_create(struct kvm_device *dev, u32 type)
|
||||
if (irqchip_in_kernel(kvm))
|
||||
return -EEXIST;
|
||||
|
||||
if (!riscv_isa_extension_available(NULL, SSAIA))
|
||||
return -ENODEV;
|
||||
|
||||
ret = -EBUSY;
|
||||
if (kvm_trylock_all_vcpus(kvm))
|
||||
return ret;
|
||||
@@ -437,7 +441,7 @@ static int aia_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
||||
|
||||
static int aia_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
||||
{
|
||||
int nr_vcpus;
|
||||
int nr_vcpus, r = -ENXIO;
|
||||
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_RISCV_AIA_GRP_CONFIG:
|
||||
@@ -466,12 +470,18 @@ static int aia_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
|
||||
}
|
||||
break;
|
||||
case KVM_DEV_RISCV_AIA_GRP_APLIC:
|
||||
return kvm_riscv_aia_aplic_has_attr(dev->kvm, attr->attr);
|
||||
mutex_lock(&dev->kvm->lock);
|
||||
r = kvm_riscv_aia_aplic_has_attr(dev->kvm, attr->attr);
|
||||
mutex_unlock(&dev->kvm->lock);
|
||||
break;
|
||||
case KVM_DEV_RISCV_AIA_GRP_IMSIC:
|
||||
return kvm_riscv_aia_imsic_has_attr(dev->kvm, attr->attr);
|
||||
mutex_lock(&dev->kvm->lock);
|
||||
r = kvm_riscv_aia_imsic_has_attr(dev->kvm, attr->attr);
|
||||
mutex_unlock(&dev->kvm->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENXIO;
|
||||
return r;
|
||||
}
|
||||
|
||||
struct kvm_device_ops kvm_riscv_aia_device_ops = {
|
||||
|
||||
@@ -908,6 +908,10 @@ int kvm_riscv_vcpu_aia_imsic_rmw(struct kvm_vcpu *vcpu, unsigned long isel,
|
||||
int r, rc = KVM_INSN_CONTINUE_NEXT_SEPC;
|
||||
struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
|
||||
|
||||
/* If IMSIC vCPU state not initialized then forward to user space */
|
||||
if (!imsic)
|
||||
return KVM_INSN_EXIT_TO_USER_SPACE;
|
||||
|
||||
if (isel == KVM_RISCV_AIA_IMSIC_TOPEI) {
|
||||
/* Read pending and enabled interrupt with highest priority */
|
||||
topei = imsic_mrif_topei(imsic->swfile, imsic->nr_eix,
|
||||
|
||||
@@ -245,6 +245,7 @@ out:
|
||||
bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
|
||||
{
|
||||
struct kvm_gstage gstage;
|
||||
bool mmu_locked;
|
||||
|
||||
if (!kvm->arch.pgd)
|
||||
return false;
|
||||
@@ -253,9 +254,12 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
|
||||
gstage.flags = 0;
|
||||
gstage.vmid = READ_ONCE(kvm->arch.vmid.vmid);
|
||||
gstage.pgd = kvm->arch.pgd;
|
||||
mmu_locked = spin_trylock(&kvm->mmu_lock);
|
||||
kvm_riscv_gstage_unmap_range(&gstage, range->start << PAGE_SHIFT,
|
||||
(range->end - range->start) << PAGE_SHIFT,
|
||||
range->may_block);
|
||||
if (mmu_locked)
|
||||
spin_unlock(&kvm->mmu_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -535,7 +539,7 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
|
||||
goto out_unlock;
|
||||
|
||||
/* Check if we are backed by a THP and thus use block mapping if possible */
|
||||
if (vma_pagesize == PAGE_SIZE)
|
||||
if (!logging && (vma_pagesize == PAGE_SIZE))
|
||||
vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
|
||||
|
||||
if (writable) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, ecall_exit_stat),
|
||||
STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
@@ -93,9 +94,11 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
|
||||
if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
|
||||
reg_val = &cntx->fp.f.fcsr;
|
||||
else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) &&
|
||||
reg_num <= KVM_REG_RISCV_FP_F_REG(f[31]))
|
||||
reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) {
|
||||
reg_num = array_index_nospec(reg_num,
|
||||
ARRAY_SIZE(cntx->fp.f.f));
|
||||
reg_val = &cntx->fp.f.f[reg_num];
|
||||
else
|
||||
} else
|
||||
return -ENOENT;
|
||||
} else if ((rtype == KVM_REG_RISCV_FP_D) &&
|
||||
riscv_isa_extension_available(vcpu->arch.isa, d)) {
|
||||
@@ -107,6 +110,8 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
|
||||
reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) {
|
||||
if (KVM_REG_SIZE(reg->id) != sizeof(u64))
|
||||
return -EINVAL;
|
||||
reg_num = array_index_nospec(reg_num,
|
||||
ARRAY_SIZE(cntx->fp.d.f));
|
||||
reg_val = &cntx->fp.d.f[reg_num];
|
||||
} else
|
||||
return -ENOENT;
|
||||
@@ -138,9 +143,11 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
|
||||
if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
|
||||
reg_val = &cntx->fp.f.fcsr;
|
||||
else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) &&
|
||||
reg_num <= KVM_REG_RISCV_FP_F_REG(f[31]))
|
||||
reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) {
|
||||
reg_num = array_index_nospec(reg_num,
|
||||
ARRAY_SIZE(cntx->fp.f.f));
|
||||
reg_val = &cntx->fp.f.f[reg_num];
|
||||
else
|
||||
} else
|
||||
return -ENOENT;
|
||||
} else if ((rtype == KVM_REG_RISCV_FP_D) &&
|
||||
riscv_isa_extension_available(vcpu->arch.isa, d)) {
|
||||
@@ -152,6 +159,8 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
|
||||
reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) {
|
||||
if (KVM_REG_SIZE(reg->id) != sizeof(u64))
|
||||
return -EINVAL;
|
||||
reg_num = array_index_nospec(reg_num,
|
||||
ARRAY_SIZE(cntx->fp.d.f));
|
||||
reg_val = &cntx->fp.d.f[reg_num];
|
||||
} else
|
||||
return -ENOENT;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/cacheflush.h>
|
||||
@@ -127,6 +128,7 @@ static int kvm_riscv_vcpu_isa_check_host(unsigned long kvm_ext, unsigned long *g
|
||||
kvm_ext >= ARRAY_SIZE(kvm_isa_ext_arr))
|
||||
return -ENOENT;
|
||||
|
||||
kvm_ext = array_index_nospec(kvm_ext, ARRAY_SIZE(kvm_isa_ext_arr));
|
||||
*guest_ext = kvm_isa_ext_arr[kvm_ext];
|
||||
switch (*guest_ext) {
|
||||
case RISCV_ISA_EXT_SMNPM:
|
||||
@@ -443,13 +445,16 @@ static int kvm_riscv_vcpu_get_reg_core(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
|
||||
KVM_REG_SIZE_MASK |
|
||||
KVM_REG_RISCV_CORE);
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_core) / sizeof(unsigned long);
|
||||
unsigned long reg_val;
|
||||
|
||||
if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long))
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
if (reg_num == KVM_REG_RISCV_CORE_REG(regs.pc))
|
||||
reg_val = cntx->sepc;
|
||||
else if (KVM_REG_RISCV_CORE_REG(regs.pc) < reg_num &&
|
||||
@@ -476,13 +481,16 @@ static int kvm_riscv_vcpu_set_reg_core(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
|
||||
KVM_REG_SIZE_MASK |
|
||||
KVM_REG_RISCV_CORE);
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_core) / sizeof(unsigned long);
|
||||
unsigned long reg_val;
|
||||
|
||||
if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
if (reg_num >= sizeof(struct kvm_riscv_core) / sizeof(unsigned long))
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id)))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -507,10 +515,13 @@ static int kvm_riscv_vcpu_general_get_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
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;
|
||||
@@ -526,10 +537,13 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_val)
|
||||
{
|
||||
struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
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;
|
||||
@@ -548,10 +562,15 @@ static inline int kvm_riscv_vcpu_smstateen_set_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_val)
|
||||
{
|
||||
struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_smstateen_csr) /
|
||||
sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
|
||||
sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN))
|
||||
return -ENOENT;
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
((unsigned long *)csr)[reg_num] = reg_val;
|
||||
return 0;
|
||||
@@ -562,10 +581,15 @@ static int kvm_riscv_vcpu_smstateen_get_csr(struct kvm_vcpu *vcpu,
|
||||
unsigned long *out_val)
|
||||
{
|
||||
struct kvm_vcpu_smstateen_csr *csr = &vcpu->arch.smstateen_csr;
|
||||
unsigned long regs_max = sizeof(struct kvm_riscv_smstateen_csr) /
|
||||
sizeof(unsigned long);
|
||||
|
||||
if (reg_num >= sizeof(struct kvm_riscv_smstateen_csr) /
|
||||
sizeof(unsigned long))
|
||||
return -EINVAL;
|
||||
if (!riscv_isa_extension_available(vcpu->arch.isa, SMSTATEEN))
|
||||
return -ENOENT;
|
||||
if (reg_num >= regs_max)
|
||||
return -ENOENT;
|
||||
|
||||
reg_num = array_index_nospec(reg_num, regs_max);
|
||||
|
||||
*out_val = ((unsigned long *)csr)[reg_num];
|
||||
return 0;
|
||||
@@ -595,10 +619,7 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
|
||||
rc = kvm_riscv_vcpu_aia_get_csr(vcpu, reg_num, ®_val);
|
||||
break;
|
||||
case KVM_REG_RISCV_CSR_SMSTATEEN:
|
||||
rc = -EINVAL;
|
||||
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
|
||||
rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num,
|
||||
®_val);
|
||||
rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num, ®_val);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOENT;
|
||||
@@ -640,10 +661,7 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
|
||||
rc = kvm_riscv_vcpu_aia_set_csr(vcpu, reg_num, reg_val);
|
||||
break;
|
||||
case KVM_REG_RISCV_CSR_SMSTATEEN:
|
||||
rc = -EINVAL;
|
||||
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
|
||||
rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num,
|
||||
reg_val);
|
||||
rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num, reg_val);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOENT;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kvm_host.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/perf/riscv_pmu.h>
|
||||
#include <asm/csr.h>
|
||||
#include <asm/kvm_vcpu_sbi.h>
|
||||
@@ -87,7 +88,8 @@ static void kvm_pmu_release_perf_event(struct kvm_pmc *pmc)
|
||||
|
||||
static u64 kvm_pmu_get_perf_event_hw_config(u32 sbi_event_code)
|
||||
{
|
||||
return hw_event_perf_map[sbi_event_code];
|
||||
return hw_event_perf_map[array_index_nospec(sbi_event_code,
|
||||
SBI_PMU_HW_GENERAL_MAX)];
|
||||
}
|
||||
|
||||
static u64 kvm_pmu_get_perf_event_cache_config(u32 sbi_event_code)
|
||||
@@ -218,6 +220,7 @@ static int pmu_fw_ctr_read_hi(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[cidx];
|
||||
|
||||
if (pmc->cinfo.type != SBI_PMU_CTR_TYPE_FW)
|
||||
@@ -244,6 +247,7 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[cidx];
|
||||
|
||||
if (pmc->cinfo.type == SBI_PMU_CTR_TYPE_FW) {
|
||||
@@ -520,11 +524,12 @@ int kvm_riscv_vcpu_pmu_ctr_info(struct kvm_vcpu *vcpu, unsigned long cidx,
|
||||
{
|
||||
struct kvm_pmu *kvpmu = vcpu_to_pmu(vcpu);
|
||||
|
||||
if (cidx > RISCV_KVM_MAX_COUNTERS || cidx == 1) {
|
||||
if (cidx >= RISCV_KVM_MAX_COUNTERS || cidx == 1) {
|
||||
retdata->err_val = SBI_ERR_INVALID_PARAM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cidx = array_index_nospec(cidx, RISCV_KVM_MAX_COUNTERS);
|
||||
retdata->out_val = kvpmu->pmc[cidx].cinfo.value;
|
||||
|
||||
return 0;
|
||||
@@ -559,7 +564,8 @@ int kvm_riscv_vcpu_pmu_ctr_start(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
||||
}
|
||||
/* Start the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
pmc_index = i + ctr_base;
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
continue;
|
||||
/* The guest started the counter again. Reset the overflow status */
|
||||
@@ -630,7 +636,8 @@ int kvm_riscv_vcpu_pmu_ctr_stop(struct kvm_vcpu *vcpu, unsigned long ctr_base,
|
||||
|
||||
/* Stop the counters that have been configured and requested by the guest */
|
||||
for_each_set_bit(i, &ctr_mask, RISCV_MAX_COUNTERS) {
|
||||
pmc_index = i + ctr_base;
|
||||
pmc_index = array_index_nospec(i + ctr_base,
|
||||
RISCV_KVM_MAX_COUNTERS);
|
||||
if (!test_bit(pmc_index, kvpmu->pmc_in_use))
|
||||
continue;
|
||||
pmc = &kvpmu->pmc[pmc_index];
|
||||
@@ -761,6 +768,7 @@ int kvm_riscv_vcpu_pmu_ctr_cfg_match(struct kvm_vcpu *vcpu, unsigned long ctr_ba
|
||||
}
|
||||
}
|
||||
|
||||
ctr_idx = array_index_nospec(ctr_idx, RISCV_KVM_MAX_COUNTERS);
|
||||
pmc = &kvpmu->pmc[ctr_idx];
|
||||
pmc->idx = ctr_idx;
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS()
|
||||
};
|
||||
static_assert(ARRAY_SIZE(kvm_vm_stats_desc) ==
|
||||
|
||||
@@ -147,10 +147,8 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
||||
bool from_idle;
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle) {
|
||||
if (from_idle)
|
||||
update_timer_idle();
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
irq_enter_rcu();
|
||||
|
||||
@@ -176,6 +174,9 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
||||
|
||||
set_irq_regs(old_regs);
|
||||
irqentry_exit(regs, state);
|
||||
|
||||
if (from_idle)
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
void noinstr do_ext_irq(struct pt_regs *regs)
|
||||
@@ -185,10 +186,8 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
||||
bool from_idle;
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle) {
|
||||
if (from_idle)
|
||||
update_timer_idle();
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
irq_enter_rcu();
|
||||
|
||||
@@ -210,6 +209,9 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
||||
irq_exit_rcu();
|
||||
set_irq_regs(old_regs);
|
||||
irqentry_exit(regs, state);
|
||||
|
||||
if (from_idle)
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
static void show_msi_interrupt(struct seq_file *p, int irq)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
|
||||
(KVM_MAX_VCPUS + LOCAL_IRQS))
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_COUNTER(VM, inject_io),
|
||||
STATS_DESC_COUNTER(VM, inject_float_mchk),
|
||||
@@ -91,7 +91,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, exit_userspace),
|
||||
STATS_DESC_COUNTER(VCPU, exit_null),
|
||||
|
||||
@@ -2485,7 +2485,8 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
|
||||
KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS | \
|
||||
KVM_X86_QUIRK_SLOT_ZAP_ALL | \
|
||||
KVM_X86_QUIRK_STUFF_FEATURE_MSRS | \
|
||||
KVM_X86_QUIRK_IGNORE_GUEST_PAT)
|
||||
KVM_X86_QUIRK_IGNORE_GUEST_PAT | \
|
||||
KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM)
|
||||
|
||||
#define KVM_X86_CONDITIONAL_QUIRKS \
|
||||
(KVM_X86_QUIRK_CD_NW_CLEARED | \
|
||||
|
||||
@@ -476,6 +476,7 @@ struct kvm_sync_regs {
|
||||
#define KVM_X86_QUIRK_SLOT_ZAP_ALL (1 << 7)
|
||||
#define KVM_X86_QUIRK_STUFF_FEATURE_MSRS (1 << 8)
|
||||
#define KVM_X86_QUIRK_IGNORE_GUEST_PAT (1 << 9)
|
||||
#define KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM (1 << 10)
|
||||
|
||||
#define KVM_STATE_NESTED_FORMAT_VMX 0
|
||||
#define KVM_STATE_NESTED_FORMAT_SVM 1
|
||||
|
||||
@@ -1894,6 +1894,7 @@ void __init check_x2apic(void)
|
||||
|
||||
static inline void try_to_enable_x2apic(int remap_mode) { }
|
||||
static inline void __x2apic_enable(void) { }
|
||||
static inline void __x2apic_disable(void) { }
|
||||
#endif /* !CONFIG_X86_X2APIC */
|
||||
|
||||
void __init enable_IR_x2apic(void)
|
||||
@@ -2456,6 +2457,11 @@ static void lapic_resume(void *data)
|
||||
if (x2apic_mode) {
|
||||
__x2apic_enable();
|
||||
} else {
|
||||
if (x2apic_enabled()) {
|
||||
pr_warn_once("x2apic: re-enabled by firmware during resume. Disabling\n");
|
||||
__x2apic_disable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the APICBASE points to the right address
|
||||
*
|
||||
|
||||
@@ -776,7 +776,10 @@ do { \
|
||||
#define SYNTHESIZED_F(name) \
|
||||
({ \
|
||||
kvm_cpu_cap_synthesized |= feature_bit(name); \
|
||||
F(name); \
|
||||
\
|
||||
BUILD_BUG_ON(X86_FEATURE_##name >= MAX_CPU_FEATURES); \
|
||||
if (boot_cpu_has(X86_FEATURE_##name)) \
|
||||
F(name); \
|
||||
})
|
||||
|
||||
/*
|
||||
|
||||
@@ -1981,16 +1981,17 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
|
||||
if (entries[i] == KVM_HV_TLB_FLUSHALL_ENTRY)
|
||||
goto out_flush_all;
|
||||
|
||||
if (is_noncanonical_invlpg_address(entries[i], vcpu))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Lower 12 bits of 'address' encode the number of additional
|
||||
* pages to flush.
|
||||
*/
|
||||
gva = entries[i] & PAGE_MASK;
|
||||
for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++)
|
||||
for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++) {
|
||||
if (is_noncanonical_invlpg_address(gva + j * PAGE_SIZE, vcpu))
|
||||
continue;
|
||||
|
||||
kvm_x86_call(flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE);
|
||||
}
|
||||
|
||||
++vcpu->stat.tlb_flush;
|
||||
}
|
||||
|
||||
@@ -321,7 +321,8 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
|
||||
idx = srcu_read_lock(&kvm->irq_srcu);
|
||||
gsi = kvm_irq_map_chip_pin(kvm, irqchip, pin);
|
||||
if (gsi != -1)
|
||||
hlist_for_each_entry_rcu(kimn, &ioapic->mask_notifier_list, link)
|
||||
hlist_for_each_entry_srcu(kimn, &ioapic->mask_notifier_list, link,
|
||||
srcu_read_lock_held(&kvm->irq_srcu))
|
||||
if (kimn->irq == gsi)
|
||||
kimn->func(kimn, mask);
|
||||
srcu_read_unlock(&kvm->irq_srcu, idx);
|
||||
|
||||
@@ -189,12 +189,12 @@ static void avic_activate_vmcb(struct vcpu_svm *svm)
|
||||
struct kvm_vcpu *vcpu = &svm->vcpu;
|
||||
|
||||
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
|
||||
|
||||
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
|
||||
vmcb->control.avic_physical_id |= avic_get_max_physical_id(vcpu);
|
||||
|
||||
vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
|
||||
|
||||
svm_clr_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
/*
|
||||
* Note: KVM supports hybrid-AVIC mode, where KVM emulates x2APIC MSR
|
||||
* accesses, while interrupt injection to a running vCPU can be
|
||||
@@ -226,6 +226,9 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm)
|
||||
vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK);
|
||||
vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK;
|
||||
|
||||
if (!sev_es_guest(svm->vcpu.kvm))
|
||||
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
/*
|
||||
* If running nested and the guest uses its own MSR bitmap, there
|
||||
* is no need to update L0's msr bitmap
|
||||
@@ -368,7 +371,7 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb)
|
||||
vmcb->control.avic_physical_id = __sme_set(__pa(kvm_svm->avic_physical_id_table));
|
||||
vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE;
|
||||
|
||||
if (kvm_apicv_activated(svm->vcpu.kvm))
|
||||
if (kvm_vcpu_apicv_active(&svm->vcpu))
|
||||
avic_activate_vmcb(svm);
|
||||
else
|
||||
avic_deactivate_vmcb(svm);
|
||||
|
||||
@@ -418,6 +418,15 @@ static bool nested_vmcb_check_controls(struct kvm_vcpu *vcpu)
|
||||
return __nested_vmcb_check_controls(vcpu, ctl);
|
||||
}
|
||||
|
||||
int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (!nested_vmcb_check_save(vcpu) ||
|
||||
!nested_vmcb_check_controls(vcpu))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a feature is not advertised to L1, clear the corresponding vmcb12
|
||||
* intercept.
|
||||
@@ -1028,8 +1037,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
|
||||
nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
|
||||
nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
|
||||
|
||||
if (!nested_vmcb_check_save(vcpu) ||
|
||||
!nested_vmcb_check_controls(vcpu)) {
|
||||
if (nested_svm_check_cached_vmcb12(vcpu) < 0) {
|
||||
vmcb12->control.exit_code = SVM_EXIT_ERR;
|
||||
vmcb12->control.exit_info_1 = 0;
|
||||
vmcb12->control.exit_info_2 = 0;
|
||||
|
||||
@@ -1077,8 +1077,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event)
|
||||
svm_set_intercept(svm, INTERCEPT_CR0_WRITE);
|
||||
svm_set_intercept(svm, INTERCEPT_CR3_WRITE);
|
||||
svm_set_intercept(svm, INTERCEPT_CR4_WRITE);
|
||||
if (!kvm_vcpu_apicv_active(vcpu))
|
||||
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
set_dr_intercepts(svm);
|
||||
|
||||
@@ -1189,7 +1188,7 @@ static void init_vmcb(struct kvm_vcpu *vcpu, bool init_event)
|
||||
if (guest_cpu_cap_has(vcpu, X86_FEATURE_ERAPS))
|
||||
svm->vmcb->control.erap_ctl |= ERAP_CONTROL_ALLOW_LARGER_RAP;
|
||||
|
||||
if (kvm_vcpu_apicv_active(vcpu))
|
||||
if (enable_apicv && irqchip_in_kernel(vcpu->kvm))
|
||||
avic_init_vmcb(svm, vmcb);
|
||||
|
||||
if (vnmi)
|
||||
@@ -2674,9 +2673,11 @@ static int dr_interception(struct kvm_vcpu *vcpu)
|
||||
|
||||
static int cr8_write_interception(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u8 cr8_prev = kvm_get_cr8(vcpu);
|
||||
int r;
|
||||
|
||||
u8 cr8_prev = kvm_get_cr8(vcpu);
|
||||
WARN_ON_ONCE(kvm_vcpu_apicv_active(vcpu));
|
||||
|
||||
/* instruction emulation calls kvm_set_cr8() */
|
||||
r = cr_interception(vcpu);
|
||||
if (lapic_in_kernel(vcpu))
|
||||
@@ -4879,11 +4880,15 @@ static int svm_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
|
||||
vmcb12 = map.hva;
|
||||
nested_copy_vmcb_control_to_cache(svm, &vmcb12->control);
|
||||
nested_copy_vmcb_save_to_cache(svm, &vmcb12->save);
|
||||
ret = enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa, vmcb12, false);
|
||||
|
||||
if (ret)
|
||||
if (nested_svm_check_cached_vmcb12(vcpu) < 0)
|
||||
goto unmap_save;
|
||||
|
||||
if (enter_svm_guest_mode(vcpu, smram64->svm_guest_vmcb_gpa,
|
||||
vmcb12, false) != 0)
|
||||
goto unmap_save;
|
||||
|
||||
ret = 0;
|
||||
svm->nested.nested_run_pending = 1;
|
||||
|
||||
unmap_save:
|
||||
|
||||
@@ -797,6 +797,7 @@ static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
|
||||
|
||||
int nested_svm_exit_handled(struct vcpu_svm *svm);
|
||||
int nested_svm_check_permissions(struct kvm_vcpu *vcpu);
|
||||
int nested_svm_check_cached_vmcb12(struct kvm_vcpu *vcpu);
|
||||
int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
|
||||
bool has_error_code, u32 error_code);
|
||||
int nested_svm_exit_special(struct vcpu_svm *svm);
|
||||
|
||||
@@ -3300,10 +3300,24 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
|
||||
if (CC(vmcs12->guest_cr4 & X86_CR4_CET && !(vmcs12->guest_cr0 & X86_CR0_WP)))
|
||||
return -EINVAL;
|
||||
|
||||
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) &&
|
||||
(CC(!kvm_dr7_valid(vmcs12->guest_dr7)) ||
|
||||
CC(!vmx_is_valid_debugctl(vcpu, vmcs12->guest_ia32_debugctl, false))))
|
||||
return -EINVAL;
|
||||
if (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) {
|
||||
u64 debugctl = vmcs12->guest_ia32_debugctl;
|
||||
|
||||
/*
|
||||
* FREEZE_IN_SMM is not virtualized, but allow L1 to set it in
|
||||
* vmcs12's DEBUGCTL under a quirk for backwards compatibility.
|
||||
* Note that the quirk only relaxes the consistency check. The
|
||||
* vmcc02 bit is still under the control of the host. In
|
||||
* particular, if a host administrator decides to clear the bit,
|
||||
* then L1 has no say in the matter.
|
||||
*/
|
||||
if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_VMCS12_ALLOW_FREEZE_IN_SMM))
|
||||
debugctl &= ~DEBUGCTLMSR_FREEZE_IN_SMM;
|
||||
|
||||
if (CC(!kvm_dr7_valid(vmcs12->guest_dr7)) ||
|
||||
CC(!vmx_is_valid_debugctl(vcpu, debugctl, false)))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) &&
|
||||
CC(!kvm_pat_valid(vmcs12->guest_ia32_pat)))
|
||||
@@ -6842,13 +6856,34 @@ void vmx_leave_nested(struct kvm_vcpu *vcpu)
|
||||
free_nested(vcpu);
|
||||
}
|
||||
|
||||
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
enum vm_entry_failure_code ignored;
|
||||
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
|
||||
|
||||
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
|
||||
vmcs12->vmcs_link_pointer != INVALID_GPA) {
|
||||
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
|
||||
|
||||
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
|
||||
!shadow_vmcs12->hdr.shadow_vmcs)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nested_vmx_check_controls(vcpu, vmcs12) ||
|
||||
nested_vmx_check_host_state(vcpu, vmcs12) ||
|
||||
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
struct kvm_nested_state __user *user_kvm_nested_state,
|
||||
struct kvm_nested_state *kvm_state)
|
||||
{
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
struct vmcs12 *vmcs12;
|
||||
enum vm_entry_failure_code ignored;
|
||||
struct kvm_vmx_nested_state_data __user *user_vmx_nested_state =
|
||||
&user_kvm_nested_state->data.vmx[0];
|
||||
int ret;
|
||||
@@ -6979,25 +7014,20 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
vmx->nested.mtf_pending =
|
||||
!!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (nested_cpu_has_shadow_vmcs(vmcs12) &&
|
||||
vmcs12->vmcs_link_pointer != INVALID_GPA) {
|
||||
struct vmcs12 *shadow_vmcs12 = get_shadow_vmcs12(vcpu);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (kvm_state->size <
|
||||
sizeof(*kvm_state) +
|
||||
sizeof(user_vmx_nested_state->vmcs12) + sizeof(*shadow_vmcs12))
|
||||
goto error_guest_mode;
|
||||
|
||||
ret = -EFAULT;
|
||||
if (copy_from_user(shadow_vmcs12,
|
||||
user_vmx_nested_state->shadow_vmcs12,
|
||||
sizeof(*shadow_vmcs12))) {
|
||||
ret = -EFAULT;
|
||||
goto error_guest_mode;
|
||||
}
|
||||
|
||||
if (shadow_vmcs12->hdr.revision_id != VMCS12_REVISION ||
|
||||
!shadow_vmcs12->hdr.shadow_vmcs)
|
||||
sizeof(*shadow_vmcs12)))
|
||||
goto error_guest_mode;
|
||||
}
|
||||
|
||||
@@ -7008,9 +7038,8 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
kvm_state->hdr.vmx.preemption_timer_deadline;
|
||||
}
|
||||
|
||||
if (nested_vmx_check_controls(vcpu, vmcs12) ||
|
||||
nested_vmx_check_host_state(vcpu, vmcs12) ||
|
||||
nested_vmx_check_guest_state(vcpu, vmcs12, &ignored))
|
||||
ret = nested_vmx_check_restored_vmcs12(vcpu);
|
||||
if (ret < 0)
|
||||
goto error_guest_mode;
|
||||
|
||||
vmx->nested.dirty_vmcs12 = true;
|
||||
|
||||
@@ -22,6 +22,7 @@ void nested_vmx_setup_ctls_msrs(struct vmcs_config *vmcs_conf, u32 ept_caps);
|
||||
void nested_vmx_hardware_unsetup(void);
|
||||
__init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
|
||||
void nested_vmx_set_vmcs_shadowing_bitmap(void);
|
||||
int nested_vmx_check_restored_vmcs12(struct kvm_vcpu *vcpu);
|
||||
void nested_vmx_free_vcpu(struct kvm_vcpu *vcpu);
|
||||
enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
|
||||
bool from_vmentry);
|
||||
|
||||
@@ -1149,7 +1149,7 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr,
|
||||
}
|
||||
|
||||
vmx_add_auto_msr(&m->guest, msr, guest_val, VM_ENTRY_MSR_LOAD_COUNT, kvm);
|
||||
vmx_add_auto_msr(&m->guest, msr, host_val, VM_EXIT_MSR_LOAD_COUNT, kvm);
|
||||
vmx_add_auto_msr(&m->host, msr, host_val, VM_EXIT_MSR_LOAD_COUNT, kvm);
|
||||
}
|
||||
|
||||
static bool update_transition_efer(struct vcpu_vmx *vmx)
|
||||
@@ -8528,9 +8528,13 @@ int vmx_leave_smm(struct kvm_vcpu *vcpu, const union kvm_smram *smram)
|
||||
}
|
||||
|
||||
if (vmx->nested.smm.guest_mode) {
|
||||
/* Triple fault if the state is invalid. */
|
||||
if (nested_vmx_check_restored_vmcs12(vcpu) < 0)
|
||||
return 1;
|
||||
|
||||
ret = nested_vmx_enter_non_root_mode(vcpu, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret != NVMX_VMENTRY_SUCCESS)
|
||||
return 1;
|
||||
|
||||
vmx->nested.nested_run_pending = 1;
|
||||
vmx->nested.smm.guest_mode = false;
|
||||
|
||||
@@ -243,7 +243,7 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_ipiv);
|
||||
bool __read_mostly enable_device_posted_irqs = true;
|
||||
EXPORT_SYMBOL_FOR_KVM_INTERNAL(enable_device_posted_irqs);
|
||||
|
||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||
KVM_GENERIC_VM_STATS(),
|
||||
STATS_DESC_COUNTER(VM, mmu_shadow_zapped),
|
||||
STATS_DESC_COUNTER(VM, mmu_pte_write),
|
||||
@@ -269,7 +269,7 @@ const struct kvm_stats_header kvm_vm_stats_header = {
|
||||
sizeof(kvm_vm_stats_desc),
|
||||
};
|
||||
|
||||
const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
const struct kvm_stats_desc kvm_vcpu_stats_desc[] = {
|
||||
KVM_GENERIC_VCPU_STATS(),
|
||||
STATS_DESC_COUNTER(VCPU, pf_taken),
|
||||
STATS_DESC_COUNTER(VCPU, pf_fixed),
|
||||
|
||||
@@ -165,7 +165,6 @@ aie2_sched_notify(struct amdxdna_sched_job *job)
|
||||
|
||||
trace_xdna_job(&job->base, job->hwctx->name, "signaled fence", job->seq);
|
||||
|
||||
amdxdna_pm_suspend_put(job->hwctx->client->xdna);
|
||||
job->hwctx->priv->completed++;
|
||||
dma_fence_signal(fence);
|
||||
|
||||
@@ -290,19 +289,11 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
struct dma_fence *fence;
|
||||
int ret;
|
||||
|
||||
ret = amdxdna_pm_resume_get(hwctx->client->xdna);
|
||||
if (ret)
|
||||
if (!hwctx->priv->mbox_chann)
|
||||
return NULL;
|
||||
|
||||
if (!hwctx->priv->mbox_chann) {
|
||||
amdxdna_pm_suspend_put(hwctx->client->xdna);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!mmget_not_zero(job->mm)) {
|
||||
amdxdna_pm_suspend_put(hwctx->client->xdna);
|
||||
if (!mmget_not_zero(job->mm))
|
||||
return ERR_PTR(-ESRCH);
|
||||
}
|
||||
|
||||
kref_get(&job->refcnt);
|
||||
fence = dma_fence_get(job->fence);
|
||||
@@ -333,7 +324,6 @@ aie2_sched_job_run(struct drm_sched_job *sched_job)
|
||||
|
||||
out:
|
||||
if (ret) {
|
||||
amdxdna_pm_suspend_put(hwctx->client->xdna);
|
||||
dma_fence_put(job->fence);
|
||||
aie2_job_put(job);
|
||||
mmput(job->mm);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "amdxdna_ctx.h"
|
||||
#include "amdxdna_gem.h"
|
||||
#include "amdxdna_pci_drv.h"
|
||||
#include "amdxdna_pm.h"
|
||||
|
||||
#define MAX_HWCTX_ID 255
|
||||
#define MAX_ARG_COUNT 4095
|
||||
@@ -445,6 +446,7 @@ put_shmem_bo:
|
||||
void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job)
|
||||
{
|
||||
trace_amdxdna_debug_point(job->hwctx->name, job->seq, "job release");
|
||||
amdxdna_pm_suspend_put(job->hwctx->client->xdna);
|
||||
amdxdna_arg_bos_put(job);
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
dma_fence_put(job->fence);
|
||||
@@ -482,6 +484,12 @@ int amdxdna_cmd_submit(struct amdxdna_client *client,
|
||||
goto cmd_put;
|
||||
}
|
||||
|
||||
ret = amdxdna_pm_resume_get(xdna);
|
||||
if (ret) {
|
||||
XDNA_ERR(xdna, "Resume failed, ret %d", ret);
|
||||
goto put_bos;
|
||||
}
|
||||
|
||||
idx = srcu_read_lock(&client->hwctx_srcu);
|
||||
hwctx = xa_load(&client->hwctx_xa, hwctx_hdl);
|
||||
if (!hwctx) {
|
||||
@@ -522,6 +530,8 @@ put_fence:
|
||||
dma_fence_put(job->fence);
|
||||
unlock_srcu:
|
||||
srcu_read_unlock(&client->hwctx_srcu, idx);
|
||||
amdxdna_pm_suspend_put(xdna);
|
||||
put_bos:
|
||||
amdxdna_arg_bos_put(job);
|
||||
cmd_put:
|
||||
amdxdna_gem_put_obj(job->cmd_bo);
|
||||
|
||||
@@ -121,12 +121,6 @@
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY 0x0003006cu
|
||||
#define VPU_50XX_HOST_SS_AON_PWR_ISLAND_STATUS_DLY_STATUS_DLY_MASK GENMASK(7, 0)
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_RETENTION0 0x0003000cu
|
||||
#define VPU_40XX_HOST_SS_AON_RETENTION1 0x00030010u
|
||||
#define VPU_40XX_HOST_SS_AON_RETENTION2 0x00030014u
|
||||
#define VPU_40XX_HOST_SS_AON_RETENTION3 0x00030018u
|
||||
#define VPU_40XX_HOST_SS_AON_RETENTION4 0x0003001cu
|
||||
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN 0x00030200u
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_EN_MASK BIT_MASK(0)
|
||||
#define VPU_40XX_HOST_SS_AON_IDLE_GEN_HW_PG_EN_MASK BIT_MASK(1)
|
||||
|
||||
@@ -931,7 +931,6 @@ static int soc_cpu_boot_40xx(struct ivpu_device *vdev)
|
||||
|
||||
static int soc_cpu_boot_60xx(struct ivpu_device *vdev)
|
||||
{
|
||||
REGV_WR64(VPU_40XX_HOST_SS_AON_RETENTION1, vdev->fw->mem_bp->vpu_addr);
|
||||
soc_cpu_set_entry_point_40xx(vdev, vdev->fw->cold_boot_entry_point);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -9,6 +9,7 @@ config ARCH_SUPPORTS_ACPI
|
||||
menuconfig ACPI
|
||||
bool "ACPI (Advanced Configuration and Power Interface) Support"
|
||||
depends on ARCH_SUPPORTS_ACPI
|
||||
select AUXILIARY_BUS
|
||||
select PNP
|
||||
select NLS
|
||||
select CRC32
|
||||
|
||||
@@ -135,7 +135,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
|
||||
}
|
||||
}
|
||||
|
||||
if (adev->device_type == ACPI_BUS_TYPE_DEVICE && !adev->pnp.type.backlight) {
|
||||
if (adev->device_type == ACPI_BUS_TYPE_DEVICE) {
|
||||
LIST_HEAD(resource_list);
|
||||
|
||||
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
|
||||
|
||||
@@ -113,6 +113,10 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
||||
PCI_ANY_ID, PCI_ANY_ID, NULL);
|
||||
if (ide_dev) {
|
||||
errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
|
||||
if (errata.piix4.bmisx)
|
||||
dev_dbg(&ide_dev->dev,
|
||||
"Bus master activity detection (BM-IDE) erratum enabled\n");
|
||||
|
||||
pci_dev_put(ide_dev);
|
||||
}
|
||||
|
||||
@@ -131,20 +135,17 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
|
||||
if (isa_dev) {
|
||||
pci_read_config_byte(isa_dev, 0x76, &value1);
|
||||
pci_read_config_byte(isa_dev, 0x77, &value2);
|
||||
if ((value1 & 0x80) || (value2 & 0x80))
|
||||
if ((value1 & 0x80) || (value2 & 0x80)) {
|
||||
errata.piix4.fdma = 1;
|
||||
dev_dbg(&isa_dev->dev,
|
||||
"Type-F DMA livelock erratum (C3 disabled)\n");
|
||||
}
|
||||
pci_dev_put(isa_dev);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ide_dev)
|
||||
dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n");
|
||||
|
||||
if (isa_dev)
|
||||
dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#define pr_fmt(fmt) "ACPI: video: " fmt
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -21,7 +22,6 @@
|
||||
#include <linux/sort.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/suspend.h>
|
||||
@@ -77,8 +77,9 @@ static int register_count;
|
||||
static DEFINE_MUTEX(register_count_mutex);
|
||||
static DEFINE_MUTEX(video_list_lock);
|
||||
static LIST_HEAD(video_bus_head);
|
||||
static int acpi_video_bus_probe(struct platform_device *pdev);
|
||||
static void acpi_video_bus_remove(struct platform_device *pdev);
|
||||
static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
|
||||
const struct auxiliary_device_id *id);
|
||||
static void acpi_video_bus_remove(struct auxiliary_device *aux);
|
||||
static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
/*
|
||||
@@ -93,19 +94,16 @@ enum acpi_video_level_idx {
|
||||
ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */
|
||||
};
|
||||
|
||||
static const struct acpi_device_id video_device_ids[] = {
|
||||
{ACPI_VIDEO_HID, 0},
|
||||
{"", 0},
|
||||
static const struct auxiliary_device_id video_bus_auxiliary_id_table[] = {
|
||||
{ .name = "acpi.video_bus" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, video_device_ids);
|
||||
MODULE_DEVICE_TABLE(auxiliary, video_bus_auxiliary_id_table);
|
||||
|
||||
static struct platform_driver acpi_video_bus = {
|
||||
static struct auxiliary_driver acpi_video_bus = {
|
||||
.probe = acpi_video_bus_probe,
|
||||
.remove = acpi_video_bus_remove,
|
||||
.driver = {
|
||||
.name = "acpi-video",
|
||||
.acpi_match_table = video_device_ids,
|
||||
},
|
||||
.id_table = video_bus_auxiliary_id_table,
|
||||
};
|
||||
|
||||
struct acpi_video_bus_flags {
|
||||
@@ -1885,7 +1883,7 @@ static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device)
|
||||
}
|
||||
|
||||
static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video,
|
||||
struct platform_device *pdev)
|
||||
struct device *parent)
|
||||
{
|
||||
struct input_dev *input;
|
||||
struct acpi_video_device *dev;
|
||||
@@ -1908,7 +1906,7 @@ static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video,
|
||||
input->phys = video->phys;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.product = 0x06;
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->dev.parent = parent;
|
||||
input->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
|
||||
set_bit(KEY_VIDEO_NEXT, input->keybit);
|
||||
@@ -1980,9 +1978,10 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
|
||||
|
||||
static int instance;
|
||||
|
||||
static int acpi_video_bus_probe(struct platform_device *pdev)
|
||||
static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
|
||||
const struct auxiliary_device_id *id_unused)
|
||||
{
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
|
||||
struct acpi_video_bus *video;
|
||||
bool auto_detect;
|
||||
int error;
|
||||
@@ -2019,7 +2018,7 @@ static int acpi_video_bus_probe(struct platform_device *pdev)
|
||||
instance++;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, video);
|
||||
auxiliary_set_drvdata(aux_dev, video);
|
||||
|
||||
video->device = device;
|
||||
strscpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
|
||||
@@ -2068,7 +2067,7 @@ static int acpi_video_bus_probe(struct platform_device *pdev)
|
||||
!auto_detect)
|
||||
acpi_video_bus_register_backlight(video);
|
||||
|
||||
error = acpi_video_bus_add_notify_handler(video, pdev);
|
||||
error = acpi_video_bus_add_notify_handler(video, &aux_dev->dev);
|
||||
if (error)
|
||||
goto err_del;
|
||||
|
||||
@@ -2096,10 +2095,10 @@ err_free_video:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void acpi_video_bus_remove(struct platform_device *pdev)
|
||||
static void acpi_video_bus_remove(struct auxiliary_device *aux_dev)
|
||||
{
|
||||
struct acpi_video_bus *video = platform_get_drvdata(pdev);
|
||||
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
|
||||
struct acpi_video_bus *video = auxiliary_get_drvdata(aux_dev);
|
||||
struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
|
||||
|
||||
acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
|
||||
acpi_video_bus_notify);
|
||||
@@ -2163,7 +2162,7 @@ int acpi_video_register(void)
|
||||
|
||||
dmi_check_system(video_dmi_table);
|
||||
|
||||
ret = platform_driver_register(&acpi_video_bus);
|
||||
ret = auxiliary_driver_register(&acpi_video_bus);
|
||||
if (ret)
|
||||
goto leave;
|
||||
|
||||
@@ -2183,7 +2182,7 @@ void acpi_video_unregister(void)
|
||||
{
|
||||
mutex_lock(®ister_count_mutex);
|
||||
if (register_count) {
|
||||
platform_driver_unregister(&acpi_video_bus);
|
||||
auxiliary_driver_unregister(&acpi_video_bus);
|
||||
register_count = 0;
|
||||
may_report_brightness_keys = false;
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
|
||||
|
||||
{{"_DSM",
|
||||
METHOD_4ARGS(ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
|
||||
ACPI_TYPE_ANY | ACPI_TYPE_PACKAGE) |
|
||||
ACPI_TYPE_PACKAGE | ACPI_TYPE_ANY) |
|
||||
ARG_COUNT_IS_MINIMUM,
|
||||
METHOD_RETURNS(ACPI_RTYPE_ALL)}}, /* Must return a value, but it can be of any type */
|
||||
|
||||
|
||||
@@ -818,9 +818,6 @@ const struct acpi_device *acpi_companion_match(const struct device *dev)
|
||||
if (list_empty(&adev->pnp.ids))
|
||||
return NULL;
|
||||
|
||||
if (adev->pnp.type.backlight)
|
||||
return adev;
|
||||
|
||||
return acpi_primary_dev_companion(adev, dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -1681,7 +1681,7 @@ acpi_status __init acpi_os_initialize(void)
|
||||
* Use acpi_os_map_generic_address to pre-map the reset
|
||||
* register if it's in system memory.
|
||||
*/
|
||||
void *rv;
|
||||
void __iomem *rv;
|
||||
|
||||
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
|
||||
pr_debug("%s: Reset register mapping %s\n", __func__,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define pr_fmt(fmt) "ACPI: " fmt
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -2192,6 +2193,44 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
|
||||
return acpi_bus_check_add(handle, false, (struct acpi_device **)ret_p);
|
||||
}
|
||||
|
||||
static void acpi_video_bus_device_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *aux_dev = to_auxiliary_dev(dev);
|
||||
|
||||
kfree(aux_dev);
|
||||
}
|
||||
|
||||
static void acpi_create_video_bus_device(struct acpi_device *adev,
|
||||
struct acpi_device *parent)
|
||||
{
|
||||
struct auxiliary_device *aux_dev;
|
||||
static unsigned int aux_dev_id;
|
||||
|
||||
aux_dev = kzalloc_obj(*aux_dev);
|
||||
if (!aux_dev)
|
||||
return;
|
||||
|
||||
aux_dev->id = aux_dev_id++;
|
||||
aux_dev->name = "video_bus";
|
||||
aux_dev->dev.parent = acpi_get_first_physical_node(parent);
|
||||
if (!aux_dev->dev.parent)
|
||||
goto err;
|
||||
|
||||
aux_dev->dev.release = acpi_video_bus_device_release;
|
||||
|
||||
if (auxiliary_device_init(aux_dev))
|
||||
goto err;
|
||||
|
||||
ACPI_COMPANION_SET(&aux_dev->dev, adev);
|
||||
if (__auxiliary_device_add(aux_dev, "acpi"))
|
||||
auxiliary_device_uninit(aux_dev);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
kfree(aux_dev);
|
||||
}
|
||||
|
||||
struct acpi_scan_system_dev {
|
||||
struct list_head node;
|
||||
struct acpi_device *adev;
|
||||
@@ -2229,6 +2268,12 @@ static void acpi_default_enumeration(struct acpi_device *device)
|
||||
sd->adev = device;
|
||||
list_add_tail(&sd->node, &acpi_scan_system_dev_list);
|
||||
}
|
||||
} else if (device->pnp.type.backlight) {
|
||||
struct acpi_device *parent;
|
||||
|
||||
parent = acpi_dev_parent(device);
|
||||
if (parent)
|
||||
acpi_create_video_bus_device(device, parent);
|
||||
} else {
|
||||
/* For a regular device object, create a platform device. */
|
||||
acpi_create_platform_device(device, NULL);
|
||||
|
||||
@@ -142,6 +142,30 @@ pub(crate) struct ShrinkablePageRange {
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
// We do not define any ops. For now, used only to check identity of vmas.
|
||||
static BINDER_VM_OPS: bindings::vm_operations_struct = pin_init::zeroed();
|
||||
|
||||
// To ensure that we do not accidentally install pages into or zap pages from the wrong vma, we
|
||||
// check its vm_ops and private data before using it.
|
||||
fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> {
|
||||
// SAFETY: Just reading the vm_ops pointer of any active vma is safe.
|
||||
let vm_ops = unsafe { (*vma.as_ptr()).vm_ops };
|
||||
if !ptr::eq(vm_ops, &BINDER_VM_OPS) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// SAFETY: Reading the vm_private_data pointer of a binder-owned vma is safe.
|
||||
let vm_private_data = unsafe { (*vma.as_ptr()).vm_private_data };
|
||||
// The ShrinkablePageRange is only dropped when the Process is dropped, which only happens once
|
||||
// the file's ->release handler is invoked, which means the ShrinkablePageRange outlives any
|
||||
// VMA associated with it, so there can't be any false positives due to pointer reuse here.
|
||||
if !ptr::eq(vm_private_data, owner.cast()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
vma.as_mixedmap_vma()
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
/// Array of pages.
|
||||
///
|
||||
@@ -308,6 +332,18 @@ impl ShrinkablePageRange {
|
||||
inner.size = num_pages;
|
||||
inner.vma_addr = vma.start();
|
||||
|
||||
// This pointer is only used for comparison - it's not dereferenced.
|
||||
//
|
||||
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
|
||||
// `vm_private_data`.
|
||||
unsafe {
|
||||
(*vma.as_ptr()).vm_private_data = ptr::from_ref(self).cast_mut().cast::<c_void>()
|
||||
};
|
||||
|
||||
// SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on
|
||||
// `vm_ops`.
|
||||
unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS };
|
||||
|
||||
Ok(num_pages)
|
||||
}
|
||||
|
||||
@@ -399,22 +435,25 @@ impl ShrinkablePageRange {
|
||||
//
|
||||
// Using `mmput_async` avoids this, because then the `mm` cleanup is instead queued to a
|
||||
// workqueue.
|
||||
MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?)
|
||||
.mmap_read_lock()
|
||||
.vma_lookup(vma_addr)
|
||||
.ok_or(ESRCH)?
|
||||
.as_mixedmap_vma()
|
||||
.ok_or(ESRCH)?
|
||||
.vm_insert_page(user_page_addr, &new_page)
|
||||
.inspect_err(|err| {
|
||||
pr_warn!(
|
||||
"Failed to vm_insert_page({}): vma_addr:{} i:{} err:{:?}",
|
||||
user_page_addr,
|
||||
vma_addr,
|
||||
i,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
let mm = MmWithUser::into_mmput_async(self.mm.mmget_not_zero().ok_or(ESRCH)?);
|
||||
{
|
||||
let vma_read;
|
||||
let mmap_read;
|
||||
let vma = if let Some(ret) = mm.lock_vma_under_rcu(vma_addr) {
|
||||
vma_read = ret;
|
||||
check_vma(&vma_read, self)
|
||||
} else {
|
||||
mmap_read = mm.mmap_read_lock();
|
||||
mmap_read
|
||||
.vma_lookup(vma_addr)
|
||||
.and_then(|vma| check_vma(vma, self))
|
||||
};
|
||||
|
||||
match vma {
|
||||
Some(vma) => vma.vm_insert_page(user_page_addr, &new_page)?,
|
||||
None => return Err(ESRCH),
|
||||
}
|
||||
}
|
||||
|
||||
let inner = self.lock.lock();
|
||||
|
||||
@@ -667,12 +706,15 @@ unsafe extern "C" fn rust_shrink_free_page(
|
||||
let mmap_read;
|
||||
let mm_mutex;
|
||||
let vma_addr;
|
||||
let range_ptr;
|
||||
|
||||
{
|
||||
// CAST: The `list_head` field is first in `PageInfo`.
|
||||
let info = item as *mut PageInfo;
|
||||
// SAFETY: The `range` field of `PageInfo` is immutable.
|
||||
let range = unsafe { &*((*info).range) };
|
||||
range_ptr = unsafe { (*info).range };
|
||||
// SAFETY: The `range` outlives its `PageInfo` values.
|
||||
let range = unsafe { &*range_ptr };
|
||||
|
||||
mm = match range.mm.mmget_not_zero() {
|
||||
Some(mm) => MmWithUser::into_mmput_async(mm),
|
||||
@@ -717,9 +759,11 @@ unsafe extern "C" fn rust_shrink_free_page(
|
||||
// SAFETY: The lru lock is locked when this method is called.
|
||||
unsafe { bindings::spin_unlock(&raw mut (*lru).lock) };
|
||||
|
||||
if let Some(vma) = mmap_read.vma_lookup(vma_addr) {
|
||||
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
|
||||
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
|
||||
if let Some(unchecked_vma) = mmap_read.vma_lookup(vma_addr) {
|
||||
if let Some(vma) = check_vma(unchecked_vma, range_ptr) {
|
||||
let user_page_addr = vma_addr + (page_index << PAGE_SHIFT);
|
||||
vma.zap_page_range_single(user_page_addr, PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
drop(mmap_read);
|
||||
|
||||
@@ -1295,7 +1295,8 @@ impl Process {
|
||||
}
|
||||
|
||||
pub(crate) fn dead_binder_done(&self, cookie: u64, thread: &Thread) {
|
||||
if let Some(death) = self.inner.lock().pull_delivered_death(cookie) {
|
||||
let death = self.inner.lock().pull_delivered_death(cookie);
|
||||
if let Some(death) = death {
|
||||
death.set_notification_done(thread);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl<T> ArrayRangeAllocator<T> {
|
||||
size: usize,
|
||||
is_oneway: bool,
|
||||
pid: Pid,
|
||||
) -> Result<usize> {
|
||||
) -> Result<(usize, bool)> {
|
||||
// Compute new value of free_oneway_space, which is set only on success.
|
||||
let new_oneway_space = if is_oneway {
|
||||
match self.free_oneway_space.checked_sub(size) {
|
||||
@@ -146,7 +146,38 @@ impl<T> ArrayRangeAllocator<T> {
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
Ok(insert_at_offset)
|
||||
// Start detecting spammers once we have less than 20%
|
||||
// of async space left (which is less than 10% of total
|
||||
// buffer size).
|
||||
//
|
||||
// (This will short-circuit, so `low_oneway_space` is
|
||||
// only called when necessary.)
|
||||
let oneway_spam_detected =
|
||||
is_oneway && new_oneway_space < self.size / 10 && self.low_oneway_space(pid);
|
||||
|
||||
Ok((insert_at_offset, oneway_spam_detected))
|
||||
}
|
||||
|
||||
/// Find the amount and size of buffers allocated by the current caller.
|
||||
///
|
||||
/// The idea is that once we cross the threshold, whoever is responsible
|
||||
/// for the low async space is likely to try to send another async transaction,
|
||||
/// and at some point we'll catch them in the act. This is more efficient
|
||||
/// than keeping a map per pid.
|
||||
fn low_oneway_space(&self, calling_pid: Pid) -> bool {
|
||||
let mut total_alloc_size = 0;
|
||||
let mut num_buffers = 0;
|
||||
|
||||
// Warn if this pid has more than 50 transactions, or more than 50% of
|
||||
// async space (which is 25% of total buffer size). Oneway spam is only
|
||||
// detected when the threshold is exceeded.
|
||||
for range in &self.ranges {
|
||||
if range.state.is_oneway() && range.state.pid() == calling_pid {
|
||||
total_alloc_size += range.size;
|
||||
num_buffers += 1;
|
||||
}
|
||||
}
|
||||
num_buffers > 50 || total_alloc_size > self.size / 4
|
||||
}
|
||||
|
||||
pub(crate) fn reservation_abort(&mut self, offset: usize) -> Result<FreedRange> {
|
||||
|
||||
@@ -188,11 +188,11 @@ impl<T> RangeAllocator<T> {
|
||||
self.reserve_new(args)
|
||||
}
|
||||
Impl::Array(array) => {
|
||||
let offset =
|
||||
let (offset, oneway_spam_detected) =
|
||||
array.reserve_new(args.debug_id, args.size, args.is_oneway, args.pid)?;
|
||||
Ok(ReserveNew::Success(ReserveNewSuccess {
|
||||
offset,
|
||||
oneway_spam_detected: false,
|
||||
oneway_spam_detected,
|
||||
_empty_array_alloc: args.empty_array_alloc,
|
||||
_new_tree_alloc: args.new_tree_alloc,
|
||||
_tree_alloc: args.tree_alloc,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user