Commit 5167d09f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 updates from Will Deacon:
 "Once again, Catalin's off on holiday and I'm looking after the arm64
  tree.  Please can you pull the following arm64 updates for 3.17?

  Note that this branch also includes the new GICv3 driver (merged via a
  stable tag from Jason's irqchip tree), since there is a fix for older
  binutils on top.

  Changes include:
   - context tracking support (NO_HZ_FULL) which narrowly missed 3.16
   - vDSO layout rework following Andy's work on x86
   - TEXT_OFFSET fuzzing for bootloader testing
   - /proc/cpuinfo tidy-up
   - preliminary work to support 48-bit virtual addresses, but this is
     currently disabled until KVM has been ported to use it (the patches
     do, however, bring some nice clean-up)
   - boot-time CPU sanity checks (especially useful on heterogenous
     systems)
   - support for syscall auditing
   - support for CC_STACKPROTECTOR
   - defconfig updates"

* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (55 commits)
  arm64: add newline to I-cache policy string
  Revert "arm64: dmi: Add SMBIOS/DMI support"
  arm64: fpsimd: fix a typo in fpsimd_save_partial_state ENDPROC
  arm64: don't call break hooks for BRK exceptions from EL0
  arm64: defconfig: enable devtmpfs mount option
  arm64: vdso: fix build error when switching from LE to BE
  arm64: defconfig: add virtio support for running as a kvm guest
  arm64: gicv3: Allow GICv3 compilation with older binutils
  arm64: fix soft lockup due to large tlb flush range
  arm64/crypto: fix makefile rule for aes-glue-%.o
  arm64: Do not invoke audit_syscall_* functions if !CONFIG_AUDIT_SYSCALL
  arm64: Fix barriers used for page table modifications
  arm64: Add support for 48-bit VA space with 64KB page configuration
  arm64: asm/pgtable.h pmd/pud definitions clean-up
  arm64: Determine the vmalloc/vmemmap space at build time based on VA_BITS
  arm64: Clean up the initial page table creation in head.S
  arm64: Remove asm/pgtable-*level-types.h files
  arm64: Remove asm/pgtable-*level-hwdef.h files
  arm64: Convert bool ARM64_x_LEVELS to int ARM64_PGTABLE_LEVELS
  arm64: mm: Implement 4 levels of translation tables
  ...
parents 8533ce72 ea171967
...@@ -72,27 +72,54 @@ The decompressed kernel image contains a 64-byte header as follows: ...@@ -72,27 +72,54 @@ The decompressed kernel image contains a 64-byte header as follows:
u32 code0; /* Executable code */ u32 code0; /* Executable code */
u32 code1; /* Executable code */ u32 code1; /* Executable code */
u64 text_offset; /* Image load offset */ u64 text_offset; /* Image load offset, little endian */
u64 res0 = 0; /* reserved */ u64 image_size; /* Effective Image size, little endian */
u64 res1 = 0; /* reserved */ u64 flags; /* kernel flags, little endian */
u64 res2 = 0; /* reserved */ u64 res2 = 0; /* reserved */
u64 res3 = 0; /* reserved */ u64 res3 = 0; /* reserved */
u64 res4 = 0; /* reserved */ u64 res4 = 0; /* reserved */
u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */ u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
u32 res5 = 0; /* reserved */ u32 res5; /* reserved (used for PE COFF offset) */
Header notes: Header notes:
- As of v3.17, all fields are little endian unless stated otherwise.
- code0/code1 are responsible for branching to stext. - code0/code1 are responsible for branching to stext.
- when booting through EFI, code0/code1 are initially skipped. - when booting through EFI, code0/code1 are initially skipped.
res5 is an offset to the PE header and the PE header has the EFI res5 is an offset to the PE header and the PE header has the EFI
entry point (efi_stub_entry). When the stub has done its work, it entry point (efi_stub_entry). When the stub has done its work, it
jumps to code0 to resume the normal boot process. jumps to code0 to resume the normal boot process.
The image must be placed at the specified offset (currently 0x80000) - Prior to v3.17, the endianness of text_offset was not specified. In
from the start of the system RAM and called there. The start of the these cases image_size is zero and text_offset is 0x80000 in the
system RAM must be aligned to 2MB. endianness of the kernel. Where image_size is non-zero image_size is
little-endian and must be respected. Where image_size is zero,
text_offset can be assumed to be 0x80000.
- The flags field (introduced in v3.17) is a little-endian 64-bit field
composed as follows:
Bit 0: Kernel endianness. 1 if BE, 0 if LE.
Bits 1-63: Reserved.
- When image_size is zero, a bootloader should attempt to keep as much
memory as possible free for use by the kernel immediately after the
end of the kernel image. The amount of space required will vary
depending on selected features, and is effectively unbound.
The Image must be placed text_offset bytes from a 2MB aligned base
address near the start of usable system RAM and called there. Memory
below that base address is currently unusable by Linux, and therefore it
is strongly recommended that this location is the start of system RAM.
At least image_size bytes from the start of the image must be free for
use by the kernel.
Any memory described to the kernel (even that below the 2MB aligned base
address) which is not marked as reserved from the kernel e.g. with a
memreserve region in the device tree) will be considered as available to
the kernel.
Before jumping into the kernel, the following conditions must be met: Before jumping into the kernel, the following conditions must be met:
......
...@@ -2,18 +2,18 @@ ...@@ -2,18 +2,18 @@
============================== ==============================
Author: Catalin Marinas <catalin.marinas@arm.com> Author: Catalin Marinas <catalin.marinas@arm.com>
Date : 20 February 2012
This document describes the virtual memory layout used by the AArch64 This document describes the virtual memory layout used by the AArch64
Linux kernel. The architecture allows up to 4 levels of translation Linux kernel. The architecture allows up to 4 levels of translation
tables with a 4KB page size and up to 3 levels with a 64KB page size. tables with a 4KB page size and up to 3 levels with a 64KB page size.
AArch64 Linux uses 3 levels of translation tables with the 4KB page AArch64 Linux uses either 3 levels or 4 levels of translation tables
configuration, allowing 39-bit (512GB) virtual addresses for both user with the 4KB page configuration, allowing 39-bit (512GB) or 48-bit
and kernel. With 64KB pages, only 2 levels of translation tables are (256TB) virtual addresses, respectively, for both user and kernel. With
used but the memory layout is the same. 64KB pages, only 2 levels of translation tables, allowing 42-bit (4TB)
virtual address, are used but the memory layout is the same.
User addresses have bits 63:39 set to 0 while the kernel addresses have User addresses have bits 63:48 set to 0 while the kernel addresses have
the same bits set to 1. TTBRx selection is given by bit 63 of the the same bits set to 1. TTBRx selection is given by bit 63 of the
virtual address. The swapper_pg_dir contains only kernel (global) virtual address. The swapper_pg_dir contains only kernel (global)
mappings while the user pgd contains only user (non-global) mappings. mappings while the user pgd contains only user (non-global) mappings.
...@@ -21,58 +21,40 @@ The swapper_pgd_dir address is written to TTBR1 and never written to ...@@ -21,58 +21,40 @@ The swapper_pgd_dir address is written to TTBR1 and never written to
TTBR0. TTBR0.
AArch64 Linux memory layout with 4KB pages: AArch64 Linux memory layout with 4KB pages + 3 levels:
Start End Size Use Start End Size Use
----------------------------------------------------------------------- -----------------------------------------------------------------------
0000000000000000 0000007fffffffff 512GB user 0000000000000000 0000007fffffffff 512GB user
ffffff8000000000 ffffffffffffffff 512GB kernel
ffffff8000000000 ffffffbbfffeffff ~240GB vmalloc
ffffffbbffff0000 ffffffbbffffffff 64KB [guard page] AArch64 Linux memory layout with 4KB pages + 4 levels:
ffffffbc00000000 ffffffbdffffffff 8GB vmemmap Start End Size Use
-----------------------------------------------------------------------
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap] 0000000000000000 0000ffffffffffff 256TB user
ffff000000000000 ffffffffffffffff 256TB kernel
ffffffbffa000000 ffffffbffaffffff 16MB PCI I/O space
ffffffbffb000000 ffffffbffbbfffff 12MB [guard]
ffffffbffbc00000 ffffffbffbdfffff 2MB fixed mappings
ffffffbffbe00000 ffffffbffbffffff 2MB [guard]
ffffffbffc000000 ffffffbfffffffff 64MB modules
ffffffc000000000 ffffffffffffffff 256GB kernel logical memory map
AArch64 Linux memory layout with 64KB pages: AArch64 Linux memory layout with 64KB pages + 2 levels:
Start End Size Use Start End Size Use
----------------------------------------------------------------------- -----------------------------------------------------------------------
0000000000000000 000003ffffffffff 4TB user 0000000000000000 000003ffffffffff 4TB user
fffffc0000000000 ffffffffffffffff 4TB kernel
fffffc0000000000 fffffdfbfffeffff ~2TB vmalloc
fffffdfbffff0000 fffffdfbffffffff 64KB [guard page] AArch64 Linux memory layout with 64KB pages + 3 levels:
fffffdfc00000000 fffffdfdffffffff 8GB vmemmap Start End Size Use
-----------------------------------------------------------------------
fffffdfe00000000 fffffdfffbbfffff ~8GB [guard, future vmmemap] 0000000000000000 0000ffffffffffff 256TB user
ffff000000000000 ffffffffffffffff 256TB kernel
fffffdfffa000000 fffffdfffaffffff 16MB PCI I/O space
fffffdfffb000000 fffffdfffbbfffff 12MB [guard]
fffffdfffbc00000 fffffdfffbdfffff 2MB fixed mappings
fffffdfffbe00000 fffffdfffbffffff 2MB [guard]
fffffdfffc000000 fffffdffffffffff 64MB modules
fffffe0000000000 ffffffffffffffff 2TB kernel logical memory map For details of the virtual kernel memory layout please see the kernel
booting log.
Translation table lookup with 4KB pages: Translation table lookup with 4KB pages:
...@@ -86,7 +68,7 @@ Translation table lookup with 4KB pages: ...@@ -86,7 +68,7 @@ Translation table lookup with 4KB pages:
| | | | +-> [20:12] L3 index | | | | +-> [20:12] L3 index
| | | +-----------> [29:21] L2 index | | | +-----------> [29:21] L2 index
| | +---------------------> [38:30] L1 index | | +---------------------> [38:30] L1 index
| +-------------------------------> [47:39] L0 index (not used) | +-------------------------------> [47:39] L0 index
+-------------------------------------------------> [63] TTBR0/1 +-------------------------------------------------> [63] TTBR0/1
...@@ -99,10 +81,11 @@ Translation table lookup with 64KB pages: ...@@ -99,10 +81,11 @@ Translation table lookup with 64KB pages:
| | | | v | | | | v
| | | | [15:0] in-page offset | | | | [15:0] in-page offset
| | | +----------> [28:16] L3 index | | | +----------> [28:16] L3 index
| | +--------------------------> [41:29] L2 index (only 38:29 used) | | +--------------------------> [41:29] L2 index
| +-------------------------------> [47:42] L1 index (not used) | +-------------------------------> [47:42] L1 index
+-------------------------------------------------> [63] TTBR0/1 +-------------------------------------------------> [63] TTBR0/1
When using KVM, the hypervisor maps kernel pages in EL2, at a fixed When using KVM, the hypervisor maps kernel pages in EL2, at a fixed
offset from the kernel VA (top 24bits of the kernel VA set to zero): offset from the kernel VA (top 24bits of the kernel VA set to zero):
......
config ARM64 config ARM64
def_bool y def_bool y
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
select ARCH_HAS_OPP
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_ATOMIC_RMW
...@@ -11,6 +10,8 @@ config ARM64 ...@@ -11,6 +10,8 @@ config ARM64
select ARM_AMBA select ARM_AMBA
select ARM_ARCH_TIMER select ARM_ARCH_TIMER
select ARM_GIC select ARM_GIC
select AUDIT_ARCH_COMPAT_GENERIC
select ARM_GIC_V3
select BUILDTIME_EXTABLE_SORT select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS select CLONE_BACKWARDS
select COMMON_CLK select COMMON_CLK
...@@ -29,10 +30,12 @@ config ARM64 ...@@ -29,10 +30,12 @@ config ARM64
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select GENERIC_TIME_VSYSCALL select GENERIC_TIME_VSYSCALL
select HARDIRQS_SW_RESEND select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KGDB select HAVE_ARCH_KGDB
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_C_RECORDMCOUNT select HAVE_C_RECORDMCOUNT
select HAVE_CC_STACKPROTECTOR
select HAVE_DEBUG_BUGVERBOSE select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG select HAVE_DMA_API_DEBUG
...@@ -63,6 +66,7 @@ config ARM64 ...@@ -63,6 +66,7 @@ config ARM64
select RTC_LIB select RTC_LIB
select SPARSE_IRQ select SPARSE_IRQ
select SYSCTL_EXCEPTION_TRACE select SYSCTL_EXCEPTION_TRACE
select HAVE_CONTEXT_TRACKING
help help
ARM 64-bit (AArch64) Linux support. ARM 64-bit (AArch64) Linux support.
...@@ -155,14 +159,63 @@ endmenu ...@@ -155,14 +159,63 @@ endmenu
menu "Kernel Features" menu "Kernel Features"
choice
prompt "Page size"
default ARM64_4K_PAGES
help
Page size (translation granule) configuration.
config ARM64_4K_PAGES
bool "4KB"
help
This feature enables 4KB pages support.
config ARM64_64K_PAGES config ARM64_64K_PAGES
bool "Enable 64KB pages support" bool "64KB"
help help
This feature enables 64KB pages support (4KB by default) This feature enables 64KB pages support (4KB by default)
allowing only two levels of page tables and faster TLB allowing only two levels of page tables and faster TLB
look-up. AArch32 emulation is not available when this feature look-up. AArch32 emulation is not available when this feature
is enabled. is enabled.
endchoice
choice
prompt "Virtual address space size"
default ARM64_VA_BITS_39 if ARM64_4K_PAGES
default ARM64_VA_BITS_42 if ARM64_64K_PAGES
help
Allows choosing one of multiple possible virtual address
space sizes. The level of translation table is determined by
a combination of page size and virtual address space size.
config ARM64_VA_BITS_39
bool "39-bit"
depends on ARM64_4K_PAGES
config ARM64_VA_BITS_42
bool "42-bit"
depends on ARM64_64K_PAGES
config ARM64_VA_BITS_48
bool "48-bit"
depends on BROKEN
endchoice
config ARM64_VA_BITS
int
default 39 if ARM64_VA_BITS_39
default 42 if ARM64_VA_BITS_42
default 48 if ARM64_VA_BITS_48
config ARM64_PGTABLE_LEVELS
int
default 2 if ARM64_64K_PAGES && ARM64_VA_BITS_42
default 3 if ARM64_64K_PAGES && ARM64_VA_BITS_48
default 3 if ARM64_4K_PAGES && ARM64_VA_BITS_39
default 4 if ARM64_4K_PAGES && ARM64_VA_BITS_48
config CPU_BIG_ENDIAN config CPU_BIG_ENDIAN
bool "Build big-endian kernel" bool "Build big-endian kernel"
help help
......
...@@ -28,4 +28,19 @@ config PID_IN_CONTEXTIDR ...@@ -28,4 +28,19 @@ config PID_IN_CONTEXTIDR
instructions during context switch. Say Y here only if you are instructions during context switch. Say Y here only if you are
planning to use hardware trace tools with this kernel. planning to use hardware trace tools with this kernel.
config ARM64_RANDOMIZE_TEXT_OFFSET
bool "Randomize TEXT_OFFSET at build time"
help
Say Y here if you want the image load offset (AKA TEXT_OFFSET)
of the kernel to be randomized at build-time. When selected,
this option will cause TEXT_OFFSET to be randomized upon any
build of the kernel, and the offset will be reflected in the
text_offset field of the resulting Image. This can be used to
fuzz-test bootloaders which respect text_offset.
This option is intended for bootloader and/or kernel testing
only. Bootloaders must make no assumptions regarding the value
of TEXT_OFFSET and platforms must not require a specific
value.
endmenu endmenu
...@@ -38,7 +38,11 @@ CHECKFLAGS += -D__aarch64__ ...@@ -38,7 +38,11 @@ CHECKFLAGS += -D__aarch64__
head-y := arch/arm64/kernel/head.o head-y := arch/arm64/kernel/head.o
# The byte offset of the kernel image in RAM from the start of RAM. # The byte offset of the kernel image in RAM from the start of RAM.
ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
else
TEXT_OFFSET := 0x00080000 TEXT_OFFSET := 0x00080000
endif
export TEXT_OFFSET GZFLAGS export TEXT_OFFSET GZFLAGS
......
...@@ -52,8 +52,11 @@ CONFIG_IP_PNP_BOOTP=y ...@@ -52,8 +52,11 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_LRO is not set # CONFIG_INET_LRO is not set
# CONFIG_IPV6 is not set # CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set # CONFIG_WIRELESS is not set
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y CONFIG_DMA_CMA=y
CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP=y
CONFIG_VIRTIO_BLK=y CONFIG_VIRTIO_BLK=y
...@@ -65,6 +68,7 @@ CONFIG_PATA_PLATFORM=y ...@@ -65,6 +68,7 @@ CONFIG_PATA_PLATFORM=y
CONFIG_PATA_OF_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
CONFIG_TUN=y CONFIG_TUN=y
CONFIG_VIRTIO_NET=y
CONFIG_SMC91X=y CONFIG_SMC91X=y
CONFIG_SMSC911X=y CONFIG_SMSC911X=y
# CONFIG_WLAN is not set # CONFIG_WLAN is not set
...@@ -76,6 +80,7 @@ CONFIG_SERIAL_8250_CONSOLE=y ...@@ -76,6 +80,7 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set # CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set # CONFIG_HWMON is not set
CONFIG_REGULATOR=y CONFIG_REGULATOR=y
...@@ -90,6 +95,7 @@ CONFIG_USB_ISP1760_HCD=y ...@@ -90,6 +95,7 @@ CONFIG_USB_ISP1760_HCD=y
CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_MMC_ARMMMCI=y CONFIG_MMC_ARMMMCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO=y
# CONFIG_IOMMU_SUPPORT is not set # CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
...@@ -107,6 +113,7 @@ CONFIG_HUGETLBFS=y ...@@ -107,6 +113,7 @@ CONFIG_HUGETLBFS=y
# CONFIG_MISC_FILESYSTEMS is not set # CONFIG_MISC_FILESYSTEMS is not set
CONFIG_NFS_FS=y CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y CONFIG_ROOT_NFS=y
CONFIG_9P_FS=y
CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y CONFIG_NLS_ISO8859_1=y
CONFIG_VIRTUALIZATION=y CONFIG_VIRTUALIZATION=y
......
...@@ -35,4 +35,4 @@ AFLAGS_aes-neon.o := -DINTERLEAVE=4 ...@@ -35,4 +35,4 @@ AFLAGS_aes-neon.o := -DINTERLEAVE=4
CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS
$(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE $(obj)/aes-glue-%.o: $(src)/aes-glue.c FORCE
$(call if_changed_dep,cc_o_c) $(call if_changed_rule,cc_o_c)
...@@ -138,19 +138,10 @@ static inline void __flush_icache_all(void) ...@@ -138,19 +138,10 @@ static inline void __flush_icache_all(void)
#define flush_icache_page(vma,page) do { } while (0) #define flush_icache_page(vma,page) do { } while (0)
/* /*
* flush_cache_vmap() is used when creating mappings (eg, via vmap, * Not required on AArch64 (PIPT or VIPT non-aliasing D-cache).
* vmalloc, ioremap etc) in kernel space for pages. On non-VIPT
* caches, since the direct-mappings of these pages may contain cached
* data, we need to do a full cache flush to ensure that writebacks
* don't corrupt data placed into these pages via the new mappings.
*/ */
static inline void flush_cache_vmap(unsigned long start, unsigned long end) static inline void flush_cache_vmap(unsigned long start, unsigned long end)
{ {
/*
* set_pte_at() called from vmap_pte_range() does not
* have a DSB after cleaning the cache line.
*/
dsb(ish);
} }
static inline void flush_cache_vunmap(unsigned long start, unsigned long end) static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
......
...@@ -30,10 +30,14 @@ ...@@ -30,10 +30,14 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
static inline u32 icache_policy(void) #include <linux/bitops.h>
{
return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK; #define CTR_L1IP(ctr) (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK)
}
#define ICACHEF_ALIASING BIT(0)
#define ICACHEF_AIVIVT BIT(1)
extern unsigned long __icache_flags;
/* /*
* Whilst the D-side always behaves as PIPT on AArch64, aliasing is * Whilst the D-side always behaves as PIPT on AArch64, aliasing is
...@@ -41,12 +45,12 @@ static inline u32 icache_policy(void) ...@@ -41,12 +45,12 @@ static inline u32 icache_policy(void)
*/ */
static inline int icache_is_aliasing(void) static inline int icache_is_aliasing(void)
{ {
return icache_policy() != ICACHE_POLICY_PIPT; return test_bit(ICACHEF_ALIASING, &__icache_flags);
} }
static inline int icache_is_aivivt(void) static inline int icache_is_aivivt(void)
{ {
return icache_policy() == ICACHE_POLICY_AIVIVT; return test_bit(ICACHEF_AIVIVT, &__icache_flags);
} }
static inline u32 cache_type_cwg(void) static inline u32 cache_type_cwg(void)
......
/* /*
* Copyright (C) 2012 ARM Ltd. * Copyright (C) 2014 ARM Ltd.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -13,31 +13,47 @@ ...@@ -13,31 +13,47 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __ASM_PGTABLE_2LEVEL_HWDEF_H #ifndef __ASM_CPU_H
#define __ASM_PGTABLE_2LEVEL_HWDEF_H #define __ASM_CPU_H
/* #include <linux/cpu.h>
* With LPAE and 64KB pages, there are 2 levels of page tables. Each level has #include <linux/init.h>
* 8192 entries of 8 bytes each, occupying a 64KB page. Levels 0 and 1 are not #include <linux/percpu.h>
* used. The 2nd level table (PGD for Linux) can cover a range of 4TB, each
* entry representing 512MB. The user and kernel address spaces are limited to
* 4TB in the 64KB page configuration.
*/
#define PTRS_PER_PTE 8192
#define PTRS_PER_PGD 8192
/* /*
* PGDIR_SHIFT determines the size a top-level page table entry can map. * Records attributes of an individual CPU.
*/ */
#define PGDIR_SHIFT 29 struct cpuinfo_arm64 {
#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) struct cpu cpu;
#define PGDIR_MASK (~(PGDIR_SIZE-1)) u32 reg_ctr;
u32 reg_cntfrq;
u32 reg_dczid;
u32 reg_midr;
/* u64 reg_id_aa64isar0;
* section address mask and size definitions. u64 reg_id_aa64isar1;
*/ u64 reg_id_aa64mmfr0;
#define SECTION_SHIFT 29 u64 reg_id_aa64mmfr1;
#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) u64 reg_id_aa64pfr0;
#define SECTION_MASK (~(SECTION_SIZE-1)) u64 reg_id_aa64pfr1;
u32 reg_id_isar0;
u32 reg_id_isar1;
u32 reg_id_isar2;
u32 reg_id_isar3;
u32 reg_id_isar4;
u32 reg_id_isar5;
u32 reg_id_mmfr0;
u32 reg_id_mmfr1;
u32 reg_id_mmfr2;
u32 reg_id_mmfr3;
u32 reg_id_pfr0;
u32 reg_id_pfr1;
};
DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data);
void cpuinfo_store_cpu(void);
void __init cpuinfo_store_boot_cpu(void);
#endif #endif /* __ASM_CPU_H */
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#define INVALID_HWID ULONG_MAX #define INVALID_HWID ULONG_MAX
#define MPIDR_UP_BITMASK (0x1 << 30)
#define MPIDR_MT_BITMASK (0x1 << 24)
#define MPIDR_HWID_BITMASK 0xff00ffffff #define MPIDR_HWID_BITMASK 0xff00ffffff
#define MPIDR_LEVEL_BITS_SHIFT 3 #define MPIDR_LEVEL_BITS_SHIFT 3
...@@ -36,15 +38,34 @@ ...@@ -36,15 +38,34 @@
__val; \ __val; \
}) })
#define MIDR_REVISION_MASK 0xf
#define MIDR_REVISION(midr) ((midr) & MIDR_REVISION_MASK)
#define MIDR_PARTNUM_SHIFT 4
#define MIDR_PARTNUM_MASK (0xfff << MIDR_PARTNUM_SHIFT)
#define MIDR_PARTNUM(midr) \
(((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT)
#define MIDR_ARCHITECTURE_SHIFT 16
#define MIDR_ARCHITECTURE_MASK (0xf << MIDR_ARCHITECTURE_SHIFT)
#define MIDR_ARCHITECTURE(midr) \
(((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT)
#define MIDR_VARIANT_SHIFT 20
#define MIDR_VARIANT_MASK (0xf << MIDR_VARIANT_SHIFT)
#define MIDR_VARIANT(midr) \
(((midr) & MIDR_VARIANT_MASK) >> MIDR_VARIANT_SHIFT)
#define MIDR_IMPLEMENTOR_SHIFT 24
#define MIDR_IMPLEMENTOR_MASK (0xff << MIDR_IMPLEMENTOR_SHIFT)
#define MIDR_IMPLEMENTOR(midr) \
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
#define ARM_CPU_IMP_ARM 0x41 #define ARM_CPU_IMP_ARM 0x41
#define ARM_CPU_IMP_APM 0x50 #define ARM_CPU_IMP_APM 0x50
#define ARM_CPU_PART_AEM_V8 0xD0F0 #define ARM_CPU_PART_AEM_V8 0xD0F
#define ARM_CPU_PART_FOUNDATION 0xD000 #define ARM_CPU_PART_FOUNDATION 0xD00
#define ARM_CPU_PART_CORTEX_A53 0xD030 #define ARM_CPU_PART_CORTEX_A57 0xD07
#define ARM_CPU_PART_CORTEX_A57 0xD070 #define ARM_CPU_PART_CORTEX_A53 0xD03
#define APM_CPU_PART_POTENZA 0x0000 #define APM_CPU_PART_POTENZA 0x000
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
...@@ -65,12 +86,12 @@ static inline u64 __attribute_const__ read_cpuid_mpidr(void) ...@@ -65,12 +86,12 @@ static inline u64 __attribute_const__ read_cpuid_mpidr(void)
static inline unsigned int __attribute_const__ read_cpuid_implementor(void) static inline unsigned int __attribute_const__ read_cpuid_implementor(void)
{ {
return (read_cpuid_id() & 0xFF000000) >> 24; return MIDR_IMPLEMENTOR(read_cpuid_id());
} }
static inline unsigned int __attribute_const__ read_cpuid_part_number(void) static inline unsigned int __attribute_const__ read_cpuid_part_number(void)
{ {
return (read_cpuid_id() & 0xFFF0); return MIDR_PARTNUM(read_cpuid_id());
} }
static inline u32 __attribute_const__ read_cpuid_cachetype(void) static inline u32 __attribute_const__ read_cpuid_cachetype(void)
......
...@@ -40,6 +40,19 @@ ...@@ -40,6 +40,19 @@
str w\tmpnr, [\state, #16 * 2 + 4] str w\tmpnr, [\state, #16 * 2 + 4]
.endm .endm
.macro fpsimd_restore_fpcr state, tmp
/*
* Writes to fpcr may be self-synchronising, so avoid restoring
* the register if it hasn't changed.
*/
mrs \tmp, fpcr
cmp \tmp, \state
b.eq 9999f
msr fpcr, \state
9999:
.endm
/* Clobbers \state */
.macro fpsimd_restore state, tmpnr .macro fpsimd_restore state, tmpnr
ldp q0, q1, [\state, #16 * 0] ldp q0, q1, [\state, #16 * 0]
ldp q2, q3, [\state, #16 * 2] ldp q2, q3, [\state, #16 * 2]
...@@ -60,7 +73,7 @@ ...@@ -60,7 +73,7 @@
ldr w\tmpnr, [\state, #16 * 2] ldr w\tmpnr, [\state, #16 * 2]
msr fpsr, x\tmpnr msr fpsr, x\tmpnr
ldr w\tmpnr, [\state, #16 * 2 + 4] ldr w\tmpnr, [\state, #16 * 2 + 4]
msr fpcr, x\tmpnr fpsimd_restore_fpcr x\tmpnr, \state
.endm .endm
.altmacro .altmacro
...@@ -84,7 +97,7 @@ ...@@ -84,7 +97,7 @@
.macro fpsimd_restore_partial state, tmpnr1, tmpnr2 .macro fpsimd_restore_partial state, tmpnr1, tmpnr2
ldp w\tmpnr1, w\tmpnr2, [\state] ldp w\tmpnr1, w\tmpnr2, [\state]
msr fpsr, x\tmpnr1 msr fpsr, x\tmpnr1
msr fpcr, x\tmpnr2 fpsimd_restore_fpcr x\tmpnr2, x\tmpnr1
adr x\tmpnr1, 0f adr x\tmpnr1, 0f
ldr w\tmpnr2, [\state, #8] ldr w\tmpnr2, [\state, #8]
add \state, \state, x\tmpnr2, lsl #4 add \state, \state, x\tmpnr2, lsl #4
......
...@@ -41,11 +41,7 @@ ...@@ -41,11 +41,7 @@
* The module space lives between the addresses given by TASK_SIZE * The module space lives between the addresses given by TASK_SIZE
* and PAGE_OFFSET - it must be within 128MB of the kernel text. * and PAGE_OFFSET - it must be within 128MB of the kernel text.
*/ */
#ifdef CONFIG_ARM64_64K_PAGES #define VA_BITS (CONFIG_ARM64_VA_BITS)
#define VA_BITS (42)
#else
#define VA_BITS (39)
#endif
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) #define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
#define MODULES_END (PAGE_OFFSET) #define MODULES_END (PAGE_OFFSET)
#define MODULES_VADDR (MODULES_END - SZ_64M) #define MODULES_VADDR (MODULES_END - SZ_64M)
......
...@@ -31,14 +31,26 @@ ...@@ -31,14 +31,26 @@
/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */ /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
#define __HAVE_ARCH_GATE_AREA 1 #define __HAVE_ARCH_GATE_AREA 1
#ifndef __ASSEMBLY__ /*
* The idmap and swapper page tables need some space reserved in the kernel
* 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).
*/
#ifdef CONFIG_ARM64_64K_PAGES #ifdef CONFIG_ARM64_64K_PAGES
#include <asm/pgtable-2level-types.h> #define SWAPPER_PGTABLE_LEVELS (CONFIG_ARM64_PGTABLE_LEVELS)
#else #else
#include <asm/pgtable-3level-types.h> #define SWAPPER_PGTABLE_LEVELS (CONFIG_ARM64_PGTABLE_LEVELS - 1)
#endif #endif
#define SWAPPER_DIR_SIZE (SWAPPER_PGTABLE_LEVELS * PAGE_SIZE)
#define IDMAP_DIR_SIZE (SWAPPER_DIR_SIZE)
#ifndef __ASSEMBLY__
#include <asm/pgtable-types.h>
extern void __cpu_clear_user_page(void *p, unsigned long user); extern void __cpu_clear_user_page(void *p, unsigned long user);
extern void __cpu_copy_user_page(void *to, const void *from, extern void __cpu_copy_user_page(void *to, const void *from,
unsigned long user); unsigned long user);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#define check_pgt_cache() do { } while (0) #define check_pgt_cache() do { } while (0)
#ifndef CONFIG_ARM64_64K_PAGES #if CONFIG_ARM64_PGTABLE_LEVELS > 2
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{ {
...@@ -44,7 +44,27 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) ...@@ -44,7 +44,27 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE));
} }
#endif /* CONFIG_ARM64_64K_PAGES */ #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
return (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
}
static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
free_page((unsigned long)pud);
}
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
set_pgd(pgd, __pgd(__pa(pud) | PUD_TYPE_TABLE));
}
#endif /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */
extern pgd_t *pgd_alloc(struct mm_struct *mm); extern pgd_t *pgd_alloc(struct mm_struct *mm);
extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
......
...@@ -16,18 +16,50 @@ ...@@ -16,18 +16,50 @@
#ifndef __ASM_PGTABLE_HWDEF_H #ifndef __ASM_PGTABLE_HWDEF_H
#define __ASM_PGTABLE_HWDEF_H #define __ASM_PGTABLE_HWDEF_H
#ifdef CONFIG_ARM64_64K_PAGES #define PTRS_PER_PTE (1 << (PAGE_SHIFT - 3))
#include <asm/pgtable-2level-hwdef.h>
#else /*
#include <asm/pgtable-3level-hwdef.h> * PMD_SHIFT determines the size a level 2 page table entry can map.
*/
#if CONFIG_ARM64_PGTABLE_LEVELS > 2
#define PMD_SHIFT ((PAGE_SHIFT - 3) * 2 + 3)
#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PTRS_PER_PMD PTRS_PER_PTE
#endif
/*
* PUD_SHIFT determines the size a level 1 page table entry can map.
*/
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
#define PUD_SHIFT ((PAGE_SHIFT - 3) * 3 + 3)
#define PUD_SIZE (_AC(1, UL) << PUD_SHIFT)
#define PUD_MASK (~(PUD_SIZE-1))
#define PTRS_PER_PUD PTRS_PER_PTE
#endif #endif
/*
* PGDIR_SHIFT determines the size a top-level page table entry can map
* (depending on the configuration, this level can be 0, 1 or 2).
*/
#define PGDIR_SHIFT ((PAGE_SHIFT - 3) * CONFIG_ARM64_PGTABLE_LEVELS + 3)
#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PTRS_PER_PGD (1 << (VA_BITS - PGDIR_SHIFT))
/*
* Section address mask and size definitions.
*/
#define SECTION_SHIFT PMD_SHIFT
#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT)
#define SECTION_MASK (~(SECTION_SIZE-1))
/* /*
* Hardware page table definitions. * Hardware page table definitions.
* *
* Level 1 descriptor (PUD). * Level 1 descriptor (PUD).
*/ */
#define PUD_TYPE_TABLE (_AT(pudval_t, 3) << 0)
#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1) #define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1)
#define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0) #define PUD_TYPE_MASK (_AT(pgdval_t, 3) << 0)
#define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0) #define PUD_TYPE_SECT (_AT(pgdval_t, 1) << 0)
......
/* /*
* Copyright (C) 2012 ARM Ltd. * Page table types definitions.
* *
* This program is free software; you can redistribute it and/or modify * Copyright (C) 2014 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*
* 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
...@@ -13,13 +16,15 @@ ...@@ -13,13 +16,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __ASM_PGTABLE_3LEVEL_TYPES_H
#define __ASM_PGTABLE_3LEVEL_TYPES_H #ifndef __ASM_PGTABLE_TYPES_H
#define __ASM_PGTABLE_TYPES_H
#include <asm/types.h> #include <asm/types.h>
typedef u64 pteval_t; typedef u64 pteval_t;
typedef u64 pmdval_t; typedef u64 pmdval_t;
typedef u64 pudval_t;
typedef u64 pgdval_t; typedef u64 pgdval_t;
#undef STRICT_MM_TYPECHECKS #undef STRICT_MM_TYPECHECKS
...@@ -30,39 +35,61 @@ typedef u64 pgdval_t; ...@@ -30,39 +35,61 @@ typedef u64 pgdval_t;
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
typedef struct { pteval_t pte; } pte_t; typedef struct { pteval_t pte; } pte_t;
#define pte_val(x) ((x).pte)
#define __pte(x) ((pte_t) { (x) } )
#if CONFIG_ARM64_PGTABLE_LEVELS > 2
typedef struct { pmdval_t pmd; } pmd_t; typedef struct { pmdval_t pmd; } pmd_t;
typedef struct { pgdval_t pgd; } pgd_t; #define pmd_val(x) ((x).pmd)
typedef struct { pteval_t pgprot; } pgprot_t; #define __pmd(x) ((pmd_t) { (x) } )
#endif
#define pte_val(x) ((x).pte) #if CONFIG_ARM64_PGTABLE_LEVELS > 3
#define pmd_val(x) ((x).pmd) typedef struct { pudval_t pud; } pud_t;
#define pgd_val(x) ((x).pgd) #define pud_val(x) ((x).pud)
#define pgprot_val(x) ((x).pgprot) #define __pud(x) ((pud_t) { (x) } )
#endif
#define __pte(x) ((pte_t) { (x) } ) typedef struct { pgdval_t pgd; } pgd_t;
#define __pmd(x) ((pmd_t) { (x) } ) #define pgd_val(x) ((x).pgd)
#define __pgd(x) ((pgd_t) { (x) } ) #define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
typedef struct { pteval_t pgprot; } pgprot_t;
#define pgprot_val(x) ((x).pgprot)
#define __pgprot(x) ((pgprot_t) { (x) } )
#else /* !STRICT_MM_TYPECHECKS */ #else /* !STRICT_MM_TYPECHECKS */
typedef pteval_t pte_t; typedef pteval_t pte_t;
typedef pmdval_t pmd_t;
typedef pgdval_t pgd_t;
typedef pteval_t pgprot_t;
#define pte_val(x) (x) #define pte_val(x) (x)
#define pmd_val(x) (x)
#define pgd_val(x) (x)
#define pgprot_val(x) (x)
#define __pte(x) (x) #define __pte(x) (x)
#if CONFIG_ARM64_PGTABLE_LEVELS > 2
typedef pmdval_t pmd_t;
#define pmd_val(x) (x)
#define __pmd(x) (x) #define __pmd(x) (x)
#endif
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
typedef pudval_t pud_t;
#define pud_val(x) (x)
#define __pud(x) (x)
#endif
typedef pgdval_t pgd_t;
#define pgd_val(x) (x)
#define __pgd(x) (x) #define __pgd(x) (x)
typedef pteval_t pgprot_t;
#define pgprot_val(x) (x)
#define __pgprot(x) (x) #define __pgprot(x) (x)
#endif /* STRICT_MM_TYPECHECKS */ #endif /* STRICT_MM_TYPECHECKS */
#if CONFIG_ARM64_PGTABLE_LEVELS == 2
#include <asm-generic/pgtable-nopmd.h>
#elif CONFIG_ARM64_PGTABLE_LEVELS == 3
#include <asm-generic/pgtable-nopud.h> #include <asm-generic/pgtable-nopud.h>
#endif
#endif /* __ASM_PGTABLE_3LEVEL_TYPES_H */ #endif /* __ASM_PGTABLE_TYPES_H */
...@@ -33,9 +33,16 @@ ...@@ -33,9 +33,16 @@
/* /*
* VMALLOC and SPARSEMEM_VMEMMAP ranges. * VMALLOC and SPARSEMEM_VMEMMAP ranges.
*
* VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array
* (rounded up to PUD_SIZE).
* VMALLOC_START: beginning of the kernel VA space
* VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space,
* fixed mappings and modules
*/ */
#define VMEMMAP_SIZE ALIGN((1UL << (VA_BITS - PAGE_SHIFT)) * sizeof(struct page), PUD_SIZE)
#define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS) #define VMALLOC_START (UL(0xffffffffffffffff) << VA_BITS)
#define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K) #define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) #define vmemmap ((struct page *)(VMALLOC_END + SZ_64K))
...@@ -44,14 +51,9 @@ ...@@ -44,14 +51,9 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern void __pte_error(const char *file, int line, unsigned long val); extern void __pte_error(const char *file, int line, unsigned long val);
extern void __pmd_error(const char *file, int line, unsigned long val); extern void __pmd_error(const char *file, int line, unsigned long val);
extern void __pud_error(const char *file, int line, unsigned long val);
extern void __pgd_error(const char *file, int line, unsigned long val); extern void __pgd_error(const char *file, int line, unsigned long val);
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
#ifndef CONFIG_ARM64_64K_PAGES
#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
#endif
#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
...@@ -112,6 +114,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val); ...@@ -112,6 +114,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
extern struct page *empty_zero_page; extern struct page *empty_zero_page;
#define ZERO_PAGE(vaddr) (empty_zero_page) #define ZERO_PAGE(vaddr) (empty_zero_page)
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
#define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT) #define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
#define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
...@@ -119,6 +123,10 @@ extern struct page *empty_zero_page; ...@@ -119,6 +123,10 @@ extern struct page *empty_zero_page;
#define pte_none(pte) (!pte_val(pte)) #define pte_none(pte) (!pte_val(pte))
#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) #define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0))
#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) #define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
/* Find an entry in the third-level page table. */
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr)) #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
...@@ -138,6 +146,8 @@ extern struct page *empty_zero_page; ...@@ -138,6 +146,8 @@ extern struct page *empty_zero_page;
#define pte_valid_user(pte) \ #define pte_valid_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
#define pte_valid_not_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
static inline pte_t pte_wrprotect(pte_t pte) static inline pte_t pte_wrprotect(pte_t pte)
{ {
...@@ -184,6 +194,15 @@ static inline pte_t pte_mkspecial(pte_t pte) ...@@ -184,6 +194,15 @@ static inline pte_t pte_mkspecial(pte_t pte)
static inline void set_pte(pte_t *ptep, pte_t pte) static inline void set_pte(pte_t *ptep, pte_t pte)
{ {
*ptep = pte; *ptep = pte;
/*
* Only if the new pte is valid and kernel, otherwise TLB maintenance
* or update_mmu_cache() have the necessary barriers.
*/
if (pte_valid_not_user(pte)) {
dsb(ishst);
isb();
}
} }
extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
...@@ -303,6 +322,7 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) ...@@ -303,6 +322,7 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{ {
*pmdp = pmd; *pmdp = pmd;
dsb(ishst); dsb(ishst);
isb();
} }
static inline void pmd_clear(pmd_t *pmdp) static inline void pmd_clear(pmd_t *pmdp)
...@@ -323,7 +343,9 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd) ...@@ -323,7 +343,9 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
*/ */
#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) #define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot)
#ifndef CONFIG_ARM64_64K_PAGES #if CONFIG_ARM64_PGTABLE_LEVELS > 2
#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
#define pud_none(pud) (!pud_val(pud)) #define pud_none(pud) (!pud_val(pud))
#define pud_bad(pud) (!(pud_val(pud) & 2)) #define pud_bad(pud) (!(pud_val(pud) & 2))
...@@ -333,6 +355,7 @@ static inline void set_pud(pud_t *pudp, pud_t pud) ...@@ -333,6 +355,7 @@ static inline void set_pud(pud_t *pudp, pud_t pud)
{ {
*pudp = pud; *pudp = pud;
dsb(ishst); dsb(ishst);
isb();
} }
static inline void pud_clear(pud_t *pudp) static inline void pud_clear(pud_t *pudp)
...@@ -345,7 +368,51 @@ static inline pmd_t *pud_page_vaddr(pud_t pud) ...@@ -345,7 +368,51 @@ static inline pmd_t *pud_page_vaddr(pud_t pud)
return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK);
} }
#endif /* CONFIG_ARM64_64K_PAGES */ /* Find an entry in the second-level page table. */
#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
{
return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
}
#endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
#define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud))
#define pgd_none(pgd) (!pgd_val(pgd))
#define pgd_bad(pgd) (!(pgd_val(pgd) & 2))
#define pgd_present(pgd) (pgd_val(pgd))
static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
{
*pgdp = pgd;
dsb(ishst);
}
static inline void pgd_clear(pgd_t *pgdp)
{
set_pgd(pgdp, __pgd(0));
}
static inline pud_t *pgd_page_vaddr(pgd_t pgd)
{
return __va(pgd_val(pgd) & PHYS_MASK & (s32)PAGE_MASK);
}
/* Find an entry in the frst-level page table. */
#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
{
return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr);
}
#endif /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */
#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
/* to find an entry in a page-table-directory */ /* to find an entry in a page-table-directory */
#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
...@@ -355,18 +422,6 @@ static inline pmd_t *pud_page_vaddr(pud_t pud) ...@@ -355,18 +422,6 @@ static inline pmd_t *pud_page_vaddr(pud_t pud)
/* to find an entry in a kernel page-table-directory */ /* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) #define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
/* Find an entry in the second-level page table.. */
#ifndef CONFIG_ARM64_64K_PAGES
#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
{
return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
}
#endif
/* Find an entry in the third-level page table.. */
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{ {
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
...@@ -383,9 +438,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) ...@@ -383,9 +438,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE)
#define IDMAP_DIR_SIZE (2 * PAGE_SIZE)
/* /*
* Encode and decode a swap entry: * Encode and decode a swap entry:
* bits 0-1: present (must be zero) * bits 0-1: present (must be zero)
......
...@@ -137,8 +137,8 @@ extern struct task_struct *cpu_switch_to(struct task_struct *prev, ...@@ -137,8 +137,8 @@ extern struct task_struct *cpu_switch_to(struct task_struct *prev,
#define task_pt_regs(p) \ #define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
#define KSTK_EIP(tsk) task_pt_regs(tsk)->pc #define KSTK_EIP(tsk) ((unsigned long)task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) task_pt_regs(tsk)->sp #define KSTK_ESP(tsk) ((unsigned long)task_pt_regs(tsk)->sp)
/* /*
* Prefetching support * Prefetching support
......
/*
* GCC stack protector support.
*
* Stack protector works by putting predefined pattern at the start of
* the stack frame and verifying that it hasn't been overwritten when
* returning from the function. The pattern is called stack canary
* and gcc expects it to be defined by a global variable called
* "__stack_chk_guard" on ARM. This unfortunately means that on SMP
* we cannot have a different canary value per task.
*/
#ifndef __ASM_STACKPROTECTOR_H
#define __ASM_STACKPROTECTOR_H
#include <linux/random.h>
#include <linux/version.h>
extern unsigned long __stack_chk_guard;
/*
* Initialize the stackprotector canary value.
*
* NOTE: this must only be called from functions that never return,
* and it must always be inlined.
*/
static __always_inline void boot_init_stack_canary(void)
{
unsigned long canary;
/* Try to get a semi random initial value. */
get_random_bytes(&canary, sizeof(canary));
canary ^= LINUX_VERSION_CODE;
current->stack_canary = canary;
__stack_chk_guard = current->stack_canary;
}
#endif /* _ASM_STACKPROTECTOR_H */
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#ifndef __ASM_SYSCALL_H #ifndef __ASM_SYSCALL_H
#define __ASM_SYSCALL_H #define __ASM_SYSCALL_H
#include <uapi/linux/audit.h>
#include <linux/compat.h>
#include <linux/err.h> #include <linux/err.h>
extern const void *sys_call_table[]; extern const void *sys_call_table[];
...@@ -105,4 +107,16 @@ static inline void syscall_set_arguments(struct task_struct *task, ...@@ -105,4 +107,16 @@ static inline void syscall_set_arguments(struct task_struct *task,
memcpy(&regs->regs[i], args, n * sizeof(args[0])); memcpy(&regs->regs[i], args, n * sizeof(args[0]));
} }
/*
* We don't care about endianness (__AUDIT_ARCH_LE bit) here because
* AArch64 has the same system calls both on little- and big- endian.
*/
static inline int syscall_get_arch(void)
{
if (is_compat_task())
return AUDIT_ARCH_ARM;
return AUDIT_ARCH_AARCH64;
}
#endif /* __ASM_SYSCALL_H */ #endif /* __ASM_SYSCALL_H */
/* /*
* Copyright (C) 2012 ARM Ltd. * Macros for accessing system registers with older binutils.
* *
* This program is free software; you can redistribute it and/or modify * Copyright (C) 2014 ARM Ltd.
* Author: Catalin Marinas <catalin.marinas@arm.com>
*
* 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 * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
...@@ -13,50 +16,45 @@ ...@@ -13,50 +16,45 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __ASM_PGTABLE_2LEVEL_TYPES_H
#define __ASM_PGTABLE_2LEVEL_TYPES_H
#include <asm/types.h>
typedef u64 pteval_t;
typedef u64 pgdval_t;
typedef pgdval_t pmdval_t;
#undef STRICT_MM_TYPECHECKS
#ifdef STRICT_MM_TYPECHECKS #ifndef __ASM_SYSREG_H
#define __ASM_SYSREG_H
/*
* These are used to make use of C type-checking..
*/
typedef struct { pteval_t pte; } pte_t;
typedef struct { pgdval_t pgd; } pgd_t;
typedef struct { pteval_t pgprot; } pgprot_t;
#define pte_val(x) ((x).pte) #define sys_reg(op0, op1, crn, crm, op2) \
#define pgd_val(x) ((x).pgd) ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } ) #ifdef __ASSEMBLY__
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
#else /* !STRICT_MM_TYPECHECKS */ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
.equ __reg_num_x\num, \num
.endr
.equ __reg_num_xzr, 31
typedef pteval_t pte_t; .macro mrs_s, rt, sreg
typedef pgdval_t pgd_t; .inst 0xd5300000|(\sreg)|(__reg_num_\rt)
typedef pteval_t pgprot_t; .endm
#define pte_val(x) (x) .macro msr_s, sreg, rt
#define pgd_val(x) (x) .inst 0xd5100000|(\sreg)|(__reg_num_\rt)
#define pgprot_val(x) (x) .endm
#define __pte(x) (x) #else
#define __pgd(x) (x)
#define __pgprot(x) (x)
#endif /* STRICT_MM_TYPECHECKS */ asm(
" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
" .equ __reg_num_x\\num, \\num\n"
" .endr\n"
" .equ __reg_num_xzr, 31\n"
"\n"
" .macro mrs_s, rt, sreg\n"
" .inst 0xd5300000|(\\sreg)|(__reg_num_\\rt)\n"
" .endm\n"
"\n"
" .macro msr_s, sreg, rt\n"
" .inst 0xd5100000|(\\sreg)|(__reg_num_\\rt)\n"
" .endm\n"
);
#include <asm-generic/pgtable-nopmd.h> #endif
#endif /* __ASM_PGTABLE_2LEVEL_TYPES_H */ #endif /* __ASM_SYSREG_H */
...@@ -103,6 +103,7 @@ static inline struct thread_info *current_thread_info(void) ...@@ -103,6 +103,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NEED_RESCHED 1 #define TIF_NEED_RESCHED 1
#define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
#define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */ #define TIF_FOREIGN_FPSTATE 3 /* CPU's FP state is not current's */
#define TIF_NOHZ 7
#define TIF_SYSCALL_TRACE 8 #define TIF_SYSCALL_TRACE 8
#define TIF_SYSCALL_AUDIT 9 #define TIF_SYSCALL_AUDIT 9
#define TIF_SYSCALL_TRACEPOINT 10 #define TIF_SYSCALL_TRACEPOINT 10
...@@ -118,6 +119,7 @@ static inline struct thread_info *current_thread_info(void) ...@@ -118,6 +119,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE) #define _TIF_FOREIGN_FPSTATE (1 << TIF_FOREIGN_FPSTATE)
#define _TIF_NOHZ (1 << TIF_NOHZ)
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
...@@ -128,7 +130,8 @@ static inline struct thread_info *current_thread_info(void) ...@@ -128,7 +130,8 @@ static inline struct thread_info *current_thread_info(void)
_TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE) _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE)
#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
_TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP) _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
_TIF_NOHZ)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASM_THREAD_INFO_H */ #endif /* __ASM_THREAD_INFO_H */
...@@ -91,7 +91,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, ...@@ -91,7 +91,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
tlb_remove_page(tlb, pte); tlb_remove_page(tlb, pte);
} }
#ifndef CONFIG_ARM64_64K_PAGES #if CONFIG_ARM64_PGTABLE_LEVELS > 2
static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
unsigned long addr) unsigned long addr)
{ {
...@@ -100,6 +100,15 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, ...@@ -100,6 +100,15 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
} }
#endif #endif
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
unsigned long addr)
{
tlb_add_flush(tlb, addr);
tlb_remove_page(tlb, virt_to_page(pudp));
}
#endif
static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp,
unsigned long address) unsigned long address)
{ {
......
...@@ -98,8 +98,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, ...@@ -98,8 +98,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
dsb(ish); dsb(ish);
} }
static inline void flush_tlb_range(struct vm_area_struct *vma, static inline void __flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end) unsigned long start, unsigned long end)
{ {
unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48; unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48;
unsigned long addr; unsigned long addr;
...@@ -112,7 +112,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, ...@@ -112,7 +112,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
dsb(ish); dsb(ish);
} }
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end)
{ {
unsigned long addr; unsigned long addr;
start >>= 12; start >>= 12;
...@@ -122,6 +122,30 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end ...@@ -122,6 +122,30 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12))
asm("tlbi vaae1is, %0" : : "r"(addr)); asm("tlbi vaae1is, %0" : : "r"(addr));
dsb(ish); dsb(ish);
isb();
}
/*
* This is meant to avoid soft lock-ups on large TLB flushing ranges and not
* necessarily a performance improvement.
*/
#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT)
static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
if ((end - start) <= MAX_TLB_RANGE)
__flush_tlb_range(vma, start, end);
else
flush_tlb_mm(vma->vm_mm);
}
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
if ((end - start) <= MAX_TLB_RANGE)
__flush_tlb_kernel_range(start, end);
else
flush_tlb_all();
} }
/* /*
...@@ -131,8 +155,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, ...@@ -131,8 +155,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep) unsigned long addr, pte_t *ptep)
{ {
/* /*
* set_pte() does not have a DSB, so make sure that the page table * set_pte() does not have a DSB for user mappings, so make sure that
* write is visible. * the page table write is visible.
*/ */
dsb(ishst); dsb(ishst);
} }
......
...@@ -26,7 +26,24 @@ ...@@ -26,7 +26,24 @@
#define __ARCH_WANT_COMPAT_SYS_SENDFILE #define __ARCH_WANT_COMPAT_SYS_SENDFILE
#define __ARCH_WANT_SYS_FORK #define __ARCH_WANT_SYS_FORK
#define __ARCH_WANT_SYS_VFORK #define __ARCH_WANT_SYS_VFORK
/*
* Compat syscall numbers used by the AArch64 kernel.
*/
#define __NR_compat_restart_syscall 0
#define __NR_compat_sigreturn 119
#define __NR_compat_rt_sigreturn 173
/*
* The following SVCs are ARM private.
*/
#define __ARM_NR_COMPAT_BASE 0x0f0000
#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2)
#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5)
#define __NR_compat_syscalls 383
#endif #endif
#define __ARCH_WANT_SYS_CLONE #define __ARCH_WANT_SYS_CLONE
#include <uapi/asm/unistd.h> #include <uapi/asm/unistd.h>
......
This diff is collapsed.
...@@ -15,7 +15,8 @@ CFLAGS_REMOVE_return_address.o = -pg ...@@ -15,7 +15,8 @@ CFLAGS_REMOVE_return_address.o = -pg
arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \ entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \ sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
cpuinfo.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o sys_compat.o
......
...@@ -30,8 +30,8 @@ const struct cpu_operations *cpu_ops[NR_CPUS]; ...@@ -30,8 +30,8 @@ const struct cpu_operations *cpu_ops[NR_CPUS];
static const struct cpu_operations *supported_cpu_ops[] __initconst = { static const struct cpu_operations *supported_cpu_ops[] __initconst = {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
&smp_spin_table_ops, &smp_spin_table_ops,
&cpu_psci_ops,
#endif #endif
&cpu_psci_ops,
NULL, NULL,
}; };
......
/*
* Record and handle CPU attributes.
*
* Copyright (C) 2014 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 <asm/arch_timer.h>
#include <asm/cachetype.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/smp.h>
/*
* In case the boot CPU is hotpluggable, we record its initial state and
* current state separately. Certain system registers may contain different
* values depending on configuration at or after reset.
*/
DEFINE_PER_CPU(struct cpuinfo_arm64, cpu_data);
static struct cpuinfo_arm64 boot_cpu_data;
static char *icache_policy_str[] = {
[ICACHE_POLICY_RESERVED] = "RESERVED/UNKNOWN",
[ICACHE_POLICY_AIVIVT] = "AIVIVT",
[ICACHE_POLICY_VIPT] = "VIPT",
[ICACHE_POLICY_PIPT] = "PIPT",
};
unsigned long __icache_flags;
static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info)
{
unsigned int cpu = smp_processor_id();
u32 l1ip = CTR_L1IP(info->reg_ctr);
if (l1ip != ICACHE_POLICY_PIPT)
set_bit(ICACHEF_ALIASING, &__icache_flags);
if (l1ip == ICACHE_POLICY_AIVIVT);
set_bit(ICACHEF_AIVIVT, &__icache_flags);
pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu);
}
static int check_reg_mask(char *name, u64 mask, u64 boot, u64 cur, int cpu)
{
if ((boot & mask) == (cur & mask))
return 0;
pr_warn("SANITY CHECK: Unexpected variation in %s. Boot CPU: %#016lx, CPU%d: %#016lx\n",
name, (unsigned long)boot, cpu, (unsigned long)cur);
return 1;
}
#define CHECK_MASK(field, mask, boot, cur, cpu) \
check_reg_mask(#field, mask, (boot)->reg_ ## field, (cur)->reg_ ## field, cpu)
#define CHECK(field, boot, cur, cpu) \
CHECK_MASK(field, ~0ULL, boot, cur, cpu)
/*
* Verify that CPUs don't have unexpected differences that will cause problems.
*/
static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
{
unsigned int cpu = smp_processor_id();
struct cpuinfo_arm64 *boot = &boot_cpu_data;
unsigned int diff = 0;
/*
* The kernel can handle differing I-cache policies, but otherwise
* caches should look identical. Userspace JITs will make use of
* *minLine.
*/
diff |= CHECK_MASK(ctr, 0xffff3fff, boot, cur, cpu);
/*
* Userspace may perform DC ZVA instructions. Mismatched block sizes
* could result in too much or too little memory being zeroed if a
* process is preempted and migrated between CPUs.
*/
diff |= CHECK(dczid, boot, cur, cpu);
/* If different, timekeeping will be broken (especially with KVM) */
diff |= CHECK(cntfrq, boot, cur, cpu);
/*
* Even in big.LITTLE, processors should be identical instruction-set
* wise.
*/
diff |= CHECK(id_aa64isar0, boot, cur, cpu);
diff |= CHECK(id_aa64isar1, boot, cur, cpu);
/*
* Differing PARange support is fine as long as all peripherals and
* memory are mapped within the minimum PARange of all CPUs.
* Linux should not care about secure memory.
* ID_AA64MMFR1 is currently RES0.
*/
diff |= CHECK_MASK(id_aa64mmfr0, 0xffffffffffff0ff0, boot, cur, cpu);
diff |= CHECK(id_aa64mmfr1, boot, cur, cpu);
/*
* EL3 is not our concern.
* ID_AA64PFR1 is currently RES0.
*/
diff |= CHECK_MASK(id_aa64pfr0, 0xffffffffffff0fff, boot, cur, cpu);
diff |= CHECK(id_aa64pfr1, boot, cur, cpu);
/*
* If we have AArch32, we care about 32-bit features for compat. These
* registers should be RES0 otherwise.
*/
diff |= CHECK(id_isar0, boot, cur, cpu);
diff |= CHECK(id_isar1, boot, cur, cpu);
diff |= CHECK(id_isar2, boot, cur, cpu);
diff |= CHECK(id_isar3, boot, cur, cpu);
diff |= CHECK(id_isar4, boot, cur, cpu);
diff |= CHECK(id_isar5, boot, cur, cpu);
diff |= CHECK(id_mmfr0, boot, cur, cpu);
diff |= CHECK(id_mmfr1, boot, cur, cpu);
diff |= CHECK(id_mmfr2, boot, cur, cpu);
diff |= CHECK(id_mmfr3, boot, cur, cpu);
diff |= CHECK(id_pfr0, boot, cur, cpu);
diff |= CHECK(id_pfr1, boot, cur, cpu);
/*
* Mismatched CPU features are a recipe for disaster. Don't even
* pretend to support them.
*/
WARN_TAINT_ONCE(diff, TAINT_CPU_OUT_OF_SPEC,
"Unsupported CPU feature variation.");
}
static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
{
info->reg_cntfrq = arch_timer_get_cntfrq();
info->reg_ctr = read_cpuid_cachetype();
info->reg_dczid = read_cpuid(DCZID_EL0);
info->reg_midr = read_cpuid_id();
info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
info->reg_id_aa64mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
info->reg_id_isar3 = read_cpuid(ID_ISAR3_EL1);
info->reg_id_isar4 = read_cpuid(ID_ISAR4_EL1);
info->reg_id_isar5 = read_cpuid(ID_ISAR5_EL1);
info->reg_id_mmfr0 = read_cpuid(ID_MMFR0_EL1);
info->reg_id_mmfr1 = read_cpuid(ID_MMFR1_EL1);
info->reg_id_mmfr2 = read_cpuid(ID_MMFR2_EL1);
info->reg_id_mmfr3 = read_cpuid(ID_MMFR3_EL1);
info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
cpuinfo_detect_icache_policy(info);
}
void cpuinfo_store_cpu(void)
{
struct cpuinfo_arm64 *info = this_cpu_ptr(&cpu_data);
__cpuinfo_store_cpu(info);
cpuinfo_sanity_check(info);
}
void __init cpuinfo_store_boot_cpu(void)
{
struct cpuinfo_arm64 *info = &per_cpu(cpu_data, 0);
__cpuinfo_store_cpu(info);
boot_cpu_data = *info;
}
...@@ -315,20 +315,20 @@ static int brk_handler(unsigned long addr, unsigned int esr, ...@@ -315,20 +315,20 @@ static int brk_handler(unsigned long addr, unsigned int esr,
{ {
siginfo_t info; siginfo_t info;
if (call_break_hook(regs, esr) == DBG_HOOK_HANDLED) if (user_mode(regs)) {
return 0; info = (siginfo_t) {
.si_signo = SIGTRAP,
.si_errno = 0,
.si_code = TRAP_BRKPT,
.si_addr = (void __user *)instruction_pointer(regs),
};
if (!user_mode(regs)) force_sig_info(SIGTRAP, &info, current);
} else if (call_break_hook(regs, esr) != DBG_HOOK_HANDLED) {
pr_warning("Unexpected kernel BRK exception at EL1\n");
return -EFAULT; return -EFAULT;
}
info = (siginfo_t) {
.si_signo = SIGTRAP,
.si_errno = 0,
.si_code = TRAP_BRKPT,
.si_addr = (void __user *)instruction_pointer(regs),
};
force_sig_info(SIGTRAP, &info, current);
return 0; return 0;
} }
......
...@@ -52,7 +52,7 @@ ENDPROC(fpsimd_load_state) ...@@ -52,7 +52,7 @@ ENDPROC(fpsimd_load_state)
ENTRY(fpsimd_save_partial_state) ENTRY(fpsimd_save_partial_state)
fpsimd_save_partial x0, 1, 8, 9 fpsimd_save_partial x0, 1, 8, 9
ret ret
ENDPROC(fpsimd_load_partial_state) ENDPROC(fpsimd_save_partial_state)
/* /*
* Load the bottom n FP registers. * Load the bottom n FP registers.
......
...@@ -27,7 +27,32 @@ ...@@ -27,7 +27,32 @@
#include <asm/esr.h> #include <asm/esr.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/unistd32.h>
/*
* Context tracking subsystem. Used to instrument transitions
* between user and kernel mode.
*/
.macro ct_user_exit, syscall = 0
#ifdef CONFIG_CONTEXT_TRACKING
bl context_tracking_user_exit
.if \syscall == 1
/*
* Save/restore needed during syscalls. Restore syscall arguments from
* the values already saved on stack during kernel_entry.
*/
ldp x0, x1, [sp]
ldp x2, x3, [sp, #S_X2]
ldp x4, x5, [sp, #S_X4]
ldp x6, x7, [sp, #S_X6]
.endif
#endif
.endm
.macro ct_user_enter
#ifdef CONFIG_CONTEXT_TRACKING
bl context_tracking_user_enter
#endif
.endm
/* /*
* Bad Abort numbers * Bad Abort numbers
...@@ -91,6 +116,7 @@ ...@@ -91,6 +116,7 @@
.macro kernel_exit, el, ret = 0 .macro kernel_exit, el, ret = 0
ldp x21, x22, [sp, #S_PC] // load ELR, SPSR ldp x21, x22, [sp, #S_PC] // load ELR, SPSR
.if \el == 0 .if \el == 0
ct_user_enter
ldr x23, [sp, #S_SP] // load return stack pointer ldr x23, [sp, #S_SP] // load return stack pointer
.endif .endif
.if \ret .if \ret
...@@ -353,7 +379,6 @@ el0_sync: ...@@ -353,7 +379,6 @@ el0_sync:
lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class
cmp x24, #ESR_EL1_EC_SVC64 // SVC in 64-bit state cmp x24, #ESR_EL1_EC_SVC64 // SVC in 64-bit state
b.eq el0_svc b.eq el0_svc
adr lr, ret_to_user
cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0
b.eq el0_da b.eq el0_da
cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0
...@@ -382,7 +407,6 @@ el0_sync_compat: ...@@ -382,7 +407,6 @@ el0_sync_compat:
lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class lsr x24, x25, #ESR_EL1_EC_SHIFT // exception class
cmp x24, #ESR_EL1_EC_SVC32 // SVC in 32-bit state cmp x24, #ESR_EL1_EC_SVC32 // SVC in 32-bit state
b.eq el0_svc_compat b.eq el0_svc_compat
adr lr, ret_to_user
cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0 cmp x24, #ESR_EL1_EC_DABT_EL0 // data abort in EL0
b.eq el0_da b.eq el0_da
cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0 cmp x24, #ESR_EL1_EC_IABT_EL0 // instruction abort in EL0
...@@ -425,48 +449,59 @@ el0_da: ...@@ -425,48 +449,59 @@ el0_da:
/* /*
* Data abort handling * Data abort handling
*/ */
mrs x0, far_el1 mrs x26, far_el1
bic x0, x0, #(0xff << 56)
// enable interrupts before calling the main handler // enable interrupts before calling the main handler
enable_dbg_and_irq enable_dbg_and_irq
ct_user_exit
bic x0, x26, #(0xff << 56)
mov x1, x25 mov x1, x25
mov x2, sp mov x2, sp
adr lr, ret_to_user
b do_mem_abort b do_mem_abort
el0_ia: el0_ia:
/* /*
* Instruction abort handling * Instruction abort handling
*/ */
mrs x0, far_el1 mrs x26, far_el1
// enable interrupts before calling the main handler // enable interrupts before calling the main handler
enable_dbg_and_irq enable_dbg_and_irq
ct_user_exit
mov x0, x26
orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts
mov x2, sp mov x2, sp
adr lr, ret_to_user
b do_mem_abort b do_mem_abort
el0_fpsimd_acc: el0_fpsimd_acc:
/* /*
* Floating Point or Advanced SIMD access * Floating Point or Advanced SIMD access
*/ */
enable_dbg enable_dbg
ct_user_exit
mov x0, x25 mov x0, x25
mov x1, sp mov x1, sp
adr lr, ret_to_user
b do_fpsimd_acc b do_fpsimd_acc
el0_fpsimd_exc: el0_fpsimd_exc:
/* /*
* Floating Point or Advanced SIMD exception * Floating Point or Advanced SIMD exception
*/ */
enable_dbg enable_dbg
ct_user_exit
mov x0, x25 mov x0, x25
mov x1, sp mov x1, sp
adr lr, ret_to_user
b do_fpsimd_exc b do_fpsimd_exc
el0_sp_pc: el0_sp_pc:
/* /*
* Stack or PC alignment exception handling * Stack or PC alignment exception handling
*/ */
mrs x0, far_el1 mrs x26, far_el1
// enable interrupts before calling the main handler // enable interrupts before calling the main handler
enable_dbg_and_irq enable_dbg_and_irq
mov x0, x26
mov x1, x25 mov x1, x25
mov x2, sp mov x2, sp
adr lr, ret_to_user
b do_sp_pc_abort b do_sp_pc_abort
el0_undef: el0_undef:
/* /*
...@@ -474,7 +509,9 @@ el0_undef: ...@@ -474,7 +509,9 @@ el0_undef:
*/ */
// enable interrupts before calling the main handler // enable interrupts before calling the main handler
enable_dbg_and_irq enable_dbg_and_irq
ct_user_exit
mov x0, sp mov x0, sp
adr lr, ret_to_user
b do_undefinstr b do_undefinstr
el0_dbg: el0_dbg:
/* /*
...@@ -486,12 +523,15 @@ el0_dbg: ...@@ -486,12 +523,15 @@ el0_dbg:
mov x2, sp mov x2, sp
bl do_debug_exception bl do_debug_exception
enable_dbg enable_dbg
ct_user_exit
b ret_to_user b ret_to_user
el0_inv: el0_inv:
enable_dbg enable_dbg
ct_user_exit
mov x0, sp mov x0, sp
mov x1, #BAD_SYNC mov x1, #BAD_SYNC
mrs x2, esr_el1 mrs x2, esr_el1
adr lr, ret_to_user
b bad_mode b bad_mode
ENDPROC(el0_sync) ENDPROC(el0_sync)
...@@ -504,6 +544,7 @@ el0_irq_naked: ...@@ -504,6 +544,7 @@ el0_irq_naked:
bl trace_hardirqs_off bl trace_hardirqs_off
#endif #endif
ct_user_exit
irq_handler irq_handler
#ifdef CONFIG_TRACE_IRQFLAGS #ifdef CONFIG_TRACE_IRQFLAGS
...@@ -608,6 +649,7 @@ el0_svc: ...@@ -608,6 +649,7 @@ el0_svc:
el0_svc_naked: // compat entry point el0_svc_naked: // compat entry point
stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number
enable_dbg_and_irq enable_dbg_and_irq
ct_user_exit 1
ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks
tst x16, #_TIF_SYSCALL_WORK tst x16, #_TIF_SYSCALL_WORK
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/assembler.h> #include <asm/assembler.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -35,37 +36,31 @@ ...@@ -35,37 +36,31 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/virt.h> #include <asm/virt.h>
/*
* swapper_pg_dir is the virtual address of the initial page table. We place
* the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has
* 2 pages and is placed below swapper_pg_dir.
*/
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000 #if (TEXT_OFFSET & 0xf) != 0
#error KERNEL_RAM_VADDR must start at 0xXXX80000 #error TEXT_OFFSET must be at least 16B aligned
#elif (PAGE_OFFSET & 0xfffff) != 0
#error PAGE_OFFSET must be at least 2MB aligned
#elif TEXT_OFFSET > 0xfffff
#error TEXT_OFFSET must be less than 2MB
#endif #endif
#define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) .macro pgtbl, ttb0, ttb1, virt_to_phys
#define IDMAP_DIR_SIZE (2 * PAGE_SIZE) ldr \ttb1, =swapper_pg_dir
ldr \ttb0, =idmap_pg_dir
.globl swapper_pg_dir add \ttb1, \ttb1, \virt_to_phys
.equ swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE add \ttb0, \ttb0, \virt_to_phys
.globl idmap_pg_dir
.equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE
.macro pgtbl, ttb0, ttb1, phys
add \ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE
sub \ttb0, \ttb1, #IDMAP_DIR_SIZE
.endm .endm
#ifdef CONFIG_ARM64_64K_PAGES #ifdef CONFIG_ARM64_64K_PAGES
#define BLOCK_SHIFT PAGE_SHIFT #define BLOCK_SHIFT PAGE_SHIFT
#define BLOCK_SIZE PAGE_SIZE #define BLOCK_SIZE PAGE_SIZE
#define TABLE_SHIFT PMD_SHIFT
#else #else
#define BLOCK_SHIFT SECTION_SHIFT #define BLOCK_SHIFT SECTION_SHIFT
#define BLOCK_SIZE SECTION_SIZE #define BLOCK_SIZE SECTION_SIZE
#define TABLE_SHIFT PUD_SHIFT
#endif #endif
#define KERNEL_START KERNEL_RAM_VADDR #define KERNEL_START KERNEL_RAM_VADDR
...@@ -120,9 +115,9 @@ efi_head: ...@@ -120,9 +115,9 @@ efi_head:
b stext // branch to kernel start, magic b stext // branch to kernel start, magic
.long 0 // reserved .long 0 // reserved
#endif #endif
.quad TEXT_OFFSET // Image load offset from start of RAM .quad _kernel_offset_le // Image load offset from start of RAM, little-endian
.quad 0 // reserved .quad _kernel_size_le // Effective size of kernel image, little-endian
.quad 0 // reserved .quad _kernel_flags_le // Informative flags, little-endian
.quad 0 // reserved .quad 0 // reserved
.quad 0 // reserved .quad 0 // reserved
.quad 0 // reserved .quad 0 // reserved
...@@ -295,6 +290,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1 ...@@ -295,6 +290,23 @@ CPU_LE( bic x0, x0, #(3 << 24) ) // Clear the EE and E0E bits for EL1
msr cnthctl_el2, x0 msr cnthctl_el2, x0
msr cntvoff_el2, xzr // Clear virtual offset msr cntvoff_el2, xzr // Clear virtual offset
#ifdef CONFIG_ARM_GIC_V3
/* GICv3 system register access */
mrs x0, id_aa64pfr0_el1
ubfx x0, x0, #24, #4
cmp x0, #1
b.ne 3f
mrs_s x0, ICC_SRE_EL2
orr x0, x0, #ICC_SRE_EL2_SRE // Set ICC_SRE_EL2.SRE==1
orr x0, x0, #ICC_SRE_EL2_ENABLE // Set ICC_SRE_EL2.Enable==1
msr_s ICC_SRE_EL2, x0
isb // Make sure SRE is now set
msr_s ICH_HCR_EL2, xzr // Reset ICC_HCR_EL2 to defaults
3:
#endif
/* Populate ID registers. */ /* Populate ID registers. */
mrs x0, midr_el1 mrs x0, midr_el1
mrs x1, mpidr_el1 mrs x1, mpidr_el1
...@@ -413,7 +425,7 @@ ENTRY(secondary_startup) ...@@ -413,7 +425,7 @@ ENTRY(secondary_startup)
mov x23, x0 // x23=current cpu_table mov x23, x0 // x23=current cpu_table
cbz x23, __error_p // invalid processor (x23=0)? cbz x23, __error_p // invalid processor (x23=0)?
pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 pgtbl x25, x26, x28 // x25=TTBR0, x26=TTBR1
ldr x12, [x23, #CPU_INFO_SETUP] ldr x12, [x23, #CPU_INFO_SETUP]
add x12, x12, x28 // __virt_to_phys add x12, x12, x28 // __virt_to_phys
blr x12 // initialise processor blr x12 // initialise processor
...@@ -455,8 +467,13 @@ ENDPROC(__enable_mmu) ...@@ -455,8 +467,13 @@ ENDPROC(__enable_mmu)
* x27 = *virtual* address to jump to upon completion * x27 = *virtual* address to jump to upon completion
* *
* other registers depend on the function called 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 6 .align 4
__turn_mmu_on: __turn_mmu_on:
msr sctlr_el1, x0 msr sctlr_el1, x0
isb isb
...@@ -479,17 +496,38 @@ ENDPROC(__calc_phys_offset) ...@@ -479,17 +496,38 @@ ENDPROC(__calc_phys_offset)
.quad PAGE_OFFSET .quad PAGE_OFFSET
/* /*
* Macro to populate the PGD for the corresponding block entry in the next * Macro to create a table entry to the next page.
* level (tbl) for the given virtual address. *
* tbl: page table address
* virt: virtual address
* shift: #imm page table shift
* ptrs: #imm pointers per table page
*
* Preserves: virt
* Corrupts: tmp1, tmp2
* Returns: tbl -> next level table page address
*/
.macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2
lsr \tmp1, \virt, #\shift
and \tmp1, \tmp1, #\ptrs - 1 // table index
add \tmp2, \tbl, #PAGE_SIZE
orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type
str \tmp2, [\tbl, \tmp1, lsl #3]
add \tbl, \tbl, #PAGE_SIZE // next level table page
.endm
/*
* Macro to populate the PGD (and possibily PUD) for the corresponding
* block entry in the next level (tbl) for the given virtual address.
* *
* Preserves: pgd, tbl, virt * Preserves: tbl, next, virt
* Corrupts: tmp1, tmp2 * Corrupts: tmp1, tmp2
*/ */
.macro create_pgd_entry, pgd, tbl, virt, tmp1, tmp2 .macro create_pgd_entry, tbl, virt, tmp1, tmp2
lsr \tmp1, \virt, #PGDIR_SHIFT create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2
and \tmp1, \tmp1, #PTRS_PER_PGD - 1 // PGD index #if SWAPPER_PGTABLE_LEVELS == 3
orr \tmp2, \tbl, #3 // PGD entry table type create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2
str \tmp2, [\pgd, \tmp1, lsl #3] #endif
.endm .endm
/* /*
...@@ -522,7 +560,7 @@ ENDPROC(__calc_phys_offset) ...@@ -522,7 +560,7 @@ ENDPROC(__calc_phys_offset)
* - pgd entry for fixed mappings (TTBR1) * - pgd entry for fixed mappings (TTBR1)
*/ */
__create_page_tables: __create_page_tables:
pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses
mov x27, lr mov x27, lr
/* /*
...@@ -550,10 +588,10 @@ __create_page_tables: ...@@ -550,10 +588,10 @@ __create_page_tables:
/* /*
* Create the identity mapping. * Create the identity mapping.
*/ */
add x0, x25, #PAGE_SIZE // section table address mov x0, x25 // idmap_pg_dir
ldr x3, =KERNEL_START ldr x3, =KERNEL_START
add x3, x3, x28 // __pa(KERNEL_START) add x3, x3, x28 // __pa(KERNEL_START)
create_pgd_entry x25, x0, x3, x5, x6 create_pgd_entry x0, x3, x5, x6
ldr x6, =KERNEL_END ldr x6, =KERNEL_END
mov x5, x3 // __pa(KERNEL_START) mov x5, x3 // __pa(KERNEL_START)
add x6, x6, x28 // __pa(KERNEL_END) add x6, x6, x28 // __pa(KERNEL_END)
...@@ -562,9 +600,9 @@ __create_page_tables: ...@@ -562,9 +600,9 @@ __create_page_tables:
/* /*
* Map the kernel image (starting with PHYS_OFFSET). * Map the kernel image (starting with PHYS_OFFSET).
*/ */
add x0, x26, #PAGE_SIZE // section table address mov x0, x26 // swapper_pg_dir
mov x5, #PAGE_OFFSET mov x5, #PAGE_OFFSET
create_pgd_entry x26, x0, x5, x3, x6 create_pgd_entry x0, x5, x3, x6
ldr x6, =KERNEL_END ldr x6, =KERNEL_END
mov x3, x24 // phys offset mov x3, x24 // phys offset
create_block_map x0, x7, x3, x5, x6 create_block_map x0, x7, x3, x5, x6
...@@ -585,13 +623,6 @@ __create_page_tables: ...@@ -585,13 +623,6 @@ __create_page_tables:
sub x6, x6, #1 // inclusive range sub x6, x6, #1 // inclusive range
create_block_map x0, x7, x3, x5, x6 create_block_map x0, x7, x3, x5, x6
1: 1:
/*
* Create the pgd entry for the fixed mappings.
*/
ldr x5, =FIXADDR_TOP // Fixed mapping virtual address
add x0, x26, #2 * PAGE_SIZE // section table address
create_pgd_entry x26, x0, x5, x6, x7
/* /*
* Since the page tables have been populated with non-cacheable * Since the page tables have been populated with non-cacheable
* accesses (MMU disabled), invalidate the idmap and swapper page * accesses (MMU disabled), invalidate the idmap and swapper page
...@@ -611,7 +642,7 @@ ENDPROC(__create_page_tables) ...@@ -611,7 +642,7 @@ ENDPROC(__create_page_tables)
__switch_data: __switch_data:
.quad __mmap_switched .quad __mmap_switched
.quad __bss_start // x6 .quad __bss_start // x6
.quad _end // x7 .quad __bss_stop // x7
.quad processor_id // x4 .quad processor_id // x4
.quad __fdt_pointer // x5 .quad __fdt_pointer // x5
.quad memstart_addr // x6 .quad memstart_addr // x6
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/linkage.h> #include <linux/linkage.h>
#include <linux/irqchip/arm-gic-v3.h>
#include <asm/assembler.h> #include <asm/assembler.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
......
/*
* Linker script macros to generate Image header fields.
*
* Copyright (C) 2014 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_IMAGE_H
#define __ASM_IMAGE_H
#ifndef LINKER_SCRIPT
#error This file should only be included in vmlinux.lds.S
#endif
/*
* There aren't any ELF relocations we can use to endian-swap values known only
* at link time (e.g. the subtraction of two symbol addresses), so we must get
* the linker to endian-swap certain values before emitting them.
*/
#ifdef CONFIG_CPU_BIG_ENDIAN
#define DATA_LE64(data) \
((((data) & 0x00000000000000ff) << 56) | \
(((data) & 0x000000000000ff00) << 40) | \
(((data) & 0x0000000000ff0000) << 24) | \
(((data) & 0x00000000ff000000) << 8) | \
(((data) & 0x000000ff00000000) >> 8) | \
(((data) & 0x0000ff0000000000) >> 24) | \
(((data) & 0x00ff000000000000) >> 40) | \
(((data) & 0xff00000000000000) >> 56))
#else
#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
#endif
#ifdef CONFIG_CPU_BIG_ENDIAN
#define __HEAD_FLAG_BE 1
#else
#define __HEAD_FLAG_BE 0
#endif
#define __HEAD_FLAGS (__HEAD_FLAG_BE << 0)
/*
* These will output as part of the Image header, which should be little-endian
* regardless of the endianness of the kernel. While constant values could be
* endian swapped in head.S, all are done here for consistency.
*/
#define HEAD_SYMBOLS \
_kernel_size_le = DATA_LE64(_end - _text); \
_kernel_offset_le = DATA_LE64(TEXT_OFFSET); \
_kernel_flags_le = DATA_LE64(__HEAD_FLAGS);
#endif /* __ASM_IMAGE_H */
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
* See Documentation/arm/kernel_user_helpers.txt for formal definitions. * See Documentation/arm/kernel_user_helpers.txt for formal definitions.
*/ */
#include <asm/unistd32.h> #include <asm/unistd.h>
.align 5 .align 5
.globl __kuser_helper_start .globl __kuser_helper_start
......
...@@ -51,6 +51,12 @@ ...@@ -51,6 +51,12 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
#ifdef CONFIG_CC_STACKPROTECTOR
#include <linux/stackprotector.h>
unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
static void setup_restart(void) static void setup_restart(void)
{ {
/* /*
......
...@@ -235,7 +235,7 @@ static void psci_sys_poweroff(void) ...@@ -235,7 +235,7 @@ static void psci_sys_poweroff(void)
* PSCI Function IDs for v0.2+ are well defined so use * PSCI Function IDs for v0.2+ are well defined so use
* standard values. * standard values.
*/ */
static int psci_0_2_init(struct device_node *np) static int __init psci_0_2_init(struct device_node *np)
{ {
int err, ver; int err, ver;
...@@ -296,7 +296,7 @@ static int psci_0_2_init(struct device_node *np) ...@@ -296,7 +296,7 @@ static int psci_0_2_init(struct device_node *np)
/* /*
* PSCI < v0.2 get PSCI Function IDs via DT. * PSCI < v0.2 get PSCI Function IDs via DT.
*/ */
static int psci_0_1_init(struct device_node *np) static int __init psci_0_1_init(struct device_node *np)
{ {
u32 id; u32 id;
int err; int err;
...@@ -434,9 +434,11 @@ static int cpu_psci_cpu_kill(unsigned int cpu) ...@@ -434,9 +434,11 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
return 0; return 0;
} }
#endif #endif
#endif
const struct cpu_operations cpu_psci_ops = { const struct cpu_operations cpu_psci_ops = {
.name = "psci", .name = "psci",
#ifdef CONFIG_SMP
.cpu_init = cpu_psci_cpu_init, .cpu_init = cpu_psci_cpu_init,
.cpu_prepare = cpu_psci_cpu_prepare, .cpu_prepare = cpu_psci_cpu_prepare,
.cpu_boot = cpu_psci_cpu_boot, .cpu_boot = cpu_psci_cpu_boot,
...@@ -445,6 +447,6 @@ const struct cpu_operations cpu_psci_ops = { ...@@ -445,6 +447,6 @@ const struct cpu_operations cpu_psci_ops = {
.cpu_die = cpu_psci_cpu_die, .cpu_die = cpu_psci_cpu_die,
.cpu_kill = cpu_psci_cpu_kill, .cpu_kill = cpu_psci_cpu_kill,
#endif #endif
#endif
}; };
#endif
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/audit.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include <asm/compat.h> #include <asm/compat.h>
#include <asm/debug-monitors.h> #include <asm/debug-monitors.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/syscall.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/system_misc.h> #include <asm/system_misc.h>
...@@ -1113,11 +1115,20 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) ...@@ -1113,11 +1115,20 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_enter(regs, regs->syscallno); trace_sys_enter(regs, regs->syscallno);
#ifdef CONFIG_AUDITSYSCALL
audit_syscall_entry(syscall_get_arch(), regs->syscallno,
regs->orig_x0, regs->regs[1], regs->regs[2], regs->regs[3]);
#endif
return regs->syscallno; return regs->syscallno;
} }
asmlinkage void syscall_trace_exit(struct pt_regs *regs) asmlinkage void syscall_trace_exit(struct pt_regs *regs)
{ {
#ifdef CONFIG_AUDITSYSCALL
audit_syscall_exit(regs);
#endif
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
trace_sys_exit(regs, regs_return_value(regs)); trace_sys_exit(regs, regs_return_value(regs));
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include <linux/efi.h> #include <linux/efi.h>
#include <asm/fixmap.h> #include <asm/fixmap.h>
#include <asm/cpu.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/cputable.h> #include <asm/cputable.h>
...@@ -77,7 +78,6 @@ unsigned int compat_elf_hwcap2 __read_mostly; ...@@ -77,7 +78,6 @@ unsigned int compat_elf_hwcap2 __read_mostly;
#endif #endif
static const char *cpu_name; static const char *cpu_name;
static const char *machine_name;
phys_addr_t __fdt_pointer __initdata; phys_addr_t __fdt_pointer __initdata;
/* /*
...@@ -219,6 +219,8 @@ static void __init setup_processor(void) ...@@ -219,6 +219,8 @@ static void __init setup_processor(void)
sprintf(init_utsname()->machine, ELF_PLATFORM); sprintf(init_utsname()->machine, ELF_PLATFORM);
elf_hwcap = 0; elf_hwcap = 0;
cpuinfo_store_boot_cpu();
/* /*
* Check for sane CTR_EL0.CWG value. * Check for sane CTR_EL0.CWG value.
*/ */
...@@ -307,8 +309,6 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys) ...@@ -307,8 +309,6 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
while (true) while (true)
cpu_relax(); cpu_relax();
} }
machine_name = of_flat_dt_get_machine_name();
} }
/* /*
...@@ -417,14 +417,12 @@ static int __init arm64_device_init(void) ...@@ -417,14 +417,12 @@ static int __init arm64_device_init(void)
} }
arch_initcall_sync(arm64_device_init); arch_initcall_sync(arm64_device_init);
static DEFINE_PER_CPU(struct cpu, cpu_data);
static int __init topology_init(void) static int __init topology_init(void)
{ {
int i; int i;
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
struct cpu *cpu = &per_cpu(cpu_data, i); struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
cpu->hotpluggable = 1; cpu->hotpluggable = 1;
register_cpu(cpu, i); register_cpu(cpu, i);
} }
...@@ -449,10 +447,21 @@ static int c_show(struct seq_file *m, void *v) ...@@ -449,10 +447,21 @@ static int c_show(struct seq_file *m, void *v)
{ {
int i; int i;
seq_printf(m, "Processor\t: %s rev %d (%s)\n", /*
cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); * Dump out the common processor features in a single line. Userspace
* should read the hwcaps with getauxval(AT_HWCAP) rather than
* attempting to parse this.
*/
seq_puts(m, "features\t:");
for (i = 0; hwcap_str[i]; i++)
if (elf_hwcap & (1 << i))
seq_printf(m, " %s", hwcap_str[i]);
seq_puts(m, "\n\n");
for_each_online_cpu(i) { for_each_online_cpu(i) {
struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
u32 midr = cpuinfo->reg_midr;
/* /*
* glibc reads /proc/cpuinfo to determine the number of * glibc reads /proc/cpuinfo to determine the number of
* online processors, looking for lines beginning with * online processors, looking for lines beginning with
...@@ -461,25 +470,13 @@ static int c_show(struct seq_file *m, void *v) ...@@ -461,25 +470,13 @@ static int c_show(struct seq_file *m, void *v)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
seq_printf(m, "processor\t: %d\n", i); seq_printf(m, "processor\t: %d\n", i);
#endif #endif
seq_printf(m, "implementer\t: 0x%02x\n",
MIDR_IMPLEMENTOR(midr));
seq_printf(m, "variant\t\t: 0x%x\n", MIDR_VARIANT(midr));
seq_printf(m, "partnum\t\t: 0x%03x\n", MIDR_PARTNUM(midr));
seq_printf(m, "revision\t: 0x%x\n\n", MIDR_REVISION(midr));
} }
/* dump out the processor features */
seq_puts(m, "Features\t: ");
for (i = 0; hwcap_str[i]; i++)
if (elf_hwcap & (1 << i))
seq_printf(m, "%s ", hwcap_str[i]);
seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
seq_printf(m, "CPU architecture: AArch64\n");
seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
seq_puts(m, "\n");
seq_printf(m, "Hardware\t: %s\n", machine_name);
return 0; return 0;
} }
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include <asm/fpsimd.h> #include <asm/fpsimd.h>
#include <asm/signal32.h> #include <asm/signal32.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd32.h> #include <asm/unistd.h>
struct compat_sigcontext { struct compat_sigcontext {
/* We always set these two fields to 0 */ /* We always set these two fields to 0 */
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h> #include <asm/cputype.h>
#include <asm/cpu_ops.h> #include <asm/cpu_ops.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
...@@ -154,6 +155,11 @@ asmlinkage void secondary_start_kernel(void) ...@@ -154,6 +155,11 @@ asmlinkage void secondary_start_kernel(void)
if (cpu_ops[cpu]->cpu_postboot) if (cpu_ops[cpu]->cpu_postboot)
cpu_ops[cpu]->cpu_postboot(); cpu_ops[cpu]->cpu_postboot();
/*
* Log the CPU info before it is marked online and might get read.
*/
cpuinfo_store_cpu();
/* /*
* Enable GIC and timers. * Enable GIC and timers.
*/ */
......
...@@ -119,7 +119,7 @@ int cpu_suspend(unsigned long arg) ...@@ -119,7 +119,7 @@ int cpu_suspend(unsigned long arg)
extern struct sleep_save_sp sleep_save_sp; extern struct sleep_save_sp sleep_save_sp;
extern phys_addr_t sleep_idmap_phys; extern phys_addr_t sleep_idmap_phys;
static int cpu_suspend_init(void) static int __init cpu_suspend_init(void)
{ {
void *ctx_ptr; void *ctx_ptr;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/unistd32.h> #include <asm/unistd.h>
static inline void static inline void
do_compat_cache_op(unsigned long start, unsigned long end, int flags) do_compat_cache_op(unsigned long start, unsigned long end, int flags)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/cputype.h>
#include <asm/topology.h> #include <asm/topology.h>
static int __init get_cpu_for_node(struct device_node *node) static int __init get_cpu_for_node(struct device_node *node)
...@@ -188,13 +189,9 @@ static int __init parse_dt_topology(void) ...@@ -188,13 +189,9 @@ static int __init parse_dt_topology(void)
* Check that all cores are in the topology; the SMP code will * Check that all cores are in the topology; the SMP code will
* only mark cores described in the DT as possible. * only mark cores described in the DT as possible.
*/ */
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu)
if (cpu_topology[cpu].cluster_id == -1) { if (cpu_topology[cpu].cluster_id == -1)
pr_err("CPU%d: No topology information specified\n",
cpu);
ret = -EINVAL; ret = -EINVAL;
}
}
out_map: out_map:
of_node_put(map); of_node_put(map);
...@@ -219,14 +216,6 @@ static void update_siblings_masks(unsigned int cpuid) ...@@ -219,14 +216,6 @@ static void update_siblings_masks(unsigned int cpuid)
struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
int cpu; int cpu;
if (cpuid_topo->cluster_id == -1) {
/*
* DT does not contain topology information for this cpu.
*/
pr_debug("CPU%u: No topology information configured\n", cpuid);
return;
}
/* update core and thread sibling masks */ /* update core and thread sibling masks */
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
cpu_topo = &cpu_topology[cpu]; cpu_topo = &cpu_topology[cpu];
...@@ -249,6 +238,36 @@ static void update_siblings_masks(unsigned int cpuid) ...@@ -249,6 +238,36 @@ static void update_siblings_masks(unsigned int cpuid)
void store_cpu_topology(unsigned int cpuid) void store_cpu_topology(unsigned int cpuid)
{ {
struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
u64 mpidr;
if (cpuid_topo->cluster_id != -1)
goto topology_populated;
mpidr = read_cpuid_mpidr();
/* Uniprocessor systems can rely on default topology values */
if (mpidr & MPIDR_UP_BITMASK)
return;
/* Create cpu topology mapping based on MPIDR. */
if (mpidr & MPIDR_MT_BITMASK) {
/* Multiprocessor system : Multi-threads per core */
cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
} else {
/* Multiprocessor system : Single-thread per core */
cpuid_topo->thread_id = -1;
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
}
pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
cpuid, cpuid_topo->cluster_id, cpuid_topo->core_id,
cpuid_topo->thread_id, mpidr);
topology_populated:
update_siblings_masks(cpuid); update_siblings_masks(cpuid);
} }
......
...@@ -156,7 +156,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) ...@@ -156,7 +156,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.pc = thread_saved_pc(tsk); frame.pc = thread_saved_pc(tsk);
} }
printk("Call trace:\n"); pr_emerg("Call trace:\n");
while (1) { while (1) {
unsigned long where = frame.pc; unsigned long where = frame.pc;
int ret; int ret;
...@@ -331,17 +331,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) ...@@ -331,17 +331,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
void __pte_error(const char *file, int line, unsigned long val) void __pte_error(const char *file, int line, unsigned long val)
{ {
printk("%s:%d: bad pte %016lx.\n", file, line, val); pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
} }
void __pmd_error(const char *file, int line, unsigned long val) void __pmd_error(const char *file, int line, unsigned long val)
{ {
printk("%s:%d: bad pmd %016lx.\n", file, line, val); pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
}
void __pud_error(const char *file, int line, unsigned long val)
{
pr_crit("%s:%d: bad pud %016lx.\n", file, line, val);
} }
void __pgd_error(const char *file, int line, unsigned long val) void __pgd_error(const char *file, int line, unsigned long val)
{ {
printk("%s:%d: bad pgd %016lx.\n", file, line, val); pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
} }
void __init trap_init(void) void __init trap_init(void)
......
...@@ -88,22 +88,29 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp) ...@@ -88,22 +88,29 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned long addr = AARCH32_VECTORS_BASE; unsigned long addr = AARCH32_VECTORS_BASE;
int ret; static struct vm_special_mapping spec = {
.name = "[vectors]",
.pages = vectors_page,
};
void *ret;
down_write(&mm->mmap_sem); down_write(&mm->mmap_sem);
current->mm->context.vdso = (void *)addr; current->mm->context.vdso = (void *)addr;
/* Map vectors page at the high address. */ /* Map vectors page at the high address. */
ret = install_special_mapping(mm, addr, PAGE_SIZE, ret = _install_special_mapping(mm, addr, PAGE_SIZE,
VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC, VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC,
vectors_page); &spec);
up_write(&mm->mmap_sem); up_write(&mm->mmap_sem);
return ret; return PTR_ERR_OR_ZERO(ret);
} }
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_COMPAT */
static struct vm_special_mapping vdso_spec[2];
static int __init vdso_init(void) static int __init vdso_init(void)
{ {
int i; int i;
...@@ -114,8 +121,8 @@ static int __init vdso_init(void) ...@@ -114,8 +121,8 @@ static int __init vdso_init(void)
} }
vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n", pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
vdso_pages + 1, vdso_pages, 1L, &vdso_start); vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
/* Allocate the vDSO pagelist, plus a page for the data. */ /* Allocate the vDSO pagelist, plus a page for the data. */
vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *), vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
...@@ -123,12 +130,23 @@ static int __init vdso_init(void) ...@@ -123,12 +130,23 @@ static int __init vdso_init(void)
if (vdso_pagelist == NULL) if (vdso_pagelist == NULL)
return -ENOMEM; return -ENOMEM;
/* Grab the vDSO data page. */
vdso_pagelist[0] = virt_to_page(vdso_data);
/* Grab the vDSO code pages. */ /* Grab the vDSO code pages. */
for (i = 0; i < vdso_pages; i++) for (i = 0; i < vdso_pages; i++)
vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE); vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
/* Grab the vDSO data page. */ /* Populate the special mapping structures */
vdso_pagelist[i] = virt_to_page(vdso_data); vdso_spec[0] = (struct vm_special_mapping) {
.name = "[vvar]",
.pages = vdso_pagelist,
};
vdso_spec[1] = (struct vm_special_mapping) {
.name = "[vdso]",
.pages = &vdso_pagelist[1],
};
return 0; return 0;
} }
...@@ -138,52 +156,42 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, ...@@ -138,52 +156,42 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
int uses_interp) int uses_interp)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned long vdso_base, vdso_mapping_len; unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
int ret; void *ret;
vdso_text_len = vdso_pages << PAGE_SHIFT;
/* Be sure to map the data page */ /* Be sure to map the data page */
vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT; vdso_mapping_len = vdso_text_len + PAGE_SIZE;
down_write(&mm->mmap_sem); down_write(&mm->mmap_sem);
vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
if (IS_ERR_VALUE(vdso_base)) { if (IS_ERR_VALUE(vdso_base)) {
ret = vdso_base; ret = ERR_PTR(vdso_base);
goto up_fail; goto up_fail;
} }
mm->context.vdso = (void *)vdso_base; ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
VM_READ|VM_MAYREAD,
ret = install_special_mapping(mm, vdso_base, vdso_mapping_len, &vdso_spec[0]);
VM_READ|VM_EXEC| if (IS_ERR(ret))
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
vdso_pagelist);
if (ret) {
mm->context.vdso = NULL;
goto up_fail; goto up_fail;
}
up_fail: vdso_base += PAGE_SIZE;
up_write(&mm->mmap_sem); mm->context.vdso = (void *)vdso_base;
ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
VM_READ|VM_EXEC|
VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
&vdso_spec[1]);
if (IS_ERR(ret))
goto up_fail;
return ret;
}
const char *arch_vma_name(struct vm_area_struct *vma) up_write(&mm->mmap_sem);
{ return 0;
/*
* We can re-use the vdso pointer in mm_context_t for identifying
* the vectors page for compat applications. The vDSO will always
* sit above TASK_UNMAPPED_BASE and so we don't need to worry about
* it conflicting with the vectors base.
*/
if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) {
#ifdef CONFIG_COMPAT
if (vma->vm_start == AARCH32_VECTORS_BASE)
return "[vectors]";
#endif
return "[vdso]";
}
return NULL; up_fail:
mm->context.vdso = NULL;
up_write(&mm->mmap_sem);
return PTR_ERR(ret);
} }
/* /*
......
...@@ -43,13 +43,13 @@ $(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE ...@@ -43,13 +43,13 @@ $(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE
$(call if_changed,vdsosym) $(call if_changed,vdsosym)
# Assembly rules for the .S files # Assembly rules for the .S files
$(obj-vdso): %.o: %.S $(obj-vdso): %.o: %.S FORCE
$(call if_changed_dep,vdsoas) $(call if_changed_dep,vdsoas)
# Actual build commands # Actual build commands
quiet_cmd_vdsold = VDSOL $@ quiet_cmd_vdsold = VDSOL $@
cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@ cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
quiet_cmd_vdsoas = VDSOA $@ quiet_cmd_vdsoas = VDSOA $@
cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
# Install commands for the unstripped file # Install commands for the unstripped file
......
...@@ -28,6 +28,7 @@ OUTPUT_ARCH(aarch64) ...@@ -28,6 +28,7 @@ OUTPUT_ARCH(aarch64)
SECTIONS SECTIONS
{ {
PROVIDE(_vdso_data = . - PAGE_SIZE);
. = VDSO_LBASE + SIZEOF_HEADERS; . = VDSO_LBASE + SIZEOF_HEADERS;
.hash : { *(.hash) } :text .hash : { *(.hash) } :text
...@@ -57,9 +58,6 @@ SECTIONS ...@@ -57,9 +58,6 @@ SECTIONS
_end = .; _end = .;
PROVIDE(end = .); PROVIDE(end = .);
. = ALIGN(PAGE_SIZE);
PROVIDE(_vdso_data = .);
/DISCARD/ : { /DISCARD/ : {
*(.note.GNU-stack) *(.note.GNU-stack)
*(.data .data.* .gnu.linkonce.d.* .sdata*) *(.data .data.* .gnu.linkonce.d.* .sdata*)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <asm/memory.h> #include <asm/memory.h>
#include <asm/page.h> #include <asm/page.h>
#include "image.h"
#define ARM_EXIT_KEEP(x) #define ARM_EXIT_KEEP(x)
#define ARM_EXIT_DISCARD(x) x #define ARM_EXIT_DISCARD(x) x
...@@ -104,9 +106,18 @@ SECTIONS ...@@ -104,9 +106,18 @@ SECTIONS
_edata = .; _edata = .;
BSS_SECTION(0, 0, 0) BSS_SECTION(0, 0, 0)
. = ALIGN(PAGE_SIZE);
idmap_pg_dir = .;
. += IDMAP_DIR_SIZE;
swapper_pg_dir = .;
. += SWAPPER_DIR_SIZE;
_end = .; _end = .;
STABS_DEBUG STABS_DEBUG
HEAD_SYMBOLS
} }
/* /*
...@@ -114,3 +125,8 @@ SECTIONS ...@@ -114,3 +125,8 @@ SECTIONS
*/ */
ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end), ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end),
"HYP init code too big") "HYP init code too big")
/*
* If padding is applied before .head.text, virt<->phys conversions will fail.
*/
ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
...@@ -62,6 +62,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr) ...@@ -62,6 +62,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
break; break;
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
printk(", *pud=%016llx", pud_val(*pud));
if (pud_none(*pud) || pud_bad(*pud)) if (pud_none(*pud) || pud_bad(*pud))
break; break;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dma-contiguous.h> #include <linux/dma-contiguous.h>
#include <asm/fixmap.h>
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/sizes.h> #include <asm/sizes.h>
...@@ -137,20 +138,16 @@ void __init arm64_memblock_init(void) ...@@ -137,20 +138,16 @@ void __init arm64_memblock_init(void)
{ {
phys_addr_t dma_phys_limit = 0; phys_addr_t dma_phys_limit = 0;
/* Register the kernel text, kernel data and initrd with memblock */ /*
* Register the kernel text, kernel data, initrd, and initial
* pagetables with memblock.
*/
memblock_reserve(__pa(_text), _end - _text); memblock_reserve(__pa(_text), _end - _text);
#ifdef CONFIG_BLK_DEV_INITRD #ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start) if (initrd_start)
memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start); memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
#endif #endif
/*
* Reserve the page tables. These are already in use,
* and can only be in node 0.
*/
memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
early_init_fdt_scan_reserved_mem(); early_init_fdt_scan_reserved_mem();
/* 4GB maximum for 32-bit only capable devices */ /* 4GB maximum for 32-bit only capable devices */
...@@ -269,26 +266,33 @@ void __init mem_init(void) ...@@ -269,26 +266,33 @@ void __init mem_init(void)
#define MLK(b, t) b, t, ((t) - (b)) >> 10 #define MLK(b, t) b, t, ((t) - (b)) >> 10
#define MLM(b, t) b, t, ((t) - (b)) >> 20 #define MLM(b, t) b, t, ((t) - (b)) >> 20
#define MLG(b, t) b, t, ((t) - (b)) >> 30
#define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K)
pr_notice("Virtual kernel memory layout:\n" pr_notice("Virtual kernel memory layout:\n"
" vmalloc : 0x%16lx - 0x%16lx (%6ld MB)\n" " vmalloc : 0x%16lx - 0x%16lx (%6ld GB)\n"
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
" vmemmap : 0x%16lx - 0x%16lx (%6ld MB)\n" " vmemmap : 0x%16lx - 0x%16lx (%6ld GB maximum)\n"
" 0x%16lx - 0x%16lx (%6ld MB actual)\n"
#endif #endif
" PCI I/O : 0x%16lx - 0x%16lx (%6ld MB)\n"
" fixed : 0x%16lx - 0x%16lx (%6ld KB)\n"
" modules : 0x%16lx - 0x%16lx (%6ld MB)\n" " modules : 0x%16lx - 0x%16lx (%6ld MB)\n"
" memory : 0x%16lx - 0x%16lx (%6ld MB)\n" " memory : 0x%16lx - 0x%16lx (%6ld MB)\n"
" .init : 0x%p" " - 0x%p" " (%6ld kB)\n" " .init : 0x%p" " - 0x%p" " (%6ld KB)\n"
" .text : 0x%p" " - 0x%p" " (%6ld kB)\n" " .text : 0x%p" " - 0x%p" " (%6ld KB)\n"
" .data : 0x%p" " - 0x%p" " (%6ld kB)\n", " .data : 0x%p" " - 0x%p" " (%6ld KB)\n",
MLM(VMALLOC_START, VMALLOC_END), MLG(VMALLOC_START, VMALLOC_END),
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
MLG((unsigned long)vmemmap,
(unsigned long)vmemmap + VMEMMAP_SIZE),
MLM((unsigned long)virt_to_page(PAGE_OFFSET), MLM((unsigned long)virt_to_page(PAGE_OFFSET),
(unsigned long)virt_to_page(high_memory)), (unsigned long)virt_to_page(high_memory)),
#endif #endif
MLM((unsigned long)PCI_IOBASE, (unsigned long)PCI_IOBASE + SZ_16M),
MLK(FIXADDR_START, FIXADDR_TOP),
MLM(MODULES_VADDR, MODULES_END), MLM(MODULES_VADDR, MODULES_END),
MLM(PAGE_OFFSET, (unsigned long)high_memory), MLM(PAGE_OFFSET, (unsigned long)high_memory),
MLK_ROUNDUP(__init_begin, __init_end), MLK_ROUNDUP(__init_begin, __init_end),
MLK_ROUNDUP(_text, _etext), MLK_ROUNDUP(_text, _etext),
MLK_ROUNDUP(_sdata, _edata)); MLK_ROUNDUP(_sdata, _edata));
......
...@@ -103,19 +103,28 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size) ...@@ -103,19 +103,28 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
} }
EXPORT_SYMBOL(ioremap_cache); EXPORT_SYMBOL(ioremap_cache);
#ifndef CONFIG_ARM64_64K_PAGES
static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss; static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
#if CONFIG_ARM64_PGTABLE_LEVELS > 2
static pte_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
#endif
#if CONFIG_ARM64_PGTABLE_LEVELS > 3
static pte_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
#endif #endif
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) static inline pud_t * __init early_ioremap_pud(unsigned long addr)
{ {
pgd_t *pgd; pgd_t *pgd;
pud_t *pud;
pgd = pgd_offset_k(addr); pgd = pgd_offset_k(addr);
BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd)); BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
pud = pud_offset(pgd, addr); return pud_offset(pgd, addr);
}
static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
{
pud_t *pud = early_ioremap_pud(addr);
BUG_ON(pud_none(*pud) || pud_bad(*pud)); BUG_ON(pud_none(*pud) || pud_bad(*pud));
return pmd_offset(pud, addr); return pmd_offset(pud, addr);
...@@ -132,13 +141,18 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr) ...@@ -132,13 +141,18 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
void __init early_ioremap_init(void) void __init early_ioremap_init(void)
{ {
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
unsigned long addr = fix_to_virt(FIX_BTMAP_BEGIN);
pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); pgd = pgd_offset_k(addr);
#ifndef CONFIG_ARM64_64K_PAGES pgd_populate(&init_mm, pgd, bm_pud);
/* need to populate pmd for 4k pagesize only */ pud = pud_offset(pgd, addr);
pud_populate(&init_mm, pud, bm_pmd);
pmd = pmd_offset(pud, addr);
pmd_populate_kernel(&init_mm, pmd, bm_pte); pmd_populate_kernel(&init_mm, pmd, bm_pte);
#endif
/* /*
* The boot-ioremap range spans multiple pmds, for which * The boot-ioremap range spans multiple pmds, for which
* we are not prepared: * we are not prepared:
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/sizes.h> #include <asm/sizes.h>
#include <asm/tlb.h> #include <asm/tlb.h>
#include <asm/memblock.h>
#include <asm/mmu_context.h> #include <asm/mmu_context.h>
#include "mm.h" #include "mm.h"
...@@ -204,9 +205,16 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, ...@@ -204,9 +205,16 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
unsigned long end, unsigned long phys, unsigned long end, unsigned long phys,
int map_io) int map_io)
{ {
pud_t *pud = pud_offset(pgd, addr); pud_t *pud;
unsigned long next; unsigned long next;
if (pgd_none(*pgd)) {
pud = early_alloc(PTRS_PER_PUD * sizeof(pud_t));
pgd_populate(&init_mm, pgd, pud);
}
BUG_ON(pgd_bad(*pgd));
pud = pud_offset(pgd, addr);
do { do {
next = pud_addr_end(addr, end); next = pud_addr_end(addr, end);
...@@ -290,10 +298,10 @@ static void __init map_mem(void) ...@@ -290,10 +298,10 @@ static void __init map_mem(void)
* memory addressable from the initial direct kernel mapping. * memory addressable from the initial direct kernel mapping.
* *
* The initial direct kernel mapping, located at swapper_pg_dir, * The initial direct kernel mapping, located at swapper_pg_dir,
* gives us PGDIR_SIZE memory starting from PHYS_OFFSET (which must be * gives us PUD_SIZE memory starting from PHYS_OFFSET (which must be
* aligned to 2MB as per Documentation/arm64/booting.txt). * aligned to 2MB as per Documentation/arm64/booting.txt).
*/ */
limit = PHYS_OFFSET + PGDIR_SIZE; limit = PHYS_OFFSET + PUD_SIZE;
memblock_set_current_limit(limit); memblock_set_current_limit(limit);
/* map all the memory banks */ /* map all the memory banks */
......
...@@ -10,6 +10,11 @@ config ARM_GIC ...@@ -10,6 +10,11 @@ config ARM_GIC
config GIC_NON_BANKED config GIC_NON_BANKED
bool bool
config ARM_GIC_V3
bool
select IRQ_DOMAIN
select MULTI_IRQ_HANDLER
config ARM_NVIC config ARM_NVIC
bool bool
select IRQ_DOMAIN select IRQ_DOMAIN
......
...@@ -15,7 +15,8 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o ...@@ -15,7 +15,8 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o
......
/*
* Copyright (C) 2002 ARM Limited, All Rights Reserved.
*
* 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/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip/arm-gic.h>
#include "irq-gic-common.h"
void gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void))
{
u32 enablemask = 1 << (irq % 32);
u32 enableoff = (irq / 32) * 4;
u32 confmask = 0x2 << ((irq % 16) * 2);
u32 confoff = (irq / 16) * 4;
bool enabled = false;
u32 val;
/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type == IRQ_TYPE_LEVEL_HIGH)
val &= ~confmask;
else if (type == IRQ_TYPE_EDGE_RISING)
val |= confmask;
/*
* As recommended by the spec, disable the interrupt before changing
* the configuration
*/
if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
if (sync_access)
sync_access();
enabled = true;
}
/*
* Write back the new configuration, and possibly re-enable
* the interrupt.
*/
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
if (enabled)
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
if (sync_access)
sync_access();
}
void __init gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void))
{
unsigned int i;
/*
* Set all global interrupts to be level triggered, active low.
*/
for (i = 32; i < gic_irqs; i += 16)
writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4);
/*
* Set priority on all global interrupts.
*/
for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as they are enabled by redistributor registers.
*/
for (i = 32; i < gic_irqs; i += 32)
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8);
if (sync_access)
sync_access();
}
void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
{
int i;
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR);
writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET);
/*
* Set priority on PPI and SGI interrupts
*/
for (i = 0; i < 32; i += 4)
writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
if (sync_access)
sync_access();
}
/* /*
* Copyright (C) 2012 ARM Ltd. * Copyright (C) 2002 ARM Limited, All Rights Reserved.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -13,38 +13,17 @@ ...@@ -13,38 +13,17 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef __ASM_PGTABLE_3LEVEL_HWDEF_H
#define __ASM_PGTABLE_3LEVEL_HWDEF_H
/* #ifndef _IRQ_GIC_COMMON_H
* With LPAE and 4KB pages, there are 3 levels of page tables. Each level has #define _IRQ_GIC_COMMON_H
* 512 entries of 8 bytes each, occupying a 4K page. The first level table
* covers a range of 512GB, each entry representing 1GB. The user and kernel
* address spaces are limited to 512GB each.
*/
#define PTRS_PER_PTE 512
#define PTRS_PER_PMD 512
#define PTRS_PER_PGD 512
/* #include <linux/of.h>
* PGDIR_SHIFT determines the size a top-level page table entry can map. #include <linux/irqdomain.h>
*/
#define PGDIR_SHIFT 30
#define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/* void gic_configure_irq(unsigned int irq, unsigned int type,
* PMD_SHIFT determines the size a middle-level page table entry can map. void __iomem *base, void (*sync_access)(void));
*/ void gic_dist_config(void __iomem *base, int gic_irqs,
#define PMD_SHIFT 21 void (*sync_access)(void));
#define PMD_SIZE (_AC(1, UL) << PMD_SHIFT) void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
#define PMD_MASK (~(PMD_SIZE-1))
/*
* section address mask and size definitions.
*/
#define SECTION_SHIFT 21
#define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT)
#define SECTION_MASK (~(SECTION_SIZE-1))
#endif #endif /* _IRQ_GIC_COMMON_H */
This diff is collapsed.
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include <asm/exception.h> #include <asm/exception.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
#include "irq-gic-common.h"
#include "irqchip.h" #include "irqchip.h"
union gic_base { union gic_base {
...@@ -189,12 +190,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -189,12 +190,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{ {
void __iomem *base = gic_dist_base(d); void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d); unsigned int gicirq = gic_irq(d);
u32 enablemask = 1 << (gicirq % 32);
u32 enableoff = (gicirq / 32) * 4;
u32 confmask = 0x2 << ((gicirq % 16) * 2);
u32 confoff = (gicirq / 16) * 4;
bool enabled = false;
u32 val;
/* Interrupt configuration for SGIs can't be changed */ /* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16) if (gicirq < 16)
...@@ -208,25 +203,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ...@@ -208,25 +203,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (gic_arch_extn.irq_set_type) if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type); gic_arch_extn.irq_set_type(d, type);
val = readl_relaxed(base + GIC_DIST_CONFIG + confoff); gic_configure_irq(gicirq, type, base, NULL);
if (type == IRQ_TYPE_LEVEL_HIGH)
val &= ~confmask;
else if (type == IRQ_TYPE_EDGE_RISING)
val |= confmask;
/*
* As recommended by the spec, disable the interrupt before changing
* the configuration
*/
if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
enabled = true;
}
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
if (enabled)
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
raw_spin_unlock(&irq_controller_lock); raw_spin_unlock(&irq_controller_lock);
...@@ -387,12 +364,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic) ...@@ -387,12 +364,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
writel_relaxed(0, base + GIC_DIST_CTRL); writel_relaxed(0, base + GIC_DIST_CTRL);
/*
* Set all global interrupts to be level triggered, active low.
*/
for (i = 32; i < gic_irqs; i += 16)
writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
/* /*
* Set all global interrupts to this CPU only. * Set all global interrupts to this CPU only.
*/ */
...@@ -402,18 +373,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic) ...@@ -402,18 +373,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
for (i = 32; i < gic_irqs; i += 4) for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4); writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
/* gic_dist_config(base, gic_irqs, NULL);
* Set priority on all global interrupts.
*/
for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
for (i = 32; i < gic_irqs; i += 32)
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
writel_relaxed(1, base + GIC_DIST_CTRL); writel_relaxed(1, base + GIC_DIST_CTRL);
} }
...@@ -440,18 +400,7 @@ static void gic_cpu_init(struct gic_chip_data *gic) ...@@ -440,18 +400,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
if (i != cpu) if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask; gic_cpu_map[i] &= ~cpu_mask;
/* gic_cpu_config(dist_base, NULL);
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
/*
* Set priority on PPI and SGI interrupts
*/
for (i = 0; i < 32; i += 4)
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
writel_relaxed(1, base + GIC_CPU_CTRL); writel_relaxed(1, base + GIC_CPU_CTRL);
......
This diff is collapsed.
...@@ -342,6 +342,7 @@ enum { ...@@ -342,6 +342,7 @@ enum {
#define __AUDIT_ARCH_64BIT 0x80000000 #define __AUDIT_ARCH_64BIT 0x80000000
#define __AUDIT_ARCH_LE 0x40000000 #define __AUDIT_ARCH_LE 0x40000000
#define AUDIT_ARCH_AARCH64 (EM_AARCH64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) #define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE) #define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_ARMEB (EM_ARM) #define AUDIT_ARCH_ARMEB (EM_ARM)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment