Merge branch 'for-next/selftests' into for-next/core
authorWill Deacon <will@kernel.org>
Thu, 9 May 2024 14:56:18 +0000 (15:56 +0100)
committerWill Deacon <will@kernel.org>
Thu, 9 May 2024 14:56:18 +0000 (15:56 +0100)
* for-next/selftests:
  kselftest: arm64: Add a null pointer check
  kselftest/arm64: Remove unused parameters in abi test

57 files changed:
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/perf/hisi-pmu.rst
Documentation/admin-guide/perf/hns3-pmu.rst
Documentation/admin-guide/perf/qcom_l2_pmu.rst
Documentation/admin-guide/perf/qcom_l3_pmu.rst
Documentation/admin-guide/perf/thunderx2-pmu.rst
Documentation/admin-guide/perf/xgene-pmu.rst
Documentation/process/changes.rst
MAINTAINERS
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/.gitignore
arch/arm64/boot/Makefile
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/el2_setup.h
arch/arm64/include/asm/irqflags.h
arch/arm64/include/asm/jump_label.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/acpi.c
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/pi/idreg-override.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/stacktrace.c
arch/arm64/mm/mmu.c
arch/arm64/mm/proc.S
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbutils.c
drivers/perf/alibaba_uncore_drw_pmu.c
drivers/perf/amlogic/meson_ddr_pmu_core.c
drivers/perf/arm-cci.c
drivers/perf/arm-ccn.c
drivers/perf/arm-cmn.c
drivers/perf/arm_cspmu/arm_cspmu.c
drivers/perf/arm_dmc620_pmu.c
drivers/perf/arm_dsu_pmu.c
drivers/perf/arm_pmu_platform.c
drivers/perf/arm_smmuv3_pmu.c
drivers/perf/arm_spe_pmu.c
drivers/perf/dwc_pcie_pmu.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/perf/hisilicon/hisi_pcie_pmu.c
drivers/perf/hisilicon/hisi_uncore_pmu.c
drivers/perf/hisilicon/hns3_pmu.c
drivers/perf/qcom_l2_pmu.c
drivers/perf/qcom_l3_pmu.c
drivers/perf/riscv_pmu_legacy.c
drivers/perf/riscv_pmu_sbi.c
drivers/perf/thunderx2_pmu.c
drivers/perf/xgene_pmu.c
include/linux/cpumask.h
scripts/Makefile.lib
scripts/make_fit.py [new file with mode: 0755]
tools/arch/arm64/include/asm/sysreg.h

index 623fce7d5fcd0c4392432908e21aaba5134e3aa0..afd6fcc1e8b94cba4918c812d40d20bc660be25e 100644 (file)
        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
 
index e0174d20809a18470ab5809c4bd7336247826b15..5cc248d18c63a72ee351cdff9f28ad5c9234b5bc 100644 (file)
@@ -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.
 
index 75a40846d47f5f9fdff5ba3bc275ab382b4820a2..1195e570f2d6b592f912dd6b6d58c2930322a3ca 100644 (file)
@@ -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::
index c130178a4a55595c5b4ad6bb28dba85c7ff78e80..c37c6be9b8d889a3f129d94d0b0fce017f869edd 100644 (file)
@@ -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.
 
index a3d014a46bfdb3f12b1f762648b9e223ace15630..a66556b7e985c1eb38d03dda5728ee81fc903bd9 100644 (file)
@@ -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.
index 01f158238ae1ee1d0bdb445f272a1e15482edbae..9255f7bf945202a424e26ce196af7d93eb2eb1ec 100644 (file)
@@ -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.
index 644f8ed89152d69cfdbd97485bf2557948fd96e5..98ccb8e777c4d1f88160ea1c9930df5231545a1e 100644 (file)
@@ -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"
index 7ef8de58f7f89252fb4e9330542d622d969d6a4e..3a39395bd9d3b28f00e56a3a8bf53a93e36dadcc 100644 (file)
@@ -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
 ****************
 
index aea47e04c3a52aa6774a090c2bd17555306c4a02..9db17a2fe3b0db2a329c0883293ad6e53cdd06f9 100644 (file)
@@ -3051,6 +3051,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>
index 7b11c98b3e84bf76bcd6a33b34af257a9b7f48d7..a04059c31abab1e04b67f3322fb176cd1ba8905b 100644 (file)
@@ -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.
 
index 0e075d3c546b4820c1559a3811eb7c9fdebd2f4a..b8b1d4f4a572b03aa6f47643321e6fb79f0e4c21 100644 (file)
@@ -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'
index af5dc61f8b438852afac1ae66e007f53076e046a..abaae9de1bdda243ea10887b8e816bca9fc65854 100644 (file)
@@ -2,3 +2,4 @@
 Image
 Image.gz
 vmlinuz*
+image.fit
index a5a7873711173b518b5553ae2367b8058fffdde9..607a67a649c46395daee49082083b14c6382fa0a 100644 (file)
@@ -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
index ab8b396428da8ab920d4fd5cee7760b41c04a6b2..bc0b0d75acef7b46df814e0c49a1ac27ab7a75cc 100644 (file)
        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
index 52f076afeb96006c42dfee6edefcf348048af96b..936389e9aecbc717828cf9a595145f4bd540b98b 100644 (file)
@@ -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
 #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)
index b7afaa026842b7ebce94228e6031ce99f5cbb2a8..e4546b29dd0cbfbb5b902e15caadab69458b1fac 100644 (file)
 
 .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
index 0a7186a93882da715d0e72b61bbbf2ca6e0c6c23..d4d7451c2c129f47216d51200d29297610122112 100644 (file)
@@ -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>
index 6aafbb7899916e631eab9241c39c1313a7c93707..4e753908b80188f0e58b50a0048e1482e32ec94f 100644 (file)
 
 #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;
index dd9ee67d1d87c7a4638e4090e621a966c4c2a313..b11cfb9fdd379ab2eb6b9797af192d0679495bf3 100644 (file)
 #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)
index afdd56d26ad7004eecce8254cfe589c81eb8a285..bde9fd1793887907c4cc2991bb7ff3e89aaf44dd 100644 (file)
@@ -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)
index 9e8999592f3af5068b27717f137337e5af500165..af3b206fa42399c234d74b720daa91177b0acc34 100644 (file)
  * 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))
 
index dba8fcec7f33d6581848bbfd61b9e65f3413bcaa..e0e7b93c16cc430f5e60be3ebc23f58818c89d48 100644 (file)
@@ -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);
index 6d157f32187b73eb2935f647732cd19c4a758754..e8ed5673f48174bdd28799dfb39cec00606d0b5e 100644 (file)
 
 #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)
-{
-       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);
-
-       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;
-}
-
-#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)
+static bool callchain_trace(void *data, unsigned long pc)
 {
-       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;
+       struct perf_callchain_entry_ctx *entry = data;
 
-       return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
+       return perf_callchain_store(entry, pc) == 0;
 }
-#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,
index aad399796e812180aa4e8e244d30a97fb29950d9..48c1aa456af9054c51eae6dfae1b002c63fc478c 100644 (file)
@@ -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)
index 65a052bf741f04144d3d28600356209916746b8d..a096e2451044d35bad506ecb67edcf3f2d30b87c 100644 (file)
@@ -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);
 
index 4ced34f62dab59bc399290921061d75425473217..31c8b3094dd7bfd205470bffb079ac7d36ba6dae 100644 (file)
@@ -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);
 
        /*
index 684c26511696bbb264d9e2b988b8ed93f14a8e58..6b32588603778da3662a99f5d71b934ab44278b4 100644 (file)
@@ -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
+       }
+}
index 495b732d5af36f208291b28e1f1f167231b01e2d..c927e9312f102ec14384b51b22cf5d3a1740f067 100644 (file)
@@ -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,
-                    phys_addr_t phys, pgprot_t prot)
+static void init_clear_pgtable(void *table)
 {
-       pte_t *ptep;
+       clear_page(table);
 
-       ptep = pte_set_fixmap_offset(pmdp, addr);
+       /* 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)
+{
        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);
 }
 
index 9d40f3ffd8d233ba6fec0044fca5e71d9d586cb1..f4bc6c5bac0625386566763e1e5c485f311610f2 100644 (file)
@@ -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
 
index 44267a92bce5e2f586ae7e0aeb73a360a9090a1b..3c126c6d306b06446af06e5cb9f0c837a11896e7 100644 (file)
@@ -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);
        }
 }
 
index bb4a56e5673a5f71ec3157b3919d30962013f0f2..15fa68a5ea6e25b7160bbf40b8c085bf3aa865b2 100644 (file)
@@ -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,
index a9277dcf90ce0c6bd6ee97edb25b1a5814fc1e48..89dd38343f93ce29dba7b59b033cecbdd852f16d 100644 (file)
@@ -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)
index bbc7285fd934a3be5362d52c3e8c556da14e2fc2..07446d784a1a64ae54beec2cce75c9f6f522f83c 100644 (file)
@@ -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,
index 6be03f81ae5db7489dd6ae49790ee5f1c99ca37e..a7fd806779197fbc0cc5009a74b7ddec5ecd70d6 100644 (file)
@@ -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,
index 641471bd5eff4010e2124e28ff8a7b4f628fed98..f4495ff6525f65ba213e5b8a754437859fd4561a 100644 (file)
@@ -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,
index 7ef9c7e4836b72498db6cd8d5263c2ea5bf9f730..e26ad1d3ed0bb73dcc92116cba47c4936d200b8d 100644 (file)
@@ -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,
index b9a252272f1e9f596db7aeba99f4d28dd6b95f84..ba0cf2f466ef000f25170068354a40d60ce41262 100644 (file)
@@ -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;
 
index 8a81be2dd5ecf56fe82f1d5e0e823c220942a255..2ec96e204c403ec7b3403561433ccddf97fbb743 100644 (file)
@@ -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,
index bae3ca37f846ee9d7fb9c982ae3eb7d740e11ba7..92248a24a1aabe36f4f2c7004ab8609f34eaac1f 100644 (file)
@@ -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;
index 3596db36cbff4f99f096a6d2cbadb440b8c6ef03..4b1a9a92ea117b13ed6cd004d520bb53723c989d 100644 (file)
@@ -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);
index 719aa953a1c4d6cff65426ae6099859065380543..d5fa92ba8373976982a35cd5d706551d885e657e 100644 (file)
@@ -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,
index 35f0de03416fc052c79e0f3dfe2fa869a6964fe3..9100d82bfabc0d5f99216f05befd713d9b67f483 100644 (file)
@@ -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,
                /*
index 957058ad0099e2faa97c28d22153285983abf045..c5e328f2384194b9e273ef6834662f7f0af630b9 100644 (file)
@@ -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) {
index 4e8fa5a48fcfe0477e8a869af4ea83a759632ba7..1bbdb29743c442c2a2a840b3154aa80f22b26da4 100644 (file)
@@ -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,
index 5d1f0e9fdb08d2ecdbff6170b8172859b196c12d..03c506aa385388ed88f596604c09e9bc4af23905 100644 (file)
@@ -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,
index 04031450d5fecae9c5740deb553f4ce0ea574673..a60e4c9660987664d322bcc3edd1fcdb469c75bf 100644 (file)
@@ -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;
index 16869bf5bf4cca7ecdaea40db1c13a4a7eeb7be3..e900f8e00b1891e431cfcd9803dbea81907a4ae0 100644 (file)
@@ -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;
index 148df5ae8ef8322e8ca577868b64cbb3099c0cc2..980e3051edd72522cd6b494f4ce1e17d5fc7ec05 100644 (file)
@@ -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,
index f16783d03db7b6be3bead4d8e331d1b9f7cec936..37786e88514e8cd8136b3f9b267109d4e00735c3 100644 (file)
@@ -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,
index fa0bccf4edf2ea6172c7ee72d577cb0904073ea7..04487ad7fba0b538508ba3ae3628e437d2dc1b53 100644 (file)
@@ -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;
index 8cbe6e5f9c39a6f5b585251b02908b8b7309e23d..82636273d726595f4f460f84ed470e64d69a990d 100644 (file)
@@ -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;
index e16d10c763de193d5ef77949c8836d62c0358b44..faf763d2c95cb8935538f43d05e686285cc923e9 100644 (file)
@@ -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)
index 0d49343d704b7c971b1616527f4a0190d9f89f19..8823b4c6b55613bc3370790fce7139ab28aa6c20 100644 (file)
@@ -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,
index 1c29947db84899cd72b00a8c77685972dc187b80..121f3ac757ffee302b4bb486e003ffbbdf955826 100644 (file)
@@ -388,6 +388,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
index 3179747cbd2cc014d0a8ba98cff008f28fbbc050..afa1099b6b8e5a3a78bde33627b65ca587d121e2 100644 (file)
@@ -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.
diff --git a/scripts/make_fit.py b/scripts/make_fit.py
new file mode 100755 (executable)
index 0000000..3de90c5
--- /dev/null
@@ -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())
index ccc13e9913760b5a6a85ec78430d873fe22ca51f..cd8420e8c3ad8c09499cca7d85a22e3dd60e6ded 100644 (file)
  * 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))