mirror of
https://github.com/Fishwaldo/build.git
synced 2025-07-21 04:18:52 +00:00
939 lines
32 KiB
Diff
939 lines
32 KiB
Diff
diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
|
|
index 2cf3affa1be70..96c0b1440c9c5 100644
|
|
--- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
|
|
+++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt
|
|
@@ -15,8 +15,15 @@ Required properties:
|
|
- "nvidia,tegra210-sdhci": for Tegra210
|
|
- "nvidia,tegra186-sdhci": for Tegra186
|
|
- "nvidia,tegra194-sdhci": for Tegra194
|
|
-- clocks : Must contain one entry, for the module clock.
|
|
- See ../clocks/clock-bindings.txt for details.
|
|
+- clocks: For Tegra210, Tegra186 and Tegra194 must contain two entries.
|
|
+ One for the module clock and one for the timeout clock.
|
|
+ For all other Tegra devices, must contain a single entry for
|
|
+ the module clock. See ../clocks/clock-bindings.txt for details.
|
|
+- clock-names: For Tegra210, Tegra186 and Tegra194 must contain the
|
|
+ strings 'sdhci' and 'tmclk' to represent the module and
|
|
+ the timeout clocks, respectively.
|
|
+ For all other Tegra devices must contain the string 'sdhci'
|
|
+ to represent the module clock.
|
|
- resets : Must contain an entry for each entry in reset-names.
|
|
See ../reset/reset.txt for details.
|
|
- reset-names : Must include the following entries:
|
|
@@ -99,7 +106,7 @@ Optional properties for Tegra210, Tegra186 and Tegra194:
|
|
|
|
Example:
|
|
sdhci@700b0000 {
|
|
- compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
|
|
+ compatible = "nvidia,tegra124-sdhci";
|
|
reg = <0x0 0x700b0000 0x0 0x200>;
|
|
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
|
|
clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
|
|
@@ -115,3 +122,22 @@ sdhci@700b0000 {
|
|
nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
|
|
status = "disabled";
|
|
};
|
|
+
|
|
+sdhci@700b0000 {
|
|
+ compatible = "nvidia,tegra210-sdhci";
|
|
+ reg = <0x0 0x700b0000 0x0 0x200>;
|
|
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
|
|
+ <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
+ resets = <&tegra_car 14>;
|
|
+ reset-names = "sdhci";
|
|
+ pinctrl-names = "sdmmc-3v3", "sdmmc-1v8";
|
|
+ pinctrl-0 = <&sdmmc1_3v3>;
|
|
+ pinctrl-1 = <&sdmmc1_1v8>;
|
|
+ nvidia,pad-autocal-pull-up-offset-3v3 = <0x00>;
|
|
+ nvidia,pad-autocal-pull-down-offset-3v3 = <0x7d>;
|
|
+ nvidia,pad-autocal-pull-up-offset-1v8 = <0x7b>;
|
|
+ nvidia,pad-autocal-pull-down-offset-1v8 = <0x7b>;
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/Makefile b/Makefile
|
|
index 5cf35650373b1..5081bd85af29f 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 5
|
|
PATCHLEVEL = 8
|
|
-SUBLEVEL = 6
|
|
+SUBLEVEL = 7
|
|
EXTRAVERSION =
|
|
NAME = Kleptomaniac Octopus
|
|
|
|
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
|
|
index 58100fb9cd8b5..93236febd327f 100644
|
|
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
|
|
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
|
|
@@ -331,8 +331,9 @@
|
|
compatible = "nvidia,tegra186-sdhci";
|
|
reg = <0x0 0x03400000 0x0 0x10000>;
|
|
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA186_CLK_SDMMC1>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA186_CLK_SDMMC1>,
|
|
+ <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&bpmp TEGRA186_RESET_SDMMC1>;
|
|
reset-names = "sdhci";
|
|
iommus = <&smmu TEGRA186_SID_SDMMC1>;
|
|
@@ -357,8 +358,9 @@
|
|
compatible = "nvidia,tegra186-sdhci";
|
|
reg = <0x0 0x03420000 0x0 0x10000>;
|
|
interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA186_CLK_SDMMC2>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA186_CLK_SDMMC2>,
|
|
+ <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&bpmp TEGRA186_RESET_SDMMC2>;
|
|
reset-names = "sdhci";
|
|
iommus = <&smmu TEGRA186_SID_SDMMC2>;
|
|
@@ -378,8 +380,9 @@
|
|
compatible = "nvidia,tegra186-sdhci";
|
|
reg = <0x0 0x03440000 0x0 0x10000>;
|
|
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA186_CLK_SDMMC3>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA186_CLK_SDMMC3>,
|
|
+ <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&bpmp TEGRA186_RESET_SDMMC3>;
|
|
reset-names = "sdhci";
|
|
iommus = <&smmu TEGRA186_SID_SDMMC3>;
|
|
@@ -401,8 +404,9 @@
|
|
compatible = "nvidia,tegra186-sdhci";
|
|
reg = <0x0 0x03460000 0x0 0x10000>;
|
|
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA186_CLK_SDMMC4>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
|
|
+ <&bpmp TEGRA186_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
assigned-clocks = <&bpmp TEGRA186_CLK_SDMMC4>,
|
|
<&bpmp TEGRA186_CLK_PLLC4_VCO>;
|
|
assigned-clock-parents = <&bpmp TEGRA186_CLK_PLLC4_VCO>;
|
|
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
|
|
index 4bc187a4eacdb..980a8500b4b27 100644
|
|
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
|
|
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
|
|
@@ -453,8 +453,9 @@
|
|
compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
|
|
reg = <0x03400000 0x10000>;
|
|
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA194_CLK_SDMMC1>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA194_CLK_SDMMC1>,
|
|
+ <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&bpmp TEGRA194_RESET_SDMMC1>;
|
|
reset-names = "sdhci";
|
|
nvidia,pad-autocal-pull-up-offset-3v3-timeout =
|
|
@@ -475,8 +476,9 @@
|
|
compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
|
|
reg = <0x03440000 0x10000>;
|
|
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA194_CLK_SDMMC3>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA194_CLK_SDMMC3>,
|
|
+ <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&bpmp TEGRA194_RESET_SDMMC3>;
|
|
reset-names = "sdhci";
|
|
nvidia,pad-autocal-pull-up-offset-1v8 = <0x00>;
|
|
@@ -498,8 +500,9 @@
|
|
compatible = "nvidia,tegra194-sdhci", "nvidia,tegra186-sdhci";
|
|
reg = <0x03460000 0x10000>;
|
|
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&bpmp TEGRA194_CLK_SDMMC4>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
|
|
+ <&bpmp TEGRA194_CLK_SDMMC_LEGACY_TM>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
assigned-clocks = <&bpmp TEGRA194_CLK_SDMMC4>,
|
|
<&bpmp TEGRA194_CLK_PLLC4>;
|
|
assigned-clock-parents =
|
|
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
|
|
index 08655081f72d1..04f3a2d4990de 100644
|
|
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
|
|
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
|
|
@@ -1180,8 +1180,9 @@
|
|
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
|
|
reg = <0x0 0x700b0000 0x0 0x200>;
|
|
interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&tegra_car TEGRA210_CLK_SDMMC1>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&tegra_car TEGRA210_CLK_SDMMC1>,
|
|
+ <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&tegra_car 14>;
|
|
reset-names = "sdhci";
|
|
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
|
|
@@ -1208,8 +1209,9 @@
|
|
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
|
|
reg = <0x0 0x700b0200 0x0 0x200>;
|
|
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&tegra_car TEGRA210_CLK_SDMMC2>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&tegra_car TEGRA210_CLK_SDMMC2>,
|
|
+ <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&tegra_car 9>;
|
|
reset-names = "sdhci";
|
|
pinctrl-names = "sdmmc-1v8-drv";
|
|
@@ -1225,8 +1227,9 @@
|
|
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
|
|
reg = <0x0 0x700b0400 0x0 0x200>;
|
|
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&tegra_car TEGRA210_CLK_SDMMC3>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&tegra_car TEGRA210_CLK_SDMMC3>,
|
|
+ <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&tegra_car 69>;
|
|
reset-names = "sdhci";
|
|
pinctrl-names = "sdmmc-3v3", "sdmmc-1v8",
|
|
@@ -1248,8 +1251,9 @@
|
|
compatible = "nvidia,tegra210-sdhci", "nvidia,tegra124-sdhci";
|
|
reg = <0x0 0x700b0600 0x0 0x200>;
|
|
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
|
- clocks = <&tegra_car TEGRA210_CLK_SDMMC4>;
|
|
- clock-names = "sdhci";
|
|
+ clocks = <&tegra_car TEGRA210_CLK_SDMMC4>,
|
|
+ <&tegra_car TEGRA210_CLK_SDMMC_LEGACY>;
|
|
+ clock-names = "sdhci", "tmclk";
|
|
resets = <&tegra_car 15>;
|
|
reset-names = "sdhci";
|
|
pinctrl-names = "sdmmc-3v3-drv", "sdmmc-1v8-drv";
|
|
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
|
|
index 352aaebf41980..2eff49d81be2d 100644
|
|
--- a/arch/arm64/include/asm/kvm_asm.h
|
|
+++ b/arch/arm64/include/asm/kvm_asm.h
|
|
@@ -121,6 +121,34 @@ extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
|
|
*__hyp_this_cpu_ptr(sym); \
|
|
})
|
|
|
|
+#define __KVM_EXTABLE(from, to) \
|
|
+ " .pushsection __kvm_ex_table, \"a\"\n" \
|
|
+ " .align 3\n" \
|
|
+ " .long (" #from " - .), (" #to " - .)\n" \
|
|
+ " .popsection\n"
|
|
+
|
|
+
|
|
+#define __kvm_at(at_op, addr) \
|
|
+( { \
|
|
+ int __kvm_at_err = 0; \
|
|
+ u64 spsr, elr; \
|
|
+ asm volatile( \
|
|
+ " mrs %1, spsr_el2\n" \
|
|
+ " mrs %2, elr_el2\n" \
|
|
+ "1: at "at_op", %3\n" \
|
|
+ " isb\n" \
|
|
+ " b 9f\n" \
|
|
+ "2: msr spsr_el2, %1\n" \
|
|
+ " msr elr_el2, %2\n" \
|
|
+ " mov %w0, %4\n" \
|
|
+ "9:\n" \
|
|
+ __KVM_EXTABLE(1b, 2b) \
|
|
+ : "+r" (__kvm_at_err), "=&r" (spsr), "=&r" (elr) \
|
|
+ : "r" (addr), "i" (-EFAULT)); \
|
|
+ __kvm_at_err; \
|
|
+} )
|
|
+
|
|
+
|
|
#else /* __ASSEMBLY__ */
|
|
|
|
.macro hyp_adr_this_cpu reg, sym, tmp
|
|
@@ -146,6 +174,21 @@ extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
|
|
kern_hyp_va \vcpu
|
|
.endm
|
|
|
|
+/*
|
|
+ * KVM extable for unexpected exceptions.
|
|
+ * In the same format _asm_extable, but output to a different section so that
|
|
+ * it can be mapped to EL2. The KVM version is not sorted. The caller must
|
|
+ * ensure:
|
|
+ * x18 has the hypervisor value to allow any Shadow-Call-Stack instrumented
|
|
+ * code to write to it, and that SPSR_EL2 and ELR_EL2 are restored by the fixup.
|
|
+ */
|
|
+.macro _kvm_extable, from, to
|
|
+ .pushsection __kvm_ex_table, "a"
|
|
+ .align 3
|
|
+ .long (\from - .), (\to - .)
|
|
+ .popsection
|
|
+.endm
|
|
+
|
|
#endif
|
|
|
|
#endif /* __ARM_KVM_ASM_H__ */
|
|
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
|
|
index 5423ffe0a9876..1417a9042d135 100644
|
|
--- a/arch/arm64/kernel/vmlinux.lds.S
|
|
+++ b/arch/arm64/kernel/vmlinux.lds.S
|
|
@@ -21,6 +21,13 @@ ENTRY(_text)
|
|
|
|
jiffies = jiffies_64;
|
|
|
|
+
|
|
+#define HYPERVISOR_EXTABLE \
|
|
+ . = ALIGN(SZ_8); \
|
|
+ __start___kvm_ex_table = .; \
|
|
+ *(__kvm_ex_table) \
|
|
+ __stop___kvm_ex_table = .;
|
|
+
|
|
#define HYPERVISOR_TEXT \
|
|
/* \
|
|
* Align to 4 KB so that \
|
|
@@ -36,6 +43,7 @@ jiffies = jiffies_64;
|
|
__hyp_idmap_text_end = .; \
|
|
__hyp_text_start = .; \
|
|
*(.hyp.text) \
|
|
+ HYPERVISOR_EXTABLE \
|
|
__hyp_text_end = .;
|
|
|
|
#define IDMAP_TEXT \
|
|
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
|
|
index 90186cf6473e0..c2e6da3564082 100644
|
|
--- a/arch/arm64/kvm/hyp/entry.S
|
|
+++ b/arch/arm64/kvm/hyp/entry.S
|
|
@@ -198,20 +198,23 @@ alternative_endif
|
|
// This is our single instruction exception window. A pending
|
|
// SError is guaranteed to occur at the earliest when we unmask
|
|
// it, and at the latest just after the ISB.
|
|
- .global abort_guest_exit_start
|
|
abort_guest_exit_start:
|
|
|
|
isb
|
|
|
|
- .global abort_guest_exit_end
|
|
abort_guest_exit_end:
|
|
|
|
msr daifset, #4 // Mask aborts
|
|
+ ret
|
|
+
|
|
+ _kvm_extable abort_guest_exit_start, 9997f
|
|
+ _kvm_extable abort_guest_exit_end, 9997f
|
|
+9997:
|
|
+ msr daifset, #4 // Mask aborts
|
|
+ mov x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
|
|
|
|
- // If the exception took place, restore the EL1 exception
|
|
- // context so that we can report some information.
|
|
- // Merge the exception code with the SError pending bit.
|
|
- tbz x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
|
|
+ // restore the EL1 exception context so that we can report some
|
|
+ // information. Merge the exception code with the SError pending bit.
|
|
msr elr_el2, x2
|
|
msr esr_el2, x3
|
|
msr spsr_el2, x4
|
|
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
index 9c5cfb04170ee..741f7cbaeb799 100644
|
|
--- a/arch/arm64/kvm/hyp/hyp-entry.S
|
|
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
|
|
@@ -15,6 +15,30 @@
|
|
#include <asm/kvm_mmu.h>
|
|
#include <asm/mmu.h>
|
|
|
|
+.macro save_caller_saved_regs_vect
|
|
+ /* x0 and x1 were saved in the vector entry */
|
|
+ stp x2, x3, [sp, #-16]!
|
|
+ stp x4, x5, [sp, #-16]!
|
|
+ stp x6, x7, [sp, #-16]!
|
|
+ stp x8, x9, [sp, #-16]!
|
|
+ stp x10, x11, [sp, #-16]!
|
|
+ stp x12, x13, [sp, #-16]!
|
|
+ stp x14, x15, [sp, #-16]!
|
|
+ stp x16, x17, [sp, #-16]!
|
|
+.endm
|
|
+
|
|
+.macro restore_caller_saved_regs_vect
|
|
+ ldp x16, x17, [sp], #16
|
|
+ ldp x14, x15, [sp], #16
|
|
+ ldp x12, x13, [sp], #16
|
|
+ ldp x10, x11, [sp], #16
|
|
+ ldp x8, x9, [sp], #16
|
|
+ ldp x6, x7, [sp], #16
|
|
+ ldp x4, x5, [sp], #16
|
|
+ ldp x2, x3, [sp], #16
|
|
+ ldp x0, x1, [sp], #16
|
|
+.endm
|
|
+
|
|
.text
|
|
.pushsection .hyp.text, "ax"
|
|
|
|
@@ -142,13 +166,19 @@ el1_error:
|
|
b __guest_exit
|
|
|
|
el2_sync:
|
|
- /* Check for illegal exception return, otherwise panic */
|
|
+ /* Check for illegal exception return */
|
|
mrs x0, spsr_el2
|
|
+ tbnz x0, #20, 1f
|
|
|
|
- /* if this was something else, then panic! */
|
|
- tst x0, #PSR_IL_BIT
|
|
- b.eq __hyp_panic
|
|
+ save_caller_saved_regs_vect
|
|
+ stp x29, x30, [sp, #-16]!
|
|
+ bl kvm_unexpected_el2_exception
|
|
+ ldp x29, x30, [sp], #16
|
|
+ restore_caller_saved_regs_vect
|
|
|
|
+ eret
|
|
+
|
|
+1:
|
|
/* Let's attempt a recovery from the illegal exception return */
|
|
get_vcpu_ptr x1, x0
|
|
mov x0, #ARM_EXCEPTION_IL
|
|
@@ -156,27 +186,14 @@ el2_sync:
|
|
|
|
|
|
el2_error:
|
|
- ldp x0, x1, [sp], #16
|
|
+ save_caller_saved_regs_vect
|
|
+ stp x29, x30, [sp, #-16]!
|
|
+
|
|
+ bl kvm_unexpected_el2_exception
|
|
+
|
|
+ ldp x29, x30, [sp], #16
|
|
+ restore_caller_saved_regs_vect
|
|
|
|
- /*
|
|
- * Only two possibilities:
|
|
- * 1) Either we come from the exit path, having just unmasked
|
|
- * PSTATE.A: change the return code to an EL2 fault, and
|
|
- * carry on, as we're already in a sane state to handle it.
|
|
- * 2) Or we come from anywhere else, and that's a bug: we panic.
|
|
- *
|
|
- * For (1), x0 contains the original return code and x1 doesn't
|
|
- * contain anything meaningful at that stage. We can reuse them
|
|
- * as temp registers.
|
|
- * For (2), who cares?
|
|
- */
|
|
- mrs x0, elr_el2
|
|
- adr x1, abort_guest_exit_start
|
|
- cmp x0, x1
|
|
- adr x1, abort_guest_exit_end
|
|
- ccmp x0, x1, #4, ne
|
|
- b.ne __hyp_panic
|
|
- mov x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
|
|
eret
|
|
sb
|
|
|
|
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
|
|
index 9270b14157b55..ba225e09aaf15 100644
|
|
--- a/arch/arm64/kvm/hyp/switch.c
|
|
+++ b/arch/arm64/kvm/hyp/switch.c
|
|
@@ -14,6 +14,7 @@
|
|
|
|
#include <asm/barrier.h>
|
|
#include <asm/cpufeature.h>
|
|
+#include <asm/extable.h>
|
|
#include <asm/kprobes.h>
|
|
#include <asm/kvm_asm.h>
|
|
#include <asm/kvm_emulate.h>
|
|
@@ -24,6 +25,9 @@
|
|
#include <asm/processor.h>
|
|
#include <asm/thread_info.h>
|
|
|
|
+extern struct exception_table_entry __start___kvm_ex_table;
|
|
+extern struct exception_table_entry __stop___kvm_ex_table;
|
|
+
|
|
/* Check whether the FP regs were dirtied while in the host-side run loop: */
|
|
static bool __hyp_text update_fp_enabled(struct kvm_vcpu *vcpu)
|
|
{
|
|
@@ -299,10 +303,10 @@ static bool __hyp_text __translate_far_to_hpfar(u64 far, u64 *hpfar)
|
|
* saved the guest context yet, and we may return early...
|
|
*/
|
|
par = read_sysreg(par_el1);
|
|
- asm volatile("at s1e1r, %0" : : "r" (far));
|
|
- isb();
|
|
-
|
|
- tmp = read_sysreg(par_el1);
|
|
+ if (!__kvm_at("s1e1r", far))
|
|
+ tmp = read_sysreg(par_el1);
|
|
+ else
|
|
+ tmp = SYS_PAR_EL1_F; /* back to the guest */
|
|
write_sysreg(par, par_el1);
|
|
|
|
if (unlikely(tmp & SYS_PAR_EL1_F))
|
|
@@ -934,3 +938,30 @@ void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *host_ctxt)
|
|
|
|
unreachable();
|
|
}
|
|
+
|
|
+asmlinkage void __hyp_text kvm_unexpected_el2_exception(void)
|
|
+{
|
|
+ unsigned long addr, fixup;
|
|
+ struct kvm_cpu_context *host_ctxt;
|
|
+ struct exception_table_entry *entry, *end;
|
|
+ unsigned long elr_el2 = read_sysreg(elr_el2);
|
|
+
|
|
+ entry = hyp_symbol_addr(__start___kvm_ex_table);
|
|
+ end = hyp_symbol_addr(__stop___kvm_ex_table);
|
|
+ host_ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt;
|
|
+
|
|
+ while (entry < end) {
|
|
+ addr = (unsigned long)&entry->insn + entry->insn;
|
|
+ fixup = (unsigned long)&entry->fixup + entry->fixup;
|
|
+
|
|
+ if (addr != elr_el2) {
|
|
+ entry++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ write_sysreg(fixup, elr_el2);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ hyp_panic(host_ctxt);
|
|
+}
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index 359616e3efbbb..d2ecc9c452554 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -1597,6 +1597,17 @@ static void hid_output_field(const struct hid_device *hid,
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Compute the size of a report.
|
|
+ */
|
|
+static size_t hid_compute_report_size(struct hid_report *report)
|
|
+{
|
|
+ if (report->size)
|
|
+ return ((report->size - 1) >> 3) + 1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* Create a report. 'data' has to be allocated using
|
|
* hid_alloc_report_buf() so that it has proper size.
|
|
@@ -1609,7 +1620,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
|
|
if (report->id > 0)
|
|
*data++ = report->id;
|
|
|
|
- memset(data, 0, ((report->size - 1) >> 3) + 1);
|
|
+ memset(data, 0, hid_compute_report_size(report));
|
|
for (n = 0; n < report->maxfield; n++)
|
|
hid_output_field(report->device, report->field[n], data);
|
|
}
|
|
@@ -1739,7 +1750,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
|
|
csize--;
|
|
}
|
|
|
|
- rsize = ((report->size - 1) >> 3) + 1;
|
|
+ rsize = hid_compute_report_size(report);
|
|
|
|
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
|
|
rsize = HID_MAX_BUFFER_SIZE - 1;
|
|
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
|
|
index e8641ce677e47..e3d475f4baf66 100644
|
|
--- a/drivers/hid/hid-input.c
|
|
+++ b/drivers/hid/hid-input.c
|
|
@@ -1132,6 +1132,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
|
}
|
|
|
|
mapped:
|
|
+ /* Mapping failed, bail out */
|
|
+ if (!bit)
|
|
+ return;
|
|
+
|
|
if (device->driver->input_mapped &&
|
|
device->driver->input_mapped(device, hidinput, field, usage,
|
|
&bit, &max) < 0) {
|
|
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
|
|
index 3f94b4954225b..e3152155c4b85 100644
|
|
--- a/drivers/hid/hid-multitouch.c
|
|
+++ b/drivers/hid/hid-multitouch.c
|
|
@@ -856,6 +856,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
code = BTN_0 + ((usage->hid - 1) & HID_USAGE);
|
|
|
|
hid_map_usage(hi, usage, bit, max, EV_KEY, code);
|
|
+ if (!*bit)
|
|
+ return -1;
|
|
input_set_capability(hi->input, EV_KEY, code);
|
|
return 1;
|
|
|
|
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
index 2322f08a98be6..5e057f798a15b 100644
|
|
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
|
|
@@ -3186,14 +3186,16 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
|
|
#ifdef CONFIG_COMPAT_32BIT_TIME
|
|
case VIDIOC_DQEVENT_TIME32: {
|
|
struct v4l2_event *ev = parg;
|
|
- struct v4l2_event_time32 ev32 = {
|
|
- .type = ev->type,
|
|
- .pending = ev->pending,
|
|
- .sequence = ev->sequence,
|
|
- .timestamp.tv_sec = ev->timestamp.tv_sec,
|
|
- .timestamp.tv_nsec = ev->timestamp.tv_nsec,
|
|
- .id = ev->id,
|
|
- };
|
|
+ struct v4l2_event_time32 ev32;
|
|
+
|
|
+ memset(&ev32, 0, sizeof(ev32));
|
|
+
|
|
+ ev32.type = ev->type;
|
|
+ ev32.pending = ev->pending;
|
|
+ ev32.sequence = ev->sequence;
|
|
+ ev32.timestamp.tv_sec = ev->timestamp.tv_sec;
|
|
+ ev32.timestamp.tv_nsec = ev->timestamp.tv_nsec;
|
|
+ ev32.id = ev->id;
|
|
|
|
memcpy(&ev32.u, &ev->u, sizeof(ev->u));
|
|
memcpy(&ev32.reserved, &ev->reserved, sizeof(ev->reserved));
|
|
@@ -3207,21 +3209,23 @@ static int video_put_user(void __user *arg, void *parg, unsigned int cmd)
|
|
case VIDIOC_DQBUF_TIME32:
|
|
case VIDIOC_PREPARE_BUF_TIME32: {
|
|
struct v4l2_buffer *vb = parg;
|
|
- struct v4l2_buffer_time32 vb32 = {
|
|
- .index = vb->index,
|
|
- .type = vb->type,
|
|
- .bytesused = vb->bytesused,
|
|
- .flags = vb->flags,
|
|
- .field = vb->field,
|
|
- .timestamp.tv_sec = vb->timestamp.tv_sec,
|
|
- .timestamp.tv_usec = vb->timestamp.tv_usec,
|
|
- .timecode = vb->timecode,
|
|
- .sequence = vb->sequence,
|
|
- .memory = vb->memory,
|
|
- .m.userptr = vb->m.userptr,
|
|
- .length = vb->length,
|
|
- .request_fd = vb->request_fd,
|
|
- };
|
|
+ struct v4l2_buffer_time32 vb32;
|
|
+
|
|
+ memset(&vb32, 0, sizeof(vb32));
|
|
+
|
|
+ vb32.index = vb->index;
|
|
+ vb32.type = vb->type;
|
|
+ vb32.bytesused = vb->bytesused;
|
|
+ vb32.flags = vb->flags;
|
|
+ vb32.field = vb->field;
|
|
+ vb32.timestamp.tv_sec = vb->timestamp.tv_sec;
|
|
+ vb32.timestamp.tv_usec = vb->timestamp.tv_usec;
|
|
+ vb32.timecode = vb->timecode;
|
|
+ vb32.sequence = vb->sequence;
|
|
+ vb32.memory = vb->memory;
|
|
+ vb32.m.userptr = vb->m.userptr;
|
|
+ vb32.length = vb->length;
|
|
+ vb32.request_fd = vb->request_fd;
|
|
|
|
if (copy_to_user(arg, &vb32, sizeof(vb32)))
|
|
return -EFAULT;
|
|
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
|
|
index 3a372ab3d12e8..db1a8d1c96b36 100644
|
|
--- a/drivers/mmc/host/sdhci-tegra.c
|
|
+++ b/drivers/mmc/host/sdhci-tegra.c
|
|
@@ -1409,7 +1409,6 @@ static const struct sdhci_ops tegra210_sdhci_ops = {
|
|
|
|
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
|
|
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
|
|
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
|
SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
|
SDHCI_QUIRK_NO_HISPD_BIT |
|
|
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
|
|
@@ -1447,7 +1446,6 @@ static const struct sdhci_ops tegra186_sdhci_ops = {
|
|
|
|
static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
|
|
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
|
|
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
|
SDHCI_QUIRK_SINGLE_POWER_WRITE |
|
|
SDHCI_QUIRK_NO_HISPD_BIT |
|
|
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
|
|
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
|
|
index 9ab960cc39b6f..0209bc23e631e 100644
|
|
--- a/drivers/target/target_core_user.c
|
|
+++ b/drivers/target/target_core_user.c
|
|
@@ -676,8 +676,10 @@ static void scatter_data_area(struct tcmu_dev *udev,
|
|
from = kmap_atomic(sg_page(sg)) + sg->offset;
|
|
while (sg_remaining > 0) {
|
|
if (block_remaining == 0) {
|
|
- if (to)
|
|
+ if (to) {
|
|
+ flush_dcache_page(page);
|
|
kunmap_atomic(to);
|
|
+ }
|
|
|
|
block_remaining = DATA_BLOCK_SIZE;
|
|
dbi = tcmu_cmd_get_dbi(tcmu_cmd);
|
|
@@ -722,7 +724,6 @@ static void scatter_data_area(struct tcmu_dev *udev,
|
|
memcpy(to + offset,
|
|
from + sg->length - sg_remaining,
|
|
copy_bytes);
|
|
- tcmu_flush_dcache_range(to, copy_bytes);
|
|
}
|
|
|
|
sg_remaining -= copy_bytes;
|
|
@@ -731,8 +732,10 @@ static void scatter_data_area(struct tcmu_dev *udev,
|
|
kunmap_atomic(from - sg->offset);
|
|
}
|
|
|
|
- if (to)
|
|
+ if (to) {
|
|
+ flush_dcache_page(page);
|
|
kunmap_atomic(to);
|
|
+ }
|
|
}
|
|
|
|
static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
|
|
@@ -778,13 +781,13 @@ static void gather_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd,
|
|
dbi = tcmu_cmd_get_dbi(cmd);
|
|
page = tcmu_get_block_page(udev, dbi);
|
|
from = kmap_atomic(page);
|
|
+ flush_dcache_page(page);
|
|
}
|
|
copy_bytes = min_t(size_t, sg_remaining,
|
|
block_remaining);
|
|
if (read_len < copy_bytes)
|
|
copy_bytes = read_len;
|
|
offset = DATA_BLOCK_SIZE - block_remaining;
|
|
- tcmu_flush_dcache_range(from, copy_bytes);
|
|
memcpy(to + sg->length - sg_remaining, from + offset,
|
|
copy_bytes);
|
|
|
|
diff --git a/include/linux/hid.h b/include/linux/hid.h
|
|
index 875f71132b142..c7044a14200ea 100644
|
|
--- a/include/linux/hid.h
|
|
+++ b/include/linux/hid.h
|
|
@@ -959,34 +959,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) {
|
|
* @max: maximal valid usage->code to consider later (out parameter)
|
|
* @type: input event type (EV_KEY, EV_REL, ...)
|
|
* @c: code which corresponds to this usage and type
|
|
+ *
|
|
+ * The value pointed to by @bit will be set to NULL if either @type is
|
|
+ * an unhandled event type, or if @c is out of range for @type. This
|
|
+ * can be used as an error condition.
|
|
*/
|
|
static inline void hid_map_usage(struct hid_input *hidinput,
|
|
struct hid_usage *usage, unsigned long **bit, int *max,
|
|
- __u8 type, __u16 c)
|
|
+ __u8 type, unsigned int c)
|
|
{
|
|
struct input_dev *input = hidinput->input;
|
|
-
|
|
- usage->type = type;
|
|
- usage->code = c;
|
|
+ unsigned long *bmap = NULL;
|
|
+ unsigned int limit = 0;
|
|
|
|
switch (type) {
|
|
case EV_ABS:
|
|
- *bit = input->absbit;
|
|
- *max = ABS_MAX;
|
|
+ bmap = input->absbit;
|
|
+ limit = ABS_MAX;
|
|
break;
|
|
case EV_REL:
|
|
- *bit = input->relbit;
|
|
- *max = REL_MAX;
|
|
+ bmap = input->relbit;
|
|
+ limit = REL_MAX;
|
|
break;
|
|
case EV_KEY:
|
|
- *bit = input->keybit;
|
|
- *max = KEY_MAX;
|
|
+ bmap = input->keybit;
|
|
+ limit = KEY_MAX;
|
|
break;
|
|
case EV_LED:
|
|
- *bit = input->ledbit;
|
|
- *max = LED_MAX;
|
|
+ bmap = input->ledbit;
|
|
+ limit = LED_MAX;
|
|
break;
|
|
}
|
|
+
|
|
+ if (unlikely(c > limit || !bmap)) {
|
|
+ pr_warn_ratelimited("%s: Invalid code %d type %d\n",
|
|
+ input->name, c, type);
|
|
+ *bit = NULL;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ usage->type = type;
|
|
+ usage->code = c;
|
|
+ *max = limit;
|
|
+ *bit = bmap;
|
|
}
|
|
|
|
/**
|
|
@@ -1000,7 +1015,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
|
|
__u8 type, __u16 c)
|
|
{
|
|
hid_map_usage(hidinput, usage, bit, max, type, c);
|
|
- clear_bit(c, *bit);
|
|
+ if (*bit)
|
|
+ clear_bit(usage->code, *bit);
|
|
}
|
|
|
|
/**
|
|
diff --git a/mm/gup.c b/mm/gup.c
|
|
index 6f47697f8fb0b..0d8d76f10ac61 100644
|
|
--- a/mm/gup.c
|
|
+++ b/mm/gup.c
|
|
@@ -843,7 +843,7 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address,
|
|
goto unmap;
|
|
*page = pte_page(*pte);
|
|
}
|
|
- if (unlikely(!try_get_page(*page))) {
|
|
+ if (unlikely(!try_grab_page(*page, gup_flags))) {
|
|
ret = -ENOMEM;
|
|
goto unmap;
|
|
}
|
|
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
|
|
index b6aad3fc46c35..b85ce6f0c0a6f 100644
|
|
--- a/net/netfilter/nft_set_rbtree.c
|
|
+++ b/net/netfilter/nft_set_rbtree.c
|
|
@@ -238,21 +238,27 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
*
|
|
* b1. _ _ __>| !_ _ __| (insert end before existing start)
|
|
* b2. _ _ ___| !_ _ _>| (insert end after existing start)
|
|
- * b3. _ _ ___! >|_ _ __| (insert start after existing end)
|
|
+ * b3. _ _ ___! >|_ _ __| (insert start after existing end, as a leaf)
|
|
+ * '--' no nodes falling in this range
|
|
+ * b4. >|_ _ ! (insert start before existing start)
|
|
*
|
|
* Case a3. resolves to b3.:
|
|
* - if the inserted start element is the leftmost, because the '0'
|
|
* element in the tree serves as end element
|
|
- * - otherwise, if an existing end is found. Note that end elements are
|
|
- * always inserted after corresponding start elements.
|
|
+ * - otherwise, if an existing end is found immediately to the left. If
|
|
+ * there are existing nodes in between, we need to further descend the
|
|
+ * tree before we can conclude the new start isn't causing an overlap
|
|
+ *
|
|
+ * or to b4., which, preceded by a3., means we already traversed one or
|
|
+ * more existing intervals entirely, from the right.
|
|
*
|
|
* For a new, rightmost pair of elements, we'll hit cases b3. and b2.,
|
|
* in that order.
|
|
*
|
|
* The flag is also cleared in two special cases:
|
|
*
|
|
- * b4. |__ _ _!|<_ _ _ (insert start right before existing end)
|
|
- * b5. |__ _ >|!__ _ _ (insert end right after existing start)
|
|
+ * b5. |__ _ _!|<_ _ _ (insert start right before existing end)
|
|
+ * b6. |__ _ >|!__ _ _ (insert end right after existing start)
|
|
*
|
|
* which always happen as last step and imply that no further
|
|
* overlapping is possible.
|
|
@@ -272,7 +278,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
if (nft_rbtree_interval_start(new)) {
|
|
if (nft_rbtree_interval_end(rbe) &&
|
|
nft_set_elem_active(&rbe->ext, genmask) &&
|
|
- !nft_set_elem_expired(&rbe->ext))
|
|
+ !nft_set_elem_expired(&rbe->ext) && !*p)
|
|
overlap = false;
|
|
} else {
|
|
overlap = nft_rbtree_interval_end(rbe) &&
|
|
@@ -288,10 +294,9 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
|
|
nft_set_elem_active(&rbe->ext,
|
|
genmask) &&
|
|
!nft_set_elem_expired(&rbe->ext);
|
|
- } else if (nft_rbtree_interval_end(rbe) &&
|
|
- nft_set_elem_active(&rbe->ext, genmask) &&
|
|
+ } else if (nft_set_elem_active(&rbe->ext, genmask) &&
|
|
!nft_set_elem_expired(&rbe->ext)) {
|
|
- overlap = true;
|
|
+ overlap = nft_rbtree_interval_end(rbe);
|
|
}
|
|
} else {
|
|
if (nft_rbtree_interval_end(rbe) &&
|
|
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
|
|
index 7fbca0854265a..279c87a2a523b 100644
|
|
--- a/net/wireless/nl80211.c
|
|
+++ b/net/wireless/nl80211.c
|
|
@@ -6010,7 +6010,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
if (info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY])
|
|
params.he_6ghz_capa =
|
|
- nla_data(info->attrs[NL80211_ATTR_HE_CAPABILITY]);
|
|
+ nla_data(info->attrs[NL80211_ATTR_HE_6GHZ_CAPABILITY]);
|
|
|
|
if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
|
|
params.airtime_weight =
|
|
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
|
|
index fa8a5fcd27aba..950e4ad213747 100644
|
|
--- a/tools/perf/Documentation/perf-record.txt
|
|
+++ b/tools/perf/Documentation/perf-record.txt
|
|
@@ -33,6 +33,10 @@ OPTIONS
|
|
- a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
|
|
hexadecimal event descriptor.
|
|
|
|
+ - a symbolic or raw PMU event followed by an optional colon
|
|
+ and a list of event modifiers, e.g., cpu-cycles:p. See the
|
|
+ linkperf:perf-list[1] man page for details on event modifiers.
|
|
+
|
|
- a symbolically formed PMU event like 'pmu/param1=0x3,param2/' where
|
|
'param1', 'param2', etc are defined as formats for the PMU in
|
|
/sys/bus/event_source/devices/<pmu>/format/*.
|
|
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
|
|
index b029ee728a0bc..c8209467076b1 100644
|
|
--- a/tools/perf/Documentation/perf-stat.txt
|
|
+++ b/tools/perf/Documentation/perf-stat.txt
|
|
@@ -39,6 +39,10 @@ report::
|
|
- a raw PMU event (eventsel+umask) in the form of rNNN where NNN is a
|
|
hexadecimal event descriptor.
|
|
|
|
+ - a symbolic or raw PMU event followed by an optional colon
|
|
+ and a list of event modifiers, e.g., cpu-cycles:p. See the
|
|
+ linkperf:perf-list[1] man page for details on event modifiers.
|
|
+
|
|
- a symbolically formed event like 'pmu/param1=0x3,param2/' where
|
|
param1 and param2 are defined as formats for the PMU in
|
|
/sys/bus/event_source/devices/<pmu>/format/*
|
|
diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c
|
|
index c41f24b517f40..65c141ebfbbde 100644
|
|
--- a/tools/testing/selftests/x86/test_vsyscall.c
|
|
+++ b/tools/testing/selftests/x86/test_vsyscall.c
|
|
@@ -462,6 +462,17 @@ static int test_vsys_x(void)
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Debuggers expect ptrace() to be able to peek at the vsyscall page.
|
|
+ * Use process_vm_readv() as a proxy for ptrace() to test this. We
|
|
+ * want it to work in the vsyscall=emulate case and to fail in the
|
|
+ * vsyscall=xonly case.
|
|
+ *
|
|
+ * It's worth noting that this ABI is a bit nutty. write(2) can't
|
|
+ * read from the vsyscall page on any kernel version or mode. The
|
|
+ * fact that ptrace() ever worked was a nice courtesy of old kernels,
|
|
+ * but the code to support it is fairly gross.
|
|
+ */
|
|
static int test_process_vm_readv(void)
|
|
{
|
|
#ifdef __x86_64__
|
|
@@ -477,8 +488,12 @@ static int test_process_vm_readv(void)
|
|
remote.iov_len = 4096;
|
|
ret = process_vm_readv(getpid(), &local, 1, &remote, 1, 0);
|
|
if (ret != 4096) {
|
|
- printf("[OK]\tprocess_vm_readv() failed (ret = %d, errno = %d)\n", ret, errno);
|
|
- return 0;
|
|
+ /*
|
|
+ * We expect process_vm_readv() to work if and only if the
|
|
+ * vsyscall page is readable.
|
|
+ */
|
|
+ printf("[%s]\tprocess_vm_readv() failed (ret = %d, errno = %d)\n", vsyscall_map_r ? "FAIL" : "OK", ret, errno);
|
|
+ return vsyscall_map_r ? 1 : 0;
|
|
}
|
|
|
|
if (vsyscall_map_r) {
|
|
@@ -488,6 +503,9 @@ static int test_process_vm_readv(void)
|
|
printf("[FAIL]\tIt worked but returned incorrect data\n");
|
|
return 1;
|
|
}
|
|
+ } else {
|
|
+ printf("[FAIL]\tprocess_rm_readv() succeeded, but it should have failed in this configuration\n");
|
|
+ return 1;
|
|
}
|
|
#endif
|
|
|