mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
arm64 updates for 6.10
ACPI: * Support for the Firmware ACPI Control Structure (FACS) signature feature which is used to reboot out of hibernation on some systems. Kbuild: * Support for building Flat Image Tree (FIT) images, where the kernel Image is compressed alongside a set of devicetree blobs. Memory management: * Optimisation of our early page-table manipulation for creation of the linear mapping. * Support for userfaultfd write protection, which brings along some nice cleanups to our handling of invalid but present ptes. * Extend our use of range TLBI invalidation at EL1. Perf and PMUs: * Ensure that the 'pmu->parent' pointer is correctly initialised by PMU drivers. * Avoid allocating 'cpumask_t' types on the stack in some PMU drivers. * Fix parsing of the CPU PMU "version" field in assembly code, as it doesn't follow the usual architectural rules. * Add best-effort unwinding support for USER_STACKTRACE * Minor driver fixes and cleanups. Selftests: * Minor cleanups to the arm64 selftests (missing NULL check, unused variable). Miscellaneous * Add a command-line alias for disabling 32-bit application support. * Add part number for Neoverse-V2 CPUs. * Minor fixes and cleanups. -----BEGIN PGP SIGNATURE----- iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAmY+IWkQHHdpbGxAa2Vy bmVsLm9yZwAKCRC3rHDchMFjNBVNB/9JG4jlmgxzbTDoer0md31YFvWCDGeOKx1x g3XhE24W5w8eLXnc75p7/tOUKfo0TNWL4qdUs0hJCEUAOSy6a4Qz13bkkkvvBtDm nnHvEjidx5yprHggocsoTF29CKgHMJ3bt8rJe6g+O3Lp1JAFlXXNgplX5koeaVtm TtaFvX9MGyDDNkPIcQ/SQTFZJ2Oz51+ik6O8SYuGYtmAcR7MzlxH77lHl2mrF1bf Jzv/f5n0lS+Gt9tRuFWhbfEm4aKdUlLha4ufzUq42/vJvELboZbG3LqLxRG8DbqR +HvyZOG/xtu2dbzDqHkRumMToWmwzD4oBGSK4JAoJxeHavEdAvSG =JMvT -----END PGP SIGNATURE----- Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux Pull arm64 updates from Will Deacon: "The most interesting parts are probably the mm changes from Ryan which optimise the creation of the linear mapping at boot and (separately) implement write-protect support for userfaultfd. Outside of our usual directories, the Kbuild-related changes under scripts/ have been acked by Masahiro whilst the drivers/acpi/ parts have been acked by Rafael and the addition of cpumask_any_and_but() has been acked by Yury. ACPI: - Support for the Firmware ACPI Control Structure (FACS) signature feature which is used to reboot out of hibernation on some systems Kbuild: - Support for building Flat Image Tree (FIT) images, where the kernel Image is compressed alongside a set of devicetree blobs Memory management: - Optimisation of our early page-table manipulation for creation of the linear mapping - Support for userfaultfd write protection, which brings along some nice cleanups to our handling of invalid but present ptes - Extend our use of range TLBI invalidation at EL1 Perf and PMUs: - Ensure that the 'pmu->parent' pointer is correctly initialised by PMU drivers - Avoid allocating 'cpumask_t' types on the stack in some PMU drivers - Fix parsing of the CPU PMU "version" field in assembly code, as it doesn't follow the usual architectural rules - Add best-effort unwinding support for USER_STACKTRACE - Minor driver fixes and cleanups Selftests: - Minor cleanups to the arm64 selftests (missing NULL check, unused variable) Miscellaneous: - Add a command-line alias for disabling 32-bit application support - Add part number for Neoverse-V2 CPUs - Minor fixes and cleanups" * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (64 commits) arm64/mm: Fix pud_user_accessible_page() for PGTABLE_LEVELS <= 2 arm64/mm: Add uffd write-protect support arm64/mm: Move PTE_PRESENT_INVALID to overlay PTE_NG arm64/mm: Remove PTE_PROT_NONE bit arm64/mm: generalize PMD_PRESENT_INVALID for all levels arm64: simplify arch_static_branch/_jump function arm64: Add USER_STACKTRACE support arm64: Add the arm64.no32bit_el0 command line option drivers/perf: hisi: hns3: Actually use devm_add_action_or_reset() drivers/perf: hisi: hns3: Fix out-of-bound access when valid event group drivers/perf: hisi_pcie: Fix out-of-bound access when valid event group kselftest: arm64: Add a null pointer check arm64: defer clearing DAIF.D arm64: assembler: update stale comment for disable_step_tsk arm64/sysreg: Update PIE permission encodings kselftest/arm64: Remove unused parameters in abi test perf/arm-spe: Assign parents for event_source device perf/arm-smmuv3: Assign parents for event_source device perf/arm-dsu: Assign parents for event_source device perf/arm-dmc620: Assign parents for event_source device ...
This commit is contained in:
commit
103916ffe2
@ -431,6 +431,9 @@
|
||||
arcrimi= [HW,NET] ARCnet - "RIM I" (entirely mem-mapped) cards
|
||||
Format: <io>,<irq>,<nodeID>
|
||||
|
||||
arm64.no32bit_el0 [ARM64] Unconditionally disable the execution of
|
||||
32 bit applications.
|
||||
|
||||
arm64.nobti [ARM64] Unconditionally disable Branch Target
|
||||
Identification support
|
||||
|
||||
|
@ -20,7 +20,6 @@ interrupt, and the PMU driver shall register perf PMU drivers like L3C,
|
||||
HHA and DDRC etc. The available events and configuration options shall
|
||||
be described in the sysfs, see:
|
||||
|
||||
/sys/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>/, or
|
||||
/sys/bus/event_source/devices/hisi_sccl{X}_<l3c{Y}/hha{Y}/ddrc{Y}>.
|
||||
The "perf list" command shall list the available events from sysfs.
|
||||
|
||||
|
@ -16,7 +16,7 @@ HNS3 PMU driver
|
||||
|
||||
The HNS3 PMU driver registers a perf PMU with the name of its sicl id.::
|
||||
|
||||
/sys/devices/hns3_pmu_sicl_<sicl_id>
|
||||
/sys/bus/event_source/devices/hns3_pmu_sicl_<sicl_id>
|
||||
|
||||
PMU driver provides description of available events, filter modes, format,
|
||||
identifier and cpumask in sysfs.
|
||||
@ -40,9 +40,9 @@ device.
|
||||
|
||||
Example usage of checking event code and subevent code::
|
||||
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_time
|
||||
$# cat /sys/bus/event_source/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_time
|
||||
config=0x00204
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_packet_num
|
||||
$# cat /sys/bus/event_source/devices/hns3_pmu_sicl_0/events/dly_tx_normal_to_mac_packet_num
|
||||
config=0x10204
|
||||
|
||||
Each performance statistic has a pair of events to get two values to
|
||||
@ -60,7 +60,7 @@ computation to calculate real performance data is:::
|
||||
|
||||
Example usage of checking supported filter mode::
|
||||
|
||||
$# cat /sys/devices/hns3_pmu_sicl_0/filtermode/bw_ssu_rpu_byte_num
|
||||
$# cat /sys/bus/event_source/devices/hns3_pmu_sicl_0/filtermode/bw_ssu_rpu_byte_num
|
||||
filter mode supported: global/port/port-tc/func/func-queue/
|
||||
|
||||
Example usage of perf::
|
||||
|
@ -10,7 +10,7 @@ There is one logical L2 PMU exposed, which aggregates the results from
|
||||
the physical PMUs.
|
||||
|
||||
The driver provides a description of its available events and configuration
|
||||
options in sysfs, see /sys/devices/l2cache_0.
|
||||
options in sysfs, see /sys/bus/event_source/devices/l2cache_0.
|
||||
|
||||
The "format" directory describes the format of the events.
|
||||
|
||||
|
@ -9,7 +9,7 @@ PMU with device name l3cache_<socket>_<instance>. User space is responsible
|
||||
for aggregating across slices.
|
||||
|
||||
The driver provides a description of its available events and configuration
|
||||
options in sysfs, see /sys/devices/l3cache*. Given that these are uncore PMUs
|
||||
options in sysfs, see /sys/bus/event_source/devices/l3cache*. Given that these are uncore PMUs
|
||||
the driver also exposes a "cpumask" sysfs attribute which contains a mask
|
||||
consisting of one CPU per socket which will be used to handle all the PMU
|
||||
events on that socket.
|
||||
|
@ -22,7 +22,7 @@ The thunderx2_pmu driver registers per-socket perf PMUs for the DMC and
|
||||
L3C devices. Each PMU can be used to count up to 4 (DMC/L3C) or up to 8
|
||||
(CCPI2) events simultaneously. The PMUs provide a description of their
|
||||
available events and configuration options under sysfs, see
|
||||
/sys/devices/uncore_<l3c_S/dmc_S/ccpi2_S/>; S is the socket id.
|
||||
/sys/bus/event_source/devices/uncore_<l3c_S/dmc_S/ccpi2_S/>; S is the socket id.
|
||||
|
||||
The driver does not support sampling, therefore "perf record" will not
|
||||
work. Per-task perf sessions are also not supported.
|
||||
|
@ -13,7 +13,7 @@ PMU (perf) driver
|
||||
|
||||
The xgene-pmu driver registers several perf PMU drivers. Each of the perf
|
||||
driver provides description of its available events and configuration options
|
||||
in sysfs, see /sys/devices/<l3cX/iobX/mcbX/mcX>/.
|
||||
in sysfs, see /sys/bus/event_source/devices/<l3cX/iobX/mcbX/mcX>/.
|
||||
|
||||
The "format" directory describes format of the config (event ID),
|
||||
config1 (agent ID) fields of the perf_event_attr structure. The "events"
|
||||
|
@ -62,6 +62,7 @@ Sphinx\ [#f1]_ 2.4.4 sphinx-build --version
|
||||
cpio any cpio --version
|
||||
GNU tar 1.28 tar --version
|
||||
gtags (optional) 6.6.5 gtags --version
|
||||
mkimage (optional) 2017.01 mkimage --version
|
||||
====================== =============== ========================================
|
||||
|
||||
.. [#f1] Sphinx is needed only to build the Kernel documentation
|
||||
@ -189,6 +190,14 @@ The kernel build requires GNU GLOBAL version 6.6.5 or later to generate
|
||||
tag files through ``make gtags``. This is due to its use of the gtags
|
||||
``-C (--directory)`` flag.
|
||||
|
||||
mkimage
|
||||
-------
|
||||
|
||||
This tool is used when building a Flat Image Tree (FIT), commonly used on ARM
|
||||
platforms. The tool is available via the ``u-boot-tools`` package or can be
|
||||
built from the U-Boot source code. See the instructions at
|
||||
https://docs.u-boot.org/en/latest/build/tools.html#building-tools-for-linux
|
||||
|
||||
System utilities
|
||||
****************
|
||||
|
||||
|
@ -3073,6 +3073,13 @@ F: drivers/mmc/host/sdhci-of-arasan.c
|
||||
N: zynq
|
||||
N: xilinx
|
||||
|
||||
ARM64 FIT SUPPORT
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: arch/arm64/boot/Makefile
|
||||
F: scripts/make_fit.py
|
||||
|
||||
ARM64 PORT (AARCH64 ARCHITECTURE)
|
||||
M: Catalin Marinas <catalin.marinas@arm.com>
|
||||
M: Will Deacon <will@kernel.org>
|
||||
|
@ -255,9 +255,11 @@ config ARM64
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
select THREAD_INFO_IN_TASK
|
||||
select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD
|
||||
select HAVE_ARCH_USERFAULTFD_WP if USERFAULTFD
|
||||
select TRACE_IRQFLAGS_SUPPORT
|
||||
select TRACE_IRQFLAGS_NMI_SUPPORT
|
||||
select HAVE_SOFTIRQ_ON_OWN_STACK
|
||||
select USER_STACKTRACE_SUPPORT
|
||||
help
|
||||
ARM 64-bit (AArch64) Linux support.
|
||||
|
||||
|
@ -154,6 +154,10 @@ libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
# Default target when executing plain make
|
||||
boot := arch/arm64/boot
|
||||
|
||||
BOOT_TARGETS := Image vmlinuz.efi image.fit
|
||||
|
||||
PHONY += $(BOOT_TARGETS)
|
||||
|
||||
ifeq ($(CONFIG_EFI_ZBOOT),)
|
||||
KBUILD_IMAGE := $(boot)/Image.gz
|
||||
else
|
||||
@ -162,8 +166,10 @@ endif
|
||||
|
||||
all: $(notdir $(KBUILD_IMAGE))
|
||||
|
||||
vmlinuz.efi: Image
|
||||
Image vmlinuz.efi: vmlinux
|
||||
image.fit: dtbs
|
||||
|
||||
vmlinuz.efi image.fit: Image
|
||||
$(BOOT_TARGETS): vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
Image.%: Image
|
||||
@ -215,6 +221,7 @@ virtconfig:
|
||||
define archhelp
|
||||
echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
|
||||
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
|
||||
echo ' image.fit - Flat Image Tree (arch/$(ARCH)/boot/image.fit)'
|
||||
echo ' install - Install uncompressed kernel'
|
||||
echo ' zinstall - Install compressed kernel'
|
||||
echo ' Install using (your) ~/bin/installkernel or'
|
||||
|
1
arch/arm64/boot/.gitignore
vendored
1
arch/arm64/boot/.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
Image
|
||||
Image.gz
|
||||
vmlinuz*
|
||||
image.fit
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
|
||||
|
||||
targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo Image.zst
|
||||
targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo \
|
||||
Image.zst image.fit
|
||||
|
||||
$(obj)/Image: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@ -39,6 +40,9 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
|
||||
$(obj)/Image.zst: $(obj)/Image FORCE
|
||||
$(call if_changed,zstd)
|
||||
|
||||
$(obj)/image.fit: $(obj)/Image $(obj)/dts/dtbs-list FORCE
|
||||
$(call if_changed,fit)
|
||||
|
||||
EFI_ZBOOT_PAYLOAD := Image
|
||||
EFI_ZBOOT_BFD_TARGET := elf64-littleaarch64
|
||||
EFI_ZBOOT_MACH_TYPE := ARM64
|
||||
|
@ -50,16 +50,12 @@
|
||||
msr daif, \flags
|
||||
.endm
|
||||
|
||||
.macro enable_dbg
|
||||
msr daifclr, #8
|
||||
.endm
|
||||
|
||||
.macro disable_step_tsk, flgs, tmp
|
||||
tbz \flgs, #TIF_SINGLESTEP, 9990f
|
||||
mrs \tmp, mdscr_el1
|
||||
bic \tmp, \tmp, #DBG_MDSCR_SS
|
||||
msr mdscr_el1, \tmp
|
||||
isb // Synchronise with enable_dbg
|
||||
isb // Take effect before a subsequent clear of DAIF.D
|
||||
9990:
|
||||
.endm
|
||||
|
||||
@ -480,9 +476,10 @@ alternative_endif
|
||||
*/
|
||||
.macro reset_pmuserenr_el0, tmpreg
|
||||
mrs \tmpreg, id_aa64dfr0_el1
|
||||
sbfx \tmpreg, \tmpreg, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp \tmpreg, #1 // Skip if no PMU present
|
||||
b.lt 9000f
|
||||
ubfx \tmpreg, \tmpreg, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp \tmpreg, #ID_AA64DFR0_EL1_PMUVer_NI
|
||||
ccmp \tmpreg, #ID_AA64DFR0_EL1_PMUVer_IMP_DEF, #4, ne
|
||||
b.eq 9000f // Skip if no PMU present or IMP_DEF
|
||||
msr pmuserenr_el0, xzr // Disable PMU access from EL0
|
||||
9000:
|
||||
.endm
|
||||
|
@ -86,6 +86,7 @@
|
||||
#define ARM_CPU_PART_CORTEX_X2 0xD48
|
||||
#define ARM_CPU_PART_NEOVERSE_N2 0xD49
|
||||
#define ARM_CPU_PART_CORTEX_A78C 0xD4B
|
||||
#define ARM_CPU_PART_NEOVERSE_V2 0xD4F
|
||||
|
||||
#define APM_CPU_PART_XGENE 0x000
|
||||
#define APM_CPU_VAR_POTENZA 0x00
|
||||
@ -159,6 +160,7 @@
|
||||
#define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
|
||||
#define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
|
||||
#define MIDR_CORTEX_A78C MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
|
||||
#define MIDR_NEOVERSE_V2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V2)
|
||||
#define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
|
||||
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
|
||||
#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
|
||||
|
@ -59,13 +59,14 @@
|
||||
|
||||
.macro __init_el2_debug
|
||||
mrs x1, id_aa64dfr0_el1
|
||||
sbfx x0, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp x0, #1
|
||||
b.lt .Lskip_pmu_\@ // Skip if no PMU present
|
||||
ubfx x0, x1, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
|
||||
cmp x0, #ID_AA64DFR0_EL1_PMUVer_NI
|
||||
ccmp x0, #ID_AA64DFR0_EL1_PMUVer_IMP_DEF, #4, ne
|
||||
b.eq .Lskip_pmu_\@ // Skip if no PMU present or IMP_DEF
|
||||
mrs x0, pmcr_el0 // Disable debug access traps
|
||||
ubfx x0, x0, #11, #5 // to EL2 and allow access to
|
||||
.Lskip_pmu_\@:
|
||||
csel x2, xzr, x0, lt // all PMU counters from EL1
|
||||
csel x2, xzr, x0, eq // all PMU counters from EL1
|
||||
|
||||
/* Statistical profiling */
|
||||
ubfx x0, x1, #ID_AA64DFR0_EL1_PMSVer_SHIFT, #4
|
||||
|
@ -5,7 +5,6 @@
|
||||
#ifndef __ASM_IRQFLAGS_H
|
||||
#define __ASM_IRQFLAGS_H
|
||||
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/sysreg.h>
|
||||
|
@ -15,17 +15,23 @@
|
||||
|
||||
#define JUMP_LABEL_NOP_SIZE AARCH64_INSN_SIZE
|
||||
|
||||
#define JUMP_TABLE_ENTRY(key, label) \
|
||||
".pushsection __jump_table, \"aw\"\n\t" \
|
||||
".align 3\n\t" \
|
||||
".long 1b - ., %l["#label"] - .\n\t" \
|
||||
".quad %c0 - .\n\t" \
|
||||
".popsection\n\t" \
|
||||
: : "i"(key) : : label
|
||||
|
||||
static __always_inline bool arch_static_branch(struct static_key * const key,
|
||||
const bool branch)
|
||||
{
|
||||
char *k = &((char *)key)[branch];
|
||||
|
||||
asm goto(
|
||||
"1: nop \n\t"
|
||||
" .pushsection __jump_table, \"aw\" \n\t"
|
||||
" .align 3 \n\t"
|
||||
" .long 1b - ., %l[l_yes] - . \n\t"
|
||||
" .quad %c0 - . \n\t"
|
||||
" .popsection \n\t"
|
||||
: : "i"(&((char *)key)[branch]) : : l_yes);
|
||||
JUMP_TABLE_ENTRY(k, l_yes)
|
||||
);
|
||||
|
||||
return false;
|
||||
l_yes:
|
||||
@ -35,15 +41,11 @@ l_yes:
|
||||
static __always_inline bool arch_static_branch_jump(struct static_key * const key,
|
||||
const bool branch)
|
||||
{
|
||||
char *k = &((char *)key)[branch];
|
||||
asm goto(
|
||||
"1: b %l[l_yes] \n\t"
|
||||
" .pushsection __jump_table, \"aw\" \n\t"
|
||||
" .align 3 \n\t"
|
||||
" .long 1b - ., %l[l_yes] - . \n\t"
|
||||
" .quad %c0 - . \n\t"
|
||||
" .popsection \n\t"
|
||||
: : "i"(&((char *)key)[branch]) : : l_yes);
|
||||
|
||||
JUMP_TABLE_ENTRY(k, l_yes)
|
||||
);
|
||||
return false;
|
||||
l_yes:
|
||||
return true;
|
||||
|
@ -18,14 +18,21 @@
|
||||
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
|
||||
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
|
||||
#define PTE_DEVMAP (_AT(pteval_t, 1) << 57)
|
||||
#define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
|
||||
|
||||
/*
|
||||
* This bit indicates that the entry is present i.e. pmd_page()
|
||||
* still points to a valid huge page in memory even if the pmd
|
||||
* has been invalidated.
|
||||
* PTE_PRESENT_INVALID=1 & PTE_VALID=0 indicates that the pte's fields should be
|
||||
* interpreted according to the HW layout by SW but any attempted HW access to
|
||||
* the address will result in a fault. pte_present() returns true.
|
||||
*/
|
||||
#define PMD_PRESENT_INVALID (_AT(pteval_t, 1) << 59) /* only when !PMD_SECT_VALID */
|
||||
#define PTE_PRESENT_INVALID (PTE_NG) /* only when !PTE_VALID */
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
#define PTE_UFFD_WP (_AT(pteval_t, 1) << 58) /* uffd-wp tracking */
|
||||
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 1) << 3) /* only for swp ptes */
|
||||
#else
|
||||
#define PTE_UFFD_WP (_AT(pteval_t, 0))
|
||||
#define PTE_SWP_UFFD_WP (_AT(pteval_t, 0))
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
|
||||
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
|
||||
@ -103,7 +110,7 @@ static inline bool __pure lpa2_is_enabled(void)
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
|
||||
#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PRESENT_INVALID | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
|
||||
/* shared+writable pages are clean by default, hence PTE_RDONLY|PTE_WRITE */
|
||||
#define PAGE_SHARED __pgprot(_PAGE_SHARED)
|
||||
#define PAGE_SHARED_EXEC __pgprot(_PAGE_SHARED_EXEC)
|
||||
|
@ -105,7 +105,7 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
|
||||
/*
|
||||
* The following only work if pte_present(). Undefined behaviour otherwise.
|
||||
*/
|
||||
#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
|
||||
#define pte_present(pte) (pte_valid(pte) || pte_present_invalid(pte))
|
||||
#define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
|
||||
#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
|
||||
#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
|
||||
@ -132,6 +132,8 @@ static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
|
||||
#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte))
|
||||
|
||||
#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
|
||||
#define pte_present_invalid(pte) \
|
||||
((pte_val(pte) & (PTE_VALID | PTE_PRESENT_INVALID)) == PTE_PRESENT_INVALID)
|
||||
/*
|
||||
* Execute-only user mappings do not have the PTE_USER bit set. All valid
|
||||
* kernel mappings have the PTE_UXN bit set.
|
||||
@ -261,6 +263,13 @@ static inline pte_t pte_mkpresent(pte_t pte)
|
||||
return set_pte_bit(pte, __pgprot(PTE_VALID));
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkinvalid(pte_t pte)
|
||||
{
|
||||
pte = set_pte_bit(pte, __pgprot(PTE_PRESENT_INVALID));
|
||||
pte = clear_pte_bit(pte, __pgprot(PTE_VALID));
|
||||
return pte;
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkcont(pmd_t pmd)
|
||||
{
|
||||
return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
|
||||
@ -271,9 +280,31 @@ static inline pte_t pte_mkdevmap(pte_t pte)
|
||||
return set_pte_bit(pte, __pgprot(PTE_DEVMAP | PTE_SPECIAL));
|
||||
}
|
||||
|
||||
static inline void __set_pte(pte_t *ptep, pte_t pte)
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
static inline int pte_uffd_wp(pte_t pte)
|
||||
{
|
||||
return !!(pte_val(pte) & PTE_UFFD_WP);
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkuffd_wp(pte_t pte)
|
||||
{
|
||||
return pte_wrprotect(set_pte_bit(pte, __pgprot(PTE_UFFD_WP)));
|
||||
}
|
||||
|
||||
static inline pte_t pte_clear_uffd_wp(pte_t pte)
|
||||
{
|
||||
return clear_pte_bit(pte, __pgprot(PTE_UFFD_WP));
|
||||
}
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
static inline void __set_pte_nosync(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
WRITE_ONCE(*ptep, pte);
|
||||
}
|
||||
|
||||
static inline void __set_pte(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
__set_pte_nosync(ptep, pte);
|
||||
|
||||
/*
|
||||
* Only if the new pte is valid and kernel, otherwise TLB maintenance
|
||||
@ -463,13 +494,39 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
|
||||
return clear_pte_bit(pte, __pgprot(PTE_SWP_EXCLUSIVE));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
static inline pte_t pte_swp_mkuffd_wp(pte_t pte)
|
||||
{
|
||||
return set_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
|
||||
}
|
||||
|
||||
static inline int pte_swp_uffd_wp(pte_t pte)
|
||||
{
|
||||
return !!(pte_val(pte) & PTE_SWP_UFFD_WP);
|
||||
}
|
||||
|
||||
static inline pte_t pte_swp_clear_uffd_wp(pte_t pte)
|
||||
{
|
||||
return clear_pte_bit(pte, __pgprot(PTE_SWP_UFFD_WP));
|
||||
}
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#ifdef CONFIG_NUMA_BALANCING
|
||||
/*
|
||||
* See the comment in include/linux/pgtable.h
|
||||
*/
|
||||
static inline int pte_protnone(pte_t pte)
|
||||
{
|
||||
return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE;
|
||||
/*
|
||||
* pte_present_invalid() tells us that the pte is invalid from HW
|
||||
* perspective but present from SW perspective, so the fields are to be
|
||||
* interpretted as per the HW layout. The second 2 checks are the unique
|
||||
* encoding that we use for PROT_NONE. It is insufficient to only use
|
||||
* the first check because we share the same encoding scheme with pmds
|
||||
* which support pmd_mkinvalid(), so can be present-invalid without
|
||||
* being PROT_NONE.
|
||||
*/
|
||||
return pte_present_invalid(pte) && !pte_user(pte) && !pte_user_exec(pte);
|
||||
}
|
||||
|
||||
static inline int pmd_protnone(pmd_t pmd)
|
||||
@ -478,12 +535,7 @@ static inline int pmd_protnone(pmd_t pmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define pmd_present_invalid(pmd) (!!(pmd_val(pmd) & PMD_PRESENT_INVALID))
|
||||
|
||||
static inline int pmd_present(pmd_t pmd)
|
||||
{
|
||||
return pte_present(pmd_pte(pmd)) || pmd_present_invalid(pmd);
|
||||
}
|
||||
#define pmd_present(pmd) pte_present(pmd_pte(pmd))
|
||||
|
||||
/*
|
||||
* THP definitions.
|
||||
@ -508,14 +560,16 @@ static inline int pmd_trans_huge(pmd_t pmd)
|
||||
#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
|
||||
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
|
||||
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
|
||||
|
||||
static inline pmd_t pmd_mkinvalid(pmd_t pmd)
|
||||
{
|
||||
pmd = set_pmd_bit(pmd, __pgprot(PMD_PRESENT_INVALID));
|
||||
pmd = clear_pmd_bit(pmd, __pgprot(PMD_SECT_VALID));
|
||||
|
||||
return pmd;
|
||||
}
|
||||
#define pmd_mkinvalid(pmd) pte_pmd(pte_mkinvalid(pmd_pte(pmd)))
|
||||
#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_WP
|
||||
#define pmd_uffd_wp(pmd) pte_uffd_wp(pmd_pte(pmd))
|
||||
#define pmd_mkuffd_wp(pmd) pte_pmd(pte_mkuffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_clear_uffd_wp(pmd) pte_pmd(pte_clear_uffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_swp_uffd_wp(pmd) pte_swp_uffd_wp(pmd_pte(pmd))
|
||||
#define pmd_swp_mkuffd_wp(pmd) pte_pmd(pte_swp_mkuffd_wp(pmd_pte(pmd)))
|
||||
#define pmd_swp_clear_uffd_wp(pmd) \
|
||||
pte_pmd(pte_swp_clear_uffd_wp(pmd_pte(pmd)))
|
||||
#endif /* CONFIG_HAVE_ARCH_USERFAULTFD_WP */
|
||||
|
||||
#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd))
|
||||
|
||||
@ -760,6 +814,7 @@ static inline pmd_t *pud_pgtable(pud_t pud)
|
||||
|
||||
#else
|
||||
|
||||
#define pud_valid(pud) false
|
||||
#define pud_page_paddr(pud) ({ BUILD_BUG(); 0; })
|
||||
#define pud_user_exec(pud) pud_user(pud) /* Always 0 with folding */
|
||||
|
||||
@ -1005,6 +1060,8 @@ static inline p4d_t *p4d_offset_kimg(pgd_t *pgdp, u64 addr)
|
||||
|
||||
static inline bool pgtable_l5_enabled(void) { return false; }
|
||||
|
||||
#define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1))
|
||||
|
||||
/* Match p4d_offset folding in <asm/generic/pgtable-nop4d.h> */
|
||||
#define p4d_set_fixmap(addr) NULL
|
||||
#define p4d_set_fixmap_offset(p4dp, addr) ((p4d_t *)p4dp)
|
||||
@ -1027,8 +1084,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
|
||||
* in MAIR_EL1. The mask below has to include PTE_ATTRINDX_MASK.
|
||||
*/
|
||||
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
|
||||
PTE_PROT_NONE | PTE_VALID | PTE_WRITE | PTE_GP |
|
||||
PTE_ATTRINDX_MASK;
|
||||
PTE_PRESENT_INVALID | PTE_VALID | PTE_WRITE |
|
||||
PTE_GP | PTE_ATTRINDX_MASK;
|
||||
/* preserve the hardware dirty information */
|
||||
if (pte_hw_dirty(pte))
|
||||
pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
||||
@ -1076,17 +1133,17 @@ static inline int pgd_devmap(pgd_t pgd)
|
||||
#ifdef CONFIG_PAGE_TABLE_CHECK
|
||||
static inline bool pte_user_accessible_page(pte_t pte)
|
||||
{
|
||||
return pte_present(pte) && (pte_user(pte) || pte_user_exec(pte));
|
||||
return pte_valid(pte) && (pte_user(pte) || pte_user_exec(pte));
|
||||
}
|
||||
|
||||
static inline bool pmd_user_accessible_page(pmd_t pmd)
|
||||
{
|
||||
return pmd_leaf(pmd) && !pmd_present_invalid(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
|
||||
return pmd_valid(pmd) && !pmd_table(pmd) && (pmd_user(pmd) || pmd_user_exec(pmd));
|
||||
}
|
||||
|
||||
static inline bool pud_user_accessible_page(pud_t pud)
|
||||
{
|
||||
return pud_leaf(pud) && (pud_user(pud) || pud_user_exec(pud));
|
||||
return pud_valid(pud) && !pud_table(pud) && (pud_user(pud) || pud_user_exec(pud));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1248,15 +1305,16 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
|
||||
* Encode and decode a swap entry:
|
||||
* bits 0-1: present (must be zero)
|
||||
* bits 2: remember PG_anon_exclusive
|
||||
* bits 3-7: swap type
|
||||
* bits 8-57: swap offset
|
||||
* bit 58: PTE_PROT_NONE (must be zero)
|
||||
* bit 3: remember uffd-wp state
|
||||
* bits 6-10: swap type
|
||||
* bit 11: PTE_PRESENT_INVALID (must be zero)
|
||||
* bits 12-61: swap offset
|
||||
*/
|
||||
#define __SWP_TYPE_SHIFT 3
|
||||
#define __SWP_TYPE_SHIFT 6
|
||||
#define __SWP_TYPE_BITS 5
|
||||
#define __SWP_OFFSET_BITS 50
|
||||
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
|
||||
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
|
||||
#define __SWP_OFFSET_SHIFT 12
|
||||
#define __SWP_OFFSET_BITS 50
|
||||
#define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1)
|
||||
|
||||
#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
|
||||
|
@ -1036,18 +1036,18 @@
|
||||
* Permission Indirection Extension (PIE) permission encodings.
|
||||
* Encodings with the _O suffix, have overlays applied (Permission Overlay Extension).
|
||||
*/
|
||||
#define PIE_NONE_O 0x0
|
||||
#define PIE_R_O 0x1
|
||||
#define PIE_X_O 0x2
|
||||
#define PIE_RX_O 0x3
|
||||
#define PIE_RW_O 0x5
|
||||
#define PIE_RWnX_O 0x6
|
||||
#define PIE_RWX_O 0x7
|
||||
#define PIE_R 0x8
|
||||
#define PIE_GCS 0x9
|
||||
#define PIE_RX 0xa
|
||||
#define PIE_RW 0xc
|
||||
#define PIE_RWX 0xe
|
||||
#define PIE_NONE_O UL(0x0)
|
||||
#define PIE_R_O UL(0x1)
|
||||
#define PIE_X_O UL(0x2)
|
||||
#define PIE_RX_O UL(0x3)
|
||||
#define PIE_RW_O UL(0x5)
|
||||
#define PIE_RWnX_O UL(0x6)
|
||||
#define PIE_RWX_O UL(0x7)
|
||||
#define PIE_R UL(0x8)
|
||||
#define PIE_GCS UL(0x9)
|
||||
#define PIE_RX UL(0xa)
|
||||
#define PIE_RW UL(0xc)
|
||||
#define PIE_RWX UL(0xe)
|
||||
|
||||
#define PIRx_ELx_PERM(idx, perm) ((perm) << ((idx) * 4))
|
||||
|
||||
|
@ -142,17 +142,24 @@ static inline unsigned long get_trans_granule(void)
|
||||
* EL1, Inner Shareable".
|
||||
*
|
||||
*/
|
||||
#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl) \
|
||||
({ \
|
||||
unsigned long __ta = (baddr); \
|
||||
unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0; \
|
||||
__ta &= GENMASK_ULL(36, 0); \
|
||||
__ta |= __ttl << 37; \
|
||||
__ta |= (unsigned long)(num) << 39; \
|
||||
__ta |= (unsigned long)(scale) << 44; \
|
||||
__ta |= get_trans_granule() << 46; \
|
||||
__ta |= (unsigned long)(asid) << 48; \
|
||||
__ta; \
|
||||
#define TLBIR_ASID_MASK GENMASK_ULL(63, 48)
|
||||
#define TLBIR_TG_MASK GENMASK_ULL(47, 46)
|
||||
#define TLBIR_SCALE_MASK GENMASK_ULL(45, 44)
|
||||
#define TLBIR_NUM_MASK GENMASK_ULL(43, 39)
|
||||
#define TLBIR_TTL_MASK GENMASK_ULL(38, 37)
|
||||
#define TLBIR_BADDR_MASK GENMASK_ULL(36, 0)
|
||||
|
||||
#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl) \
|
||||
({ \
|
||||
unsigned long __ta = 0; \
|
||||
unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0; \
|
||||
__ta |= FIELD_PREP(TLBIR_BADDR_MASK, baddr); \
|
||||
__ta |= FIELD_PREP(TLBIR_TTL_MASK, __ttl); \
|
||||
__ta |= FIELD_PREP(TLBIR_NUM_MASK, num); \
|
||||
__ta |= FIELD_PREP(TLBIR_SCALE_MASK, scale); \
|
||||
__ta |= FIELD_PREP(TLBIR_TG_MASK, get_trans_granule()); \
|
||||
__ta |= FIELD_PREP(TLBIR_ASID_MASK, asid); \
|
||||
__ta; \
|
||||
})
|
||||
|
||||
/* These macros are used by the TLBI RANGE feature. */
|
||||
@ -439,11 +446,11 @@ static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma,
|
||||
* When not uses TLB range ops, we can handle up to
|
||||
* (MAX_DVM_OPS - 1) pages;
|
||||
* When uses TLB range ops, we can handle up to
|
||||
* (MAX_TLBI_RANGE_PAGES - 1) pages.
|
||||
* MAX_TLBI_RANGE_PAGES pages.
|
||||
*/
|
||||
if ((!system_supports_tlb_range() &&
|
||||
(end - start) >= (MAX_DVM_OPS * stride)) ||
|
||||
pages >= MAX_TLBI_RANGE_PAGES) {
|
||||
pages > MAX_TLBI_RANGE_PAGES) {
|
||||
flush_tlb_mm(vma->vm_mm);
|
||||
return;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
#include <acpi/ghes.h>
|
||||
@ -227,6 +228,15 @@ done:
|
||||
if (earlycon_acpi_spcr_enable)
|
||||
early_init_dt_scan_chosen_stdout();
|
||||
} else {
|
||||
#ifdef CONFIG_HIBERNATION
|
||||
struct acpi_table_header *facs = NULL;
|
||||
acpi_get_table(ACPI_SIG_FACS, 1, &facs);
|
||||
if (facs) {
|
||||
swsusp_hardware_signature =
|
||||
((struct acpi_table_facs *)facs)->hardware_signature;
|
||||
acpi_put_table(facs);
|
||||
}
|
||||
#endif
|
||||
acpi_parse_spcr(earlycon_acpi_spcr_enable, true);
|
||||
if (IS_ENABLED(CONFIG_ACPI_BGRT))
|
||||
acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
|
||||
|
@ -10,95 +10,13 @@
|
||||
|
||||
#include <asm/pointer_auth.h>
|
||||
|
||||
struct frame_tail {
|
||||
struct frame_tail __user *fp;
|
||||
unsigned long lr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Get the return address for a single stackframe and return a pointer to the
|
||||
* next frame tail.
|
||||
*/
|
||||
static struct frame_tail __user *
|
||||
user_backtrace(struct frame_tail __user *tail,
|
||||
struct perf_callchain_entry_ctx *entry)
|
||||
static bool callchain_trace(void *data, unsigned long pc)
|
||||
{
|
||||
struct frame_tail buftail;
|
||||
unsigned long err;
|
||||
unsigned long lr;
|
||||
struct perf_callchain_entry_ctx *entry = data;
|
||||
|
||||
/* Also check accessibility of one struct frame_tail beyond */
|
||||
if (!access_ok(tail, sizeof(buftail)))
|
||||
return NULL;
|
||||
|
||||
pagefault_disable();
|
||||
err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
|
||||
pagefault_enable();
|
||||
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
lr = ptrauth_strip_user_insn_pac(buftail.lr);
|
||||
|
||||
perf_callchain_store(entry, lr);
|
||||
|
||||
/*
|
||||
* Frame pointers should strictly progress back up the stack
|
||||
* (towards higher addresses).
|
||||
*/
|
||||
if (tail >= buftail.fp)
|
||||
return NULL;
|
||||
|
||||
return buftail.fp;
|
||||
return perf_callchain_store(entry, pc) == 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* The registers we're interested in are at the end of the variable
|
||||
* length saved register structure. The fp points at the end of this
|
||||
* structure so the address of this struct is:
|
||||
* (struct compat_frame_tail *)(xxx->fp)-1
|
||||
*
|
||||
* This code has been adapted from the ARM OProfile support.
|
||||
*/
|
||||
struct compat_frame_tail {
|
||||
compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */
|
||||
u32 sp;
|
||||
u32 lr;
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct compat_frame_tail __user *
|
||||
compat_user_backtrace(struct compat_frame_tail __user *tail,
|
||||
struct perf_callchain_entry_ctx *entry)
|
||||
{
|
||||
struct compat_frame_tail buftail;
|
||||
unsigned long err;
|
||||
|
||||
/* Also check accessibility of one struct frame_tail beyond */
|
||||
if (!access_ok(tail, sizeof(buftail)))
|
||||
return NULL;
|
||||
|
||||
pagefault_disable();
|
||||
err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
|
||||
pagefault_enable();
|
||||
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
perf_callchain_store(entry, buftail.lr);
|
||||
|
||||
/*
|
||||
* Frame pointers should strictly progress back up the stack
|
||||
* (towards higher addresses).
|
||||
*/
|
||||
if (tail + 1 >= (struct compat_frame_tail __user *)
|
||||
compat_ptr(buftail.fp))
|
||||
return NULL;
|
||||
|
||||
return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
|
||||
}
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
@ -107,35 +25,7 @@ void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
|
||||
return;
|
||||
}
|
||||
|
||||
perf_callchain_store(entry, regs->pc);
|
||||
|
||||
if (!compat_user_mode(regs)) {
|
||||
/* AARCH64 mode */
|
||||
struct frame_tail __user *tail;
|
||||
|
||||
tail = (struct frame_tail __user *)regs->regs[29];
|
||||
|
||||
while (entry->nr < entry->max_stack &&
|
||||
tail && !((unsigned long)tail & 0x7))
|
||||
tail = user_backtrace(tail, entry);
|
||||
} else {
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* AARCH32 compat mode */
|
||||
struct compat_frame_tail __user *tail;
|
||||
|
||||
tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
|
||||
|
||||
while ((entry->nr < entry->max_stack) &&
|
||||
tail && !((unsigned long)tail & 0x3))
|
||||
tail = compat_user_backtrace(tail, entry);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static bool callchain_trace(void *data, unsigned long pc)
|
||||
{
|
||||
struct perf_callchain_entry_ctx *entry = data;
|
||||
return perf_callchain_store(entry, pc) == 0;
|
||||
arch_stack_walk_user(callchain_trace, entry, regs);
|
||||
}
|
||||
|
||||
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
|
||||
|
@ -108,6 +108,7 @@ static const struct ftr_set_desc pfr0 __prel64_initconst = {
|
||||
.override = &id_aa64pfr0_override,
|
||||
.fields = {
|
||||
FIELD("sve", ID_AA64PFR0_EL1_SVE_SHIFT, pfr0_sve_filter),
|
||||
FIELD("el0", ID_AA64PFR0_EL1_EL0_SHIFT, NULL),
|
||||
{}
|
||||
},
|
||||
};
|
||||
@ -223,6 +224,7 @@ static const struct {
|
||||
{ "nokaslr", "arm64_sw.nokaslr=1" },
|
||||
{ "rodata=off", "arm64_sw.rodataoff=1" },
|
||||
{ "arm64.nolva", "id_aa64mmfr2.varange=0" },
|
||||
{ "arm64.no32bit_el0", "id_aa64pfr0.el0=1" },
|
||||
};
|
||||
|
||||
static int __init parse_hexdigit(const char *p, u64 *v)
|
||||
|
@ -298,8 +298,15 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
||||
dynamic_scs_init();
|
||||
|
||||
/*
|
||||
* Unmask SError as soon as possible after initializing earlycon so
|
||||
* that we can report any SErrors immediately.
|
||||
* The primary CPU enters the kernel with all DAIF exceptions masked.
|
||||
*
|
||||
* We must unmask Debug and SError before preemption or scheduling is
|
||||
* possible to ensure that these are consistently unmasked across
|
||||
* threads, and we want to unmask SError as soon as possible after
|
||||
* initializing earlycon so that we can report any SErrors immediately.
|
||||
*
|
||||
* IRQ and FIQ will be unmasked after the root irqchip has been
|
||||
* detected and initialized.
|
||||
*/
|
||||
local_daif_restore(DAIF_PROCCTX_NOIRQ);
|
||||
|
||||
|
@ -264,6 +264,13 @@ asmlinkage notrace void secondary_start_kernel(void)
|
||||
set_cpu_online(cpu, true);
|
||||
complete(&cpu_running);
|
||||
|
||||
/*
|
||||
* Secondary CPUs enter the kernel with all DAIF exceptions masked.
|
||||
*
|
||||
* As with setup_arch() we must unmask Debug and SError exceptions, and
|
||||
* as the root irqchip has already been detected and initialized we can
|
||||
* unmask IRQ and FIQ at the same time.
|
||||
*/
|
||||
local_daif_restore(DAIF_PROCCTX);
|
||||
|
||||
/*
|
||||
|
@ -324,3 +324,123 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
|
||||
dump_backtrace(NULL, tsk, loglvl);
|
||||
barrier();
|
||||
}
|
||||
|
||||
/*
|
||||
* The struct defined for userspace stack frame in AARCH64 mode.
|
||||
*/
|
||||
struct frame_tail {
|
||||
struct frame_tail __user *fp;
|
||||
unsigned long lr;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Get the return address for a single stackframe and return a pointer to the
|
||||
* next frame tail.
|
||||
*/
|
||||
static struct frame_tail __user *
|
||||
unwind_user_frame(struct frame_tail __user *tail, void *cookie,
|
||||
stack_trace_consume_fn consume_entry)
|
||||
{
|
||||
struct frame_tail buftail;
|
||||
unsigned long err;
|
||||
unsigned long lr;
|
||||
|
||||
/* Also check accessibility of one struct frame_tail beyond */
|
||||
if (!access_ok(tail, sizeof(buftail)))
|
||||
return NULL;
|
||||
|
||||
pagefault_disable();
|
||||
err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
|
||||
pagefault_enable();
|
||||
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
lr = ptrauth_strip_user_insn_pac(buftail.lr);
|
||||
|
||||
if (!consume_entry(cookie, lr))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Frame pointers should strictly progress back up the stack
|
||||
* (towards higher addresses).
|
||||
*/
|
||||
if (tail >= buftail.fp)
|
||||
return NULL;
|
||||
|
||||
return buftail.fp;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* The registers we're interested in are at the end of the variable
|
||||
* length saved register structure. The fp points at the end of this
|
||||
* structure so the address of this struct is:
|
||||
* (struct compat_frame_tail *)(xxx->fp)-1
|
||||
*
|
||||
* This code has been adapted from the ARM OProfile support.
|
||||
*/
|
||||
struct compat_frame_tail {
|
||||
compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */
|
||||
u32 sp;
|
||||
u32 lr;
|
||||
} __attribute__((packed));
|
||||
|
||||
static struct compat_frame_tail __user *
|
||||
unwind_compat_user_frame(struct compat_frame_tail __user *tail, void *cookie,
|
||||
stack_trace_consume_fn consume_entry)
|
||||
{
|
||||
struct compat_frame_tail buftail;
|
||||
unsigned long err;
|
||||
|
||||
/* Also check accessibility of one struct frame_tail beyond */
|
||||
if (!access_ok(tail, sizeof(buftail)))
|
||||
return NULL;
|
||||
|
||||
pagefault_disable();
|
||||
err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
|
||||
pagefault_enable();
|
||||
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
if (!consume_entry(cookie, buftail.lr))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Frame pointers should strictly progress back up the stack
|
||||
* (towards higher addresses).
|
||||
*/
|
||||
if (tail + 1 >= (struct compat_frame_tail __user *)
|
||||
compat_ptr(buftail.fp))
|
||||
return NULL;
|
||||
|
||||
return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
|
||||
}
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
|
||||
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
const struct pt_regs *regs)
|
||||
{
|
||||
if (!consume_entry(cookie, regs->pc))
|
||||
return;
|
||||
|
||||
if (!compat_user_mode(regs)) {
|
||||
/* AARCH64 mode */
|
||||
struct frame_tail __user *tail;
|
||||
|
||||
tail = (struct frame_tail __user *)regs->regs[29];
|
||||
while (tail && !((unsigned long)tail & 0x7))
|
||||
tail = unwind_user_frame(tail, cookie, consume_entry);
|
||||
} else {
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* AARCH32 compat mode */
|
||||
struct compat_frame_tail __user *tail;
|
||||
|
||||
tail = (struct compat_frame_tail __user *)regs->compat_fp - 1;
|
||||
while (tail && !((unsigned long)tail & 0x3))
|
||||
tail = unwind_compat_user_frame(tail, cookie, consume_entry);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -109,28 +109,12 @@ EXPORT_SYMBOL(phys_mem_access_prot);
|
||||
static phys_addr_t __init early_pgtable_alloc(int shift)
|
||||
{
|
||||
phys_addr_t phys;
|
||||
void *ptr;
|
||||
|
||||
phys = memblock_phys_alloc_range(PAGE_SIZE, PAGE_SIZE, 0,
|
||||
MEMBLOCK_ALLOC_NOLEAKTRACE);
|
||||
if (!phys)
|
||||
panic("Failed to allocate page table page\n");
|
||||
|
||||
/*
|
||||
* The FIX_{PGD,PUD,PMD} slots may be in active use, but the FIX_PTE
|
||||
* slot will be free, so we can (ab)use the FIX_PTE slot to initialise
|
||||
* any level of table.
|
||||
*/
|
||||
ptr = pte_set_fixmap(phys);
|
||||
|
||||
memset(ptr, 0, PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* Implicit barriers also ensure the zeroed page is visible to the page
|
||||
* table walker
|
||||
*/
|
||||
pte_clear_fixmap();
|
||||
|
||||
return phys;
|
||||
}
|
||||
|
||||
@ -172,16 +156,25 @@ bool pgattr_change_is_safe(u64 old, u64 new)
|
||||
return ((old ^ new) & ~mask) == 0;
|
||||
}
|
||||
|
||||
static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
|
||||
static void init_clear_pgtable(void *table)
|
||||
{
|
||||
clear_page(table);
|
||||
|
||||
/* Ensure the zeroing is observed by page table walks. */
|
||||
dsb(ishst);
|
||||
}
|
||||
|
||||
static void init_pte(pte_t *ptep, unsigned long addr, unsigned long end,
|
||||
phys_addr_t phys, pgprot_t prot)
|
||||
{
|
||||
pte_t *ptep;
|
||||
|
||||
ptep = pte_set_fixmap_offset(pmdp, addr);
|
||||
do {
|
||||
pte_t old_pte = __ptep_get(ptep);
|
||||
|
||||
__set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));
|
||||
/*
|
||||
* Required barriers to make this visible to the table walker
|
||||
* are deferred to the end of alloc_init_cont_pte().
|
||||
*/
|
||||
__set_pte_nosync(ptep, pfn_pte(__phys_to_pfn(phys), prot));
|
||||
|
||||
/*
|
||||
* After the PTE entry has been populated once, we
|
||||
@ -192,8 +185,6 @@ static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
|
||||
|
||||
phys += PAGE_SIZE;
|
||||
} while (ptep++, addr += PAGE_SIZE, addr != end);
|
||||
|
||||
pte_clear_fixmap();
|
||||
}
|
||||
|
||||
static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
|
||||
@ -204,6 +195,7 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
|
||||
{
|
||||
unsigned long next;
|
||||
pmd_t pmd = READ_ONCE(*pmdp);
|
||||
pte_t *ptep;
|
||||
|
||||
BUG_ON(pmd_sect(pmd));
|
||||
if (pmd_none(pmd)) {
|
||||
@ -214,10 +206,14 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
|
||||
pmdval |= PMD_TABLE_PXN;
|
||||
BUG_ON(!pgtable_alloc);
|
||||
pte_phys = pgtable_alloc(PAGE_SHIFT);
|
||||
ptep = pte_set_fixmap(pte_phys);
|
||||
init_clear_pgtable(ptep);
|
||||
ptep += pte_index(addr);
|
||||
__pmd_populate(pmdp, pte_phys, pmdval);
|
||||
pmd = READ_ONCE(*pmdp);
|
||||
} else {
|
||||
BUG_ON(pmd_bad(pmd));
|
||||
ptep = pte_set_fixmap_offset(pmdp, addr);
|
||||
}
|
||||
BUG_ON(pmd_bad(pmd));
|
||||
|
||||
do {
|
||||
pgprot_t __prot = prot;
|
||||
@ -229,20 +225,26 @@ static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
|
||||
(flags & NO_CONT_MAPPINGS) == 0)
|
||||
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
|
||||
|
||||
init_pte(pmdp, addr, next, phys, __prot);
|
||||
init_pte(ptep, addr, next, phys, __prot);
|
||||
|
||||
ptep += pte_index(next) - pte_index(addr);
|
||||
phys += next - addr;
|
||||
} while (addr = next, addr != end);
|
||||
|
||||
/*
|
||||
* Note: barriers and maintenance necessary to clear the fixmap slot
|
||||
* ensure that all previous pgtable writes are visible to the table
|
||||
* walker.
|
||||
*/
|
||||
pte_clear_fixmap();
|
||||
}
|
||||
|
||||
static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
|
||||
static void init_pmd(pmd_t *pmdp, unsigned long addr, unsigned long end,
|
||||
phys_addr_t phys, pgprot_t prot,
|
||||
phys_addr_t (*pgtable_alloc)(int), int flags)
|
||||
{
|
||||
unsigned long next;
|
||||
pmd_t *pmdp;
|
||||
|
||||
pmdp = pmd_set_fixmap_offset(pudp, addr);
|
||||
do {
|
||||
pmd_t old_pmd = READ_ONCE(*pmdp);
|
||||
|
||||
@ -268,8 +270,6 @@ static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
|
||||
}
|
||||
phys += next - addr;
|
||||
} while (pmdp++, addr = next, addr != end);
|
||||
|
||||
pmd_clear_fixmap();
|
||||
}
|
||||
|
||||
static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
|
||||
@ -279,6 +279,7 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
|
||||
{
|
||||
unsigned long next;
|
||||
pud_t pud = READ_ONCE(*pudp);
|
||||
pmd_t *pmdp;
|
||||
|
||||
/*
|
||||
* Check for initial section mappings in the pgd/pud.
|
||||
@ -292,10 +293,14 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
|
||||
pudval |= PUD_TABLE_PXN;
|
||||
BUG_ON(!pgtable_alloc);
|
||||
pmd_phys = pgtable_alloc(PMD_SHIFT);
|
||||
pmdp = pmd_set_fixmap(pmd_phys);
|
||||
init_clear_pgtable(pmdp);
|
||||
pmdp += pmd_index(addr);
|
||||
__pud_populate(pudp, pmd_phys, pudval);
|
||||
pud = READ_ONCE(*pudp);
|
||||
} else {
|
||||
BUG_ON(pud_bad(pud));
|
||||
pmdp = pmd_set_fixmap_offset(pudp, addr);
|
||||
}
|
||||
BUG_ON(pud_bad(pud));
|
||||
|
||||
do {
|
||||
pgprot_t __prot = prot;
|
||||
@ -307,10 +312,13 @@ static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
|
||||
(flags & NO_CONT_MAPPINGS) == 0)
|
||||
__prot = __pgprot(pgprot_val(prot) | PTE_CONT);
|
||||
|
||||
init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
|
||||
init_pmd(pmdp, addr, next, phys, __prot, pgtable_alloc, flags);
|
||||
|
||||
pmdp += pmd_index(next) - pmd_index(addr);
|
||||
phys += next - addr;
|
||||
} while (addr = next, addr != end);
|
||||
|
||||
pmd_clear_fixmap();
|
||||
}
|
||||
|
||||
static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,
|
||||
@ -330,12 +338,15 @@ static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,
|
||||
p4dval |= P4D_TABLE_PXN;
|
||||
BUG_ON(!pgtable_alloc);
|
||||
pud_phys = pgtable_alloc(PUD_SHIFT);
|
||||
pudp = pud_set_fixmap(pud_phys);
|
||||
init_clear_pgtable(pudp);
|
||||
pudp += pud_index(addr);
|
||||
__p4d_populate(p4dp, pud_phys, p4dval);
|
||||
p4d = READ_ONCE(*p4dp);
|
||||
} else {
|
||||
BUG_ON(p4d_bad(p4d));
|
||||
pudp = pud_set_fixmap_offset(p4dp, addr);
|
||||
}
|
||||
BUG_ON(p4d_bad(p4d));
|
||||
|
||||
pudp = pud_set_fixmap_offset(p4dp, addr);
|
||||
do {
|
||||
pud_t old_pud = READ_ONCE(*pudp);
|
||||
|
||||
@ -385,12 +396,15 @@ static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end,
|
||||
pgdval |= PGD_TABLE_PXN;
|
||||
BUG_ON(!pgtable_alloc);
|
||||
p4d_phys = pgtable_alloc(P4D_SHIFT);
|
||||
p4dp = p4d_set_fixmap(p4d_phys);
|
||||
init_clear_pgtable(p4dp);
|
||||
p4dp += p4d_index(addr);
|
||||
__pgd_populate(pgdp, p4d_phys, pgdval);
|
||||
pgd = READ_ONCE(*pgdp);
|
||||
} else {
|
||||
BUG_ON(pgd_bad(pgd));
|
||||
p4dp = p4d_set_fixmap_offset(pgdp, addr);
|
||||
}
|
||||
BUG_ON(pgd_bad(pgd));
|
||||
|
||||
p4dp = p4d_set_fixmap_offset(pgdp, addr);
|
||||
do {
|
||||
p4d_t old_p4d = READ_ONCE(*p4dp);
|
||||
|
||||
@ -457,11 +471,10 @@ void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
|
||||
|
||||
static phys_addr_t __pgd_pgtable_alloc(int shift)
|
||||
{
|
||||
void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL);
|
||||
BUG_ON(!ptr);
|
||||
/* Page is zeroed by init_clear_pgtable() so don't duplicate effort. */
|
||||
void *ptr = (void *)__get_free_page(GFP_PGTABLE_KERNEL & ~__GFP_ZERO);
|
||||
|
||||
/* Ensure the zeroed page is visible to the page table walker */
|
||||
dsb(ishst);
|
||||
BUG_ON(!ptr);
|
||||
return __pa(ptr);
|
||||
}
|
||||
|
||||
|
@ -135,14 +135,6 @@ SYM_FUNC_START(cpu_do_resume)
|
||||
|
||||
msr tcr_el1, x8
|
||||
msr vbar_el1, x9
|
||||
|
||||
/*
|
||||
* __cpu_setup() cleared MDSCR_EL1.MDE and friends, before unmasking
|
||||
* debug exceptions. By restoring MDSCR_EL1 here, we may take a debug
|
||||
* exception. Mask them until local_daif_restore() in cpu_suspend()
|
||||
* resets them.
|
||||
*/
|
||||
disable_daif
|
||||
msr mdscr_el1, x10
|
||||
|
||||
msr sctlr_el1, x12
|
||||
@ -466,8 +458,6 @@ SYM_FUNC_START(__cpu_setup)
|
||||
msr cpacr_el1, xzr // Reset cpacr_el1
|
||||
mov x1, #1 << 12 // Reset mdscr_el1 and disable
|
||||
msr mdscr_el1, x1 // access to the DCC from EL0
|
||||
isb // Unmask debug exceptions now,
|
||||
enable_dbg // since this is per-cpu
|
||||
reset_pmuserenr_el0 x1 // Disable PMU access from EL0
|
||||
reset_amuserenr_el0 x1 // Disable AMU access from EL0
|
||||
|
||||
|
@ -315,23 +315,19 @@ void acpi_tb_parse_fadt(void)
|
||||
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
|
||||
NULL, FALSE, TRUE, &acpi_gbl_dsdt_index);
|
||||
|
||||
/* If Hardware Reduced flag is set, there is no FACS */
|
||||
|
||||
if (!acpi_gbl_reduced_hardware) {
|
||||
if (acpi_gbl_FADT.facs) {
|
||||
acpi_tb_install_standard_table((acpi_physical_address)
|
||||
acpi_gbl_FADT.facs,
|
||||
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
|
||||
NULL, FALSE, TRUE,
|
||||
&acpi_gbl_facs_index);
|
||||
}
|
||||
if (acpi_gbl_FADT.Xfacs) {
|
||||
acpi_tb_install_standard_table((acpi_physical_address)
|
||||
acpi_gbl_FADT.Xfacs,
|
||||
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
|
||||
NULL, FALSE, TRUE,
|
||||
&acpi_gbl_xfacs_index);
|
||||
}
|
||||
if (acpi_gbl_FADT.facs) {
|
||||
acpi_tb_install_standard_table((acpi_physical_address)
|
||||
acpi_gbl_FADT.facs,
|
||||
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
|
||||
NULL, FALSE, TRUE,
|
||||
&acpi_gbl_facs_index);
|
||||
}
|
||||
if (acpi_gbl_FADT.Xfacs) {
|
||||
acpi_tb_install_standard_table((acpi_physical_address)
|
||||
acpi_gbl_FADT.Xfacs,
|
||||
ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
|
||||
NULL, FALSE, TRUE,
|
||||
&acpi_gbl_xfacs_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,12 +36,7 @@ acpi_status acpi_tb_initialize_facs(void)
|
||||
{
|
||||
struct acpi_table_facs *facs;
|
||||
|
||||
/* If Hardware Reduced flag is set, there is no FACS */
|
||||
|
||||
if (acpi_gbl_reduced_hardware) {
|
||||
acpi_gbl_FACS = NULL;
|
||||
return (AE_OK);
|
||||
} else if (acpi_gbl_FADT.Xfacs &&
|
||||
if (acpi_gbl_FADT.Xfacs &&
|
||||
(!acpi_gbl_FADT.facs
|
||||
|| !acpi_gbl_use32_bit_facs_addresses)) {
|
||||
(void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
|
||||
|
@ -709,6 +709,7 @@ static int ali_drw_pmu_probe(struct platform_device *pdev)
|
||||
|
||||
drw_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = ali_drw_pmu_event_init,
|
||||
.add = ali_drw_pmu_add,
|
||||
@ -746,18 +747,14 @@ static int ali_drw_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
struct ali_drw_pmu_irq *irq;
|
||||
struct ali_drw_pmu *drw_pmu;
|
||||
unsigned int target;
|
||||
int ret;
|
||||
cpumask_t node_online_cpus;
|
||||
|
||||
irq = hlist_entry_safe(node, struct ali_drw_pmu_irq, node);
|
||||
if (cpu != irq->cpu)
|
||||
return 0;
|
||||
|
||||
ret = cpumask_and(&node_online_cpus,
|
||||
cpumask_of_node(cpu_to_node(cpu)), cpu_online_mask);
|
||||
if (ret)
|
||||
target = cpumask_any_but(&node_online_cpus, cpu);
|
||||
else
|
||||
target = cpumask_any_and_but(cpumask_of_node(cpu_to_node(cpu)),
|
||||
cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
target = cpumask_any_but(cpu_online_mask, cpu);
|
||||
|
||||
if (target >= nr_cpu_ids)
|
||||
|
@ -492,6 +492,7 @@ int meson_ddr_pmu_create(struct platform_device *pdev)
|
||||
*pmu = (struct ddr_pmu) {
|
||||
.pmu = {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.attr_groups = attr_groups,
|
||||
|
@ -1409,6 +1409,7 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
|
||||
|
||||
cci_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.name = cci_pmu->model->name,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.pmu_enable = cci_pmu_enable,
|
||||
|
@ -1265,6 +1265,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
|
||||
/* Perf driver registration */
|
||||
ccn->dt.pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = ccn->dev,
|
||||
.attr_groups = arm_ccn_pmu_attr_groups,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = arm_ccn_pmu_event_init,
|
||||
|
@ -1950,20 +1950,20 @@ static int arm_cmn_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_no
|
||||
struct arm_cmn *cmn;
|
||||
unsigned int target;
|
||||
int node;
|
||||
cpumask_t mask;
|
||||
|
||||
cmn = hlist_entry_safe(cpuhp_node, struct arm_cmn, cpuhp_node);
|
||||
if (cpu != cmn->cpu)
|
||||
return 0;
|
||||
|
||||
node = dev_to_node(cmn->dev);
|
||||
if (cpumask_and(&mask, cpumask_of_node(node), cpu_online_mask) &&
|
||||
cpumask_andnot(&mask, &mask, cpumask_of(cpu)))
|
||||
target = cpumask_any(&mask);
|
||||
else
|
||||
|
||||
target = cpumask_any_and_but(cpumask_of_node(node), cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
target = cpumask_any_but(cpu_online_mask, cpu);
|
||||
|
||||
if (target < nr_cpu_ids)
|
||||
arm_cmn_migrate(cmn, target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2482,6 +2482,7 @@ static int arm_cmn_probe(struct platform_device *pdev)
|
||||
cmn->cpu = cpumask_local_spread(0, dev_to_node(cmn->dev));
|
||||
cmn->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = cmn->dev,
|
||||
.attr_groups = arm_cmn_attr_groups,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
|
@ -1206,6 +1206,7 @@ static int arm_cspmu_register_pmu(struct arm_cspmu *cspmu)
|
||||
cspmu->pmu = (struct pmu){
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.module = cspmu->impl.module,
|
||||
.parent = cspmu->dev,
|
||||
.pmu_enable = arm_cspmu_enable,
|
||||
.pmu_disable = arm_cspmu_disable,
|
||||
.event_init = arm_cspmu_event_init,
|
||||
@ -1322,8 +1323,7 @@ static int arm_cspmu_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
static int arm_cspmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
int dst;
|
||||
struct cpumask online_supported;
|
||||
unsigned int dst;
|
||||
|
||||
struct arm_cspmu *cspmu =
|
||||
hlist_entry_safe(node, struct arm_cspmu, cpuhp_node);
|
||||
@ -1333,9 +1333,8 @@ static int arm_cspmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
|
||||
return 0;
|
||||
|
||||
/* Choose a new CPU to migrate ownership of the PMU to */
|
||||
cpumask_and(&online_supported, &cspmu->associated_cpus,
|
||||
cpu_online_mask);
|
||||
dst = cpumask_any_but(&online_supported, cpu);
|
||||
dst = cpumask_any_and_but(&cspmu->associated_cpus,
|
||||
cpu_online_mask, cpu);
|
||||
if (dst >= nr_cpu_ids)
|
||||
return 0;
|
||||
|
||||
|
@ -673,6 +673,7 @@ static int dmc620_pmu_device_probe(struct platform_device *pdev)
|
||||
|
||||
dmc620_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = dmc620_pmu_event_init,
|
||||
|
@ -230,15 +230,6 @@ static const struct attribute_group *dsu_pmu_attr_groups[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int dsu_pmu_get_online_cpu_any_but(struct dsu_pmu *dsu_pmu, int cpu)
|
||||
{
|
||||
struct cpumask online_supported;
|
||||
|
||||
cpumask_and(&online_supported,
|
||||
&dsu_pmu->associated_cpus, cpu_online_mask);
|
||||
return cpumask_any_but(&online_supported, cpu);
|
||||
}
|
||||
|
||||
static inline bool dsu_pmu_counter_valid(struct dsu_pmu *dsu_pmu, u32 idx)
|
||||
{
|
||||
return (idx < dsu_pmu->num_counters) ||
|
||||
@ -751,6 +742,7 @@ static int dsu_pmu_device_probe(struct platform_device *pdev)
|
||||
|
||||
dsu_pmu->pmu = (struct pmu) {
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.parent = &pdev->dev,
|
||||
.module = THIS_MODULE,
|
||||
.pmu_enable = dsu_pmu_enable,
|
||||
.pmu_disable = dsu_pmu_disable,
|
||||
@ -827,14 +819,16 @@ static int dsu_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
static int dsu_pmu_cpu_teardown(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
int dst;
|
||||
struct dsu_pmu *dsu_pmu = hlist_entry_safe(node, struct dsu_pmu,
|
||||
cpuhp_node);
|
||||
struct dsu_pmu *dsu_pmu;
|
||||
unsigned int dst;
|
||||
|
||||
dsu_pmu = hlist_entry_safe(node, struct dsu_pmu, cpuhp_node);
|
||||
|
||||
if (!cpumask_test_and_clear_cpu(cpu, &dsu_pmu->active_cpu))
|
||||
return 0;
|
||||
|
||||
dst = dsu_pmu_get_online_cpu_any_but(dsu_pmu, cpu);
|
||||
dst = cpumask_any_and_but(&dsu_pmu->associated_cpus,
|
||||
cpu_online_mask, cpu);
|
||||
/* If there are no active CPUs in the DSU, leave IRQ disabled */
|
||||
if (dst >= nr_cpu_ids)
|
||||
return 0;
|
||||
|
@ -196,6 +196,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
|
||||
if (!pmu)
|
||||
return -ENOMEM;
|
||||
|
||||
pmu->pmu.parent = &pdev->dev;
|
||||
pmu->plat_device = pdev;
|
||||
|
||||
ret = pmu_parse_irqs(pmu);
|
||||
|
@ -860,6 +860,7 @@ static int smmu_pmu_probe(struct platform_device *pdev)
|
||||
|
||||
smmu_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.pmu_enable = smmu_pmu_enable,
|
||||
.pmu_disable = smmu_pmu_disable,
|
||||
|
@ -932,6 +932,7 @@ static int arm_spe_pmu_perf_init(struct arm_spe_pmu *spe_pmu)
|
||||
|
||||
spe_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = &spe_pmu->pdev->dev,
|
||||
.capabilities = PERF_PMU_CAP_EXCLUSIVE | PERF_PMU_CAP_ITRACE,
|
||||
.attr_groups = arm_spe_pmu_attr_groups,
|
||||
/*
|
||||
|
@ -690,9 +690,8 @@ static int dwc_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_n
|
||||
{
|
||||
struct dwc_pcie_pmu *pcie_pmu;
|
||||
struct pci_dev *pdev;
|
||||
int node;
|
||||
cpumask_t mask;
|
||||
unsigned int target;
|
||||
int node;
|
||||
|
||||
pcie_pmu = hlist_entry_safe(cpuhp_node, struct dwc_pcie_pmu, cpuhp_node);
|
||||
/* Nothing to do if this CPU doesn't own the PMU */
|
||||
@ -702,10 +701,9 @@ static int dwc_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_n
|
||||
pcie_pmu->on_cpu = -1;
|
||||
pdev = pcie_pmu->pdev;
|
||||
node = dev_to_node(&pdev->dev);
|
||||
if (cpumask_and(&mask, cpumask_of_node(node), cpu_online_mask) &&
|
||||
cpumask_andnot(&mask, &mask, cpumask_of(cpu)))
|
||||
target = cpumask_any(&mask);
|
||||
else
|
||||
|
||||
target = cpumask_any_and_but(cpumask_of_node(node), cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
target = cpumask_any_but(cpu_online_mask, cpu);
|
||||
|
||||
if (target >= nr_cpu_ids) {
|
||||
|
@ -651,6 +651,7 @@ static int ddr_perf_init(struct ddr_pmu *pmu, void __iomem *base,
|
||||
*pmu = (struct ddr_pmu) {
|
||||
.pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = dev,
|
||||
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.attr_groups = attr_groups,
|
||||
|
@ -350,15 +350,27 @@ static bool hisi_pcie_pmu_validate_event_group(struct perf_event *event)
|
||||
return false;
|
||||
|
||||
for (num = 0; num < counters; num++) {
|
||||
/*
|
||||
* If we find a related event, then it's a valid group
|
||||
* since we don't need to allocate a new counter for it.
|
||||
*/
|
||||
if (hisi_pcie_pmu_cmp_event(event_group[num], sibling))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise it's a new event but if there's no available counter,
|
||||
* fail the check since we cannot schedule all the events in
|
||||
* the group simultaneously.
|
||||
*/
|
||||
if (num == HISI_PCIE_MAX_COUNTERS)
|
||||
return false;
|
||||
|
||||
if (num == counters)
|
||||
event_group[counters++] = sibling;
|
||||
}
|
||||
|
||||
return counters <= HISI_PCIE_MAX_COUNTERS;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hisi_pcie_pmu_event_init(struct perf_event *event)
|
||||
@ -673,7 +685,6 @@ static int hisi_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
struct hisi_pcie_pmu *pcie_pmu = hlist_entry_safe(node, struct hisi_pcie_pmu, node);
|
||||
unsigned int target;
|
||||
cpumask_t mask;
|
||||
int numa_node;
|
||||
|
||||
/* Nothing to do if this CPU doesn't own the PMU */
|
||||
@ -684,10 +695,10 @@ static int hisi_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
/* Choose a local CPU from all online cpus. */
|
||||
numa_node = dev_to_node(&pcie_pmu->pdev->dev);
|
||||
if (cpumask_and(&mask, cpumask_of_node(numa_node), cpu_online_mask) &&
|
||||
cpumask_andnot(&mask, &mask, cpumask_of(cpu)))
|
||||
target = cpumask_any(&mask);
|
||||
else
|
||||
|
||||
target = cpumask_any_and_but(cpumask_of_node(numa_node),
|
||||
cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
target = cpumask_any_but(cpu_online_mask, cpu);
|
||||
|
||||
if (target >= nr_cpu_ids) {
|
||||
@ -807,6 +818,7 @@ static int hisi_pcie_alloc_pmu(struct pci_dev *pdev, struct hisi_pcie_pmu *pcie_
|
||||
pcie_pmu->pmu = (struct pmu) {
|
||||
.name = name,
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.event_init = hisi_pcie_pmu_event_init,
|
||||
.pmu_enable = hisi_pcie_pmu_enable,
|
||||
.pmu_disable = hisi_pcie_pmu_disable,
|
||||
|
@ -504,7 +504,6 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
struct hisi_pmu *hisi_pmu = hlist_entry_safe(node, struct hisi_pmu,
|
||||
node);
|
||||
cpumask_t pmu_online_cpus;
|
||||
unsigned int target;
|
||||
|
||||
if (!cpumask_test_and_clear_cpu(cpu, &hisi_pmu->associated_cpus))
|
||||
@ -518,9 +517,8 @@ int hisi_uncore_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
hisi_pmu->on_cpu = -1;
|
||||
|
||||
/* Choose a new CPU to migrate ownership of the PMU to */
|
||||
cpumask_and(&pmu_online_cpus, &hisi_pmu->associated_cpus,
|
||||
cpu_online_mask);
|
||||
target = cpumask_any_but(&pmu_online_cpus, cpu);
|
||||
target = cpumask_any_and_but(&hisi_pmu->associated_cpus,
|
||||
cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids)
|
||||
return 0;
|
||||
|
||||
@ -538,6 +536,7 @@ void hisi_pmu_init(struct hisi_pmu *hisi_pmu, struct module *module)
|
||||
struct pmu *pmu = &hisi_pmu->pmu;
|
||||
|
||||
pmu->module = module;
|
||||
pmu->parent = hisi_pmu->dev;
|
||||
pmu->task_ctx_nr = perf_invalid_context;
|
||||
pmu->event_init = hisi_uncore_pmu_event_init;
|
||||
pmu->pmu_enable = hisi_uncore_pmu_enable;
|
||||
|
@ -1085,15 +1085,27 @@ static bool hns3_pmu_validate_event_group(struct perf_event *event)
|
||||
return false;
|
||||
|
||||
for (num = 0; num < counters; num++) {
|
||||
/*
|
||||
* If we find a related event, then it's a valid group
|
||||
* since we don't need to allocate a new counter for it.
|
||||
*/
|
||||
if (hns3_pmu_cmp_event(event_group[num], sibling))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise it's a new event but if there's no available counter,
|
||||
* fail the check since we cannot schedule all the events in
|
||||
* the group simultaneously.
|
||||
*/
|
||||
if (num == HNS3_PMU_MAX_HW_EVENTS)
|
||||
return false;
|
||||
|
||||
if (num == counters)
|
||||
event_group[counters++] = sibling;
|
||||
}
|
||||
|
||||
return counters <= HNS3_PMU_MAX_HW_EVENTS;
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 hns3_pmu_get_filter_condition(struct perf_event *event)
|
||||
@ -1419,6 +1431,7 @@ static int hns3_pmu_alloc_pmu(struct pci_dev *pdev, struct hns3_pmu *hns3_pmu)
|
||||
hns3_pmu->pmu = (struct pmu) {
|
||||
.name = name,
|
||||
.module = THIS_MODULE,
|
||||
.parent = &pdev->dev,
|
||||
.event_init = hns3_pmu_event_init,
|
||||
.pmu_enable = hns3_pmu_enable,
|
||||
.pmu_disable = hns3_pmu_disable,
|
||||
@ -1515,7 +1528,7 @@ static int hns3_pmu_irq_register(struct pci_dev *pdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action(&pdev->dev, hns3_pmu_free_irq, pdev);
|
||||
ret = devm_add_action_or_reset(&pdev->dev, hns3_pmu_free_irq, pdev);
|
||||
if (ret) {
|
||||
pci_err(pdev, "failed to add free irq action, ret = %d.\n", ret);
|
||||
return ret;
|
||||
|
@ -801,9 +801,8 @@ static int l2cache_pmu_online_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
|
||||
static int l2cache_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
{
|
||||
struct cluster_pmu *cluster;
|
||||
struct l2cache_pmu *l2cache_pmu;
|
||||
cpumask_t cluster_online_cpus;
|
||||
struct cluster_pmu *cluster;
|
||||
unsigned int target;
|
||||
|
||||
l2cache_pmu = hlist_entry_safe(node, struct l2cache_pmu, node);
|
||||
@ -820,9 +819,8 @@ static int l2cache_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
|
||||
cluster->on_cpu = -1;
|
||||
|
||||
/* Any other CPU for this cluster which is still online */
|
||||
cpumask_and(&cluster_online_cpus, &cluster->cluster_cpus,
|
||||
cpu_online_mask);
|
||||
target = cpumask_any_but(&cluster_online_cpus, cpu);
|
||||
target = cpumask_any_and_but(&cluster->cluster_cpus,
|
||||
cpu_online_mask, cpu);
|
||||
if (target >= nr_cpu_ids) {
|
||||
disable_irq(cluster->irq);
|
||||
return 0;
|
||||
@ -904,6 +902,7 @@ static int l2_cache_pmu_probe(struct platform_device *pdev)
|
||||
l2cache_pmu->pmu = (struct pmu) {
|
||||
/* suffix is instance id for future use with multiple sockets */
|
||||
.name = "l2cache_0",
|
||||
.parent = &pdev->dev,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.pmu_enable = l2_cache_pmu_enable,
|
||||
.pmu_disable = l2_cache_pmu_disable,
|
||||
|
@ -748,6 +748,7 @@ static int qcom_l3_cache_pmu_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
l3pmu->pmu = (struct pmu) {
|
||||
.parent = &pdev->dev,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
|
||||
.pmu_enable = qcom_l3_cache__pmu_enable,
|
||||
|
@ -136,6 +136,7 @@ static int pmu_legacy_device_probe(struct platform_device *pdev)
|
||||
pmu = riscv_pmu_alloc();
|
||||
if (!pmu)
|
||||
return -ENOMEM;
|
||||
pmu->pmu.parent = &pdev->dev;
|
||||
pmu_legacy_init(pmu);
|
||||
|
||||
return 0;
|
||||
|
@ -1043,7 +1043,6 @@ static struct ctl_table sbi_pmu_sysctl_table[] = {
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
.extra2 = SYSCTL_TWO,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static int pmu_sbi_device_probe(struct platform_device *pdev)
|
||||
@ -1081,6 +1080,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
pmu->pmu.attr_groups = riscv_pmu_attr_groups;
|
||||
pmu->pmu.parent = &pdev->dev;
|
||||
pmu->cmask = cmask;
|
||||
pmu->ctr_start = pmu_sbi_ctr_start;
|
||||
pmu->ctr_stop = pmu_sbi_ctr_stop;
|
||||
|
@ -504,24 +504,19 @@ static void tx2_uncore_event_update(struct perf_event *event)
|
||||
|
||||
static enum tx2_uncore_type get_tx2_pmu_type(struct acpi_device *adev)
|
||||
{
|
||||
int i = 0;
|
||||
struct acpi_tx2_pmu_device {
|
||||
__u8 id[ACPI_ID_LEN];
|
||||
enum tx2_uncore_type type;
|
||||
} devices[] = {
|
||||
struct acpi_device_id devices[] = {
|
||||
{"CAV901D", PMU_TYPE_L3C},
|
||||
{"CAV901F", PMU_TYPE_DMC},
|
||||
{"CAV901E", PMU_TYPE_CCPI2},
|
||||
{"", PMU_TYPE_INVALID}
|
||||
{}
|
||||
};
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
while (devices[i].type != PMU_TYPE_INVALID) {
|
||||
if (!strcmp(acpi_device_hid(adev), devices[i].id))
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
id = acpi_match_acpi_device(devices, adev);
|
||||
if (!id)
|
||||
return PMU_TYPE_INVALID;
|
||||
|
||||
return devices[i].type;
|
||||
return (enum tx2_uncore_type)id->driver_data;
|
||||
}
|
||||
|
||||
static bool tx2_uncore_validate_event(struct pmu *pmu,
|
||||
@ -729,6 +724,7 @@ static int tx2_uncore_pmu_register(
|
||||
/* Perf event registration */
|
||||
tx2_pmu->pmu = (struct pmu) {
|
||||
.module = THIS_MODULE,
|
||||
.parent = tx2_pmu->dev,
|
||||
.attr_groups = tx2_pmu->attr_groups,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.event_init = tx2_uncore_event_init,
|
||||
@ -932,9 +928,8 @@ static int tx2_uncore_pmu_online_cpu(unsigned int cpu,
|
||||
static int tx2_uncore_pmu_offline_cpu(unsigned int cpu,
|
||||
struct hlist_node *hpnode)
|
||||
{
|
||||
int new_cpu;
|
||||
struct tx2_uncore_pmu *tx2_pmu;
|
||||
struct cpumask cpu_online_mask_temp;
|
||||
unsigned int new_cpu;
|
||||
|
||||
tx2_pmu = hlist_entry_safe(hpnode,
|
||||
struct tx2_uncore_pmu, hpnode);
|
||||
@ -945,11 +940,8 @@ static int tx2_uncore_pmu_offline_cpu(unsigned int cpu,
|
||||
if (tx2_pmu->hrtimer_callback)
|
||||
hrtimer_cancel(&tx2_pmu->hrtimer);
|
||||
|
||||
cpumask_copy(&cpu_online_mask_temp, cpu_online_mask);
|
||||
cpumask_clear_cpu(cpu, &cpu_online_mask_temp);
|
||||
new_cpu = cpumask_any_and(
|
||||
cpumask_of_node(tx2_pmu->node),
|
||||
&cpu_online_mask_temp);
|
||||
new_cpu = cpumask_any_and_but(cpumask_of_node(tx2_pmu->node),
|
||||
cpu_online_mask, cpu);
|
||||
|
||||
tx2_pmu->cpu = new_cpu;
|
||||
if (new_cpu >= nr_cpu_ids)
|
||||
|
@ -1102,6 +1102,7 @@ static int xgene_init_perf(struct xgene_pmu_dev *pmu_dev, char *name)
|
||||
|
||||
/* Perf driver registration */
|
||||
pmu_dev->pmu = (struct pmu) {
|
||||
.parent = pmu_dev->parent->dev,
|
||||
.attr_groups = pmu_dev->attr_groups,
|
||||
.task_ctx_nr = perf_invalid_context,
|
||||
.pmu_enable = xgene_perf_pmu_enable,
|
||||
|
@ -405,6 +405,29 @@ unsigned int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpumask_any_and_but - pick a "random" cpu from *mask1 & *mask2, but not this one.
|
||||
* @mask1: the first input cpumask
|
||||
* @mask2: the second input cpumask
|
||||
* @cpu: the cpu to ignore
|
||||
*
|
||||
* Returns >= nr_cpu_ids if no cpus set.
|
||||
*/
|
||||
static inline
|
||||
unsigned int cpumask_any_and_but(const struct cpumask *mask1,
|
||||
const struct cpumask *mask2,
|
||||
unsigned int cpu)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
cpumask_check(cpu);
|
||||
i = cpumask_first_and(mask1, mask2);
|
||||
if (i != cpu)
|
||||
return i;
|
||||
|
||||
return cpumask_next_and(cpu, mask1, mask2);
|
||||
}
|
||||
|
||||
/**
|
||||
* cpumask_nth - get the Nth cpu in a cpumask
|
||||
* @srcp: the cpumask pointer
|
||||
|
@ -504,6 +504,22 @@ quiet_cmd_uimage = UIMAGE $@
|
||||
-a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
|
||||
-n '$(UIMAGE_NAME)' -d $< $@
|
||||
|
||||
# Flat Image Tree (FIT)
|
||||
# This allows for packaging of a kernel and all devicetrees files, using
|
||||
# compression.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
MAKE_FIT := $(srctree)/scripts/make_fit.py
|
||||
|
||||
# Use this to override the compression algorithm
|
||||
FIT_COMPRESSION ?= gzip
|
||||
|
||||
quiet_cmd_fit = FIT $@
|
||||
cmd_fit = $(MAKE_FIT) -o $@ --arch $(UIMAGE_ARCH) --os linux \
|
||||
--name '$(UIMAGE_NAME)' \
|
||||
$(if $(findstring 1,$(KBUILD_VERBOSE)),-v) \
|
||||
--compress $(FIT_COMPRESSION) -k $< @$(word 2,$^)
|
||||
|
||||
# XZ
|
||||
# ---------------------------------------------------------------------------
|
||||
# Use xzkern to compress the kernel image and xzmisc to compress other things.
|
||||
|
290
scripts/make_fit.py
Executable file
290
scripts/make_fit.py
Executable file
@ -0,0 +1,290 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright 2024 Google LLC
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
"""Build a FIT containing a lot of devicetree files
|
||||
|
||||
Usage:
|
||||
make_fit.py -A arm64 -n 'Linux-6.6' -O linux
|
||||
-o arch/arm64/boot/image.fit -k /tmp/kern/arch/arm64/boot/image.itk
|
||||
@arch/arm64/boot/dts/dtbs-list -E -c gzip
|
||||
|
||||
Creates a FIT containing the supplied kernel and a set of devicetree files,
|
||||
either specified individually or listed in a file (with an '@' prefix).
|
||||
|
||||
Use -E to generate an external FIT (where the data is placed after the
|
||||
FIT data structure). This allows parsing of the data without loading
|
||||
the entire FIT.
|
||||
|
||||
Use -c to compress the data, using bzip2, gzip, lz4, lzma, lzo and
|
||||
zstd algorithms.
|
||||
|
||||
The resulting FIT can be booted by bootloaders which support FIT, such
|
||||
as U-Boot, Linuxboot, Tianocore, etc.
|
||||
|
||||
Note that this tool does not yet support adding a ramdisk / initrd.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import libfdt
|
||||
|
||||
|
||||
# Tool extension and the name of the command-line tools
|
||||
CompTool = collections.namedtuple('CompTool', 'ext,tools')
|
||||
|
||||
COMP_TOOLS = {
|
||||
'bzip2': CompTool('.bz2', 'bzip2'),
|
||||
'gzip': CompTool('.gz', 'pigz,gzip'),
|
||||
'lz4': CompTool('.lz4', 'lz4'),
|
||||
'lzma': CompTool('.lzma', 'lzma'),
|
||||
'lzo': CompTool('.lzo', 'lzop'),
|
||||
'zstd': CompTool('.zstd', 'zstd'),
|
||||
}
|
||||
|
||||
|
||||
def parse_args():
|
||||
"""Parse the program ArgumentParser
|
||||
|
||||
Returns:
|
||||
Namespace object containing the arguments
|
||||
"""
|
||||
epilog = 'Build a FIT from a directory tree containing .dtb files'
|
||||
parser = argparse.ArgumentParser(epilog=epilog, fromfile_prefix_chars='@')
|
||||
parser.add_argument('-A', '--arch', type=str, required=True,
|
||||
help='Specifies the architecture')
|
||||
parser.add_argument('-c', '--compress', type=str, default='none',
|
||||
help='Specifies the compression')
|
||||
parser.add_argument('-E', '--external', action='store_true',
|
||||
help='Convert the FIT to use external data')
|
||||
parser.add_argument('-n', '--name', type=str, required=True,
|
||||
help='Specifies the name')
|
||||
parser.add_argument('-o', '--output', type=str, required=True,
|
||||
help='Specifies the output file (.fit)')
|
||||
parser.add_argument('-O', '--os', type=str, required=True,
|
||||
help='Specifies the operating system')
|
||||
parser.add_argument('-k', '--kernel', type=str, required=True,
|
||||
help='Specifies the (uncompressed) kernel input file (.itk)')
|
||||
parser.add_argument('-v', '--verbose', action='store_true',
|
||||
help='Enable verbose output')
|
||||
parser.add_argument('dtbs', type=str, nargs='*',
|
||||
help='Specifies the devicetree files to process')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def setup_fit(fsw, name):
|
||||
"""Make a start on writing the FIT
|
||||
|
||||
Outputs the root properties and the 'images' node
|
||||
|
||||
Args:
|
||||
fsw (libfdt.FdtSw): Object to use for writing
|
||||
name (str): Name of kernel image
|
||||
"""
|
||||
fsw.INC_SIZE = 65536
|
||||
fsw.finish_reservemap()
|
||||
fsw.begin_node('')
|
||||
fsw.property_string('description', f'{name} with devicetree set')
|
||||
fsw.property_u32('#address-cells', 1)
|
||||
|
||||
fsw.property_u32('timestamp', int(time.time()))
|
||||
fsw.begin_node('images')
|
||||
|
||||
|
||||
def write_kernel(fsw, data, args):
|
||||
"""Write out the kernel image
|
||||
|
||||
Writes a kernel node along with the required properties
|
||||
|
||||
Args:
|
||||
fsw (libfdt.FdtSw): Object to use for writing
|
||||
data (bytes): Data to write (possibly compressed)
|
||||
args (Namespace): Contains necessary strings:
|
||||
arch: FIT architecture, e.g. 'arm64'
|
||||
fit_os: Operating Systems, e.g. 'linux'
|
||||
name: Name of OS, e.g. 'Linux-6.6.0-rc7'
|
||||
compress: Compression algorithm to use, e.g. 'gzip'
|
||||
"""
|
||||
with fsw.add_node('kernel'):
|
||||
fsw.property_string('description', args.name)
|
||||
fsw.property_string('type', 'kernel_noload')
|
||||
fsw.property_string('arch', args.arch)
|
||||
fsw.property_string('os', args.os)
|
||||
fsw.property_string('compression', args.compress)
|
||||
fsw.property('data', data)
|
||||
fsw.property_u32('load', 0)
|
||||
fsw.property_u32('entry', 0)
|
||||
|
||||
|
||||
def finish_fit(fsw, entries):
|
||||
"""Finish the FIT ready for use
|
||||
|
||||
Writes the /configurations node and subnodes
|
||||
|
||||
Args:
|
||||
fsw (libfdt.FdtSw): Object to use for writing
|
||||
entries (list of tuple): List of configurations:
|
||||
str: Description of model
|
||||
str: Compatible stringlist
|
||||
"""
|
||||
fsw.end_node()
|
||||
seq = 0
|
||||
with fsw.add_node('configurations'):
|
||||
for model, compat in entries:
|
||||
seq += 1
|
||||
with fsw.add_node(f'conf-{seq}'):
|
||||
fsw.property('compatible', bytes(compat))
|
||||
fsw.property_string('description', model)
|
||||
fsw.property_string('fdt', f'fdt-{seq}')
|
||||
fsw.property_string('kernel', 'kernel')
|
||||
fsw.end_node()
|
||||
|
||||
|
||||
def compress_data(inf, compress):
|
||||
"""Compress data using a selected algorithm
|
||||
|
||||
Args:
|
||||
inf (IOBase): Filename containing the data to compress
|
||||
compress (str): Compression algorithm, e.g. 'gzip'
|
||||
|
||||
Return:
|
||||
bytes: Compressed data
|
||||
"""
|
||||
if compress == 'none':
|
||||
return inf.read()
|
||||
|
||||
comp = COMP_TOOLS.get(compress)
|
||||
if not comp:
|
||||
raise ValueError(f"Unknown compression algorithm '{compress}'")
|
||||
|
||||
with tempfile.NamedTemporaryFile() as comp_fname:
|
||||
with open(comp_fname.name, 'wb') as outf:
|
||||
done = False
|
||||
for tool in comp.tools.split(','):
|
||||
try:
|
||||
subprocess.call([tool, '-c'], stdin=inf, stdout=outf)
|
||||
done = True
|
||||
break
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
if not done:
|
||||
raise ValueError(f'Missing tool(s): {comp.tools}\n')
|
||||
with open(comp_fname.name, 'rb') as compf:
|
||||
comp_data = compf.read()
|
||||
return comp_data
|
||||
|
||||
|
||||
def output_dtb(fsw, seq, fname, arch, compress):
|
||||
"""Write out a single devicetree to the FIT
|
||||
|
||||
Args:
|
||||
fsw (libfdt.FdtSw): Object to use for writing
|
||||
seq (int): Sequence number (1 for first)
|
||||
fmame (str): Filename containing the DTB
|
||||
arch: FIT architecture, e.g. 'arm64'
|
||||
compress (str): Compressed algorithm, e.g. 'gzip'
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
str: Model name
|
||||
bytes: Compatible stringlist
|
||||
"""
|
||||
with fsw.add_node(f'fdt-{seq}'):
|
||||
# Get the compatible / model information
|
||||
with open(fname, 'rb') as inf:
|
||||
data = inf.read()
|
||||
fdt = libfdt.FdtRo(data)
|
||||
model = fdt.getprop(0, 'model').as_str()
|
||||
compat = fdt.getprop(0, 'compatible')
|
||||
|
||||
fsw.property_string('description', model)
|
||||
fsw.property_string('type', 'flat_dt')
|
||||
fsw.property_string('arch', arch)
|
||||
fsw.property_string('compression', compress)
|
||||
fsw.property('compatible', bytes(compat))
|
||||
|
||||
with open(fname, 'rb') as inf:
|
||||
compressed = compress_data(inf, compress)
|
||||
fsw.property('data', compressed)
|
||||
return model, compat
|
||||
|
||||
|
||||
def build_fit(args):
|
||||
"""Build the FIT from the provided files and arguments
|
||||
|
||||
Args:
|
||||
args (Namespace): Program arguments
|
||||
|
||||
Returns:
|
||||
tuple:
|
||||
bytes: FIT data
|
||||
int: Number of configurations generated
|
||||
size: Total uncompressed size of data
|
||||
"""
|
||||
seq = 0
|
||||
size = 0
|
||||
fsw = libfdt.FdtSw()
|
||||
setup_fit(fsw, args.name)
|
||||
entries = []
|
||||
|
||||
# Handle the kernel
|
||||
with open(args.kernel, 'rb') as inf:
|
||||
comp_data = compress_data(inf, args.compress)
|
||||
size += os.path.getsize(args.kernel)
|
||||
write_kernel(fsw, comp_data, args)
|
||||
|
||||
for fname in args.dtbs:
|
||||
# Ignore overlay (.dtbo) files
|
||||
if os.path.splitext(fname)[1] == '.dtb':
|
||||
seq += 1
|
||||
size += os.path.getsize(fname)
|
||||
model, compat = output_dtb(fsw, seq, fname, args.arch, args.compress)
|
||||
entries.append([model, compat])
|
||||
|
||||
finish_fit(fsw, entries)
|
||||
|
||||
# Include the kernel itself in the returned file count
|
||||
return fsw.as_fdt().as_bytearray(), seq + 1, size
|
||||
|
||||
|
||||
def run_make_fit():
|
||||
"""Run the tool's main logic"""
|
||||
args = parse_args()
|
||||
|
||||
out_data, count, size = build_fit(args)
|
||||
with open(args.output, 'wb') as outf:
|
||||
outf.write(out_data)
|
||||
|
||||
ext_fit_size = None
|
||||
if args.external:
|
||||
mkimage = os.environ.get('MKIMAGE', 'mkimage')
|
||||
subprocess.check_call([mkimage, '-E', '-F', args.output],
|
||||
stdout=subprocess.DEVNULL)
|
||||
|
||||
with open(args.output, 'rb') as inf:
|
||||
data = inf.read()
|
||||
ext_fit = libfdt.FdtRo(data)
|
||||
ext_fit_size = ext_fit.totalsize()
|
||||
|
||||
if args.verbose:
|
||||
comp_size = len(out_data)
|
||||
print(f'FIT size {comp_size:#x}/{comp_size / 1024 / 1024:.1f} MB',
|
||||
end='')
|
||||
if ext_fit_size:
|
||||
print(f', header {ext_fit_size:#x}/{ext_fit_size / 1024:.1f} KB',
|
||||
end='')
|
||||
print(f', {count} files, uncompressed {size / 1024 / 1024:.1f} MB')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run_make_fit())
|
@ -701,18 +701,18 @@
|
||||
* Permission Indirection Extension (PIE) permission encodings.
|
||||
* Encodings with the _O suffix, have overlays applied (Permission Overlay Extension).
|
||||
*/
|
||||
#define PIE_NONE_O 0x0
|
||||
#define PIE_R_O 0x1
|
||||
#define PIE_X_O 0x2
|
||||
#define PIE_RX_O 0x3
|
||||
#define PIE_RW_O 0x5
|
||||
#define PIE_RWnX_O 0x6
|
||||
#define PIE_RWX_O 0x7
|
||||
#define PIE_R 0x8
|
||||
#define PIE_GCS 0x9
|
||||
#define PIE_RX 0xa
|
||||
#define PIE_RW 0xc
|
||||
#define PIE_RWX 0xe
|
||||
#define PIE_NONE_O UL(0x0)
|
||||
#define PIE_R_O UL(0x1)
|
||||
#define PIE_X_O UL(0x2)
|
||||
#define PIE_RX_O UL(0x3)
|
||||
#define PIE_RW_O UL(0x5)
|
||||
#define PIE_RWnX_O UL(0x6)
|
||||
#define PIE_RWX_O UL(0x7)
|
||||
#define PIE_R UL(0x8)
|
||||
#define PIE_GCS UL(0x9)
|
||||
#define PIE_RX UL(0xa)
|
||||
#define PIE_RW UL(0xc)
|
||||
#define PIE_RWX UL(0xe)
|
||||
|
||||
#define PIRx_ELx_PERM(idx, perm) ((perm) << ((idx) * 4))
|
||||
|
||||
|
@ -262,7 +262,7 @@ static int write_clone_read(void)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
putstr("TAP version 13\n");
|
||||
putstr("1..");
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "../../kselftest.h"
|
||||
|
||||
#define SHIFT_TAG(tag) ((uint64_t)(tag) << 56)
|
||||
#define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \
|
||||
@ -21,6 +22,9 @@ int main(void)
|
||||
if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0)
|
||||
tbi_enabled = 1;
|
||||
ptr = (struct utsname *)malloc(sizeof(*ptr));
|
||||
if (!ptr)
|
||||
ksft_exit_fail_msg("Failed to allocate utsname buffer\n");
|
||||
|
||||
if (tbi_enabled)
|
||||
tag = 0x42;
|
||||
ptr = (struct utsname *)SET_TAG(ptr, tag);
|
||||
|
Loading…
Reference in New Issue
Block a user