Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Apr 2015 18:58:29 +0000 (13:58 -0500)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Apr 2015 18:58:29 +0000 (13:58 -0500)
Pull arm64 updates from Will Deacon:
 "Here are the core arm64 updates for 4.1.

  Highlights include a significant rework to head.S (allowing us to boot
  on machines with physical memory at a really high address), an AES
  performance boost on Cortex-A57 and the ability to run a 32-bit
  userspace with 64k pages (although this requires said userspace to be
  built with a recent binutils).

  The head.S rework spilt over into KVM, so there are some changes under
  arch/arm/ which have been acked by Marc Zyngier (KVM co-maintainer).
  In particular, the linker script changes caused us some issues in
  -next, so there are a few merge commits where we had to apply fixes on
  top of a stable branch.

  Other changes include:

   - AES performance boost for Cortex-A57
   - AArch32 (compat) userspace with 64k pages
   - Cortex-A53 erratum workaround for #845719
   - defconfig updates (new platforms, PCI, ...)"

* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (39 commits)
  arm64: fix midr range for Cortex-A57 erratum 832075
  arm64: errata: add workaround for cortex-a53 erratum #845719
  arm64: Use bool function return values of true/false not 1/0
  arm64: defconfig: updates for 4.1
  arm64: Extract feature parsing code from cpu_errata.c
  arm64: alternative: Allow immediate branch as alternative instruction
  arm64: insn: Add aarch64_insn_decode_immediate
  ARM: kvm: round HYP section to page size instead of log2 upper bound
  ARM: kvm: assert on HYP section boundaries not actual code size
  arm64: head.S: ensure idmap_t0sz is visible
  arm64: pmu: add support for interrupt-affinity property
  dt: pmu: extend ARM PMU binding to allow for explicit interrupt affinity
  arm64: head.S: ensure visibility of page tables
  arm64: KVM: use ID map with increased VA range if required
  arm64: mm: increase VA range of identity map
  ARM: kvm: implement replacement for ld's LOG2CEIL()
  arm64: proc: remove unused cpu_get_pgd macro
  arm64: enforce x1|x2|x3 == 0 upon kernel entry as per boot protocol
  arm64: remove __calc_phys_offset
  arm64: merge __enable_mmu and __turn_mmu_on
  ...

45 files changed:
Documentation/devicetree/bindings/arm/pmu.txt
arch/arm/include/asm/kvm_mmu.h
arch/arm/kernel/vmlinux.lds.S
arch/arm/kvm/mmu.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/configs/defconfig
arch/arm64/crypto/aes-ce-ccm-core.S
arch/arm64/crypto/aes-ce.S
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputable.h [deleted file]
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/page.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/pmu.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/smp_plat.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/alternative.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c [new file with mode: 0644]
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/cputable.c [deleted file]
arch/arm64/kernel/entry.S
arch/arm64/kernel/entry32.S
arch/arm64/kernel/head.S
arch/arm64/kernel/insn.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/sys32.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/hyp-init.S
arch/arm64/mm/mmu.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/proc-macros.S
arch/arm64/mm/proc.S

index 6e54a9d88b7ab753dd2063a03dd6b39daff8e8db..3b5f5d1088c6399f0fa8145717134cf2a96d08ba 100644 (file)
@@ -26,6 +26,13 @@ Required properties:
 
 Optional properties:
 
+- interrupt-affinity : Valid only when using SPIs, specifies a list of phandles
+                       to CPU nodes corresponding directly to the affinity of
+                      the SPIs listed in the interrupts property.
+
+                      This property should be present when there is more than
+                      a single SPI.
+
 - qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd
                      events.
 
index 4cf48c3aca13e9afe7b852660afa4d5945994a93..405aa18833073b88b52103363b54d534d9c69263 100644 (file)
@@ -269,6 +269,16 @@ static inline void __kvm_flush_dcache_pud(pud_t pud)
 void kvm_set_way_flush(struct kvm_vcpu *vcpu);
 void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
 
+static inline bool __kvm_cpu_uses_extended_idmap(void)
+{
+       return false;
+}
+
+static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
+                                      pgd_t *hyp_pgd,
+                                      pgd_t *merged_hyp_pgd,
+                                      unsigned long hyp_idmap_start) { }
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ARM_KVM_MMU_H__ */
index 7a301be9ac6784e999f2aa44a91cae1edb3f62a0..8b60fde5ce48a628e5d1f2c682d2aa0684ed6642 100644 (file)
@@ -11,7 +11,7 @@
 #ifdef CONFIG_ARM_KERNMEM_PERMS
 #include <asm/pgtable.h>
 #endif
-       
+
 #define PROC_INFO                                                      \
        . = ALIGN(4);                                                   \
        VMLINUX_SYMBOL(__proc_info_begin) = .;                          \
@@ -23,7 +23,7 @@
        VMLINUX_SYMBOL(__idmap_text_start) = .;                         \
        *(.idmap.text)                                                  \
        VMLINUX_SYMBOL(__idmap_text_end) = .;                           \
-       . = ALIGN(32);                                                  \
+       . = ALIGN(PAGE_SIZE);                                           \
        VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;                     \
        *(.hyp.idmap.text)                                              \
        VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
@@ -343,8 +343,11 @@ SECTIONS
  */
 ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
 ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
+
 /*
- * The HYP init code can't be more than a page long.
+ * The HYP init code can't be more than a page long,
+ * and should not cross a page boundary.
  * The above comment applies as well.
  */
-ASSERT(((__hyp_idmap_text_end - __hyp_idmap_text_start) <= PAGE_SIZE), "HYP init code too big")
+ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
+       "HYP init code too big or misaligned")
index 15b050d46fc968afdc53029ada4b7d945ee23515..1d5accbd3dcf2ae771e7ba9475c8607846a05a0d 100644 (file)
@@ -35,9 +35,9 @@ extern char  __hyp_idmap_text_start[], __hyp_idmap_text_end[];
 
 static pgd_t *boot_hyp_pgd;
 static pgd_t *hyp_pgd;
+static pgd_t *merged_hyp_pgd;
 static DEFINE_MUTEX(kvm_hyp_pgd_mutex);
 
-static void *init_bounce_page;
 static unsigned long hyp_idmap_start;
 static unsigned long hyp_idmap_end;
 static phys_addr_t hyp_idmap_vector;
@@ -405,9 +405,6 @@ void free_boot_hyp_pgd(void)
        if (hyp_pgd)
                unmap_range(NULL, hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
 
-       free_page((unsigned long)init_bounce_page);
-       init_bounce_page = NULL;
-
        mutex_unlock(&kvm_hyp_pgd_mutex);
 }
 
@@ -438,6 +435,11 @@ void free_hyp_pgds(void)
                free_pages((unsigned long)hyp_pgd, hyp_pgd_order);
                hyp_pgd = NULL;
        }
+       if (merged_hyp_pgd) {
+               clear_page(merged_hyp_pgd);
+               free_page((unsigned long)merged_hyp_pgd);
+               merged_hyp_pgd = NULL;
+       }
 
        mutex_unlock(&kvm_hyp_pgd_mutex);
 }
@@ -1622,12 +1624,18 @@ void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 
 phys_addr_t kvm_mmu_get_httbr(void)
 {
-       return virt_to_phys(hyp_pgd);
+       if (__kvm_cpu_uses_extended_idmap())
+               return virt_to_phys(merged_hyp_pgd);
+       else
+               return virt_to_phys(hyp_pgd);
 }
 
 phys_addr_t kvm_mmu_get_boot_httbr(void)
 {
-       return virt_to_phys(boot_hyp_pgd);
+       if (__kvm_cpu_uses_extended_idmap())
+               return virt_to_phys(merged_hyp_pgd);
+       else
+               return virt_to_phys(boot_hyp_pgd);
 }
 
 phys_addr_t kvm_get_idmap_vector(void)
@@ -1643,39 +1651,11 @@ int kvm_mmu_init(void)
        hyp_idmap_end = kvm_virt_to_phys(__hyp_idmap_text_end);
        hyp_idmap_vector = kvm_virt_to_phys(__kvm_hyp_init);
 
-       if ((hyp_idmap_start ^ hyp_idmap_end) & PAGE_MASK) {
-               /*
-                * Our init code is crossing a page boundary. Allocate
-                * a bounce page, copy the code over and use that.
-                */
-               size_t len = __hyp_idmap_text_end - __hyp_idmap_text_start;
-               phys_addr_t phys_base;
-
-               init_bounce_page = (void *)__get_free_page(GFP_KERNEL);
-               if (!init_bounce_page) {
-                       kvm_err("Couldn't allocate HYP init bounce page\n");
-                       err = -ENOMEM;
-                       goto out;
-               }
-
-               memcpy(init_bounce_page, __hyp_idmap_text_start, len);
-               /*
-                * Warning: the code we just copied to the bounce page
-                * must be flushed to the point of coherency.
-                * Otherwise, the data may be sitting in L2, and HYP
-                * mode won't be able to observe it as it runs with
-                * caches off at that point.
-                */
-               kvm_flush_dcache_to_poc(init_bounce_page, len);
-
-               phys_base = kvm_virt_to_phys(init_bounce_page);
-               hyp_idmap_vector += phys_base - hyp_idmap_start;
-               hyp_idmap_start = phys_base;
-               hyp_idmap_end = phys_base + len;
-
-               kvm_info("Using HYP init bounce page @%lx\n",
-                        (unsigned long)phys_base);
-       }
+       /*
+        * We rely on the linker script to ensure at build time that the HYP
+        * init code does not cross a page boundary.
+        */
+       BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
 
        hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, hyp_pgd_order);
        boot_hyp_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, hyp_pgd_order);
@@ -1698,6 +1678,17 @@ int kvm_mmu_init(void)
                goto out;
        }
 
+       if (__kvm_cpu_uses_extended_idmap()) {
+               merged_hyp_pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+               if (!merged_hyp_pgd) {
+                       kvm_err("Failed to allocate extra HYP pgd\n");
+                       goto out;
+               }
+               __kvm_extend_hypmap(boot_hyp_pgd, hyp_pgd, merged_hyp_pgd,
+                                   hyp_idmap_start);
+               return 0;
+       }
+
        /* Map the very same page at the trampoline VA */
        err =   __create_hyp_mappings(boot_hyp_pgd,
                                      TRAMPOLINE_VA, TRAMPOLINE_VA + PAGE_SIZE,
index 34f487d5d84e4dbdc5253b2fd7b9f1a248d31646..b8d96f1554af11aef71af0627278925f244067a9 100644 (file)
@@ -368,6 +368,27 @@ config ARM64_ERRATUM_832075
 
          If unsure, say Y.
 
+config ARM64_ERRATUM_845719
+       bool "Cortex-A53: 845719: a load might read incorrect data"
+       depends on COMPAT
+       default y
+       help
+         This option adds an alternative code sequence to work around ARM
+         erratum 845719 on Cortex-A53 parts up to r0p4.
+
+         When running a compat (AArch32) userspace on an affected Cortex-A53
+         part, a load at EL0 from a virtual address that matches the bottom 32
+         bits of the virtual address used by a recent load at (AArch64) EL1
+         might return incorrect data.
+
+         The workaround is to write the contextidr_el1 register on exception
+         return to a 32-bit task.
+         Please note that this does not necessarily enable the workaround,
+         as it depends on the alternative framework, which will only patch
+         the kernel if an affected CPU is detected.
+
+         If unsure, say Y.
+
 endmenu
 
 
@@ -455,8 +476,8 @@ config SCHED_SMT
          places. If unsure say N here.
 
 config NR_CPUS
-       int "Maximum number of CPUs (2-64)"
-       range 2 64
+       int "Maximum number of CPUs (2-4096)"
+       range 2 4096
        depends on SMP
        # These have to remain sorted largest to smallest
        default "64"
@@ -470,6 +491,10 @@ config HOTPLUG_CPU
 
 source kernel/Kconfig.preempt
 
+config UP_LATE_INIT
+       def_bool y
+       depends on !SMP
+
 config HZ
        int
        default 100
@@ -670,7 +695,7 @@ source "fs/Kconfig.binfmt"
 
 config COMPAT
        bool "Kernel support for 32-bit EL0"
-       depends on !ARM64_64K_PAGES
+       depends on !ARM64_64K_PAGES || EXPERT
        select COMPAT_BINFMT_ELF
        select HAVE_UID16
        select OLD_SIGSUSPEND3
@@ -681,6 +706,10 @@ config COMPAT
          the user helper functions, VFP support and the ptrace interface are
          handled appropriately by the kernel.
 
+         If you also enabled CONFIG_ARM64_64K_PAGES, please be aware that you
+         will only be able to execute AArch32 binaries that were compiled with
+         64k aligned segments.
+
          If you want to execute 32-bit userspace applications, say Y.
 
 config SYSVIPC_COMPAT
index 69ceedc982a50a128698741b54fbe937db8a2d74..4d2a925998f925268a38f661018e2a40c637548a 100644 (file)
@@ -48,7 +48,7 @@ core-$(CONFIG_KVM) += arch/arm64/kvm/
 core-$(CONFIG_XEN) += arch/arm64/xen/
 core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
 libs-y         := arch/arm64/lib/ $(libs-y)
-libs-$(CONFIG_EFI_STUB) += drivers/firmware/efi/libstub/
+core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 
 # Default target when executing plain make
 KBUILD_IMAGE   := Image.gz
index af6a452b1aac2b404a57c420ab86b5b8fb4f619f..4e03d8dd23f6fe7423df8971484195b071756cd5 100644 (file)
@@ -31,8 +31,12 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_EXYNOS7=y
 CONFIG_ARCH_FSL_LS2085A=y
 CONFIG_ARCH_MEDIATEK=y
+CONFIG_ARCH_SEATTLE=y
+CONFIG_ARCH_TEGRA=y
+CONFIG_ARCH_TEGRA_132_SOC=y
 CONFIG_ARCH_THUNDER=y
 CONFIG_ARCH_VEXPRESS=y
 CONFIG_ARCH_XGENE=y
@@ -62,6 +66,7 @@ CONFIG_BPF_JIT=y
 # CONFIG_WIRELESS is not set
 CONFIG_NET_9P=y
 CONFIG_NET_9P_VIRTIO=y
+# CONFIG_TEGRA_AHB is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_DEVTMPFS=y
 CONFIG_DEVTMPFS_MOUNT=y
@@ -81,6 +86,7 @@ CONFIG_NETDEVICES=y
 CONFIG_TUN=y
 CONFIG_VIRTIO_NET=y
 CONFIG_NET_XGENE=y
+CONFIG_SKY2=y
 CONFIG_SMC91X=y
 CONFIG_SMSC911X=y
 # CONFIG_WLAN is not set
@@ -100,6 +106,8 @@ CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_PL061=y
 CONFIG_GPIO_XGENE=y
+CONFIG_POWER_RESET_XGENE=y
+CONFIG_POWER_RESET_SYSCON=y
 # CONFIG_HWMON is not set
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -112,10 +120,10 @@ CONFIG_LOGO=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_ISP1760_HCD=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_ISP1760=y
 CONFIG_USB_ULPI=y
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
@@ -125,6 +133,7 @@ CONFIG_MMC_SPI=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_EFI=y
 CONFIG_RTC_DRV_XGENE=y
+CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
 CONFIG_VIRTIO_MMIO=y
 # CONFIG_IOMMU_SUPPORT is not set
@@ -143,8 +152,10 @@ CONFIG_CUSE=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
+CONFIG_EFIVAR_FS=y
 # CONFIG_MISC_FILESYSTEMS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_9P_FS=y
 CONFIG_NLS_CODEPAGE_437=y
@@ -159,7 +170,6 @@ CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_FTRACE is not set
-CONFIG_KEYS=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_ARM64_CRYPTO=y
index 432e4841cd811b0a15c087d51fc325fec162c1de..a2a7fbcacc141ed595f31026510cecd459a733f0 100644 (file)
@@ -101,19 +101,19 @@ ENTRY(ce_aes_ccm_final)
 0:     mov     v4.16b, v3.16b
 1:     ld1     {v5.2d}, [x2], #16              /* load next round key */
        aese    v0.16b, v4.16b
-       aese    v1.16b, v4.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v4.16b
        aesmc   v1.16b, v1.16b
 2:     ld1     {v3.2d}, [x2], #16              /* load next round key */
        aese    v0.16b, v5.16b
-       aese    v1.16b, v5.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v5.16b
        aesmc   v1.16b, v1.16b
 3:     ld1     {v4.2d}, [x2], #16              /* load next round key */
        subs    w3, w3, #3
        aese    v0.16b, v3.16b
-       aese    v1.16b, v3.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v3.16b
        aesmc   v1.16b, v1.16b
        bpl     1b
        aese    v0.16b, v4.16b
@@ -146,19 +146,19 @@ ENDPROC(ce_aes_ccm_final)
        ld1     {v5.2d}, [x10], #16             /* load 2nd round key */
 2:     /* inner loop: 3 rounds, 2x interleaved */
        aese    v0.16b, v4.16b
-       aese    v1.16b, v4.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v4.16b
        aesmc   v1.16b, v1.16b
 3:     ld1     {v3.2d}, [x10], #16             /* load next round key */
        aese    v0.16b, v5.16b
-       aese    v1.16b, v5.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v5.16b
        aesmc   v1.16b, v1.16b
 4:     ld1     {v4.2d}, [x10], #16             /* load next round key */
        subs    w7, w7, #3
        aese    v0.16b, v3.16b
-       aese    v1.16b, v3.16b
        aesmc   v0.16b, v0.16b
+       aese    v1.16b, v3.16b
        aesmc   v1.16b, v1.16b
        ld1     {v5.2d}, [x10], #16             /* load next round key */
        bpl     2b
index 685a18f731eb64b1de808fa124f7e28241ab8765..78f3cfe92c0872345992203a6501ba0460cc2c91 100644 (file)
 
        .macro          do_enc_Nx, de, mc, k, i0, i1, i2, i3
        aes\de          \i0\().16b, \k\().16b
-       .ifnb           \i1
-       aes\de          \i1\().16b, \k\().16b
-       .ifnb           \i3
-       aes\de          \i2\().16b, \k\().16b
-       aes\de          \i3\().16b, \k\().16b
-       .endif
-       .endif
        aes\mc          \i0\().16b, \i0\().16b
        .ifnb           \i1
+       aes\de          \i1\().16b, \k\().16b
        aes\mc          \i1\().16b, \i1\().16b
        .ifnb           \i3
+       aes\de          \i2\().16b, \k\().16b
        aes\mc          \i2\().16b, \i2\().16b
+       aes\de          \i3\().16b, \k\().16b
        aes\mc          \i3\().16b, \i3\().16b
        .endif
        .endif
index 750bac4e637e5323f29bd4859b6e655b3a035d95..144b64ad96c33bc80904ed053abdef2c6b5cf791 100644 (file)
@@ -159,4 +159,52 @@ lr .req    x30             // link register
        orr     \rd, \lbits, \hbits, lsl #32
        .endm
 
+/*
+ * Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
+ * <symbol> is within the range +/- 4 GB of the PC.
+ */
+       /*
+        * @dst: destination register (64 bit wide)
+        * @sym: name of the symbol
+        * @tmp: optional scratch register to be used if <dst> == sp, which
+        *       is not allowed in an adrp instruction
+        */
+       .macro  adr_l, dst, sym, tmp=
+       .ifb    \tmp
+       adrp    \dst, \sym
+       add     \dst, \dst, :lo12:\sym
+       .else
+       adrp    \tmp, \sym
+       add     \dst, \tmp, :lo12:\sym
+       .endif
+       .endm
+
+       /*
+        * @dst: destination register (32 or 64 bit wide)
+        * @sym: name of the symbol
+        * @tmp: optional 64-bit scratch register to be used if <dst> is a
+        *       32-bit wide register, in which case it cannot be used to hold
+        *       the address
+        */
+       .macro  ldr_l, dst, sym, tmp=
+       .ifb    \tmp
+       adrp    \dst, \sym
+       ldr     \dst, [\dst, :lo12:\sym]
+       .else
+       adrp    \tmp, \sym
+       ldr     \dst, [\tmp, :lo12:\sym]
+       .endif
+       .endm
+
+       /*
+        * @src: source register (32 or 64 bit wide)
+        * @sym: name of the symbol
+        * @tmp: mandatory 64-bit scratch register to calculate the address
+        *       while <src> needs to be preserved.
+        */
+       .macro  str_l, src, sym, tmp
+       adrp    \tmp, \sym
+       str     \src, [\tmp, :lo12:\sym]
+       .endm
+
 #endif /* __ASM_ASSEMBLER_H */
index b6c16d5f622fd046a36f954ac589fe1e7ddfbf98..82cb9f98ba1a3632ffbc87bff8681cb8a7eb24ff 100644 (file)
 
 #define ARM64_WORKAROUND_CLEAN_CACHE           0
 #define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE   1
+#define ARM64_WORKAROUND_845719                        2
 
-#define ARM64_NCAPS                            2
+#define ARM64_NCAPS                            3
 
 #ifndef __ASSEMBLY__
 
+struct arm64_cpu_capabilities {
+       const char *desc;
+       u16 capability;
+       bool (*matches)(const struct arm64_cpu_capabilities *);
+       union {
+               struct {        /* To be used for erratum handling only */
+                       u32 midr_model;
+                       u32 midr_range_min, midr_range_max;
+               };
+       };
+};
+
 extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
 
 static inline bool cpu_have_feature(unsigned int num)
@@ -51,7 +64,10 @@ static inline void cpus_set_cap(unsigned int num)
                __set_bit(num, cpu_hwcaps);
 }
 
+void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
+                           const char *info);
 void check_local_cpu_errata(void);
+void check_local_cpu_features(void);
 bool cpu_supports_mixed_endian_el0(void);
 bool system_supports_mixed_endian_el0(void);
 
diff --git a/arch/arm64/include/asm/cputable.h b/arch/arm64/include/asm/cputable.h
deleted file mode 100644 (file)
index e3bd983..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * arch/arm64/include/asm/cputable.h
- *
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-#ifndef __ASM_CPUTABLE_H
-#define __ASM_CPUTABLE_H
-
-struct cpu_info {
-       unsigned int    cpu_id_val;
-       unsigned int    cpu_id_mask;
-       const char      *cpu_name;
-       unsigned long   (*cpu_setup)(void);
-};
-
-extern struct cpu_info *lookup_processor_type(unsigned int);
-
-#endif
index 6932bb57dba0210cd2605dc4081571f84150b615..9437e3dc58338ea4c48b9b6afe24d62bc09a7c79 100644 (file)
@@ -97,7 +97,7 @@ static inline int dma_set_mask(struct device *dev, u64 mask)
 static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
 {
        if (!dev->dma_mask)
-               return 0;
+               return false;
 
        return addr + size - 1 <= *dev->dma_mask;
 }
index defa0ff982509c19928db8937097e714cc5e8c54..92649568655474296e38f1f49697bf25ec3b0b75 100644 (file)
@@ -33,6 +33,7 @@
 enum fixed_addresses {
        FIX_HOLE,
        FIX_EARLYCON_MEM_BASE,
+       FIX_TEXT_POKE0,
        __end_of_permanent_fixed_addresses,
 
        /*
@@ -49,7 +50,6 @@ enum fixed_addresses {
 
        FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
        FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
-       FIX_TEXT_POKE0,
        __end_of_fixed_addresses
 };
 
index d2f49423c5dcbad70f63cbe777d522edbd41da75..f81b328d9cf4034991e41d2ce3c621c1b7182c49 100644 (file)
@@ -285,6 +285,7 @@ bool aarch64_insn_is_nop(u32 insn);
 int aarch64_insn_read(void *addr, u32 *insnp);
 int aarch64_insn_write(void *addr, u32 insn);
 enum aarch64_insn_encoding_class aarch64_get_insn_class(u32 insn);
+u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn);
 u32 aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
                                  u32 insn, u64 imm);
 u32 aarch64_insn_gen_branch_imm(unsigned long pc, unsigned long addr,
index 36250705dc4c0fe242057e8a4c793c56dc1db951..61505676d0853bb65710fc9ad7746db8f58e4658 100644 (file)
@@ -68,6 +68,8 @@
 #include <asm/pgalloc.h>
 #include <asm/cachetype.h>
 #include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
 
 #define KERN_TO_HYP(kva)       ((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OFFSET)
 
@@ -269,5 +271,36 @@ static inline void __kvm_flush_dcache_pud(pud_t pud)
 void kvm_set_way_flush(struct kvm_vcpu *vcpu);
 void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
 
+static inline bool __kvm_cpu_uses_extended_idmap(void)
+{
+       return __cpu_uses_extended_idmap();
+}
+
+static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
+                                      pgd_t *hyp_pgd,
+                                      pgd_t *merged_hyp_pgd,
+                                      unsigned long hyp_idmap_start)
+{
+       int idmap_idx;
+
+       /*
+        * Use the first entry to access the HYP mappings. It is
+        * guaranteed to be free, otherwise we wouldn't use an
+        * extended idmap.
+        */
+       VM_BUG_ON(pgd_val(merged_hyp_pgd[0]));
+       merged_hyp_pgd[0] = __pgd(__pa(hyp_pgd) | PMD_TYPE_TABLE);
+
+       /*
+        * Create another extended level entry that points to the boot HYP map,
+        * which contains an ID mapping of the HYP init code. We essentially
+        * merge the boot and runtime HYP maps by doing so, but they don't
+        * overlap anyway, so this is fine.
+        */
+       idmap_idx = hyp_idmap_start >> VA_BITS;
+       VM_BUG_ON(pgd_val(merged_hyp_pgd[idmap_idx]));
+       merged_hyp_pgd[idmap_idx] = __pgd(__pa(boot_hyp_pgd) | PMD_TYPE_TABLE);
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ARM64_KVM_MMU_H__ */
index 101a42bde728a8b9547bca989b696d473dcd7e42..8ec41e5f56f081b9d65d2ed58769a0f22060716d 100644 (file)
@@ -64,6 +64,49 @@ static inline void cpu_set_reserved_ttbr0(void)
        : "r" (ttbr));
 }
 
+/*
+ * TCR.T0SZ value to use when the ID map is active. Usually equals
+ * TCR_T0SZ(VA_BITS), unless system RAM is positioned very high in
+ * physical memory, in which case it will be smaller.
+ */
+extern u64 idmap_t0sz;
+
+static inline bool __cpu_uses_extended_idmap(void)
+{
+       return (!IS_ENABLED(CONFIG_ARM64_VA_BITS_48) &&
+               unlikely(idmap_t0sz != TCR_T0SZ(VA_BITS)));
+}
+
+static inline void __cpu_set_tcr_t0sz(u64 t0sz)
+{
+       unsigned long tcr;
+
+       if (__cpu_uses_extended_idmap())
+               asm volatile (
+               "       mrs     %0, tcr_el1     ;"
+               "       bfi     %0, %1, %2, %3  ;"
+               "       msr     tcr_el1, %0     ;"
+               "       isb"
+               : "=&r" (tcr)
+               : "r"(t0sz), "I"(TCR_T0SZ_OFFSET), "I"(TCR_TxSZ_WIDTH));
+}
+
+/*
+ * Set TCR.T0SZ to the value appropriate for activating the identity map.
+ */
+static inline void cpu_set_idmap_tcr_t0sz(void)
+{
+       __cpu_set_tcr_t0sz(idmap_t0sz);
+}
+
+/*
+ * Set TCR.T0SZ to its default value (based on VA_BITS)
+ */
+static inline void cpu_set_default_tcr_t0sz(void)
+{
+       __cpu_set_tcr_t0sz(TCR_T0SZ(VA_BITS));
+}
+
 static inline void switch_new_context(struct mm_struct *mm)
 {
        unsigned long flags;
index 8fc8fa280e92a4ed468807211f05b5662c7ce292..7d9c7e4a424bddd87dfdbd34e2be0d05b2078f58 100644 (file)
@@ -33,7 +33,9 @@
  * image. Both require pgd, pud (4 levels only) and pmd tables to (section)
  * map the kernel. With the 64K page configuration, swapper and idmap need to
  * map to pte level. The swapper also maps the FDT (see __create_page_tables
- * for more information).
+ * for more information). Note that the number of ID map translation levels
+ * could be increased on the fly if system RAM is out of reach for the default
+ * VA range, so 3 pages are reserved in all cases.
  */
 #ifdef CONFIG_ARM64_64K_PAGES
 #define SWAPPER_PGTABLE_LEVELS (CONFIG_PGTABLE_LEVELS)
@@ -42,7 +44,7 @@
 #endif
 
 #define SWAPPER_DIR_SIZE       (SWAPPER_PGTABLE_LEVELS * PAGE_SIZE)
-#define IDMAP_DIR_SIZE         (SWAPPER_DIR_SIZE)
+#define IDMAP_DIR_SIZE         (3 * PAGE_SIZE)
 
 #ifndef __ASSEMBLY__
 
index 80f3d241cff806b124b4c7e5650604d206139244..59bfae75dc9800da3b6f65050bc6f025848d3c4d 100644 (file)
 /*
  * TCR flags.
  */
-#define TCR_TxSZ(x)            (((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0))
+#define TCR_T0SZ_OFFSET                0
+#define TCR_T1SZ_OFFSET                16
+#define TCR_T0SZ(x)            ((UL(64) - (x)) << TCR_T0SZ_OFFSET)
+#define TCR_T1SZ(x)            ((UL(64) - (x)) << TCR_T1SZ_OFFSET)
+#define TCR_TxSZ(x)            (TCR_T0SZ(x) | TCR_T1SZ(x))
+#define TCR_TxSZ_WIDTH         6
 #define TCR_IRGN_NC            ((UL(0) << 8) | (UL(0) << 24))
 #define TCR_IRGN_WBWA          ((UL(1) << 8) | (UL(1) << 24))
 #define TCR_IRGN_WT            ((UL(2) << 8) | (UL(2) << 24))
index e6f087806aaf11d65732aca8ffb221b291a53c85..b7710a59672c0355b8a6096937bdbc3c703f1cdf 100644 (file)
@@ -44,6 +44,7 @@ struct pmu_hw_events {
 struct arm_pmu {
        struct pmu              pmu;
        cpumask_t               active_irqs;
+       int                     *irq_affinity;
        const char              *name;
        irqreturn_t             (*handle_irq)(int irq_num, void *dev);
        void                    (*enable)(struct hw_perf_event *evt, int idx);
index 941c375616e2072d3b9fbf6442426c3491f00c01..220633b791b819b3346d36d0ff0a959c4dfbef02 100644 (file)
@@ -45,15 +45,6 @@ do {                                                 \
        cpu_do_switch_mm(virt_to_phys(pgd),mm);         \
 } while (0)
 
-#define cpu_get_pgd()                                  \
-({                                                     \
-       unsigned long pg;                               \
-       asm("mrs        %0, ttbr0_el1\n"                \
-           : "=r" (pg));                               \
-       pg &= ~0xffff000000003ffful;                    \
-       (pgd_t *)phys_to_virt(pg);                      \
-})
-
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_PROCFNS_H */
index 20e9591a60cff97c5ef3c93cbadab1aa1312fe09..d2c37a1df0ebaf2d610f3c5be77759c914b8d597 100644 (file)
@@ -127,7 +127,11 @@ extern void release_thread(struct task_struct *);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#define cpu_relax()                    barrier()
+static inline void cpu_relax(void)
+{
+       asm volatile("yield" ::: "memory");
+}
+
 #define cpu_relax_lowlatency()                cpu_relax()
 
 /* Thread switching */
index 59e282311b582b76b975fa5fe5520090a3f3687d..8dcd61e32176b4500939bba9f05e63ba591e5a8b 100644 (file)
@@ -40,4 +40,6 @@ static inline u32 mpidr_hash_size(void)
 extern u64 __cpu_logical_map[NR_CPUS];
 #define cpu_logical_map(cpu)    __cpu_logical_map[cpu]
 
+void __init do_post_cpus_up_work(void);
+
 #endif /* __ASM_SMP_PLAT_H */
index 27224426e0bf920de713c22cd4b6ca125c84d9bf..cef934a90f17ecec303a1dcd12133a962f27b9d1 100644 (file)
@@ -406,7 +406,7 @@ __SYSCALL(__NR_vfork, sys_vfork)
 #define __NR_ugetrlimit 191    /* SuS compliant getrlimit */
 __SYSCALL(__NR_ugetrlimit, compat_sys_getrlimit)               /* SuS compliant getrlimit */
 #define __NR_mmap2 192
-__SYSCALL(__NR_mmap2, sys_mmap_pgoff)
+__SYSCALL(__NR_mmap2, compat_sys_mmap2_wrapper)
 #define __NR_truncate64 193
 __SYSCALL(__NR_truncate64, compat_sys_truncate64_wrapper)
 #define __NR_ftruncate64 194
index 5ee07eee80c2b0c1f5ba2b1292420eb396103be0..b12e15b80516af7862ef6c88be568498173f2b17 100644 (file)
@@ -12,12 +12,12 @@ CFLAGS_REMOVE_insn.o = -pg
 CFLAGS_REMOVE_return_address.o = -pg
 
 # Object file lists.
-arm64-obj-y            := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
+arm64-obj-y            := debug-monitors.o entry.o irq.o fpsimd.o              \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
                           sys.o stacktrace.o time.o traps.o io.o vdso.o        \
                           hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o       \
                           return_address.o cpuinfo.o cpu_errata.o              \
-                          alternative.o cacheinfo.o
+                          cpufeature.o alternative.o cacheinfo.o
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o entry32.o               \
index ad7821d64a1d156fa05cf6b09932054ab4ab037b..21033bba939051b7db11e415983d7b10fcc485ca 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/cacheflush.h>
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
+#include <asm/insn.h>
 #include <linux/stop_machine.h>
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
@@ -33,6 +34,48 @@ struct alt_region {
        struct alt_instr *end;
 };
 
+/*
+ * Decode the imm field of a b/bl instruction, and return the byte
+ * offset as a signed value (so it can be used when computing a new
+ * branch target).
+ */
+static s32 get_branch_offset(u32 insn)
+{
+       s32 imm = aarch64_insn_decode_immediate(AARCH64_INSN_IMM_26, insn);
+
+       /* sign-extend the immediate before turning it into a byte offset */
+       return (imm << 6) >> 4;
+}
+
+static u32 get_alt_insn(u8 *insnptr, u8 *altinsnptr)
+{
+       u32 insn;
+
+       aarch64_insn_read(altinsnptr, &insn);
+
+       /* Stop the world on instructions we don't support... */
+       BUG_ON(aarch64_insn_is_cbz(insn));
+       BUG_ON(aarch64_insn_is_cbnz(insn));
+       BUG_ON(aarch64_insn_is_bcond(insn));
+       /* ... and there is probably more. */
+
+       if (aarch64_insn_is_b(insn) || aarch64_insn_is_bl(insn)) {
+               enum aarch64_insn_branch_type type;
+               unsigned long target;
+
+               if (aarch64_insn_is_b(insn))
+                       type = AARCH64_INSN_BRANCH_NOLINK;
+               else
+                       type = AARCH64_INSN_BRANCH_LINK;
+
+               target = (unsigned long)altinsnptr + get_branch_offset(insn);
+               insn = aarch64_insn_gen_branch_imm((unsigned long)insnptr,
+                                                  target, type);
+       }
+
+       return insn;
+}
+
 static int __apply_alternatives(void *alt_region)
 {
        struct alt_instr *alt;
@@ -40,16 +83,24 @@ static int __apply_alternatives(void *alt_region)
        u8 *origptr, *replptr;
 
        for (alt = region->begin; alt < region->end; alt++) {
+               u32 insn;
+               int i;
+
                if (!cpus_have_cap(alt->cpufeature))
                        continue;
 
-               BUG_ON(alt->alt_len > alt->orig_len);
+               BUG_ON(alt->alt_len != alt->orig_len);
 
                pr_info_once("patching kernel code\n");
 
                origptr = (u8 *)&alt->orig_offset + alt->orig_offset;
                replptr = (u8 *)&alt->alt_offset + alt->alt_offset;
-               memcpy(origptr, replptr, alt->alt_len);
+
+               for (i = 0; i < alt->alt_len; i += sizeof(insn)) {
+                       insn = get_alt_insn(origptr + i, replptr + i);
+                       aarch64_insn_write(origptr + i, insn);
+               }
+
                flush_icache_range((uintptr_t)origptr,
                                   (uintptr_t)(origptr + alt->alt_len));
        }
index 56cadd3606bf70c3e18d2df8da882804288a8e35..da675cc5dfaeef4e4e0dfb954c0fe26a46238615 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kvm_host.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
-#include <asm/cputable.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
@@ -70,9 +69,6 @@ int main(void)
   BLANK();
   DEFINE(PAGE_SZ,              PAGE_SIZE);
   BLANK();
-  DEFINE(CPU_INFO_SZ,          sizeof(struct cpu_info));
-  DEFINE(CPU_INFO_SETUP,       offsetof(struct cpu_info, cpu_setup));
-  BLANK();
   DEFINE(DMA_BIDIRECTIONAL,    DMA_BIDIRECTIONAL);
   DEFINE(DMA_TO_DEVICE,                DMA_TO_DEVICE);
   DEFINE(DMA_FROM_DEVICE,      DMA_FROM_DEVICE);
index fa62637e63a8c6e7498ba7957395b3030583bb02..6ffd914385609d0aab875813e4e9e8b690976421 100644 (file)
@@ -16,8 +16,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define pr_fmt(fmt) "alternatives: " fmt
-
 #include <linux/types.h>
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
 #define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
 
-/*
- * Add a struct or another datatype to the union below if you need
- * different means to detect an affected CPU.
- */
-struct arm64_cpu_capabilities {
-       const char *desc;
-       u16 capability;
-       bool (*is_affected)(struct arm64_cpu_capabilities *);
-       union {
-               struct {
-                       u32 midr_model;
-                       u32 midr_range_min, midr_range_max;
-               };
-       };
-};
-
 #define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
                        MIDR_ARCHITECTURE_MASK)
 
 static bool __maybe_unused
-is_affected_midr_range(struct arm64_cpu_capabilities *entry)
+is_affected_midr_range(const struct arm64_cpu_capabilities *entry)
 {
        u32 midr = read_cpuid_id();
 
@@ -59,12 +41,12 @@ is_affected_midr_range(struct arm64_cpu_capabilities *entry)
 }
 
 #define MIDR_RANGE(model, min, max) \
-       .is_affected = is_affected_midr_range, \
+       .matches = is_affected_midr_range, \
        .midr_model = model, \
        .midr_range_min = min, \
        .midr_range_max = max
 
-struct arm64_cpu_capabilities arm64_errata[] = {
+const struct arm64_cpu_capabilities arm64_errata[] = {
 #if    defined(CONFIG_ARM64_ERRATUM_826319) || \
        defined(CONFIG_ARM64_ERRATUM_827319) || \
        defined(CONFIG_ARM64_ERRATUM_824069)
@@ -88,7 +70,16 @@ struct arm64_cpu_capabilities arm64_errata[] = {
        /* Cortex-A57 r0p0 - r1p2 */
                .desc = "ARM erratum 832075",
                .capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
-               MIDR_RANGE(MIDR_CORTEX_A57, 0x00, 0x12),
+               MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
+                          (1 << MIDR_VARIANT_SHIFT) | 2),
+       },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_845719
+       {
+       /* Cortex-A53 r0p[01234] */
+               .desc = "ARM erratum 845719",
+               .capability = ARM64_WORKAROUND_845719,
+               MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x04),
        },
 #endif
        {
@@ -97,15 +88,5 @@ struct arm64_cpu_capabilities arm64_errata[] = {
 
 void check_local_cpu_errata(void)
 {
-       struct arm64_cpu_capabilities *cpus = arm64_errata;
-       int i;
-
-       for (i = 0; cpus[i].desc; i++) {
-               if (!cpus[i].is_affected(&cpus[i]))
-                       continue;
-
-               if (!cpus_have_cap(cpus[i].capability))
-                       pr_info("enabling workaround for %s\n", cpus[i].desc);
-               cpus_set_cap(cpus[i].capability);
-       }
+       check_cpu_capabilities(arm64_errata, "enabling workaround for");
 }
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
new file mode 100644 (file)
index 0000000..3d9967e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Contains CPU feature definitions
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "alternatives: " fmt
+
+#include <linux/types.h>
+#include <asm/cpu.h>
+#include <asm/cpufeature.h>
+
+static const struct arm64_cpu_capabilities arm64_features[] = {
+       {},
+};
+
+void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
+                           const char *info)
+{
+       int i;
+
+       for (i = 0; caps[i].desc; i++) {
+               if (!caps[i].matches(&caps[i]))
+                       continue;
+
+               if (!cpus_have_cap(caps[i].capability))
+                       pr_info("%s %s\n", info, caps[i].desc);
+               cpus_set_cap(caps[i].capability);
+       }
+}
+
+void check_local_cpu_features(void)
+{
+       check_cpu_capabilities(arm64_features, "detected feature");
+}
index 929855691dae623d781a1dc5465ff8bcd8913689..75d5a867e7fb1420172ef5e7cb281c9d9aa1f206 100644 (file)
@@ -236,6 +236,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
        cpuinfo_detect_icache_policy(info);
 
        check_local_cpu_errata();
+       check_local_cpu_features();
        update_cpu_features(info);
 }
 
diff --git a/arch/arm64/kernel/cputable.c b/arch/arm64/kernel/cputable.c
deleted file mode 100644 (file)
index fd3993c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * arch/arm64/kernel/cputable.c
- *
- * Copyright (C) 2012 ARM Ltd.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/init.h>
-
-#include <asm/cputable.h>
-
-extern unsigned long __cpu_setup(void);
-
-struct cpu_info cpu_table[] = {
-       {
-               .cpu_id_val     = 0x000f0000,
-               .cpu_id_mask    = 0x000f0000,
-               .cpu_name       = "AArch64 Processor",
-               .cpu_setup      = __cpu_setup,
-       },
-       { /* Empty */ },
-};
index cf21bb3bf7524c5907463119a20832467b181745..959fe8733560971e4a8d9d222f943dac192c6057 100644 (file)
 #include <linux/init.h>
 #include <linux/linkage.h>
 
+#include <asm/alternative-asm.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
 #include <asm/errno.h>
 #include <asm/esr.h>
 #include <asm/thread_info.h>
        ct_user_enter
        ldr     x23, [sp, #S_SP]                // load return stack pointer
        msr     sp_el0, x23
+
+#ifdef CONFIG_ARM64_ERRATUM_845719
+       alternative_insn                                                \
+       "nop",                                                          \
+       "tbz x22, #4, 1f",                                              \
+       ARM64_WORKAROUND_845719
+#ifdef CONFIG_PID_IN_CONTEXTIDR
+       alternative_insn                                                \
+       "nop; nop",                                                     \
+       "mrs x29, contextidr_el1; msr contextidr_el1, x29; 1:",         \
+       ARM64_WORKAROUND_845719
+#else
+       alternative_insn                                                \
+       "nop",                                                          \
+       "msr contextidr_el1, xzr; 1:",                                  \
+       ARM64_WORKAROUND_845719
+#endif
+#endif
        .endif
        msr     elr_el1, x21                    // set up the return data
        msr     spsr_el1, x22
index 9a8f6ae2530e701741f1c8ddb1eff677abbd7ab1..bd9bfaa9269bc59980e89209e22ac0286288f9ef 100644 (file)
  */
 
 #include <linux/linkage.h>
+#include <linux/const.h>
 
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
+#include <asm/errno.h>
+#include <asm/page.h>
 
 /*
  * System call wrappers for the AArch32 compatibility layer.
@@ -53,6 +56,21 @@ ENTRY(compat_sys_fstatfs64_wrapper)
        b       compat_sys_fstatfs64
 ENDPROC(compat_sys_fstatfs64_wrapper)
 
+/*
+ * Note: off_4k (w5) is always in units of 4K. If we can't do the
+ * requested offset because it is not page-aligned, we return -EINVAL.
+ */
+ENTRY(compat_sys_mmap2_wrapper)
+#if PAGE_SHIFT > 12
+       tst     w5, #~PAGE_MASK >> 12
+       b.ne    1f
+       lsr     w5, w5, #PAGE_SHIFT - 12
+#endif
+       b       sys_mmap_pgoff
+1:     mov     x0, #-EINVAL
+       ret
+ENDPROC(compat_sys_mmap2_wrapper)
+
 /*
  * Wrappers for AArch32 syscalls that either take 64-bit parameters
  * in registers or that take 32-bit parameters which require sign
index 07f930540f4a8b96b520cb630226ce700f79e732..19f915e8f6e0f001ce061b9eaf22cdedb9506c08 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/page.h>
 #include <asm/virt.h>
 
-#define KERNEL_RAM_VADDR       (PAGE_OFFSET + TEXT_OFFSET)
+#define __PHYS_OFFSET  (KERNEL_START - TEXT_OFFSET)
 
 #if (TEXT_OFFSET & 0xfff) != 0
 #error TEXT_OFFSET must be at least 4KB aligned
 #error TEXT_OFFSET must be less than 2MB
 #endif
 
-       .macro  pgtbl, ttb0, ttb1, virt_to_phys
-       ldr     \ttb1, =swapper_pg_dir
-       ldr     \ttb0, =idmap_pg_dir
-       add     \ttb1, \ttb1, \virt_to_phys
-       add     \ttb0, \ttb0, \virt_to_phys
-       .endm
-
 #ifdef CONFIG_ARM64_64K_PAGES
 #define BLOCK_SHIFT    PAGE_SHIFT
 #define BLOCK_SIZE     PAGE_SIZE
@@ -63,7 +56,7 @@
 #define TABLE_SHIFT    PUD_SHIFT
 #endif
 
-#define KERNEL_START   KERNEL_RAM_VADDR
+#define KERNEL_START   _text
 #define KERNEL_END     _end
 
 /*
@@ -240,39 +233,42 @@ section_table:
 #endif
 
 ENTRY(stext)
-       mov     x21, x0                         // x21=FDT
+       bl      preserve_boot_args
        bl      el2_setup                       // Drop to EL1, w20=cpu_boot_mode
-       bl      __calc_phys_offset              // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
+       adrp    x24, __PHYS_OFFSET
        bl      set_cpu_boot_mode_flag
-       mrs     x22, midr_el1                   // x22=cpuid
-       mov     x0, x22
-       bl      lookup_processor_type
-       mov     x23, x0                         // x23=current cpu_table
-       /*
-        * __error_p may end up out of range for cbz if text areas are
-        * aligned up to section sizes.
-        */
-       cbnz    x23, 1f                         // invalid processor (x23=0)?
-       b       __error_p
-1:
+
        bl      __vet_fdt
        bl      __create_page_tables            // x25=TTBR0, x26=TTBR1
        /*
-        * The following calls CPU specific code in a position independent
-        * manner. See arch/arm64/mm/proc.S for details. x23 = base of
-        * cpu_info structure selected by lookup_processor_type above.
+        * The following calls CPU setup code, see arch/arm64/mm/proc.S for
+        * details.
         * On return, the CPU will be ready for the MMU to be turned on and
         * the TCR will have been set.
         */
-       ldr     x27, __switch_data              // address to jump to after
+       ldr     x27, =__mmap_switched           // address to jump to after
                                                // MMU has been enabled
-       adrp    lr, __enable_mmu                // return (PIC) address
-       add     lr, lr, #:lo12:__enable_mmu
-       ldr     x12, [x23, #CPU_INFO_SETUP]
-       add     x12, x12, x28                   // __virt_to_phys
-       br      x12                             // initialise processor
+       adr_l   lr, __enable_mmu                // return (PIC) address
+       b       __cpu_setup                     // initialise processor
 ENDPROC(stext)
 
+/*
+ * Preserve the arguments passed by the bootloader in x0 .. x3
+ */
+preserve_boot_args:
+       mov     x21, x0                         // x21=FDT
+
+       adr_l   x0, boot_args                   // record the contents of
+       stp     x21, x1, [x0]                   // x0 .. x3 at kernel entry
+       stp     x2, x3, [x0, #16]
+
+       dmb     sy                              // needed before dc ivac with
+                                               // MMU off
+
+       add     x1, x0, #0x20                   // 4 x 8 bytes
+       b       __inval_cache_range             // tail call
+ENDPROC(preserve_boot_args)
+
 /*
  * Determine validity of the x21 FDT pointer.
  * The dtb must be 8-byte aligned and live in the first 512M of memory.
@@ -356,7 +352,8 @@ ENDPROC(__vet_fdt)
  *   - pgd entry for fixed mappings (TTBR1)
  */
 __create_page_tables:
-       pgtbl   x25, x26, x28                   // idmap_pg_dir and swapper_pg_dir addresses
+       adrp    x25, idmap_pg_dir
+       adrp    x26, swapper_pg_dir
        mov     x27, lr
 
        /*
@@ -385,12 +382,50 @@ __create_page_tables:
         * Create the identity mapping.
         */
        mov     x0, x25                         // idmap_pg_dir
-       ldr     x3, =KERNEL_START
-       add     x3, x3, x28                     // __pa(KERNEL_START)
+       adrp    x3, KERNEL_START                // __pa(KERNEL_START)
+
+#ifndef CONFIG_ARM64_VA_BITS_48
+#define EXTRA_SHIFT    (PGDIR_SHIFT + PAGE_SHIFT - 3)
+#define EXTRA_PTRS     (1 << (48 - EXTRA_SHIFT))
+
+       /*
+        * If VA_BITS < 48, it may be too small to allow for an ID mapping to be
+        * created that covers system RAM if that is located sufficiently high
+        * in the physical address space. So for the ID map, use an extended
+        * virtual range in that case, by configuring an additional translation
+        * level.
+        * First, we have to verify our assumption that the current value of
+        * VA_BITS was chosen such that all translation levels are fully
+        * utilised, and that lowering T0SZ will always result in an additional
+        * translation level to be configured.
+        */
+#if VA_BITS != EXTRA_SHIFT
+#error "Mismatch between VA_BITS and page size/number of translation levels"
+#endif
+
+       /*
+        * Calculate the maximum allowed value for TCR_EL1.T0SZ so that the
+        * entire kernel image can be ID mapped. As T0SZ == (64 - #bits used),
+        * this number conveniently equals the number of leading zeroes in
+        * the physical address of KERNEL_END.
+        */
+       adrp    x5, KERNEL_END
+       clz     x5, x5
+       cmp     x5, TCR_T0SZ(VA_BITS)   // default T0SZ small enough?
+       b.ge    1f                      // .. then skip additional level
+
+       adr_l   x6, idmap_t0sz
+       str     x5, [x6]
+       dmb     sy
+       dc      ivac, x6                // Invalidate potentially stale cache line
+
+       create_table_entry x0, x3, EXTRA_SHIFT, EXTRA_PTRS, x5, x6
+1:
+#endif
+
        create_pgd_entry x0, x3, x5, x6
-       ldr     x6, =KERNEL_END
        mov     x5, x3                          // __pa(KERNEL_START)
-       add     x6, x6, x28                     // __pa(KERNEL_END)
+       adr_l   x6, KERNEL_END                  // __pa(KERNEL_END)
        create_block_map x0, x7, x3, x5, x6
 
        /*
@@ -399,7 +434,7 @@ __create_page_tables:
        mov     x0, x26                         // swapper_pg_dir
        mov     x5, #PAGE_OFFSET
        create_pgd_entry x0, x5, x3, x6
-       ldr     x6, =KERNEL_END
+       ldr     x6, =KERNEL_END                 // __va(KERNEL_END)
        mov     x3, x24                         // phys offset
        create_block_map x0, x7, x3, x5, x6
 
@@ -426,6 +461,7 @@ __create_page_tables:
         */
        mov     x0, x25
        add     x1, x26, #SWAPPER_DIR_SIZE
+       dmb     sy
        bl      __inval_cache_range
 
        mov     lr, x27
@@ -433,37 +469,22 @@ __create_page_tables:
 ENDPROC(__create_page_tables)
        .ltorg
 
-       .align  3
-       .type   __switch_data, %object
-__switch_data:
-       .quad   __mmap_switched
-       .quad   __bss_start                     // x6
-       .quad   __bss_stop                      // x7
-       .quad   processor_id                    // x4
-       .quad   __fdt_pointer                   // x5
-       .quad   memstart_addr                   // x6
-       .quad   init_thread_union + THREAD_START_SP // sp
-
 /*
- * The following fragment of code is executed with the MMU on in MMU mode, and
- * uses absolute addresses; this is not position independent.
+ * The following fragment of code is executed with the MMU enabled.
  */
+       .set    initial_sp, init_thread_union + THREAD_START_SP
 __mmap_switched:
-       adr     x3, __switch_data + 8
+       adr_l   x6, __bss_start
+       adr_l   x7, __bss_stop
 
-       ldp     x6, x7, [x3], #16
 1:     cmp     x6, x7
        b.hs    2f
        str     xzr, [x6], #8                   // Clear BSS
        b       1b
 2:
-       ldp     x4, x5, [x3], #16
-       ldr     x6, [x3], #8
-       ldr     x16, [x3]
-       mov     sp, x16
-       str     x22, [x4]                       // Save processor ID
-       str     x21, [x5]                       // Save FDT pointer
-       str     x24, [x6]                       // Save PHYS_OFFSET
+       adr_l   sp, initial_sp, x4
+       str_l   x21, __fdt_pointer, x5          // Save FDT pointer
+       str_l   x24, memstart_addr, x6          // Save PHYS_OFFSET
        mov     x29, #0
        b       start_kernel
 ENDPROC(__mmap_switched)
@@ -566,8 +587,7 @@ ENDPROC(el2_setup)
  * in x20. See arch/arm64/include/asm/virt.h for more info.
  */
 ENTRY(set_cpu_boot_mode_flag)
-       ldr     x1, =__boot_cpu_mode            // Compute __boot_cpu_mode
-       add     x1, x1, x28
+       adr_l   x1, __boot_cpu_mode
        cmp     w20, #BOOT_CPU_MODE_EL2
        b.ne    1f
        add     x1, x1, #4
@@ -588,29 +608,21 @@ ENDPROC(set_cpu_boot_mode_flag)
        .align  L1_CACHE_SHIFT
 ENTRY(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
-       .long   0
+       .long   BOOT_CPU_MODE_EL1
        .popsection
 
 #ifdef CONFIG_SMP
-       .align  3
-1:     .quad   .
-       .quad   secondary_holding_pen_release
-
        /*
         * This provides a "holding pen" for platforms to hold all secondary
         * cores are held until we're ready for them to initialise.
         */
 ENTRY(secondary_holding_pen)
        bl      el2_setup                       // Drop to EL1, w20=cpu_boot_mode
-       bl      __calc_phys_offset              // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
        bl      set_cpu_boot_mode_flag
        mrs     x0, mpidr_el1
        ldr     x1, =MPIDR_HWID_BITMASK
        and     x0, x0, x1
-       adr     x1, 1b
-       ldp     x2, x3, [x1]
-       sub     x1, x1, x2
-       add     x3, x3, x1
+       adr_l   x3, secondary_holding_pen_release
 pen:   ldr     x4, [x3]
        cmp     x4, x0
        b.eq    secondary_startup
@@ -624,7 +636,6 @@ ENDPROC(secondary_holding_pen)
         */
 ENTRY(secondary_entry)
        bl      el2_setup                       // Drop to EL1
-       bl      __calc_phys_offset              // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
        bl      set_cpu_boot_mode_flag
        b       secondary_startup
 ENDPROC(secondary_entry)
@@ -633,16 +644,9 @@ ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
         */
-       mrs     x22, midr_el1                   // x22=cpuid
-       mov     x0, x22
-       bl      lookup_processor_type
-       mov     x23, x0                         // x23=current cpu_table
-       cbz     x23, __error_p                  // invalid processor (x23=0)?
-
-       pgtbl   x25, x26, x28                   // x25=TTBR0, x26=TTBR1
-       ldr     x12, [x23, #CPU_INFO_SETUP]
-       add     x12, x12, x28                   // __virt_to_phys
-       blr     x12                             // initialise processor
+       adrp    x25, idmap_pg_dir
+       adrp    x26, swapper_pg_dir
+       bl      __cpu_setup                     // initialise processor
 
        ldr     x21, =secondary_data
        ldr     x27, =__secondary_switched      // address to jump to after enabling the MMU
@@ -658,11 +662,12 @@ ENDPROC(__secondary_switched)
 #endif /* CONFIG_SMP */
 
 /*
- * Setup common bits before finally enabling the MMU. Essentially this is just
- * loading the page table pointer and vector base registers.
+ * Enable the MMU.
  *
- * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on
- * the MMU.
+ *  x0  = SCTLR_EL1 value for turning on the MMU.
+ *  x27 = *virtual* address to jump to upon completion
+ *
+ * other registers depend on the function called upon completion
  */
 __enable_mmu:
        ldr     x5, =vectors
@@ -670,89 +675,7 @@ __enable_mmu:
        msr     ttbr0_el1, x25                  // load TTBR0
        msr     ttbr1_el1, x26                  // load TTBR1
        isb
-       b       __turn_mmu_on
-ENDPROC(__enable_mmu)
-
-/*
- * Enable the MMU. This completely changes the structure of the visible memory
- * space. You will not be able to trace execution through this.
- *
- *  x0  = system control register
- *  x27 = *virtual* address to jump to upon completion
- *
- * other registers depend on the function called upon completion
- *
- * We align the entire function to the smallest power of two larger than it to
- * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET
- * close to the end of a 512MB or 1GB block we might require an additional
- * table to map the entire function.
- */
-       .align  4
-__turn_mmu_on:
        msr     sctlr_el1, x0
        isb
        br      x27
-ENDPROC(__turn_mmu_on)
-
-/*
- * Calculate the start of physical memory.
- */
-__calc_phys_offset:
-       adr     x0, 1f
-       ldp     x1, x2, [x0]
-       sub     x28, x0, x1                     // x28 = PHYS_OFFSET - PAGE_OFFSET
-       add     x24, x2, x28                    // x24 = PHYS_OFFSET
-       ret
-ENDPROC(__calc_phys_offset)
-
-       .align 3
-1:     .quad   .
-       .quad   PAGE_OFFSET
-
-/*
- * Exception handling. Something went wrong and we can't proceed. We ought to
- * tell the user, but since we don't have any guarantee that we're even
- * running on the right architecture, we do virtually nothing.
- */
-__error_p:
-ENDPROC(__error_p)
-
-__error:
-1:     nop
-       b       1b
-ENDPROC(__error)
-
-/*
- * This function gets the processor ID in w0 and searches the cpu_table[] for
- * a match. It returns a pointer to the struct cpu_info it found. The
- * cpu_table[] must end with an empty (all zeros) structure.
- *
- * This routine can be called via C code and it needs to work with the MMU
- * both disabled and enabled (the offset is calculated automatically).
- */
-ENTRY(lookup_processor_type)
-       adr     x1, __lookup_processor_type_data
-       ldp     x2, x3, [x1]
-       sub     x1, x1, x2                      // get offset between VA and PA
-       add     x3, x3, x1                      // convert VA to PA
-1:
-       ldp     w5, w6, [x3]                    // load cpu_id_val and cpu_id_mask
-       cbz     w5, 2f                          // end of list?
-       and     w6, w6, w0
-       cmp     w5, w6
-       b.eq    3f
-       add     x3, x3, #CPU_INFO_SZ
-       b       1b
-2:
-       mov     x3, #0                          // unknown processor
-3:
-       mov     x0, x3
-       ret
-ENDPROC(lookup_processor_type)
-
-       .align  3
-       .type   __lookup_processor_type_data, %object
-__lookup_processor_type_data:
-       .quad   .
-       .quad   cpu_table
-       .size   __lookup_processor_type_data, . - __lookup_processor_type_data
+ENDPROC(__enable_mmu)
index c8eca88f12e6b2702df24bc758ac99815226827c..924902083e47eca28812837c8d76583a30fdaafb 100644 (file)
@@ -265,23 +265,13 @@ int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
        return aarch64_insn_patch_text_sync(addrs, insns, cnt);
 }
 
-u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
-                                 u32 insn, u64 imm)
+static int __kprobes aarch64_get_imm_shift_mask(enum aarch64_insn_imm_type type,
+                                               u32 *maskp, int *shiftp)
 {
-       u32 immlo, immhi, lomask, himask, mask;
+       u32 mask;
        int shift;
 
        switch (type) {
-       case AARCH64_INSN_IMM_ADR:
-               lomask = 0x3;
-               himask = 0x7ffff;
-               immlo = imm & lomask;
-               imm >>= 2;
-               immhi = imm & himask;
-               imm = (immlo << 24) | (immhi);
-               mask = (lomask << 24) | (himask);
-               shift = 5;
-               break;
        case AARCH64_INSN_IMM_26:
                mask = BIT(26) - 1;
                shift = 0;
@@ -320,9 +310,68 @@ u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
                shift = 16;
                break;
        default:
-               pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
-                       type);
-               return 0;
+               return -EINVAL;
+       }
+
+       *maskp = mask;
+       *shiftp = shift;
+
+       return 0;
+}
+
+#define ADR_IMM_HILOSPLIT      2
+#define ADR_IMM_SIZE           SZ_2M
+#define ADR_IMM_LOMASK         ((1 << ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_HIMASK         ((ADR_IMM_SIZE >> ADR_IMM_HILOSPLIT) - 1)
+#define ADR_IMM_LOSHIFT                29
+#define ADR_IMM_HISHIFT                5
+
+u64 aarch64_insn_decode_immediate(enum aarch64_insn_imm_type type, u32 insn)
+{
+       u32 immlo, immhi, mask;
+       int shift;
+
+       switch (type) {
+       case AARCH64_INSN_IMM_ADR:
+               shift = 0;
+               immlo = (insn >> ADR_IMM_LOSHIFT) & ADR_IMM_LOMASK;
+               immhi = (insn >> ADR_IMM_HISHIFT) & ADR_IMM_HIMASK;
+               insn = (immhi << ADR_IMM_HILOSPLIT) | immlo;
+               mask = ADR_IMM_SIZE - 1;
+               break;
+       default:
+               if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
+                       pr_err("aarch64_insn_decode_immediate: unknown immediate encoding %d\n",
+                              type);
+                       return 0;
+               }
+       }
+
+       return (insn >> shift) & mask;
+}
+
+u32 __kprobes aarch64_insn_encode_immediate(enum aarch64_insn_imm_type type,
+                                 u32 insn, u64 imm)
+{
+       u32 immlo, immhi, mask;
+       int shift;
+
+       switch (type) {
+       case AARCH64_INSN_IMM_ADR:
+               shift = 0;
+               immlo = (imm & ADR_IMM_LOMASK) << ADR_IMM_LOSHIFT;
+               imm >>= ADR_IMM_HILOSPLIT;
+               immhi = (imm & ADR_IMM_HIMASK) << ADR_IMM_HISHIFT;
+               imm = immlo | immhi;
+               mask = ((ADR_IMM_LOMASK << ADR_IMM_LOSHIFT) |
+                       (ADR_IMM_HIMASK << ADR_IMM_HISHIFT));
+               break;
+       default:
+               if (aarch64_get_imm_shift_mask(type, &mask, &shift) < 0) {
+                       pr_err("aarch64_insn_encode_immediate: unknown immediate encoding %d\n",
+                              type);
+                       return 0;
+               }
        }
 
        /* Update the immediate field. */
index 25a5308744b1ce17e8299502be30cca1b3cca628..195991dadc3772c67a084396d28aa2a7c8b2019e 100644 (file)
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
+#include <linux/of.h>
 #include <linux/perf_event.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 
@@ -322,22 +324,31 @@ out:
 }
 
 static int
-validate_event(struct pmu_hw_events *hw_events,
-              struct perf_event *event)
+validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events,
+                               struct perf_event *event)
 {
-       struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+       struct arm_pmu *armpmu;
        struct hw_perf_event fake_event = event->hw;
        struct pmu *leader_pmu = event->group_leader->pmu;
 
        if (is_software_event(event))
                return 1;
 
+       /*
+        * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The
+        * core perf code won't check that the pmu->ctx == leader->ctx
+        * until after pmu->event_init(event).
+        */
+       if (event->pmu != pmu)
+               return 0;
+
        if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
                return 1;
 
        if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
                return 1;
 
+       armpmu = to_arm_pmu(event->pmu);
        return armpmu->get_event_idx(hw_events, &fake_event) >= 0;
 }
 
@@ -355,15 +366,15 @@ validate_group(struct perf_event *event)
        memset(fake_used_mask, 0, sizeof(fake_used_mask));
        fake_pmu.used_mask = fake_used_mask;
 
-       if (!validate_event(&fake_pmu, leader))
+       if (!validate_event(event->pmu, &fake_pmu, leader))
                return -EINVAL;
 
        list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
-               if (!validate_event(&fake_pmu, sibling))
+               if (!validate_event(event->pmu, &fake_pmu, sibling))
                        return -EINVAL;
        }
 
-       if (!validate_event(&fake_pmu, event))
+       if (!validate_event(event->pmu, &fake_pmu, event))
                return -EINVAL;
 
        return 0;
@@ -396,7 +407,12 @@ armpmu_release_hardware(struct arm_pmu *armpmu)
                free_percpu_irq(irq, &cpu_hw_events);
        } else {
                for (i = 0; i < irqs; ++i) {
-                       if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
+                       int cpu = i;
+
+                       if (armpmu->irq_affinity)
+                               cpu = armpmu->irq_affinity[i];
+
+                       if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs))
                                continue;
                        irq = platform_get_irq(pmu_device, i);
                        if (irq > 0)
@@ -450,19 +466,24 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
                on_each_cpu(armpmu_enable_percpu_irq, &irq, 1);
        } else {
                for (i = 0; i < irqs; ++i) {
+                       int cpu = i;
+
                        err = 0;
                        irq = platform_get_irq(pmu_device, i);
                        if (irq <= 0)
                                continue;
 
+                       if (armpmu->irq_affinity)
+                               cpu = armpmu->irq_affinity[i];
+
                        /*
                         * If we have a single PMU interrupt that we can't shift,
                         * assume that we're running on a uniprocessor machine and
                         * continue. Otherwise, continue without this interrupt.
                         */
-                       if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+                       if (irq_set_affinity(irq, cpumask_of(cpu)) && irqs > 1) {
                                pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
-                                               irq, i);
+                                               irq, cpu);
                                continue;
                        }
 
@@ -476,7 +497,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
                                return err;
                        }
 
-                       cpumask_set_cpu(i, &armpmu->active_irqs);
+                       cpumask_set_cpu(cpu, &armpmu->active_irqs);
                }
        }
 
@@ -1289,9 +1310,46 @@ static const struct of_device_id armpmu_of_device_ids[] = {
 
 static int armpmu_device_probe(struct platform_device *pdev)
 {
+       int i, *irqs;
+
        if (!cpu_pmu)
                return -ENODEV;
 
+       irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
+       if (!irqs)
+               return -ENOMEM;
+
+       for (i = 0; i < pdev->num_resources; ++i) {
+               struct device_node *dn;
+               int cpu;
+
+               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
+                                     i);
+               if (!dn) {
+                       pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
+                               of_node_full_name(dn), i);
+                       break;
+               }
+
+               for_each_possible_cpu(cpu)
+                       if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
+                               break;
+
+               of_node_put(dn);
+               if (cpu >= nr_cpu_ids) {
+                       pr_warn("Failed to find logical CPU for %s\n",
+                               dn->name);
+                       break;
+               }
+
+               irqs[i] = cpu;
+       }
+
+       if (i == pdev->num_resources)
+               cpu_pmu->irq_affinity = irqs;
+       else
+               kfree(irqs);
+
        cpu_pmu->plat_device = pdev;
        return 0;
 }
index e8420f635bd44711f968fef5ad8aaadc220cc511..51ef97274b52ac342a6c760aa60cd90665a7e705 100644 (file)
@@ -50,7 +50,6 @@
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/elf.h>
-#include <asm/cputable.h>
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/sections.h>
@@ -62,9 +61,7 @@
 #include <asm/memblock.h>
 #include <asm/psci.h>
 #include <asm/efi.h>
-
-unsigned int processor_id;
-EXPORT_SYMBOL(processor_id);
+#include <asm/virt.h>
 
 unsigned long elf_hwcap __read_mostly;
 EXPORT_SYMBOL_GPL(elf_hwcap);
@@ -83,7 +80,6 @@ unsigned int compat_elf_hwcap2 __read_mostly;
 
 DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
 
-static const char *cpu_name;
 phys_addr_t __fdt_pointer __initdata;
 
 /*
@@ -119,6 +115,11 @@ void __init early_print(const char *str, ...)
        printk("%s", buf);
 }
 
+/*
+ * The recorded values of x0 .. x3 upon kernel entry.
+ */
+u64 __cacheline_aligned boot_args[4];
+
 void __init smp_setup_processor_id(void)
 {
        u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
@@ -207,24 +208,38 @@ static void __init smp_build_mpidr_hash(void)
 }
 #endif
 
+static void __init hyp_mode_check(void)
+{
+       if (is_hyp_mode_available())
+               pr_info("CPU: All CPU(s) started at EL2\n");
+       else if (is_hyp_mode_mismatched())
+               WARN_TAINT(1, TAINT_CPU_OUT_OF_SPEC,
+                          "CPU: CPUs started in inconsistent modes");
+       else
+               pr_info("CPU: All CPU(s) started at EL1\n");
+}
+
+void __init do_post_cpus_up_work(void)
+{
+       hyp_mode_check();
+       apply_alternatives_all();
+}
+
+#ifdef CONFIG_UP_LATE_INIT
+void __init up_late_init(void)
+{
+       do_post_cpus_up_work();
+}
+#endif /* CONFIG_UP_LATE_INIT */
+
 static void __init setup_processor(void)
 {
-       struct cpu_info *cpu_info;
        u64 features, block;
        u32 cwg;
        int cls;
 
-       cpu_info = lookup_processor_type(read_cpuid_id());
-       if (!cpu_info) {
-               printk("CPU configuration botched (ID %08x), unable to continue.\n",
-                      read_cpuid_id());
-               while (1);
-       }
-
-       cpu_name = cpu_info->cpu_name;
-
-       printk("CPU: %s [%08x] revision %d\n",
-              cpu_name, read_cpuid_id(), read_cpuid_id() & 15);
+       printk("CPU: AArch64 Processor [%08x] revision %d\n",
+              read_cpuid_id(), read_cpuid_id() & 15);
 
        sprintf(init_utsname()->machine, ELF_PLATFORM);
        elf_hwcap = 0;
@@ -402,6 +417,12 @@ void __init setup_arch(char **cmdline_p)
        conswitchp = &dummy_con;
 #endif
 #endif
+       if (boot_args[1] || boot_args[2] || boot_args[3]) {
+               pr_err("WARNING: x1-x3 nonzero in violation of boot protocol:\n"
+                       "\tx1: %016llx\n\tx2: %016llx\n\tx3: %016llx\n"
+                       "This indicates a broken bootloader or old kernel\n",
+                       boot_args[1], boot_args[2], boot_args[3]);
+       }
 }
 
 static int __init arm64_device_init(void)
index 328b8ce4b007031ed10140ec7898c48cfd12ba2d..ffe8e1b814e00dd8d4caf392a751569fe0787cb0 100644 (file)
@@ -151,6 +151,7 @@ asmlinkage void secondary_start_kernel(void)
         */
        cpu_set_reserved_ttbr0();
        flush_tlb_all();
+       cpu_set_default_tcr_t0sz();
 
        preempt_disable();
        trace_hardirqs_off();
@@ -309,7 +310,7 @@ void cpu_die(void)
 void __init smp_cpus_done(unsigned int max_cpus)
 {
        pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
-       apply_alternatives_all();
+       do_post_cpus_up_work();
 }
 
 void __init smp_prepare_boot_cpu(void)
index 2d5ab3c90b820f1b40e0a7a0098cafa4992721ea..a40b1343b819f86bdf4a0e80f143a12425f8fd6b 100644 (file)
@@ -37,6 +37,7 @@ asmlinkage long compat_sys_readahead_wrapper(void);
 asmlinkage long compat_sys_fadvise64_64_wrapper(void);
 asmlinkage long compat_sys_sync_file_range2_wrapper(void);
 asmlinkage long compat_sys_fallocate_wrapper(void);
+asmlinkage long compat_sys_mmap2_wrapper(void);
 
 #undef __SYSCALL
 #define __SYSCALL(nr, sym)     [nr] = sym,
index 5d9d2dca530d97a7039789bf76efed5ea4e030a1..a2c29865c3fe54e2d3c8c7ce1b956ba5ce5c0bf7 100644 (file)
@@ -23,10 +23,14 @@ jiffies = jiffies_64;
 
 #define HYPERVISOR_TEXT                                        \
        /*                                              \
-        * Force the alignment to be compatible with    \
-        * the vectors requirements                     \
+        * Align to 4 KB so that                        \
+        * a) the HYP vector table is at its minimum    \
+        *    alignment of 2048 bytes                   \
+        * b) the HYP init code will not cross a page   \
+        *    boundary if its size does not exceed      \
+        *    4 KB (see related ASSERT() below)         \
         */                                             \
-       . = ALIGN(2048);                                \
+       . = ALIGN(SZ_4K);                               \
        VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;     \
        *(.hyp.idmap.text)                              \
        VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;       \
@@ -163,10 +167,11 @@ SECTIONS
 }
 
 /*
- * The HYP init code can't be more than a page long.
+ * The HYP init code can't be more than a page long,
+ * and should not cross a page boundary.
  */
-ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end),
-       "HYP init code too big")
+ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K,
+       "HYP init code too big or misaligned")
 
 /*
  * If padding is applied before .head.text, virt<->phys conversions will fail.
index c3191168a994fba06b6f5ddc807dbc8eceec224b..178ba2248a9804b82157f392e16026b010cb76b6 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/assembler.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_mmu.h>
+#include <asm/pgtable-hwdef.h>
 
        .text
        .pushsection    .hyp.idmap.text, "ax"
@@ -65,6 +66,25 @@ __do_hyp_init:
        and     x4, x4, x5
        ldr     x5, =TCR_EL2_FLAGS
        orr     x4, x4, x5
+
+#ifndef CONFIG_ARM64_VA_BITS_48
+       /*
+        * If we are running with VA_BITS < 48, we may be running with an extra
+        * level of translation in the ID map. This is only the case if system
+        * RAM is out of range for the currently configured page size and number
+        * of translation levels, in which case we will also need the extra
+        * level for the HYP ID map, or we won't be able to enable the EL2 MMU.
+        *
+        * However, at EL2, there is only one TTBR register, and we can't switch
+        * between translation tables *and* update TCR_EL2.T0SZ at the same
+        * time. Bottom line: we need the extra level in *both* our translation
+        * tables.
+        *
+        * So use the same T0SZ value we use for the ID map.
+        */
+       ldr_l   x5, idmap_t0sz
+       bfi     x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
+#endif
        msr     tcr_el2, x4
 
        ldr     x4, =VTCR_EL2_FLAGS
@@ -91,6 +111,10 @@ __do_hyp_init:
        msr     sctlr_el2, x4
        isb
 
+       /* Skip the trampoline dance if we merged the boot and runtime PGDs */
+       cmp     x0, x1
+       b.eq    merged
+
        /* MMU is now enabled. Get ready for the trampoline dance */
        ldr     x4, =TRAMPOLINE_VA
        adr     x5, target
@@ -105,6 +129,7 @@ target: /* We're now in the trampoline code, switch page tables */
        tlbi    alle2
        dsb     sy
 
+merged:
        /* Set the stack and new vectors */
        kern_hyp_va     x2
        mov     sp, x2
index 79e01163a981424db584789f3936a37592e2d765..5b8b664422d369a00dc6f6bc78b6f28ffd32da1b 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "mm.h"
 
+u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
+
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
  * and COW.
@@ -454,6 +456,7 @@ void __init paging_init(void)
         */
        cpu_set_reserved_ttbr0();
        flush_tlb_all();
+       cpu_set_default_tcr_t0sz();
 }
 
 /*
@@ -461,8 +464,10 @@ void __init paging_init(void)
  */
 void setup_mm_for_reboot(void)
 {
-       cpu_switch_mm(idmap_pg_dir, &init_mm);
+       cpu_set_reserved_ttbr0();
        flush_tlb_all();
+       cpu_set_idmap_tcr_t0sz();
+       cpu_switch_mm(idmap_pg_dir, &init_mm);
 }
 
 /*
@@ -627,10 +632,7 @@ void __set_fixmap(enum fixed_addresses idx,
        unsigned long addr = __fix_to_virt(idx);
        pte_t *pte;
 
-       if (idx >= __end_of_fixed_addresses) {
-               BUG();
-               return;
-       }
+       BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
 
        pte = fixmap_pte(addr);
 
index 1d3ec3ddd84b72e654819b7818d03cbaf082815e..e47ed1c5dce1bbe50c22094b17cc12e82dde6cdf 100644 (file)
@@ -73,7 +73,6 @@ int set_memory_ro(unsigned long addr, int numpages)
                                        __pgprot(PTE_RDONLY),
                                        __pgprot(PTE_WRITE));
 }
-EXPORT_SYMBOL_GPL(set_memory_ro);
 
 int set_memory_rw(unsigned long addr, int numpages)
 {
@@ -81,7 +80,6 @@ int set_memory_rw(unsigned long addr, int numpages)
                                        __pgprot(PTE_WRITE),
                                        __pgprot(PTE_RDONLY));
 }
-EXPORT_SYMBOL_GPL(set_memory_rw);
 
 int set_memory_nx(unsigned long addr, int numpages)
 {
index 005d29e2977da0848248975354c537a4f648d405..4c4d93c4bf65b154fd0df25c4b8165593ff044be 100644 (file)
        mov     \reg, #4                        // bytes per word
        lsl     \reg, \reg, \tmp                // actual cache line size
        .endm
+
+/*
+ * tcr_set_idmap_t0sz - update TCR.T0SZ so that we can load the ID map
+ */
+       .macro  tcr_set_idmap_t0sz, valreg, tmpreg
+#ifndef CONFIG_ARM64_VA_BITS_48
+       ldr_l   \tmpreg, idmap_t0sz
+       bfi     \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
+#endif
+       .endm
index 28eebfb6af763db14be54594fb0ec39f7a747142..cdd754e19b9b26ddafbec1c83784ea151331eb43 100644 (file)
@@ -156,6 +156,7 @@ ENTRY(cpu_do_resume)
        msr     cpacr_el1, x6
        msr     ttbr0_el1, x1
        msr     ttbr1_el1, x7
+       tcr_set_idmap_t0sz x8, x7
        msr     tcr_el1, x8
        msr     vbar_el1, x9
        msr     mdscr_el1, x10
@@ -233,6 +234,8 @@ ENTRY(__cpu_setup)
         */
        ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
                        TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0
+       tcr_set_idmap_t0sz      x10, x9
+
        /*
         * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in
         * TCR_EL1.