diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 14:51:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 14:51:57 -0400 |
| commit | 81f56e5375e84689b891e0e6c5a02ec12a1f18d9 (patch) | |
| tree | a1e128a71ff24fc705428df86a858076cfe4bc13 | |
| parent | 6c09931b3f987898f5c581d267ef269f5e2e9575 (diff) | |
| parent | 27aa55c5e5123fa8b8ad0156559d34d7edff58ca (diff) | |
Merge tag 'arm64-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64
Pull arm64 support from Catalin Marinas:
"Linux support for the 64-bit ARM architecture (AArch64)
Features currently supported:
- 39-bit address space for user and kernel (each)
- 4KB and 64KB page configurations
- Compat (32-bit) user applications (ARMv7, EABI only)
- Flattened Device Tree (mandated for all AArch64 platforms)
- ARM generic timers"
* tag 'arm64-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/linux-aarch64: (35 commits)
arm64: ptrace: remove obsolete ptrace request numbers from user headers
arm64: Do not set the SMP/nAMP processor bit
arm64: MAINTAINERS update
arm64: Build infrastructure
arm64: Miscellaneous header files
arm64: Generic timers support
arm64: Loadable modules
arm64: Miscellaneous library functions
arm64: Performance counters support
arm64: Add support for /proc/sys/debug/exception-trace
arm64: Debugging support
arm64: Floating point and SIMD
arm64: 32-bit (compat) applications support
arm64: User access library functions
arm64: Signal handling support
arm64: VDSO support
arm64: System calls handling
arm64: ELF definitions
arm64: SMP support
arm64: DMA mapping API
...
171 files changed, 21762 insertions, 6 deletions
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt new file mode 100644 index 000000000000..9c4d388daddc --- /dev/null +++ b/Documentation/arm64/booting.txt | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | Booting AArch64 Linux | ||
| 2 | ===================== | ||
| 3 | |||
| 4 | Author: Will Deacon <will.deacon@arm.com> | ||
| 5 | Date : 07 September 2012 | ||
| 6 | |||
| 7 | This document is based on the ARM booting document by Russell King and | ||
| 8 | is relevant to all public releases of the AArch64 Linux kernel. | ||
| 9 | |||
| 10 | The AArch64 exception model is made up of a number of exception levels | ||
| 11 | (EL0 - EL3), with EL0 and EL1 having a secure and a non-secure | ||
| 12 | counterpart. EL2 is the hypervisor level and exists only in non-secure | ||
| 13 | mode. EL3 is the highest priority level and exists only in secure mode. | ||
| 14 | |||
| 15 | For the purposes of this document, we will use the term `boot loader' | ||
| 16 | simply to define all software that executes on the CPU(s) before control | ||
| 17 | is passed to the Linux kernel. This may include secure monitor and | ||
| 18 | hypervisor code, or it may just be a handful of instructions for | ||
| 19 | preparing a minimal boot environment. | ||
| 20 | |||
| 21 | Essentially, the boot loader should provide (as a minimum) the | ||
| 22 | following: | ||
| 23 | |||
| 24 | 1. Setup and initialise the RAM | ||
| 25 | 2. Setup the device tree | ||
| 26 | 3. Decompress the kernel image | ||
| 27 | 4. Call the kernel image | ||
| 28 | |||
| 29 | |||
| 30 | 1. Setup and initialise RAM | ||
| 31 | --------------------------- | ||
| 32 | |||
| 33 | Requirement: MANDATORY | ||
| 34 | |||
| 35 | The boot loader is expected to find and initialise all RAM that the | ||
| 36 | kernel will use for volatile data storage in the system. It performs | ||
| 37 | this in a machine dependent manner. (It may use internal algorithms | ||
| 38 | to automatically locate and size all RAM, or it may use knowledge of | ||
| 39 | the RAM in the machine, or any other method the boot loader designer | ||
| 40 | sees fit.) | ||
| 41 | |||
| 42 | |||
| 43 | 2. Setup the device tree | ||
| 44 | ------------------------- | ||
| 45 | |||
| 46 | Requirement: MANDATORY | ||
| 47 | |||
| 48 | The device tree blob (dtb) must be no bigger than 2 megabytes in size | ||
| 49 | and placed at a 2-megabyte boundary within the first 512 megabytes from | ||
| 50 | the start of the kernel image. This is to allow the kernel to map the | ||
| 51 | blob using a single section mapping in the initial page tables. | ||
| 52 | |||
| 53 | |||
| 54 | 3. Decompress the kernel image | ||
| 55 | ------------------------------ | ||
| 56 | |||
| 57 | Requirement: OPTIONAL | ||
| 58 | |||
| 59 | The AArch64 kernel does not currently provide a decompressor and | ||
| 60 | therefore requires decompression (gzip etc.) to be performed by the boot | ||
| 61 | loader if a compressed Image target (e.g. Image.gz) is used. For | ||
| 62 | bootloaders that do not implement this requirement, the uncompressed | ||
| 63 | Image target is available instead. | ||
| 64 | |||
| 65 | |||
| 66 | 4. Call the kernel image | ||
| 67 | ------------------------ | ||
| 68 | |||
| 69 | Requirement: MANDATORY | ||
| 70 | |||
| 71 | The decompressed kernel image contains a 32-byte header as follows: | ||
| 72 | |||
| 73 | u32 magic = 0x14000008; /* branch to stext, little-endian */ | ||
| 74 | u32 res0 = 0; /* reserved */ | ||
| 75 | u64 text_offset; /* Image load offset */ | ||
| 76 | u64 res1 = 0; /* reserved */ | ||
| 77 | u64 res2 = 0; /* reserved */ | ||
| 78 | |||
| 79 | The image must be placed at the specified offset (currently 0x80000) | ||
| 80 | from the start of the system RAM and called there. The start of the | ||
| 81 | system RAM must be aligned to 2MB. | ||
| 82 | |||
| 83 | Before jumping into the kernel, the following conditions must be met: | ||
| 84 | |||
| 85 | - Quiesce all DMA capable devices so that memory does not get | ||
| 86 | corrupted by bogus network packets or disk data. This will save | ||
| 87 | you many hours of debug. | ||
| 88 | |||
| 89 | - Primary CPU general-purpose register settings | ||
| 90 | x0 = physical address of device tree blob (dtb) in system RAM. | ||
| 91 | x1 = 0 (reserved for future use) | ||
| 92 | x2 = 0 (reserved for future use) | ||
| 93 | x3 = 0 (reserved for future use) | ||
| 94 | |||
| 95 | - CPU mode | ||
| 96 | All forms of interrupts must be masked in PSTATE.DAIF (Debug, SError, | ||
| 97 | IRQ and FIQ). | ||
| 98 | The CPU must be in either EL2 (RECOMMENDED in order to have access to | ||
| 99 | the virtualisation extensions) or non-secure EL1. | ||
| 100 | |||
| 101 | - Caches, MMUs | ||
| 102 | The MMU must be off. | ||
| 103 | Instruction cache may be on or off. | ||
| 104 | Data cache must be off and invalidated. | ||
| 105 | External caches (if present) must be configured and disabled. | ||
| 106 | |||
| 107 | - Architected timers | ||
| 108 | CNTFRQ must be programmed with the timer frequency. | ||
| 109 | If entering the kernel at EL1, CNTHCTL_EL2 must have EL1PCTEN (bit 0) | ||
| 110 | set where available. | ||
| 111 | |||
| 112 | - Coherency | ||
| 113 | All CPUs to be booted by the kernel must be part of the same coherency | ||
| 114 | domain on entry to the kernel. This may require IMPLEMENTATION DEFINED | ||
| 115 | initialisation to enable the receiving of maintenance operations on | ||
| 116 | each CPU. | ||
| 117 | |||
| 118 | - System registers | ||
| 119 | All writable architected system registers at the exception level where | ||
| 120 | the kernel image will be entered must be initialised by software at a | ||
| 121 | higher exception level to prevent execution in an UNKNOWN state. | ||
| 122 | |||
| 123 | The boot loader is expected to enter the kernel on each CPU in the | ||
| 124 | following manner: | ||
| 125 | |||
| 126 | - The primary CPU must jump directly to the first instruction of the | ||
| 127 | kernel image. The device tree blob passed by this CPU must contain | ||
| 128 | for each CPU node: | ||
| 129 | |||
| 130 | 1. An 'enable-method' property. Currently, the only supported value | ||
| 131 | for this field is the string "spin-table". | ||
| 132 | |||
| 133 | 2. A 'cpu-release-addr' property identifying a 64-bit, | ||
| 134 | zero-initialised memory location. | ||
| 135 | |||
| 136 | It is expected that the bootloader will generate these device tree | ||
| 137 | properties and insert them into the blob prior to kernel entry. | ||
| 138 | |||
| 139 | - Any secondary CPUs must spin outside of the kernel in a reserved area | ||
| 140 | of memory (communicated to the kernel by a /memreserve/ region in the | ||
| 141 | device tree) polling their cpu-release-addr location, which must be | ||
| 142 | contained in the reserved region. A wfe instruction may be inserted | ||
| 143 | to reduce the overhead of the busy-loop and a sev will be issued by | ||
| 144 | the primary CPU. When a read of the location pointed to by the | ||
| 145 | cpu-release-addr returns a non-zero value, the CPU must jump directly | ||
| 146 | to this value. | ||
| 147 | |||
| 148 | - Secondary CPU general-purpose register settings | ||
| 149 | x0 = 0 (reserved for future use) | ||
| 150 | x1 = 0 (reserved for future use) | ||
| 151 | x2 = 0 (reserved for future use) | ||
| 152 | x3 = 0 (reserved for future use) | ||
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt new file mode 100644 index 000000000000..dbbdcbba75a3 --- /dev/null +++ b/Documentation/arm64/memory.txt | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | Memory Layout on AArch64 Linux | ||
| 2 | ============================== | ||
| 3 | |||
| 4 | Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 5 | Date : 20 February 2012 | ||
| 6 | |||
| 7 | This document describes the virtual memory layout used by the AArch64 | ||
| 8 | Linux kernel. The architecture allows up to 4 levels of translation | ||
| 9 | tables with a 4KB page size and up to 3 levels with a 64KB page size. | ||
| 10 | |||
| 11 | AArch64 Linux uses 3 levels of translation tables with the 4KB page | ||
| 12 | configuration, allowing 39-bit (512GB) virtual addresses for both user | ||
| 13 | and kernel. With 64KB pages, only 2 levels of translation tables are | ||
| 14 | used but the memory layout is the same. | ||
| 15 | |||
| 16 | User addresses have bits 63:39 set to 0 while the kernel addresses have | ||
| 17 | the same bits set to 1. TTBRx selection is given by bit 63 of the | ||
| 18 | virtual address. The swapper_pg_dir contains only kernel (global) | ||
| 19 | mappings while the user pgd contains only user (non-global) mappings. | ||
| 20 | The swapper_pgd_dir address is written to TTBR1 and never written to | ||
| 21 | TTBR0. | ||
| 22 | |||
| 23 | |||
| 24 | AArch64 Linux memory layout: | ||
| 25 | |||
| 26 | Start End Size Use | ||
| 27 | ----------------------------------------------------------------------- | ||
| 28 | 0000000000000000 0000007fffffffff 512GB user | ||
| 29 | |||
| 30 | ffffff8000000000 ffffffbbfffcffff ~240GB vmalloc | ||
| 31 | |||
| 32 | ffffffbbfffd0000 ffffffbcfffdffff 64KB [guard page] | ||
| 33 | |||
| 34 | ffffffbbfffe0000 ffffffbcfffeffff 64KB PCI I/O space | ||
| 35 | |||
| 36 | ffffffbbffff0000 ffffffbcffffffff 64KB [guard page] | ||
| 37 | |||
| 38 | ffffffbc00000000 ffffffbdffffffff 8GB vmemmap | ||
| 39 | |||
| 40 | ffffffbe00000000 ffffffbffbffffff ~8GB [guard, future vmmemap] | ||
| 41 | |||
| 42 | ffffffbffc000000 ffffffbfffffffff 64MB modules | ||
| 43 | |||
| 44 | ffffffc000000000 ffffffffffffffff 256GB memory | ||
| 45 | |||
| 46 | |||
| 47 | Translation table lookup with 4KB pages: | ||
| 48 | |||
| 49 | +--------+--------+--------+--------+--------+--------+--------+--------+ | ||
| 50 | |63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| | ||
| 51 | +--------+--------+--------+--------+--------+--------+--------+--------+ | ||
| 52 | | | | | | | | ||
| 53 | | | | | | v | ||
| 54 | | | | | | [11:0] in-page offset | ||
| 55 | | | | | +-> [20:12] L3 index | ||
| 56 | | | | +-----------> [29:21] L2 index | ||
| 57 | | | +---------------------> [38:30] L1 index | ||
| 58 | | +-------------------------------> [47:39] L0 index (not used) | ||
| 59 | +-------------------------------------------------> [63] TTBR0/1 | ||
| 60 | |||
| 61 | |||
| 62 | Translation table lookup with 64KB pages: | ||
| 63 | |||
| 64 | +--------+--------+--------+--------+--------+--------+--------+--------+ | ||
| 65 | |63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0| | ||
| 66 | +--------+--------+--------+--------+--------+--------+--------+--------+ | ||
| 67 | | | | | | | ||
| 68 | | | | | v | ||
| 69 | | | | | [15:0] in-page offset | ||
| 70 | | | | +----------> [28:16] L3 index | ||
| 71 | | | +--------------------------> [41:29] L2 index (only 38:29 used) | ||
| 72 | | +-------------------------------> [47:42] L1 index (not used) | ||
| 73 | +-------------------------------------------------> [63] TTBR0/1 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 9362f54bccb8..c98b1a1520d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -1209,6 +1209,12 @@ S: Maintained | |||
| 1209 | F: arch/arm/mach-pxa/z2.c | 1209 | F: arch/arm/mach-pxa/z2.c |
| 1210 | F: arch/arm/mach-pxa/include/mach/z2.h | 1210 | F: arch/arm/mach-pxa/include/mach/z2.h |
| 1211 | 1211 | ||
| 1212 | ARM64 PORT (AARCH64 ARCHITECTURE) | ||
| 1213 | M: Catalin Marinas <catalin.marinas@arm.com> | ||
| 1214 | L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) | ||
| 1215 | S: Maintained | ||
| 1216 | F: arch/arm64/ | ||
| 1217 | |||
| 1212 | ASC7621 HARDWARE MONITOR DRIVER | 1218 | ASC7621 HARDWARE MONITOR DRIVER |
| 1213 | M: George Joseph <george.joseph@fairview5.com> | 1219 | M: George Joseph <george.joseph@fairview5.com> |
| 1214 | L: lm-sensors@lm-sensors.org | 1220 | L: lm-sensors@lm-sensors.org |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig new file mode 100644 index 000000000000..767ba5685454 --- /dev/null +++ b/arch/arm64/Kconfig | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | config ARM64 | ||
| 2 | def_bool y | ||
| 3 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | ||
| 4 | select GENERIC_CLOCKEVENTS | ||
| 5 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
| 6 | select GENERIC_IOMAP | ||
| 7 | select GENERIC_IRQ_PROBE | ||
| 8 | select GENERIC_IRQ_SHOW | ||
| 9 | select GENERIC_SMP_IDLE_THREAD | ||
| 10 | select GENERIC_TIME_VSYSCALL | ||
| 11 | select HARDIRQS_SW_RESEND | ||
| 12 | select HAVE_ARCH_TRACEHOOK | ||
| 13 | select HAVE_DMA_API_DEBUG | ||
| 14 | select HAVE_DMA_ATTRS | ||
| 15 | select HAVE_GENERIC_DMA_COHERENT | ||
| 16 | select HAVE_GENERIC_HARDIRQS | ||
| 17 | select HAVE_HW_BREAKPOINT if PERF_EVENTS | ||
| 18 | select HAVE_IRQ_WORK | ||
| 19 | select HAVE_MEMBLOCK | ||
| 20 | select HAVE_PERF_EVENTS | ||
| 21 | select HAVE_SPARSE_IRQ | ||
| 22 | select IRQ_DOMAIN | ||
| 23 | select NO_BOOTMEM | ||
| 24 | select OF | ||
| 25 | select OF_EARLY_FLATTREE | ||
| 26 | select PERF_USE_VMALLOC | ||
| 27 | select RTC_LIB | ||
| 28 | select SPARSE_IRQ | ||
| 29 | help | ||
| 30 | ARM 64-bit (AArch64) Linux support. | ||
| 31 | |||
| 32 | config 64BIT | ||
| 33 | def_bool y | ||
| 34 | |||
| 35 | config ARCH_PHYS_ADDR_T_64BIT | ||
| 36 | def_bool y | ||
| 37 | |||
| 38 | config MMU | ||
| 39 | def_bool y | ||
| 40 | |||
| 41 | config NO_IOPORT | ||
| 42 | def_bool y | ||
| 43 | |||
| 44 | config STACKTRACE_SUPPORT | ||
| 45 | def_bool y | ||
| 46 | |||
| 47 | config LOCKDEP_SUPPORT | ||
| 48 | def_bool y | ||
| 49 | |||
| 50 | config TRACE_IRQFLAGS_SUPPORT | ||
| 51 | def_bool y | ||
| 52 | |||
| 53 | config GENERIC_LOCKBREAK | ||
| 54 | def_bool y | ||
| 55 | depends on SMP && PREEMPT | ||
| 56 | |||
| 57 | config RWSEM_GENERIC_SPINLOCK | ||
| 58 | def_bool y | ||
| 59 | |||
| 60 | config GENERIC_HWEIGHT | ||
| 61 | def_bool y | ||
| 62 | |||
| 63 | config GENERIC_CSUM | ||
| 64 | def_bool y | ||
| 65 | |||
| 66 | config GENERIC_CALIBRATE_DELAY | ||
| 67 | def_bool y | ||
| 68 | |||
| 69 | config ZONE_DMA32 | ||
| 70 | def_bool y | ||
| 71 | |||
| 72 | config ARCH_DMA_ADDR_T_64BIT | ||
| 73 | def_bool y | ||
| 74 | |||
| 75 | config NEED_DMA_MAP_STATE | ||
| 76 | def_bool y | ||
| 77 | |||
| 78 | config NEED_SG_DMA_LENGTH | ||
| 79 | def_bool y | ||
| 80 | |||
| 81 | config SWIOTLB | ||
| 82 | def_bool y | ||
| 83 | |||
| 84 | config IOMMU_HELPER | ||
| 85 | def_bool SWIOTLB | ||
| 86 | |||
| 87 | source "init/Kconfig" | ||
| 88 | |||
| 89 | source "kernel/Kconfig.freezer" | ||
| 90 | |||
| 91 | menu "System Type" | ||
| 92 | |||
| 93 | endmenu | ||
| 94 | |||
| 95 | menu "Bus support" | ||
| 96 | |||
| 97 | config ARM_AMBA | ||
| 98 | bool | ||
| 99 | |||
| 100 | endmenu | ||
| 101 | |||
| 102 | menu "Kernel Features" | ||
| 103 | |||
| 104 | source "kernel/time/Kconfig" | ||
| 105 | |||
| 106 | config ARM64_64K_PAGES | ||
| 107 | bool "Enable 64KB pages support" | ||
| 108 | help | ||
| 109 | This feature enables 64KB pages support (4KB by default) | ||
| 110 | allowing only two levels of page tables and faster TLB | ||
| 111 | look-up. AArch32 emulation is not available when this feature | ||
| 112 | is enabled. | ||
| 113 | |||
| 114 | config SMP | ||
| 115 | bool "Symmetric Multi-Processing" | ||
| 116 | select USE_GENERIC_SMP_HELPERS | ||
| 117 | help | ||
| 118 | This enables support for systems with more than one CPU. If | ||
| 119 | you say N here, the kernel will run on single and | ||
| 120 | multiprocessor machines, but will use only one CPU of a | ||
| 121 | multiprocessor machine. If you say Y here, the kernel will run | ||
| 122 | on many, but not all, single processor machines. On a single | ||
| 123 | processor machine, the kernel will run faster if you say N | ||
| 124 | here. | ||
| 125 | |||
| 126 | If you don't know what to do here, say N. | ||
| 127 | |||
| 128 | config NR_CPUS | ||
| 129 | int "Maximum number of CPUs (2-32)" | ||
| 130 | range 2 32 | ||
| 131 | depends on SMP | ||
| 132 | default "4" | ||
| 133 | |||
| 134 | source kernel/Kconfig.preempt | ||
| 135 | |||
| 136 | config HZ | ||
| 137 | int | ||
| 138 | default 100 | ||
| 139 | |||
| 140 | config ARCH_HAS_HOLES_MEMORYMODEL | ||
| 141 | def_bool y if SPARSEMEM | ||
| 142 | |||
| 143 | config ARCH_SPARSEMEM_ENABLE | ||
| 144 | def_bool y | ||
| 145 | select SPARSEMEM_VMEMMAP_ENABLE | ||
| 146 | |||
| 147 | config ARCH_SPARSEMEM_DEFAULT | ||
| 148 | def_bool ARCH_SPARSEMEM_ENABLE | ||
| 149 | |||
| 150 | config ARCH_SELECT_MEMORY_MODEL | ||
| 151 | def_bool ARCH_SPARSEMEM_ENABLE | ||
| 152 | |||
| 153 | config HAVE_ARCH_PFN_VALID | ||
| 154 | def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM | ||
| 155 | |||
| 156 | config HW_PERF_EVENTS | ||
| 157 | bool "Enable hardware performance counter support for perf events" | ||
| 158 | depends on PERF_EVENTS | ||
| 159 | default y | ||
| 160 | help | ||
| 161 | Enable hardware performance counter support for perf events. If | ||
| 162 | disabled, perf events will use software events only. | ||
| 163 | |||
| 164 | source "mm/Kconfig" | ||
| 165 | |||
| 166 | endmenu | ||
| 167 | |||
| 168 | menu "Boot options" | ||
| 169 | |||
| 170 | config CMDLINE | ||
| 171 | string "Default kernel command string" | ||
| 172 | default "" | ||
| 173 | help | ||
| 174 | Provide a set of default command-line options at build time by | ||
| 175 | entering them here. As a minimum, you should specify the the | ||
| 176 | root device (e.g. root=/dev/nfs). | ||
| 177 | |||
| 178 | config CMDLINE_FORCE | ||
| 179 | bool "Always use the default kernel command string" | ||
| 180 | help | ||
| 181 | Always use the default kernel command string, even if the boot | ||
| 182 | loader passes other arguments to the kernel. | ||
| 183 | This is useful if you cannot or don't want to change the | ||
| 184 | command-line options your boot loader passes to the kernel. | ||
| 185 | |||
| 186 | endmenu | ||
| 187 | |||
| 188 | menu "Userspace binary formats" | ||
| 189 | |||
| 190 | source "fs/Kconfig.binfmt" | ||
| 191 | |||
| 192 | config COMPAT | ||
| 193 | bool "Kernel support for 32-bit EL0" | ||
| 194 | depends on !ARM64_64K_PAGES | ||
| 195 | select COMPAT_BINFMT_ELF | ||
| 196 | help | ||
| 197 | This option enables support for a 32-bit EL0 running under a 64-bit | ||
| 198 | kernel at EL1. AArch32-specific components such as system calls, | ||
| 199 | the user helper functions, VFP support and the ptrace interface are | ||
| 200 | handled appropriately by the kernel. | ||
| 201 | |||
| 202 | If you want to execute 32-bit userspace applications, say Y. | ||
| 203 | |||
| 204 | config SYSVIPC_COMPAT | ||
| 205 | def_bool y | ||
| 206 | depends on COMPAT && SYSVIPC | ||
| 207 | |||
| 208 | endmenu | ||
| 209 | |||
| 210 | source "net/Kconfig" | ||
| 211 | |||
| 212 | source "drivers/Kconfig" | ||
| 213 | |||
| 214 | source "fs/Kconfig" | ||
| 215 | |||
| 216 | source "arch/arm64/Kconfig.debug" | ||
| 217 | |||
| 218 | source "security/Kconfig" | ||
| 219 | |||
| 220 | source "crypto/Kconfig" | ||
| 221 | |||
| 222 | source "lib/Kconfig" | ||
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug new file mode 100644 index 000000000000..d7553f2bda66 --- /dev/null +++ b/arch/arm64/Kconfig.debug | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | menu "Kernel hacking" | ||
| 2 | |||
| 3 | source "lib/Kconfig.debug" | ||
| 4 | |||
| 5 | config FRAME_POINTER | ||
| 6 | bool | ||
| 7 | default y | ||
| 8 | |||
| 9 | config DEBUG_ERRORS | ||
| 10 | bool "Verbose kernel error messages" | ||
| 11 | depends on DEBUG_KERNEL | ||
| 12 | help | ||
| 13 | This option controls verbose debugging information which can be | ||
| 14 | printed when the kernel detects an internal error. This debugging | ||
| 15 | information is useful to kernel hackers when tracking down problems, | ||
| 16 | but mostly meaningless to other people. It's safe to say Y unless | ||
| 17 | you are concerned with the code size or don't want to see these | ||
| 18 | messages. | ||
| 19 | |||
| 20 | config DEBUG_STACK_USAGE | ||
| 21 | bool "Enable stack utilization instrumentation" | ||
| 22 | depends on DEBUG_KERNEL | ||
| 23 | help | ||
| 24 | Enables the display of the minimum amount of free stack which each | ||
| 25 | task has ever had available in the sysrq-T output. | ||
| 26 | |||
| 27 | endmenu | ||
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile new file mode 100644 index 000000000000..364191f3be43 --- /dev/null +++ b/arch/arm64/Makefile | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | # | ||
| 2 | # arch/arm64/Makefile | ||
| 3 | # | ||
| 4 | # This file is included by the global makefile so that you can add your own | ||
| 5 | # architecture-specific flags and dependencies. | ||
| 6 | # | ||
| 7 | # This file is subject to the terms and conditions of the GNU General Public | ||
| 8 | # License. See the file "COPYING" in the main directory of this archive | ||
| 9 | # for more details. | ||
| 10 | # | ||
| 11 | # Copyright (C) 1995-2001 by Russell King | ||
| 12 | |||
| 13 | LDFLAGS_vmlinux :=-p --no-undefined -X | ||
| 14 | CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) | ||
| 15 | OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S | ||
| 16 | GZFLAGS :=-9 | ||
| 17 | |||
| 18 | LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name) | ||
| 19 | |||
| 20 | KBUILD_DEFCONFIG := defconfig | ||
| 21 | |||
| 22 | KBUILD_CFLAGS += -mgeneral-regs-only | ||
| 23 | KBUILD_CPPFLAGS += -mlittle-endian | ||
| 24 | AS += -EL | ||
| 25 | LD += -EL | ||
| 26 | |||
| 27 | comma = , | ||
| 28 | |||
| 29 | CHECKFLAGS += -D__aarch64__ | ||
| 30 | |||
| 31 | # Default value | ||
| 32 | head-y := arch/arm64/kernel/head.o | ||
| 33 | |||
| 34 | # The byte offset of the kernel image in RAM from the start of RAM. | ||
| 35 | TEXT_OFFSET := 0x00080000 | ||
| 36 | |||
| 37 | export TEXT_OFFSET GZFLAGS | ||
| 38 | |||
| 39 | core-y += arch/arm64/kernel/ arch/arm64/mm/ | ||
| 40 | libs-y := arch/arm64/lib/ $(libs-y) | ||
| 41 | libs-y += $(LIBGCC) | ||
| 42 | |||
| 43 | # Default target when executing plain make | ||
| 44 | KBUILD_IMAGE := Image.gz | ||
| 45 | |||
| 46 | all: $(KBUILD_IMAGE) | ||
| 47 | |||
| 48 | boot := arch/arm64/boot | ||
| 49 | |||
| 50 | Image Image.gz: vmlinux | ||
| 51 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ | ||
| 52 | |||
| 53 | zinstall install: vmlinux | ||
| 54 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@ | ||
| 55 | |||
| 56 | %.dtb: | ||
| 57 | $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@ | ||
| 58 | |||
| 59 | # We use MRPROPER_FILES and CLEAN_FILES now | ||
| 60 | archclean: | ||
| 61 | $(Q)$(MAKE) $(clean)=$(boot) | ||
| 62 | |||
| 63 | define archhelp | ||
| 64 | echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)' | ||
| 65 | echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' | ||
| 66 | echo ' install - Install uncompressed kernel' | ||
| 67 | echo ' zinstall - Install compressed kernel' | ||
| 68 | echo ' Install using (your) ~/bin/installkernel or' | ||
| 69 | echo ' (distribution) /sbin/installkernel or' | ||
| 70 | echo ' install to $$(INSTALL_PATH) and run lilo' | ||
| 71 | endef | ||
diff --git a/arch/arm64/boot/.gitignore b/arch/arm64/boot/.gitignore new file mode 100644 index 000000000000..8dab0bb6ae66 --- /dev/null +++ b/arch/arm64/boot/.gitignore | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | Image | ||
| 2 | Image.gz | ||
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile new file mode 100644 index 000000000000..eca209b2b0bf --- /dev/null +++ b/arch/arm64/boot/Makefile | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | # | ||
| 2 | # arch/arm64/boot/Makefile | ||
| 3 | # | ||
| 4 | # This file is included by the global makefile so that you can add your own | ||
| 5 | # architecture-specific flags and dependencies. | ||
| 6 | # | ||
| 7 | # This file is subject to the terms and conditions of the GNU General Public | ||
| 8 | # License. See the file "COPYING" in the main directory of this archive | ||
| 9 | # for more details. | ||
| 10 | # | ||
| 11 | # Copyright (C) 2012, ARM Ltd. | ||
| 12 | # Author: Will Deacon <will.deacon@arm.com> | ||
| 13 | # | ||
| 14 | # Based on the ia64 boot/Makefile. | ||
| 15 | # | ||
| 16 | |||
| 17 | targets := Image Image.gz | ||
| 18 | |||
| 19 | $(obj)/Image: vmlinux FORCE | ||
| 20 | $(call if_changed,objcopy) | ||
| 21 | |||
| 22 | $(obj)/Image.gz: $(obj)/Image FORCE | ||
| 23 | $(call if_changed,gzip) | ||
| 24 | |||
| 25 | $(obj)/%.dtb: $(src)/dts/%.dts | ||
| 26 | $(call cmd,dtc) | ||
| 27 | |||
| 28 | install: $(obj)/Image | ||
| 29 | $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ | ||
| 30 | $(obj)/Image System.map "$(INSTALL_PATH)" | ||
| 31 | |||
| 32 | zinstall: $(obj)/Image.gz | ||
| 33 | $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ | ||
| 34 | $(obj)/Image.gz System.map "$(INSTALL_PATH)" | ||
| 35 | |||
| 36 | clean-files += *.dtb | ||
diff --git a/arch/arm64/boot/install.sh b/arch/arm64/boot/install.sh new file mode 100644 index 000000000000..12ed78aa6f0c --- /dev/null +++ b/arch/arm64/boot/install.sh | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # | ||
| 3 | # arch/arm64/boot/install.sh | ||
| 4 | # | ||
| 5 | # This file is subject to the terms and conditions of the GNU General Public | ||
| 6 | # License. See the file "COPYING" in the main directory of this archive | ||
| 7 | # for more details. | ||
| 8 | # | ||
| 9 | # Copyright (C) 1995 by Linus Torvalds | ||
| 10 | # | ||
| 11 | # Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin | ||
| 12 | # Adapted from code in arch/i386/boot/install.sh by Russell King | ||
| 13 | # | ||
| 14 | # "make install" script for the AArch64 Linux port | ||
| 15 | # | ||
| 16 | # Arguments: | ||
| 17 | # $1 - kernel version | ||
| 18 | # $2 - kernel image file | ||
| 19 | # $3 - kernel map file | ||
| 20 | # $4 - default install path (blank if root directory) | ||
| 21 | # | ||
| 22 | |||
| 23 | # User may have a custom install script | ||
| 24 | if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi | ||
| 25 | if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi | ||
| 26 | |||
| 27 | if [ "$(basename $2)" = "Image.gz" ]; then | ||
| 28 | # Compressed install | ||
| 29 | echo "Installing compressed kernel" | ||
| 30 | base=vmlinuz | ||
| 31 | else | ||
| 32 | # Normal install | ||
| 33 | echo "Installing normal kernel" | ||
| 34 | base=vmlinux | ||
| 35 | fi | ||
| 36 | |||
| 37 | if [ -f $4/$base-$1 ]; then | ||
| 38 | mv $4/$base-$1 $4/$base-$1.old | ||
| 39 | fi | ||
| 40 | cat $2 > $4/$base-$1 | ||
| 41 | |||
| 42 | # Install system map file | ||
| 43 | if [ -f $4/System.map-$1 ]; then | ||
| 44 | mv $4/System.map-$1 $4/System.map-$1.old | ||
| 45 | fi | ||
| 46 | cp $3 $4/System.map-$1 | ||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig new file mode 100644 index 000000000000..9212c7880da7 --- /dev/null +++ b/arch/arm64/configs/defconfig | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | CONFIG_EXPERIMENTAL=y | ||
| 2 | # CONFIG_LOCALVERSION_AUTO is not set | ||
| 3 | # CONFIG_SWAP is not set | ||
| 4 | CONFIG_SYSVIPC=y | ||
| 5 | CONFIG_POSIX_MQUEUE=y | ||
| 6 | CONFIG_BSD_PROCESS_ACCT=y | ||
| 7 | CONFIG_BSD_PROCESS_ACCT_V3=y | ||
| 8 | CONFIG_NO_HZ=y | ||
| 9 | CONFIG_HIGH_RES_TIMERS=y | ||
| 10 | CONFIG_IKCONFIG=y | ||
| 11 | CONFIG_IKCONFIG_PROC=y | ||
| 12 | CONFIG_LOG_BUF_SHIFT=14 | ||
| 13 | # CONFIG_UTS_NS is not set | ||
| 14 | # CONFIG_IPC_NS is not set | ||
| 15 | # CONFIG_PID_NS is not set | ||
| 16 | # CONFIG_NET_NS is not set | ||
| 17 | CONFIG_SCHED_AUTOGROUP=y | ||
| 18 | CONFIG_BLK_DEV_INITRD=y | ||
| 19 | CONFIG_KALLSYMS_ALL=y | ||
| 20 | # CONFIG_COMPAT_BRK is not set | ||
| 21 | CONFIG_PROFILING=y | ||
| 22 | CONFIG_MODULES=y | ||
| 23 | CONFIG_MODULE_UNLOAD=y | ||
| 24 | # CONFIG_BLK_DEV_BSG is not set | ||
| 25 | # CONFIG_IOSCHED_DEADLINE is not set | ||
| 26 | CONFIG_SMP=y | ||
| 27 | CONFIG_PREEMPT_VOLUNTARY=y | ||
| 28 | CONFIG_CMDLINE="console=ttyAMA0" | ||
| 29 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set | ||
| 30 | CONFIG_COMPAT=y | ||
| 31 | CONFIG_NET=y | ||
| 32 | CONFIG_PACKET=y | ||
| 33 | CONFIG_UNIX=y | ||
| 34 | CONFIG_INET=y | ||
| 35 | CONFIG_IP_PNP=y | ||
| 36 | CONFIG_IP_PNP_DHCP=y | ||
| 37 | CONFIG_IP_PNP_BOOTP=y | ||
| 38 | # CONFIG_INET_LRO is not set | ||
| 39 | # CONFIG_IPV6 is not set | ||
| 40 | # CONFIG_WIRELESS is not set | ||
| 41 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
| 42 | CONFIG_DEVTMPFS=y | ||
| 43 | # CONFIG_BLK_DEV is not set | ||
| 44 | CONFIG_SCSI=y | ||
| 45 | # CONFIG_SCSI_PROC_FS is not set | ||
| 46 | CONFIG_BLK_DEV_SD=y | ||
| 47 | # CONFIG_SCSI_LOWLEVEL is not set | ||
| 48 | CONFIG_NETDEVICES=y | ||
| 49 | CONFIG_MII=y | ||
| 50 | # CONFIG_WLAN is not set | ||
| 51 | CONFIG_INPUT_EVDEV=y | ||
| 52 | # CONFIG_SERIO_I8042 is not set | ||
| 53 | # CONFIG_SERIO_SERPORT is not set | ||
| 54 | CONFIG_LEGACY_PTY_COUNT=16 | ||
| 55 | # CONFIG_HW_RANDOM is not set | ||
| 56 | # CONFIG_HWMON is not set | ||
| 57 | CONFIG_FB=y | ||
| 58 | # CONFIG_VGA_CONSOLE is not set | ||
| 59 | CONFIG_FRAMEBUFFER_CONSOLE=y | ||
| 60 | CONFIG_LOGO=y | ||
| 61 | # CONFIG_LOGO_LINUX_MONO is not set | ||
| 62 | # CONFIG_LOGO_LINUX_VGA16 is not set | ||
| 63 | # CONFIG_USB_SUPPORT is not set | ||
| 64 | # CONFIG_IOMMU_SUPPORT is not set | ||
| 65 | CONFIG_EXT2_FS=y | ||
| 66 | CONFIG_EXT3_FS=y | ||
| 67 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | ||
| 68 | # CONFIG_EXT3_FS_XATTR is not set | ||
| 69 | CONFIG_FUSE_FS=y | ||
| 70 | CONFIG_CUSE=y | ||
| 71 | CONFIG_VFAT_FS=y | ||
| 72 | CONFIG_TMPFS=y | ||
| 73 | # CONFIG_MISC_FILESYSTEMS is not set | ||
| 74 | CONFIG_NFS_FS=y | ||
| 75 | CONFIG_ROOT_NFS=y | ||
| 76 | CONFIG_NLS_CODEPAGE_437=y | ||
| 77 | CONFIG_NLS_ISO8859_1=y | ||
| 78 | CONFIG_MAGIC_SYSRQ=y | ||
| 79 | CONFIG_DEBUG_FS=y | ||
| 80 | CONFIG_DEBUG_KERNEL=y | ||
| 81 | # CONFIG_SCHED_DEBUG is not set | ||
| 82 | CONFIG_DEBUG_INFO=y | ||
| 83 | # CONFIG_FTRACE is not set | ||
| 84 | CONFIG_ATOMIC64_SELFTEST=y | ||
| 85 | CONFIG_DEBUG_ERRORS=y | ||
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild new file mode 100644 index 000000000000..35924a542d43 --- /dev/null +++ b/arch/arm64/include/asm/Kbuild | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | include include/asm-generic/Kbuild.asm | ||
| 2 | |||
| 3 | header-y += hwcap.h | ||
| 4 | |||
| 5 | generic-y += bug.h | ||
| 6 | generic-y += bugs.h | ||
| 7 | generic-y += checksum.h | ||
| 8 | generic-y += cputime.h | ||
| 9 | generic-y += current.h | ||
| 10 | generic-y += delay.h | ||
| 11 | generic-y += div64.h | ||
| 12 | generic-y += dma.h | ||
| 13 | generic-y += emergency-restart.h | ||
| 14 | generic-y += errno.h | ||
| 15 | generic-y += ftrace.h | ||
| 16 | generic-y += hw_irq.h | ||
| 17 | generic-y += ioctl.h | ||
| 18 | generic-y += ioctls.h | ||
| 19 | generic-y += ipcbuf.h | ||
| 20 | generic-y += irq_regs.h | ||
| 21 | generic-y += kdebug.h | ||
| 22 | generic-y += kmap_types.h | ||
| 23 | generic-y += linkage.h | ||
| 24 | generic-y += local.h | ||
| 25 | generic-y += local64.h | ||
| 26 | generic-y += mman.h | ||
| 27 | generic-y += msgbuf.h | ||
| 28 | generic-y += mutex.h | ||
| 29 | generic-y += pci.h | ||
| 30 | generic-y += percpu.h | ||
| 31 | generic-y += poll.h | ||
| 32 | generic-y += posix_types.h | ||
| 33 | generic-y += resource.h | ||
| 34 | generic-y += scatterlist.h | ||
| 35 | generic-y += sections.h | ||
| 36 | generic-y += segment.h | ||
| 37 | generic-y += sembuf.h | ||
| 38 | generic-y += serial.h | ||
| 39 | generic-y += shmbuf.h | ||
| 40 | generic-y += sizes.h | ||
| 41 | generic-y += socket.h | ||
| 42 | generic-y += sockios.h | ||
| 43 | generic-y += string.h | ||
| 44 | generic-y += switch_to.h | ||
| 45 | generic-y += swab.h | ||
| 46 | generic-y += termbits.h | ||
| 47 | generic-y += termios.h | ||
| 48 | generic-y += topology.h | ||
| 49 | generic-y += types.h | ||
| 50 | generic-y += unaligned.h | ||
| 51 | generic-y += user.h | ||
diff --git a/arch/arm64/include/asm/arm_generic.h b/arch/arm64/include/asm/arm_generic.h new file mode 100644 index 000000000000..e4cec9d30f27 --- /dev/null +++ b/arch/arm64/include/asm/arm_generic.h | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm64/include/asm/arm_generic.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_ARM_GENERIC_H | ||
| 20 | #define __ASM_ARM_GENERIC_H | ||
| 21 | |||
| 22 | #include <linux/clocksource.h> | ||
| 23 | |||
| 24 | #define ARCH_TIMER_CTRL_ENABLE (1 << 0) | ||
| 25 | #define ARCH_TIMER_CTRL_IMASK (1 << 1) | ||
| 26 | #define ARCH_TIMER_CTRL_ISTATUS (1 << 2) | ||
| 27 | |||
| 28 | #define ARCH_TIMER_REG_CTRL 0 | ||
| 29 | #define ARCH_TIMER_REG_FREQ 1 | ||
| 30 | #define ARCH_TIMER_REG_TVAL 2 | ||
| 31 | |||
| 32 | static inline void arch_timer_reg_write(int reg, u32 val) | ||
| 33 | { | ||
| 34 | switch (reg) { | ||
| 35 | case ARCH_TIMER_REG_CTRL: | ||
| 36 | asm volatile("msr cntp_ctl_el0, %0" : : "r" (val)); | ||
| 37 | break; | ||
| 38 | case ARCH_TIMER_REG_TVAL: | ||
| 39 | asm volatile("msr cntp_tval_el0, %0" : : "r" (val)); | ||
| 40 | break; | ||
| 41 | default: | ||
| 42 | BUILD_BUG(); | ||
| 43 | } | ||
| 44 | |||
| 45 | isb(); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline u32 arch_timer_reg_read(int reg) | ||
| 49 | { | ||
| 50 | u32 val; | ||
| 51 | |||
| 52 | switch (reg) { | ||
| 53 | case ARCH_TIMER_REG_CTRL: | ||
| 54 | asm volatile("mrs %0, cntp_ctl_el0" : "=r" (val)); | ||
| 55 | break; | ||
| 56 | case ARCH_TIMER_REG_FREQ: | ||
| 57 | asm volatile("mrs %0, cntfrq_el0" : "=r" (val)); | ||
| 58 | break; | ||
| 59 | case ARCH_TIMER_REG_TVAL: | ||
| 60 | asm volatile("mrs %0, cntp_tval_el0" : "=r" (val)); | ||
| 61 | break; | ||
| 62 | default: | ||
| 63 | BUILD_BUG(); | ||
| 64 | } | ||
| 65 | |||
| 66 | return val; | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline void __cpuinit arch_counter_enable_user_access(void) | ||
| 70 | { | ||
| 71 | u32 cntkctl; | ||
| 72 | |||
| 73 | /* Disable user access to the timers and the virtual counter. */ | ||
| 74 | asm volatile("mrs %0, cntkctl_el1" : "=r" (cntkctl)); | ||
| 75 | cntkctl &= ~((3 << 8) | (1 << 1)); | ||
| 76 | |||
| 77 | /* Enable user access to the physical counter and frequency. */ | ||
| 78 | cntkctl |= 1; | ||
| 79 | asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl)); | ||
| 80 | } | ||
| 81 | |||
| 82 | static inline cycle_t arch_counter_get_cntpct(void) | ||
| 83 | { | ||
| 84 | cycle_t cval; | ||
| 85 | |||
| 86 | asm volatile("mrs %0, cntpct_el0" : "=r" (cval)); | ||
| 87 | |||
| 88 | return cval; | ||
| 89 | } | ||
| 90 | |||
| 91 | static inline cycle_t arch_counter_get_cntvct(void) | ||
| 92 | { | ||
| 93 | cycle_t cval; | ||
| 94 | |||
| 95 | asm volatile("mrs %0, cntvct_el0" : "=r" (cval)); | ||
| 96 | |||
| 97 | return cval; | ||
| 98 | } | ||
| 99 | |||
| 100 | #endif | ||
diff --git a/arch/arm64/include/asm/asm-offsets.h b/arch/arm64/include/asm/asm-offsets.h new file mode 100644 index 000000000000..d370ee36a182 --- /dev/null +++ b/arch/arm64/include/asm/asm-offsets.h | |||
| @@ -0,0 +1 @@ | |||
| #include <generated/asm-offsets.h> | |||
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h new file mode 100644 index 000000000000..da2a13e8f1e6 --- /dev/null +++ b/arch/arm64/include/asm/assembler.h | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/assembler.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1996-2000 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASSEMBLY__ | ||
| 20 | #error "Only include this from assembly code" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #include <asm/ptrace.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Stack pushing/popping (register pairs only). Equivalent to store decrement | ||
| 27 | * before, load increment after. | ||
| 28 | */ | ||
| 29 | .macro push, xreg1, xreg2 | ||
| 30 | stp \xreg1, \xreg2, [sp, #-16]! | ||
| 31 | .endm | ||
| 32 | |||
| 33 | .macro pop, xreg1, xreg2 | ||
| 34 | ldp \xreg1, \xreg2, [sp], #16 | ||
| 35 | .endm | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Enable and disable interrupts. | ||
| 39 | */ | ||
| 40 | .macro disable_irq | ||
| 41 | msr daifset, #2 | ||
| 42 | .endm | ||
| 43 | |||
| 44 | .macro enable_irq | ||
| 45 | msr daifclr, #2 | ||
| 46 | .endm | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Save/disable and restore interrupts. | ||
| 50 | */ | ||
| 51 | .macro save_and_disable_irqs, olddaif | ||
| 52 | mrs \olddaif, daif | ||
| 53 | disable_irq | ||
| 54 | .endm | ||
| 55 | |||
| 56 | .macro restore_irqs, olddaif | ||
| 57 | msr daif, \olddaif | ||
| 58 | .endm | ||
| 59 | |||
| 60 | /* | ||
| 61 | * Enable and disable debug exceptions. | ||
| 62 | */ | ||
| 63 | .macro disable_dbg | ||
| 64 | msr daifset, #8 | ||
| 65 | .endm | ||
| 66 | |||
| 67 | .macro enable_dbg | ||
| 68 | msr daifclr, #8 | ||
| 69 | .endm | ||
| 70 | |||
| 71 | .macro disable_step, tmp | ||
| 72 | mrs \tmp, mdscr_el1 | ||
| 73 | bic \tmp, \tmp, #1 | ||
| 74 | msr mdscr_el1, \tmp | ||
| 75 | .endm | ||
| 76 | |||
| 77 | .macro enable_step, tmp | ||
| 78 | mrs \tmp, mdscr_el1 | ||
| 79 | orr \tmp, \tmp, #1 | ||
| 80 | msr mdscr_el1, \tmp | ||
| 81 | .endm | ||
| 82 | |||
| 83 | .macro enable_dbg_if_not_stepping, tmp | ||
| 84 | mrs \tmp, mdscr_el1 | ||
| 85 | tbnz \tmp, #1, 9990f | ||
| 86 | enable_dbg | ||
| 87 | 9990: | ||
| 88 | .endm | ||
| 89 | |||
| 90 | /* | ||
| 91 | * SMP data memory barrier | ||
| 92 | */ | ||
| 93 | .macro smp_dmb, opt | ||
| 94 | #ifdef CONFIG_SMP | ||
| 95 | dmb \opt | ||
| 96 | #endif | ||
| 97 | .endm | ||
| 98 | |||
| 99 | #define USER(l, x...) \ | ||
| 100 | 9999: x; \ | ||
| 101 | .section __ex_table,"a"; \ | ||
| 102 | .align 3; \ | ||
| 103 | .quad 9999b,l; \ | ||
| 104 | .previous | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Register aliases. | ||
| 108 | */ | ||
| 109 | lr .req x30 // link register | ||
diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h new file mode 100644 index 000000000000..407717ba060e --- /dev/null +++ b/arch/arm64/include/asm/atomic.h | |||
| @@ -0,0 +1,305 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/atomic.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1996 Russell King. | ||
| 5 | * Copyright (C) 2002 Deep Blue Solutions Ltd. | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | #ifndef __ASM_ATOMIC_H | ||
| 21 | #define __ASM_ATOMIC_H | ||
| 22 | |||
| 23 | #include <linux/compiler.h> | ||
| 24 | #include <linux/types.h> | ||
| 25 | |||
| 26 | #include <asm/barrier.h> | ||
| 27 | #include <asm/cmpxchg.h> | ||
| 28 | |||
| 29 | #define ATOMIC_INIT(i) { (i) } | ||
| 30 | |||
| 31 | #ifdef __KERNEL__ | ||
| 32 | |||
| 33 | /* | ||
| 34 | * On ARM, ordinary assignment (str instruction) doesn't clear the local | ||
| 35 | * strex/ldrex monitor on some implementations. The reason we can use it for | ||
| 36 | * atomic_set() is the clrex or dummy strex done on every exception return. | ||
| 37 | */ | ||
| 38 | #define atomic_read(v) (*(volatile int *)&(v)->counter) | ||
| 39 | #define atomic_set(v,i) (((v)->counter) = (i)) | ||
| 40 | |||
| 41 | /* | ||
| 42 | * AArch64 UP and SMP safe atomic ops. We use load exclusive and | ||
| 43 | * store exclusive to ensure that these are atomic. We may loop | ||
| 44 | * to ensure that the update happens. | ||
| 45 | */ | ||
| 46 | static inline void atomic_add(int i, atomic_t *v) | ||
| 47 | { | ||
| 48 | unsigned long tmp; | ||
| 49 | int result; | ||
| 50 | |||
| 51 | asm volatile("// atomic_add\n" | ||
| 52 | "1: ldxr %w0, [%3]\n" | ||
| 53 | " add %w0, %w0, %w4\n" | ||
| 54 | " stxr %w1, %w0, [%3]\n" | ||
| 55 | " cbnz %w1, 1b" | ||
| 56 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 57 | : "r" (&v->counter), "Ir" (i) | ||
| 58 | : "cc"); | ||
| 59 | } | ||
| 60 | |||
| 61 | static inline int atomic_add_return(int i, atomic_t *v) | ||
| 62 | { | ||
| 63 | unsigned long tmp; | ||
| 64 | int result; | ||
| 65 | |||
| 66 | asm volatile("// atomic_add_return\n" | ||
| 67 | "1: ldaxr %w0, [%3]\n" | ||
| 68 | " add %w0, %w0, %w4\n" | ||
| 69 | " stlxr %w1, %w0, [%3]\n" | ||
| 70 | " cbnz %w1, 1b" | ||
| 71 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 72 | : "r" (&v->counter), "Ir" (i) | ||
| 73 | : "cc"); | ||
| 74 | |||
| 75 | return result; | ||
| 76 | } | ||
| 77 | |||
| 78 | static inline void atomic_sub(int i, atomic_t *v) | ||
| 79 | { | ||
| 80 | unsigned long tmp; | ||
| 81 | int result; | ||
| 82 | |||
| 83 | asm volatile("// atomic_sub\n" | ||
| 84 | "1: ldxr %w0, [%3]\n" | ||
| 85 | " sub %w0, %w0, %w4\n" | ||
| 86 | " stxr %w1, %w0, [%3]\n" | ||
| 87 | " cbnz %w1, 1b" | ||
| 88 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 89 | : "r" (&v->counter), "Ir" (i) | ||
| 90 | : "cc"); | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline int atomic_sub_return(int i, atomic_t *v) | ||
| 94 | { | ||
| 95 | unsigned long tmp; | ||
| 96 | int result; | ||
| 97 | |||
| 98 | asm volatile("// atomic_sub_return\n" | ||
| 99 | "1: ldaxr %w0, [%3]\n" | ||
| 100 | " sub %w0, %w0, %w4\n" | ||
| 101 | " stlxr %w1, %w0, [%3]\n" | ||
| 102 | " cbnz %w1, 1b" | ||
| 103 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 104 | : "r" (&v->counter), "Ir" (i) | ||
| 105 | : "cc"); | ||
| 106 | |||
| 107 | return result; | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) | ||
| 111 | { | ||
| 112 | unsigned long tmp; | ||
| 113 | int oldval; | ||
| 114 | |||
| 115 | asm volatile("// atomic_cmpxchg\n" | ||
| 116 | "1: ldaxr %w1, [%3]\n" | ||
| 117 | " cmp %w1, %w4\n" | ||
| 118 | " b.ne 2f\n" | ||
| 119 | " stlxr %w0, %w5, [%3]\n" | ||
| 120 | " cbnz %w0, 1b\n" | ||
| 121 | "2:" | ||
| 122 | : "=&r" (tmp), "=&r" (oldval), "+o" (ptr->counter) | ||
| 123 | : "r" (&ptr->counter), "Ir" (old), "r" (new) | ||
| 124 | : "cc"); | ||
| 125 | |||
| 126 | return oldval; | ||
| 127 | } | ||
| 128 | |||
| 129 | static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) | ||
| 130 | { | ||
| 131 | unsigned long tmp, tmp2; | ||
| 132 | |||
| 133 | asm volatile("// atomic_clear_mask\n" | ||
| 134 | "1: ldxr %0, [%3]\n" | ||
| 135 | " bic %0, %0, %4\n" | ||
| 136 | " stxr %w1, %0, [%3]\n" | ||
| 137 | " cbnz %w1, 1b" | ||
| 138 | : "=&r" (tmp), "=&r" (tmp2), "+o" (*addr) | ||
| 139 | : "r" (addr), "Ir" (mask) | ||
| 140 | : "cc"); | ||
| 141 | } | ||
| 142 | |||
| 143 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | ||
| 144 | |||
| 145 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | ||
| 146 | { | ||
| 147 | int c, old; | ||
| 148 | |||
| 149 | c = atomic_read(v); | ||
| 150 | while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) | ||
| 151 | c = old; | ||
| 152 | return c; | ||
| 153 | } | ||
| 154 | |||
| 155 | #define atomic_inc(v) atomic_add(1, v) | ||
| 156 | #define atomic_dec(v) atomic_sub(1, v) | ||
| 157 | |||
| 158 | #define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) | ||
| 159 | #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) | ||
| 160 | #define atomic_inc_return(v) (atomic_add_return(1, v)) | ||
| 161 | #define atomic_dec_return(v) (atomic_sub_return(1, v)) | ||
| 162 | #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) | ||
| 163 | |||
| 164 | #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) | ||
| 165 | |||
| 166 | #define smp_mb__before_atomic_dec() smp_mb() | ||
| 167 | #define smp_mb__after_atomic_dec() smp_mb() | ||
| 168 | #define smp_mb__before_atomic_inc() smp_mb() | ||
| 169 | #define smp_mb__after_atomic_inc() smp_mb() | ||
| 170 | |||
| 171 | /* | ||
| 172 | * 64-bit atomic operations. | ||
| 173 | */ | ||
| 174 | #define ATOMIC64_INIT(i) { (i) } | ||
| 175 | |||
| 176 | #define atomic64_read(v) (*(volatile long long *)&(v)->counter) | ||
| 177 | #define atomic64_set(v,i) (((v)->counter) = (i)) | ||
| 178 | |||
| 179 | static inline void atomic64_add(u64 i, atomic64_t *v) | ||
| 180 | { | ||
| 181 | long result; | ||
| 182 | unsigned long tmp; | ||
| 183 | |||
| 184 | asm volatile("// atomic64_add\n" | ||
| 185 | "1: ldxr %0, [%3]\n" | ||
| 186 | " add %0, %0, %4\n" | ||
| 187 | " stxr %w1, %0, [%3]\n" | ||
| 188 | " cbnz %w1, 1b" | ||
| 189 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 190 | : "r" (&v->counter), "Ir" (i) | ||
| 191 | : "cc"); | ||
| 192 | } | ||
| 193 | |||
| 194 | static inline long atomic64_add_return(long i, atomic64_t *v) | ||
| 195 | { | ||
| 196 | long result; | ||
| 197 | unsigned long tmp; | ||
| 198 | |||
| 199 | asm volatile("// atomic64_add_return\n" | ||
| 200 | "1: ldaxr %0, [%3]\n" | ||
| 201 | " add %0, %0, %4\n" | ||
| 202 | " stlxr %w1, %0, [%3]\n" | ||
| 203 | " cbnz %w1, 1b" | ||
| 204 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 205 | : "r" (&v->counter), "Ir" (i) | ||
| 206 | : "cc"); | ||
| 207 | |||
| 208 | return result; | ||
| 209 | } | ||
| 210 | |||
| 211 | static inline void atomic64_sub(u64 i, atomic64_t *v) | ||
| 212 | { | ||
| 213 | long result; | ||
| 214 | unsigned long tmp; | ||
| 215 | |||
| 216 | asm volatile("// atomic64_sub\n" | ||
| 217 | "1: ldxr %0, [%3]\n" | ||
| 218 | " sub %0, %0, %4\n" | ||
| 219 | " stxr %w1, %0, [%3]\n" | ||
| 220 | " cbnz %w1, 1b" | ||
| 221 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 222 | : "r" (&v->counter), "Ir" (i) | ||
| 223 | : "cc"); | ||
| 224 | } | ||
| 225 | |||
| 226 | static inline long atomic64_sub_return(long i, atomic64_t *v) | ||
| 227 | { | ||
| 228 | long result; | ||
| 229 | unsigned long tmp; | ||
| 230 | |||
| 231 | asm volatile("// atomic64_sub_return\n" | ||
| 232 | "1: ldaxr %0, [%3]\n" | ||
| 233 | " sub %0, %0, %4\n" | ||
| 234 | " stlxr %w1, %0, [%3]\n" | ||
| 235 | " cbnz %w1, 1b" | ||
| 236 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 237 | : "r" (&v->counter), "Ir" (i) | ||
| 238 | : "cc"); | ||
| 239 | |||
| 240 | return result; | ||
| 241 | } | ||
| 242 | |||
| 243 | static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) | ||
| 244 | { | ||
| 245 | long oldval; | ||
| 246 | unsigned long res; | ||
| 247 | |||
| 248 | asm volatile("// atomic64_cmpxchg\n" | ||
| 249 | "1: ldaxr %1, [%3]\n" | ||
| 250 | " cmp %1, %4\n" | ||
| 251 | " b.ne 2f\n" | ||
| 252 | " stlxr %w0, %5, [%3]\n" | ||
| 253 | " cbnz %w0, 1b\n" | ||
| 254 | "2:" | ||
| 255 | : "=&r" (res), "=&r" (oldval), "+o" (ptr->counter) | ||
| 256 | : "r" (&ptr->counter), "Ir" (old), "r" (new) | ||
| 257 | : "cc"); | ||
| 258 | |||
| 259 | return oldval; | ||
| 260 | } | ||
| 261 | |||
| 262 | #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) | ||
| 263 | |||
| 264 | static inline long atomic64_dec_if_positive(atomic64_t *v) | ||
| 265 | { | ||
| 266 | long result; | ||
| 267 | unsigned long tmp; | ||
| 268 | |||
| 269 | asm volatile("// atomic64_dec_if_positive\n" | ||
| 270 | "1: ldaxr %0, [%3]\n" | ||
| 271 | " subs %0, %0, #1\n" | ||
| 272 | " b.mi 2f\n" | ||
| 273 | " stlxr %w1, %0, [%3]\n" | ||
| 274 | " cbnz %w1, 1b\n" | ||
| 275 | "2:" | ||
| 276 | : "=&r" (result), "=&r" (tmp), "+o" (v->counter) | ||
| 277 | : "r" (&v->counter) | ||
| 278 | : "cc"); | ||
| 279 | |||
| 280 | return result; | ||
| 281 | } | ||
| 282 | |||
| 283 | static inline int atomic64_add_unless(atomic64_t *v, long a, long u) | ||
| 284 | { | ||
| 285 | long c, old; | ||
| 286 | |||
| 287 | c = atomic64_read(v); | ||
| 288 | while (c != u && (old = atomic64_cmpxchg((v), c, c + a)) != c) | ||
| 289 | c = old; | ||
| 290 | |||
| 291 | return c != u; | ||
| 292 | } | ||
| 293 | |||
| 294 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) | ||
| 295 | #define atomic64_inc(v) atomic64_add(1LL, (v)) | ||
| 296 | #define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) | ||
| 297 | #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) | ||
| 298 | #define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) | ||
| 299 | #define atomic64_dec(v) atomic64_sub(1LL, (v)) | ||
| 300 | #define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) | ||
| 301 | #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) | ||
| 302 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) | ||
| 303 | |||
| 304 | #endif | ||
| 305 | #endif | ||
diff --git a/arch/arm64/include/asm/auxvec.h b/arch/arm64/include/asm/auxvec.h new file mode 100644 index 000000000000..22d6d8885854 --- /dev/null +++ b/arch/arm64/include/asm/auxvec.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_AUXVEC_H | ||
| 17 | #define __ASM_AUXVEC_H | ||
| 18 | |||
| 19 | /* vDSO location */ | ||
| 20 | #define AT_SYSINFO_EHDR 33 | ||
| 21 | |||
| 22 | #endif | ||
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h new file mode 100644 index 000000000000..d4a63338a53c --- /dev/null +++ b/arch/arm64/include/asm/barrier.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/barrier.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_BARRIER_H | ||
| 19 | #define __ASM_BARRIER_H | ||
| 20 | |||
| 21 | #ifndef __ASSEMBLY__ | ||
| 22 | |||
| 23 | #define sev() asm volatile("sev" : : : "memory") | ||
| 24 | #define wfe() asm volatile("wfe" : : : "memory") | ||
| 25 | #define wfi() asm volatile("wfi" : : : "memory") | ||
| 26 | |||
| 27 | #define isb() asm volatile("isb" : : : "memory") | ||
| 28 | #define dsb() asm volatile("dsb sy" : : : "memory") | ||
| 29 | |||
| 30 | #define mb() dsb() | ||
| 31 | #define rmb() asm volatile("dsb ld" : : : "memory") | ||
| 32 | #define wmb() asm volatile("dsb st" : : : "memory") | ||
| 33 | |||
| 34 | #ifndef CONFIG_SMP | ||
| 35 | #define smp_mb() barrier() | ||
| 36 | #define smp_rmb() barrier() | ||
| 37 | #define smp_wmb() barrier() | ||
| 38 | #else | ||
| 39 | #define smp_mb() asm volatile("dmb ish" : : : "memory") | ||
| 40 | #define smp_rmb() asm volatile("dmb ishld" : : : "memory") | ||
| 41 | #define smp_wmb() asm volatile("dmb ishst" : : : "memory") | ||
| 42 | #endif | ||
| 43 | |||
| 44 | #define read_barrier_depends() do { } while(0) | ||
| 45 | #define smp_read_barrier_depends() do { } while(0) | ||
| 46 | |||
| 47 | #define set_mb(var, value) do { var = value; smp_mb(); } while (0) | ||
| 48 | #define nop() asm volatile("nop"); | ||
| 49 | |||
| 50 | #endif /* __ASSEMBLY__ */ | ||
| 51 | |||
| 52 | #endif /* __ASM_BARRIER_H */ | ||
diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h new file mode 100644 index 000000000000..5e693073b030 --- /dev/null +++ b/arch/arm64/include/asm/bitops.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_BITOPS_H | ||
| 17 | #define __ASM_BITOPS_H | ||
| 18 | |||
| 19 | #include <linux/compiler.h> | ||
| 20 | |||
| 21 | #include <asm/barrier.h> | ||
| 22 | |||
| 23 | /* | ||
| 24 | * clear_bit may not imply a memory barrier | ||
| 25 | */ | ||
| 26 | #ifndef smp_mb__before_clear_bit | ||
| 27 | #define smp_mb__before_clear_bit() smp_mb() | ||
| 28 | #define smp_mb__after_clear_bit() smp_mb() | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #ifndef _LINUX_BITOPS_H | ||
| 32 | #error only <linux/bitops.h> can be included directly | ||
| 33 | #endif | ||
| 34 | |||
| 35 | #include <asm-generic/bitops/builtin-__ffs.h> | ||
| 36 | #include <asm-generic/bitops/builtin-ffs.h> | ||
| 37 | #include <asm-generic/bitops/builtin-__fls.h> | ||
| 38 | #include <asm-generic/bitops/builtin-fls.h> | ||
| 39 | |||
| 40 | #include <asm-generic/bitops/ffz.h> | ||
| 41 | #include <asm-generic/bitops/fls64.h> | ||
| 42 | #include <asm-generic/bitops/find.h> | ||
| 43 | |||
| 44 | #include <asm-generic/bitops/sched.h> | ||
| 45 | #include <asm-generic/bitops/hweight.h> | ||
| 46 | #include <asm-generic/bitops/lock.h> | ||
| 47 | |||
| 48 | #include <asm-generic/bitops/atomic.h> | ||
| 49 | #include <asm-generic/bitops/non-atomic.h> | ||
| 50 | #include <asm-generic/bitops/le.h> | ||
| 51 | #include <asm-generic/bitops/ext2-atomic.h> | ||
| 52 | |||
| 53 | #endif /* __ASM_BITOPS_H */ | ||
diff --git a/arch/arm64/include/asm/bitsperlong.h b/arch/arm64/include/asm/bitsperlong.h new file mode 100644 index 000000000000..fce9c2924fa3 --- /dev/null +++ b/arch/arm64/include/asm/bitsperlong.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_BITSPERLONG_H | ||
| 17 | #define __ASM_BITSPERLONG_H | ||
| 18 | |||
| 19 | #define __BITS_PER_LONG 64 | ||
| 20 | |||
| 21 | #include <asm-generic/bitsperlong.h> | ||
| 22 | |||
| 23 | #endif /* __ASM_BITSPERLONG_H */ | ||
diff --git a/arch/arm64/include/asm/byteorder.h b/arch/arm64/include/asm/byteorder.h new file mode 100644 index 000000000000..2b92046aafc5 --- /dev/null +++ b/arch/arm64/include/asm/byteorder.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_BYTEORDER_H | ||
| 17 | #define __ASM_BYTEORDER_H | ||
| 18 | |||
| 19 | #include <linux/byteorder/little_endian.h> | ||
| 20 | |||
| 21 | #endif /* __ASM_BYTEORDER_H */ | ||
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h new file mode 100644 index 000000000000..390308a67f0d --- /dev/null +++ b/arch/arm64/include/asm/cache.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_CACHE_H | ||
| 17 | #define __ASM_CACHE_H | ||
| 18 | |||
| 19 | #define L1_CACHE_SHIFT 6 | ||
| 20 | #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Memory returned by kmalloc() may be used for DMA, so we must make | ||
| 24 | * sure that all such allocations are cache aligned. Otherwise, | ||
| 25 | * unrelated code may cause parts of the buffer to be read into the | ||
| 26 | * cache before the transfer is done, causing old data to be seen by | ||
| 27 | * the CPU. | ||
| 28 | */ | ||
| 29 | #define ARCH_DMA_MINALIGN L1_CACHE_BYTES | ||
| 30 | #define ARCH_SLAB_MINALIGN 8 | ||
| 31 | |||
| 32 | #endif | ||
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h new file mode 100644 index 000000000000..aa3132ab7f29 --- /dev/null +++ b/arch/arm64/include/asm/cacheflush.h | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/cacheflush.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1999-2002 Russell King. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_CACHEFLUSH_H | ||
| 20 | #define __ASM_CACHEFLUSH_H | ||
| 21 | |||
| 22 | #include <linux/mm.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * This flag is used to indicate that the page pointed to by a pte is clean | ||
| 26 | * and does not require cleaning before returning it to the user. | ||
| 27 | */ | ||
| 28 | #define PG_dcache_clean PG_arch_1 | ||
| 29 | |||
| 30 | /* | ||
| 31 | * MM Cache Management | ||
| 32 | * =================== | ||
| 33 | * | ||
| 34 | * The arch/arm64/mm/cache.S implements these methods. | ||
| 35 | * | ||
| 36 | * Start addresses are inclusive and end addresses are exclusive; start | ||
| 37 | * addresses should be rounded down, end addresses up. | ||
| 38 | * | ||
| 39 | * See Documentation/cachetlb.txt for more information. Please note that | ||
| 40 | * the implementation assumes non-aliasing VIPT D-cache and (aliasing) | ||
| 41 | * VIPT or ASID-tagged VIVT I-cache. | ||
| 42 | * | ||
| 43 | * flush_cache_all() | ||
| 44 | * | ||
| 45 | * Unconditionally clean and invalidate the entire cache. | ||
| 46 | * | ||
| 47 | * flush_cache_mm(mm) | ||
| 48 | * | ||
| 49 | * Clean and invalidate all user space cache entries | ||
| 50 | * before a change of page tables. | ||
| 51 | * | ||
| 52 | * flush_icache_range(start, end) | ||
| 53 | * | ||
| 54 | * Ensure coherency between the I-cache and the D-cache in the | ||
| 55 | * region described by start, end. | ||
| 56 | * - start - virtual start address | ||
| 57 | * - end - virtual end address | ||
| 58 | * | ||
| 59 | * __flush_cache_user_range(start, end) | ||
| 60 | * | ||
| 61 | * Ensure coherency between the I-cache and the D-cache in the | ||
| 62 | * region described by start, end. | ||
| 63 | * - start - virtual start address | ||
| 64 | * - end - virtual end address | ||
| 65 | * | ||
| 66 | * __flush_dcache_area(kaddr, size) | ||
| 67 | * | ||
| 68 | * Ensure that the data held in page is written back. | ||
| 69 | * - kaddr - page address | ||
| 70 | * - size - region size | ||
| 71 | */ | ||
| 72 | extern void flush_cache_all(void); | ||
| 73 | extern void flush_cache_mm(struct mm_struct *mm); | ||
| 74 | extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); | ||
| 75 | extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn); | ||
| 76 | extern void flush_icache_range(unsigned long start, unsigned long end); | ||
| 77 | extern void __flush_dcache_area(void *addr, size_t len); | ||
| 78 | extern void __flush_cache_user_range(unsigned long start, unsigned long end); | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Copy user data from/to a page which is mapped into a different | ||
| 82 | * processes address space. Really, we want to allow our "user | ||
| 83 | * space" model to handle this. | ||
| 84 | */ | ||
| 85 | extern void copy_to_user_page(struct vm_area_struct *, struct page *, | ||
| 86 | unsigned long, void *, const void *, unsigned long); | ||
| 87 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | ||
| 88 | do { \ | ||
| 89 | memcpy(dst, src, len); \ | ||
| 90 | } while (0) | ||
| 91 | |||
| 92 | #define flush_cache_dup_mm(mm) flush_cache_mm(mm) | ||
| 93 | |||
| 94 | /* | ||
| 95 | * flush_dcache_page is used when the kernel has written to the page | ||
| 96 | * cache page at virtual address page->virtual. | ||
| 97 | * | ||
| 98 | * If this page isn't mapped (ie, page_mapping == NULL), or it might | ||
| 99 | * have userspace mappings, then we _must_ always clean + invalidate | ||
| 100 | * the dcache entries associated with the kernel mapping. | ||
| 101 | * | ||
| 102 | * Otherwise we can defer the operation, and clean the cache when we are | ||
| 103 | * about to change to user space. This is the same method as used on SPARC64. | ||
| 104 | * See update_mmu_cache for the user space part. | ||
| 105 | */ | ||
| 106 | #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 | ||
| 107 | extern void flush_dcache_page(struct page *); | ||
| 108 | |||
| 109 | static inline void __flush_icache_all(void) | ||
| 110 | { | ||
| 111 | asm("ic ialluis"); | ||
| 112 | } | ||
| 113 | |||
| 114 | #define flush_dcache_mmap_lock(mapping) \ | ||
| 115 | spin_lock_irq(&(mapping)->tree_lock) | ||
| 116 | #define flush_dcache_mmap_unlock(mapping) \ | ||
| 117 | spin_unlock_irq(&(mapping)->tree_lock) | ||
| 118 | |||
| 119 | #define flush_icache_user_range(vma,page,addr,len) \ | ||
| 120 | flush_dcache_page(page) | ||
| 121 | |||
| 122 | /* | ||
| 123 | * We don't appear to need to do anything here. In fact, if we did, we'd | ||
| 124 | * duplicate cache flushing elsewhere performed by flush_dcache_page(). | ||
| 125 | */ | ||
| 126 | #define flush_icache_page(vma,page) do { } while (0) | ||
| 127 | |||
| 128 | /* | ||
| 129 | * flush_cache_vmap() is used when creating mappings (eg, via vmap, | ||
| 130 | * vmalloc, ioremap etc) in kernel space for pages. On non-VIPT | ||
| 131 | * caches, since the direct-mappings of these pages may contain cached | ||
| 132 | * data, we need to do a full cache flush to ensure that writebacks | ||
| 133 | * don't corrupt data placed into these pages via the new mappings. | ||
| 134 | */ | ||
| 135 | static inline void flush_cache_vmap(unsigned long start, unsigned long end) | ||
| 136 | { | ||
| 137 | /* | ||
| 138 | * set_pte_at() called from vmap_pte_range() does not | ||
| 139 | * have a DSB after cleaning the cache line. | ||
| 140 | */ | ||
| 141 | dsb(); | ||
| 142 | } | ||
| 143 | |||
| 144 | static inline void flush_cache_vunmap(unsigned long start, unsigned long end) | ||
| 145 | { | ||
| 146 | } | ||
| 147 | |||
| 148 | #endif | ||
diff --git a/arch/arm64/include/asm/cachetype.h b/arch/arm64/include/asm/cachetype.h new file mode 100644 index 000000000000..85f5f511352a --- /dev/null +++ b/arch/arm64/include/asm/cachetype.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_CACHETYPE_H | ||
| 17 | #define __ASM_CACHETYPE_H | ||
| 18 | |||
| 19 | #include <asm/cputype.h> | ||
| 20 | |||
| 21 | #define CTR_L1IP_SHIFT 14 | ||
| 22 | #define CTR_L1IP_MASK 3 | ||
| 23 | |||
| 24 | #define ICACHE_POLICY_RESERVED 0 | ||
| 25 | #define ICACHE_POLICY_AIVIVT 1 | ||
| 26 | #define ICACHE_POLICY_VIPT 2 | ||
| 27 | #define ICACHE_POLICY_PIPT 3 | ||
| 28 | |||
| 29 | static inline u32 icache_policy(void) | ||
| 30 | { | ||
| 31 | return (read_cpuid_cachetype() >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK; | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Whilst the D-side always behaves as PIPT on AArch64, aliasing is | ||
| 36 | * permitted in the I-cache. | ||
| 37 | */ | ||
| 38 | static inline int icache_is_aliasing(void) | ||
| 39 | { | ||
| 40 | return icache_policy() != ICACHE_POLICY_PIPT; | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline int icache_is_aivivt(void) | ||
| 44 | { | ||
| 45 | return icache_policy() == ICACHE_POLICY_AIVIVT; | ||
| 46 | } | ||
| 47 | |||
| 48 | #endif /* __ASM_CACHETYPE_H */ | ||
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h new file mode 100644 index 000000000000..e0e65b069d9e --- /dev/null +++ b/arch/arm64/include/asm/cmpxchg.h | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/cmpxchg.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_CMPXCHG_H | ||
| 19 | #define __ASM_CMPXCHG_H | ||
| 20 | |||
| 21 | #include <linux/bug.h> | ||
| 22 | |||
| 23 | #include <asm/barrier.h> | ||
| 24 | |||
| 25 | static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) | ||
| 26 | { | ||
| 27 | unsigned long ret, tmp; | ||
| 28 | |||
| 29 | switch (size) { | ||
| 30 | case 1: | ||
| 31 | asm volatile("// __xchg1\n" | ||
| 32 | "1: ldaxrb %w0, [%3]\n" | ||
| 33 | " stlxrb %w1, %w2, [%3]\n" | ||
| 34 | " cbnz %w1, 1b\n" | ||
| 35 | : "=&r" (ret), "=&r" (tmp) | ||
| 36 | : "r" (x), "r" (ptr) | ||
| 37 | : "memory", "cc"); | ||
| 38 | break; | ||
| 39 | case 2: | ||
| 40 | asm volatile("// __xchg2\n" | ||
| 41 | "1: ldaxrh %w0, [%3]\n" | ||
| 42 | " stlxrh %w1, %w2, [%3]\n" | ||
| 43 | " cbnz %w1, 1b\n" | ||
| 44 | : "=&r" (ret), "=&r" (tmp) | ||
| 45 | : "r" (x), "r" (ptr) | ||
| 46 | : "memory", "cc"); | ||
| 47 | break; | ||
| 48 | case 4: | ||
| 49 | asm volatile("// __xchg4\n" | ||
| 50 | "1: ldaxr %w0, [%3]\n" | ||
| 51 | " stlxr %w1, %w2, [%3]\n" | ||
| 52 | " cbnz %w1, 1b\n" | ||
| 53 | : "=&r" (ret), "=&r" (tmp) | ||
| 54 | : "r" (x), "r" (ptr) | ||
| 55 | : "memory", "cc"); | ||
| 56 | break; | ||
| 57 | case 8: | ||
| 58 | asm volatile("// __xchg8\n" | ||
| 59 | "1: ldaxr %0, [%3]\n" | ||
| 60 | " stlxr %w1, %2, [%3]\n" | ||
| 61 | " cbnz %w1, 1b\n" | ||
| 62 | : "=&r" (ret), "=&r" (tmp) | ||
| 63 | : "r" (x), "r" (ptr) | ||
| 64 | : "memory", "cc"); | ||
| 65 | break; | ||
| 66 | default: | ||
| 67 | BUILD_BUG(); | ||
| 68 | } | ||
| 69 | |||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | #define xchg(ptr,x) \ | ||
| 74 | ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | ||
| 75 | |||
| 76 | static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, | ||
| 77 | unsigned long new, int size) | ||
| 78 | { | ||
| 79 | unsigned long oldval = 0, res; | ||
| 80 | |||
| 81 | switch (size) { | ||
| 82 | case 1: | ||
| 83 | do { | ||
| 84 | asm volatile("// __cmpxchg1\n" | ||
| 85 | " ldxrb %w1, [%2]\n" | ||
| 86 | " mov %w0, #0\n" | ||
| 87 | " cmp %w1, %w3\n" | ||
| 88 | " b.ne 1f\n" | ||
| 89 | " stxrb %w0, %w4, [%2]\n" | ||
| 90 | "1:\n" | ||
| 91 | : "=&r" (res), "=&r" (oldval) | ||
| 92 | : "r" (ptr), "Ir" (old), "r" (new) | ||
| 93 | : "cc"); | ||
| 94 | } while (res); | ||
| 95 | break; | ||
| 96 | |||
| 97 | case 2: | ||
| 98 | do { | ||
| 99 | asm volatile("// __cmpxchg2\n" | ||
| 100 | " ldxrh %w1, [%2]\n" | ||
| 101 | " mov %w0, #0\n" | ||
| 102 | " cmp %w1, %w3\n" | ||
| 103 | " b.ne 1f\n" | ||
| 104 | " stxrh %w0, %w4, [%2]\n" | ||
| 105 | "1:\n" | ||
| 106 | : "=&r" (res), "=&r" (oldval) | ||
| 107 | : "r" (ptr), "Ir" (old), "r" (new) | ||
| 108 | : "memory", "cc"); | ||
| 109 | } while (res); | ||
| 110 | break; | ||
| 111 | |||
| 112 | case 4: | ||
| 113 | do { | ||
| 114 | asm volatile("// __cmpxchg4\n" | ||
| 115 | " ldxr %w1, [%2]\n" | ||
| 116 | " mov %w0, #0\n" | ||
| 117 | " cmp %w1, %w3\n" | ||
| 118 | " b.ne 1f\n" | ||
| 119 | " stxr %w0, %w4, [%2]\n" | ||
| 120 | "1:\n" | ||
| 121 | : "=&r" (res), "=&r" (oldval) | ||
| 122 | : "r" (ptr), "Ir" (old), "r" (new) | ||
| 123 | : "cc"); | ||
| 124 | } while (res); | ||
| 125 | break; | ||
| 126 | |||
| 127 | case 8: | ||
| 128 | do { | ||
| 129 | asm volatile("// __cmpxchg8\n" | ||
| 130 | " ldxr %1, [%2]\n" | ||
| 131 | " mov %w0, #0\n" | ||
| 132 | " cmp %1, %3\n" | ||
| 133 | " b.ne 1f\n" | ||
| 134 | " stxr %w0, %4, [%2]\n" | ||
| 135 | "1:\n" | ||
| 136 | : "=&r" (res), "=&r" (oldval) | ||
| 137 | : "r" (ptr), "Ir" (old), "r" (new) | ||
| 138 | : "cc"); | ||
| 139 | } while (res); | ||
| 140 | break; | ||
| 141 | |||
| 142 | default: | ||
| 143 | BUILD_BUG(); | ||
| 144 | } | ||
| 145 | |||
| 146 | return oldval; | ||
| 147 | } | ||
| 148 | |||
| 149 | static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, | ||
| 150 | unsigned long new, int size) | ||
| 151 | { | ||
| 152 | unsigned long ret; | ||
| 153 | |||
| 154 | smp_mb(); | ||
| 155 | ret = __cmpxchg(ptr, old, new, size); | ||
| 156 | smp_mb(); | ||
| 157 | |||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | |||
| 161 | #define cmpxchg(ptr,o,n) \ | ||
| 162 | ((__typeof__(*(ptr)))__cmpxchg_mb((ptr), \ | ||
| 163 | (unsigned long)(o), \ | ||
| 164 | (unsigned long)(n), \ | ||
| 165 | sizeof(*(ptr)))) | ||
| 166 | |||
| 167 | #define cmpxchg_local(ptr,o,n) \ | ||
| 168 | ((__typeof__(*(ptr)))__cmpxchg((ptr), \ | ||
| 169 | (unsigned long)(o), \ | ||
| 170 | (unsigned long)(n), \ | ||
| 171 | sizeof(*(ptr)))) | ||
| 172 | |||
| 173 | #endif /* __ASM_CMPXCHG_H */ | ||
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h new file mode 100644 index 000000000000..a670a33ad736 --- /dev/null +++ b/arch/arm64/include/asm/compat.h | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_COMPAT_H | ||
| 17 | #define __ASM_COMPAT_H | ||
| 18 | #ifdef __KERNEL__ | ||
| 19 | #ifdef CONFIG_COMPAT | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Architecture specific compatibility types | ||
| 23 | */ | ||
| 24 | #include <linux/types.h> | ||
| 25 | #include <linux/sched.h> | ||
| 26 | |||
| 27 | #define COMPAT_USER_HZ 100 | ||
| 28 | #define COMPAT_UTS_MACHINE "armv8l\0\0" | ||
| 29 | |||
| 30 | typedef u32 compat_size_t; | ||
| 31 | typedef s32 compat_ssize_t; | ||
| 32 | typedef s32 compat_time_t; | ||
| 33 | typedef s32 compat_clock_t; | ||
| 34 | typedef s32 compat_pid_t; | ||
| 35 | typedef u32 __compat_uid_t; | ||
| 36 | typedef u32 __compat_gid_t; | ||
| 37 | typedef u32 __compat_uid32_t; | ||
| 38 | typedef u32 __compat_gid32_t; | ||
| 39 | typedef u32 compat_mode_t; | ||
| 40 | typedef u32 compat_ino_t; | ||
| 41 | typedef u32 compat_dev_t; | ||
| 42 | typedef s32 compat_off_t; | ||
| 43 | typedef s64 compat_loff_t; | ||
| 44 | typedef s16 compat_nlink_t; | ||
| 45 | typedef u16 compat_ipc_pid_t; | ||
| 46 | typedef s32 compat_daddr_t; | ||
| 47 | typedef u32 compat_caddr_t; | ||
| 48 | typedef __kernel_fsid_t compat_fsid_t; | ||
| 49 | typedef s32 compat_key_t; | ||
| 50 | typedef s32 compat_timer_t; | ||
| 51 | |||
| 52 | typedef s32 compat_int_t; | ||
| 53 | typedef s32 compat_long_t; | ||
| 54 | typedef s64 compat_s64; | ||
| 55 | typedef u32 compat_uint_t; | ||
| 56 | typedef u32 compat_ulong_t; | ||
| 57 | typedef u64 compat_u64; | ||
| 58 | |||
| 59 | struct compat_timespec { | ||
| 60 | compat_time_t tv_sec; | ||
| 61 | s32 tv_nsec; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct compat_timeval { | ||
| 65 | compat_time_t tv_sec; | ||
| 66 | s32 tv_usec; | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct compat_stat { | ||
| 70 | compat_dev_t st_dev; | ||
| 71 | compat_ino_t st_ino; | ||
| 72 | compat_mode_t st_mode; | ||
| 73 | compat_nlink_t st_nlink; | ||
| 74 | __compat_uid32_t st_uid; | ||
| 75 | __compat_gid32_t st_gid; | ||
| 76 | compat_dev_t st_rdev; | ||
| 77 | compat_off_t st_size; | ||
| 78 | compat_off_t st_blksize; | ||
| 79 | compat_off_t st_blocks; | ||
| 80 | compat_time_t st_atime; | ||
| 81 | u32 st_atime_nsec; | ||
| 82 | compat_time_t st_mtime; | ||
| 83 | u32 st_mtime_nsec; | ||
| 84 | compat_time_t st_ctime; | ||
| 85 | u32 st_ctime_nsec; | ||
| 86 | u32 __unused4[2]; | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct compat_flock { | ||
| 90 | short l_type; | ||
| 91 | short l_whence; | ||
| 92 | compat_off_t l_start; | ||
| 93 | compat_off_t l_len; | ||
| 94 | compat_pid_t l_pid; | ||
| 95 | }; | ||
| 96 | |||
| 97 | #define F_GETLK64 12 /* using 'struct flock64' */ | ||
| 98 | #define F_SETLK64 13 | ||
| 99 | #define F_SETLKW64 14 | ||
| 100 | |||
| 101 | struct compat_flock64 { | ||
| 102 | short l_type; | ||
| 103 | short l_whence; | ||
| 104 | compat_loff_t l_start; | ||
| 105 | compat_loff_t l_len; | ||
| 106 | compat_pid_t l_pid; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct compat_statfs { | ||
| 110 | int f_type; | ||
| 111 | int f_bsize; | ||
| 112 | int f_blocks; | ||
| 113 | int f_bfree; | ||
| 114 | int f_bavail; | ||
| 115 | int f_files; | ||
| 116 | int f_ffree; | ||
| 117 | compat_fsid_t f_fsid; | ||
| 118 | int f_namelen; /* SunOS ignores this field. */ | ||
| 119 | int f_frsize; | ||
| 120 | int f_flags; | ||
| 121 | int f_spare[4]; | ||
| 122 | }; | ||
| 123 | |||
| 124 | #define COMPAT_RLIM_INFINITY 0xffffffff | ||
| 125 | |||
| 126 | typedef u32 compat_old_sigset_t; | ||
| 127 | |||
| 128 | #define _COMPAT_NSIG 64 | ||
| 129 | #define _COMPAT_NSIG_BPW 32 | ||
| 130 | |||
| 131 | typedef u32 compat_sigset_word; | ||
| 132 | |||
| 133 | #define COMPAT_OFF_T_MAX 0x7fffffff | ||
| 134 | #define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL | ||
| 135 | |||
| 136 | /* | ||
| 137 | * A pointer passed in from user mode. This should not | ||
| 138 | * be used for syscall parameters, just declare them | ||
| 139 | * as pointers because the syscall entry code will have | ||
| 140 | * appropriately converted them already. | ||
| 141 | */ | ||
| 142 | typedef u32 compat_uptr_t; | ||
| 143 | |||
| 144 | static inline void __user *compat_ptr(compat_uptr_t uptr) | ||
| 145 | { | ||
| 146 | return (void __user *)(unsigned long)uptr; | ||
| 147 | } | ||
| 148 | |||
| 149 | static inline compat_uptr_t ptr_to_compat(void __user *uptr) | ||
| 150 | { | ||
| 151 | return (u32)(unsigned long)uptr; | ||
| 152 | } | ||
| 153 | |||
| 154 | static inline void __user *arch_compat_alloc_user_space(long len) | ||
| 155 | { | ||
| 156 | struct pt_regs *regs = task_pt_regs(current); | ||
| 157 | return (void __user *)regs->compat_sp - len; | ||
| 158 | } | ||
| 159 | |||
| 160 | struct compat_ipc64_perm { | ||
| 161 | compat_key_t key; | ||
| 162 | __compat_uid32_t uid; | ||
| 163 | __compat_gid32_t gid; | ||
| 164 | __compat_uid32_t cuid; | ||
| 165 | __compat_gid32_t cgid; | ||
| 166 | unsigned short mode; | ||
| 167 | unsigned short __pad1; | ||
| 168 | unsigned short seq; | ||
| 169 | unsigned short __pad2; | ||
| 170 | compat_ulong_t unused1; | ||
| 171 | compat_ulong_t unused2; | ||
| 172 | }; | ||
| 173 | |||
| 174 | struct compat_semid64_ds { | ||
| 175 | struct compat_ipc64_perm sem_perm; | ||
| 176 | compat_time_t sem_otime; | ||
| 177 | compat_ulong_t __unused1; | ||
| 178 | compat_time_t sem_ctime; | ||
| 179 | compat_ulong_t __unused2; | ||
| 180 | compat_ulong_t sem_nsems; | ||
| 181 | compat_ulong_t __unused3; | ||
| 182 | compat_ulong_t __unused4; | ||
| 183 | }; | ||
| 184 | |||
| 185 | struct compat_msqid64_ds { | ||
| 186 | struct compat_ipc64_perm msg_perm; | ||
| 187 | compat_time_t msg_stime; | ||
| 188 | compat_ulong_t __unused1; | ||
| 189 | compat_time_t msg_rtime; | ||
| 190 | compat_ulong_t __unused2; | ||
| 191 | compat_time_t msg_ctime; | ||
| 192 | compat_ulong_t __unused3; | ||
| 193 | compat_ulong_t msg_cbytes; | ||
| 194 | compat_ulong_t msg_qnum; | ||
| 195 | compat_ulong_t msg_qbytes; | ||
| 196 | compat_pid_t msg_lspid; | ||
| 197 | compat_pid_t msg_lrpid; | ||
| 198 | compat_ulong_t __unused4; | ||
| 199 | compat_ulong_t __unused5; | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct compat_shmid64_ds { | ||
| 203 | struct compat_ipc64_perm shm_perm; | ||
| 204 | compat_size_t shm_segsz; | ||
| 205 | compat_time_t shm_atime; | ||
| 206 | compat_ulong_t __unused1; | ||
| 207 | compat_time_t shm_dtime; | ||
| 208 | compat_ulong_t __unused2; | ||
| 209 | compat_time_t shm_ctime; | ||
| 210 | compat_ulong_t __unused3; | ||
| 211 | compat_pid_t shm_cpid; | ||
| 212 | compat_pid_t shm_lpid; | ||
| 213 | compat_ulong_t shm_nattch; | ||
| 214 | compat_ulong_t __unused4; | ||
| 215 | compat_ulong_t __unused5; | ||
| 216 | }; | ||
| 217 | |||
| 218 | static inline int is_compat_task(void) | ||
| 219 | { | ||
| 220 | return test_thread_flag(TIF_32BIT); | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline int is_compat_thread(struct thread_info *thread) | ||
| 224 | { | ||
| 225 | return test_ti_thread_flag(thread, TIF_32BIT); | ||
| 226 | } | ||
| 227 | |||
| 228 | #else /* !CONFIG_COMPAT */ | ||
| 229 | |||
| 230 | static inline int is_compat_task(void) | ||
| 231 | { | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | static inline int is_compat_thread(struct thread_info *thread) | ||
| 236 | { | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | #endif /* CONFIG_COMPAT */ | ||
| 241 | #endif /* __KERNEL__ */ | ||
| 242 | #endif /* __ASM_COMPAT_H */ | ||
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h new file mode 100644 index 000000000000..ee35fd0f2236 --- /dev/null +++ b/arch/arm64/include/asm/compiler.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/compiler.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_COMPILER_H | ||
| 19 | #define __ASM_COMPILER_H | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This is used to ensure the compiler did actually allocate the register we | ||
| 23 | * asked it for some inline assembly sequences. Apparently we can't trust the | ||
| 24 | * compiler from one version to another so a bit of paranoia won't hurt. This | ||
| 25 | * string is meant to be concatenated with the inline asm string and will | ||
| 26 | * cause compilation to stop on mismatch. (for details, see gcc PR 15089) | ||
| 27 | */ | ||
| 28 | #define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" | ||
| 29 | |||
| 30 | #endif /* __ASM_COMPILER_H */ | ||
diff --git a/arch/arm64/include/asm/cputable.h b/arch/arm64/include/asm/cputable.h new file mode 100644 index 000000000000..e3bd983d3661 --- /dev/null +++ b/arch/arm64/include/asm/cputable.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm64/include/asm/cputable.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_CPUTABLE_H | ||
| 19 | #define __ASM_CPUTABLE_H | ||
| 20 | |||
| 21 | struct cpu_info { | ||
| 22 | unsigned int cpu_id_val; | ||
| 23 | unsigned int cpu_id_mask; | ||
| 24 | const char *cpu_name; | ||
| 25 | unsigned long (*cpu_setup)(void); | ||
| 26 | }; | ||
| 27 | |||
| 28 | extern struct cpu_info *lookup_processor_type(unsigned int); | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h new file mode 100644 index 000000000000..ef54125e6c1e --- /dev/null +++ b/arch/arm64/include/asm/cputype.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_CPUTYPE_H | ||
| 17 | #define __ASM_CPUTYPE_H | ||
| 18 | |||
| 19 | #define ID_MIDR_EL1 "midr_el1" | ||
| 20 | #define ID_CTR_EL0 "ctr_el0" | ||
| 21 | |||
| 22 | #define ID_AA64PFR0_EL1 "id_aa64pfr0_el1" | ||
| 23 | #define ID_AA64DFR0_EL1 "id_aa64dfr0_el1" | ||
| 24 | #define ID_AA64AFR0_EL1 "id_aa64afr0_el1" | ||
| 25 | #define ID_AA64ISAR0_EL1 "id_aa64isar0_el1" | ||
| 26 | #define ID_AA64MMFR0_EL1 "id_aa64mmfr0_el1" | ||
| 27 | |||
| 28 | #define read_cpuid(reg) ({ \ | ||
| 29 | u64 __val; \ | ||
| 30 | asm("mrs %0, " reg : "=r" (__val)); \ | ||
| 31 | __val; \ | ||
| 32 | }) | ||
| 33 | |||
| 34 | /* | ||
| 35 | * The CPU ID never changes at run time, so we might as well tell the | ||
| 36 | * compiler that it's constant. Use this function to read the CPU ID | ||
| 37 | * rather than directly reading processor_id or read_cpuid() directly. | ||
| 38 | */ | ||
| 39 | static inline u32 __attribute_const__ read_cpuid_id(void) | ||
| 40 | { | ||
| 41 | return read_cpuid(ID_MIDR_EL1); | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline u32 __attribute_const__ read_cpuid_cachetype(void) | ||
| 45 | { | ||
| 46 | return read_cpuid(ID_CTR_EL0); | ||
| 47 | } | ||
| 48 | |||
| 49 | #endif | ||
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h new file mode 100644 index 000000000000..7eaa0b302493 --- /dev/null +++ b/arch/arm64/include/asm/debug-monitors.h | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_DEBUG_MONITORS_H | ||
| 17 | #define __ASM_DEBUG_MONITORS_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | #define DBG_ESR_EVT(x) (((x) >> 27) & 0x7) | ||
| 22 | |||
| 23 | /* AArch64 */ | ||
| 24 | #define DBG_ESR_EVT_HWBP 0x0 | ||
| 25 | #define DBG_ESR_EVT_HWSS 0x1 | ||
| 26 | #define DBG_ESR_EVT_HWWP 0x2 | ||
| 27 | #define DBG_ESR_EVT_BRK 0x6 | ||
| 28 | |||
| 29 | enum debug_el { | ||
| 30 | DBG_ACTIVE_EL0 = 0, | ||
| 31 | DBG_ACTIVE_EL1, | ||
| 32 | }; | ||
| 33 | |||
| 34 | /* AArch32 */ | ||
| 35 | #define DBG_ESR_EVT_BKPT 0x4 | ||
| 36 | #define DBG_ESR_EVT_VECC 0x5 | ||
| 37 | |||
| 38 | #define AARCH32_BREAK_ARM 0x07f001f0 | ||
| 39 | #define AARCH32_BREAK_THUMB 0xde01 | ||
| 40 | #define AARCH32_BREAK_THUMB2_LO 0xf7f0 | ||
| 41 | #define AARCH32_BREAK_THUMB2_HI 0xa000 | ||
| 42 | |||
| 43 | #ifndef __ASSEMBLY__ | ||
| 44 | struct task_struct; | ||
| 45 | |||
| 46 | #define local_dbg_save(flags) \ | ||
| 47 | do { \ | ||
| 48 | typecheck(unsigned long, flags); \ | ||
| 49 | asm volatile( \ | ||
| 50 | "mrs %0, daif // local_dbg_save\n" \ | ||
| 51 | "msr daifset, #8" \ | ||
| 52 | : "=r" (flags) : : "memory"); \ | ||
| 53 | } while (0) | ||
| 54 | |||
| 55 | #define local_dbg_restore(flags) \ | ||
| 56 | do { \ | ||
| 57 | typecheck(unsigned long, flags); \ | ||
| 58 | asm volatile( \ | ||
| 59 | "msr daif, %0 // local_dbg_restore\n" \ | ||
| 60 | : : "r" (flags) : "memory"); \ | ||
| 61 | } while (0) | ||
| 62 | |||
| 63 | #define DBG_ARCH_ID_RESERVED 0 /* In case of ptrace ABI updates. */ | ||
| 64 | |||
| 65 | u8 debug_monitors_arch(void); | ||
| 66 | |||
| 67 | void enable_debug_monitors(enum debug_el el); | ||
| 68 | void disable_debug_monitors(enum debug_el el); | ||
| 69 | |||
| 70 | void user_rewind_single_step(struct task_struct *task); | ||
| 71 | void user_fastforward_single_step(struct task_struct *task); | ||
| 72 | |||
| 73 | void kernel_enable_single_step(struct pt_regs *regs); | ||
| 74 | void kernel_disable_single_step(void); | ||
| 75 | int kernel_active_single_step(void); | ||
| 76 | |||
| 77 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 78 | int reinstall_suspended_bps(struct pt_regs *regs); | ||
| 79 | #else | ||
| 80 | static inline int reinstall_suspended_bps(struct pt_regs *regs) | ||
| 81 | { | ||
| 82 | return -ENODEV; | ||
| 83 | } | ||
| 84 | #endif | ||
| 85 | |||
| 86 | #endif /* __ASSEMBLY */ | ||
| 87 | #endif /* __KERNEL__ */ | ||
| 88 | #endif /* __ASM_DEBUG_MONITORS_H */ | ||
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h new file mode 100644 index 000000000000..0d8453c755a8 --- /dev/null +++ b/arch/arm64/include/asm/device.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_DEVICE_H | ||
| 17 | #define __ASM_DEVICE_H | ||
| 18 | |||
| 19 | struct dev_archdata { | ||
| 20 | struct dma_map_ops *dma_ops; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct pdev_archdata { | ||
| 24 | }; | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h new file mode 100644 index 000000000000..538f4b44db5d --- /dev/null +++ b/arch/arm64/include/asm/dma-mapping.h | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_DMA_MAPPING_H | ||
| 17 | #define __ASM_DMA_MAPPING_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/vmalloc.h> | ||
| 23 | |||
| 24 | #include <asm-generic/dma-coherent.h> | ||
| 25 | |||
| 26 | #define ARCH_HAS_DMA_GET_REQUIRED_MASK | ||
| 27 | |||
| 28 | extern struct dma_map_ops *dma_ops; | ||
| 29 | |||
| 30 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) | ||
| 31 | { | ||
| 32 | if (unlikely(!dev) || !dev->archdata.dma_ops) | ||
| 33 | return dma_ops; | ||
| 34 | else | ||
| 35 | return dev->archdata.dma_ops; | ||
| 36 | } | ||
| 37 | |||
| 38 | #include <asm-generic/dma-mapping-common.h> | ||
| 39 | |||
| 40 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | ||
| 41 | { | ||
| 42 | return (dma_addr_t)paddr; | ||
| 43 | } | ||
| 44 | |||
| 45 | static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) | ||
| 46 | { | ||
| 47 | return (phys_addr_t)dev_addr; | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr) | ||
| 51 | { | ||
| 52 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
| 53 | return ops->mapping_error(dev, dev_addr); | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline int dma_supported(struct device *dev, u64 mask) | ||
| 57 | { | ||
| 58 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
| 59 | return ops->dma_supported(dev, mask); | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline int dma_set_mask(struct device *dev, u64 mask) | ||
| 63 | { | ||
| 64 | if (!dev->dma_mask || !dma_supported(dev, mask)) | ||
| 65 | return -EIO; | ||
| 66 | *dev->dma_mask = mask; | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) | ||
| 72 | { | ||
| 73 | if (!dev->dma_mask) | ||
| 74 | return 0; | ||
| 75 | |||
| 76 | return addr + size - 1 <= *dev->dma_mask; | ||
| 77 | } | ||
| 78 | |||
| 79 | static inline void dma_mark_clean(void *addr, size_t size) | ||
| 80 | { | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, | ||
| 84 | dma_addr_t *dma_handle, gfp_t flags) | ||
| 85 | { | ||
| 86 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
| 87 | void *vaddr; | ||
| 88 | |||
| 89 | if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr)) | ||
| 90 | return vaddr; | ||
| 91 | |||
| 92 | vaddr = ops->alloc(dev, size, dma_handle, flags, NULL); | ||
| 93 | debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr); | ||
| 94 | return vaddr; | ||
| 95 | } | ||
| 96 | |||
| 97 | static inline void dma_free_coherent(struct device *dev, size_t size, | ||
| 98 | void *vaddr, dma_addr_t dev_addr) | ||
| 99 | { | ||
| 100 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
| 101 | |||
| 102 | if (dma_release_from_coherent(dev, get_order(size), vaddr)) | ||
| 103 | return; | ||
| 104 | |||
| 105 | debug_dma_free_coherent(dev, size, vaddr, dev_addr); | ||
| 106 | ops->free(dev, size, vaddr, dev_addr, NULL); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* | ||
| 110 | * There is no dma_cache_sync() implementation, so just return NULL here. | ||
| 111 | */ | ||
| 112 | static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, | ||
| 113 | dma_addr_t *handle, gfp_t flags) | ||
| 114 | { | ||
| 115 | return NULL; | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline void dma_free_noncoherent(struct device *dev, size_t size, | ||
| 119 | void *cpu_addr, dma_addr_t handle) | ||
| 120 | { | ||
| 121 | } | ||
| 122 | |||
| 123 | #endif /* __KERNEL__ */ | ||
| 124 | #endif /* __ASM_DMA_MAPPING_H */ | ||
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h new file mode 100644 index 000000000000..cf284649dfcb --- /dev/null +++ b/arch/arm64/include/asm/elf.h | |||
| @@ -0,0 +1,179 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_ELF_H | ||
| 17 | #define __ASM_ELF_H | ||
| 18 | |||
| 19 | #include <asm/hwcap.h> | ||
| 20 | |||
| 21 | /* | ||
| 22 | * ELF register definitions.. | ||
| 23 | */ | ||
| 24 | #include <asm/ptrace.h> | ||
| 25 | #include <asm/user.h> | ||
| 26 | |||
| 27 | typedef unsigned long elf_greg_t; | ||
| 28 | typedef unsigned long elf_freg_t[3]; | ||
| 29 | |||
| 30 | #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) | ||
| 31 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | ||
| 32 | |||
| 33 | typedef struct user_fp elf_fpregset_t; | ||
| 34 | |||
| 35 | #define EM_AARCH64 183 | ||
| 36 | |||
| 37 | /* | ||
| 38 | * AArch64 static relocation types. | ||
| 39 | */ | ||
| 40 | |||
| 41 | /* Miscellaneous. */ | ||
| 42 | #define R_ARM_NONE 0 | ||
| 43 | #define R_AARCH64_NONE 256 | ||
| 44 | |||
| 45 | /* Data. */ | ||
| 46 | #define R_AARCH64_ABS64 257 | ||
| 47 | #define R_AARCH64_ABS32 258 | ||
| 48 | #define R_AARCH64_ABS16 259 | ||
| 49 | #define R_AARCH64_PREL64 260 | ||
| 50 | #define R_AARCH64_PREL32 261 | ||
| 51 | #define R_AARCH64_PREL16 262 | ||
| 52 | |||
| 53 | /* Instructions. */ | ||
| 54 | #define R_AARCH64_MOVW_UABS_G0 263 | ||
| 55 | #define R_AARCH64_MOVW_UABS_G0_NC 264 | ||
| 56 | #define R_AARCH64_MOVW_UABS_G1 265 | ||
| 57 | #define R_AARCH64_MOVW_UABS_G1_NC 266 | ||
| 58 | #define R_AARCH64_MOVW_UABS_G2 267 | ||
| 59 | #define R_AARCH64_MOVW_UABS_G2_NC 268 | ||
| 60 | #define R_AARCH64_MOVW_UABS_G3 269 | ||
| 61 | |||
| 62 | #define R_AARCH64_MOVW_SABS_G0 270 | ||
| 63 | #define R_AARCH64_MOVW_SABS_G1 271 | ||
| 64 | #define R_AARCH64_MOVW_SABS_G2 272 | ||
| 65 | |||
| 66 | #define R_AARCH64_LD_PREL_LO19 273 | ||
| 67 | #define R_AARCH64_ADR_PREL_LO21 274 | ||
| 68 | #define R_AARCH64_ADR_PREL_PG_HI21 275 | ||
| 69 | #define R_AARCH64_ADR_PREL_PG_HI21_NC 276 | ||
| 70 | #define R_AARCH64_ADD_ABS_LO12_NC 277 | ||
| 71 | #define R_AARCH64_LDST8_ABS_LO12_NC 278 | ||
| 72 | |||
| 73 | #define R_AARCH64_TSTBR14 279 | ||
| 74 | #define R_AARCH64_CONDBR19 280 | ||
| 75 | #define R_AARCH64_JUMP26 282 | ||
| 76 | #define R_AARCH64_CALL26 283 | ||
| 77 | #define R_AARCH64_LDST16_ABS_LO12_NC 284 | ||
| 78 | #define R_AARCH64_LDST32_ABS_LO12_NC 285 | ||
| 79 | #define R_AARCH64_LDST64_ABS_LO12_NC 286 | ||
| 80 | #define R_AARCH64_LDST128_ABS_LO12_NC 299 | ||
| 81 | |||
| 82 | #define R_AARCH64_MOVW_PREL_G0 287 | ||
| 83 | #define R_AARCH64_MOVW_PREL_G0_NC 288 | ||
| 84 | #define R_AARCH64_MOVW_PREL_G1 289 | ||
| 85 | #define R_AARCH64_MOVW_PREL_G1_NC 290 | ||
| 86 | #define R_AARCH64_MOVW_PREL_G2 291 | ||
| 87 | #define R_AARCH64_MOVW_PREL_G2_NC 292 | ||
| 88 | #define R_AARCH64_MOVW_PREL_G3 293 | ||
| 89 | |||
| 90 | |||
| 91 | /* | ||
| 92 | * These are used to set parameters in the core dumps. | ||
| 93 | */ | ||
| 94 | #define ELF_CLASS ELFCLASS64 | ||
| 95 | #define ELF_DATA ELFDATA2LSB | ||
| 96 | #define ELF_ARCH EM_AARCH64 | ||
| 97 | |||
| 98 | #define ELF_PLATFORM_SIZE 16 | ||
| 99 | #define ELF_PLATFORM ("aarch64") | ||
| 100 | |||
| 101 | /* | ||
| 102 | * This is used to ensure we don't load something for the wrong architecture. | ||
| 103 | */ | ||
| 104 | #define elf_check_arch(x) ((x)->e_machine == EM_AARCH64) | ||
| 105 | |||
| 106 | #define elf_read_implies_exec(ex,stk) (stk != EXSTACK_DISABLE_X) | ||
| 107 | |||
| 108 | #define CORE_DUMP_USE_REGSET | ||
| 109 | #define ELF_EXEC_PAGESIZE PAGE_SIZE | ||
| 110 | |||
| 111 | /* | ||
| 112 | * This is the location that an ET_DYN program is loaded if exec'ed. Typical | ||
| 113 | * use of this is to invoke "./ld.so someprog" to test out a new version of | ||
| 114 | * the loader. We need to make sure that it is out of the way of the program | ||
| 115 | * that it will "exec", and that there is sufficient room for the brk. | ||
| 116 | */ | ||
| 117 | extern unsigned long randomize_et_dyn(unsigned long base); | ||
| 118 | #define ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_64 / 3)) | ||
| 119 | |||
| 120 | /* | ||
| 121 | * When the program starts, a1 contains a pointer to a function to be | ||
| 122 | * registered with atexit, as per the SVR4 ABI. A value of 0 means we have no | ||
| 123 | * such handler. | ||
| 124 | */ | ||
| 125 | #define ELF_PLAT_INIT(_r, load_addr) (_r)->regs[0] = 0 | ||
| 126 | |||
| 127 | #define SET_PERSONALITY(ex) clear_thread_flag(TIF_32BIT); | ||
| 128 | |||
| 129 | #define ARCH_DLINFO \ | ||
| 130 | do { \ | ||
| 131 | NEW_AUX_ENT(AT_SYSINFO_EHDR, \ | ||
| 132 | (elf_addr_t)current->mm->context.vdso); \ | ||
| 133 | } while (0) | ||
| 134 | |||
| 135 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES | ||
| 136 | struct linux_binprm; | ||
| 137 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
| 138 | int uses_interp); | ||
| 139 | |||
| 140 | /* 1GB of VA */ | ||
| 141 | #ifdef CONFIG_COMPAT | ||
| 142 | #define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \ | ||
| 143 | 0x7ff >> (PAGE_SHIFT - 12) : \ | ||
| 144 | 0x3ffff >> (PAGE_SHIFT - 12)) | ||
| 145 | #else | ||
| 146 | #define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) | ||
| 147 | #endif | ||
| 148 | |||
| 149 | struct mm_struct; | ||
| 150 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); | ||
| 151 | #define arch_randomize_brk arch_randomize_brk | ||
| 152 | |||
| 153 | #ifdef CONFIG_COMPAT | ||
| 154 | #define EM_ARM 40 | ||
| 155 | #define COMPAT_ELF_PLATFORM ("v8l") | ||
| 156 | |||
| 157 | #define COMPAT_ELF_ET_DYN_BASE (randomize_et_dyn(2 * TASK_SIZE_32 / 3)) | ||
| 158 | |||
| 159 | /* AArch32 registers. */ | ||
| 160 | #define COMPAT_ELF_NGREG 18 | ||
| 161 | typedef unsigned int compat_elf_greg_t; | ||
| 162 | typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; | ||
| 163 | |||
| 164 | /* AArch32 EABI. */ | ||
| 165 | #define EF_ARM_EABI_MASK 0xff000000 | ||
| 166 | #define compat_elf_check_arch(x) (((x)->e_machine == EM_ARM) && \ | ||
| 167 | ((x)->e_flags & EF_ARM_EABI_MASK)) | ||
| 168 | |||
| 169 | #define compat_start_thread compat_start_thread | ||
| 170 | #define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT); | ||
| 171 | #define COMPAT_ARCH_DLINFO | ||
| 172 | extern int aarch32_setup_vectors_page(struct linux_binprm *bprm, | ||
| 173 | int uses_interp); | ||
| 174 | #define compat_arch_setup_additional_pages \ | ||
| 175 | aarch32_setup_vectors_page | ||
| 176 | |||
| 177 | #endif /* CONFIG_COMPAT */ | ||
| 178 | |||
| 179 | #endif | ||
diff --git a/arch/arm64/include/asm/exception.h b/arch/arm64/include/asm/exception.h new file mode 100644 index 000000000000..ac63519b7b90 --- /dev/null +++ b/arch/arm64/include/asm/exception.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/exception.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_EXCEPTION_H | ||
| 19 | #define __ASM_EXCEPTION_H | ||
| 20 | |||
| 21 | #define __exception __attribute__((section(".exception.text"))) | ||
| 22 | |||
| 23 | #endif /* __ASM_EXCEPTION_H */ | ||
diff --git a/arch/arm64/include/asm/exec.h b/arch/arm64/include/asm/exec.h new file mode 100644 index 000000000000..db0563c23482 --- /dev/null +++ b/arch/arm64/include/asm/exec.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/exec.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_EXEC_H | ||
| 19 | #define __ASM_EXEC_H | ||
| 20 | |||
| 21 | extern unsigned long arch_align_stack(unsigned long sp); | ||
| 22 | |||
| 23 | #endif /* __ASM_EXEC_H */ | ||
diff --git a/arch/arm64/include/asm/fb.h b/arch/arm64/include/asm/fb.h new file mode 100644 index 000000000000..adb88a64b2fe --- /dev/null +++ b/arch/arm64/include/asm/fb.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_FB_H_ | ||
| 17 | #define __ASM_FB_H_ | ||
| 18 | |||
| 19 | #include <linux/fb.h> | ||
| 20 | #include <linux/fs.h> | ||
| 21 | #include <asm/page.h> | ||
| 22 | |||
| 23 | static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, | ||
| 24 | unsigned long off) | ||
| 25 | { | ||
| 26 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
| 27 | } | ||
| 28 | |||
| 29 | static inline int fb_is_primary_device(struct fb_info *info) | ||
| 30 | { | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | #endif /* __ASM_FB_H_ */ | ||
diff --git a/arch/arm64/include/asm/fcntl.h b/arch/arm64/include/asm/fcntl.h new file mode 100644 index 000000000000..cd2e630c235e --- /dev/null +++ b/arch/arm64/include/asm/fcntl.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_FCNTL_H | ||
| 17 | #define __ASM_FCNTL_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Using our own definitions for AArch32 (compat) support. | ||
| 21 | */ | ||
| 22 | #define O_DIRECTORY 040000 /* must be a directory */ | ||
| 23 | #define O_NOFOLLOW 0100000 /* don't follow links */ | ||
| 24 | #define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ | ||
| 25 | #define O_LARGEFILE 0400000 | ||
| 26 | |||
| 27 | #include <asm-generic/fcntl.h> | ||
| 28 | |||
| 29 | #endif | ||
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h new file mode 100644 index 000000000000..b42fab9f62a9 --- /dev/null +++ b/arch/arm64/include/asm/fpsimd.h | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_FP_H | ||
| 17 | #define __ASM_FP_H | ||
| 18 | |||
| 19 | #include <asm/ptrace.h> | ||
| 20 | |||
| 21 | #ifndef __ASSEMBLY__ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * FP/SIMD storage area has: | ||
| 25 | * - FPSR and FPCR | ||
| 26 | * - 32 128-bit data registers | ||
| 27 | * | ||
| 28 | * Note that user_fp forms a prefix of this structure, which is relied | ||
| 29 | * upon in the ptrace FP/SIMD accessors. struct user_fpsimd_state must | ||
| 30 | * form a prefix of struct fpsimd_state. | ||
| 31 | */ | ||
| 32 | struct fpsimd_state { | ||
| 33 | union { | ||
| 34 | struct user_fpsimd_state user_fpsimd; | ||
| 35 | struct { | ||
| 36 | __uint128_t vregs[32]; | ||
| 37 | u32 fpsr; | ||
| 38 | u32 fpcr; | ||
| 39 | }; | ||
| 40 | }; | ||
| 41 | }; | ||
| 42 | |||
| 43 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | ||
| 44 | /* Masks for extracting the FPSR and FPCR from the FPSCR */ | ||
| 45 | #define VFP_FPSCR_STAT_MASK 0xf800009f | ||
| 46 | #define VFP_FPSCR_CTRL_MASK 0x07f79f00 | ||
| 47 | /* | ||
| 48 | * The VFP state has 32x64-bit registers and a single 32-bit | ||
| 49 | * control/status register. | ||
| 50 | */ | ||
| 51 | #define VFP_STATE_SIZE ((32 * 8) + 4) | ||
| 52 | #endif | ||
| 53 | |||
| 54 | struct task_struct; | ||
| 55 | |||
| 56 | extern void fpsimd_save_state(struct fpsimd_state *state); | ||
| 57 | extern void fpsimd_load_state(struct fpsimd_state *state); | ||
| 58 | |||
| 59 | extern void fpsimd_thread_switch(struct task_struct *next); | ||
| 60 | extern void fpsimd_flush_thread(void); | ||
| 61 | |||
| 62 | #endif | ||
| 63 | |||
| 64 | #endif | ||
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h new file mode 100644 index 000000000000..3468ae8439fa --- /dev/null +++ b/arch/arm64/include/asm/futex.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_FUTEX_H | ||
| 17 | #define __ASM_FUTEX_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | #include <linux/futex.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include <asm/errno.h> | ||
| 24 | |||
| 25 | #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ | ||
| 26 | asm volatile( \ | ||
| 27 | "1: ldaxr %w1, %2\n" \ | ||
| 28 | insn "\n" \ | ||
| 29 | "2: stlxr %w3, %w0, %2\n" \ | ||
| 30 | " cbnz %w3, 1b\n" \ | ||
| 31 | "3:\n" \ | ||
| 32 | " .pushsection .fixup,\"ax\"\n" \ | ||
| 33 | "4: mov %w0, %w5\n" \ | ||
| 34 | " b 3b\n" \ | ||
| 35 | " .popsection\n" \ | ||
| 36 | " .pushsection __ex_table,\"a\"\n" \ | ||
| 37 | " .align 3\n" \ | ||
| 38 | " .quad 1b, 4b, 2b, 4b\n" \ | ||
| 39 | " .popsection\n" \ | ||
| 40 | : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ | ||
| 41 | : "r" (oparg), "Ir" (-EFAULT) \ | ||
| 42 | : "cc") | ||
| 43 | |||
| 44 | static inline int | ||
| 45 | futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | ||
| 46 | { | ||
| 47 | int op = (encoded_op >> 28) & 7; | ||
| 48 | int cmp = (encoded_op >> 24) & 15; | ||
| 49 | int oparg = (encoded_op << 8) >> 20; | ||
| 50 | int cmparg = (encoded_op << 20) >> 20; | ||
| 51 | int oldval = 0, ret, tmp; | ||
| 52 | |||
| 53 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | ||
| 54 | oparg = 1 << oparg; | ||
| 55 | |||
| 56 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
| 57 | return -EFAULT; | ||
| 58 | |||
| 59 | pagefault_disable(); /* implies preempt_disable() */ | ||
| 60 | |||
| 61 | switch (op) { | ||
| 62 | case FUTEX_OP_SET: | ||
| 63 | __futex_atomic_op("mov %w0, %w4", | ||
| 64 | ret, oldval, uaddr, tmp, oparg); | ||
| 65 | break; | ||
| 66 | case FUTEX_OP_ADD: | ||
| 67 | __futex_atomic_op("add %w0, %w1, %w4", | ||
| 68 | ret, oldval, uaddr, tmp, oparg); | ||
| 69 | break; | ||
| 70 | case FUTEX_OP_OR: | ||
| 71 | __futex_atomic_op("orr %w0, %w1, %w4", | ||
| 72 | ret, oldval, uaddr, tmp, oparg); | ||
| 73 | break; | ||
| 74 | case FUTEX_OP_ANDN: | ||
| 75 | __futex_atomic_op("and %w0, %w1, %w4", | ||
| 76 | ret, oldval, uaddr, tmp, ~oparg); | ||
| 77 | break; | ||
| 78 | case FUTEX_OP_XOR: | ||
| 79 | __futex_atomic_op("eor %w0, %w1, %w4", | ||
| 80 | ret, oldval, uaddr, tmp, oparg); | ||
| 81 | break; | ||
| 82 | default: | ||
| 83 | ret = -ENOSYS; | ||
| 84 | } | ||
| 85 | |||
| 86 | pagefault_enable(); /* subsumes preempt_enable() */ | ||
| 87 | |||
| 88 | if (!ret) { | ||
| 89 | switch (cmp) { | ||
| 90 | case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | ||
| 91 | case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | ||
| 92 | case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | ||
| 93 | case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | ||
| 94 | case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | ||
| 95 | case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | ||
| 96 | default: ret = -ENOSYS; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline int | ||
| 103 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | ||
| 104 | u32 oldval, u32 newval) | ||
| 105 | { | ||
| 106 | int ret = 0; | ||
| 107 | u32 val, tmp; | ||
| 108 | |||
| 109 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
| 110 | return -EFAULT; | ||
| 111 | |||
| 112 | asm volatile("// futex_atomic_cmpxchg_inatomic\n" | ||
| 113 | "1: ldaxr %w1, %2\n" | ||
| 114 | " sub %w3, %w1, %w4\n" | ||
| 115 | " cbnz %w3, 3f\n" | ||
| 116 | "2: stlxr %w3, %w5, %2\n" | ||
| 117 | " cbnz %w3, 1b\n" | ||
| 118 | "3:\n" | ||
| 119 | " .pushsection .fixup,\"ax\"\n" | ||
| 120 | "4: mov %w0, %w6\n" | ||
| 121 | " b 3b\n" | ||
| 122 | " .popsection\n" | ||
| 123 | " .pushsection __ex_table,\"a\"\n" | ||
| 124 | " .align 3\n" | ||
| 125 | " .quad 1b, 4b, 2b, 4b\n" | ||
| 126 | " .popsection\n" | ||
| 127 | : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp) | ||
| 128 | : "r" (oldval), "r" (newval), "Ir" (-EFAULT) | ||
| 129 | : "cc", "memory"); | ||
| 130 | |||
| 131 | *uval = val; | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | #endif /* __KERNEL__ */ | ||
| 136 | #endif /* __ASM_FUTEX_H */ | ||
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h new file mode 100644 index 000000000000..507546353d62 --- /dev/null +++ b/arch/arm64/include/asm/hardirq.h | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_HARDIRQ_H | ||
| 17 | #define __ASM_HARDIRQ_H | ||
| 18 | |||
| 19 | #include <linux/cache.h> | ||
| 20 | #include <linux/threads.h> | ||
| 21 | #include <asm/irq.h> | ||
| 22 | |||
| 23 | #define NR_IPI 4 | ||
| 24 | |||
| 25 | typedef struct { | ||
| 26 | unsigned int __softirq_pending; | ||
| 27 | #ifdef CONFIG_SMP | ||
| 28 | unsigned int ipi_irqs[NR_IPI]; | ||
| 29 | #endif | ||
| 30 | } ____cacheline_aligned irq_cpustat_t; | ||
| 31 | |||
| 32 | #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ | ||
| 33 | |||
| 34 | #define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ | ||
| 35 | #define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) | ||
| 36 | |||
| 37 | #ifdef CONFIG_SMP | ||
| 38 | u64 smp_irq_stat_cpu(unsigned int cpu); | ||
| 39 | #define arch_irq_stat_cpu smp_irq_stat_cpu | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 | ||
| 43 | |||
| 44 | static inline void ack_bad_irq(unsigned int irq) | ||
| 45 | { | ||
| 46 | extern unsigned long irq_err_count; | ||
| 47 | irq_err_count++; | ||
| 48 | } | ||
| 49 | |||
| 50 | extern void handle_IRQ(unsigned int, struct pt_regs *); | ||
| 51 | |||
| 52 | #endif /* __ASM_HARDIRQ_H */ | ||
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h new file mode 100644 index 000000000000..d064047612b1 --- /dev/null +++ b/arch/arm64/include/asm/hw_breakpoint.h | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_HW_BREAKPOINT_H | ||
| 17 | #define __ASM_HW_BREAKPOINT_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | struct arch_hw_breakpoint_ctrl { | ||
| 22 | u32 __reserved : 19, | ||
| 23 | len : 8, | ||
| 24 | type : 2, | ||
| 25 | privilege : 2, | ||
| 26 | enabled : 1; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct arch_hw_breakpoint { | ||
| 30 | u64 address; | ||
| 31 | u64 trigger; | ||
| 32 | struct arch_hw_breakpoint_ctrl ctrl; | ||
| 33 | }; | ||
| 34 | |||
| 35 | static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl) | ||
| 36 | { | ||
| 37 | return (ctrl.len << 5) | (ctrl.type << 3) | (ctrl.privilege << 1) | | ||
| 38 | ctrl.enabled; | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void decode_ctrl_reg(u32 reg, | ||
| 42 | struct arch_hw_breakpoint_ctrl *ctrl) | ||
| 43 | { | ||
| 44 | ctrl->enabled = reg & 0x1; | ||
| 45 | reg >>= 1; | ||
| 46 | ctrl->privilege = reg & 0x3; | ||
| 47 | reg >>= 2; | ||
| 48 | ctrl->type = reg & 0x3; | ||
| 49 | reg >>= 2; | ||
| 50 | ctrl->len = reg & 0xff; | ||
| 51 | } | ||
| 52 | |||
| 53 | /* Breakpoint */ | ||
| 54 | #define ARM_BREAKPOINT_EXECUTE 0 | ||
| 55 | |||
| 56 | /* Watchpoints */ | ||
| 57 | #define ARM_BREAKPOINT_LOAD 1 | ||
| 58 | #define ARM_BREAKPOINT_STORE 2 | ||
| 59 | #define AARCH64_ESR_ACCESS_MASK (1 << 6) | ||
| 60 | |||
| 61 | /* Privilege Levels */ | ||
| 62 | #define AARCH64_BREAKPOINT_EL1 1 | ||
| 63 | #define AARCH64_BREAKPOINT_EL0 2 | ||
| 64 | |||
| 65 | /* Lengths */ | ||
| 66 | #define ARM_BREAKPOINT_LEN_1 0x1 | ||
| 67 | #define ARM_BREAKPOINT_LEN_2 0x3 | ||
| 68 | #define ARM_BREAKPOINT_LEN_4 0xf | ||
| 69 | #define ARM_BREAKPOINT_LEN_8 0xff | ||
| 70 | |||
| 71 | /* Kernel stepping */ | ||
| 72 | #define ARM_KERNEL_STEP_NONE 0 | ||
| 73 | #define ARM_KERNEL_STEP_ACTIVE 1 | ||
| 74 | #define ARM_KERNEL_STEP_SUSPEND 2 | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Limits. | ||
| 78 | * Changing these will require modifications to the register accessors. | ||
| 79 | */ | ||
| 80 | #define ARM_MAX_BRP 16 | ||
| 81 | #define ARM_MAX_WRP 16 | ||
| 82 | #define ARM_MAX_HBP_SLOTS (ARM_MAX_BRP + ARM_MAX_WRP) | ||
| 83 | |||
| 84 | /* Virtual debug register bases. */ | ||
| 85 | #define AARCH64_DBG_REG_BVR 0 | ||
| 86 | #define AARCH64_DBG_REG_BCR (AARCH64_DBG_REG_BVR + ARM_MAX_BRP) | ||
| 87 | #define AARCH64_DBG_REG_WVR (AARCH64_DBG_REG_BCR + ARM_MAX_BRP) | ||
| 88 | #define AARCH64_DBG_REG_WCR (AARCH64_DBG_REG_WVR + ARM_MAX_WRP) | ||
| 89 | |||
| 90 | /* Debug register names. */ | ||
| 91 | #define AARCH64_DBG_REG_NAME_BVR "bvr" | ||
| 92 | #define AARCH64_DBG_REG_NAME_BCR "bcr" | ||
| 93 | #define AARCH64_DBG_REG_NAME_WVR "wvr" | ||
| 94 | #define AARCH64_DBG_REG_NAME_WCR "wcr" | ||
| 95 | |||
| 96 | /* Accessor macros for the debug registers. */ | ||
| 97 | #define AARCH64_DBG_READ(N, REG, VAL) do {\ | ||
| 98 | asm volatile("mrs %0, dbg" REG #N "_el1" : "=r" (VAL));\ | ||
| 99 | } while (0) | ||
| 100 | |||
| 101 | #define AARCH64_DBG_WRITE(N, REG, VAL) do {\ | ||
| 102 | asm volatile("msr dbg" REG #N "_el1, %0" :: "r" (VAL));\ | ||
| 103 | } while (0) | ||
| 104 | |||
| 105 | struct task_struct; | ||
| 106 | struct notifier_block; | ||
| 107 | struct perf_event; | ||
| 108 | struct pmu; | ||
| 109 | |||
| 110 | extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, | ||
| 111 | int *gen_len, int *gen_type); | ||
| 112 | extern int arch_check_bp_in_kernelspace(struct perf_event *bp); | ||
| 113 | extern int arch_validate_hwbkpt_settings(struct perf_event *bp); | ||
| 114 | extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | ||
| 115 | unsigned long val, void *data); | ||
| 116 | |||
| 117 | extern int arch_install_hw_breakpoint(struct perf_event *bp); | ||
| 118 | extern void arch_uninstall_hw_breakpoint(struct perf_event *bp); | ||
| 119 | extern void hw_breakpoint_pmu_read(struct perf_event *bp); | ||
| 120 | extern int hw_breakpoint_slots(int type); | ||
| 121 | |||
| 122 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 123 | extern void hw_breakpoint_thread_switch(struct task_struct *next); | ||
| 124 | extern void ptrace_hw_copy_thread(struct task_struct *task); | ||
| 125 | #else | ||
| 126 | static inline void hw_breakpoint_thread_switch(struct task_struct *next) | ||
| 127 | { | ||
| 128 | } | ||
| 129 | static inline void ptrace_hw_copy_thread(struct task_struct *task) | ||
| 130 | { | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | |||
| 134 | extern struct pmu perf_ops_bp; | ||
| 135 | |||
| 136 | #endif /* __KERNEL__ */ | ||
| 137 | #endif /* __ASM_BREAKPOINT_H */ | ||
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h new file mode 100644 index 000000000000..f8190ba45a3e --- /dev/null +++ b/arch/arm64/include/asm/hwcap.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_HWCAP_H | ||
| 17 | #define __ASM_HWCAP_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP | ||
| 21 | */ | ||
| 22 | #define HWCAP_FP (1 << 0) | ||
| 23 | #define HWCAP_ASIMD (1 << 1) | ||
| 24 | |||
| 25 | #define COMPAT_HWCAP_HALF (1 << 1) | ||
| 26 | #define COMPAT_HWCAP_THUMB (1 << 2) | ||
| 27 | #define COMPAT_HWCAP_FAST_MULT (1 << 4) | ||
| 28 | #define COMPAT_HWCAP_VFP (1 << 6) | ||
| 29 | #define COMPAT_HWCAP_EDSP (1 << 7) | ||
| 30 | #define COMPAT_HWCAP_NEON (1 << 12) | ||
| 31 | #define COMPAT_HWCAP_VFPv3 (1 << 13) | ||
| 32 | #define COMPAT_HWCAP_TLS (1 << 15) | ||
| 33 | #define COMPAT_HWCAP_VFPv4 (1 << 16) | ||
| 34 | #define COMPAT_HWCAP_IDIVA (1 << 17) | ||
| 35 | #define COMPAT_HWCAP_IDIVT (1 << 18) | ||
| 36 | #define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT) | ||
| 37 | |||
| 38 | #if defined(__KERNEL__) && !defined(__ASSEMBLY__) | ||
| 39 | /* | ||
| 40 | * This yields a mask that user programs can use to figure out what | ||
| 41 | * instruction set this cpu supports. | ||
| 42 | */ | ||
| 43 | #define ELF_HWCAP (elf_hwcap) | ||
| 44 | #define COMPAT_ELF_HWCAP (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ | ||
| 45 | COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\ | ||
| 46 | COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\ | ||
| 47 | COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\ | ||
| 48 | COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV) | ||
| 49 | |||
| 50 | extern unsigned int elf_hwcap; | ||
| 51 | #endif | ||
| 52 | |||
| 53 | #endif | ||
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h new file mode 100644 index 000000000000..74a2a7d304a9 --- /dev/null +++ b/arch/arm64/include/asm/io.h | |||
| @@ -0,0 +1,258 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/io.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1996-2000 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_IO_H | ||
| 20 | #define __ASM_IO_H | ||
| 21 | |||
| 22 | #ifdef __KERNEL__ | ||
| 23 | |||
| 24 | #include <linux/types.h> | ||
| 25 | |||
| 26 | #include <asm/byteorder.h> | ||
| 27 | #include <asm/barrier.h> | ||
| 28 | #include <asm/pgtable.h> | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Generic IO read/write. These perform native-endian accesses. | ||
| 32 | */ | ||
| 33 | static inline void __raw_writeb(u8 val, volatile void __iomem *addr) | ||
| 34 | { | ||
| 35 | asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr)); | ||
| 36 | } | ||
| 37 | |||
| 38 | static inline void __raw_writew(u16 val, volatile void __iomem *addr) | ||
| 39 | { | ||
| 40 | asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr)); | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline void __raw_writel(u32 val, volatile void __iomem *addr) | ||
| 44 | { | ||
| 45 | asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr)); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void __raw_writeq(u64 val, volatile void __iomem *addr) | ||
| 49 | { | ||
| 50 | asm volatile("str %0, [%1]" : : "r" (val), "r" (addr)); | ||
| 51 | } | ||
| 52 | |||
| 53 | static inline u8 __raw_readb(const volatile void __iomem *addr) | ||
| 54 | { | ||
| 55 | u8 val; | ||
| 56 | asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
| 57 | return val; | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline u16 __raw_readw(const volatile void __iomem *addr) | ||
| 61 | { | ||
| 62 | u16 val; | ||
| 63 | asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
| 64 | return val; | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline u32 __raw_readl(const volatile void __iomem *addr) | ||
| 68 | { | ||
| 69 | u32 val; | ||
| 70 | asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); | ||
| 71 | return val; | ||
| 72 | } | ||
| 73 | |||
| 74 | static inline u64 __raw_readq(const volatile void __iomem *addr) | ||
| 75 | { | ||
| 76 | u64 val; | ||
| 77 | asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); | ||
| 78 | return val; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* IO barriers */ | ||
| 82 | #define __iormb() rmb() | ||
| 83 | #define __iowmb() wmb() | ||
| 84 | |||
| 85 | #define mmiowb() do { } while (0) | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Relaxed I/O memory access primitives. These follow the Device memory | ||
| 89 | * ordering rules but do not guarantee any ordering relative to Normal memory | ||
| 90 | * accesses. | ||
| 91 | */ | ||
| 92 | #define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; }) | ||
| 93 | #define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; }) | ||
| 94 | #define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; }) | ||
| 95 | |||
| 96 | #define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c))) | ||
| 97 | #define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) | ||
| 98 | #define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) | ||
| 99 | |||
| 100 | /* | ||
| 101 | * I/O memory access primitives. Reads are ordered relative to any | ||
| 102 | * following Normal memory access. Writes are ordered relative to any prior | ||
| 103 | * Normal memory access. | ||
| 104 | */ | ||
| 105 | #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) | ||
| 106 | #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) | ||
| 107 | #define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) | ||
| 108 | |||
| 109 | #define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); }) | ||
| 110 | #define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); }) | ||
| 111 | #define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); }) | ||
| 112 | |||
| 113 | /* | ||
| 114 | * I/O port access primitives. | ||
| 115 | */ | ||
| 116 | #define IO_SPACE_LIMIT 0xffff | ||
| 117 | #define PCI_IOBASE ((void __iomem *)0xffffffbbfffe0000UL) | ||
| 118 | |||
| 119 | static inline u8 inb(unsigned long addr) | ||
| 120 | { | ||
| 121 | return readb(addr + PCI_IOBASE); | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline u16 inw(unsigned long addr) | ||
| 125 | { | ||
| 126 | return readw(addr + PCI_IOBASE); | ||
| 127 | } | ||
| 128 | |||
| 129 | static inline u32 inl(unsigned long addr) | ||
| 130 | { | ||
| 131 | return readl(addr + PCI_IOBASE); | ||
| 132 | } | ||
| 133 | |||
| 134 | static inline void outb(u8 b, unsigned long addr) | ||
| 135 | { | ||
| 136 | writeb(b, addr + PCI_IOBASE); | ||
| 137 | } | ||
| 138 | |||
| 139 | static inline void outw(u16 b, unsigned long addr) | ||
| 140 | { | ||
| 141 | writew(b, addr + PCI_IOBASE); | ||
| 142 | } | ||
| 143 | |||
| 144 | static inline void outl(u32 b, unsigned long addr) | ||
| 145 | { | ||
| 146 | writel(b, addr + PCI_IOBASE); | ||
| 147 | } | ||
| 148 | |||
| 149 | #define inb_p(addr) inb(addr) | ||
| 150 | #define inw_p(addr) inw(addr) | ||
| 151 | #define inl_p(addr) inl(addr) | ||
| 152 | |||
| 153 | #define outb_p(x, addr) outb((x), (addr)) | ||
| 154 | #define outw_p(x, addr) outw((x), (addr)) | ||
| 155 | #define outl_p(x, addr) outl((x), (addr)) | ||
| 156 | |||
| 157 | static inline void insb(unsigned long addr, void *buffer, int count) | ||
| 158 | { | ||
| 159 | u8 *buf = buffer; | ||
| 160 | while (count--) | ||
| 161 | *buf++ = __raw_readb(addr + PCI_IOBASE); | ||
| 162 | } | ||
| 163 | |||
| 164 | static inline void insw(unsigned long addr, void *buffer, int count) | ||
| 165 | { | ||
| 166 | u16 *buf = buffer; | ||
| 167 | while (count--) | ||
| 168 | *buf++ = __raw_readw(addr + PCI_IOBASE); | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline void insl(unsigned long addr, void *buffer, int count) | ||
| 172 | { | ||
| 173 | u32 *buf = buffer; | ||
| 174 | while (count--) | ||
| 175 | *buf++ = __raw_readl(addr + PCI_IOBASE); | ||
| 176 | } | ||
| 177 | |||
| 178 | static inline void outsb(unsigned long addr, const void *buffer, int count) | ||
| 179 | { | ||
| 180 | const u8 *buf = buffer; | ||
| 181 | while (count--) | ||
| 182 | __raw_writeb(*buf++, addr + PCI_IOBASE); | ||
| 183 | } | ||
| 184 | |||
| 185 | static inline void outsw(unsigned long addr, const void *buffer, int count) | ||
| 186 | { | ||
| 187 | const u16 *buf = buffer; | ||
| 188 | while (count--) | ||
| 189 | __raw_writew(*buf++, addr + PCI_IOBASE); | ||
| 190 | } | ||
| 191 | |||
| 192 | static inline void outsl(unsigned long addr, const void *buffer, int count) | ||
| 193 | { | ||
| 194 | const u32 *buf = buffer; | ||
| 195 | while (count--) | ||
| 196 | __raw_writel(*buf++, addr + PCI_IOBASE); | ||
| 197 | } | ||
| 198 | |||
| 199 | #define insb_p(port,to,len) insb(port,to,len) | ||
| 200 | #define insw_p(port,to,len) insw(port,to,len) | ||
| 201 | #define insl_p(port,to,len) insl(port,to,len) | ||
| 202 | |||
| 203 | #define outsb_p(port,from,len) outsb(port,from,len) | ||
| 204 | #define outsw_p(port,from,len) outsw(port,from,len) | ||
| 205 | #define outsl_p(port,from,len) outsl(port,from,len) | ||
| 206 | |||
| 207 | /* | ||
| 208 | * String version of I/O memory access operations. | ||
| 209 | */ | ||
| 210 | extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t); | ||
| 211 | extern void __memcpy_toio(volatile void __iomem *, const void *, size_t); | ||
| 212 | extern void __memset_io(volatile void __iomem *, int, size_t); | ||
| 213 | |||
| 214 | #define memset_io(c,v,l) __memset_io((c),(v),(l)) | ||
| 215 | #define memcpy_fromio(a,c,l) __memcpy_fromio((a),(c),(l)) | ||
| 216 | #define memcpy_toio(c,a,l) __memcpy_toio((c),(a),(l)) | ||
| 217 | |||
| 218 | /* | ||
| 219 | * I/O memory mapping functions. | ||
| 220 | */ | ||
| 221 | extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot); | ||
| 222 | extern void __iounmap(volatile void __iomem *addr); | ||
| 223 | |||
| 224 | #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY) | ||
| 225 | #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) | ||
| 226 | #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC)) | ||
| 227 | |||
| 228 | #define ioremap(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) | ||
| 229 | #define ioremap_nocache(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) | ||
| 230 | #define ioremap_wc(addr, size) __ioremap((addr), (size), PROT_NORMAL_NC) | ||
| 231 | #define iounmap __iounmap | ||
| 232 | |||
| 233 | #define ARCH_HAS_IOREMAP_WC | ||
| 234 | #include <asm-generic/iomap.h> | ||
| 235 | |||
| 236 | /* | ||
| 237 | * More restrictive address range checking than the default implementation | ||
| 238 | * (PHYS_OFFSET and PHYS_MASK taken into account). | ||
| 239 | */ | ||
| 240 | #define ARCH_HAS_VALID_PHYS_ADDR_RANGE | ||
| 241 | extern int valid_phys_addr_range(unsigned long addr, size_t size); | ||
| 242 | extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); | ||
| 243 | |||
| 244 | extern int devmem_is_allowed(unsigned long pfn); | ||
| 245 | |||
| 246 | /* | ||
| 247 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | ||
| 248 | * access | ||
| 249 | */ | ||
| 250 | #define xlate_dev_mem_ptr(p) __va(p) | ||
| 251 | |||
| 252 | /* | ||
| 253 | * Convert a virtual cached pointer to an uncached pointer | ||
| 254 | */ | ||
| 255 | #define xlate_dev_kmem_ptr(p) p | ||
| 256 | |||
| 257 | #endif /* __KERNEL__ */ | ||
| 258 | #endif /* __ASM_IO_H */ | ||
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h new file mode 100644 index 000000000000..a4e1cad3202a --- /dev/null +++ b/arch/arm64/include/asm/irq.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef __ASM_IRQ_H | ||
| 2 | #define __ASM_IRQ_H | ||
| 3 | |||
| 4 | #include <asm-generic/irq.h> | ||
| 5 | |||
| 6 | extern void (*handle_arch_irq)(struct pt_regs *); | ||
| 7 | |||
| 8 | #endif | ||
diff --git a/arch/arm64/include/asm/irqflags.h b/arch/arm64/include/asm/irqflags.h new file mode 100644 index 000000000000..aa11943b8502 --- /dev/null +++ b/arch/arm64/include/asm/irqflags.h | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_IRQFLAGS_H | ||
| 17 | #define __ASM_IRQFLAGS_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | #include <asm/ptrace.h> | ||
| 22 | |||
| 23 | /* | ||
| 24 | * CPU interrupt mask handling. | ||
| 25 | */ | ||
| 26 | static inline unsigned long arch_local_irq_save(void) | ||
| 27 | { | ||
| 28 | unsigned long flags; | ||
| 29 | asm volatile( | ||
| 30 | "mrs %0, daif // arch_local_irq_save\n" | ||
| 31 | "msr daifset, #2" | ||
| 32 | : "=r" (flags) | ||
| 33 | : | ||
| 34 | : "memory"); | ||
| 35 | return flags; | ||
| 36 | } | ||
| 37 | |||
| 38 | static inline void arch_local_irq_enable(void) | ||
| 39 | { | ||
| 40 | asm volatile( | ||
| 41 | "msr daifclr, #2 // arch_local_irq_enable" | ||
| 42 | : | ||
| 43 | : | ||
| 44 | : "memory"); | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline void arch_local_irq_disable(void) | ||
| 48 | { | ||
| 49 | asm volatile( | ||
| 50 | "msr daifset, #2 // arch_local_irq_disable" | ||
| 51 | : | ||
| 52 | : | ||
| 53 | : "memory"); | ||
| 54 | } | ||
| 55 | |||
| 56 | #define local_fiq_enable() asm("msr daifclr, #1" : : : "memory") | ||
| 57 | #define local_fiq_disable() asm("msr daifset, #1" : : : "memory") | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Save the current interrupt enable state. | ||
| 61 | */ | ||
| 62 | static inline unsigned long arch_local_save_flags(void) | ||
| 63 | { | ||
| 64 | unsigned long flags; | ||
| 65 | asm volatile( | ||
| 66 | "mrs %0, daif // arch_local_save_flags" | ||
| 67 | : "=r" (flags) | ||
| 68 | : | ||
| 69 | : "memory"); | ||
| 70 | return flags; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* | ||
| 74 | * restore saved IRQ state | ||
| 75 | */ | ||
| 76 | static inline void arch_local_irq_restore(unsigned long flags) | ||
| 77 | { | ||
| 78 | asm volatile( | ||
| 79 | "msr daif, %0 // arch_local_irq_restore" | ||
| 80 | : | ||
| 81 | : "r" (flags) | ||
| 82 | : "memory"); | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline int arch_irqs_disabled_flags(unsigned long flags) | ||
| 86 | { | ||
| 87 | return flags & PSR_I_BIT; | ||
| 88 | } | ||
| 89 | |||
| 90 | #endif | ||
| 91 | #endif | ||
diff --git a/arch/arm64/include/asm/memblock.h b/arch/arm64/include/asm/memblock.h new file mode 100644 index 000000000000..6afeed2467f1 --- /dev/null +++ b/arch/arm64/include/asm/memblock.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_MEMBLOCK_H | ||
| 17 | #define __ASM_MEMBLOCK_H | ||
| 18 | |||
| 19 | extern void arm64_memblock_init(void); | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h new file mode 100644 index 000000000000..1cac16a001cb --- /dev/null +++ b/arch/arm64/include/asm/memory.h | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/memory.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000-2002 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | * | ||
| 19 | * Note: this file should not be included by non-asm/.h files | ||
| 20 | */ | ||
| 21 | #ifndef __ASM_MEMORY_H | ||
| 22 | #define __ASM_MEMORY_H | ||
| 23 | |||
| 24 | #include <linux/compiler.h> | ||
| 25 | #include <linux/const.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | #include <asm/sizes.h> | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Allow for constants defined here to be used from assembly code | ||
| 31 | * by prepending the UL suffix only with actual C code compilation. | ||
| 32 | */ | ||
| 33 | #define UL(x) _AC(x, UL) | ||
| 34 | |||
| 35 | /* | ||
| 36 | * PAGE_OFFSET - the virtual address of the start of the kernel image. | ||
| 37 | * VA_BITS - the maximum number of bits for virtual addresses. | ||
| 38 | * TASK_SIZE - the maximum size of a user space task. | ||
| 39 | * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. | ||
| 40 | * The module space lives between the addresses given by TASK_SIZE | ||
| 41 | * and PAGE_OFFSET - it must be within 128MB of the kernel text. | ||
| 42 | */ | ||
| 43 | #define PAGE_OFFSET UL(0xffffffc000000000) | ||
| 44 | #define MODULES_END (PAGE_OFFSET) | ||
| 45 | #define MODULES_VADDR (MODULES_END - SZ_64M) | ||
| 46 | #define VA_BITS (39) | ||
| 47 | #define TASK_SIZE_64 (UL(1) << VA_BITS) | ||
| 48 | |||
| 49 | #ifdef CONFIG_COMPAT | ||
| 50 | #define TASK_SIZE_32 UL(0x100000000) | ||
| 51 | #define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ | ||
| 52 | TASK_SIZE_32 : TASK_SIZE_64) | ||
| 53 | #else | ||
| 54 | #define TASK_SIZE TASK_SIZE_64 | ||
| 55 | #endif /* CONFIG_COMPAT */ | ||
| 56 | |||
| 57 | #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4)) | ||
| 58 | |||
| 59 | #if TASK_SIZE_64 > MODULES_VADDR | ||
| 60 | #error Top of 64-bit user space clashes with start of module space | ||
| 61 | #endif | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Physical vs virtual RAM address space conversion. These are | ||
| 65 | * private definitions which should NOT be used outside memory.h | ||
| 66 | * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. | ||
| 67 | */ | ||
| 68 | #define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) | ||
| 69 | #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET)) | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Convert a physical address to a Page Frame Number and back | ||
| 73 | */ | ||
| 74 | #define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) | ||
| 75 | #define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT) | ||
| 76 | |||
| 77 | /* | ||
| 78 | * Convert a page to/from a physical address | ||
| 79 | */ | ||
| 80 | #define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page))) | ||
| 81 | #define phys_to_page(phys) (pfn_to_page(__phys_to_pfn(phys))) | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Memory types available. | ||
| 85 | */ | ||
| 86 | #define MT_DEVICE_nGnRnE 0 | ||
| 87 | #define MT_DEVICE_nGnRE 1 | ||
| 88 | #define MT_DEVICE_GRE 2 | ||
| 89 | #define MT_NORMAL_NC 3 | ||
| 90 | #define MT_NORMAL 4 | ||
| 91 | |||
| 92 | #ifndef __ASSEMBLY__ | ||
| 93 | |||
| 94 | extern phys_addr_t memstart_addr; | ||
| 95 | /* PHYS_OFFSET - the physical address of the start of memory. */ | ||
| 96 | #define PHYS_OFFSET ({ memstart_addr; }) | ||
| 97 | |||
| 98 | /* | ||
| 99 | * PFNs are used to describe any physical page; this means | ||
| 100 | * PFN 0 == physical address 0. | ||
| 101 | * | ||
| 102 | * This is the PFN of the first RAM page in the kernel | ||
| 103 | * direct-mapped view. We assume this is the first page | ||
| 104 | * of RAM in the mem_map as well. | ||
| 105 | */ | ||
| 106 | #define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) | ||
| 107 | |||
| 108 | /* | ||
| 109 | * Note: Drivers should NOT use these. They are the wrong | ||
| 110 | * translation for translating DMA addresses. Use the driver | ||
| 111 | * DMA support - see dma-mapping.h. | ||
| 112 | */ | ||
| 113 | static inline phys_addr_t virt_to_phys(const volatile void *x) | ||
| 114 | { | ||
| 115 | return __virt_to_phys((unsigned long)(x)); | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline void *phys_to_virt(phys_addr_t x) | ||
| 119 | { | ||
| 120 | return (void *)(__phys_to_virt(x)); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Drivers should NOT use these either. | ||
| 125 | */ | ||
| 126 | #define __pa(x) __virt_to_phys((unsigned long)(x)) | ||
| 127 | #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) | ||
| 128 | #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) | ||
| 129 | |||
| 130 | /* | ||
| 131 | * virt_to_page(k) convert a _valid_ virtual address to struct page * | ||
| 132 | * virt_addr_valid(k) indicates whether a virtual address is valid | ||
| 133 | */ | ||
| 134 | #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET | ||
| 135 | |||
| 136 | #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) | ||
| 137 | #define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ | ||
| 138 | ((void *)(kaddr) < (void *)high_memory)) | ||
| 139 | |||
| 140 | #endif | ||
| 141 | |||
| 142 | #include <asm-generic/memory_model.h> | ||
| 143 | |||
| 144 | #endif | ||
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h new file mode 100644 index 000000000000..d4f7fd5b9e33 --- /dev/null +++ b/arch/arm64/include/asm/mmu.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_MMU_H | ||
| 17 | #define __ASM_MMU_H | ||
| 18 | |||
| 19 | typedef struct { | ||
| 20 | unsigned int id; | ||
| 21 | raw_spinlock_t id_lock; | ||
| 22 | void *vdso; | ||
| 23 | } mm_context_t; | ||
| 24 | |||
| 25 | #define ASID(mm) ((mm)->context.id & 0xffff) | ||
| 26 | |||
| 27 | extern void paging_init(void); | ||
| 28 | extern void setup_mm_for_reboot(void); | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h new file mode 100644 index 000000000000..f68465dee026 --- /dev/null +++ b/arch/arm64/include/asm/mmu_context.h | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/mmu_context.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1996 Russell King. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_MMU_CONTEXT_H | ||
| 20 | #define __ASM_MMU_CONTEXT_H | ||
| 21 | |||
| 22 | #include <linux/compiler.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | |||
| 25 | #include <asm/cacheflush.h> | ||
| 26 | #include <asm/proc-fns.h> | ||
| 27 | #include <asm-generic/mm_hooks.h> | ||
| 28 | #include <asm/cputype.h> | ||
| 29 | #include <asm/pgtable.h> | ||
| 30 | |||
| 31 | #define MAX_ASID_BITS 16 | ||
| 32 | |||
| 33 | extern unsigned int cpu_last_asid; | ||
| 34 | |||
| 35 | void __init_new_context(struct task_struct *tsk, struct mm_struct *mm); | ||
| 36 | void __new_context(struct mm_struct *mm); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Set TTBR0 to empty_zero_page. No translations will be possible via TTBR0. | ||
| 40 | */ | ||
| 41 | static inline void cpu_set_reserved_ttbr0(void) | ||
| 42 | { | ||
| 43 | unsigned long ttbr = page_to_phys(empty_zero_page); | ||
| 44 | |||
| 45 | asm( | ||
| 46 | " msr ttbr0_el1, %0 // set TTBR0\n" | ||
| 47 | " isb" | ||
| 48 | : | ||
| 49 | : "r" (ttbr)); | ||
| 50 | } | ||
| 51 | |||
| 52 | static inline void switch_new_context(struct mm_struct *mm) | ||
| 53 | { | ||
| 54 | unsigned long flags; | ||
| 55 | |||
| 56 | __new_context(mm); | ||
| 57 | |||
| 58 | local_irq_save(flags); | ||
| 59 | cpu_switch_mm(mm->pgd, mm); | ||
| 60 | local_irq_restore(flags); | ||
| 61 | } | ||
| 62 | |||
| 63 | static inline void check_and_switch_context(struct mm_struct *mm, | ||
| 64 | struct task_struct *tsk) | ||
| 65 | { | ||
| 66 | /* | ||
| 67 | * Required during context switch to avoid speculative page table | ||
| 68 | * walking with the wrong TTBR. | ||
| 69 | */ | ||
| 70 | cpu_set_reserved_ttbr0(); | ||
| 71 | |||
| 72 | if (!((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS)) | ||
| 73 | /* | ||
| 74 | * The ASID is from the current generation, just switch to the | ||
| 75 | * new pgd. This condition is only true for calls from | ||
| 76 | * context_switch() and interrupts are already disabled. | ||
| 77 | */ | ||
| 78 | cpu_switch_mm(mm->pgd, mm); | ||
| 79 | else if (irqs_disabled()) | ||
| 80 | /* | ||
| 81 | * Defer the new ASID allocation until after the context | ||
| 82 | * switch critical region since __new_context() cannot be | ||
| 83 | * called with interrupts disabled. | ||
| 84 | */ | ||
| 85 | set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM); | ||
| 86 | else | ||
| 87 | /* | ||
| 88 | * That is a direct call to switch_mm() or activate_mm() with | ||
| 89 | * interrupts enabled and a new context. | ||
| 90 | */ | ||
| 91 | switch_new_context(mm); | ||
| 92 | } | ||
| 93 | |||
| 94 | #define init_new_context(tsk,mm) (__init_new_context(tsk,mm),0) | ||
| 95 | #define destroy_context(mm) do { } while(0) | ||
| 96 | |||
| 97 | #define finish_arch_post_lock_switch \ | ||
| 98 | finish_arch_post_lock_switch | ||
| 99 | static inline void finish_arch_post_lock_switch(void) | ||
| 100 | { | ||
| 101 | if (test_and_clear_thread_flag(TIF_SWITCH_MM)) { | ||
| 102 | struct mm_struct *mm = current->mm; | ||
| 103 | unsigned long flags; | ||
| 104 | |||
| 105 | __new_context(mm); | ||
| 106 | |||
| 107 | local_irq_save(flags); | ||
| 108 | cpu_switch_mm(mm->pgd, mm); | ||
| 109 | local_irq_restore(flags); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | /* | ||
| 114 | * This is called when "tsk" is about to enter lazy TLB mode. | ||
| 115 | * | ||
| 116 | * mm: describes the currently active mm context | ||
| 117 | * tsk: task which is entering lazy tlb | ||
| 118 | * cpu: cpu number which is entering lazy tlb | ||
| 119 | * | ||
| 120 | * tsk->mm will be NULL | ||
| 121 | */ | ||
| 122 | static inline void | ||
| 123 | enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | ||
| 124 | { | ||
| 125 | } | ||
| 126 | |||
| 127 | /* | ||
| 128 | * This is the actual mm switch as far as the scheduler | ||
| 129 | * is concerned. No registers are touched. We avoid | ||
| 130 | * calling the CPU specific function when the mm hasn't | ||
| 131 | * actually changed. | ||
| 132 | */ | ||
| 133 | static inline void | ||
| 134 | switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
| 135 | struct task_struct *tsk) | ||
| 136 | { | ||
| 137 | unsigned int cpu = smp_processor_id(); | ||
| 138 | |||
| 139 | #ifdef CONFIG_SMP | ||
| 140 | /* check for possible thread migration */ | ||
| 141 | if (!cpumask_empty(mm_cpumask(next)) && | ||
| 142 | !cpumask_test_cpu(cpu, mm_cpumask(next))) | ||
| 143 | __flush_icache_all(); | ||
| 144 | #endif | ||
| 145 | if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) | ||
| 146 | check_and_switch_context(next, tsk); | ||
| 147 | } | ||
| 148 | |||
| 149 | #define deactivate_mm(tsk,mm) do { } while (0) | ||
| 150 | #define activate_mm(prev,next) switch_mm(prev, next, NULL) | ||
| 151 | |||
| 152 | #endif | ||
diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/module.h new file mode 100644 index 000000000000..e80e232b730e --- /dev/null +++ b/arch/arm64/include/asm/module.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_MODULE_H | ||
| 17 | #define __ASM_MODULE_H | ||
| 18 | |||
| 19 | #include <asm-generic/module.h> | ||
| 20 | |||
| 21 | #define MODULE_ARCH_VERMAGIC "aarch64" | ||
| 22 | |||
| 23 | #endif /* __ASM_MODULE_H */ | ||
diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h new file mode 100644 index 000000000000..46bf66628b6a --- /dev/null +++ b/arch/arm64/include/asm/page.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/page.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2003 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_PAGE_H | ||
| 20 | #define __ASM_PAGE_H | ||
| 21 | |||
| 22 | /* PAGE_SHIFT determines the page size */ | ||
| 23 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 24 | #define PAGE_SHIFT 16 | ||
| 25 | #else | ||
| 26 | #define PAGE_SHIFT 12 | ||
| 27 | #endif | ||
| 28 | #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) | ||
| 29 | #define PAGE_MASK (~(PAGE_SIZE-1)) | ||
| 30 | |||
| 31 | /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */ | ||
| 32 | #define __HAVE_ARCH_GATE_AREA 1 | ||
| 33 | |||
| 34 | #ifndef __ASSEMBLY__ | ||
| 35 | |||
| 36 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 37 | #include <asm/pgtable-2level-types.h> | ||
| 38 | #else | ||
| 39 | #include <asm/pgtable-3level-types.h> | ||
| 40 | #endif | ||
| 41 | |||
| 42 | extern void __cpu_clear_user_page(void *p, unsigned long user); | ||
| 43 | extern void __cpu_copy_user_page(void *to, const void *from, | ||
| 44 | unsigned long user); | ||
| 45 | extern void copy_page(void *to, const void *from); | ||
| 46 | extern void clear_page(void *to); | ||
| 47 | |||
| 48 | #define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr) | ||
| 49 | #define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr) | ||
| 50 | |||
| 51 | typedef struct page *pgtable_t; | ||
| 52 | |||
| 53 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID | ||
| 54 | extern int pfn_valid(unsigned long); | ||
| 55 | #endif | ||
| 56 | |||
| 57 | #include <asm/memory.h> | ||
| 58 | |||
| 59 | #endif /* !__ASSEMBLY__ */ | ||
| 60 | |||
| 61 | #define VM_DATA_DEFAULT_FLAGS \ | ||
| 62 | (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ | ||
| 63 | VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | ||
| 64 | |||
| 65 | #include <asm-generic/getorder.h> | ||
| 66 | |||
| 67 | #endif | ||
diff --git a/arch/arm64/include/asm/param.h b/arch/arm64/include/asm/param.h new file mode 100644 index 000000000000..8e3a281d448a --- /dev/null +++ b/arch/arm64/include/asm/param.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PARAM_H | ||
| 17 | #define __ASM_PARAM_H | ||
| 18 | |||
| 19 | #define EXEC_PAGESIZE 65536 | ||
| 20 | |||
| 21 | #include <asm-generic/param.h> | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h new file mode 100644 index 000000000000..a6fffd511c5e --- /dev/null +++ b/arch/arm64/include/asm/perf_event.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __ASM_PERF_EVENT_H | ||
| 18 | #define __ASM_PERF_EVENT_H | ||
| 19 | |||
| 20 | /* It's quiet around here... */ | ||
| 21 | |||
| 22 | #endif | ||
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h new file mode 100644 index 000000000000..f214069ec5d5 --- /dev/null +++ b/arch/arm64/include/asm/pgalloc.h | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/pgalloc.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000-2001 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_PGALLOC_H | ||
| 20 | #define __ASM_PGALLOC_H | ||
| 21 | |||
| 22 | #include <asm/pgtable-hwdef.h> | ||
| 23 | #include <asm/processor.h> | ||
| 24 | #include <asm/cacheflush.h> | ||
| 25 | #include <asm/tlbflush.h> | ||
| 26 | |||
| 27 | #define check_pgt_cache() do { } while (0) | ||
| 28 | |||
| 29 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 30 | |||
| 31 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
| 32 | { | ||
| 33 | return (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT); | ||
| 34 | } | ||
| 35 | |||
| 36 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | ||
| 37 | { | ||
| 38 | BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); | ||
| 39 | free_page((unsigned long)pmd); | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | ||
| 43 | { | ||
| 44 | set_pud(pud, __pud(__pa(pmd) | PMD_TYPE_TABLE)); | ||
| 45 | } | ||
| 46 | |||
| 47 | #endif /* CONFIG_ARM64_64K_PAGES */ | ||
| 48 | |||
| 49 | extern pgd_t *pgd_alloc(struct mm_struct *mm); | ||
| 50 | extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); | ||
| 51 | |||
| 52 | #define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO) | ||
| 53 | |||
| 54 | static inline pte_t * | ||
| 55 | pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) | ||
| 56 | { | ||
| 57 | return (pte_t *)__get_free_page(PGALLOC_GFP); | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline pgtable_t | ||
| 61 | pte_alloc_one(struct mm_struct *mm, unsigned long addr) | ||
| 62 | { | ||
| 63 | struct page *pte; | ||
| 64 | |||
| 65 | pte = alloc_pages(PGALLOC_GFP, 0); | ||
| 66 | if (pte) | ||
| 67 | pgtable_page_ctor(pte); | ||
| 68 | |||
| 69 | return pte; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* | ||
| 73 | * Free a PTE table. | ||
| 74 | */ | ||
| 75 | static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) | ||
| 76 | { | ||
| 77 | if (pte) | ||
| 78 | free_page((unsigned long)pte); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline void pte_free(struct mm_struct *mm, pgtable_t pte) | ||
| 82 | { | ||
| 83 | pgtable_page_dtor(pte); | ||
| 84 | __free_page(pte); | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte, | ||
| 88 | pmdval_t prot) | ||
| 89 | { | ||
| 90 | set_pmd(pmdp, __pmd(pte | prot)); | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | ||
| 94 | * Populate the pmdp entry with a pointer to the pte. This pmd is part | ||
| 95 | * of the mm address space. | ||
| 96 | */ | ||
| 97 | static inline void | ||
| 98 | pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) | ||
| 99 | { | ||
| 100 | /* | ||
| 101 | * The pmd must be loaded with the physical address of the PTE table | ||
| 102 | */ | ||
| 103 | __pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE); | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline void | ||
| 107 | pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) | ||
| 108 | { | ||
| 109 | __pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE); | ||
| 110 | } | ||
| 111 | #define pmd_pgtable(pmd) pmd_page(pmd) | ||
| 112 | |||
| 113 | #endif | ||
diff --git a/arch/arm64/include/asm/pgtable-2level-hwdef.h b/arch/arm64/include/asm/pgtable-2level-hwdef.h new file mode 100644 index 000000000000..0a8ed3f94e93 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-2level-hwdef.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_2LEVEL_HWDEF_H | ||
| 17 | #define __ASM_PGTABLE_2LEVEL_HWDEF_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * With LPAE and 64KB pages, there are 2 levels of page tables. Each level has | ||
| 21 | * 8192 entries of 8 bytes each, occupying a 64KB page. Levels 0 and 1 are not | ||
| 22 | * used. The 2nd level table (PGD for Linux) can cover a range of 4TB, each | ||
| 23 | * entry representing 512MB. The user and kernel address spaces are limited to | ||
| 24 | * 512GB and therefore we only use 1024 entries in the PGD. | ||
| 25 | */ | ||
| 26 | #define PTRS_PER_PTE 8192 | ||
| 27 | #define PTRS_PER_PGD 1024 | ||
| 28 | |||
| 29 | /* | ||
| 30 | * PGDIR_SHIFT determines the size a top-level page table entry can map. | ||
| 31 | */ | ||
| 32 | #define PGDIR_SHIFT 29 | ||
| 33 | #define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) | ||
| 34 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) | ||
| 35 | |||
| 36 | /* | ||
| 37 | * section address mask and size definitions. | ||
| 38 | */ | ||
| 39 | #define SECTION_SHIFT 29 | ||
| 40 | #define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) | ||
| 41 | #define SECTION_MASK (~(SECTION_SIZE-1)) | ||
| 42 | |||
| 43 | #endif | ||
diff --git a/arch/arm64/include/asm/pgtable-2level-types.h b/arch/arm64/include/asm/pgtable-2level-types.h new file mode 100644 index 000000000000..3c3ca7d361e4 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-2level-types.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_2LEVEL_TYPES_H | ||
| 17 | #define __ASM_PGTABLE_2LEVEL_TYPES_H | ||
| 18 | |||
| 19 | typedef u64 pteval_t; | ||
| 20 | typedef u64 pgdval_t; | ||
| 21 | typedef pgdval_t pmdval_t; | ||
| 22 | |||
| 23 | #undef STRICT_MM_TYPECHECKS | ||
| 24 | |||
| 25 | #ifdef STRICT_MM_TYPECHECKS | ||
| 26 | |||
| 27 | /* | ||
| 28 | * These are used to make use of C type-checking.. | ||
| 29 | */ | ||
| 30 | typedef struct { pteval_t pte; } pte_t; | ||
| 31 | typedef struct { pgdval_t pgd; } pgd_t; | ||
| 32 | typedef struct { pteval_t pgprot; } pgprot_t; | ||
| 33 | |||
| 34 | #define pte_val(x) ((x).pte) | ||
| 35 | #define pgd_val(x) ((x).pgd) | ||
| 36 | #define pgprot_val(x) ((x).pgprot) | ||
| 37 | |||
| 38 | #define __pte(x) ((pte_t) { (x) } ) | ||
| 39 | #define __pgd(x) ((pgd_t) { (x) } ) | ||
| 40 | #define __pgprot(x) ((pgprot_t) { (x) } ) | ||
| 41 | |||
| 42 | #else /* !STRICT_MM_TYPECHECKS */ | ||
| 43 | |||
| 44 | typedef pteval_t pte_t; | ||
| 45 | typedef pgdval_t pgd_t; | ||
| 46 | typedef pteval_t pgprot_t; | ||
| 47 | |||
| 48 | #define pte_val(x) (x) | ||
| 49 | #define pgd_val(x) (x) | ||
| 50 | #define pgprot_val(x) (x) | ||
| 51 | |||
| 52 | #define __pte(x) (x) | ||
| 53 | #define __pgd(x) (x) | ||
| 54 | #define __pgprot(x) (x) | ||
| 55 | |||
| 56 | #endif /* STRICT_MM_TYPECHECKS */ | ||
| 57 | |||
| 58 | #include <asm-generic/pgtable-nopmd.h> | ||
| 59 | |||
| 60 | #endif /* __ASM_PGTABLE_2LEVEL_TYPES_H */ | ||
diff --git a/arch/arm64/include/asm/pgtable-3level-hwdef.h b/arch/arm64/include/asm/pgtable-3level-hwdef.h new file mode 100644 index 000000000000..3dbf941d7767 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-3level-hwdef.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_3LEVEL_HWDEF_H | ||
| 17 | #define __ASM_PGTABLE_3LEVEL_HWDEF_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * With LPAE and 4KB pages, there are 3 levels of page tables. Each level has | ||
| 21 | * 512 entries of 8 bytes each, occupying a 4K page. The first level table | ||
| 22 | * covers a range of 512GB, each entry representing 1GB. The user and kernel | ||
| 23 | * address spaces are limited to 512GB each. | ||
| 24 | */ | ||
| 25 | #define PTRS_PER_PTE 512 | ||
| 26 | #define PTRS_PER_PMD 512 | ||
| 27 | #define PTRS_PER_PGD 512 | ||
| 28 | |||
| 29 | /* | ||
| 30 | * PGDIR_SHIFT determines the size a top-level page table entry can map. | ||
| 31 | */ | ||
| 32 | #define PGDIR_SHIFT 30 | ||
| 33 | #define PGDIR_SIZE (_AC(1, UL) << PGDIR_SHIFT) | ||
| 34 | #define PGDIR_MASK (~(PGDIR_SIZE-1)) | ||
| 35 | |||
| 36 | /* | ||
| 37 | * PMD_SHIFT determines the size a middle-level page table entry can map. | ||
| 38 | */ | ||
| 39 | #define PMD_SHIFT 21 | ||
| 40 | #define PMD_SIZE (_AC(1, UL) << PMD_SHIFT) | ||
| 41 | #define PMD_MASK (~(PMD_SIZE-1)) | ||
| 42 | |||
| 43 | /* | ||
| 44 | * section address mask and size definitions. | ||
| 45 | */ | ||
| 46 | #define SECTION_SHIFT 21 | ||
| 47 | #define SECTION_SIZE (_AC(1, UL) << SECTION_SHIFT) | ||
| 48 | #define SECTION_MASK (~(SECTION_SIZE-1)) | ||
| 49 | |||
| 50 | #endif | ||
diff --git a/arch/arm64/include/asm/pgtable-3level-types.h b/arch/arm64/include/asm/pgtable-3level-types.h new file mode 100644 index 000000000000..4489615f14a9 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-3level-types.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_3LEVEL_TYPES_H | ||
| 17 | #define __ASM_PGTABLE_3LEVEL_TYPES_H | ||
| 18 | |||
| 19 | typedef u64 pteval_t; | ||
| 20 | typedef u64 pmdval_t; | ||
| 21 | typedef u64 pgdval_t; | ||
| 22 | |||
| 23 | #undef STRICT_MM_TYPECHECKS | ||
| 24 | |||
| 25 | #ifdef STRICT_MM_TYPECHECKS | ||
| 26 | |||
| 27 | /* | ||
| 28 | * These are used to make use of C type-checking.. | ||
| 29 | */ | ||
| 30 | typedef struct { pteval_t pte; } pte_t; | ||
| 31 | typedef struct { pmdval_t pmd; } pmd_t; | ||
| 32 | typedef struct { pgdval_t pgd; } pgd_t; | ||
| 33 | typedef struct { pteval_t pgprot; } pgprot_t; | ||
| 34 | |||
| 35 | #define pte_val(x) ((x).pte) | ||
| 36 | #define pmd_val(x) ((x).pmd) | ||
| 37 | #define pgd_val(x) ((x).pgd) | ||
| 38 | #define pgprot_val(x) ((x).pgprot) | ||
| 39 | |||
| 40 | #define __pte(x) ((pte_t) { (x) } ) | ||
| 41 | #define __pmd(x) ((pmd_t) { (x) } ) | ||
| 42 | #define __pgd(x) ((pgd_t) { (x) } ) | ||
| 43 | #define __pgprot(x) ((pgprot_t) { (x) } ) | ||
| 44 | |||
| 45 | #else /* !STRICT_MM_TYPECHECKS */ | ||
| 46 | |||
| 47 | typedef pteval_t pte_t; | ||
| 48 | typedef pmdval_t pmd_t; | ||
| 49 | typedef pgdval_t pgd_t; | ||
| 50 | typedef pteval_t pgprot_t; | ||
| 51 | |||
| 52 | #define pte_val(x) (x) | ||
| 53 | #define pmd_val(x) (x) | ||
| 54 | #define pgd_val(x) (x) | ||
| 55 | #define pgprot_val(x) (x) | ||
| 56 | |||
| 57 | #define __pte(x) (x) | ||
| 58 | #define __pmd(x) (x) | ||
| 59 | #define __pgd(x) (x) | ||
| 60 | #define __pgprot(x) (x) | ||
| 61 | |||
| 62 | #endif /* STRICT_MM_TYPECHECKS */ | ||
| 63 | |||
| 64 | #include <asm-generic/pgtable-nopud.h> | ||
| 65 | |||
| 66 | #endif /* __ASM_PGTABLE_3LEVEL_TYPES_H */ | ||
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h new file mode 100644 index 000000000000..0f3b4581d925 --- /dev/null +++ b/arch/arm64/include/asm/pgtable-hwdef.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_HWDEF_H | ||
| 17 | #define __ASM_PGTABLE_HWDEF_H | ||
| 18 | |||
| 19 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 20 | #include <asm/pgtable-2level-hwdef.h> | ||
| 21 | #else | ||
| 22 | #include <asm/pgtable-3level-hwdef.h> | ||
| 23 | #endif | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Hardware page table definitions. | ||
| 27 | * | ||
| 28 | * Level 2 descriptor (PMD). | ||
| 29 | */ | ||
| 30 | #define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0) | ||
| 31 | #define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0) | ||
| 32 | #define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0) | ||
| 33 | #define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0) | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Section | ||
| 37 | */ | ||
| 38 | #define PMD_SECT_S (_AT(pmdval_t, 3) << 8) | ||
| 39 | #define PMD_SECT_AF (_AT(pmdval_t, 1) << 10) | ||
| 40 | #define PMD_SECT_NG (_AT(pmdval_t, 1) << 11) | ||
| 41 | #define PMD_SECT_XN (_AT(pmdval_t, 1) << 54) | ||
| 42 | |||
| 43 | /* | ||
| 44 | * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). | ||
| 45 | */ | ||
| 46 | #define PMD_ATTRINDX(t) (_AT(pmdval_t, (t)) << 2) | ||
| 47 | #define PMD_ATTRINDX_MASK (_AT(pmdval_t, 7) << 2) | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Level 3 descriptor (PTE). | ||
| 51 | */ | ||
| 52 | #define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0) | ||
| 53 | #define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0) | ||
| 54 | #define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0) | ||
| 55 | #define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */ | ||
| 56 | #define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */ | ||
| 57 | #define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ | ||
| 58 | #define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ | ||
| 59 | #define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */ | ||
| 60 | #define PTE_XN (_AT(pteval_t, 1) << 54) /* XN */ | ||
| 61 | |||
| 62 | /* | ||
| 63 | * AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers). | ||
| 64 | */ | ||
| 65 | #define PTE_ATTRINDX(t) (_AT(pteval_t, (t)) << 2) | ||
| 66 | #define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2) | ||
| 67 | |||
| 68 | /* | ||
| 69 | * 40-bit physical address supported. | ||
| 70 | */ | ||
| 71 | #define PHYS_MASK_SHIFT (40) | ||
| 72 | #define PHYS_MASK ((UL(1) << PHYS_MASK_SHIFT) - 1) | ||
| 73 | |||
| 74 | /* | ||
| 75 | * TCR flags. | ||
| 76 | */ | ||
| 77 | #define TCR_TxSZ(x) (((UL(64) - (x)) << 16) | ((UL(64) - (x)) << 0)) | ||
| 78 | #define TCR_IRGN_NC ((UL(0) << 8) | (UL(0) << 24)) | ||
| 79 | #define TCR_IRGN_WBWA ((UL(1) << 8) | (UL(1) << 24)) | ||
| 80 | #define TCR_IRGN_WT ((UL(2) << 8) | (UL(2) << 24)) | ||
| 81 | #define TCR_IRGN_WBnWA ((UL(3) << 8) | (UL(3) << 24)) | ||
| 82 | #define TCR_IRGN_MASK ((UL(3) << 8) | (UL(3) << 24)) | ||
| 83 | #define TCR_ORGN_NC ((UL(0) << 10) | (UL(0) << 26)) | ||
| 84 | #define TCR_ORGN_WBWA ((UL(1) << 10) | (UL(1) << 26)) | ||
| 85 | #define TCR_ORGN_WT ((UL(2) << 10) | (UL(2) << 26)) | ||
| 86 | #define TCR_ORGN_WBnWA ((UL(3) << 10) | (UL(3) << 26)) | ||
| 87 | #define TCR_ORGN_MASK ((UL(3) << 10) | (UL(3) << 26)) | ||
| 88 | #define TCR_SHARED ((UL(3) << 12) | (UL(3) << 28)) | ||
| 89 | #define TCR_TG0_64K (UL(1) << 14) | ||
| 90 | #define TCR_TG1_64K (UL(1) << 30) | ||
| 91 | #define TCR_IPS_40BIT (UL(2) << 32) | ||
| 92 | #define TCR_ASID16 (UL(1) << 36) | ||
| 93 | |||
| 94 | #endif | ||
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h new file mode 100644 index 000000000000..8960239be722 --- /dev/null +++ b/arch/arm64/include/asm/pgtable.h | |||
| @@ -0,0 +1,328 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_PGTABLE_H | ||
| 17 | #define __ASM_PGTABLE_H | ||
| 18 | |||
| 19 | #include <asm/proc-fns.h> | ||
| 20 | |||
| 21 | #include <asm/memory.h> | ||
| 22 | #include <asm/pgtable-hwdef.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Software defined PTE bits definition. | ||
| 26 | */ | ||
| 27 | #define PTE_VALID (_AT(pteval_t, 1) << 0) /* pte_present() check */ | ||
| 28 | #define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */ | ||
| 29 | #define PTE_DIRTY (_AT(pteval_t, 1) << 55) | ||
| 30 | #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) | ||
| 31 | |||
| 32 | /* | ||
| 33 | * VMALLOC and SPARSEMEM_VMEMMAP ranges. | ||
| 34 | */ | ||
| 35 | #define VMALLOC_START UL(0xffffff8000000000) | ||
| 36 | #define VMALLOC_END (PAGE_OFFSET - UL(0x400000000) - SZ_64K) | ||
| 37 | |||
| 38 | #define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) | ||
| 39 | |||
| 40 | #define FIRST_USER_ADDRESS 0 | ||
| 41 | |||
| 42 | #ifndef __ASSEMBLY__ | ||
| 43 | extern void __pte_error(const char *file, int line, unsigned long val); | ||
| 44 | extern void __pmd_error(const char *file, int line, unsigned long val); | ||
| 45 | extern void __pgd_error(const char *file, int line, unsigned long val); | ||
| 46 | |||
| 47 | #define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) | ||
| 48 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 49 | #define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) | ||
| 50 | #endif | ||
| 51 | #define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) | ||
| 52 | |||
| 53 | /* | ||
| 54 | * The pgprot_* and protection_map entries will be fixed up at runtime to | ||
| 55 | * include the cachable and bufferable bits based on memory policy, as well as | ||
| 56 | * any architecture dependent bits like global/ASID and SMP shared mapping | ||
| 57 | * bits. | ||
| 58 | */ | ||
| 59 | #define _PAGE_DEFAULT PTE_TYPE_PAGE | PTE_AF | ||
| 60 | |||
| 61 | extern pgprot_t pgprot_default; | ||
| 62 | |||
| 63 | #define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b)) | ||
| 64 | |||
| 65 | #define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 66 | #define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN) | ||
| 67 | #define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG) | ||
| 68 | #define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 69 | #define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY) | ||
| 70 | #define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 71 | #define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY) | ||
| 72 | #define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_XN | PTE_DIRTY) | ||
| 73 | #define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_DIRTY) | ||
| 74 | |||
| 75 | #define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 76 | #define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN) | ||
| 77 | #define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG) | ||
| 78 | #define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 79 | #define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY) | ||
| 80 | #define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY) | ||
| 81 | #define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY) | ||
| 82 | |||
| 83 | #endif /* __ASSEMBLY__ */ | ||
| 84 | |||
| 85 | #define __P000 __PAGE_NONE | ||
| 86 | #define __P001 __PAGE_READONLY | ||
| 87 | #define __P010 __PAGE_COPY | ||
| 88 | #define __P011 __PAGE_COPY | ||
| 89 | #define __P100 __PAGE_READONLY_EXEC | ||
| 90 | #define __P101 __PAGE_READONLY_EXEC | ||
| 91 | #define __P110 __PAGE_COPY_EXEC | ||
| 92 | #define __P111 __PAGE_COPY_EXEC | ||
| 93 | |||
| 94 | #define __S000 __PAGE_NONE | ||
| 95 | #define __S001 __PAGE_READONLY | ||
| 96 | #define __S010 __PAGE_SHARED | ||
| 97 | #define __S011 __PAGE_SHARED | ||
| 98 | #define __S100 __PAGE_READONLY_EXEC | ||
| 99 | #define __S101 __PAGE_READONLY_EXEC | ||
| 100 | #define __S110 __PAGE_SHARED_EXEC | ||
| 101 | #define __S111 __PAGE_SHARED_EXEC | ||
| 102 | |||
| 103 | #ifndef __ASSEMBLY__ | ||
| 104 | /* | ||
| 105 | * ZERO_PAGE is a global shared page that is always zero: used | ||
| 106 | * for zero-mapped memory areas etc.. | ||
| 107 | */ | ||
| 108 | extern struct page *empty_zero_page; | ||
| 109 | #define ZERO_PAGE(vaddr) (empty_zero_page) | ||
| 110 | |||
| 111 | #define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT) | ||
| 112 | |||
| 113 | #define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) | ||
| 114 | |||
| 115 | #define pte_none(pte) (!pte_val(pte)) | ||
| 116 | #define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0)) | ||
| 117 | #define pte_page(pte) (pfn_to_page(pte_pfn(pte))) | ||
| 118 | #define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr)) | ||
| 119 | |||
| 120 | #define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr)) | ||
| 121 | #define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr)) | ||
| 122 | #define pte_unmap(pte) do { } while (0) | ||
| 123 | #define pte_unmap_nested(pte) do { } while (0) | ||
| 124 | |||
| 125 | /* | ||
| 126 | * The following only work if pte_present(). Undefined behaviour otherwise. | ||
| 127 | */ | ||
| 128 | #define pte_present(pte) (pte_val(pte) & PTE_VALID) | ||
| 129 | #define pte_dirty(pte) (pte_val(pte) & PTE_DIRTY) | ||
| 130 | #define pte_young(pte) (pte_val(pte) & PTE_AF) | ||
| 131 | #define pte_special(pte) (pte_val(pte) & PTE_SPECIAL) | ||
| 132 | #define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY)) | ||
| 133 | #define pte_exec(pte) (!(pte_val(pte) & PTE_XN)) | ||
| 134 | |||
| 135 | #define pte_present_exec_user(pte) \ | ||
| 136 | ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_XN)) == \ | ||
| 137 | (PTE_VALID | PTE_USER)) | ||
| 138 | |||
| 139 | #define PTE_BIT_FUNC(fn,op) \ | ||
| 140 | static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } | ||
| 141 | |||
| 142 | PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY); | ||
| 143 | PTE_BIT_FUNC(mkwrite, &= ~PTE_RDONLY); | ||
| 144 | PTE_BIT_FUNC(mkclean, &= ~PTE_DIRTY); | ||
| 145 | PTE_BIT_FUNC(mkdirty, |= PTE_DIRTY); | ||
| 146 | PTE_BIT_FUNC(mkold, &= ~PTE_AF); | ||
| 147 | PTE_BIT_FUNC(mkyoung, |= PTE_AF); | ||
| 148 | PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL); | ||
| 149 | |||
| 150 | static inline void set_pte(pte_t *ptep, pte_t pte) | ||
| 151 | { | ||
| 152 | *ptep = pte; | ||
| 153 | } | ||
| 154 | |||
| 155 | extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); | ||
| 156 | |||
| 157 | static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, | ||
| 158 | pte_t *ptep, pte_t pte) | ||
| 159 | { | ||
| 160 | if (pte_present_exec_user(pte)) | ||
| 161 | __sync_icache_dcache(pte, addr); | ||
| 162 | set_pte(ptep, pte); | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 166 | * Huge pte definitions. | ||
| 167 | */ | ||
| 168 | #define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE) | ||
| 169 | #define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE)) | ||
| 170 | |||
| 171 | #define __pgprot_modify(prot,mask,bits) \ | ||
| 172 | __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) | ||
| 173 | |||
| 174 | #define __HAVE_ARCH_PTE_SPECIAL | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Mark the prot value as uncacheable and unbufferable. | ||
| 178 | */ | ||
| 179 | #define pgprot_noncached(prot) \ | ||
| 180 | __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE)) | ||
| 181 | #define pgprot_writecombine(prot) \ | ||
| 182 | __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_GRE)) | ||
| 183 | #define pgprot_dmacoherent(prot) \ | ||
| 184 | __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC)) | ||
| 185 | #define __HAVE_PHYS_MEM_ACCESS_PROT | ||
| 186 | struct file; | ||
| 187 | extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | ||
| 188 | unsigned long size, pgprot_t vma_prot); | ||
| 189 | |||
| 190 | #define pmd_none(pmd) (!pmd_val(pmd)) | ||
| 191 | #define pmd_present(pmd) (pmd_val(pmd)) | ||
| 192 | |||
| 193 | #define pmd_bad(pmd) (!(pmd_val(pmd) & 2)) | ||
| 194 | |||
| 195 | static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) | ||
| 196 | { | ||
| 197 | *pmdp = pmd; | ||
| 198 | dsb(); | ||
| 199 | } | ||
| 200 | |||
| 201 | static inline void pmd_clear(pmd_t *pmdp) | ||
| 202 | { | ||
| 203 | set_pmd(pmdp, __pmd(0)); | ||
| 204 | } | ||
| 205 | |||
| 206 | static inline pte_t *pmd_page_vaddr(pmd_t pmd) | ||
| 207 | { | ||
| 208 | return __va(pmd_val(pmd) & PHYS_MASK & (s32)PAGE_MASK); | ||
| 209 | } | ||
| 210 | |||
| 211 | #define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK)) | ||
| 212 | |||
| 213 | /* | ||
| 214 | * Conversion functions: convert a page and protection to a page entry, | ||
| 215 | * and a page entry and page directory to the page they refer to. | ||
| 216 | */ | ||
| 217 | #define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) | ||
| 218 | |||
| 219 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 220 | |||
| 221 | #define pud_none(pud) (!pud_val(pud)) | ||
| 222 | #define pud_bad(pud) (!(pud_val(pud) & 2)) | ||
| 223 | #define pud_present(pud) (pud_val(pud)) | ||
| 224 | |||
| 225 | static inline void set_pud(pud_t *pudp, pud_t pud) | ||
| 226 | { | ||
| 227 | *pudp = pud; | ||
| 228 | dsb(); | ||
| 229 | } | ||
| 230 | |||
| 231 | static inline void pud_clear(pud_t *pudp) | ||
| 232 | { | ||
| 233 | set_pud(pudp, __pud(0)); | ||
| 234 | } | ||
| 235 | |||
| 236 | static inline pmd_t *pud_page_vaddr(pud_t pud) | ||
| 237 | { | ||
| 238 | return __va(pud_val(pud) & PHYS_MASK & (s32)PAGE_MASK); | ||
| 239 | } | ||
| 240 | |||
| 241 | #endif /* CONFIG_ARM64_64K_PAGES */ | ||
| 242 | |||
| 243 | /* to find an entry in a page-table-directory */ | ||
| 244 | #define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) | ||
| 245 | |||
| 246 | #define pgd_offset(mm, addr) ((mm)->pgd+pgd_index(addr)) | ||
| 247 | |||
| 248 | /* to find an entry in a kernel page-table-directory */ | ||
| 249 | #define pgd_offset_k(addr) pgd_offset(&init_mm, addr) | ||
| 250 | |||
| 251 | /* Find an entry in the second-level page table.. */ | ||
| 252 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 253 | #define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) | ||
| 254 | static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr) | ||
| 255 | { | ||
| 256 | return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr); | ||
| 257 | } | ||
| 258 | #endif | ||
| 259 | |||
| 260 | /* Find an entry in the third-level page table.. */ | ||
| 261 | #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) | ||
| 262 | |||
| 263 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | ||
| 264 | { | ||
| 265 | const pteval_t mask = PTE_USER | PTE_XN | PTE_RDONLY; | ||
| 266 | pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); | ||
| 267 | return pte; | ||
| 268 | } | ||
| 269 | |||
| 270 | extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; | ||
| 271 | extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; | ||
| 272 | |||
| 273 | #define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) | ||
| 274 | #define IDMAP_DIR_SIZE (2 * PAGE_SIZE) | ||
| 275 | |||
| 276 | /* | ||
| 277 | * Encode and decode a swap entry: | ||
| 278 | * bits 0-1: present (must be zero) | ||
| 279 | * bit 2: PTE_FILE | ||
| 280 | * bits 3-8: swap type | ||
| 281 | * bits 9-63: swap offset | ||
| 282 | */ | ||
| 283 | #define __SWP_TYPE_SHIFT 3 | ||
| 284 | #define __SWP_TYPE_BITS 6 | ||
| 285 | #define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) | ||
| 286 | #define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) | ||
| 287 | |||
| 288 | #define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) | ||
| 289 | #define __swp_offset(x) ((x).val >> __SWP_OFFSET_SHIFT) | ||
| 290 | #define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) }) | ||
| 291 | |||
| 292 | #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) | ||
| 293 | #define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Ensure that there are not more swap files than can be encoded in the kernel | ||
| 297 | * the PTEs. | ||
| 298 | */ | ||
| 299 | #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Encode and decode a file entry: | ||
| 303 | * bits 0-1: present (must be zero) | ||
| 304 | * bit 2: PTE_FILE | ||
| 305 | * bits 3-63: file offset / PAGE_SIZE | ||
| 306 | */ | ||
| 307 | #define pte_file(pte) (pte_val(pte) & PTE_FILE) | ||
| 308 | #define pte_to_pgoff(x) (pte_val(x) >> 3) | ||
| 309 | #define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE) | ||
| 310 | |||
| 311 | #define PTE_FILE_MAX_BITS 61 | ||
| 312 | |||
| 313 | extern int kern_addr_valid(unsigned long addr); | ||
| 314 | |||
| 315 | #include <asm-generic/pgtable.h> | ||
| 316 | |||
| 317 | /* | ||
| 318 | * remap a physical page `pfn' of size `size' with page protection `prot' | ||
| 319 | * into virtual address `from' | ||
| 320 | */ | ||
| 321 | #define io_remap_pfn_range(vma,from,pfn,size,prot) \ | ||
| 322 | remap_pfn_range(vma, from, pfn, size, prot) | ||
| 323 | |||
| 324 | #define pgtable_cache_init() do { } while (0) | ||
| 325 | |||
| 326 | #endif /* !__ASSEMBLY__ */ | ||
| 327 | |||
| 328 | #endif /* __ASM_PGTABLE_H */ | ||
diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h new file mode 100644 index 000000000000..e6f087806aaf --- /dev/null +++ b/arch/arm64/include/asm/pmu.h | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/pmu.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_PMU_H | ||
| 20 | #define __ASM_PMU_H | ||
| 21 | |||
| 22 | #ifdef CONFIG_HW_PERF_EVENTS | ||
| 23 | |||
| 24 | /* The events for a given PMU register set. */ | ||
| 25 | struct pmu_hw_events { | ||
| 26 | /* | ||
| 27 | * The events that are active on the PMU for the given index. | ||
| 28 | */ | ||
| 29 | struct perf_event **events; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * A 1 bit for an index indicates that the counter is being used for | ||
| 33 | * an event. A 0 means that the counter can be used. | ||
| 34 | */ | ||
| 35 | unsigned long *used_mask; | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Hardware lock to serialize accesses to PMU registers. Needed for the | ||
| 39 | * read/modify/write sequences. | ||
| 40 | */ | ||
| 41 | raw_spinlock_t pmu_lock; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct arm_pmu { | ||
| 45 | struct pmu pmu; | ||
| 46 | cpumask_t active_irqs; | ||
| 47 | const char *name; | ||
| 48 | irqreturn_t (*handle_irq)(int irq_num, void *dev); | ||
| 49 | void (*enable)(struct hw_perf_event *evt, int idx); | ||
| 50 | void (*disable)(struct hw_perf_event *evt, int idx); | ||
| 51 | int (*get_event_idx)(struct pmu_hw_events *hw_events, | ||
| 52 | struct hw_perf_event *hwc); | ||
| 53 | int (*set_event_filter)(struct hw_perf_event *evt, | ||
| 54 | struct perf_event_attr *attr); | ||
| 55 | u32 (*read_counter)(int idx); | ||
| 56 | void (*write_counter)(int idx, u32 val); | ||
| 57 | void (*start)(void); | ||
| 58 | void (*stop)(void); | ||
| 59 | void (*reset)(void *); | ||
| 60 | int (*map_event)(struct perf_event *event); | ||
| 61 | int num_events; | ||
| 62 | atomic_t active_events; | ||
| 63 | struct mutex reserve_mutex; | ||
| 64 | u64 max_period; | ||
| 65 | struct platform_device *plat_device; | ||
| 66 | struct pmu_hw_events *(*get_hw_events)(void); | ||
| 67 | }; | ||
| 68 | |||
| 69 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | ||
| 70 | |||
| 71 | int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type); | ||
| 72 | |||
| 73 | u64 armpmu_event_update(struct perf_event *event, | ||
| 74 | struct hw_perf_event *hwc, | ||
| 75 | int idx); | ||
| 76 | |||
| 77 | int armpmu_event_set_period(struct perf_event *event, | ||
| 78 | struct hw_perf_event *hwc, | ||
| 79 | int idx); | ||
| 80 | |||
| 81 | #endif /* CONFIG_HW_PERF_EVENTS */ | ||
| 82 | #endif /* __ASM_PMU_H */ | ||
diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h new file mode 100644 index 000000000000..7cdf466fd0c5 --- /dev/null +++ b/arch/arm64/include/asm/proc-fns.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/proc-fns.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1997-1999 Russell King | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | #ifndef __ASM_PROCFNS_H | ||
| 21 | #define __ASM_PROCFNS_H | ||
| 22 | |||
| 23 | #ifdef __KERNEL__ | ||
| 24 | #ifndef __ASSEMBLY__ | ||
| 25 | |||
| 26 | #include <asm/page.h> | ||
| 27 | |||
| 28 | struct mm_struct; | ||
| 29 | |||
| 30 | extern void cpu_cache_off(void); | ||
| 31 | extern void cpu_do_idle(void); | ||
| 32 | extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm); | ||
| 33 | extern void cpu_reset(unsigned long addr) __attribute__((noreturn)); | ||
| 34 | |||
| 35 | #include <asm/memory.h> | ||
| 36 | |||
| 37 | #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm) | ||
| 38 | |||
| 39 | #define cpu_get_pgd() \ | ||
| 40 | ({ \ | ||
| 41 | unsigned long pg; \ | ||
| 42 | asm("mrs %0, ttbr0_el1\n" \ | ||
| 43 | : "=r" (pg)); \ | ||
| 44 | pg &= ~0xffff000000003ffful; \ | ||
| 45 | (pgd_t *)phys_to_virt(pg); \ | ||
| 46 | }) | ||
| 47 | |||
| 48 | #endif /* __ASSEMBLY__ */ | ||
| 49 | #endif /* __KERNEL__ */ | ||
| 50 | #endif /* __ASM_PROCFNS_H */ | ||
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h new file mode 100644 index 000000000000..39a208a392f7 --- /dev/null +++ b/arch/arm64/include/asm/processor.h | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/processor.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-1999 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_PROCESSOR_H | ||
| 20 | #define __ASM_PROCESSOR_H | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Default implementation of macro that returns current | ||
| 24 | * instruction pointer ("program counter"). | ||
| 25 | */ | ||
| 26 | #define current_text_addr() ({ __label__ _l; _l: &&_l;}) | ||
| 27 | |||
| 28 | #ifdef __KERNEL__ | ||
| 29 | |||
| 30 | #include <linux/string.h> | ||
| 31 | |||
| 32 | #include <asm/fpsimd.h> | ||
| 33 | #include <asm/hw_breakpoint.h> | ||
| 34 | #include <asm/ptrace.h> | ||
| 35 | #include <asm/types.h> | ||
| 36 | |||
| 37 | #ifdef __KERNEL__ | ||
| 38 | #define STACK_TOP_MAX TASK_SIZE_64 | ||
| 39 | #ifdef CONFIG_COMPAT | ||
| 40 | #define AARCH32_VECTORS_BASE 0xffff0000 | ||
| 41 | #define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ | ||
| 42 | AARCH32_VECTORS_BASE : STACK_TOP_MAX) | ||
| 43 | #else | ||
| 44 | #define STACK_TOP STACK_TOP_MAX | ||
| 45 | #endif /* CONFIG_COMPAT */ | ||
| 46 | #endif /* __KERNEL__ */ | ||
| 47 | |||
| 48 | struct debug_info { | ||
| 49 | /* Have we suspended stepping by a debugger? */ | ||
| 50 | int suspended_step; | ||
| 51 | /* Allow breakpoints and watchpoints to be disabled for this thread. */ | ||
| 52 | int bps_disabled; | ||
| 53 | int wps_disabled; | ||
| 54 | /* Hardware breakpoints pinned to this task. */ | ||
| 55 | struct perf_event *hbp_break[ARM_MAX_BRP]; | ||
| 56 | struct perf_event *hbp_watch[ARM_MAX_WRP]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct cpu_context { | ||
| 60 | unsigned long x19; | ||
| 61 | unsigned long x20; | ||
| 62 | unsigned long x21; | ||
| 63 | unsigned long x22; | ||
| 64 | unsigned long x23; | ||
| 65 | unsigned long x24; | ||
| 66 | unsigned long x25; | ||
| 67 | unsigned long x26; | ||
| 68 | unsigned long x27; | ||
| 69 | unsigned long x28; | ||
| 70 | unsigned long fp; | ||
| 71 | unsigned long sp; | ||
| 72 | unsigned long pc; | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct thread_struct { | ||
| 76 | struct cpu_context cpu_context; /* cpu context */ | ||
| 77 | unsigned long tp_value; | ||
| 78 | struct fpsimd_state fpsimd_state; | ||
| 79 | unsigned long fault_address; /* fault info */ | ||
| 80 | struct debug_info debug; /* debugging */ | ||
| 81 | }; | ||
| 82 | |||
| 83 | #define INIT_THREAD { } | ||
| 84 | |||
| 85 | static inline void start_thread_common(struct pt_regs *regs, unsigned long pc) | ||
| 86 | { | ||
| 87 | memset(regs, 0, sizeof(*regs)); | ||
| 88 | regs->syscallno = ~0UL; | ||
| 89 | regs->pc = pc; | ||
| 90 | } | ||
| 91 | |||
| 92 | static inline void start_thread(struct pt_regs *regs, unsigned long pc, | ||
| 93 | unsigned long sp) | ||
| 94 | { | ||
| 95 | unsigned long *stack = (unsigned long *)sp; | ||
| 96 | |||
| 97 | start_thread_common(regs, pc); | ||
| 98 | regs->pstate = PSR_MODE_EL0t; | ||
| 99 | regs->sp = sp; | ||
| 100 | regs->regs[2] = stack[2]; /* x2 (envp) */ | ||
| 101 | regs->regs[1] = stack[1]; /* x1 (argv) */ | ||
| 102 | regs->regs[0] = stack[0]; /* x0 (argc) */ | ||
| 103 | } | ||
| 104 | |||
| 105 | #ifdef CONFIG_COMPAT | ||
| 106 | static inline void compat_start_thread(struct pt_regs *regs, unsigned long pc, | ||
| 107 | unsigned long sp) | ||
| 108 | { | ||
| 109 | unsigned int *stack = (unsigned int *)sp; | ||
| 110 | |||
| 111 | start_thread_common(regs, pc); | ||
| 112 | regs->pstate = COMPAT_PSR_MODE_USR; | ||
| 113 | if (pc & 1) | ||
| 114 | regs->pstate |= COMPAT_PSR_T_BIT; | ||
| 115 | regs->compat_sp = sp; | ||
| 116 | regs->regs[2] = stack[2]; /* x2 (envp) */ | ||
| 117 | regs->regs[1] = stack[1]; /* x1 (argv) */ | ||
| 118 | regs->regs[0] = stack[0]; /* x0 (argc) */ | ||
| 119 | } | ||
| 120 | #endif | ||
| 121 | |||
| 122 | /* Forward declaration, a strange C thing */ | ||
| 123 | struct task_struct; | ||
| 124 | |||
| 125 | /* Free all resources held by a thread. */ | ||
| 126 | extern void release_thread(struct task_struct *); | ||
| 127 | |||
| 128 | /* Prepare to copy thread state - unlazy all lazy status */ | ||
| 129 | #define prepare_to_copy(tsk) do { } while (0) | ||
| 130 | |||
| 131 | unsigned long get_wchan(struct task_struct *p); | ||
| 132 | |||
| 133 | #define cpu_relax() barrier() | ||
| 134 | |||
| 135 | /* Thread switching */ | ||
| 136 | extern struct task_struct *cpu_switch_to(struct task_struct *prev, | ||
| 137 | struct task_struct *next); | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Create a new kernel thread | ||
| 141 | */ | ||
| 142 | extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | ||
| 143 | |||
| 144 | #define task_pt_regs(p) \ | ||
| 145 | ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) | ||
| 146 | |||
| 147 | #define KSTK_EIP(tsk) task_pt_regs(tsk)->pc | ||
| 148 | #define KSTK_ESP(tsk) task_pt_regs(tsk)->sp | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Prefetching support | ||
| 152 | */ | ||
| 153 | #define ARCH_HAS_PREFETCH | ||
| 154 | static inline void prefetch(const void *ptr) | ||
| 155 | { | ||
| 156 | asm volatile("prfm pldl1keep, %a0\n" : : "p" (ptr)); | ||
| 157 | } | ||
| 158 | |||
| 159 | #define ARCH_HAS_PREFETCHW | ||
| 160 | static inline void prefetchw(const void *ptr) | ||
| 161 | { | ||
| 162 | asm volatile("prfm pstl1keep, %a0\n" : : "p" (ptr)); | ||
| 163 | } | ||
| 164 | |||
| 165 | #define ARCH_HAS_SPINLOCK_PREFETCH | ||
| 166 | static inline void spin_lock_prefetch(const void *x) | ||
| 167 | { | ||
| 168 | prefetchw(x); | ||
| 169 | } | ||
| 170 | |||
| 171 | #define HAVE_ARCH_PICK_MMAP_LAYOUT | ||
| 172 | |||
| 173 | #endif | ||
| 174 | |||
| 175 | #endif /* __ASM_PROCESSOR_H */ | ||
diff --git a/arch/arm64/include/asm/prom.h b/arch/arm64/include/asm/prom.h new file mode 100644 index 000000000000..68b90e682957 --- /dev/null +++ b/arch/arm64/include/asm/prom.h | |||
| @@ -0,0 +1 @@ | |||
| /* Empty for now */ | |||
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h new file mode 100644 index 000000000000..0fa5d6c9ef76 --- /dev/null +++ b/arch/arm64/include/asm/ptrace.h | |||
| @@ -0,0 +1,207 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/ptrace.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1996-2003 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_PTRACE_H | ||
| 20 | #define __ASM_PTRACE_H | ||
| 21 | |||
| 22 | #include <linux/types.h> | ||
| 23 | |||
| 24 | #include <asm/hwcap.h> | ||
| 25 | |||
| 26 | /* AArch32-specific ptrace requests */ | ||
| 27 | #define COMPAT_PTRACE_GETREGS 12 | ||
| 28 | #define COMPAT_PTRACE_SETREGS 13 | ||
| 29 | #define COMPAT_PTRACE_GET_THREAD_AREA 22 | ||
| 30 | #define COMPAT_PTRACE_SET_SYSCALL 23 | ||
| 31 | #define COMPAT_PTRACE_GETVFPREGS 27 | ||
| 32 | #define COMPAT_PTRACE_SETVFPREGS 28 | ||
| 33 | #define COMPAT_PTRACE_GETHBPREGS 29 | ||
| 34 | #define COMPAT_PTRACE_SETHBPREGS 30 | ||
| 35 | |||
| 36 | /* | ||
| 37 | * PSR bits | ||
| 38 | */ | ||
| 39 | #define PSR_MODE_EL0t 0x00000000 | ||
| 40 | #define PSR_MODE_EL1t 0x00000004 | ||
| 41 | #define PSR_MODE_EL1h 0x00000005 | ||
| 42 | #define PSR_MODE_EL2t 0x00000008 | ||
| 43 | #define PSR_MODE_EL2h 0x00000009 | ||
| 44 | #define PSR_MODE_EL3t 0x0000000c | ||
| 45 | #define PSR_MODE_EL3h 0x0000000d | ||
| 46 | #define PSR_MODE_MASK 0x0000000f | ||
| 47 | |||
| 48 | /* AArch32 CPSR bits */ | ||
| 49 | #define PSR_MODE32_BIT 0x00000010 | ||
| 50 | #define COMPAT_PSR_MODE_USR 0x00000010 | ||
| 51 | #define COMPAT_PSR_T_BIT 0x00000020 | ||
| 52 | #define COMPAT_PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ | ||
| 53 | |||
| 54 | /* AArch64 SPSR bits */ | ||
| 55 | #define PSR_F_BIT 0x00000040 | ||
| 56 | #define PSR_I_BIT 0x00000080 | ||
| 57 | #define PSR_A_BIT 0x00000100 | ||
| 58 | #define PSR_D_BIT 0x00000200 | ||
| 59 | #define PSR_Q_BIT 0x08000000 | ||
| 60 | #define PSR_V_BIT 0x10000000 | ||
| 61 | #define PSR_C_BIT 0x20000000 | ||
| 62 | #define PSR_Z_BIT 0x40000000 | ||
| 63 | #define PSR_N_BIT 0x80000000 | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Groups of PSR bits | ||
| 67 | */ | ||
| 68 | #define PSR_f 0xff000000 /* Flags */ | ||
| 69 | #define PSR_s 0x00ff0000 /* Status */ | ||
| 70 | #define PSR_x 0x0000ff00 /* Extension */ | ||
| 71 | #define PSR_c 0x000000ff /* Control */ | ||
| 72 | |||
| 73 | /* | ||
| 74 | * These are 'magic' values for PTRACE_PEEKUSR that return info about where a | ||
| 75 | * process is located in memory. | ||
| 76 | */ | ||
| 77 | #define PT_TEXT_ADDR 0x10000 | ||
| 78 | #define PT_DATA_ADDR 0x10004 | ||
| 79 | #define PT_TEXT_END_ADDR 0x10008 | ||
| 80 | |||
| 81 | #ifndef __ASSEMBLY__ | ||
| 82 | |||
| 83 | /* | ||
| 84 | * User structures for general purpose, floating point and debug registers. | ||
| 85 | */ | ||
| 86 | struct user_pt_regs { | ||
| 87 | __u64 regs[31]; | ||
| 88 | __u64 sp; | ||
| 89 | __u64 pc; | ||
| 90 | __u64 pstate; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct user_fpsimd_state { | ||
| 94 | __uint128_t vregs[32]; | ||
| 95 | __u32 fpsr; | ||
| 96 | __u32 fpcr; | ||
| 97 | }; | ||
| 98 | |||
| 99 | struct user_hwdebug_state { | ||
| 100 | __u32 dbg_info; | ||
| 101 | struct { | ||
| 102 | __u64 addr; | ||
| 103 | __u32 ctrl; | ||
| 104 | } dbg_regs[16]; | ||
| 105 | }; | ||
| 106 | |||
| 107 | #ifdef __KERNEL__ | ||
| 108 | |||
| 109 | /* sizeof(struct user) for AArch32 */ | ||
| 110 | #define COMPAT_USER_SZ 296 | ||
| 111 | /* AArch32 uses x13 as the stack pointer... */ | ||
| 112 | #define compat_sp regs[13] | ||
| 113 | /* ... and x14 as the link register. */ | ||
| 114 | #define compat_lr regs[14] | ||
| 115 | |||
| 116 | /* | ||
| 117 | * This struct defines the way the registers are stored on the stack during an | ||
| 118 | * exception. Note that sizeof(struct pt_regs) has to be a multiple of 16 (for | ||
| 119 | * stack alignment). struct user_pt_regs must form a prefix of struct pt_regs. | ||
| 120 | */ | ||
| 121 | struct pt_regs { | ||
| 122 | union { | ||
| 123 | struct user_pt_regs user_regs; | ||
| 124 | struct { | ||
| 125 | u64 regs[31]; | ||
| 126 | u64 sp; | ||
| 127 | u64 pc; | ||
| 128 | u64 pstate; | ||
| 129 | }; | ||
| 130 | }; | ||
| 131 | u64 orig_x0; | ||
| 132 | u64 syscallno; | ||
| 133 | }; | ||
| 134 | |||
| 135 | #define arch_has_single_step() (1) | ||
| 136 | |||
| 137 | #ifdef CONFIG_COMPAT | ||
| 138 | #define compat_thumb_mode(regs) \ | ||
| 139 | (((regs)->pstate & COMPAT_PSR_T_BIT)) | ||
| 140 | #else | ||
| 141 | #define compat_thumb_mode(regs) (0) | ||
| 142 | #endif | ||
| 143 | |||
| 144 | #define user_mode(regs) \ | ||
| 145 | (((regs)->pstate & PSR_MODE_MASK) == PSR_MODE_EL0t) | ||
| 146 | |||
| 147 | #define compat_user_mode(regs) \ | ||
| 148 | (((regs)->pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) == \ | ||
| 149 | (PSR_MODE32_BIT | PSR_MODE_EL0t)) | ||
| 150 | |||
| 151 | #define processor_mode(regs) \ | ||
| 152 | ((regs)->pstate & PSR_MODE_MASK) | ||
| 153 | |||
| 154 | #define interrupts_enabled(regs) \ | ||
| 155 | (!((regs)->pstate & PSR_I_BIT)) | ||
| 156 | |||
| 157 | #define fast_interrupts_enabled(regs) \ | ||
| 158 | (!((regs)->pstate & PSR_F_BIT)) | ||
| 159 | |||
| 160 | #define user_stack_pointer(regs) \ | ||
| 161 | ((regs)->sp) | ||
| 162 | |||
| 163 | /* | ||
| 164 | * Are the current registers suitable for user mode? (used to maintain | ||
| 165 | * security in signal handlers) | ||
| 166 | */ | ||
| 167 | static inline int valid_user_regs(struct user_pt_regs *regs) | ||
| 168 | { | ||
| 169 | if (user_mode(regs) && (regs->pstate & PSR_I_BIT) == 0) { | ||
| 170 | regs->pstate &= ~(PSR_F_BIT | PSR_A_BIT); | ||
| 171 | |||
| 172 | /* The T bit is reserved for AArch64 */ | ||
| 173 | if (!(regs->pstate & PSR_MODE32_BIT)) | ||
| 174 | regs->pstate &= ~COMPAT_PSR_T_BIT; | ||
| 175 | |||
| 176 | return 1; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * Force PSR to something logical... | ||
| 181 | */ | ||
| 182 | regs->pstate &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | \ | ||
| 183 | COMPAT_PSR_T_BIT | PSR_MODE32_BIT; | ||
| 184 | |||
| 185 | if (!(regs->pstate & PSR_MODE32_BIT)) { | ||
| 186 | regs->pstate &= ~COMPAT_PSR_T_BIT; | ||
| 187 | regs->pstate |= PSR_MODE_EL0t; | ||
| 188 | } | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | #define instruction_pointer(regs) (regs)->pc | ||
| 194 | |||
| 195 | #ifdef CONFIG_SMP | ||
| 196 | extern unsigned long profile_pc(struct pt_regs *regs); | ||
| 197 | #else | ||
| 198 | #define profile_pc(regs) instruction_pointer(regs) | ||
| 199 | #endif | ||
| 200 | |||
| 201 | extern int aarch32_break_trap(struct pt_regs *regs); | ||
| 202 | |||
| 203 | #endif /* __KERNEL__ */ | ||
| 204 | |||
| 205 | #endif /* __ASSEMBLY__ */ | ||
| 206 | |||
| 207 | #endif | ||
diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h new file mode 100644 index 000000000000..9cf2e46fbbdf --- /dev/null +++ b/arch/arm64/include/asm/setup.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/setup.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1997-1999 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_SETUP_H | ||
| 20 | #define __ASM_SETUP_H | ||
| 21 | |||
| 22 | #include <linux/types.h> | ||
| 23 | |||
| 24 | #define COMMAND_LINE_SIZE 2048 | ||
| 25 | |||
| 26 | #endif | ||
diff --git a/arch/arm64/include/asm/shmparam.h b/arch/arm64/include/asm/shmparam.h new file mode 100644 index 000000000000..4df608a8459e --- /dev/null +++ b/arch/arm64/include/asm/shmparam.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SHMPARAM_H | ||
| 17 | #define __ASM_SHMPARAM_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * For IPC syscalls from compat tasks, we need to use the legacy 16k | ||
| 21 | * alignment value. Since we don't have aliasing D-caches, the rest of | ||
| 22 | * the time we can safely use PAGE_SIZE. | ||
| 23 | */ | ||
| 24 | #define COMPAT_SHMLBA 0x4000 | ||
| 25 | |||
| 26 | #include <asm-generic/shmparam.h> | ||
| 27 | |||
| 28 | #endif /* __ASM_SHMPARAM_H */ | ||
diff --git a/arch/arm64/include/asm/sigcontext.h b/arch/arm64/include/asm/sigcontext.h new file mode 100644 index 000000000000..573cec778819 --- /dev/null +++ b/arch/arm64/include/asm/sigcontext.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SIGCONTEXT_H | ||
| 17 | #define __ASM_SIGCONTEXT_H | ||
| 18 | |||
| 19 | #include <linux/types.h> | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Signal context structure - contains all info to do with the state | ||
| 23 | * before the signal handler was invoked. | ||
| 24 | */ | ||
| 25 | struct sigcontext { | ||
| 26 | __u64 fault_address; | ||
| 27 | /* AArch64 registers */ | ||
| 28 | __u64 regs[31]; | ||
| 29 | __u64 sp; | ||
| 30 | __u64 pc; | ||
| 31 | __u64 pstate; | ||
| 32 | /* 4K reserved for FP/SIMD state and future expansion */ | ||
| 33 | __u8 __reserved[4096] __attribute__((__aligned__(16))); | ||
| 34 | }; | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Header to be used at the beginning of structures extending the user | ||
| 38 | * context. Such structures must be placed after the rt_sigframe on the stack | ||
| 39 | * and be 16-byte aligned. The last structure must be a dummy one with the | ||
| 40 | * magic and size set to 0. | ||
| 41 | */ | ||
| 42 | struct _aarch64_ctx { | ||
| 43 | __u32 magic; | ||
| 44 | __u32 size; | ||
| 45 | }; | ||
| 46 | |||
| 47 | #define FPSIMD_MAGIC 0x46508001 | ||
| 48 | |||
| 49 | struct fpsimd_context { | ||
| 50 | struct _aarch64_ctx head; | ||
| 51 | __u32 fpsr; | ||
| 52 | __u32 fpcr; | ||
| 53 | __uint128_t vregs[32]; | ||
| 54 | }; | ||
| 55 | |||
| 56 | #ifdef __KERNEL__ | ||
| 57 | /* | ||
| 58 | * Auxiliary context saved in the sigcontext.__reserved array. Not exported to | ||
| 59 | * user space as it will change with the addition of new context. User space | ||
| 60 | * should check the magic/size information. | ||
| 61 | */ | ||
| 62 | struct aux_context { | ||
| 63 | struct fpsimd_context fpsimd; | ||
| 64 | /* additional context to be added before "end" */ | ||
| 65 | struct _aarch64_ctx end; | ||
| 66 | }; | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #endif | ||
diff --git a/arch/arm64/include/asm/siginfo.h b/arch/arm64/include/asm/siginfo.h new file mode 100644 index 000000000000..5a74a0853db0 --- /dev/null +++ b/arch/arm64/include/asm/siginfo.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SIGINFO_H | ||
| 17 | #define __ASM_SIGINFO_H | ||
| 18 | |||
| 19 | #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) | ||
| 20 | |||
| 21 | #include <asm-generic/siginfo.h> | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/arch/arm64/include/asm/signal.h b/arch/arm64/include/asm/signal.h new file mode 100644 index 000000000000..8d1e7236431b --- /dev/null +++ b/arch/arm64/include/asm/signal.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SIGNAL_H | ||
| 17 | #define __ASM_SIGNAL_H | ||
| 18 | |||
| 19 | /* Required for AArch32 compatibility. */ | ||
| 20 | #define SA_RESTORER 0x04000000 | ||
| 21 | |||
| 22 | #include <asm-generic/signal.h> | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h new file mode 100644 index 000000000000..7c275e3b640f --- /dev/null +++ b/arch/arm64/include/asm/signal32.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SIGNAL32_H | ||
| 17 | #define __ASM_SIGNAL32_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | #ifdef CONFIG_COMPAT | ||
| 21 | #include <linux/compat.h> | ||
| 22 | |||
| 23 | #define AARCH32_KERN_SIGRET_CODE_OFFSET 0x500 | ||
| 24 | |||
| 25 | extern const compat_ulong_t aarch32_sigret_code[6]; | ||
| 26 | |||
| 27 | int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, | ||
| 28 | struct pt_regs *regs); | ||
| 29 | int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | ||
| 30 | sigset_t *set, struct pt_regs *regs); | ||
| 31 | |||
| 32 | void compat_setup_restart_syscall(struct pt_regs *regs); | ||
| 33 | #else | ||
| 34 | |||
| 35 | static inline int compat_setup_frame(int usid, struct k_sigaction *ka, | ||
| 36 | sigset_t *set, struct pt_regs *regs) | ||
| 37 | { | ||
| 38 | return -ENOSYS; | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline int compat_setup_rt_frame(int usig, struct k_sigaction *ka, | ||
| 42 | siginfo_t *info, sigset_t *set, | ||
| 43 | struct pt_regs *regs) | ||
| 44 | { | ||
| 45 | return -ENOSYS; | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void compat_setup_restart_syscall(struct pt_regs *regs) | ||
| 49 | { | ||
| 50 | } | ||
| 51 | #endif /* CONFIG_COMPAT */ | ||
| 52 | #endif /* __KERNEL__ */ | ||
| 53 | #endif /* __ASM_SIGNAL32_H */ | ||
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h new file mode 100644 index 000000000000..7e34295f78e3 --- /dev/null +++ b/arch/arm64/include/asm/smp.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SMP_H | ||
| 17 | #define __ASM_SMP_H | ||
| 18 | |||
| 19 | #include <linux/threads.h> | ||
| 20 | #include <linux/cpumask.h> | ||
| 21 | #include <linux/thread_info.h> | ||
| 22 | |||
| 23 | #ifndef CONFIG_SMP | ||
| 24 | # error "<asm/smp.h> included in non-SMP build" | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #define raw_smp_processor_id() (current_thread_info()->cpu) | ||
| 28 | |||
| 29 | struct seq_file; | ||
| 30 | |||
| 31 | /* | ||
| 32 | * generate IPI list text | ||
| 33 | */ | ||
| 34 | extern void show_ipi_list(struct seq_file *p, int prec); | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Called from C code, this handles an IPI. | ||
| 38 | */ | ||
| 39 | extern void handle_IPI(int ipinr, struct pt_regs *regs); | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Setup the set of possible CPUs (via set_cpu_possible) | ||
| 43 | */ | ||
| 44 | extern void smp_init_cpus(void); | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Provide a function to raise an IPI cross call on CPUs in callmap. | ||
| 48 | */ | ||
| 49 | extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int)); | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Called from the secondary holding pen, this is the secondary CPU entry point. | ||
| 53 | */ | ||
| 54 | asmlinkage void secondary_start_kernel(void); | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Initial data for bringing up a secondary CPU. | ||
| 58 | */ | ||
| 59 | struct secondary_data { | ||
| 60 | void *stack; | ||
| 61 | }; | ||
| 62 | extern struct secondary_data secondary_data; | ||
| 63 | extern void secondary_holding_pen(void); | ||
| 64 | extern volatile unsigned long secondary_holding_pen_release; | ||
| 65 | |||
| 66 | extern void arch_send_call_function_single_ipi(int cpu); | ||
| 67 | extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); | ||
| 68 | |||
| 69 | #endif /* ifndef __ASM_SMP_H */ | ||
diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h new file mode 100644 index 000000000000..1be62bcb9d47 --- /dev/null +++ b/arch/arm64/include/asm/sparsemem.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SPARSEMEM_H | ||
| 17 | #define __ASM_SPARSEMEM_H | ||
| 18 | |||
| 19 | #ifdef CONFIG_SPARSEMEM | ||
| 20 | #define MAX_PHYSMEM_BITS 40 | ||
| 21 | #define SECTION_SIZE_BITS 30 | ||
| 22 | #endif | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h new file mode 100644 index 000000000000..41112fe2f8b1 --- /dev/null +++ b/arch/arm64/include/asm/spinlock.h | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SPINLOCK_H | ||
| 17 | #define __ASM_SPINLOCK_H | ||
| 18 | |||
| 19 | #include <asm/spinlock_types.h> | ||
| 20 | #include <asm/processor.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Spinlock implementation. | ||
| 24 | * | ||
| 25 | * The old value is read exclusively and the new one, if unlocked, is written | ||
| 26 | * exclusively. In case of failure, the loop is restarted. | ||
| 27 | * | ||
| 28 | * The memory barriers are implicit with the load-acquire and store-release | ||
| 29 | * instructions. | ||
| 30 | * | ||
| 31 | * Unlocked value: 0 | ||
| 32 | * Locked value: 1 | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define arch_spin_is_locked(x) ((x)->lock != 0) | ||
| 36 | #define arch_spin_unlock_wait(lock) \ | ||
| 37 | do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) | ||
| 38 | |||
| 39 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) | ||
| 40 | |||
| 41 | static inline void arch_spin_lock(arch_spinlock_t *lock) | ||
| 42 | { | ||
| 43 | unsigned int tmp; | ||
| 44 | |||
| 45 | asm volatile( | ||
| 46 | " sevl\n" | ||
| 47 | "1: wfe\n" | ||
| 48 | "2: ldaxr %w0, [%1]\n" | ||
| 49 | " cbnz %w0, 1b\n" | ||
| 50 | " stxr %w0, %w2, [%1]\n" | ||
| 51 | " cbnz %w0, 2b\n" | ||
| 52 | : "=&r" (tmp) | ||
| 53 | : "r" (&lock->lock), "r" (1) | ||
| 54 | : "memory"); | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline int arch_spin_trylock(arch_spinlock_t *lock) | ||
| 58 | { | ||
| 59 | unsigned int tmp; | ||
| 60 | |||
| 61 | asm volatile( | ||
| 62 | " ldaxr %w0, [%1]\n" | ||
| 63 | " cbnz %w0, 1f\n" | ||
| 64 | " stxr %w0, %w2, [%1]\n" | ||
| 65 | "1:\n" | ||
| 66 | : "=&r" (tmp) | ||
| 67 | : "r" (&lock->lock), "r" (1) | ||
| 68 | : "memory"); | ||
| 69 | |||
| 70 | return !tmp; | ||
| 71 | } | ||
| 72 | |||
| 73 | static inline void arch_spin_unlock(arch_spinlock_t *lock) | ||
| 74 | { | ||
| 75 | asm volatile( | ||
| 76 | " stlr %w1, [%0]\n" | ||
| 77 | : : "r" (&lock->lock), "r" (0) : "memory"); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Write lock implementation. | ||
| 82 | * | ||
| 83 | * Write locks set bit 31. Unlocking, is done by writing 0 since the lock is | ||
| 84 | * exclusively held. | ||
| 85 | * | ||
| 86 | * The memory barriers are implicit with the load-acquire and store-release | ||
| 87 | * instructions. | ||
| 88 | */ | ||
| 89 | |||
| 90 | static inline void arch_write_lock(arch_rwlock_t *rw) | ||
| 91 | { | ||
| 92 | unsigned int tmp; | ||
| 93 | |||
| 94 | asm volatile( | ||
| 95 | " sevl\n" | ||
| 96 | "1: wfe\n" | ||
| 97 | "2: ldaxr %w0, [%1]\n" | ||
| 98 | " cbnz %w0, 1b\n" | ||
| 99 | " stxr %w0, %w2, [%1]\n" | ||
| 100 | " cbnz %w0, 2b\n" | ||
| 101 | : "=&r" (tmp) | ||
| 102 | : "r" (&rw->lock), "r" (0x80000000) | ||
| 103 | : "memory"); | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline int arch_write_trylock(arch_rwlock_t *rw) | ||
| 107 | { | ||
| 108 | unsigned int tmp; | ||
| 109 | |||
| 110 | asm volatile( | ||
| 111 | " ldaxr %w0, [%1]\n" | ||
| 112 | " cbnz %w0, 1f\n" | ||
| 113 | " stxr %w0, %w2, [%1]\n" | ||
| 114 | "1:\n" | ||
| 115 | : "=&r" (tmp) | ||
| 116 | : "r" (&rw->lock), "r" (0x80000000) | ||
| 117 | : "memory"); | ||
| 118 | |||
| 119 | return !tmp; | ||
| 120 | } | ||
| 121 | |||
| 122 | static inline void arch_write_unlock(arch_rwlock_t *rw) | ||
| 123 | { | ||
| 124 | asm volatile( | ||
| 125 | " stlr %w1, [%0]\n" | ||
| 126 | : : "r" (&rw->lock), "r" (0) : "memory"); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* write_can_lock - would write_trylock() succeed? */ | ||
| 130 | #define arch_write_can_lock(x) ((x)->lock == 0) | ||
| 131 | |||
| 132 | /* | ||
| 133 | * Read lock implementation. | ||
| 134 | * | ||
| 135 | * It exclusively loads the lock value, increments it and stores the new value | ||
| 136 | * back if positive and the CPU still exclusively owns the location. If the | ||
| 137 | * value is negative, the lock is already held. | ||
| 138 | * | ||
| 139 | * During unlocking there may be multiple active read locks but no write lock. | ||
| 140 | * | ||
| 141 | * The memory barriers are implicit with the load-acquire and store-release | ||
| 142 | * instructions. | ||
| 143 | */ | ||
| 144 | static inline void arch_read_lock(arch_rwlock_t *rw) | ||
| 145 | { | ||
| 146 | unsigned int tmp, tmp2; | ||
| 147 | |||
| 148 | asm volatile( | ||
| 149 | " sevl\n" | ||
| 150 | "1: wfe\n" | ||
| 151 | "2: ldaxr %w0, [%2]\n" | ||
| 152 | " add %w0, %w0, #1\n" | ||
| 153 | " tbnz %w0, #31, 1b\n" | ||
| 154 | " stxr %w1, %w0, [%2]\n" | ||
| 155 | " cbnz %w1, 2b\n" | ||
| 156 | : "=&r" (tmp), "=&r" (tmp2) | ||
| 157 | : "r" (&rw->lock) | ||
| 158 | : "memory"); | ||
| 159 | } | ||
| 160 | |||
| 161 | static inline void arch_read_unlock(arch_rwlock_t *rw) | ||
| 162 | { | ||
| 163 | unsigned int tmp, tmp2; | ||
| 164 | |||
| 165 | asm volatile( | ||
| 166 | "1: ldxr %w0, [%2]\n" | ||
| 167 | " sub %w0, %w0, #1\n" | ||
| 168 | " stlxr %w1, %w0, [%2]\n" | ||
| 169 | " cbnz %w1, 1b\n" | ||
| 170 | : "=&r" (tmp), "=&r" (tmp2) | ||
| 171 | : "r" (&rw->lock) | ||
| 172 | : "memory"); | ||
| 173 | } | ||
| 174 | |||
| 175 | static inline int arch_read_trylock(arch_rwlock_t *rw) | ||
| 176 | { | ||
| 177 | unsigned int tmp, tmp2 = 1; | ||
| 178 | |||
| 179 | asm volatile( | ||
| 180 | " ldaxr %w0, [%2]\n" | ||
| 181 | " add %w0, %w0, #1\n" | ||
| 182 | " tbnz %w0, #31, 1f\n" | ||
| 183 | " stxr %w1, %w0, [%2]\n" | ||
| 184 | "1:\n" | ||
| 185 | : "=&r" (tmp), "+r" (tmp2) | ||
| 186 | : "r" (&rw->lock) | ||
| 187 | : "memory"); | ||
| 188 | |||
| 189 | return !tmp2; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* read_can_lock - would read_trylock() succeed? */ | ||
| 193 | #define arch_read_can_lock(x) ((x)->lock < 0x80000000) | ||
| 194 | |||
| 195 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | ||
| 196 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | ||
| 197 | |||
| 198 | #define arch_spin_relax(lock) cpu_relax() | ||
| 199 | #define arch_read_relax(lock) cpu_relax() | ||
| 200 | #define arch_write_relax(lock) cpu_relax() | ||
| 201 | |||
| 202 | #endif /* __ASM_SPINLOCK_H */ | ||
diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h new file mode 100644 index 000000000000..9a494346efed --- /dev/null +++ b/arch/arm64/include/asm/spinlock_types.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SPINLOCK_TYPES_H | ||
| 17 | #define __ASM_SPINLOCK_TYPES_H | ||
| 18 | |||
| 19 | #if !defined(__LINUX_SPINLOCK_TYPES_H) && !defined(__ASM_SPINLOCK_H) | ||
| 20 | # error "please don't include this file directly" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | /* We only require natural alignment for exclusive accesses. */ | ||
| 24 | #define __lock_aligned | ||
| 25 | |||
| 26 | typedef struct { | ||
| 27 | volatile unsigned int lock; | ||
| 28 | } arch_spinlock_t; | ||
| 29 | |||
| 30 | #define __ARCH_SPIN_LOCK_UNLOCKED { 0 } | ||
| 31 | |||
| 32 | typedef struct { | ||
| 33 | volatile unsigned int lock; | ||
| 34 | } arch_rwlock_t; | ||
| 35 | |||
| 36 | #define __ARCH_RW_LOCK_UNLOCKED { 0 } | ||
| 37 | |||
| 38 | #endif | ||
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h new file mode 100644 index 000000000000..7318f6d54aa9 --- /dev/null +++ b/arch/arm64/include/asm/stacktrace.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_STACKTRACE_H | ||
| 17 | #define __ASM_STACKTRACE_H | ||
| 18 | |||
| 19 | struct stackframe { | ||
| 20 | unsigned long fp; | ||
| 21 | unsigned long sp; | ||
| 22 | unsigned long pc; | ||
| 23 | }; | ||
| 24 | |||
| 25 | extern int unwind_frame(struct stackframe *frame); | ||
| 26 | extern void walk_stackframe(struct stackframe *frame, | ||
| 27 | int (*fn)(struct stackframe *, void *), void *data); | ||
| 28 | |||
| 29 | #endif /* __ASM_STACKTRACE_H */ | ||
diff --git a/arch/arm64/include/asm/stat.h b/arch/arm64/include/asm/stat.h new file mode 100644 index 000000000000..d87225cbead8 --- /dev/null +++ b/arch/arm64/include/asm/stat.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_STAT_H | ||
| 17 | #define __ASM_STAT_H | ||
| 18 | |||
| 19 | #include <asm-generic/stat.h> | ||
| 20 | |||
| 21 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | ||
| 22 | |||
| 23 | #include <asm/compat.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * struct stat64 is needed for compat tasks only. Its definition is different | ||
| 27 | * from the generic struct stat64. | ||
| 28 | */ | ||
| 29 | struct stat64 { | ||
| 30 | compat_u64 st_dev; | ||
| 31 | unsigned char __pad0[4]; | ||
| 32 | |||
| 33 | #define STAT64_HAS_BROKEN_ST_INO 1 | ||
| 34 | compat_ulong_t __st_ino; | ||
| 35 | compat_uint_t st_mode; | ||
| 36 | compat_uint_t st_nlink; | ||
| 37 | |||
| 38 | compat_ulong_t st_uid; | ||
| 39 | compat_ulong_t st_gid; | ||
| 40 | |||
| 41 | compat_u64 st_rdev; | ||
| 42 | unsigned char __pad3[4]; | ||
| 43 | |||
| 44 | compat_s64 st_size; | ||
| 45 | compat_ulong_t st_blksize; | ||
| 46 | compat_u64 st_blocks; /* Number of 512-byte blocks allocated. */ | ||
| 47 | |||
| 48 | compat_ulong_t st_atime; | ||
| 49 | compat_ulong_t st_atime_nsec; | ||
| 50 | |||
| 51 | compat_ulong_t st_mtime; | ||
| 52 | compat_ulong_t st_mtime_nsec; | ||
| 53 | |||
| 54 | compat_ulong_t st_ctime; | ||
| 55 | compat_ulong_t st_ctime_nsec; | ||
| 56 | |||
| 57 | compat_u64 st_ino; | ||
| 58 | }; | ||
| 59 | |||
| 60 | #endif | ||
| 61 | |||
| 62 | #endif | ||
diff --git a/arch/arm64/include/asm/statfs.h b/arch/arm64/include/asm/statfs.h new file mode 100644 index 000000000000..6f6219050978 --- /dev/null +++ b/arch/arm64/include/asm/statfs.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_STATFS_H | ||
| 17 | #define __ASM_STATFS_H | ||
| 18 | |||
| 19 | #define ARCH_PACK_COMPAT_STATFS64 __attribute__((packed,aligned(4))) | ||
| 20 | |||
| 21 | #include <asm-generic/statfs.h> | ||
| 22 | |||
| 23 | #endif | ||
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h new file mode 100644 index 000000000000..89c047f9a971 --- /dev/null +++ b/arch/arm64/include/asm/syscall.h | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SYSCALL_H | ||
| 17 | #define __ASM_SYSCALL_H | ||
| 18 | |||
| 19 | #include <linux/err.h> | ||
| 20 | |||
| 21 | |||
| 22 | static inline int syscall_get_nr(struct task_struct *task, | ||
| 23 | struct pt_regs *regs) | ||
| 24 | { | ||
| 25 | return regs->syscallno; | ||
| 26 | } | ||
| 27 | |||
| 28 | static inline void syscall_rollback(struct task_struct *task, | ||
| 29 | struct pt_regs *regs) | ||
| 30 | { | ||
| 31 | regs->regs[0] = regs->orig_x0; | ||
| 32 | } | ||
| 33 | |||
| 34 | |||
| 35 | static inline long syscall_get_error(struct task_struct *task, | ||
| 36 | struct pt_regs *regs) | ||
| 37 | { | ||
| 38 | unsigned long error = regs->regs[0]; | ||
| 39 | return IS_ERR_VALUE(error) ? error : 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline long syscall_get_return_value(struct task_struct *task, | ||
| 43 | struct pt_regs *regs) | ||
| 44 | { | ||
| 45 | return regs->regs[0]; | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void syscall_set_return_value(struct task_struct *task, | ||
| 49 | struct pt_regs *regs, | ||
| 50 | int error, long val) | ||
| 51 | { | ||
| 52 | regs->regs[0] = (long) error ? error : val; | ||
| 53 | } | ||
| 54 | |||
| 55 | #define SYSCALL_MAX_ARGS 6 | ||
| 56 | |||
| 57 | static inline void syscall_get_arguments(struct task_struct *task, | ||
| 58 | struct pt_regs *regs, | ||
| 59 | unsigned int i, unsigned int n, | ||
| 60 | unsigned long *args) | ||
| 61 | { | ||
| 62 | if (i + n > SYSCALL_MAX_ARGS) { | ||
| 63 | unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; | ||
| 64 | unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; | ||
| 65 | pr_warning("%s called with max args %d, handling only %d\n", | ||
| 66 | __func__, i + n, SYSCALL_MAX_ARGS); | ||
| 67 | memset(args_bad, 0, n_bad * sizeof(args[0])); | ||
| 68 | } | ||
| 69 | |||
| 70 | if (i == 0) { | ||
| 71 | args[0] = regs->orig_x0; | ||
| 72 | args++; | ||
| 73 | i++; | ||
| 74 | n--; | ||
| 75 | } | ||
| 76 | |||
| 77 | memcpy(args, ®s->regs[i], n * sizeof(args[0])); | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void syscall_set_arguments(struct task_struct *task, | ||
| 81 | struct pt_regs *regs, | ||
| 82 | unsigned int i, unsigned int n, | ||
| 83 | const unsigned long *args) | ||
| 84 | { | ||
| 85 | if (i + n > SYSCALL_MAX_ARGS) { | ||
| 86 | pr_warning("%s called with max args %d, handling only %d\n", | ||
| 87 | __func__, i + n, SYSCALL_MAX_ARGS); | ||
| 88 | n = SYSCALL_MAX_ARGS - i; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (i == 0) { | ||
| 92 | regs->orig_x0 = args[0]; | ||
| 93 | args++; | ||
| 94 | i++; | ||
| 95 | n--; | ||
| 96 | } | ||
| 97 | |||
| 98 | memcpy(®s->regs[i], args, n * sizeof(args[0])); | ||
| 99 | } | ||
| 100 | |||
| 101 | #endif /* __ASM_SYSCALL_H */ | ||
diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h new file mode 100644 index 000000000000..09ff33572aab --- /dev/null +++ b/arch/arm64/include/asm/syscalls.h | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_SYSCALLS_H | ||
| 17 | #define __ASM_SYSCALLS_H | ||
| 18 | |||
| 19 | #include <linux/linkage.h> | ||
| 20 | #include <linux/compiler.h> | ||
| 21 | #include <linux/signal.h> | ||
| 22 | |||
| 23 | /* | ||
| 24 | * System call wrappers implemented in kernel/entry.S. | ||
| 25 | */ | ||
| 26 | asmlinkage long sys_execve_wrapper(const char __user *filename, | ||
| 27 | const char __user *const __user *argv, | ||
| 28 | const char __user *const __user *envp); | ||
| 29 | asmlinkage long sys_clone_wrapper(unsigned long clone_flags, | ||
| 30 | unsigned long newsp, | ||
| 31 | void __user *parent_tid, | ||
| 32 | unsigned long tls_val, | ||
| 33 | void __user *child_tid); | ||
| 34 | asmlinkage long sys_rt_sigreturn_wrapper(void); | ||
| 35 | asmlinkage long sys_sigaltstack_wrapper(const stack_t __user *uss, | ||
| 36 | stack_t __user *uoss); | ||
| 37 | |||
| 38 | #include <asm-generic/syscalls.h> | ||
| 39 | |||
| 40 | #endif /* __ASM_SYSCALLS_H */ | ||
diff --git a/arch/arm64/include/asm/system_misc.h b/arch/arm64/include/asm/system_misc.h new file mode 100644 index 000000000000..95e407255347 --- /dev/null +++ b/arch/arm64/include/asm/system_misc.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/system_misc.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_SYSTEM_MISC_H | ||
| 19 | #define __ASM_SYSTEM_MISC_H | ||
| 20 | |||
| 21 | #ifndef __ASSEMBLY__ | ||
| 22 | |||
| 23 | #include <linux/compiler.h> | ||
| 24 | #include <linux/linkage.h> | ||
| 25 | #include <linux/irqflags.h> | ||
| 26 | |||
| 27 | struct pt_regs; | ||
| 28 | |||
| 29 | void die(const char *msg, struct pt_regs *regs, int err); | ||
| 30 | |||
| 31 | struct siginfo; | ||
| 32 | void arm64_notify_die(const char *str, struct pt_regs *regs, | ||
| 33 | struct siginfo *info, int err); | ||
| 34 | |||
| 35 | void hook_debug_fault_code(int nr, int (*fn)(unsigned long, unsigned int, | ||
| 36 | struct pt_regs *), | ||
| 37 | int sig, int code, const char *name); | ||
| 38 | |||
| 39 | struct mm_struct; | ||
| 40 | extern void show_pte(struct mm_struct *mm, unsigned long addr); | ||
| 41 | extern void __show_regs(struct pt_regs *); | ||
| 42 | |||
| 43 | void soft_restart(unsigned long); | ||
| 44 | extern void (*pm_restart)(const char *cmd); | ||
| 45 | |||
| 46 | #define UDBG_UNDEFINED (1 << 0) | ||
| 47 | #define UDBG_SYSCALL (1 << 1) | ||
| 48 | #define UDBG_BADABORT (1 << 2) | ||
| 49 | #define UDBG_SEGV (1 << 3) | ||
| 50 | #define UDBG_BUS (1 << 4) | ||
| 51 | |||
| 52 | #endif /* __ASSEMBLY__ */ | ||
| 53 | |||
| 54 | #endif /* __ASM_SYSTEM_MISC_H */ | ||
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h new file mode 100644 index 000000000000..3659e460071d --- /dev/null +++ b/arch/arm64/include/asm/thread_info.h | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/thread_info.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 Russell King. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_THREAD_INFO_H | ||
| 20 | #define __ASM_THREAD_INFO_H | ||
| 21 | |||
| 22 | #ifdef __KERNEL__ | ||
| 23 | |||
| 24 | #include <linux/compiler.h> | ||
| 25 | |||
| 26 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 27 | #define THREAD_SIZE_ORDER 1 | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #define THREAD_SIZE 8192 | ||
| 31 | #define THREAD_START_SP (THREAD_SIZE - 16) | ||
| 32 | |||
| 33 | #ifndef __ASSEMBLY__ | ||
| 34 | |||
| 35 | struct task_struct; | ||
| 36 | struct exec_domain; | ||
| 37 | |||
| 38 | #include <asm/types.h> | ||
| 39 | |||
| 40 | typedef unsigned long mm_segment_t; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * low level task data that entry.S needs immediate access to. | ||
| 44 | * __switch_to() assumes cpu_context follows immediately after cpu_domain. | ||
| 45 | */ | ||
| 46 | struct thread_info { | ||
| 47 | unsigned long flags; /* low level flags */ | ||
| 48 | mm_segment_t addr_limit; /* address limit */ | ||
| 49 | struct task_struct *task; /* main task structure */ | ||
| 50 | struct exec_domain *exec_domain; /* execution domain */ | ||
| 51 | struct restart_block restart_block; | ||
| 52 | int preempt_count; /* 0 => preemptable, <0 => bug */ | ||
| 53 | int cpu; /* cpu */ | ||
| 54 | }; | ||
| 55 | |||
| 56 | #define INIT_THREAD_INFO(tsk) \ | ||
| 57 | { \ | ||
| 58 | .task = &tsk, \ | ||
| 59 | .exec_domain = &default_exec_domain, \ | ||
| 60 | .flags = 0, \ | ||
| 61 | .preempt_count = INIT_PREEMPT_COUNT, \ | ||
| 62 | .addr_limit = KERNEL_DS, \ | ||
| 63 | .restart_block = { \ | ||
| 64 | .fn = do_no_restart_syscall, \ | ||
| 65 | }, \ | ||
| 66 | } | ||
| 67 | |||
| 68 | #define init_thread_info (init_thread_union.thread_info) | ||
| 69 | #define init_stack (init_thread_union.stack) | ||
| 70 | |||
| 71 | /* | ||
| 72 | * how to get the thread information struct from C | ||
| 73 | */ | ||
| 74 | static inline struct thread_info *current_thread_info(void) __attribute_const__; | ||
| 75 | |||
| 76 | static inline struct thread_info *current_thread_info(void) | ||
| 77 | { | ||
| 78 | register unsigned long sp asm ("sp"); | ||
| 79 | return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); | ||
| 80 | } | ||
| 81 | |||
| 82 | #define thread_saved_pc(tsk) \ | ||
| 83 | ((unsigned long)(tsk->thread.cpu_context.pc)) | ||
| 84 | #define thread_saved_sp(tsk) \ | ||
| 85 | ((unsigned long)(tsk->thread.cpu_context.sp)) | ||
| 86 | #define thread_saved_fp(tsk) \ | ||
| 87 | ((unsigned long)(tsk->thread.cpu_context.fp)) | ||
| 88 | |||
| 89 | #endif | ||
| 90 | |||
| 91 | /* | ||
| 92 | * We use bit 30 of the preempt_count to indicate that kernel | ||
| 93 | * preemption is occurring. See <asm/hardirq.h>. | ||
| 94 | */ | ||
| 95 | #define PREEMPT_ACTIVE 0x40000000 | ||
| 96 | |||
| 97 | /* | ||
| 98 | * thread information flags: | ||
| 99 | * TIF_SYSCALL_TRACE - syscall trace active | ||
| 100 | * TIF_SIGPENDING - signal pending | ||
| 101 | * TIF_NEED_RESCHED - rescheduling necessary | ||
| 102 | * TIF_NOTIFY_RESUME - callback before returning to user | ||
| 103 | * TIF_USEDFPU - FPU was used by this task this quantum (SMP) | ||
| 104 | * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED | ||
| 105 | */ | ||
| 106 | #define TIF_SIGPENDING 0 | ||
| 107 | #define TIF_NEED_RESCHED 1 | ||
| 108 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ | ||
| 109 | #define TIF_SYSCALL_TRACE 8 | ||
| 110 | #define TIF_POLLING_NRFLAG 16 | ||
| 111 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | ||
| 112 | #define TIF_FREEZE 19 | ||
| 113 | #define TIF_RESTORE_SIGMASK 20 | ||
| 114 | #define TIF_SINGLESTEP 21 | ||
| 115 | #define TIF_32BIT 22 /* 32bit process */ | ||
| 116 | #define TIF_SWITCH_MM 23 /* deferred switch_mm */ | ||
| 117 | |||
| 118 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | ||
| 119 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | ||
| 120 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | ||
| 121 | #define _TIF_32BIT (1 << TIF_32BIT) | ||
| 122 | |||
| 123 | #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ | ||
| 124 | _TIF_NOTIFY_RESUME) | ||
| 125 | |||
| 126 | #endif /* __KERNEL__ */ | ||
| 127 | #endif /* __ASM_THREAD_INFO_H */ | ||
diff --git a/arch/arm64/include/asm/timex.h b/arch/arm64/include/asm/timex.h new file mode 100644 index 000000000000..b24a31a7e2c9 --- /dev/null +++ b/arch/arm64/include/asm/timex.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_TIMEX_H | ||
| 17 | #define __ASM_TIMEX_H | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Use the current timer as a cycle counter since this is what we use for | ||
| 21 | * the delay loop. | ||
| 22 | */ | ||
| 23 | #define get_cycles() ({ cycles_t c; read_current_timer(&c); c; }) | ||
| 24 | |||
| 25 | #include <asm-generic/timex.h> | ||
| 26 | |||
| 27 | #define ARCH_HAS_READ_CURRENT_TIMER | ||
| 28 | |||
| 29 | #endif | ||
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h new file mode 100644 index 000000000000..654f0968030b --- /dev/null +++ b/arch/arm64/include/asm/tlb.h | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/tlb.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_TLB_H | ||
| 20 | #define __ASM_TLB_H | ||
| 21 | |||
| 22 | #include <linux/pagemap.h> | ||
| 23 | #include <linux/swap.h> | ||
| 24 | |||
| 25 | #include <asm/pgalloc.h> | ||
| 26 | #include <asm/tlbflush.h> | ||
| 27 | |||
| 28 | #define MMU_GATHER_BUNDLE 8 | ||
| 29 | |||
| 30 | /* | ||
| 31 | * TLB handling. This allows us to remove pages from the page | ||
| 32 | * tables, and efficiently handle the TLB issues. | ||
| 33 | */ | ||
| 34 | struct mmu_gather { | ||
| 35 | struct mm_struct *mm; | ||
| 36 | unsigned int fullmm; | ||
| 37 | struct vm_area_struct *vma; | ||
| 38 | unsigned long range_start; | ||
| 39 | unsigned long range_end; | ||
| 40 | unsigned int nr; | ||
| 41 | unsigned int max; | ||
| 42 | struct page **pages; | ||
| 43 | struct page *local[MMU_GATHER_BUNDLE]; | ||
| 44 | }; | ||
| 45 | |||
| 46 | /* | ||
| 47 | * This is unnecessarily complex. There's three ways the TLB shootdown | ||
| 48 | * code is used: | ||
| 49 | * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region(). | ||
| 50 | * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called. | ||
| 51 | * tlb->vma will be non-NULL. | ||
| 52 | * 2. Unmapping all vmas. See exit_mmap(). | ||
| 53 | * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called. | ||
| 54 | * tlb->vma will be non-NULL. Additionally, page tables will be freed. | ||
| 55 | * 3. Unmapping argument pages. See shift_arg_pages(). | ||
| 56 | * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called. | ||
| 57 | * tlb->vma will be NULL. | ||
| 58 | */ | ||
| 59 | static inline void tlb_flush(struct mmu_gather *tlb) | ||
| 60 | { | ||
| 61 | if (tlb->fullmm || !tlb->vma) | ||
| 62 | flush_tlb_mm(tlb->mm); | ||
| 63 | else if (tlb->range_end > 0) { | ||
| 64 | flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end); | ||
| 65 | tlb->range_start = TASK_SIZE; | ||
| 66 | tlb->range_end = 0; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) | ||
| 71 | { | ||
| 72 | if (!tlb->fullmm) { | ||
| 73 | if (addr < tlb->range_start) | ||
| 74 | tlb->range_start = addr; | ||
| 75 | if (addr + PAGE_SIZE > tlb->range_end) | ||
| 76 | tlb->range_end = addr + PAGE_SIZE; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline void __tlb_alloc_page(struct mmu_gather *tlb) | ||
| 81 | { | ||
| 82 | unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); | ||
| 83 | |||
| 84 | if (addr) { | ||
| 85 | tlb->pages = (void *)addr; | ||
| 86 | tlb->max = PAGE_SIZE / sizeof(struct page *); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void tlb_flush_mmu(struct mmu_gather *tlb) | ||
| 91 | { | ||
| 92 | tlb_flush(tlb); | ||
| 93 | free_pages_and_swap_cache(tlb->pages, tlb->nr); | ||
| 94 | tlb->nr = 0; | ||
| 95 | if (tlb->pages == tlb->local) | ||
| 96 | __tlb_alloc_page(tlb); | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline void | ||
| 100 | tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm) | ||
| 101 | { | ||
| 102 | tlb->mm = mm; | ||
| 103 | tlb->fullmm = fullmm; | ||
| 104 | tlb->vma = NULL; | ||
| 105 | tlb->max = ARRAY_SIZE(tlb->local); | ||
| 106 | tlb->pages = tlb->local; | ||
| 107 | tlb->nr = 0; | ||
| 108 | __tlb_alloc_page(tlb); | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline void | ||
| 112 | tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | ||
| 113 | { | ||
| 114 | tlb_flush_mmu(tlb); | ||
| 115 | |||
| 116 | /* keep the page table cache within bounds */ | ||
| 117 | check_pgt_cache(); | ||
| 118 | |||
| 119 | if (tlb->pages != tlb->local) | ||
| 120 | free_pages((unsigned long)tlb->pages, 0); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Memorize the range for the TLB flush. | ||
| 125 | */ | ||
| 126 | static inline void | ||
| 127 | tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr) | ||
| 128 | { | ||
| 129 | tlb_add_flush(tlb, addr); | ||
| 130 | } | ||
| 131 | |||
| 132 | /* | ||
| 133 | * In the case of tlb vma handling, we can optimise these away in the | ||
| 134 | * case where we're doing a full MM flush. When we're doing a munmap, | ||
| 135 | * the vmas are adjusted to only cover the region to be torn down. | ||
| 136 | */ | ||
| 137 | static inline void | ||
| 138 | tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) | ||
| 139 | { | ||
| 140 | if (!tlb->fullmm) { | ||
| 141 | tlb->vma = vma; | ||
| 142 | tlb->range_start = TASK_SIZE; | ||
| 143 | tlb->range_end = 0; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | static inline void | ||
| 148 | tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) | ||
| 149 | { | ||
| 150 | if (!tlb->fullmm) | ||
| 151 | tlb_flush(tlb); | ||
| 152 | } | ||
| 153 | |||
| 154 | static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
| 155 | { | ||
| 156 | tlb->pages[tlb->nr++] = page; | ||
| 157 | VM_BUG_ON(tlb->nr > tlb->max); | ||
| 158 | return tlb->max - tlb->nr; | ||
| 159 | } | ||
| 160 | |||
| 161 | static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
| 162 | { | ||
| 163 | if (!__tlb_remove_page(tlb, page)) | ||
| 164 | tlb_flush_mmu(tlb); | ||
| 165 | } | ||
| 166 | |||
| 167 | static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, | ||
| 168 | unsigned long addr) | ||
| 169 | { | ||
| 170 | pgtable_page_dtor(pte); | ||
| 171 | tlb_add_flush(tlb, addr); | ||
| 172 | tlb_remove_page(tlb, pte); | ||
| 173 | } | ||
| 174 | |||
| 175 | #ifndef CONFIG_ARM64_64K_PAGES | ||
| 176 | static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, | ||
| 177 | unsigned long addr) | ||
| 178 | { | ||
| 179 | tlb_add_flush(tlb, addr); | ||
| 180 | tlb_remove_page(tlb, virt_to_page(pmdp)); | ||
| 181 | } | ||
| 182 | #endif | ||
| 183 | |||
| 184 | #define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) | ||
| 185 | #define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr) | ||
| 186 | #define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp) | ||
| 187 | |||
| 188 | #define tlb_migrate_finish(mm) do { } while (0) | ||
| 189 | |||
| 190 | #endif | ||
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h new file mode 100644 index 000000000000..122d6320f745 --- /dev/null +++ b/arch/arm64/include/asm/tlbflush.h | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/tlbflush.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 1999-2003 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #ifndef __ASM_TLBFLUSH_H | ||
| 20 | #define __ASM_TLBFLUSH_H | ||
| 21 | |||
| 22 | #ifndef __ASSEMBLY__ | ||
| 23 | |||
| 24 | #include <linux/sched.h> | ||
| 25 | #include <asm/cputype.h> | ||
| 26 | |||
| 27 | extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *); | ||
| 28 | extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long); | ||
| 29 | |||
| 30 | extern struct cpu_tlb_fns cpu_tlb; | ||
| 31 | |||
| 32 | /* | ||
| 33 | * TLB Management | ||
| 34 | * ============== | ||
| 35 | * | ||
| 36 | * The arch/arm64/mm/tlb.S files implement these methods. | ||
| 37 | * | ||
| 38 | * The TLB specific code is expected to perform whatever tests it needs | ||
| 39 | * to determine if it should invalidate the TLB for each call. Start | ||
| 40 | * addresses are inclusive and end addresses are exclusive; it is safe to | ||
| 41 | * round these addresses down. | ||
| 42 | * | ||
| 43 | * flush_tlb_all() | ||
| 44 | * | ||
| 45 | * Invalidate the entire TLB. | ||
| 46 | * | ||
| 47 | * flush_tlb_mm(mm) | ||
| 48 | * | ||
| 49 | * Invalidate all TLB entries in a particular address space. | ||
| 50 | * - mm - mm_struct describing address space | ||
| 51 | * | ||
| 52 | * flush_tlb_range(mm,start,end) | ||
| 53 | * | ||
| 54 | * Invalidate a range of TLB entries in the specified address | ||
| 55 | * space. | ||
| 56 | * - mm - mm_struct describing address space | ||
| 57 | * - start - start address (may not be aligned) | ||
| 58 | * - end - end address (exclusive, may not be aligned) | ||
| 59 | * | ||
| 60 | * flush_tlb_page(vaddr,vma) | ||
| 61 | * | ||
| 62 | * Invalidate the specified page in the specified address range. | ||
| 63 | * - vaddr - virtual address (may not be aligned) | ||
| 64 | * - vma - vma_struct describing address range | ||
| 65 | * | ||
| 66 | * flush_kern_tlb_page(kaddr) | ||
| 67 | * | ||
| 68 | * Invalidate the TLB entry for the specified page. The address | ||
| 69 | * will be in the kernels virtual memory space. Current uses | ||
| 70 | * only require the D-TLB to be invalidated. | ||
| 71 | * - kaddr - Kernel virtual memory address | ||
| 72 | */ | ||
| 73 | static inline void flush_tlb_all(void) | ||
| 74 | { | ||
| 75 | dsb(); | ||
| 76 | asm("tlbi vmalle1is"); | ||
| 77 | dsb(); | ||
| 78 | isb(); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline void flush_tlb_mm(struct mm_struct *mm) | ||
| 82 | { | ||
| 83 | unsigned long asid = (unsigned long)ASID(mm) << 48; | ||
| 84 | |||
| 85 | dsb(); | ||
| 86 | asm("tlbi aside1is, %0" : : "r" (asid)); | ||
| 87 | dsb(); | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void flush_tlb_page(struct vm_area_struct *vma, | ||
| 91 | unsigned long uaddr) | ||
| 92 | { | ||
| 93 | unsigned long addr = uaddr >> 12 | | ||
| 94 | ((unsigned long)ASID(vma->vm_mm) << 48); | ||
| 95 | |||
| 96 | dsb(); | ||
| 97 | asm("tlbi vae1is, %0" : : "r" (addr)); | ||
| 98 | dsb(); | ||
| 99 | } | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Convert calls to our calling convention. | ||
| 103 | */ | ||
| 104 | #define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) | ||
| 105 | #define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) | ||
| 106 | |||
| 107 | /* | ||
| 108 | * On AArch64, the cache coherency is handled via the set_pte_at() function. | ||
| 109 | */ | ||
| 110 | static inline void update_mmu_cache(struct vm_area_struct *vma, | ||
| 111 | unsigned long addr, pte_t *ptep) | ||
| 112 | { | ||
| 113 | /* | ||
| 114 | * set_pte() does not have a DSB, so make sure that the page table | ||
| 115 | * write is visible. | ||
| 116 | */ | ||
| 117 | dsb(); | ||
| 118 | } | ||
| 119 | |||
| 120 | #endif | ||
| 121 | |||
| 122 | #endif | ||
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h new file mode 100644 index 000000000000..10ca8ff93cc2 --- /dev/null +++ b/arch/arm64/include/asm/traps.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/traps.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_TRAP_H | ||
| 19 | #define __ASM_TRAP_H | ||
| 20 | |||
| 21 | static inline int in_exception_text(unsigned long ptr) | ||
| 22 | { | ||
| 23 | extern char __exception_text_start[]; | ||
| 24 | extern char __exception_text_end[]; | ||
| 25 | |||
| 26 | return ptr >= (unsigned long)&__exception_text_start && | ||
| 27 | ptr < (unsigned long)&__exception_text_end; | ||
| 28 | } | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h new file mode 100644 index 000000000000..008f8481da65 --- /dev/null +++ b/arch/arm64/include/asm/uaccess.h | |||
| @@ -0,0 +1,297 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/uaccess.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #ifndef __ASM_UACCESS_H | ||
| 19 | #define __ASM_UACCESS_H | ||
| 20 | |||
| 21 | /* | ||
| 22 | * User space memory access functions | ||
| 23 | */ | ||
| 24 | #include <linux/string.h> | ||
| 25 | #include <linux/thread_info.h> | ||
| 26 | |||
| 27 | #include <asm/ptrace.h> | ||
| 28 | #include <asm/errno.h> | ||
| 29 | #include <asm/memory.h> | ||
| 30 | #include <asm/compiler.h> | ||
| 31 | |||
| 32 | #define VERIFY_READ 0 | ||
| 33 | #define VERIFY_WRITE 1 | ||
| 34 | |||
| 35 | /* | ||
| 36 | * The exception table consists of pairs of addresses: the first is the | ||
| 37 | * address of an instruction that is allowed to fault, and the second is | ||
| 38 | * the address at which the program should continue. No registers are | ||
| 39 | * modified, so it is entirely up to the continuation code to figure out | ||
| 40 | * what to do. | ||
| 41 | * | ||
| 42 | * All the routines below use bits of fixup code that are out of line | ||
| 43 | * with the main instruction path. This means when everything is well, | ||
| 44 | * we don't even have to jump over them. Further, they do not intrude | ||
| 45 | * on our cache or tlb entries. | ||
| 46 | */ | ||
| 47 | |||
| 48 | struct exception_table_entry | ||
| 49 | { | ||
| 50 | unsigned long insn, fixup; | ||
| 51 | }; | ||
| 52 | |||
| 53 | extern int fixup_exception(struct pt_regs *regs); | ||
| 54 | |||
| 55 | #define KERNEL_DS (-1UL) | ||
| 56 | #define get_ds() (KERNEL_DS) | ||
| 57 | |||
| 58 | #define USER_DS TASK_SIZE_64 | ||
| 59 | #define get_fs() (current_thread_info()->addr_limit) | ||
| 60 | |||
| 61 | static inline void set_fs(mm_segment_t fs) | ||
| 62 | { | ||
| 63 | current_thread_info()->addr_limit = fs; | ||
| 64 | } | ||
| 65 | |||
| 66 | #define segment_eq(a,b) ((a) == (b)) | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Return 1 if addr < current->addr_limit, 0 otherwise. | ||
| 70 | */ | ||
| 71 | #define __addr_ok(addr) \ | ||
| 72 | ({ \ | ||
| 73 | unsigned long flag; \ | ||
| 74 | asm("cmp %1, %0; cset %0, lo" \ | ||
| 75 | : "=&r" (flag) \ | ||
| 76 | : "r" (addr), "0" (current_thread_info()->addr_limit) \ | ||
| 77 | : "cc"); \ | ||
| 78 | flag; \ | ||
| 79 | }) | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Test whether a block of memory is a valid user space address. | ||
| 83 | * Returns 1 if the range is valid, 0 otherwise. | ||
| 84 | * | ||
| 85 | * This is equivalent to the following test: | ||
| 86 | * (u65)addr + (u65)size < (u65)current->addr_limit | ||
| 87 | * | ||
| 88 | * This needs 65-bit arithmetic. | ||
| 89 | */ | ||
| 90 | #define __range_ok(addr, size) \ | ||
| 91 | ({ \ | ||
| 92 | unsigned long flag, roksum; \ | ||
| 93 | __chk_user_ptr(addr); \ | ||
| 94 | asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, cc" \ | ||
| 95 | : "=&r" (flag), "=&r" (roksum) \ | ||
| 96 | : "1" (addr), "Ir" (size), \ | ||
| 97 | "r" (current_thread_info()->addr_limit) \ | ||
| 98 | : "cc"); \ | ||
| 99 | flag; \ | ||
| 100 | }) | ||
| 101 | |||
| 102 | #define access_ok(type, addr, size) __range_ok(addr, size) | ||
| 103 | |||
| 104 | /* | ||
| 105 | * The "__xxx" versions of the user access functions do not verify the address | ||
| 106 | * space - it must have been done previously with a separate "access_ok()" | ||
| 107 | * call. | ||
| 108 | * | ||
| 109 | * The "__xxx_error" versions set the third argument to -EFAULT if an error | ||
| 110 | * occurs, and leave it unchanged on success. | ||
| 111 | */ | ||
| 112 | #define __get_user_asm(instr, reg, x, addr, err) \ | ||
| 113 | asm volatile( \ | ||
| 114 | "1: " instr " " reg "1, [%2]\n" \ | ||
| 115 | "2:\n" \ | ||
| 116 | " .section .fixup, \"ax\"\n" \ | ||
| 117 | " .align 2\n" \ | ||
| 118 | "3: mov %w0, %3\n" \ | ||
| 119 | " mov %1, #0\n" \ | ||
| 120 | " b 2b\n" \ | ||
| 121 | " .previous\n" \ | ||
| 122 | " .section __ex_table,\"a\"\n" \ | ||
| 123 | " .align 3\n" \ | ||
| 124 | " .quad 1b, 3b\n" \ | ||
| 125 | " .previous" \ | ||
| 126 | : "+r" (err), "=&r" (x) \ | ||
| 127 | : "r" (addr), "i" (-EFAULT)) | ||
| 128 | |||
| 129 | #define __get_user_err(x, ptr, err) \ | ||
| 130 | do { \ | ||
| 131 | unsigned long __gu_val; \ | ||
| 132 | __chk_user_ptr(ptr); \ | ||
| 133 | switch (sizeof(*(ptr))) { \ | ||
| 134 | case 1: \ | ||
| 135 | __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err)); \ | ||
| 136 | break; \ | ||
| 137 | case 2: \ | ||
| 138 | __get_user_asm("ldrh", "%w", __gu_val, (ptr), (err)); \ | ||
| 139 | break; \ | ||
| 140 | case 4: \ | ||
| 141 | __get_user_asm("ldr", "%w", __gu_val, (ptr), (err)); \ | ||
| 142 | break; \ | ||
| 143 | case 8: \ | ||
| 144 | __get_user_asm("ldr", "%", __gu_val, (ptr), (err)); \ | ||
| 145 | break; \ | ||
| 146 | default: \ | ||
| 147 | BUILD_BUG(); \ | ||
| 148 | } \ | ||
| 149 | (x) = (__typeof__(*(ptr)))__gu_val; \ | ||
| 150 | } while (0) | ||
| 151 | |||
| 152 | #define __get_user(x, ptr) \ | ||
| 153 | ({ \ | ||
| 154 | int __gu_err = 0; \ | ||
| 155 | __get_user_err((x), (ptr), __gu_err); \ | ||
| 156 | __gu_err; \ | ||
| 157 | }) | ||
| 158 | |||
| 159 | #define __get_user_error(x, ptr, err) \ | ||
| 160 | ({ \ | ||
| 161 | __get_user_err((x), (ptr), (err)); \ | ||
| 162 | (void)0; \ | ||
| 163 | }) | ||
| 164 | |||
| 165 | #define __get_user_unaligned __get_user | ||
| 166 | |||
| 167 | #define get_user(x, ptr) \ | ||
| 168 | ({ \ | ||
| 169 | might_sleep(); \ | ||
| 170 | access_ok(VERIFY_READ, (ptr), sizeof(*(ptr))) ? \ | ||
| 171 | __get_user((x), (ptr)) : \ | ||
| 172 | ((x) = 0, -EFAULT); \ | ||
| 173 | }) | ||
| 174 | |||
| 175 | #define __put_user_asm(instr, reg, x, addr, err) \ | ||
| 176 | asm volatile( \ | ||
| 177 | "1: " instr " " reg "1, [%2]\n" \ | ||
| 178 | "2:\n" \ | ||
| 179 | " .section .fixup,\"ax\"\n" \ | ||
| 180 | " .align 2\n" \ | ||
| 181 | "3: mov %w0, %3\n" \ | ||
| 182 | " b 2b\n" \ | ||
| 183 | " .previous\n" \ | ||
| 184 | " .section __ex_table,\"a\"\n" \ | ||
| 185 | " .align 3\n" \ | ||
| 186 | " .quad 1b, 3b\n" \ | ||
| 187 | " .previous" \ | ||
| 188 | : "+r" (err) \ | ||
| 189 | : "r" (x), "r" (addr), "i" (-EFAULT)) | ||
| 190 | |||
| 191 | #define __put_user_err(x, ptr, err) \ | ||
| 192 | do { \ | ||
| 193 | __typeof__(*(ptr)) __pu_val = (x); \ | ||
| 194 | __chk_user_ptr(ptr); \ | ||
| 195 | switch (sizeof(*(ptr))) { \ | ||
| 196 | case 1: \ | ||
| 197 | __put_user_asm("strb", "%w", __pu_val, (ptr), (err)); \ | ||
| 198 | break; \ | ||
| 199 | case 2: \ | ||
| 200 | __put_user_asm("strh", "%w", __pu_val, (ptr), (err)); \ | ||
| 201 | break; \ | ||
| 202 | case 4: \ | ||
| 203 | __put_user_asm("str", "%w", __pu_val, (ptr), (err)); \ | ||
| 204 | break; \ | ||
| 205 | case 8: \ | ||
| 206 | __put_user_asm("str", "%", __pu_val, (ptr), (err)); \ | ||
| 207 | break; \ | ||
| 208 | default: \ | ||
| 209 | BUILD_BUG(); \ | ||
| 210 | } \ | ||
| 211 | } while (0) | ||
| 212 | |||
| 213 | #define __put_user(x, ptr) \ | ||
| 214 | ({ \ | ||
| 215 | int __pu_err = 0; \ | ||
| 216 | __put_user_err((x), (ptr), __pu_err); \ | ||
| 217 | __pu_err; \ | ||
| 218 | }) | ||
| 219 | |||
| 220 | #define __put_user_error(x, ptr, err) \ | ||
| 221 | ({ \ | ||
| 222 | __put_user_err((x), (ptr), (err)); \ | ||
| 223 | (void)0; \ | ||
| 224 | }) | ||
| 225 | |||
| 226 | #define __put_user_unaligned __put_user | ||
| 227 | |||
| 228 | #define put_user(x, ptr) \ | ||
| 229 | ({ \ | ||
| 230 | might_sleep(); \ | ||
| 231 | access_ok(VERIFY_WRITE, (ptr), sizeof(*(ptr))) ? \ | ||
| 232 | __put_user((x), (ptr)) : \ | ||
| 233 | -EFAULT; \ | ||
| 234 | }) | ||
| 235 | |||
| 236 | extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n); | ||
| 237 | extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n); | ||
| 238 | extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); | ||
| 239 | extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); | ||
| 240 | |||
| 241 | extern unsigned long __must_check __strncpy_from_user(char *to, const char __user *from, unsigned long count); | ||
| 242 | extern unsigned long __must_check __strnlen_user(const char __user *s, long n); | ||
| 243 | |||
| 244 | static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) | ||
| 245 | { | ||
| 246 | if (access_ok(VERIFY_READ, from, n)) | ||
| 247 | n = __copy_from_user(to, from, n); | ||
| 248 | else /* security hole - plug it */ | ||
| 249 | memset(to, 0, n); | ||
| 250 | return n; | ||
| 251 | } | ||
| 252 | |||
| 253 | static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) | ||
| 254 | { | ||
| 255 | if (access_ok(VERIFY_WRITE, to, n)) | ||
| 256 | n = __copy_to_user(to, from, n); | ||
| 257 | return n; | ||
| 258 | } | ||
| 259 | |||
| 260 | static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n) | ||
| 261 | { | ||
| 262 | if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n)) | ||
| 263 | n = __copy_in_user(to, from, n); | ||
| 264 | return n; | ||
| 265 | } | ||
| 266 | |||
| 267 | #define __copy_to_user_inatomic __copy_to_user | ||
| 268 | #define __copy_from_user_inatomic __copy_from_user | ||
| 269 | |||
| 270 | static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) | ||
| 271 | { | ||
| 272 | if (access_ok(VERIFY_WRITE, to, n)) | ||
| 273 | n = __clear_user(to, n); | ||
| 274 | return n; | ||
| 275 | } | ||
| 276 | |||
| 277 | static inline long __must_check strncpy_from_user(char *dst, const char __user *src, long count) | ||
| 278 | { | ||
| 279 | long res = -EFAULT; | ||
| 280 | if (access_ok(VERIFY_READ, src, 1)) | ||
| 281 | res = __strncpy_from_user(dst, src, count); | ||
| 282 | return res; | ||
| 283 | } | ||
| 284 | |||
| 285 | #define strlen_user(s) strnlen_user(s, ~0UL >> 1) | ||
| 286 | |||
| 287 | static inline long __must_check strnlen_user(const char __user *s, long n) | ||
| 288 | { | ||
| 289 | unsigned long res = 0; | ||
| 290 | |||
| 291 | if (__addr_ok(s)) | ||
| 292 | res = __strnlen_user(s, n); | ||
| 293 | |||
| 294 | return res; | ||
| 295 | } | ||
| 296 | |||
| 297 | #endif /* __ASM_UACCESS_H */ | ||
diff --git a/arch/arm64/include/asm/ucontext.h b/arch/arm64/include/asm/ucontext.h new file mode 100644 index 000000000000..bde960720892 --- /dev/null +++ b/arch/arm64/include/asm/ucontext.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_UCONTEXT_H | ||
| 17 | #define __ASM_UCONTEXT_H | ||
| 18 | |||
| 19 | struct ucontext { | ||
| 20 | unsigned long uc_flags; | ||
| 21 | struct ucontext *uc_link; | ||
| 22 | stack_t uc_stack; | ||
| 23 | sigset_t uc_sigmask; | ||
| 24 | /* glibc uses a 1024-bit sigset_t */ | ||
| 25 | __u8 __unused[(1024 - sizeof(sigset_t)) / 8]; | ||
| 26 | /* last for future expansion */ | ||
| 27 | struct sigcontext uc_mcontext; | ||
| 28 | }; | ||
| 29 | |||
| 30 | #endif /* __ASM_UCONTEXT_H */ | ||
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h new file mode 100644 index 000000000000..fe18a683274f --- /dev/null +++ b/arch/arm64/include/asm/unistd.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #if !defined(__ASM_UNISTD_H) || defined(__SYSCALL) | ||
| 17 | #define __ASM_UNISTD_H | ||
| 18 | |||
| 19 | #ifndef __SYSCALL_COMPAT | ||
| 20 | #include <asm-generic/unistd.h> | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #if defined(__KERNEL__) && defined(CONFIG_COMPAT) | ||
| 24 | #include <asm/unistd32.h> | ||
| 25 | #endif | ||
| 26 | |||
| 27 | #endif /* __ASM_UNISTD_H */ | ||
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h new file mode 100644 index 000000000000..a50405f5ee42 --- /dev/null +++ b/arch/arm64/include/asm/unistd32.h | |||
| @@ -0,0 +1,758 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/include/asm/unistd.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001-2005 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | #if !defined(__ASM_UNISTD32_H) || defined(__SYSCALL) | ||
| 20 | #define __ASM_UNISTD32_H | ||
| 21 | |||
| 22 | #ifndef __SYSCALL | ||
| 23 | #define __SYSCALL(x, y) | ||
| 24 | #endif | ||
| 25 | |||
| 26 | /* | ||
| 27 | * This file contains the system call numbers. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #ifdef __SYSCALL_COMPAT | ||
| 31 | |||
| 32 | #define __NR_restart_syscall 0 | ||
| 33 | __SYSCALL(__NR_restart_syscall, sys_restart_syscall) | ||
| 34 | #define __NR_exit 1 | ||
| 35 | __SYSCALL(__NR_exit, sys_exit) | ||
| 36 | #define __NR_fork 2 | ||
| 37 | __SYSCALL(__NR_fork, sys_fork) | ||
| 38 | #define __NR_read 3 | ||
| 39 | __SYSCALL(__NR_read, sys_read) | ||
| 40 | #define __NR_write 4 | ||
| 41 | __SYSCALL(__NR_write, sys_write) | ||
| 42 | #define __NR_open 5 | ||
| 43 | __SYSCALL(__NR_open, sys_open) | ||
| 44 | #define __NR_close 6 | ||
| 45 | __SYSCALL(__NR_close, sys_close) | ||
| 46 | __SYSCALL(7, sys_ni_syscall) /* 7 was sys_waitpid */ | ||
| 47 | #define __NR_creat 8 | ||
| 48 | __SYSCALL(__NR_creat, sys_creat) | ||
| 49 | #define __NR_link 9 | ||
| 50 | __SYSCALL(__NR_link, sys_link) | ||
| 51 | #define __NR_unlink 10 | ||
| 52 | __SYSCALL(__NR_unlink, sys_unlink) | ||
| 53 | #define __NR_execve 11 | ||
| 54 | __SYSCALL(__NR_execve, sys_execve) | ||
| 55 | #define __NR_chdir 12 | ||
| 56 | __SYSCALL(__NR_chdir, sys_chdir) | ||
| 57 | __SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */ | ||
| 58 | #define __NR_mknod 14 | ||
| 59 | __SYSCALL(__NR_mknod, sys_mknod) | ||
| 60 | #define __NR_chmod 15 | ||
| 61 | __SYSCALL(__NR_chmod, sys_chmod) | ||
| 62 | #define __NR_lchown 16 | ||
| 63 | __SYSCALL(__NR_lchown, sys_lchown16) | ||
| 64 | __SYSCALL(17, sys_ni_syscall) /* 17 was sys_break */ | ||
| 65 | __SYSCALL(18, sys_ni_syscall) /* 18 was sys_stat */ | ||
| 66 | #define __NR_lseek 19 | ||
| 67 | __SYSCALL(__NR_lseek, sys_lseek) | ||
| 68 | #define __NR_getpid 20 | ||
| 69 | __SYSCALL(__NR_getpid, sys_getpid) | ||
| 70 | #define __NR_mount 21 | ||
| 71 | __SYSCALL(__NR_mount, sys_mount) | ||
| 72 | __SYSCALL(22, sys_ni_syscall) /* 22 was sys_umount */ | ||
| 73 | #define __NR_setuid 23 | ||
| 74 | __SYSCALL(__NR_setuid, sys_setuid16) | ||
| 75 | #define __NR_getuid 24 | ||
| 76 | __SYSCALL(__NR_getuid, sys_getuid16) | ||
| 77 | __SYSCALL(25, sys_ni_syscall) /* 25 was sys_stime */ | ||
| 78 | #define __NR_ptrace 26 | ||
| 79 | __SYSCALL(__NR_ptrace, sys_ptrace) | ||
| 80 | __SYSCALL(27, sys_ni_syscall) /* 27 was sys_alarm */ | ||
| 81 | __SYSCALL(28, sys_ni_syscall) /* 28 was sys_fstat */ | ||
| 82 | #define __NR_pause 29 | ||
| 83 | __SYSCALL(__NR_pause, sys_pause) | ||
| 84 | __SYSCALL(30, sys_ni_syscall) /* 30 was sys_utime */ | ||
| 85 | __SYSCALL(31, sys_ni_syscall) /* 31 was sys_stty */ | ||
| 86 | __SYSCALL(32, sys_ni_syscall) /* 32 was sys_gtty */ | ||
| 87 | #define __NR_access 33 | ||
| 88 | __SYSCALL(__NR_access, sys_access) | ||
| 89 | #define __NR_nice 34 | ||
| 90 | __SYSCALL(__NR_nice, sys_nice) | ||
| 91 | __SYSCALL(35, sys_ni_syscall) /* 35 was sys_ftime */ | ||
| 92 | #define __NR_sync 36 | ||
| 93 | __SYSCALL(__NR_sync, sys_sync) | ||
| 94 | #define __NR_kill 37 | ||
| 95 | __SYSCALL(__NR_kill, sys_kill) | ||
| 96 | #define __NR_rename 38 | ||
| 97 | __SYSCALL(__NR_rename, sys_rename) | ||
| 98 | #define __NR_mkdir 39 | ||
| 99 | __SYSCALL(__NR_mkdir, sys_mkdir) | ||
| 100 | #define __NR_rmdir 40 | ||
| 101 | __SYSCALL(__NR_rmdir, sys_rmdir) | ||
| 102 | #define __NR_dup 41 | ||
| 103 | __SYSCALL(__NR_dup, sys_dup) | ||
| 104 | #define __NR_pipe 42 | ||
| 105 | __SYSCALL(__NR_pipe, sys_pipe) | ||
| 106 | #define __NR_times 43 | ||
| 107 | __SYSCALL(__NR_times, sys_times) | ||
| 108 | __SYSCALL(44, sys_ni_syscall) /* 44 was sys_prof */ | ||
| 109 | #define __NR_brk 45 | ||
| 110 | __SYSCALL(__NR_brk, sys_brk) | ||
| 111 | #define __NR_setgid 46 | ||
| 112 | __SYSCALL(__NR_setgid, sys_setgid16) | ||
| 113 | #define __NR_getgid 47 | ||
| 114 | __SYSCALL(__NR_getgid, sys_getgid16) | ||
| 115 | __SYSCALL(48, sys_ni_syscall) /* 48 was sys_signal */ | ||
| 116 | #define __NR_geteuid 49 | ||
| 117 | __SYSCALL(__NR_geteuid, sys_geteuid16) | ||
| 118 | #define __NR_getegid 50 | ||
| 119 | __SYSCALL(__NR_getegid, sys_getegid16) | ||
| 120 | #define __NR_acct 51 | ||
| 121 | __SYSCALL(__NR_acct, sys_acct) | ||
| 122 | #define __NR_umount2 52 | ||
| 123 | __SYSCALL(__NR_umount2, sys_umount) | ||
| 124 | __SYSCALL(53, sys_ni_syscall) /* 53 was sys_lock */ | ||
| 125 | #define __NR_ioctl 54 | ||
| 126 | __SYSCALL(__NR_ioctl, sys_ioctl) | ||
| 127 | #define __NR_fcntl 55 | ||
| 128 | __SYSCALL(__NR_fcntl, sys_fcntl) | ||
| 129 | __SYSCALL(56, sys_ni_syscall) /* 56 was sys_mpx */ | ||
| 130 | #define __NR_setpgid 57 | ||
| 131 | __SYSCALL(__NR_setpgid, sys_setpgid) | ||
| 132 | __SYSCALL(58, sys_ni_syscall) /* 58 was sys_ulimit */ | ||
| 133 | __SYSCALL(59, sys_ni_syscall) /* 59 was sys_olduname */ | ||
| 134 | #define __NR_umask 60 | ||
| 135 | __SYSCALL(__NR_umask, sys_umask) | ||
| 136 | #define __NR_chroot 61 | ||
| 137 | __SYSCALL(__NR_chroot, sys_chroot) | ||
| 138 | #define __NR_ustat 62 | ||
| 139 | __SYSCALL(__NR_ustat, sys_ustat) | ||
| 140 | #define __NR_dup2 63 | ||
| 141 | __SYSCALL(__NR_dup2, sys_dup2) | ||
| 142 | #define __NR_getppid 64 | ||
| 143 | __SYSCALL(__NR_getppid, sys_getppid) | ||
| 144 | #define __NR_getpgrp 65 | ||
| 145 | __SYSCALL(__NR_getpgrp, sys_getpgrp) | ||
| 146 | #define __NR_setsid 66 | ||
| 147 | __SYSCALL(__NR_setsid, sys_setsid) | ||
| 148 | #define __NR_sigaction 67 | ||
| 149 | __SYSCALL(__NR_sigaction, sys_sigaction) | ||
| 150 | __SYSCALL(68, sys_ni_syscall) /* 68 was sys_sgetmask */ | ||
| 151 | __SYSCALL(69, sys_ni_syscall) /* 69 was sys_ssetmask */ | ||
| 152 | #define __NR_setreuid 70 | ||
| 153 | __SYSCALL(__NR_setreuid, sys_setreuid16) | ||
| 154 | #define __NR_setregid 71 | ||
| 155 | __SYSCALL(__NR_setregid, sys_setregid16) | ||
| 156 | #define __NR_sigsuspend 72 | ||
| 157 | __SYSCALL(__NR_sigsuspend, sys_sigsuspend) | ||
| 158 | #define __NR_sigpending 73 | ||
| 159 | __SYSCALL(__NR_sigpending, sys_sigpending) | ||
| 160 | #define __NR_sethostname 74 | ||
| 161 | __SYSCALL(__NR_sethostname, sys_sethostname) | ||
| 162 | #define __NR_setrlimit 75 | ||
| 163 | __SYSCALL(__NR_setrlimit, sys_setrlimit) | ||
| 164 | __SYSCALL(76, sys_ni_syscall) /* 76 was sys_getrlimit */ | ||
| 165 | #define __NR_getrusage 77 | ||
| 166 | __SYSCALL(__NR_getrusage, sys_getrusage) | ||
| 167 | #define __NR_gettimeofday 78 | ||
| 168 | __SYSCALL(__NR_gettimeofday, sys_gettimeofday) | ||
| 169 | #define __NR_settimeofday 79 | ||
| 170 | __SYSCALL(__NR_settimeofday, sys_settimeofday) | ||
| 171 | #define __NR_getgroups 80 | ||
| 172 | __SYSCALL(__NR_getgroups, sys_getgroups16) | ||
| 173 | #define __NR_setgroups 81 | ||
| 174 | __SYSCALL(__NR_setgroups, sys_setgroups16) | ||
| 175 | __SYSCALL(82, sys_ni_syscall) /* 82 was sys_select */ | ||
| 176 | #define __NR_symlink 83 | ||
| 177 | __SYSCALL(__NR_symlink, sys_symlink) | ||
| 178 | __SYSCALL(84, sys_ni_syscall) /* 84 was sys_lstat */ | ||
| 179 | #define __NR_readlink 85 | ||
| 180 | __SYSCALL(__NR_readlink, sys_readlink) | ||
| 181 | #define __NR_uselib 86 | ||
| 182 | __SYSCALL(__NR_uselib, sys_uselib) | ||
| 183 | #define __NR_swapon 87 | ||
| 184 | __SYSCALL(__NR_swapon, sys_swapon) | ||
| 185 | #define __NR_reboot 88 | ||
| 186 | __SYSCALL(__NR_reboot, sys_reboot) | ||
| 187 | __SYSCALL(89, sys_ni_syscall) /* 89 was sys_readdir */ | ||
| 188 | __SYSCALL(90, sys_ni_syscall) /* 90 was sys_mmap */ | ||
| 189 | #define __NR_munmap 91 | ||
| 190 | __SYSCALL(__NR_munmap, sys_munmap) | ||
| 191 | #define __NR_truncate 92 | ||
| 192 | __SYSCALL(__NR_truncate, sys_truncate) | ||
| 193 | #define __NR_ftruncate 93 | ||
| 194 | __SYSCALL(__NR_ftruncate, sys_ftruncate) | ||
| 195 | #define __NR_fchmod 94 | ||
| 196 | __SYSCALL(__NR_fchmod, sys_fchmod) | ||
| 197 | #define __NR_fchown 95 | ||
| 198 | __SYSCALL(__NR_fchown, sys_fchown16) | ||
| 199 | #define __NR_getpriority 96 | ||
| 200 | __SYSCALL(__NR_getpriority, sys_getpriority) | ||
| 201 | #define __NR_setpriority 97 | ||
| 202 | __SYSCALL(__NR_setpriority, sys_setpriority) | ||
| 203 | __SYSCALL(98, sys_ni_syscall) /* 98 was sys_profil */ | ||
| 204 | #define __NR_statfs 99 | ||
| 205 | __SYSCALL(__NR_statfs, sys_statfs) | ||
| 206 | #define __NR_fstatfs 100 | ||
| 207 | __SYSCALL(__NR_fstatfs, sys_fstatfs) | ||
| 208 | __SYSCALL(101, sys_ni_syscall) /* 101 was sys_ioperm */ | ||
| 209 | __SYSCALL(102, sys_ni_syscall) /* 102 was sys_socketcall */ | ||
| 210 | #define __NR_syslog 103 | ||
| 211 | __SYSCALL(__NR_syslog, sys_syslog) | ||
| 212 | #define __NR_setitimer 104 | ||
| 213 | __SYSCALL(__NR_setitimer, sys_setitimer) | ||
| 214 | #define __NR_getitimer 105 | ||
| 215 | __SYSCALL(__NR_getitimer, sys_getitimer) | ||
| 216 | #define __NR_stat 106 | ||
| 217 | __SYSCALL(__NR_stat, sys_newstat) | ||
| 218 | #define __NR_lstat 107 | ||
| 219 | __SYSCALL(__NR_lstat, sys_newlstat) | ||
| 220 | #define __NR_fstat 108 | ||
| 221 | __SYSCALL(__NR_fstat, sys_newfstat) | ||
| 222 | __SYSCALL(109, sys_ni_syscall) /* 109 was sys_uname */ | ||
| 223 | __SYSCALL(110, sys_ni_syscall) /* 110 was sys_iopl */ | ||
| 224 | #define __NR_vhangup 111 | ||
| 225 | __SYSCALL(__NR_vhangup, sys_vhangup) | ||
| 226 | __SYSCALL(112, sys_ni_syscall) /* 112 was sys_idle */ | ||
| 227 | __SYSCALL(113, sys_ni_syscall) /* 113 was sys_syscall */ | ||
| 228 | #define __NR_wait4 114 | ||
| 229 | __SYSCALL(__NR_wait4, sys_wait4) | ||
| 230 | #define __NR_swapoff 115 | ||
| 231 | __SYSCALL(__NR_swapoff, sys_swapoff) | ||
| 232 | #define __NR_sysinfo 116 | ||
| 233 | __SYSCALL(__NR_sysinfo, sys_sysinfo) | ||
| 234 | __SYSCALL(117, sys_ni_syscall) /* 117 was sys_ipc */ | ||
| 235 | #define __NR_fsync 118 | ||
| 236 | __SYSCALL(__NR_fsync, sys_fsync) | ||
| 237 | #define __NR_sigreturn 119 | ||
| 238 | __SYSCALL(__NR_sigreturn, sys_sigreturn) | ||
| 239 | #define __NR_clone 120 | ||
| 240 | __SYSCALL(__NR_clone, sys_clone) | ||
| 241 | #define __NR_setdomainname 121 | ||
| 242 | __SYSCALL(__NR_setdomainname, sys_setdomainname) | ||
| 243 | #define __NR_uname 122 | ||
| 244 | __SYSCALL(__NR_uname, sys_newuname) | ||
| 245 | __SYSCALL(123, sys_ni_syscall) /* 123 was sys_modify_ldt */ | ||
| 246 | #define __NR_adjtimex 124 | ||
| 247 | __SYSCALL(__NR_adjtimex, sys_adjtimex) | ||
| 248 | #define __NR_mprotect 125 | ||
| 249 | __SYSCALL(__NR_mprotect, sys_mprotect) | ||
| 250 | #define __NR_sigprocmask 126 | ||
| 251 | __SYSCALL(__NR_sigprocmask, sys_sigprocmask) | ||
| 252 | __SYSCALL(127, sys_ni_syscall) /* 127 was sys_create_module */ | ||
| 253 | #define __NR_init_module 128 | ||
| 254 | __SYSCALL(__NR_init_module, sys_init_module) | ||
| 255 | #define __NR_delete_module 129 | ||
| 256 | __SYSCALL(__NR_delete_module, sys_delete_module) | ||
| 257 | __SYSCALL(130, sys_ni_syscall) /* 130 was sys_get_kernel_syms */ | ||
| 258 | #define __NR_quotactl 131 | ||
| 259 | __SYSCALL(__NR_quotactl, sys_quotactl) | ||
| 260 | #define __NR_getpgid 132 | ||
| 261 | __SYSCALL(__NR_getpgid, sys_getpgid) | ||
| 262 | #define __NR_fchdir 133 | ||
| 263 | __SYSCALL(__NR_fchdir, sys_fchdir) | ||
| 264 | #define __NR_bdflush 134 | ||
| 265 | __SYSCALL(__NR_bdflush, sys_bdflush) | ||
| 266 | #define __NR_sysfs 135 | ||
| 267 | __SYSCALL(__NR_sysfs, sys_sysfs) | ||
| 268 | #define __NR_personality 136 | ||
| 269 | __SYSCALL(__NR_personality, sys_personality) | ||
| 270 | __SYSCALL(137, sys_ni_syscall) /* 137 was sys_afs_syscall */ | ||
| 271 | #define __NR_setfsuid 138 | ||
| 272 | __SYSCALL(__NR_setfsuid, sys_setfsuid16) | ||
| 273 | #define __NR_setfsgid 139 | ||
| 274 | __SYSCALL(__NR_setfsgid, sys_setfsgid16) | ||
| 275 | #define __NR__llseek 140 | ||
| 276 | __SYSCALL(__NR__llseek, sys_llseek) | ||
| 277 | #define __NR_getdents 141 | ||
| 278 | __SYSCALL(__NR_getdents, sys_getdents) | ||
| 279 | #define __NR__newselect 142 | ||
| 280 | __SYSCALL(__NR__newselect, sys_select) | ||
| 281 | #define __NR_flock 143 | ||
| 282 | __SYSCALL(__NR_flock, sys_flock) | ||
| 283 | #define __NR_msync 144 | ||
| 284 | __SYSCALL(__NR_msync, sys_msync) | ||
| 285 | #define __NR_readv 145 | ||
| 286 | __SYSCALL(__NR_readv, sys_readv) | ||
| 287 | #define __NR_writev 146 | ||
| 288 | __SYSCALL(__NR_writev, sys_writev) | ||
| 289 | #define __NR_getsid 147 | ||
| 290 | __SYSCALL(__NR_getsid, sys_getsid) | ||
| 291 | #define __NR_fdatasync 148 | ||
| 292 | __SYSCALL(__NR_fdatasync, sys_fdatasync) | ||
| 293 | #define __NR__sysctl 149 | ||
| 294 | __SYSCALL(__NR__sysctl, sys_sysctl) | ||
| 295 | #define __NR_mlock 150 | ||
| 296 | __SYSCALL(__NR_mlock, sys_mlock) | ||
| 297 | #define __NR_munlock 151 | ||
| 298 | __SYSCALL(__NR_munlock, sys_munlock) | ||
| 299 | #define __NR_mlockall 152 | ||
| 300 | __SYSCALL(__NR_mlockall, sys_mlockall) | ||
| 301 | #define __NR_munlockall 153 | ||
| 302 | __SYSCALL(__NR_munlockall, sys_munlockall) | ||
| 303 | #define __NR_sched_setparam 154 | ||
| 304 | __SYSCALL(__NR_sched_setparam, sys_sched_setparam) | ||
| 305 | #define __NR_sched_getparam 155 | ||
| 306 | __SYSCALL(__NR_sched_getparam, sys_sched_getparam) | ||
| 307 | #define __NR_sched_setscheduler 156 | ||
| 308 | __SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler) | ||
| 309 | #define __NR_sched_getscheduler 157 | ||
| 310 | __SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler) | ||
| 311 | #define __NR_sched_yield 158 | ||
| 312 | __SYSCALL(__NR_sched_yield, sys_sched_yield) | ||
| 313 | #define __NR_sched_get_priority_max 159 | ||
| 314 | __SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max) | ||
| 315 | #define __NR_sched_get_priority_min 160 | ||
| 316 | __SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min) | ||
| 317 | #define __NR_sched_rr_get_interval 161 | ||
| 318 | __SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval) | ||
| 319 | #define __NR_nanosleep 162 | ||
| 320 | __SYSCALL(__NR_nanosleep, sys_nanosleep) | ||
| 321 | #define __NR_mremap 163 | ||
| 322 | __SYSCALL(__NR_mremap, sys_mremap) | ||
| 323 | #define __NR_setresuid 164 | ||
| 324 | __SYSCALL(__NR_setresuid, sys_setresuid16) | ||
| 325 | #define __NR_getresuid 165 | ||
| 326 | __SYSCALL(__NR_getresuid, sys_getresuid16) | ||
| 327 | __SYSCALL(166, sys_ni_syscall) /* 166 was sys_vm86 */ | ||
| 328 | __SYSCALL(167, sys_ni_syscall) /* 167 was sys_query_module */ | ||
| 329 | #define __NR_poll 168 | ||
| 330 | __SYSCALL(__NR_poll, sys_poll) | ||
| 331 | #define __NR_nfsservctl 169 | ||
| 332 | __SYSCALL(__NR_nfsservctl, sys_ni_syscall) | ||
| 333 | #define __NR_setresgid 170 | ||
| 334 | __SYSCALL(__NR_setresgid, sys_setresgid16) | ||
| 335 | #define __NR_getresgid 171 | ||
| 336 | __SYSCALL(__NR_getresgid, sys_getresgid16) | ||
| 337 | #define __NR_prctl 172 | ||
| 338 | __SYSCALL(__NR_prctl, sys_prctl) | ||
| 339 | #define __NR_rt_sigreturn 173 | ||
| 340 | __SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn) | ||
| 341 | #define __NR_rt_sigaction 174 | ||
| 342 | __SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) | ||
| 343 | #define __NR_rt_sigprocmask 175 | ||
| 344 | __SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask) | ||
| 345 | #define __NR_rt_sigpending 176 | ||
| 346 | __SYSCALL(__NR_rt_sigpending, sys_rt_sigpending) | ||
| 347 | #define __NR_rt_sigtimedwait 177 | ||
| 348 | __SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait) | ||
| 349 | #define __NR_rt_sigqueueinfo 178 | ||
| 350 | __SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo) | ||
| 351 | #define __NR_rt_sigsuspend 179 | ||
| 352 | __SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) | ||
| 353 | #define __NR_pread64 180 | ||
| 354 | __SYSCALL(__NR_pread64, sys_pread64) | ||
| 355 | #define __NR_pwrite64 181 | ||
| 356 | __SYSCALL(__NR_pwrite64, sys_pwrite64) | ||
| 357 | #define __NR_chown 182 | ||
| 358 | __SYSCALL(__NR_chown, sys_chown16) | ||
| 359 | #define __NR_getcwd 183 | ||
| 360 | __SYSCALL(__NR_getcwd, sys_getcwd) | ||
| 361 | #define __NR_capget 184 | ||
| 362 | __SYSCALL(__NR_capget, sys_capget) | ||
| 363 | #define __NR_capset 185 | ||
| 364 | __SYSCALL(__NR_capset, sys_capset) | ||
| 365 | #define __NR_sigaltstack 186 | ||
| 366 | __SYSCALL(__NR_sigaltstack, sys_sigaltstack) | ||
| 367 | #define __NR_sendfile 187 | ||
| 368 | __SYSCALL(__NR_sendfile, sys_sendfile) | ||
| 369 | __SYSCALL(188, sys_ni_syscall) /* 188 reserved */ | ||
| 370 | __SYSCALL(189, sys_ni_syscall) /* 189 reserved */ | ||
| 371 | #define __NR_vfork 190 | ||
| 372 | __SYSCALL(__NR_vfork, sys_vfork) | ||
| 373 | #define __NR_ugetrlimit 191 /* SuS compliant getrlimit */ | ||
| 374 | __SYSCALL(__NR_ugetrlimit, sys_getrlimit) | ||
| 375 | #define __NR_mmap2 192 | ||
| 376 | __SYSCALL(__NR_mmap2, sys_mmap2) | ||
| 377 | #define __NR_truncate64 193 | ||
| 378 | __SYSCALL(__NR_truncate64, sys_truncate64) | ||
| 379 | #define __NR_ftruncate64 194 | ||
| 380 | __SYSCALL(__NR_ftruncate64, sys_ftruncate64) | ||
| 381 | #define __NR_stat64 195 | ||
| 382 | __SYSCALL(__NR_stat64, sys_stat64) | ||
| 383 | #define __NR_lstat64 196 | ||
| 384 | __SYSCALL(__NR_lstat64, sys_lstat64) | ||
| 385 | #define __NR_fstat64 197 | ||
| 386 | __SYSCALL(__NR_fstat64, sys_fstat64) | ||
| 387 | #define __NR_lchown32 198 | ||
| 388 | __SYSCALL(__NR_lchown32, sys_lchown) | ||
| 389 | #define __NR_getuid32 199 | ||
| 390 | __SYSCALL(__NR_getuid32, sys_getuid) | ||
| 391 | #define __NR_getgid32 200 | ||
| 392 | __SYSCALL(__NR_getgid32, sys_getgid) | ||
| 393 | #define __NR_geteuid32 201 | ||
| 394 | __SYSCALL(__NR_geteuid32, sys_geteuid) | ||
| 395 | #define __NR_getegid32 202 | ||
| 396 | __SYSCALL(__NR_getegid32, sys_getegid) | ||
| 397 | #define __NR_setreuid32 203 | ||
| 398 | __SYSCALL(__NR_setreuid32, sys_setreuid) | ||
| 399 | #define __NR_setregid32 204 | ||
| 400 | __SYSCALL(__NR_setregid32, sys_setregid) | ||
| 401 | #define __NR_getgroups32 205 | ||
| 402 | __SYSCALL(__NR_getgroups32, sys_getgroups) | ||
| 403 | #define __NR_setgroups32 206 | ||
| 404 | __SYSCALL(__NR_setgroups32, sys_setgroups) | ||
| 405 | #define __NR_fchown32 207 | ||
| 406 | __SYSCALL(__NR_fchown32, sys_fchown) | ||
| 407 | #define __NR_setresuid32 208 | ||
| 408 | __SYSCALL(__NR_setresuid32, sys_setresuid) | ||
| 409 | #define __NR_getresuid32 209 | ||
| 410 | __SYSCALL(__NR_getresuid32, sys_getresuid) | ||
| 411 | #define __NR_setresgid32 210 | ||
| 412 | __SYSCALL(__NR_setresgid32, sys_setresgid) | ||
| 413 | #define __NR_getresgid32 211 | ||
| 414 | __SYSCALL(__NR_getresgid32, sys_getresgid) | ||
| 415 | #define __NR_chown32 212 | ||
| 416 | __SYSCALL(__NR_chown32, sys_chown) | ||
| 417 | #define __NR_setuid32 213 | ||
| 418 | __SYSCALL(__NR_setuid32, sys_setuid) | ||
| 419 | #define __NR_setgid32 214 | ||
| 420 | __SYSCALL(__NR_setgid32, sys_setgid) | ||
| 421 | #define __NR_setfsuid32 215 | ||
| 422 | __SYSCALL(__NR_setfsuid32, sys_setfsuid) | ||
| 423 | #define __NR_setfsgid32 216 | ||
| 424 | __SYSCALL(__NR_setfsgid32, sys_setfsgid) | ||
| 425 | #define __NR_getdents64 217 | ||
| 426 | __SYSCALL(__NR_getdents64, sys_getdents64) | ||
| 427 | #define __NR_pivot_root 218 | ||
| 428 | __SYSCALL(__NR_pivot_root, sys_pivot_root) | ||
| 429 | #define __NR_mincore 219 | ||
| 430 | __SYSCALL(__NR_mincore, sys_mincore) | ||
| 431 | #define __NR_madvise 220 | ||
| 432 | __SYSCALL(__NR_madvise, sys_madvise) | ||
| 433 | #define __NR_fcntl64 221 | ||
| 434 | __SYSCALL(__NR_fcntl64, sys_fcntl64) | ||
| 435 | __SYSCALL(222, sys_ni_syscall) /* 222 for tux */ | ||
| 436 | __SYSCALL(223, sys_ni_syscall) /* 223 is unused */ | ||
| 437 | #define __NR_gettid 224 | ||
| 438 | __SYSCALL(__NR_gettid, sys_gettid) | ||
| 439 | #define __NR_readahead 225 | ||
| 440 | __SYSCALL(__NR_readahead, sys_readahead) | ||
| 441 | #define __NR_setxattr 226 | ||
| 442 | __SYSCALL(__NR_setxattr, sys_setxattr) | ||
| 443 | #define __NR_lsetxattr 227 | ||
| 444 | __SYSCALL(__NR_lsetxattr, sys_lsetxattr) | ||
| 445 | #define __NR_fsetxattr 228 | ||
| 446 | __SYSCALL(__NR_fsetxattr, sys_fsetxattr) | ||
| 447 | #define __NR_getxattr 229 | ||
| 448 | __SYSCALL(__NR_getxattr, sys_getxattr) | ||
| 449 | #define __NR_lgetxattr 230 | ||
| 450 | __SYSCALL(__NR_lgetxattr, sys_lgetxattr) | ||
| 451 | #define __NR_fgetxattr 231 | ||
| 452 | __SYSCALL(__NR_fgetxattr, sys_fgetxattr) | ||
| 453 | #define __NR_listxattr 232 | ||
| 454 | __SYSCALL(__NR_listxattr, sys_listxattr) | ||
| 455 | #define __NR_llistxattr 233 | ||
| 456 | __SYSCALL(__NR_llistxattr, sys_llistxattr) | ||
| 457 | #define __NR_flistxattr 234 | ||
| 458 | __SYSCALL(__NR_flistxattr, sys_flistxattr) | ||
| 459 | #define __NR_removexattr 235 | ||
| 460 | __SYSCALL(__NR_removexattr, sys_removexattr) | ||
| 461 | #define __NR_lremovexattr 236 | ||
| 462 | __SYSCALL(__NR_lremovexattr, sys_lremovexattr) | ||
| 463 | #define __NR_fremovexattr 237 | ||
| 464 | __SYSCALL(__NR_fremovexattr, sys_fremovexattr) | ||
| 465 | #define __NR_tkill 238 | ||
| 466 | __SYSCALL(__NR_tkill, sys_tkill) | ||
| 467 | #define __NR_sendfile64 239 | ||
| 468 | __SYSCALL(__NR_sendfile64, sys_sendfile64) | ||
| 469 | #define __NR_futex 240 | ||
| 470 | __SYSCALL(__NR_futex, sys_futex) | ||
| 471 | #define __NR_sched_setaffinity 241 | ||
| 472 | __SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity) | ||
| 473 | #define __NR_sched_getaffinity 242 | ||
| 474 | __SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity) | ||
| 475 | #define __NR_io_setup 243 | ||
| 476 | __SYSCALL(__NR_io_setup, sys_io_setup) | ||
| 477 | #define __NR_io_destroy 244 | ||
| 478 | __SYSCALL(__NR_io_destroy, sys_io_destroy) | ||
| 479 | #define __NR_io_getevents 245 | ||
| 480 | __SYSCALL(__NR_io_getevents, sys_io_getevents) | ||
| 481 | #define __NR_io_submit 246 | ||
| 482 | __SYSCALL(__NR_io_submit, sys_io_submit) | ||
| 483 | #define __NR_io_cancel 247 | ||
| 484 | __SYSCALL(__NR_io_cancel, sys_io_cancel) | ||
| 485 | #define __NR_exit_group 248 | ||
| 486 | __SYSCALL(__NR_exit_group, sys_exit_group) | ||
| 487 | #define __NR_lookup_dcookie 249 | ||
| 488 | __SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie) | ||
| 489 | #define __NR_epoll_create 250 | ||
| 490 | __SYSCALL(__NR_epoll_create, sys_epoll_create) | ||
| 491 | #define __NR_epoll_ctl 251 | ||
| 492 | __SYSCALL(__NR_epoll_ctl, sys_epoll_ctl) | ||
| 493 | #define __NR_epoll_wait 252 | ||
| 494 | __SYSCALL(__NR_epoll_wait, sys_epoll_wait) | ||
| 495 | #define __NR_remap_file_pages 253 | ||
| 496 | __SYSCALL(__NR_remap_file_pages, sys_remap_file_pages) | ||
| 497 | __SYSCALL(254, sys_ni_syscall) /* 254 for set_thread_area */ | ||
| 498 | __SYSCALL(255, sys_ni_syscall) /* 255 for get_thread_area */ | ||
| 499 | #define __NR_set_tid_address 256 | ||
| 500 | __SYSCALL(__NR_set_tid_address, sys_set_tid_address) | ||
| 501 | #define __NR_timer_create 257 | ||
| 502 | __SYSCALL(__NR_timer_create, sys_timer_create) | ||
| 503 | #define __NR_timer_settime 258 | ||
| 504 | __SYSCALL(__NR_timer_settime, sys_timer_settime) | ||
| 505 | #define __NR_timer_gettime 259 | ||
| 506 | __SYSCALL(__NR_timer_gettime, sys_timer_gettime) | ||
| 507 | #define __NR_timer_getoverrun 260 | ||
| 508 | __SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun) | ||
| 509 | #define __NR_timer_delete 261 | ||
| 510 | __SYSCALL(__NR_timer_delete, sys_timer_delete) | ||
| 511 | #define __NR_clock_settime 262 | ||
| 512 | __SYSCALL(__NR_clock_settime, sys_clock_settime) | ||
| 513 | #define __NR_clock_gettime 263 | ||
| 514 | __SYSCALL(__NR_clock_gettime, sys_clock_gettime) | ||
| 515 | #define __NR_clock_getres 264 | ||
| 516 | __SYSCALL(__NR_clock_getres, sys_clock_getres) | ||
| 517 | #define __NR_clock_nanosleep 265 | ||
| 518 | __SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep) | ||
| 519 | #define __NR_statfs64 266 | ||
| 520 | __SYSCALL(__NR_statfs64, sys_statfs64) | ||
| 521 | #define __NR_fstatfs64 267 | ||
| 522 | __SYSCALL(__NR_fstatfs64, sys_fstatfs64) | ||
| 523 | #define __NR_tgkill 268 | ||
| 524 | __SYSCALL(__NR_tgkill, sys_tgkill) | ||
| 525 | #define __NR_utimes 269 | ||
| 526 | __SYSCALL(__NR_utimes, sys_utimes) | ||
| 527 | #define __NR_fadvise64 270 | ||
| 528 | __SYSCALL(__NR_fadvise64, sys_fadvise64_64) | ||
| 529 | #define __NR_pciconfig_iobase 271 | ||
| 530 | __SYSCALL(__NR_pciconfig_iobase, sys_pciconfig_iobase) | ||
| 531 | #define __NR_pciconfig_read 272 | ||
| 532 | __SYSCALL(__NR_pciconfig_read, sys_pciconfig_read) | ||
| 533 | #define __NR_pciconfig_write 273 | ||
| 534 | __SYSCALL(__NR_pciconfig_write, sys_pciconfig_write) | ||
| 535 | #define __NR_mq_open 274 | ||
| 536 | __SYSCALL(__NR_mq_open, sys_mq_open) | ||
| 537 | #define __NR_mq_unlink 275 | ||
| 538 | __SYSCALL(__NR_mq_unlink, sys_mq_unlink) | ||
| 539 | #define __NR_mq_timedsend 276 | ||
| 540 | __SYSCALL(__NR_mq_timedsend, sys_mq_timedsend) | ||
| 541 | #define __NR_mq_timedreceive 277 | ||
| 542 | __SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive) | ||
| 543 | #define __NR_mq_notify 278 | ||
| 544 | __SYSCALL(__NR_mq_notify, sys_mq_notify) | ||
| 545 | #define __NR_mq_getsetattr 279 | ||
| 546 | __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr) | ||
| 547 | #define __NR_waitid 280 | ||
| 548 | __SYSCALL(__NR_waitid, sys_waitid) | ||
| 549 | #define __NR_socket 281 | ||
| 550 | __SYSCALL(__NR_socket, sys_socket) | ||
| 551 | #define __NR_bind 282 | ||
| 552 | __SYSCALL(__NR_bind, sys_bind) | ||
| 553 | #define __NR_connect 283 | ||
| 554 | __SYSCALL(__NR_connect, sys_connect) | ||
| 555 | #define __NR_listen 284 | ||
| 556 | __SYSCALL(__NR_listen, sys_listen) | ||
| 557 | #define __NR_accept 285 | ||
| 558 | __SYSCALL(__NR_accept, sys_accept) | ||
| 559 | #define __NR_getsockname 286 | ||
| 560 | __SYSCALL(__NR_getsockname, sys_getsockname) | ||
| 561 | #define __NR_getpeername 287 | ||
| 562 | __SYSCALL(__NR_getpeername, sys_getpeername) | ||
| 563 | #define __NR_socketpair 288 | ||
| 564 | __SYSCALL(__NR_socketpair, sys_socketpair) | ||
| 565 | #define __NR_send 289 | ||
| 566 | __SYSCALL(__NR_send, sys_send) | ||
| 567 | #define __NR_sendto 290 | ||
| 568 | __SYSCALL(__NR_sendto, sys_sendto) | ||
| 569 | #define __NR_recv 291 | ||
| 570 | __SYSCALL(__NR_recv, sys_recv) | ||
| 571 | #define __NR_recvfrom 292 | ||
| 572 | __SYSCALL(__NR_recvfrom, sys_recvfrom) | ||
| 573 | #define __NR_shutdown 293 | ||
| 574 | __SYSCALL(__NR_shutdown, sys_shutdown) | ||
| 575 | #define __NR_setsockopt 294 | ||
| 576 | __SYSCALL(__NR_setsockopt, sys_setsockopt) | ||
| 577 | #define __NR_getsockopt 295 | ||
| 578 | __SYSCALL(__NR_getsockopt, sys_getsockopt) | ||
| 579 | #define __NR_sendmsg 296 | ||
| 580 | __SYSCALL(__NR_sendmsg, sys_sendmsg) | ||
| 581 | #define __NR_recvmsg 297 | ||
| 582 | __SYSCALL(__NR_recvmsg, sys_recvmsg) | ||
| 583 | #define __NR_semop 298 | ||
| 584 | __SYSCALL(__NR_semop, sys_semop) | ||
| 585 | #define __NR_semget 299 | ||
| 586 | __SYSCALL(__NR_semget, sys_semget) | ||
| 587 | #define __NR_semctl 300 | ||
| 588 | __SYSCALL(__NR_semctl, sys_semctl) | ||
| 589 | #define __NR_msgsnd 301 | ||
| 590 | __SYSCALL(__NR_msgsnd, sys_msgsnd) | ||
| 591 | #define __NR_msgrcv 302 | ||
| 592 | __SYSCALL(__NR_msgrcv, sys_msgrcv) | ||
| 593 | #define __NR_msgget 303 | ||
| 594 | __SYSCALL(__NR_msgget, sys_msgget) | ||
| 595 | #define __NR_msgctl 304 | ||
| 596 | __SYSCALL(__NR_msgctl, sys_msgctl) | ||
| 597 | #define __NR_shmat 305 | ||
| 598 | __SYSCALL(__NR_shmat, sys_shmat) | ||
| 599 | #define __NR_shmdt 306 | ||
| 600 | __SYSCALL(__NR_shmdt, sys_shmdt) | ||
| 601 | #define __NR_shmget 307 | ||
| 602 | __SYSCALL(__NR_shmget, sys_shmget) | ||
| 603 | #define __NR_shmctl 308 | ||
| 604 | __SYSCALL(__NR_shmctl, sys_shmctl) | ||
| 605 | #define __NR_add_key 309 | ||
| 606 | __SYSCALL(__NR_add_key, sys_add_key) | ||
| 607 | #define __NR_request_key 310 | ||
| 608 | __SYSCALL(__NR_request_key, sys_request_key) | ||
| 609 | #define __NR_keyctl 311 | ||
| 610 | __SYSCALL(__NR_keyctl, sys_keyctl) | ||
| 611 | #define __NR_semtimedop 312 | ||
| 612 | __SYSCALL(__NR_semtimedop, sys_semtimedop) | ||
| 613 | #define __NR_vserver 313 | ||
| 614 | __SYSCALL(__NR_vserver, sys_ni_syscall) | ||
| 615 | #define __NR_ioprio_set 314 | ||
| 616 | __SYSCALL(__NR_ioprio_set, sys_ioprio_set) | ||
| 617 | #define __NR_ioprio_get 315 | ||
| 618 | __SYSCALL(__NR_ioprio_get, sys_ioprio_get) | ||
| 619 | #define __NR_inotify_init 316 | ||
| 620 | __SYSCALL(__NR_inotify_init, sys_inotify_init) | ||
| 621 | #define __NR_inotify_add_watch 317 | ||
| 622 | __SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) | ||
| 623 | #define __NR_inotify_rm_watch 318 | ||
| 624 | __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) | ||
| 625 | #define __NR_mbind 319 | ||
| 626 | __SYSCALL(__NR_mbind, sys_mbind) | ||
| 627 | #define __NR_get_mempolicy 320 | ||
| 628 | __SYSCALL(__NR_get_mempolicy, sys_get_mempolicy) | ||
| 629 | #define __NR_set_mempolicy 321 | ||
| 630 | __SYSCALL(__NR_set_mempolicy, sys_set_mempolicy) | ||
| 631 | #define __NR_openat 322 | ||
| 632 | __SYSCALL(__NR_openat, sys_openat) | ||
| 633 | #define __NR_mkdirat 323 | ||
| 634 | __SYSCALL(__NR_mkdirat, sys_mkdirat) | ||
| 635 | #define __NR_mknodat 324 | ||
| 636 | __SYSCALL(__NR_mknodat, sys_mknodat) | ||
| 637 | #define __NR_fchownat 325 | ||
| 638 | __SYSCALL(__NR_fchownat, sys_fchownat) | ||
| 639 | #define __NR_futimesat 326 | ||
| 640 | __SYSCALL(__NR_futimesat, sys_futimesat) | ||
| 641 | #define __NR_fstatat64 327 | ||
| 642 | __SYSCALL(__NR_fstatat64, sys_fstatat64) | ||
| 643 | #define __NR_unlinkat 328 | ||
| 644 | __SYSCALL(__NR_unlinkat, sys_unlinkat) | ||
| 645 | #define __NR_renameat 329 | ||
| 646 | __SYSCALL(__NR_renameat, sys_renameat) | ||
| 647 | #define __NR_linkat 330 | ||
| 648 | __SYSCALL(__NR_linkat, sys_linkat) | ||
| 649 | #define __NR_symlinkat 331 | ||
| 650 | __SYSCALL(__NR_symlinkat, sys_symlinkat) | ||
| 651 | #define __NR_readlinkat 332 | ||
| 652 | __SYSCALL(__NR_readlinkat, sys_readlinkat) | ||
| 653 | #define __NR_fchmodat 333 | ||
| 654 | __SYSCALL(__NR_fchmodat, sys_fchmodat) | ||
| 655 | #define __NR_faccessat 334 | ||
| 656 | __SYSCALL(__NR_faccessat, sys_faccessat) | ||
| 657 | #define __NR_pselect6 335 | ||
| 658 | __SYSCALL(__NR_pselect6, sys_pselect6) | ||
| 659 | #define __NR_ppoll 336 | ||
| 660 | __SYSCALL(__NR_ppoll, sys_ppoll) | ||
| 661 | #define __NR_unshare 337 | ||
| 662 | __SYSCALL(__NR_unshare, sys_unshare) | ||
| 663 | #define __NR_set_robust_list 338 | ||
| 664 | __SYSCALL(__NR_set_robust_list, sys_set_robust_list) | ||
| 665 | #define __NR_get_robust_list 339 | ||
| 666 | __SYSCALL(__NR_get_robust_list, sys_get_robust_list) | ||
| 667 | #define __NR_splice 340 | ||
| 668 | __SYSCALL(__NR_splice, sys_splice) | ||
| 669 | #define __NR_sync_file_range2 341 | ||
| 670 | __SYSCALL(__NR_sync_file_range2, sys_sync_file_range2) | ||
| 671 | #define __NR_tee 342 | ||
| 672 | __SYSCALL(__NR_tee, sys_tee) | ||
| 673 | #define __NR_vmsplice 343 | ||
| 674 | __SYSCALL(__NR_vmsplice, sys_vmsplice) | ||
| 675 | #define __NR_move_pages 344 | ||
| 676 | __SYSCALL(__NR_move_pages, sys_move_pages) | ||
| 677 | #define __NR_getcpu 345 | ||
| 678 | __SYSCALL(__NR_getcpu, sys_getcpu) | ||
| 679 | #define __NR_epoll_pwait 346 | ||
| 680 | __SYSCALL(__NR_epoll_pwait, sys_epoll_pwait) | ||
| 681 | #define __NR_kexec_load 347 | ||
| 682 | __SYSCALL(__NR_kexec_load, sys_kexec_load) | ||
| 683 | #define __NR_utimensat 348 | ||
| 684 | __SYSCALL(__NR_utimensat, sys_utimensat) | ||
| 685 | #define __NR_signalfd 349 | ||
| 686 | __SYSCALL(__NR_signalfd, sys_signalfd) | ||
| 687 | #define __NR_timerfd_create 350 | ||
| 688 | __SYSCALL(__NR_timerfd_create, sys_timerfd_create) | ||
| 689 | #define __NR_eventfd 351 | ||
| 690 | __SYSCALL(__NR_eventfd, sys_eventfd) | ||
| 691 | #define __NR_fallocate 352 | ||
| 692 | __SYSCALL(__NR_fallocate, sys_fallocate) | ||
| 693 | #define __NR_timerfd_settime 353 | ||
| 694 | __SYSCALL(__NR_timerfd_settime, sys_timerfd_settime) | ||
| 695 | #define __NR_timerfd_gettime 354 | ||
| 696 | __SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime) | ||
| 697 | #define __NR_signalfd4 355 | ||
| 698 | __SYSCALL(__NR_signalfd4, sys_signalfd4) | ||
| 699 | #define __NR_eventfd2 356 | ||
| 700 | __SYSCALL(__NR_eventfd2, sys_eventfd2) | ||
| 701 | #define __NR_epoll_create1 357 | ||
| 702 | __SYSCALL(__NR_epoll_create1, sys_epoll_create1) | ||
| 703 | #define __NR_dup3 358 | ||
| 704 | __SYSCALL(__NR_dup3, sys_dup3) | ||
| 705 | #define __NR_pipe2 359 | ||
| 706 | __SYSCALL(__NR_pipe2, sys_pipe2) | ||
| 707 | #define __NR_inotify_init1 360 | ||
| 708 | __SYSCALL(__NR_inotify_init1, sys_inotify_init1) | ||
| 709 | #define __NR_preadv 361 | ||
| 710 | __SYSCALL(__NR_preadv, sys_preadv) | ||
| 711 | #define __NR_pwritev 362 | ||
| 712 | __SYSCALL(__NR_pwritev, sys_pwritev) | ||
| 713 | #define __NR_rt_tgsigqueueinfo 363 | ||
| 714 | __SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo) | ||
| 715 | #define __NR_perf_event_open 364 | ||
| 716 | __SYSCALL(__NR_perf_event_open, sys_perf_event_open) | ||
| 717 | #define __NR_recvmmsg 365 | ||
| 718 | __SYSCALL(__NR_recvmmsg, sys_recvmmsg) | ||
| 719 | #define __NR_accept4 366 | ||
| 720 | __SYSCALL(__NR_accept4, sys_accept4) | ||
| 721 | #define __NR_fanotify_init 367 | ||
| 722 | __SYSCALL(__NR_fanotify_init, sys_fanotify_init) | ||
| 723 | #define __NR_fanotify_mark 368 | ||
| 724 | __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark) | ||
| 725 | #define __NR_prlimit64 369 | ||
| 726 | __SYSCALL(__NR_prlimit64, sys_prlimit64) | ||
| 727 | #define __NR_name_to_handle_at 370 | ||
| 728 | __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at) | ||
| 729 | #define __NR_open_by_handle_at 371 | ||
| 730 | __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at) | ||
| 731 | #define __NR_clock_adjtime 372 | ||
| 732 | __SYSCALL(__NR_clock_adjtime, sys_clock_adjtime) | ||
| 733 | #define __NR_syncfs 373 | ||
| 734 | __SYSCALL(__NR_syncfs, sys_syncfs) | ||
| 735 | |||
| 736 | /* | ||
| 737 | * The following SVCs are ARM private. | ||
| 738 | */ | ||
| 739 | #define __ARM_NR_COMPAT_BASE 0x0f0000 | ||
| 740 | #define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) | ||
| 741 | #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) | ||
| 742 | |||
| 743 | #endif /* __SYSCALL_COMPAT */ | ||
| 744 | |||
| 745 | #define __NR_compat_syscalls 374 | ||
| 746 | |||
| 747 | #define __ARCH_WANT_COMPAT_IPC_PARSE_VERSION | ||
| 748 | #define __ARCH_WANT_COMPAT_STAT64 | ||
| 749 | #define __ARCH_WANT_SYS_GETHOSTNAME | ||
| 750 | #define __ARCH_WANT_SYS_PAUSE | ||
| 751 | #define __ARCH_WANT_SYS_GETPGRP | ||
| 752 | #define __ARCH_WANT_SYS_LLSEEK | ||
| 753 | #define __ARCH_WANT_SYS_NICE | ||
| 754 | #define __ARCH_WANT_SYS_SIGPENDING | ||
| 755 | #define __ARCH_WANT_SYS_SIGPROCMASK | ||
| 756 | #define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND | ||
| 757 | |||
| 758 | #endif /* __ASM_UNISTD32_H */ | ||
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h new file mode 100644 index 000000000000..839ce0031bd5 --- /dev/null +++ b/arch/arm64/include/asm/vdso.h | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Limited | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_VDSO_H | ||
| 17 | #define __ASM_VDSO_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Default link address for the vDSO. | ||
| 23 | * Since we randomise the VDSO mapping, there's little point in trying | ||
| 24 | * to prelink this. | ||
| 25 | */ | ||
| 26 | #define VDSO_LBASE 0x0 | ||
| 27 | |||
| 28 | #ifndef __ASSEMBLY__ | ||
| 29 | |||
| 30 | #include <generated/vdso-offsets.h> | ||
| 31 | |||
| 32 | #define VDSO_SYMBOL(base, name) \ | ||
| 33 | ({ \ | ||
| 34 | (void *)(vdso_offset_##name - VDSO_LBASE + (unsigned long)(base)); \ | ||
| 35 | }) | ||
| 36 | |||
| 37 | #endif /* !__ASSEMBLY__ */ | ||
| 38 | |||
| 39 | #endif /* __KERNEL__ */ | ||
| 40 | |||
| 41 | #endif /* __ASM_VDSO_H */ | ||
diff --git a/arch/arm64/include/asm/vdso_datapage.h b/arch/arm64/include/asm/vdso_datapage.h new file mode 100644 index 000000000000..de66199673d7 --- /dev/null +++ b/arch/arm64/include/asm/vdso_datapage.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Limited | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __ASM_VDSO_DATAPAGE_H | ||
| 17 | #define __ASM_VDSO_DATAPAGE_H | ||
| 18 | |||
| 19 | #ifdef __KERNEL__ | ||
| 20 | |||
| 21 | #ifndef __ASSEMBLY__ | ||
| 22 | |||
| 23 | struct vdso_data { | ||
| 24 | __u64 cs_cycle_last; /* Timebase at clocksource init */ | ||
| 25 | __u64 xtime_clock_sec; /* Kernel time */ | ||
| 26 | __u64 xtime_clock_nsec; | ||
| 27 | __u64 xtime_coarse_sec; /* Coarse time */ | ||
| 28 | __u64 xtime_coarse_nsec; | ||
| 29 | __u64 wtm_clock_sec; /* Wall to monotonic time */ | ||
| 30 | __u64 wtm_clock_nsec; | ||
| 31 | __u32 tb_seq_count; /* Timebase sequence counter */ | ||
| 32 | __u32 cs_mult; /* Clocksource multiplier */ | ||
| 33 | __u32 cs_shift; /* Clocksource shift */ | ||
| 34 | __u32 tz_minuteswest; /* Whacky timezone stuff */ | ||
| 35 | __u32 tz_dsttime; | ||
| 36 | __u32 use_syscall; | ||
| 37 | }; | ||
| 38 | |||
| 39 | #endif /* !__ASSEMBLY__ */ | ||
| 40 | |||
| 41 | #endif /* __KERNEL__ */ | ||
| 42 | |||
| 43 | #endif /* __ASM_VDSO_DATAPAGE_H */ | ||
diff --git a/arch/arm64/kernel/.gitignore b/arch/arm64/kernel/.gitignore new file mode 100644 index 000000000000..c5f676c3c224 --- /dev/null +++ b/arch/arm64/kernel/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| vmlinux.lds | |||
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile new file mode 100644 index 000000000000..e2caff1b812a --- /dev/null +++ b/arch/arm64/kernel/Makefile | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the linux kernel. | ||
| 3 | # | ||
| 4 | |||
| 5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) | ||
| 6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | ||
| 7 | |||
| 8 | # Object file lists. | ||
| 9 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ | ||
| 10 | entry-fpsimd.o process.o ptrace.o setup.o signal.o \ | ||
| 11 | sys.o stacktrace.o time.o traps.o io.o vdso.o | ||
| 12 | |||
| 13 | arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ | ||
| 14 | sys_compat.o | ||
| 15 | arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o | ||
| 16 | arm64-obj-$(CONFIG_SMP) += smp.o | ||
| 17 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | ||
| 18 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o | ||
| 19 | |||
| 20 | obj-y += $(arm64-obj-y) vdso/ | ||
| 21 | obj-m += $(arm64-obj-m) | ||
| 22 | head-y := head.o | ||
| 23 | extra-y := $(head-y) vmlinux.lds | ||
| 24 | |||
| 25 | # vDSO - this must be built first to generate the symbol offsets | ||
| 26 | $(call objectify,$(arm64-obj-y)): $(obj)/vdso/vdso-offsets.h | ||
| 27 | $(obj)/vdso/vdso-offsets.h: $(obj)/vdso | ||
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c new file mode 100644 index 000000000000..cef3925eaf60 --- /dev/null +++ b/arch/arm64/kernel/arm64ksyms.c | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/armksyms.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/export.h> | ||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/string.h> | ||
| 23 | #include <linux/cryptohash.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/in6.h> | ||
| 26 | #include <linux/syscalls.h> | ||
| 27 | #include <linux/uaccess.h> | ||
| 28 | #include <linux/io.h> | ||
| 29 | |||
| 30 | #include <asm/checksum.h> | ||
| 31 | |||
| 32 | /* user mem (segment) */ | ||
| 33 | EXPORT_SYMBOL(__strnlen_user); | ||
| 34 | EXPORT_SYMBOL(__strncpy_from_user); | ||
| 35 | |||
| 36 | EXPORT_SYMBOL(copy_page); | ||
| 37 | |||
| 38 | EXPORT_SYMBOL(__copy_from_user); | ||
| 39 | EXPORT_SYMBOL(__copy_to_user); | ||
| 40 | EXPORT_SYMBOL(__clear_user); | ||
| 41 | |||
| 42 | /* bitops */ | ||
| 43 | EXPORT_SYMBOL(__atomic_hash); | ||
| 44 | |||
| 45 | /* physical memory */ | ||
| 46 | EXPORT_SYMBOL(memstart_addr); | ||
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c new file mode 100644 index 000000000000..a2a4d810bea3 --- /dev/null +++ b/arch/arm64/kernel/asm-offsets.c | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/asm-offsets.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2003 Russell King | ||
| 5 | * 2001-2002 Keith Owens | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/dma-mapping.h> | ||
| 24 | #include <asm/thread_info.h> | ||
| 25 | #include <asm/memory.h> | ||
| 26 | #include <asm/cputable.h> | ||
| 27 | #include <asm/vdso_datapage.h> | ||
| 28 | #include <linux/kbuild.h> | ||
| 29 | |||
| 30 | int main(void) | ||
| 31 | { | ||
| 32 | DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); | ||
| 33 | BLANK(); | ||
| 34 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | ||
| 35 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); | ||
| 36 | DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); | ||
| 37 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | ||
| 38 | DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain)); | ||
| 39 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | ||
| 40 | BLANK(); | ||
| 41 | DEFINE(THREAD_CPU_CONTEXT, offsetof(struct task_struct, thread.cpu_context)); | ||
| 42 | BLANK(); | ||
| 43 | DEFINE(S_X0, offsetof(struct pt_regs, regs[0])); | ||
| 44 | DEFINE(S_X1, offsetof(struct pt_regs, regs[1])); | ||
| 45 | DEFINE(S_X2, offsetof(struct pt_regs, regs[2])); | ||
| 46 | DEFINE(S_X3, offsetof(struct pt_regs, regs[3])); | ||
| 47 | DEFINE(S_X4, offsetof(struct pt_regs, regs[4])); | ||
| 48 | DEFINE(S_X5, offsetof(struct pt_regs, regs[5])); | ||
| 49 | DEFINE(S_X6, offsetof(struct pt_regs, regs[6])); | ||
| 50 | DEFINE(S_X7, offsetof(struct pt_regs, regs[7])); | ||
| 51 | DEFINE(S_LR, offsetof(struct pt_regs, regs[30])); | ||
| 52 | DEFINE(S_SP, offsetof(struct pt_regs, sp)); | ||
| 53 | #ifdef CONFIG_COMPAT | ||
| 54 | DEFINE(S_COMPAT_SP, offsetof(struct pt_regs, compat_sp)); | ||
| 55 | #endif | ||
| 56 | DEFINE(S_PSTATE, offsetof(struct pt_regs, pstate)); | ||
| 57 | DEFINE(S_PC, offsetof(struct pt_regs, pc)); | ||
| 58 | DEFINE(S_ORIG_X0, offsetof(struct pt_regs, orig_x0)); | ||
| 59 | DEFINE(S_SYSCALLNO, offsetof(struct pt_regs, syscallno)); | ||
| 60 | DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); | ||
| 61 | BLANK(); | ||
| 62 | DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); | ||
| 63 | BLANK(); | ||
| 64 | DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm)); | ||
| 65 | DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags)); | ||
| 66 | BLANK(); | ||
| 67 | DEFINE(VM_EXEC, VM_EXEC); | ||
| 68 | BLANK(); | ||
| 69 | DEFINE(PAGE_SZ, PAGE_SIZE); | ||
| 70 | BLANK(); | ||
| 71 | DEFINE(CPU_INFO_SZ, sizeof(struct cpu_info)); | ||
| 72 | DEFINE(CPU_INFO_SETUP, offsetof(struct cpu_info, cpu_setup)); | ||
| 73 | BLANK(); | ||
| 74 | DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); | ||
| 75 | DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); | ||
| 76 | DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE); | ||
| 77 | BLANK(); | ||
| 78 | DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); | ||
| 79 | DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); | ||
| 80 | DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); | ||
| 81 | DEFINE(CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE); | ||
| 82 | DEFINE(CLOCK_MONOTONIC_COARSE,CLOCK_MONOTONIC_COARSE); | ||
| 83 | DEFINE(CLOCK_COARSE_RES, LOW_RES_NSEC); | ||
| 84 | DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); | ||
| 85 | BLANK(); | ||
| 86 | DEFINE(VDSO_CS_CYCLE_LAST, offsetof(struct vdso_data, cs_cycle_last)); | ||
| 87 | DEFINE(VDSO_XTIME_CLK_SEC, offsetof(struct vdso_data, xtime_clock_sec)); | ||
| 88 | DEFINE(VDSO_XTIME_CLK_NSEC, offsetof(struct vdso_data, xtime_clock_nsec)); | ||
| 89 | DEFINE(VDSO_XTIME_CRS_SEC, offsetof(struct vdso_data, xtime_coarse_sec)); | ||
| 90 | DEFINE(VDSO_XTIME_CRS_NSEC, offsetof(struct vdso_data, xtime_coarse_nsec)); | ||
| 91 | DEFINE(VDSO_WTM_CLK_SEC, offsetof(struct vdso_data, wtm_clock_sec)); | ||
| 92 | DEFINE(VDSO_WTM_CLK_NSEC, offsetof(struct vdso_data, wtm_clock_nsec)); | ||
| 93 | DEFINE(VDSO_TB_SEQ_COUNT, offsetof(struct vdso_data, tb_seq_count)); | ||
| 94 | DEFINE(VDSO_CS_MULT, offsetof(struct vdso_data, cs_mult)); | ||
| 95 | DEFINE(VDSO_CS_SHIFT, offsetof(struct vdso_data, cs_shift)); | ||
| 96 | DEFINE(VDSO_TZ_MINWEST, offsetof(struct vdso_data, tz_minuteswest)); | ||
| 97 | DEFINE(VDSO_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime)); | ||
| 98 | DEFINE(VDSO_USE_SYSCALL, offsetof(struct vdso_data, use_syscall)); | ||
| 99 | BLANK(); | ||
| 100 | DEFINE(TVAL_TV_SEC, offsetof(struct timeval, tv_sec)); | ||
| 101 | DEFINE(TVAL_TV_USEC, offsetof(struct timeval, tv_usec)); | ||
| 102 | DEFINE(TSPEC_TV_SEC, offsetof(struct timespec, tv_sec)); | ||
| 103 | DEFINE(TSPEC_TV_NSEC, offsetof(struct timespec, tv_nsec)); | ||
| 104 | BLANK(); | ||
| 105 | DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); | ||
| 106 | DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); | ||
| 107 | return 0; | ||
| 108 | } | ||
diff --git a/arch/arm64/kernel/cputable.c b/arch/arm64/kernel/cputable.c new file mode 100644 index 000000000000..63cfc4a43f4e --- /dev/null +++ b/arch/arm64/kernel/cputable.c | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm64/kernel/cputable.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/init.h> | ||
| 20 | |||
| 21 | #include <asm/cputable.h> | ||
| 22 | |||
| 23 | extern unsigned long __cpu_setup(void); | ||
| 24 | |||
| 25 | struct cpu_info __initdata cpu_table[] = { | ||
| 26 | { | ||
| 27 | .cpu_id_val = 0x000f0000, | ||
| 28 | .cpu_id_mask = 0x000f0000, | ||
| 29 | .cpu_name = "AArch64 Processor", | ||
| 30 | .cpu_setup = __cpu_setup, | ||
| 31 | }, | ||
| 32 | { /* Empty */ }, | ||
| 33 | }; | ||
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c new file mode 100644 index 000000000000..0c3ba9f51376 --- /dev/null +++ b/arch/arm64/kernel/debug-monitors.c | |||
| @@ -0,0 +1,288 @@ | |||
| 1 | /* | ||
| 2 | * ARMv8 single-step debug support and mdscr context switching. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/cpu.h> | ||
| 22 | #include <linux/debugfs.h> | ||
| 23 | #include <linux/hardirq.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/ptrace.h> | ||
| 26 | #include <linux/stat.h> | ||
| 27 | |||
| 28 | #include <asm/debug-monitors.h> | ||
| 29 | #include <asm/local.h> | ||
| 30 | #include <asm/cputype.h> | ||
| 31 | #include <asm/system_misc.h> | ||
| 32 | |||
| 33 | /* Low-level stepping controls. */ | ||
| 34 | #define DBG_MDSCR_SS (1 << 0) | ||
| 35 | #define DBG_SPSR_SS (1 << 21) | ||
| 36 | |||
| 37 | /* MDSCR_EL1 enabling bits */ | ||
| 38 | #define DBG_MDSCR_KDE (1 << 13) | ||
| 39 | #define DBG_MDSCR_MDE (1 << 15) | ||
| 40 | #define DBG_MDSCR_MASK ~(DBG_MDSCR_KDE | DBG_MDSCR_MDE) | ||
| 41 | |||
| 42 | /* Determine debug architecture. */ | ||
| 43 | u8 debug_monitors_arch(void) | ||
| 44 | { | ||
| 45 | return read_cpuid(ID_AA64DFR0_EL1) & 0xf; | ||
| 46 | } | ||
| 47 | |||
| 48 | /* | ||
| 49 | * MDSCR access routines. | ||
| 50 | */ | ||
| 51 | static void mdscr_write(u32 mdscr) | ||
| 52 | { | ||
| 53 | unsigned long flags; | ||
| 54 | local_dbg_save(flags); | ||
| 55 | asm volatile("msr mdscr_el1, %0" :: "r" (mdscr)); | ||
| 56 | local_dbg_restore(flags); | ||
| 57 | } | ||
| 58 | |||
| 59 | static u32 mdscr_read(void) | ||
| 60 | { | ||
| 61 | u32 mdscr; | ||
| 62 | asm volatile("mrs %0, mdscr_el1" : "=r" (mdscr)); | ||
| 63 | return mdscr; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Allow root to disable self-hosted debug from userspace. | ||
| 68 | * This is useful if you want to connect an external JTAG debugger. | ||
| 69 | */ | ||
| 70 | static u32 debug_enabled = 1; | ||
| 71 | |||
| 72 | static int create_debug_debugfs_entry(void) | ||
| 73 | { | ||
| 74 | debugfs_create_bool("debug_enabled", 0644, NULL, &debug_enabled); | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | fs_initcall(create_debug_debugfs_entry); | ||
| 78 | |||
| 79 | static int __init early_debug_disable(char *buf) | ||
| 80 | { | ||
| 81 | debug_enabled = 0; | ||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | early_param("nodebugmon", early_debug_disable); | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Keep track of debug users on each core. | ||
| 89 | * The ref counts are per-cpu so we use a local_t type. | ||
| 90 | */ | ||
| 91 | static DEFINE_PER_CPU(local_t, mde_ref_count); | ||
| 92 | static DEFINE_PER_CPU(local_t, kde_ref_count); | ||
| 93 | |||
| 94 | void enable_debug_monitors(enum debug_el el) | ||
| 95 | { | ||
| 96 | u32 mdscr, enable = 0; | ||
| 97 | |||
| 98 | WARN_ON(preemptible()); | ||
| 99 | |||
| 100 | if (local_inc_return(&__get_cpu_var(mde_ref_count)) == 1) | ||
| 101 | enable = DBG_MDSCR_MDE; | ||
| 102 | |||
| 103 | if (el == DBG_ACTIVE_EL1 && | ||
| 104 | local_inc_return(&__get_cpu_var(kde_ref_count)) == 1) | ||
| 105 | enable |= DBG_MDSCR_KDE; | ||
| 106 | |||
| 107 | if (enable && debug_enabled) { | ||
| 108 | mdscr = mdscr_read(); | ||
| 109 | mdscr |= enable; | ||
| 110 | mdscr_write(mdscr); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | void disable_debug_monitors(enum debug_el el) | ||
| 115 | { | ||
| 116 | u32 mdscr, disable = 0; | ||
| 117 | |||
| 118 | WARN_ON(preemptible()); | ||
| 119 | |||
| 120 | if (local_dec_and_test(&__get_cpu_var(mde_ref_count))) | ||
| 121 | disable = ~DBG_MDSCR_MDE; | ||
| 122 | |||
| 123 | if (el == DBG_ACTIVE_EL1 && | ||
| 124 | local_dec_and_test(&__get_cpu_var(kde_ref_count))) | ||
| 125 | disable &= ~DBG_MDSCR_KDE; | ||
| 126 | |||
| 127 | if (disable) { | ||
| 128 | mdscr = mdscr_read(); | ||
| 129 | mdscr &= disable; | ||
| 130 | mdscr_write(mdscr); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | /* | ||
| 135 | * OS lock clearing. | ||
| 136 | */ | ||
| 137 | static void clear_os_lock(void *unused) | ||
| 138 | { | ||
| 139 | asm volatile("msr mdscr_el1, %0" : : "r" (0)); | ||
| 140 | isb(); | ||
| 141 | asm volatile("msr oslar_el1, %0" : : "r" (0)); | ||
| 142 | isb(); | ||
| 143 | } | ||
| 144 | |||
| 145 | static int __cpuinit os_lock_notify(struct notifier_block *self, | ||
| 146 | unsigned long action, void *data) | ||
| 147 | { | ||
| 148 | int cpu = (unsigned long)data; | ||
| 149 | if (action == CPU_ONLINE) | ||
| 150 | smp_call_function_single(cpu, clear_os_lock, NULL, 1); | ||
| 151 | return NOTIFY_OK; | ||
| 152 | } | ||
| 153 | |||
| 154 | static struct notifier_block __cpuinitdata os_lock_nb = { | ||
| 155 | .notifier_call = os_lock_notify, | ||
| 156 | }; | ||
| 157 | |||
| 158 | static int __cpuinit debug_monitors_init(void) | ||
| 159 | { | ||
| 160 | /* Clear the OS lock. */ | ||
| 161 | smp_call_function(clear_os_lock, NULL, 1); | ||
| 162 | clear_os_lock(NULL); | ||
| 163 | |||
| 164 | /* Register hotplug handler. */ | ||
| 165 | register_cpu_notifier(&os_lock_nb); | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | postcore_initcall(debug_monitors_init); | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Single step API and exception handling. | ||
| 172 | */ | ||
| 173 | static void set_regs_spsr_ss(struct pt_regs *regs) | ||
| 174 | { | ||
| 175 | unsigned long spsr; | ||
| 176 | |||
| 177 | spsr = regs->pstate; | ||
| 178 | spsr &= ~DBG_SPSR_SS; | ||
| 179 | spsr |= DBG_SPSR_SS; | ||
| 180 | regs->pstate = spsr; | ||
| 181 | } | ||
| 182 | |||
| 183 | static void clear_regs_spsr_ss(struct pt_regs *regs) | ||
| 184 | { | ||
| 185 | unsigned long spsr; | ||
| 186 | |||
| 187 | spsr = regs->pstate; | ||
| 188 | spsr &= ~DBG_SPSR_SS; | ||
| 189 | regs->pstate = spsr; | ||
| 190 | } | ||
| 191 | |||
| 192 | static int single_step_handler(unsigned long addr, unsigned int esr, | ||
| 193 | struct pt_regs *regs) | ||
| 194 | { | ||
| 195 | siginfo_t info; | ||
| 196 | |||
| 197 | /* | ||
| 198 | * If we are stepping a pending breakpoint, call the hw_breakpoint | ||
| 199 | * handler first. | ||
| 200 | */ | ||
| 201 | if (!reinstall_suspended_bps(regs)) | ||
| 202 | return 0; | ||
| 203 | |||
| 204 | if (user_mode(regs)) { | ||
| 205 | info.si_signo = SIGTRAP; | ||
| 206 | info.si_errno = 0; | ||
| 207 | info.si_code = TRAP_HWBKPT; | ||
| 208 | info.si_addr = (void __user *)instruction_pointer(regs); | ||
| 209 | force_sig_info(SIGTRAP, &info, current); | ||
| 210 | |||
| 211 | /* | ||
| 212 | * ptrace will disable single step unless explicitly | ||
| 213 | * asked to re-enable it. For other clients, it makes | ||
| 214 | * sense to leave it enabled (i.e. rewind the controls | ||
| 215 | * to the active-not-pending state). | ||
| 216 | */ | ||
| 217 | user_rewind_single_step(current); | ||
| 218 | } else { | ||
| 219 | /* TODO: route to KGDB */ | ||
| 220 | pr_warning("Unexpected kernel single-step exception at EL1\n"); | ||
| 221 | /* | ||
| 222 | * Re-enable stepping since we know that we will be | ||
| 223 | * returning to regs. | ||
| 224 | */ | ||
| 225 | set_regs_spsr_ss(regs); | ||
| 226 | } | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int __init single_step_init(void) | ||
| 232 | { | ||
| 233 | hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP, | ||
| 234 | TRAP_HWBKPT, "single-step handler"); | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | arch_initcall(single_step_init); | ||
| 238 | |||
| 239 | /* Re-enable single step for syscall restarting. */ | ||
| 240 | void user_rewind_single_step(struct task_struct *task) | ||
| 241 | { | ||
| 242 | /* | ||
| 243 | * If single step is active for this thread, then set SPSR.SS | ||
| 244 | * to 1 to avoid returning to the active-pending state. | ||
| 245 | */ | ||
| 246 | if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP)) | ||
| 247 | set_regs_spsr_ss(task_pt_regs(task)); | ||
| 248 | } | ||
| 249 | |||
| 250 | void user_fastforward_single_step(struct task_struct *task) | ||
| 251 | { | ||
| 252 | if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP)) | ||
| 253 | clear_regs_spsr_ss(task_pt_regs(task)); | ||
| 254 | } | ||
| 255 | |||
| 256 | /* Kernel API */ | ||
| 257 | void kernel_enable_single_step(struct pt_regs *regs) | ||
| 258 | { | ||
| 259 | WARN_ON(!irqs_disabled()); | ||
| 260 | set_regs_spsr_ss(regs); | ||
| 261 | mdscr_write(mdscr_read() | DBG_MDSCR_SS); | ||
| 262 | enable_debug_monitors(DBG_ACTIVE_EL1); | ||
| 263 | } | ||
| 264 | |||
| 265 | void kernel_disable_single_step(void) | ||
| 266 | { | ||
| 267 | WARN_ON(!irqs_disabled()); | ||
| 268 | mdscr_write(mdscr_read() & ~DBG_MDSCR_SS); | ||
| 269 | disable_debug_monitors(DBG_ACTIVE_EL1); | ||
| 270 | } | ||
| 271 | |||
| 272 | int kernel_active_single_step(void) | ||
| 273 | { | ||
| 274 | WARN_ON(!irqs_disabled()); | ||
| 275 | return mdscr_read() & DBG_MDSCR_SS; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* ptrace API */ | ||
| 279 | void user_enable_single_step(struct task_struct *task) | ||
| 280 | { | ||
| 281 | set_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP); | ||
| 282 | set_regs_spsr_ss(task_pt_regs(task)); | ||
| 283 | } | ||
| 284 | |||
| 285 | void user_disable_single_step(struct task_struct *task) | ||
| 286 | { | ||
| 287 | clear_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP); | ||
| 288 | } | ||
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S new file mode 100644 index 000000000000..17988a6e7ea2 --- /dev/null +++ b/arch/arm64/kernel/entry-fpsimd.S | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | /* | ||
| 2 | * FP/SIMD state saving and restoring | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/linkage.h> | ||
| 21 | |||
| 22 | #include <asm/assembler.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Save the FP registers. | ||
| 26 | * | ||
| 27 | * x0 - pointer to struct fpsimd_state | ||
| 28 | */ | ||
| 29 | ENTRY(fpsimd_save_state) | ||
| 30 | stp q0, q1, [x0, #16 * 0] | ||
| 31 | stp q2, q3, [x0, #16 * 2] | ||
| 32 | stp q4, q5, [x0, #16 * 4] | ||
| 33 | stp q6, q7, [x0, #16 * 6] | ||
| 34 | stp q8, q9, [x0, #16 * 8] | ||
| 35 | stp q10, q11, [x0, #16 * 10] | ||
| 36 | stp q12, q13, [x0, #16 * 12] | ||
| 37 | stp q14, q15, [x0, #16 * 14] | ||
| 38 | stp q16, q17, [x0, #16 * 16] | ||
| 39 | stp q18, q19, [x0, #16 * 18] | ||
| 40 | stp q20, q21, [x0, #16 * 20] | ||
| 41 | stp q22, q23, [x0, #16 * 22] | ||
| 42 | stp q24, q25, [x0, #16 * 24] | ||
| 43 | stp q26, q27, [x0, #16 * 26] | ||
| 44 | stp q28, q29, [x0, #16 * 28] | ||
| 45 | stp q30, q31, [x0, #16 * 30]! | ||
| 46 | mrs x8, fpsr | ||
| 47 | str w8, [x0, #16 * 2] | ||
| 48 | mrs x8, fpcr | ||
| 49 | str w8, [x0, #16 * 2 + 4] | ||
| 50 | ret | ||
| 51 | ENDPROC(fpsimd_save_state) | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Load the FP registers. | ||
| 55 | * | ||
| 56 | * x0 - pointer to struct fpsimd_state | ||
| 57 | */ | ||
| 58 | ENTRY(fpsimd_load_state) | ||
| 59 | ldp q0, q1, [x0, #16 * 0] | ||
| 60 | ldp q2, q3, [x0, #16 * 2] | ||
| 61 | ldp q4, q5, [x0, #16 * 4] | ||
| 62 | ldp q6, q7, [x0, #16 * 6] | ||
| 63 | ldp q8, q9, [x0, #16 * 8] | ||
| 64 | ldp q10, q11, [x0, #16 * 10] | ||
| 65 | ldp q12, q13, [x0, #16 * 12] | ||
| 66 | ldp q14, q15, [x0, #16 * 14] | ||
| 67 | ldp q16, q17, [x0, #16 * 16] | ||
| 68 | ldp q18, q19, [x0, #16 * 18] | ||
| 69 | ldp q20, q21, [x0, #16 * 20] | ||
| 70 | ldp q22, q23, [x0, #16 * 22] | ||
| 71 | ldp q24, q25, [x0, #16 * 24] | ||
| 72 | ldp q26, q27, [x0, #16 * 26] | ||
| 73 | ldp q28, q29, [x0, #16 * 28] | ||
| 74 | ldp q30, q31, [x0, #16 * 30]! | ||
| 75 | ldr w8, [x0, #16 * 2] | ||
| 76 | ldr w9, [x0, #16 * 2 + 4] | ||
| 77 | msr fpsr, x8 | ||
| 78 | msr fpcr, x9 | ||
| 79 | ret | ||
| 80 | ENDPROC(fpsimd_load_state) | ||
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S new file mode 100644 index 000000000000..38cf853a3667 --- /dev/null +++ b/arch/arm64/kernel/entry.S | |||
| @@ -0,0 +1,695 @@ | |||
| 1 | /* | ||
| 2 | * Low-level exception handling code | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Authors: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * Will Deacon <will.deacon@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/linkage.h> | ||
| 23 | |||
| 24 | #include <asm/assembler.h> | ||
| 25 | #include <asm/asm-offsets.h> | ||
| 26 | #include <asm/errno.h> | ||
| 27 | #include <asm/thread_info.h> | ||
| 28 | #include <asm/unistd.h> | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Bad Abort numbers | ||
| 32 | *----------------- | ||
| 33 | */ | ||
| 34 | #define BAD_SYNC 0 | ||
| 35 | #define BAD_IRQ 1 | ||
| 36 | #define BAD_FIQ 2 | ||
| 37 | #define BAD_ERROR 3 | ||
| 38 | |||
| 39 | .macro kernel_entry, el, regsize = 64 | ||
| 40 | sub sp, sp, #S_FRAME_SIZE - S_LR // room for LR, SP, SPSR, ELR | ||
| 41 | .if \regsize == 32 | ||
| 42 | mov w0, w0 // zero upper 32 bits of x0 | ||
| 43 | .endif | ||
| 44 | push x28, x29 | ||
| 45 | push x26, x27 | ||
| 46 | push x24, x25 | ||
| 47 | push x22, x23 | ||
| 48 | push x20, x21 | ||
| 49 | push x18, x19 | ||
| 50 | push x16, x17 | ||
| 51 | push x14, x15 | ||
| 52 | push x12, x13 | ||
| 53 | push x10, x11 | ||
| 54 | push x8, x9 | ||
| 55 | push x6, x7 | ||
| 56 | push x4, x5 | ||
| 57 | push x2, x3 | ||
| 58 | push x0, x1 | ||
| 59 | .if \el == 0 | ||
| 60 | mrs x21, sp_el0 | ||
| 61 | .else | ||
| 62 | add x21, sp, #S_FRAME_SIZE | ||
| 63 | .endif | ||
| 64 | mrs x22, elr_el1 | ||
| 65 | mrs x23, spsr_el1 | ||
| 66 | stp lr, x21, [sp, #S_LR] | ||
| 67 | stp x22, x23, [sp, #S_PC] | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Set syscallno to -1 by default (overridden later if real syscall). | ||
| 71 | */ | ||
| 72 | .if \el == 0 | ||
| 73 | mvn x21, xzr | ||
| 74 | str x21, [sp, #S_SYSCALLNO] | ||
| 75 | .endif | ||
| 76 | |||
| 77 | /* | ||
| 78 | * Registers that may be useful after this macro is invoked: | ||
| 79 | * | ||
| 80 | * x21 - aborted SP | ||
| 81 | * x22 - aborted PC | ||
| 82 | * x23 - aborted PSTATE | ||
| 83 | */ | ||
| 84 | .endm | ||
| 85 | |||
| 86 | .macro kernel_exit, el, ret = 0 | ||
| 87 | ldp x21, x22, [sp, #S_PC] // load ELR, SPSR | ||
| 88 | .if \el == 0 | ||
| 89 | ldr x23, [sp, #S_SP] // load return stack pointer | ||
| 90 | .endif | ||
| 91 | .if \ret | ||
| 92 | ldr x1, [sp, #S_X1] // preserve x0 (syscall return) | ||
| 93 | add sp, sp, S_X2 | ||
| 94 | .else | ||
| 95 | pop x0, x1 | ||
| 96 | .endif | ||
| 97 | pop x2, x3 // load the rest of the registers | ||
| 98 | pop x4, x5 | ||
| 99 | pop x6, x7 | ||
| 100 | pop x8, x9 | ||
| 101 | msr elr_el1, x21 // set up the return data | ||
| 102 | msr spsr_el1, x22 | ||
| 103 | .if \el == 0 | ||
| 104 | msr sp_el0, x23 | ||
| 105 | .endif | ||
| 106 | pop x10, x11 | ||
| 107 | pop x12, x13 | ||
| 108 | pop x14, x15 | ||
| 109 | pop x16, x17 | ||
| 110 | pop x18, x19 | ||
| 111 | pop x20, x21 | ||
| 112 | pop x22, x23 | ||
| 113 | pop x24, x25 | ||
| 114 | pop x26, x27 | ||
| 115 | pop x28, x29 | ||
| 116 | ldr lr, [sp], #S_FRAME_SIZE - S_LR // load LR and restore SP | ||
| 117 | eret // return to kernel | ||
| 118 | .endm | ||
| 119 | |||
| 120 | .macro get_thread_info, rd | ||
| 121 | mov \rd, sp | ||
| 122 | and \rd, \rd, #~((1 << 13) - 1) // top of 8K stack | ||
| 123 | .endm | ||
| 124 | |||
| 125 | /* | ||
| 126 | * These are the registers used in the syscall handler, and allow us to | ||
| 127 | * have in theory up to 7 arguments to a function - x0 to x6. | ||
| 128 | * | ||
| 129 | * x7 is reserved for the system call number in 32-bit mode. | ||
| 130 | */ | ||
| 131 | sc_nr .req x25 // number of system calls | ||
| 132 | scno .req x26 // syscall number | ||
| 133 | stbl .req x27 // syscall table pointer | ||
| 134 | tsk .req x28 // current thread_info | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Interrupt handling. | ||
| 138 | */ | ||
| 139 | .macro irq_handler | ||
| 140 | ldr x1, handle_arch_irq | ||
| 141 | mov x0, sp | ||
| 142 | blr x1 | ||
| 143 | .endm | ||
| 144 | |||
| 145 | .text | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Exception vectors. | ||
| 149 | */ | ||
| 150 | .macro ventry label | ||
| 151 | .align 7 | ||
| 152 | b \label | ||
| 153 | .endm | ||
| 154 | |||
| 155 | .align 11 | ||
| 156 | ENTRY(vectors) | ||
| 157 | ventry el1_sync_invalid // Synchronous EL1t | ||
| 158 | ventry el1_irq_invalid // IRQ EL1t | ||
| 159 | ventry el1_fiq_invalid // FIQ EL1t | ||
| 160 | ventry el1_error_invalid // Error EL1t | ||
| 161 | |||
| 162 | ventry el1_sync // Synchronous EL1h | ||
| 163 | ventry el1_irq // IRQ EL1h | ||
| 164 | ventry el1_fiq_invalid // FIQ EL1h | ||
| 165 | ventry el1_error_invalid // Error EL1h | ||
| 166 | |||
| 167 | ventry el0_sync // Synchronous 64-bit EL0 | ||
| 168 | ventry el0_irq // IRQ 64-bit EL0 | ||
| 169 | ventry el0_fiq_invalid // FIQ 64-bit EL0 | ||
| 170 | ventry el0_error_invalid // Error 64-bit EL0 | ||
| 171 | |||
| 172 | #ifdef CONFIG_COMPAT | ||
| 173 | ventry el0_sync_compat // Synchronous 32-bit EL0 | ||
| 174 | ventry el0_irq_compat // IRQ 32-bit EL0 | ||
| 175 | ventry el0_fiq_invalid_compat // FIQ 32-bit EL0 | ||
| 176 | ventry el0_error_invalid_compat // Error 32-bit EL0 | ||
| 177 | #else | ||
| 178 | ventry el0_sync_invalid // Synchronous 32-bit EL0 | ||
| 179 | ventry el0_irq_invalid // IRQ 32-bit EL0 | ||
| 180 | ventry el0_fiq_invalid // FIQ 32-bit EL0 | ||
| 181 | ventry el0_error_invalid // Error 32-bit EL0 | ||
| 182 | #endif | ||
| 183 | END(vectors) | ||
| 184 | |||
| 185 | /* | ||
| 186 | * Invalid mode handlers | ||
| 187 | */ | ||
| 188 | .macro inv_entry, el, reason, regsize = 64 | ||
| 189 | kernel_entry el, \regsize | ||
| 190 | mov x0, sp | ||
| 191 | mov x1, #\reason | ||
| 192 | mrs x2, esr_el1 | ||
| 193 | b bad_mode | ||
| 194 | .endm | ||
| 195 | |||
| 196 | el0_sync_invalid: | ||
| 197 | inv_entry 0, BAD_SYNC | ||
| 198 | ENDPROC(el0_sync_invalid) | ||
| 199 | |||
| 200 | el0_irq_invalid: | ||
| 201 | inv_entry 0, BAD_IRQ | ||
| 202 | ENDPROC(el0_irq_invalid) | ||
| 203 | |||
| 204 | el0_fiq_invalid: | ||
| 205 | inv_entry 0, BAD_FIQ | ||
| 206 | ENDPROC(el0_fiq_invalid) | ||
| 207 | |||
| 208 | el0_error_invalid: | ||
| 209 | inv_entry 0, BAD_ERROR | ||
| 210 | ENDPROC(el0_error_invalid) | ||
| 211 | |||
| 212 | #ifdef CONFIG_COMPAT | ||
| 213 | el0_fiq_invalid_compat: | ||
| 214 | inv_entry 0, BAD_FIQ, 32 | ||
| 215 | ENDPROC(el0_fiq_invalid_compat) | ||
| 216 | |||
| 217 | el0_error_invalid_compat: | ||
| 218 | inv_entry 0, BAD_ERROR, 32 | ||
| 219 | ENDPROC(el0_error_invalid_compat) | ||
| 220 | #endif | ||
| 221 | |||
| 222 | el1_sync_invalid: | ||
| 223 | inv_entry 1, BAD_SYNC | ||
| 224 | ENDPROC(el1_sync_invalid) | ||
| 225 | |||
| 226 | el1_irq_invalid: | ||
| 227 | inv_entry 1, BAD_IRQ | ||
| 228 | ENDPROC(el1_irq_invalid) | ||
| 229 | |||
| 230 | el1_fiq_invalid: | ||
| 231 | inv_entry 1, BAD_FIQ | ||
| 232 | ENDPROC(el1_fiq_invalid) | ||
| 233 | |||
| 234 | el1_error_invalid: | ||
| 235 | inv_entry 1, BAD_ERROR | ||
| 236 | ENDPROC(el1_error_invalid) | ||
| 237 | |||
| 238 | /* | ||
| 239 | * EL1 mode handlers. | ||
| 240 | */ | ||
| 241 | .align 6 | ||
| 242 | el1_sync: | ||
| 243 | kernel_entry 1 | ||
| 244 | mrs x1, esr_el1 // read the syndrome register | ||
| 245 | lsr x24, x1, #26 // exception class | ||
| 246 | cmp x24, #0x25 // data abort in EL1 | ||
| 247 | b.eq el1_da | ||
| 248 | cmp x24, #0x18 // configurable trap | ||
| 249 | b.eq el1_undef | ||
| 250 | cmp x24, #0x26 // stack alignment exception | ||
| 251 | b.eq el1_sp_pc | ||
| 252 | cmp x24, #0x22 // pc alignment exception | ||
| 253 | b.eq el1_sp_pc | ||
| 254 | cmp x24, #0x00 // unknown exception in EL1 | ||
| 255 | b.eq el1_undef | ||
| 256 | cmp x24, #0x30 // debug exception in EL1 | ||
| 257 | b.ge el1_dbg | ||
| 258 | b el1_inv | ||
| 259 | el1_da: | ||
| 260 | /* | ||
| 261 | * Data abort handling | ||
| 262 | */ | ||
| 263 | mrs x0, far_el1 | ||
| 264 | enable_dbg_if_not_stepping x2 | ||
| 265 | // re-enable interrupts if they were enabled in the aborted context | ||
| 266 | tbnz x23, #7, 1f // PSR_I_BIT | ||
| 267 | enable_irq | ||
| 268 | 1: | ||
| 269 | mov x2, sp // struct pt_regs | ||
| 270 | bl do_mem_abort | ||
| 271 | |||
| 272 | // disable interrupts before pulling preserved data off the stack | ||
| 273 | disable_irq | ||
| 274 | kernel_exit 1 | ||
| 275 | el1_sp_pc: | ||
| 276 | /* | ||
| 277 | * Stack or PC alignment exception handling | ||
| 278 | */ | ||
| 279 | mrs x0, far_el1 | ||
| 280 | mov x1, x25 | ||
| 281 | mov x2, sp | ||
| 282 | b do_sp_pc_abort | ||
| 283 | el1_undef: | ||
| 284 | /* | ||
| 285 | * Undefined instruction | ||
| 286 | */ | ||
| 287 | mov x0, sp | ||
| 288 | b do_undefinstr | ||
| 289 | el1_dbg: | ||
| 290 | /* | ||
| 291 | * Debug exception handling | ||
| 292 | */ | ||
| 293 | tbz x24, #0, el1_inv // EL1 only | ||
| 294 | mrs x0, far_el1 | ||
| 295 | mov x2, sp // struct pt_regs | ||
| 296 | bl do_debug_exception | ||
| 297 | |||
| 298 | kernel_exit 1 | ||
| 299 | el1_inv: | ||
| 300 | // TODO: add support for undefined instructions in kernel mode | ||
| 301 | mov x0, sp | ||
| 302 | mov x1, #BAD_SYNC | ||
| 303 | mrs x2, esr_el1 | ||
| 304 | b bad_mode | ||
| 305 | ENDPROC(el1_sync) | ||
| 306 | |||
| 307 | .align 6 | ||
| 308 | el1_irq: | ||
| 309 | kernel_entry 1 | ||
| 310 | enable_dbg_if_not_stepping x0 | ||
| 311 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 312 | bl trace_hardirqs_off | ||
| 313 | #endif | ||
| 314 | #ifdef CONFIG_PREEMPT | ||
| 315 | get_thread_info tsk | ||
| 316 | ldr x24, [tsk, #TI_PREEMPT] // get preempt count | ||
| 317 | add x0, x24, #1 // increment it | ||
| 318 | str x0, [tsk, #TI_PREEMPT] | ||
| 319 | #endif | ||
| 320 | irq_handler | ||
| 321 | #ifdef CONFIG_PREEMPT | ||
| 322 | str x24, [tsk, #TI_PREEMPT] // restore preempt count | ||
| 323 | cbnz x24, 1f // preempt count != 0 | ||
| 324 | ldr x0, [tsk, #TI_FLAGS] // get flags | ||
| 325 | tbz x0, #TIF_NEED_RESCHED, 1f // needs rescheduling? | ||
| 326 | bl el1_preempt | ||
| 327 | 1: | ||
| 328 | #endif | ||
| 329 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 330 | bl trace_hardirqs_on | ||
| 331 | #endif | ||
| 332 | kernel_exit 1 | ||
| 333 | ENDPROC(el1_irq) | ||
| 334 | |||
| 335 | #ifdef CONFIG_PREEMPT | ||
| 336 | el1_preempt: | ||
| 337 | mov x24, lr | ||
| 338 | 1: enable_dbg | ||
| 339 | bl preempt_schedule_irq // irq en/disable is done inside | ||
| 340 | ldr x0, [tsk, #TI_FLAGS] // get new tasks TI_FLAGS | ||
| 341 | tbnz x0, #TIF_NEED_RESCHED, 1b // needs rescheduling? | ||
| 342 | ret x24 | ||
| 343 | #endif | ||
| 344 | |||
| 345 | /* | ||
| 346 | * EL0 mode handlers. | ||
| 347 | */ | ||
| 348 | .align 6 | ||
| 349 | el0_sync: | ||
| 350 | kernel_entry 0 | ||
| 351 | mrs x25, esr_el1 // read the syndrome register | ||
| 352 | lsr x24, x25, #26 // exception class | ||
| 353 | cmp x24, #0x15 // SVC in 64-bit state | ||
| 354 | b.eq el0_svc | ||
| 355 | adr lr, ret_from_exception | ||
| 356 | cmp x24, #0x24 // data abort in EL0 | ||
| 357 | b.eq el0_da | ||
| 358 | cmp x24, #0x20 // instruction abort in EL0 | ||
| 359 | b.eq el0_ia | ||
| 360 | cmp x24, #0x07 // FP/ASIMD access | ||
| 361 | b.eq el0_fpsimd_acc | ||
| 362 | cmp x24, #0x2c // FP/ASIMD exception | ||
| 363 | b.eq el0_fpsimd_exc | ||
| 364 | cmp x24, #0x18 // configurable trap | ||
| 365 | b.eq el0_undef | ||
| 366 | cmp x24, #0x26 // stack alignment exception | ||
| 367 | b.eq el0_sp_pc | ||
| 368 | cmp x24, #0x22 // pc alignment exception | ||
| 369 | b.eq el0_sp_pc | ||
| 370 | cmp x24, #0x00 // unknown exception in EL0 | ||
| 371 | b.eq el0_undef | ||
| 372 | cmp x24, #0x30 // debug exception in EL0 | ||
| 373 | b.ge el0_dbg | ||
| 374 | b el0_inv | ||
| 375 | |||
| 376 | #ifdef CONFIG_COMPAT | ||
| 377 | .align 6 | ||
| 378 | el0_sync_compat: | ||
| 379 | kernel_entry 0, 32 | ||
| 380 | mrs x25, esr_el1 // read the syndrome register | ||
| 381 | lsr x24, x25, #26 // exception class | ||
| 382 | cmp x24, #0x11 // SVC in 32-bit state | ||
| 383 | b.eq el0_svc_compat | ||
| 384 | adr lr, ret_from_exception | ||
| 385 | cmp x24, #0x24 // data abort in EL0 | ||
| 386 | b.eq el0_da | ||
| 387 | cmp x24, #0x20 // instruction abort in EL0 | ||
| 388 | b.eq el0_ia | ||
| 389 | cmp x24, #0x07 // FP/ASIMD access | ||
| 390 | b.eq el0_fpsimd_acc | ||
| 391 | cmp x24, #0x28 // FP/ASIMD exception | ||
| 392 | b.eq el0_fpsimd_exc | ||
| 393 | cmp x24, #0x00 // unknown exception in EL0 | ||
| 394 | b.eq el0_undef | ||
| 395 | cmp x24, #0x30 // debug exception in EL0 | ||
| 396 | b.ge el0_dbg | ||
| 397 | b el0_inv | ||
| 398 | el0_svc_compat: | ||
| 399 | /* | ||
| 400 | * AArch32 syscall handling | ||
| 401 | */ | ||
| 402 | adr stbl, compat_sys_call_table // load compat syscall table pointer | ||
| 403 | uxtw scno, w7 // syscall number in w7 (r7) | ||
| 404 | mov sc_nr, #__NR_compat_syscalls | ||
| 405 | b el0_svc_naked | ||
| 406 | |||
| 407 | .align 6 | ||
| 408 | el0_irq_compat: | ||
| 409 | kernel_entry 0, 32 | ||
| 410 | b el0_irq_naked | ||
| 411 | #endif | ||
| 412 | |||
| 413 | el0_da: | ||
| 414 | /* | ||
| 415 | * Data abort handling | ||
| 416 | */ | ||
| 417 | mrs x0, far_el1 | ||
| 418 | disable_step x1 | ||
| 419 | isb | ||
| 420 | enable_dbg | ||
| 421 | // enable interrupts before calling the main handler | ||
| 422 | enable_irq | ||
| 423 | mov x1, x25 | ||
| 424 | mov x2, sp | ||
| 425 | b do_mem_abort | ||
| 426 | el0_ia: | ||
| 427 | /* | ||
| 428 | * Instruction abort handling | ||
| 429 | */ | ||
| 430 | mrs x0, far_el1 | ||
| 431 | disable_step x1 | ||
| 432 | isb | ||
| 433 | enable_dbg | ||
| 434 | // enable interrupts before calling the main handler | ||
| 435 | enable_irq | ||
| 436 | orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts | ||
| 437 | mov x2, sp | ||
| 438 | b do_mem_abort | ||
| 439 | el0_fpsimd_acc: | ||
| 440 | /* | ||
| 441 | * Floating Point or Advanced SIMD access | ||
| 442 | */ | ||
| 443 | mov x0, x25 | ||
| 444 | mov x1, sp | ||
| 445 | b do_fpsimd_acc | ||
| 446 | el0_fpsimd_exc: | ||
| 447 | /* | ||
| 448 | * Floating Point or Advanced SIMD exception | ||
| 449 | */ | ||
| 450 | mov x0, x25 | ||
| 451 | mov x1, sp | ||
| 452 | b do_fpsimd_exc | ||
| 453 | el0_sp_pc: | ||
| 454 | /* | ||
| 455 | * Stack or PC alignment exception handling | ||
| 456 | */ | ||
| 457 | mrs x0, far_el1 | ||
| 458 | disable_step x1 | ||
| 459 | isb | ||
| 460 | enable_dbg | ||
| 461 | // enable interrupts before calling the main handler | ||
| 462 | enable_irq | ||
| 463 | mov x1, x25 | ||
| 464 | mov x2, sp | ||
| 465 | b do_sp_pc_abort | ||
| 466 | el0_undef: | ||
| 467 | /* | ||
| 468 | * Undefined instruction | ||
| 469 | */ | ||
| 470 | mov x0, sp | ||
| 471 | b do_undefinstr | ||
| 472 | el0_dbg: | ||
| 473 | /* | ||
| 474 | * Debug exception handling | ||
| 475 | */ | ||
| 476 | tbnz x24, #0, el0_inv // EL0 only | ||
| 477 | mrs x0, far_el1 | ||
| 478 | disable_step x1 | ||
| 479 | mov x1, x25 | ||
| 480 | mov x2, sp | ||
| 481 | b do_debug_exception | ||
| 482 | el0_inv: | ||
| 483 | mov x0, sp | ||
| 484 | mov x1, #BAD_SYNC | ||
| 485 | mrs x2, esr_el1 | ||
| 486 | b bad_mode | ||
| 487 | ENDPROC(el0_sync) | ||
| 488 | |||
| 489 | .align 6 | ||
| 490 | el0_irq: | ||
| 491 | kernel_entry 0 | ||
| 492 | el0_irq_naked: | ||
| 493 | disable_step x1 | ||
| 494 | isb | ||
| 495 | enable_dbg | ||
| 496 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 497 | bl trace_hardirqs_off | ||
| 498 | #endif | ||
| 499 | get_thread_info tsk | ||
| 500 | #ifdef CONFIG_PREEMPT | ||
| 501 | ldr x24, [tsk, #TI_PREEMPT] // get preempt count | ||
| 502 | add x23, x24, #1 // increment it | ||
| 503 | str x23, [tsk, #TI_PREEMPT] | ||
| 504 | #endif | ||
| 505 | irq_handler | ||
| 506 | #ifdef CONFIG_PREEMPT | ||
| 507 | ldr x0, [tsk, #TI_PREEMPT] | ||
| 508 | str x24, [tsk, #TI_PREEMPT] | ||
| 509 | cmp x0, x23 | ||
| 510 | b.eq 1f | ||
| 511 | mov x1, #0 | ||
| 512 | str x1, [x1] // BUG | ||
| 513 | 1: | ||
| 514 | #endif | ||
| 515 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 516 | bl trace_hardirqs_on | ||
| 517 | #endif | ||
| 518 | b ret_to_user | ||
| 519 | ENDPROC(el0_irq) | ||
| 520 | |||
| 521 | /* | ||
| 522 | * This is the return code to user mode for abort handlers | ||
| 523 | */ | ||
| 524 | ret_from_exception: | ||
| 525 | get_thread_info tsk | ||
| 526 | b ret_to_user | ||
| 527 | ENDPROC(ret_from_exception) | ||
| 528 | |||
| 529 | /* | ||
| 530 | * Register switch for AArch64. The callee-saved registers need to be saved | ||
| 531 | * and restored. On entry: | ||
| 532 | * x0 = previous task_struct (must be preserved across the switch) | ||
| 533 | * x1 = next task_struct | ||
| 534 | * Previous and next are guaranteed not to be the same. | ||
| 535 | * | ||
| 536 | */ | ||
| 537 | ENTRY(cpu_switch_to) | ||
| 538 | add x8, x0, #THREAD_CPU_CONTEXT | ||
| 539 | mov x9, sp | ||
| 540 | stp x19, x20, [x8], #16 // store callee-saved registers | ||
| 541 | stp x21, x22, [x8], #16 | ||
| 542 | stp x23, x24, [x8], #16 | ||
| 543 | stp x25, x26, [x8], #16 | ||
| 544 | stp x27, x28, [x8], #16 | ||
| 545 | stp x29, x9, [x8], #16 | ||
| 546 | str lr, [x8] | ||
| 547 | add x8, x1, #THREAD_CPU_CONTEXT | ||
| 548 | ldp x19, x20, [x8], #16 // restore callee-saved registers | ||
| 549 | ldp x21, x22, [x8], #16 | ||
| 550 | ldp x23, x24, [x8], #16 | ||
| 551 | ldp x25, x26, [x8], #16 | ||
| 552 | ldp x27, x28, [x8], #16 | ||
| 553 | ldp x29, x9, [x8], #16 | ||
| 554 | ldr lr, [x8] | ||
| 555 | mov sp, x9 | ||
| 556 | ret | ||
| 557 | ENDPROC(cpu_switch_to) | ||
| 558 | |||
| 559 | /* | ||
| 560 | * This is the fast syscall return path. We do as little as possible here, | ||
| 561 | * and this includes saving x0 back into the kernel stack. | ||
| 562 | */ | ||
| 563 | ret_fast_syscall: | ||
| 564 | disable_irq // disable interrupts | ||
| 565 | ldr x1, [tsk, #TI_FLAGS] | ||
| 566 | and x2, x1, #_TIF_WORK_MASK | ||
| 567 | cbnz x2, fast_work_pending | ||
| 568 | tbz x1, #TIF_SINGLESTEP, fast_exit | ||
| 569 | disable_dbg | ||
| 570 | enable_step x2 | ||
| 571 | fast_exit: | ||
| 572 | kernel_exit 0, ret = 1 | ||
| 573 | |||
| 574 | /* | ||
| 575 | * Ok, we need to do extra processing, enter the slow path. | ||
| 576 | */ | ||
| 577 | fast_work_pending: | ||
| 578 | str x0, [sp, #S_X0] // returned x0 | ||
| 579 | work_pending: | ||
| 580 | tbnz x1, #TIF_NEED_RESCHED, work_resched | ||
| 581 | /* TIF_SIGPENDING or TIF_NOTIFY_RESUME case */ | ||
| 582 | ldr x2, [sp, #S_PSTATE] | ||
| 583 | mov x0, sp // 'regs' | ||
| 584 | tst x2, #PSR_MODE_MASK // user mode regs? | ||
| 585 | b.ne no_work_pending // returning to kernel | ||
| 586 | bl do_notify_resume | ||
| 587 | b ret_to_user | ||
| 588 | work_resched: | ||
| 589 | enable_dbg | ||
| 590 | bl schedule | ||
| 591 | |||
| 592 | /* | ||
| 593 | * "slow" syscall return path. | ||
| 594 | */ | ||
| 595 | ENTRY(ret_to_user) | ||
| 596 | disable_irq // disable interrupts | ||
| 597 | ldr x1, [tsk, #TI_FLAGS] | ||
| 598 | and x2, x1, #_TIF_WORK_MASK | ||
| 599 | cbnz x2, work_pending | ||
| 600 | tbz x1, #TIF_SINGLESTEP, no_work_pending | ||
| 601 | disable_dbg | ||
| 602 | enable_step x2 | ||
| 603 | no_work_pending: | ||
| 604 | kernel_exit 0, ret = 0 | ||
| 605 | ENDPROC(ret_to_user) | ||
| 606 | |||
| 607 | /* | ||
| 608 | * This is how we return from a fork. | ||
| 609 | */ | ||
| 610 | ENTRY(ret_from_fork) | ||
| 611 | bl schedule_tail | ||
| 612 | get_thread_info tsk | ||
| 613 | b ret_to_user | ||
| 614 | ENDPROC(ret_from_fork) | ||
| 615 | |||
| 616 | /* | ||
| 617 | * SVC handler. | ||
| 618 | */ | ||
| 619 | .align 6 | ||
| 620 | el0_svc: | ||
| 621 | adrp stbl, sys_call_table // load syscall table pointer | ||
| 622 | uxtw scno, w8 // syscall number in w8 | ||
| 623 | mov sc_nr, #__NR_syscalls | ||
| 624 | el0_svc_naked: // compat entry point | ||
| 625 | stp x0, scno, [sp, #S_ORIG_X0] // save the original x0 and syscall number | ||
| 626 | disable_step x16 | ||
| 627 | isb | ||
| 628 | enable_dbg | ||
| 629 | enable_irq | ||
| 630 | |||
| 631 | get_thread_info tsk | ||
| 632 | ldr x16, [tsk, #TI_FLAGS] // check for syscall tracing | ||
| 633 | tbnz x16, #TIF_SYSCALL_TRACE, __sys_trace // are we tracing syscalls? | ||
| 634 | adr lr, ret_fast_syscall // return address | ||
| 635 | cmp scno, sc_nr // check upper syscall limit | ||
| 636 | b.hs ni_sys | ||
| 637 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table | ||
| 638 | br x16 // call sys_* routine | ||
| 639 | ni_sys: | ||
| 640 | mov x0, sp | ||
| 641 | b do_ni_syscall | ||
| 642 | ENDPROC(el0_svc) | ||
| 643 | |||
| 644 | /* | ||
| 645 | * This is the really slow path. We're going to be doing context | ||
| 646 | * switches, and waiting for our parent to respond. | ||
| 647 | */ | ||
| 648 | __sys_trace: | ||
| 649 | mov x1, sp | ||
| 650 | mov w0, #0 // trace entry | ||
| 651 | bl syscall_trace | ||
| 652 | adr lr, __sys_trace_return // return address | ||
| 653 | uxtw scno, w0 // syscall number (possibly new) | ||
| 654 | mov x1, sp // pointer to regs | ||
| 655 | cmp scno, sc_nr // check upper syscall limit | ||
| 656 | b.hs ni_sys | ||
| 657 | ldp x0, x1, [sp] // restore the syscall args | ||
| 658 | ldp x2, x3, [sp, #S_X2] | ||
| 659 | ldp x4, x5, [sp, #S_X4] | ||
| 660 | ldp x6, x7, [sp, #S_X6] | ||
| 661 | ldr x16, [stbl, scno, lsl #3] // address in the syscall table | ||
| 662 | br x16 // call sys_* routine | ||
| 663 | |||
| 664 | __sys_trace_return: | ||
| 665 | str x0, [sp] // save returned x0 | ||
| 666 | mov x1, sp | ||
| 667 | mov w0, #1 // trace exit | ||
| 668 | bl syscall_trace | ||
| 669 | b ret_to_user | ||
| 670 | |||
| 671 | /* | ||
| 672 | * Special system call wrappers. | ||
| 673 | */ | ||
| 674 | ENTRY(sys_execve_wrapper) | ||
| 675 | mov x3, sp | ||
| 676 | b sys_execve | ||
| 677 | ENDPROC(sys_execve_wrapper) | ||
| 678 | |||
| 679 | ENTRY(sys_clone_wrapper) | ||
| 680 | mov x5, sp | ||
| 681 | b sys_clone | ||
| 682 | ENDPROC(sys_clone_wrapper) | ||
| 683 | |||
| 684 | ENTRY(sys_rt_sigreturn_wrapper) | ||
| 685 | mov x0, sp | ||
| 686 | b sys_rt_sigreturn | ||
| 687 | ENDPROC(sys_rt_sigreturn_wrapper) | ||
| 688 | |||
| 689 | ENTRY(sys_sigaltstack_wrapper) | ||
| 690 | ldr x2, [sp, #S_SP] | ||
| 691 | b sys_sigaltstack | ||
| 692 | ENDPROC(sys_sigaltstack_wrapper) | ||
| 693 | |||
| 694 | ENTRY(handle_arch_irq) | ||
| 695 | .quad 0 | ||
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c new file mode 100644 index 000000000000..e8b8357aedb4 --- /dev/null +++ b/arch/arm64/kernel/fpsimd.c | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * FP/SIMD context switching and fault handling | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/sched.h> | ||
| 23 | #include <linux/signal.h> | ||
| 24 | |||
| 25 | #include <asm/fpsimd.h> | ||
| 26 | #include <asm/cputype.h> | ||
| 27 | |||
| 28 | #define FPEXC_IOF (1 << 0) | ||
| 29 | #define FPEXC_DZF (1 << 1) | ||
| 30 | #define FPEXC_OFF (1 << 2) | ||
| 31 | #define FPEXC_UFF (1 << 3) | ||
| 32 | #define FPEXC_IXF (1 << 4) | ||
| 33 | #define FPEXC_IDF (1 << 7) | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Trapped FP/ASIMD access. | ||
| 37 | */ | ||
| 38 | void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) | ||
| 39 | { | ||
| 40 | /* TODO: implement lazy context saving/restoring */ | ||
| 41 | WARN_ON(1); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Raise a SIGFPE for the current process. | ||
| 46 | */ | ||
| 47 | void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs) | ||
| 48 | { | ||
| 49 | siginfo_t info; | ||
| 50 | unsigned int si_code = 0; | ||
| 51 | |||
| 52 | if (esr & FPEXC_IOF) | ||
| 53 | si_code = FPE_FLTINV; | ||
| 54 | else if (esr & FPEXC_DZF) | ||
| 55 | si_code = FPE_FLTDIV; | ||
| 56 | else if (esr & FPEXC_OFF) | ||
| 57 | si_code = FPE_FLTOVF; | ||
| 58 | else if (esr & FPEXC_UFF) | ||
| 59 | si_code = FPE_FLTUND; | ||
| 60 | else if (esr & FPEXC_IXF) | ||
| 61 | si_code = FPE_FLTRES; | ||
| 62 | |||
| 63 | memset(&info, 0, sizeof(info)); | ||
| 64 | info.si_signo = SIGFPE; | ||
| 65 | info.si_code = si_code; | ||
| 66 | info.si_addr = (void __user *)instruction_pointer(regs); | ||
| 67 | |||
| 68 | send_sig_info(SIGFPE, &info, current); | ||
| 69 | } | ||
| 70 | |||
| 71 | void fpsimd_thread_switch(struct task_struct *next) | ||
| 72 | { | ||
| 73 | /* check if not kernel threads */ | ||
| 74 | if (current->mm) | ||
| 75 | fpsimd_save_state(¤t->thread.fpsimd_state); | ||
| 76 | if (next->mm) | ||
| 77 | fpsimd_load_state(&next->thread.fpsimd_state); | ||
| 78 | } | ||
| 79 | |||
| 80 | void fpsimd_flush_thread(void) | ||
| 81 | { | ||
| 82 | memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state)); | ||
| 83 | fpsimd_load_state(¤t->thread.fpsimd_state); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * FP/SIMD support code initialisation. | ||
| 88 | */ | ||
| 89 | static int __init fpsimd_init(void) | ||
| 90 | { | ||
| 91 | u64 pfr = read_cpuid(ID_AA64PFR0_EL1); | ||
| 92 | |||
| 93 | if (pfr & (0xf << 16)) { | ||
| 94 | pr_notice("Floating-point is not implemented\n"); | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | elf_hwcap |= HWCAP_FP; | ||
| 98 | |||
| 99 | if (pfr & (0xf << 20)) | ||
| 100 | pr_notice("Advanced SIMD is not implemented\n"); | ||
| 101 | else | ||
| 102 | elf_hwcap |= HWCAP_ASIMD; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | late_initcall(fpsimd_init); | ||
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S new file mode 100644 index 000000000000..a2f02b63eae9 --- /dev/null +++ b/arch/arm64/kernel/head.S | |||
| @@ -0,0 +1,510 @@ | |||
| 1 | /* | ||
| 2 | * Low-level CPU initialisation | ||
| 3 | * Based on arch/arm/kernel/head.S | ||
| 4 | * | ||
| 5 | * Copyright (C) 1994-2002 Russell King | ||
| 6 | * Copyright (C) 2003-2012 ARM Ltd. | ||
| 7 | * Authors: Catalin Marinas <catalin.marinas@arm.com> | ||
| 8 | * Will Deacon <will.deacon@arm.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/linkage.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | |||
| 26 | #include <asm/assembler.h> | ||
| 27 | #include <asm/ptrace.h> | ||
| 28 | #include <asm/asm-offsets.h> | ||
| 29 | #include <asm/memory.h> | ||
| 30 | #include <asm/thread_info.h> | ||
| 31 | #include <asm/pgtable-hwdef.h> | ||
| 32 | #include <asm/pgtable.h> | ||
| 33 | #include <asm/page.h> | ||
| 34 | |||
| 35 | /* | ||
| 36 | * swapper_pg_dir is the virtual address of the initial page table. We place | ||
| 37 | * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has | ||
| 38 | * 2 pages and is placed below swapper_pg_dir. | ||
| 39 | */ | ||
| 40 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | ||
| 41 | |||
| 42 | #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000 | ||
| 43 | #error KERNEL_RAM_VADDR must start at 0xXXX80000 | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #define SWAPPER_DIR_SIZE (3 * PAGE_SIZE) | ||
| 47 | #define IDMAP_DIR_SIZE (2 * PAGE_SIZE) | ||
| 48 | |||
| 49 | .globl swapper_pg_dir | ||
| 50 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE | ||
| 51 | |||
| 52 | .globl idmap_pg_dir | ||
| 53 | .equ idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE | ||
| 54 | |||
| 55 | .macro pgtbl, ttb0, ttb1, phys | ||
| 56 | add \ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE | ||
| 57 | sub \ttb0, \ttb1, #IDMAP_DIR_SIZE | ||
| 58 | .endm | ||
| 59 | |||
| 60 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 61 | #define BLOCK_SHIFT PAGE_SHIFT | ||
| 62 | #define BLOCK_SIZE PAGE_SIZE | ||
| 63 | #else | ||
| 64 | #define BLOCK_SHIFT SECTION_SHIFT | ||
| 65 | #define BLOCK_SIZE SECTION_SIZE | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #define KERNEL_START KERNEL_RAM_VADDR | ||
| 69 | #define KERNEL_END _end | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Initial memory map attributes. | ||
| 73 | */ | ||
| 74 | #ifndef CONFIG_SMP | ||
| 75 | #define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF | ||
| 76 | #define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF | ||
| 77 | #else | ||
| 78 | #define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF | PTE_SHARED | ||
| 79 | #define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 83 | #define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS | ||
| 84 | #define IO_MMUFLAGS PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_XN | PTE_FLAGS | ||
| 85 | #else | ||
| 86 | #define MM_MMUFLAGS PMD_ATTRINDX(MT_NORMAL) | PMD_FLAGS | ||
| 87 | #define IO_MMUFLAGS PMD_ATTRINDX(MT_DEVICE_nGnRE) | PMD_SECT_XN | PMD_FLAGS | ||
| 88 | #endif | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Kernel startup entry point. | ||
| 92 | * --------------------------- | ||
| 93 | * | ||
| 94 | * The requirements are: | ||
| 95 | * MMU = off, D-cache = off, I-cache = on or off, | ||
| 96 | * x0 = physical address to the FDT blob. | ||
| 97 | * | ||
| 98 | * This code is mostly position independent so you call this at | ||
| 99 | * __pa(PAGE_OFFSET + TEXT_OFFSET). | ||
| 100 | * | ||
| 101 | * Note that the callee-saved registers are used for storing variables | ||
| 102 | * that are useful before the MMU is enabled. The allocations are described | ||
| 103 | * in the entry routines. | ||
| 104 | */ | ||
| 105 | __HEAD | ||
| 106 | |||
| 107 | /* | ||
| 108 | * DO NOT MODIFY. Image header expected by Linux boot-loaders. | ||
| 109 | */ | ||
| 110 | b stext // branch to kernel start, magic | ||
| 111 | .long 0 // reserved | ||
| 112 | .quad TEXT_OFFSET // Image load offset from start of RAM | ||
| 113 | .quad 0 // reserved | ||
| 114 | .quad 0 // reserved | ||
| 115 | |||
| 116 | ENTRY(stext) | ||
| 117 | mov x21, x0 // x21=FDT | ||
| 118 | bl el2_setup // Drop to EL1 | ||
| 119 | mrs x22, midr_el1 // x22=cpuid | ||
| 120 | mov x0, x22 | ||
| 121 | bl lookup_processor_type | ||
| 122 | mov x23, x0 // x23=current cpu_table | ||
| 123 | cbz x23, __error_p // invalid processor (x23=0)? | ||
| 124 | bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET | ||
| 125 | bl __vet_fdt | ||
| 126 | bl __create_page_tables // x25=TTBR0, x26=TTBR1 | ||
| 127 | /* | ||
| 128 | * The following calls CPU specific code in a position independent | ||
| 129 | * manner. See arch/arm64/mm/proc.S for details. x23 = base of | ||
| 130 | * cpu_info structure selected by lookup_processor_type above. | ||
| 131 | * On return, the CPU will be ready for the MMU to be turned on and | ||
| 132 | * the TCR will have been set. | ||
| 133 | */ | ||
| 134 | ldr x27, __switch_data // address to jump to after | ||
| 135 | // MMU has been enabled | ||
| 136 | adr lr, __enable_mmu // return (PIC) address | ||
| 137 | ldr x12, [x23, #CPU_INFO_SETUP] | ||
| 138 | add x12, x12, x28 // __virt_to_phys | ||
| 139 | br x12 // initialise processor | ||
| 140 | ENDPROC(stext) | ||
| 141 | |||
| 142 | /* | ||
| 143 | * If we're fortunate enough to boot at EL2, ensure that the world is | ||
| 144 | * sane before dropping to EL1. | ||
| 145 | */ | ||
| 146 | ENTRY(el2_setup) | ||
| 147 | mrs x0, CurrentEL | ||
| 148 | cmp x0, #PSR_MODE_EL2t | ||
| 149 | ccmp x0, #PSR_MODE_EL2h, #0x4, ne | ||
| 150 | b.eq 1f | ||
| 151 | ret | ||
| 152 | |||
| 153 | /* Hyp configuration. */ | ||
| 154 | 1: mov x0, #(1 << 31) // 64-bit EL1 | ||
| 155 | msr hcr_el2, x0 | ||
| 156 | |||
| 157 | /* Generic timers. */ | ||
| 158 | mrs x0, cnthctl_el2 | ||
| 159 | orr x0, x0, #3 // Enable EL1 physical timers | ||
| 160 | msr cnthctl_el2, x0 | ||
| 161 | |||
| 162 | /* Populate ID registers. */ | ||
| 163 | mrs x0, midr_el1 | ||
| 164 | mrs x1, mpidr_el1 | ||
| 165 | msr vpidr_el2, x0 | ||
| 166 | msr vmpidr_el2, x1 | ||
| 167 | |||
| 168 | /* sctlr_el1 */ | ||
| 169 | mov x0, #0x0800 // Set/clear RES{1,0} bits | ||
| 170 | movk x0, #0x30d0, lsl #16 | ||
| 171 | msr sctlr_el1, x0 | ||
| 172 | |||
| 173 | /* Coprocessor traps. */ | ||
| 174 | mov x0, #0x33ff | ||
| 175 | msr cptr_el2, x0 // Disable copro. traps to EL2 | ||
| 176 | |||
| 177 | #ifdef CONFIG_COMPAT | ||
| 178 | msr hstr_el2, xzr // Disable CP15 traps to EL2 | ||
| 179 | #endif | ||
| 180 | |||
| 181 | /* spsr */ | ||
| 182 | mov x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ | ||
| 183 | PSR_MODE_EL1h) | ||
| 184 | msr spsr_el2, x0 | ||
| 185 | msr elr_el2, lr | ||
| 186 | eret | ||
| 187 | ENDPROC(el2_setup) | ||
| 188 | |||
| 189 | .align 3 | ||
| 190 | 2: .quad . | ||
| 191 | .quad PAGE_OFFSET | ||
| 192 | |||
| 193 | #ifdef CONFIG_SMP | ||
| 194 | .pushsection .smp.pen.text, "ax" | ||
| 195 | .align 3 | ||
| 196 | 1: .quad . | ||
| 197 | .quad secondary_holding_pen_release | ||
| 198 | |||
| 199 | /* | ||
| 200 | * This provides a "holding pen" for platforms to hold all secondary | ||
| 201 | * cores are held until we're ready for them to initialise. | ||
| 202 | */ | ||
| 203 | ENTRY(secondary_holding_pen) | ||
| 204 | bl el2_setup // Drop to EL1 | ||
| 205 | mrs x0, mpidr_el1 | ||
| 206 | and x0, x0, #15 // CPU number | ||
| 207 | adr x1, 1b | ||
| 208 | ldp x2, x3, [x1] | ||
| 209 | sub x1, x1, x2 | ||
| 210 | add x3, x3, x1 | ||
| 211 | pen: ldr x4, [x3] | ||
| 212 | cmp x4, x0 | ||
| 213 | b.eq secondary_startup | ||
| 214 | wfe | ||
| 215 | b pen | ||
| 216 | ENDPROC(secondary_holding_pen) | ||
| 217 | .popsection | ||
| 218 | |||
| 219 | ENTRY(secondary_startup) | ||
| 220 | /* | ||
| 221 | * Common entry point for secondary CPUs. | ||
| 222 | */ | ||
| 223 | mrs x22, midr_el1 // x22=cpuid | ||
| 224 | mov x0, x22 | ||
| 225 | bl lookup_processor_type | ||
| 226 | mov x23, x0 // x23=current cpu_table | ||
| 227 | cbz x23, __error_p // invalid processor (x23=0)? | ||
| 228 | |||
| 229 | bl __calc_phys_offset // x24=phys offset | ||
| 230 | pgtbl x25, x26, x24 // x25=TTBR0, x26=TTBR1 | ||
| 231 | ldr x12, [x23, #CPU_INFO_SETUP] | ||
| 232 | add x12, x12, x28 // __virt_to_phys | ||
| 233 | blr x12 // initialise processor | ||
| 234 | |||
| 235 | ldr x21, =secondary_data | ||
| 236 | ldr x27, =__secondary_switched // address to jump to after enabling the MMU | ||
| 237 | b __enable_mmu | ||
| 238 | ENDPROC(secondary_startup) | ||
| 239 | |||
| 240 | ENTRY(__secondary_switched) | ||
| 241 | ldr x0, [x21] // get secondary_data.stack | ||
| 242 | mov sp, x0 | ||
| 243 | mov x29, #0 | ||
| 244 | b secondary_start_kernel | ||
| 245 | ENDPROC(__secondary_switched) | ||
| 246 | #endif /* CONFIG_SMP */ | ||
| 247 | |||
| 248 | /* | ||
| 249 | * Setup common bits before finally enabling the MMU. Essentially this is just | ||
| 250 | * loading the page table pointer and vector base registers. | ||
| 251 | * | ||
| 252 | * On entry to this code, x0 must contain the SCTLR_EL1 value for turning on | ||
| 253 | * the MMU. | ||
| 254 | */ | ||
| 255 | __enable_mmu: | ||
| 256 | ldr x5, =vectors | ||
| 257 | msr vbar_el1, x5 | ||
| 258 | msr ttbr0_el1, x25 // load TTBR0 | ||
| 259 | msr ttbr1_el1, x26 // load TTBR1 | ||
| 260 | isb | ||
| 261 | b __turn_mmu_on | ||
| 262 | ENDPROC(__enable_mmu) | ||
| 263 | |||
| 264 | /* | ||
| 265 | * Enable the MMU. This completely changes the structure of the visible memory | ||
| 266 | * space. You will not be able to trace execution through this. | ||
| 267 | * | ||
| 268 | * x0 = system control register | ||
| 269 | * x27 = *virtual* address to jump to upon completion | ||
| 270 | * | ||
| 271 | * other registers depend on the function called upon completion | ||
| 272 | */ | ||
| 273 | .align 6 | ||
| 274 | __turn_mmu_on: | ||
| 275 | msr sctlr_el1, x0 | ||
| 276 | isb | ||
| 277 | br x27 | ||
| 278 | ENDPROC(__turn_mmu_on) | ||
| 279 | |||
| 280 | /* | ||
| 281 | * Calculate the start of physical memory. | ||
| 282 | */ | ||
| 283 | __calc_phys_offset: | ||
| 284 | adr x0, 1f | ||
| 285 | ldp x1, x2, [x0] | ||
| 286 | sub x28, x0, x1 // x28 = PHYS_OFFSET - PAGE_OFFSET | ||
| 287 | add x24, x2, x28 // x24 = PHYS_OFFSET | ||
| 288 | ret | ||
| 289 | ENDPROC(__calc_phys_offset) | ||
| 290 | |||
| 291 | .align 3 | ||
| 292 | 1: .quad . | ||
| 293 | .quad PAGE_OFFSET | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Macro to populate the PGD for the corresponding block entry in the next | ||
| 297 | * level (tbl) for the given virtual address. | ||
| 298 | * | ||
| 299 | * Preserves: pgd, tbl, virt | ||
| 300 | * Corrupts: tmp1, tmp2 | ||
| 301 | */ | ||
| 302 | .macro create_pgd_entry, pgd, tbl, virt, tmp1, tmp2 | ||
| 303 | lsr \tmp1, \virt, #PGDIR_SHIFT | ||
| 304 | and \tmp1, \tmp1, #PTRS_PER_PGD - 1 // PGD index | ||
| 305 | orr \tmp2, \tbl, #3 // PGD entry table type | ||
| 306 | str \tmp2, [\pgd, \tmp1, lsl #3] | ||
| 307 | .endm | ||
| 308 | |||
| 309 | /* | ||
| 310 | * Macro to populate block entries in the page table for the start..end | ||
| 311 | * virtual range (inclusive). | ||
| 312 | * | ||
| 313 | * Preserves: tbl, flags | ||
| 314 | * Corrupts: phys, start, end, pstate | ||
| 315 | */ | ||
| 316 | .macro create_block_map, tbl, flags, phys, start, end, idmap=0 | ||
| 317 | lsr \phys, \phys, #BLOCK_SHIFT | ||
| 318 | .if \idmap | ||
| 319 | and \start, \phys, #PTRS_PER_PTE - 1 // table index | ||
| 320 | .else | ||
| 321 | lsr \start, \start, #BLOCK_SHIFT | ||
| 322 | and \start, \start, #PTRS_PER_PTE - 1 // table index | ||
| 323 | .endif | ||
| 324 | orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry | ||
| 325 | .ifnc \start,\end | ||
| 326 | lsr \end, \end, #BLOCK_SHIFT | ||
| 327 | and \end, \end, #PTRS_PER_PTE - 1 // table end index | ||
| 328 | .endif | ||
| 329 | 9999: str \phys, [\tbl, \start, lsl #3] // store the entry | ||
| 330 | .ifnc \start,\end | ||
| 331 | add \start, \start, #1 // next entry | ||
| 332 | add \phys, \phys, #BLOCK_SIZE // next block | ||
| 333 | cmp \start, \end | ||
| 334 | b.ls 9999b | ||
| 335 | .endif | ||
| 336 | .endm | ||
| 337 | |||
| 338 | /* | ||
| 339 | * Setup the initial page tables. We only setup the barest amount which is | ||
| 340 | * required to get the kernel running. The following sections are required: | ||
| 341 | * - identity mapping to enable the MMU (low address, TTBR0) | ||
| 342 | * - first few MB of the kernel linear mapping to jump to once the MMU has | ||
| 343 | * been enabled, including the FDT blob (TTBR1) | ||
| 344 | */ | ||
| 345 | __create_page_tables: | ||
| 346 | pgtbl x25, x26, x24 // idmap_pg_dir and swapper_pg_dir addresses | ||
| 347 | |||
| 348 | /* | ||
| 349 | * Clear the idmap and swapper page tables. | ||
| 350 | */ | ||
| 351 | mov x0, x25 | ||
| 352 | add x6, x26, #SWAPPER_DIR_SIZE | ||
| 353 | 1: stp xzr, xzr, [x0], #16 | ||
| 354 | stp xzr, xzr, [x0], #16 | ||
| 355 | stp xzr, xzr, [x0], #16 | ||
| 356 | stp xzr, xzr, [x0], #16 | ||
| 357 | cmp x0, x6 | ||
| 358 | b.lo 1b | ||
| 359 | |||
| 360 | ldr x7, =MM_MMUFLAGS | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Create the identity mapping. | ||
| 364 | */ | ||
| 365 | add x0, x25, #PAGE_SIZE // section table address | ||
| 366 | adr x3, __turn_mmu_on // virtual/physical address | ||
| 367 | create_pgd_entry x25, x0, x3, x5, x6 | ||
| 368 | create_block_map x0, x7, x3, x5, x5, idmap=1 | ||
| 369 | |||
| 370 | /* | ||
| 371 | * Map the kernel image (starting with PHYS_OFFSET). | ||
| 372 | */ | ||
| 373 | add x0, x26, #PAGE_SIZE // section table address | ||
| 374 | mov x5, #PAGE_OFFSET | ||
| 375 | create_pgd_entry x26, x0, x5, x3, x6 | ||
| 376 | ldr x6, =KERNEL_END - 1 | ||
| 377 | mov x3, x24 // phys offset | ||
| 378 | create_block_map x0, x7, x3, x5, x6 | ||
| 379 | |||
| 380 | /* | ||
| 381 | * Map the FDT blob (maximum 2MB; must be within 512MB of | ||
| 382 | * PHYS_OFFSET). | ||
| 383 | */ | ||
| 384 | mov x3, x21 // FDT phys address | ||
| 385 | and x3, x3, #~((1 << 21) - 1) // 2MB aligned | ||
| 386 | mov x6, #PAGE_OFFSET | ||
| 387 | sub x5, x3, x24 // subtract PHYS_OFFSET | ||
| 388 | tst x5, #~((1 << 29) - 1) // within 512MB? | ||
| 389 | csel x21, xzr, x21, ne // zero the FDT pointer | ||
| 390 | b.ne 1f | ||
| 391 | add x5, x5, x6 // __va(FDT blob) | ||
| 392 | add x6, x5, #1 << 21 // 2MB for the FDT blob | ||
| 393 | sub x6, x6, #1 // inclusive range | ||
| 394 | create_block_map x0, x7, x3, x5, x6 | ||
| 395 | 1: | ||
| 396 | ret | ||
| 397 | ENDPROC(__create_page_tables) | ||
| 398 | .ltorg | ||
| 399 | |||
| 400 | .align 3 | ||
| 401 | .type __switch_data, %object | ||
| 402 | __switch_data: | ||
| 403 | .quad __mmap_switched | ||
| 404 | .quad __data_loc // x4 | ||
| 405 | .quad _data // x5 | ||
| 406 | .quad __bss_start // x6 | ||
| 407 | .quad _end // x7 | ||
| 408 | .quad processor_id // x4 | ||
| 409 | .quad __fdt_pointer // x5 | ||
| 410 | .quad memstart_addr // x6 | ||
| 411 | .quad init_thread_union + THREAD_START_SP // sp | ||
| 412 | |||
| 413 | /* | ||
| 414 | * The following fragment of code is executed with the MMU on in MMU mode, and | ||
| 415 | * uses absolute addresses; this is not position independent. | ||
| 416 | */ | ||
| 417 | __mmap_switched: | ||
| 418 | adr x3, __switch_data + 8 | ||
| 419 | |||
| 420 | ldp x4, x5, [x3], #16 | ||
| 421 | ldp x6, x7, [x3], #16 | ||
| 422 | cmp x4, x5 // Copy data segment if needed | ||
| 423 | 1: ccmp x5, x6, #4, ne | ||
| 424 | b.eq 2f | ||
| 425 | ldr x16, [x4], #8 | ||
| 426 | str x16, [x5], #8 | ||
| 427 | b 1b | ||
| 428 | 2: | ||
| 429 | 1: cmp x6, x7 | ||
| 430 | b.hs 2f | ||
| 431 | str xzr, [x6], #8 // Clear BSS | ||
| 432 | b 1b | ||
| 433 | 2: | ||
| 434 | ldp x4, x5, [x3], #16 | ||
| 435 | ldr x6, [x3], #8 | ||
| 436 | ldr x16, [x3] | ||
| 437 | mov sp, x16 | ||
| 438 | str x22, [x4] // Save processor ID | ||
| 439 | str x21, [x5] // Save FDT pointer | ||
| 440 | str x24, [x6] // Save PHYS_OFFSET | ||
| 441 | mov x29, #0 | ||
| 442 | b start_kernel | ||
| 443 | ENDPROC(__mmap_switched) | ||
| 444 | |||
| 445 | /* | ||
| 446 | * Exception handling. Something went wrong and we can't proceed. We ought to | ||
| 447 | * tell the user, but since we don't have any guarantee that we're even | ||
| 448 | * running on the right architecture, we do virtually nothing. | ||
| 449 | */ | ||
| 450 | __error_p: | ||
| 451 | ENDPROC(__error_p) | ||
| 452 | |||
| 453 | __error: | ||
| 454 | 1: nop | ||
| 455 | b 1b | ||
| 456 | ENDPROC(__error) | ||
| 457 | |||
| 458 | /* | ||
| 459 | * This function gets the processor ID in w0 and searches the cpu_table[] for | ||
| 460 | * a match. It returns a pointer to the struct cpu_info it found. The | ||
| 461 | * cpu_table[] must end with an empty (all zeros) structure. | ||
| 462 | * | ||
| 463 | * This routine can be called via C code and it needs to work with the MMU | ||
| 464 | * both disabled and enabled (the offset is calculated automatically). | ||
| 465 | */ | ||
| 466 | ENTRY(lookup_processor_type) | ||
| 467 | adr x1, __lookup_processor_type_data | ||
| 468 | ldp x2, x3, [x1] | ||
| 469 | sub x1, x1, x2 // get offset between VA and PA | ||
| 470 | add x3, x3, x1 // convert VA to PA | ||
| 471 | 1: | ||
| 472 | ldp w5, w6, [x3] // load cpu_id_val and cpu_id_mask | ||
| 473 | cbz w5, 2f // end of list? | ||
| 474 | and w6, w6, w0 | ||
| 475 | cmp w5, w6 | ||
| 476 | b.eq 3f | ||
| 477 | add x3, x3, #CPU_INFO_SZ | ||
| 478 | b 1b | ||
| 479 | 2: | ||
| 480 | mov x3, #0 // unknown processor | ||
| 481 | 3: | ||
| 482 | mov x0, x3 | ||
| 483 | ret | ||
| 484 | ENDPROC(lookup_processor_type) | ||
| 485 | |||
| 486 | .align 3 | ||
| 487 | .type __lookup_processor_type_data, %object | ||
| 488 | __lookup_processor_type_data: | ||
| 489 | .quad . | ||
| 490 | .quad cpu_table | ||
| 491 | .size __lookup_processor_type_data, . - __lookup_processor_type_data | ||
| 492 | |||
| 493 | /* | ||
| 494 | * Determine validity of the x21 FDT pointer. | ||
| 495 | * The dtb must be 8-byte aligned and live in the first 512M of memory. | ||
| 496 | */ | ||
| 497 | __vet_fdt: | ||
| 498 | tst x21, #0x7 | ||
| 499 | b.ne 1f | ||
| 500 | cmp x21, x24 | ||
| 501 | b.lt 1f | ||
| 502 | mov x0, #(1 << 29) | ||
| 503 | add x0, x0, x24 | ||
| 504 | cmp x21, x0 | ||
| 505 | b.ge 1f | ||
| 506 | ret | ||
| 507 | 1: | ||
| 508 | mov x21, #0 | ||
| 509 | ret | ||
| 510 | ENDPROC(__vet_fdt) | ||
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c new file mode 100644 index 000000000000..5ab825c59db9 --- /dev/null +++ b/arch/arm64/kernel/hw_breakpoint.c | |||
| @@ -0,0 +1,880 @@ | |||
| 1 | /* | ||
| 2 | * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility, | ||
| 3 | * using the CPU's debug registers. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 ARM Limited | ||
| 6 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define pr_fmt(fmt) "hw-breakpoint: " fmt | ||
| 22 | |||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/hw_breakpoint.h> | ||
| 25 | #include <linux/perf_event.h> | ||
| 26 | #include <linux/ptrace.h> | ||
| 27 | #include <linux/smp.h> | ||
| 28 | |||
| 29 | #include <asm/compat.h> | ||
| 30 | #include <asm/current.h> | ||
| 31 | #include <asm/debug-monitors.h> | ||
| 32 | #include <asm/hw_breakpoint.h> | ||
| 33 | #include <asm/kdebug.h> | ||
| 34 | #include <asm/traps.h> | ||
| 35 | #include <asm/cputype.h> | ||
| 36 | #include <asm/system_misc.h> | ||
| 37 | |||
| 38 | /* Breakpoint currently in use for each BRP. */ | ||
| 39 | static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]); | ||
| 40 | |||
| 41 | /* Watchpoint currently in use for each WRP. */ | ||
| 42 | static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]); | ||
| 43 | |||
| 44 | /* Currently stepping a per-CPU kernel breakpoint. */ | ||
| 45 | static DEFINE_PER_CPU(int, stepping_kernel_bp); | ||
| 46 | |||
| 47 | /* Number of BRP/WRP registers on this CPU. */ | ||
| 48 | static int core_num_brps; | ||
| 49 | static int core_num_wrps; | ||
| 50 | |||
| 51 | /* Determine number of BRP registers available. */ | ||
| 52 | static int get_num_brps(void) | ||
| 53 | { | ||
| 54 | return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* Determine number of WRP registers available. */ | ||
| 58 | static int get_num_wrps(void) | ||
| 59 | { | ||
| 60 | return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | int hw_breakpoint_slots(int type) | ||
| 64 | { | ||
| 65 | /* | ||
| 66 | * We can be called early, so don't rely on | ||
| 67 | * our static variables being initialised. | ||
| 68 | */ | ||
| 69 | switch (type) { | ||
| 70 | case TYPE_INST: | ||
| 71 | return get_num_brps(); | ||
| 72 | case TYPE_DATA: | ||
| 73 | return get_num_wrps(); | ||
| 74 | default: | ||
| 75 | pr_warning("unknown slot type: %d\n", type); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | #define READ_WB_REG_CASE(OFF, N, REG, VAL) \ | ||
| 81 | case (OFF + N): \ | ||
| 82 | AARCH64_DBG_READ(N, REG, VAL); \ | ||
| 83 | break | ||
| 84 | |||
| 85 | #define WRITE_WB_REG_CASE(OFF, N, REG, VAL) \ | ||
| 86 | case (OFF + N): \ | ||
| 87 | AARCH64_DBG_WRITE(N, REG, VAL); \ | ||
| 88 | break | ||
| 89 | |||
| 90 | #define GEN_READ_WB_REG_CASES(OFF, REG, VAL) \ | ||
| 91 | READ_WB_REG_CASE(OFF, 0, REG, VAL); \ | ||
| 92 | READ_WB_REG_CASE(OFF, 1, REG, VAL); \ | ||
| 93 | READ_WB_REG_CASE(OFF, 2, REG, VAL); \ | ||
| 94 | READ_WB_REG_CASE(OFF, 3, REG, VAL); \ | ||
| 95 | READ_WB_REG_CASE(OFF, 4, REG, VAL); \ | ||
| 96 | READ_WB_REG_CASE(OFF, 5, REG, VAL); \ | ||
| 97 | READ_WB_REG_CASE(OFF, 6, REG, VAL); \ | ||
| 98 | READ_WB_REG_CASE(OFF, 7, REG, VAL); \ | ||
| 99 | READ_WB_REG_CASE(OFF, 8, REG, VAL); \ | ||
| 100 | READ_WB_REG_CASE(OFF, 9, REG, VAL); \ | ||
| 101 | READ_WB_REG_CASE(OFF, 10, REG, VAL); \ | ||
| 102 | READ_WB_REG_CASE(OFF, 11, REG, VAL); \ | ||
| 103 | READ_WB_REG_CASE(OFF, 12, REG, VAL); \ | ||
| 104 | READ_WB_REG_CASE(OFF, 13, REG, VAL); \ | ||
| 105 | READ_WB_REG_CASE(OFF, 14, REG, VAL); \ | ||
| 106 | READ_WB_REG_CASE(OFF, 15, REG, VAL) | ||
| 107 | |||
| 108 | #define GEN_WRITE_WB_REG_CASES(OFF, REG, VAL) \ | ||
| 109 | WRITE_WB_REG_CASE(OFF, 0, REG, VAL); \ | ||
| 110 | WRITE_WB_REG_CASE(OFF, 1, REG, VAL); \ | ||
| 111 | WRITE_WB_REG_CASE(OFF, 2, REG, VAL); \ | ||
| 112 | WRITE_WB_REG_CASE(OFF, 3, REG, VAL); \ | ||
| 113 | WRITE_WB_REG_CASE(OFF, 4, REG, VAL); \ | ||
| 114 | WRITE_WB_REG_CASE(OFF, 5, REG, VAL); \ | ||
| 115 | WRITE_WB_REG_CASE(OFF, 6, REG, VAL); \ | ||
| 116 | WRITE_WB_REG_CASE(OFF, 7, REG, VAL); \ | ||
| 117 | WRITE_WB_REG_CASE(OFF, 8, REG, VAL); \ | ||
| 118 | WRITE_WB_REG_CASE(OFF, 9, REG, VAL); \ | ||
| 119 | WRITE_WB_REG_CASE(OFF, 10, REG, VAL); \ | ||
| 120 | WRITE_WB_REG_CASE(OFF, 11, REG, VAL); \ | ||
| 121 | WRITE_WB_REG_CASE(OFF, 12, REG, VAL); \ | ||
| 122 | WRITE_WB_REG_CASE(OFF, 13, REG, VAL); \ | ||
| 123 | WRITE_WB_REG_CASE(OFF, 14, REG, VAL); \ | ||
| 124 | WRITE_WB_REG_CASE(OFF, 15, REG, VAL) | ||
| 125 | |||
| 126 | static u64 read_wb_reg(int reg, int n) | ||
| 127 | { | ||
| 128 | u64 val = 0; | ||
| 129 | |||
| 130 | switch (reg + n) { | ||
| 131 | GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val); | ||
| 132 | GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val); | ||
| 133 | GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val); | ||
| 134 | GEN_READ_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val); | ||
| 135 | default: | ||
| 136 | pr_warning("attempt to read from unknown breakpoint register %d\n", n); | ||
| 137 | } | ||
| 138 | |||
| 139 | return val; | ||
| 140 | } | ||
| 141 | |||
| 142 | static void write_wb_reg(int reg, int n, u64 val) | ||
| 143 | { | ||
| 144 | switch (reg + n) { | ||
| 145 | GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BVR, AARCH64_DBG_REG_NAME_BVR, val); | ||
| 146 | GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_BCR, AARCH64_DBG_REG_NAME_BCR, val); | ||
| 147 | GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WVR, AARCH64_DBG_REG_NAME_WVR, val); | ||
| 148 | GEN_WRITE_WB_REG_CASES(AARCH64_DBG_REG_WCR, AARCH64_DBG_REG_NAME_WCR, val); | ||
| 149 | default: | ||
| 150 | pr_warning("attempt to write to unknown breakpoint register %d\n", n); | ||
| 151 | } | ||
| 152 | isb(); | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Convert a breakpoint privilege level to the corresponding exception | ||
| 157 | * level. | ||
| 158 | */ | ||
| 159 | static enum debug_el debug_exception_level(int privilege) | ||
| 160 | { | ||
| 161 | switch (privilege) { | ||
| 162 | case AARCH64_BREAKPOINT_EL0: | ||
| 163 | return DBG_ACTIVE_EL0; | ||
| 164 | case AARCH64_BREAKPOINT_EL1: | ||
| 165 | return DBG_ACTIVE_EL1; | ||
| 166 | default: | ||
| 167 | pr_warning("invalid breakpoint privilege level %d\n", privilege); | ||
| 168 | return -EINVAL; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | /* | ||
| 173 | * Install a perf counter breakpoint. | ||
| 174 | */ | ||
| 175 | int arch_install_hw_breakpoint(struct perf_event *bp) | ||
| 176 | { | ||
| 177 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
| 178 | struct perf_event **slot, **slots; | ||
| 179 | struct debug_info *debug_info = ¤t->thread.debug; | ||
| 180 | int i, max_slots, ctrl_reg, val_reg, reg_enable; | ||
| 181 | u32 ctrl; | ||
| 182 | |||
| 183 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
| 184 | /* Breakpoint */ | ||
| 185 | ctrl_reg = AARCH64_DBG_REG_BCR; | ||
| 186 | val_reg = AARCH64_DBG_REG_BVR; | ||
| 187 | slots = __get_cpu_var(bp_on_reg); | ||
| 188 | max_slots = core_num_brps; | ||
| 189 | reg_enable = !debug_info->bps_disabled; | ||
| 190 | } else { | ||
| 191 | /* Watchpoint */ | ||
| 192 | ctrl_reg = AARCH64_DBG_REG_WCR; | ||
| 193 | val_reg = AARCH64_DBG_REG_WVR; | ||
| 194 | slots = __get_cpu_var(wp_on_reg); | ||
| 195 | max_slots = core_num_wrps; | ||
| 196 | reg_enable = !debug_info->wps_disabled; | ||
| 197 | } | ||
| 198 | |||
| 199 | for (i = 0; i < max_slots; ++i) { | ||
| 200 | slot = &slots[i]; | ||
| 201 | |||
| 202 | if (!*slot) { | ||
| 203 | *slot = bp; | ||
| 204 | break; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) | ||
| 209 | return -ENOSPC; | ||
| 210 | |||
| 211 | /* Ensure debug monitors are enabled at the correct exception level. */ | ||
| 212 | enable_debug_monitors(debug_exception_level(info->ctrl.privilege)); | ||
| 213 | |||
| 214 | /* Setup the address register. */ | ||
| 215 | write_wb_reg(val_reg, i, info->address); | ||
| 216 | |||
| 217 | /* Setup the control register. */ | ||
| 218 | ctrl = encode_ctrl_reg(info->ctrl); | ||
| 219 | write_wb_reg(ctrl_reg, i, reg_enable ? ctrl | 0x1 : ctrl & ~0x1); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | void arch_uninstall_hw_breakpoint(struct perf_event *bp) | ||
| 225 | { | ||
| 226 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
| 227 | struct perf_event **slot, **slots; | ||
| 228 | int i, max_slots, base; | ||
| 229 | |||
| 230 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
| 231 | /* Breakpoint */ | ||
| 232 | base = AARCH64_DBG_REG_BCR; | ||
| 233 | slots = __get_cpu_var(bp_on_reg); | ||
| 234 | max_slots = core_num_brps; | ||
| 235 | } else { | ||
| 236 | /* Watchpoint */ | ||
| 237 | base = AARCH64_DBG_REG_WCR; | ||
| 238 | slots = __get_cpu_var(wp_on_reg); | ||
| 239 | max_slots = core_num_wrps; | ||
| 240 | } | ||
| 241 | |||
| 242 | /* Remove the breakpoint. */ | ||
| 243 | for (i = 0; i < max_slots; ++i) { | ||
| 244 | slot = &slots[i]; | ||
| 245 | |||
| 246 | if (*slot == bp) { | ||
| 247 | *slot = NULL; | ||
| 248 | break; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) | ||
| 253 | return; | ||
| 254 | |||
| 255 | /* Reset the control register. */ | ||
| 256 | write_wb_reg(base, i, 0); | ||
| 257 | |||
| 258 | /* Release the debug monitors for the correct exception level. */ | ||
| 259 | disable_debug_monitors(debug_exception_level(info->ctrl.privilege)); | ||
| 260 | } | ||
| 261 | |||
| 262 | static int get_hbp_len(u8 hbp_len) | ||
| 263 | { | ||
| 264 | unsigned int len_in_bytes = 0; | ||
| 265 | |||
| 266 | switch (hbp_len) { | ||
| 267 | case ARM_BREAKPOINT_LEN_1: | ||
| 268 | len_in_bytes = 1; | ||
| 269 | break; | ||
| 270 | case ARM_BREAKPOINT_LEN_2: | ||
| 271 | len_in_bytes = 2; | ||
| 272 | break; | ||
| 273 | case ARM_BREAKPOINT_LEN_4: | ||
| 274 | len_in_bytes = 4; | ||
| 275 | break; | ||
| 276 | case ARM_BREAKPOINT_LEN_8: | ||
| 277 | len_in_bytes = 8; | ||
| 278 | break; | ||
| 279 | } | ||
| 280 | |||
| 281 | return len_in_bytes; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * Check whether bp virtual address is in kernel space. | ||
| 286 | */ | ||
| 287 | int arch_check_bp_in_kernelspace(struct perf_event *bp) | ||
| 288 | { | ||
| 289 | unsigned int len; | ||
| 290 | unsigned long va; | ||
| 291 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
| 292 | |||
| 293 | va = info->address; | ||
| 294 | len = get_hbp_len(info->ctrl.len); | ||
| 295 | |||
| 296 | return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); | ||
| 297 | } | ||
| 298 | |||
| 299 | /* | ||
| 300 | * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl. | ||
| 301 | * Hopefully this will disappear when ptrace can bypass the conversion | ||
| 302 | * to generic breakpoint descriptions. | ||
| 303 | */ | ||
| 304 | int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, | ||
| 305 | int *gen_len, int *gen_type) | ||
| 306 | { | ||
| 307 | /* Type */ | ||
| 308 | switch (ctrl.type) { | ||
| 309 | case ARM_BREAKPOINT_EXECUTE: | ||
| 310 | *gen_type = HW_BREAKPOINT_X; | ||
| 311 | break; | ||
| 312 | case ARM_BREAKPOINT_LOAD: | ||
| 313 | *gen_type = HW_BREAKPOINT_R; | ||
| 314 | break; | ||
| 315 | case ARM_BREAKPOINT_STORE: | ||
| 316 | *gen_type = HW_BREAKPOINT_W; | ||
| 317 | break; | ||
| 318 | case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE: | ||
| 319 | *gen_type = HW_BREAKPOINT_RW; | ||
| 320 | break; | ||
| 321 | default: | ||
| 322 | return -EINVAL; | ||
| 323 | } | ||
| 324 | |||
| 325 | /* Len */ | ||
| 326 | switch (ctrl.len) { | ||
| 327 | case ARM_BREAKPOINT_LEN_1: | ||
| 328 | *gen_len = HW_BREAKPOINT_LEN_1; | ||
| 329 | break; | ||
| 330 | case ARM_BREAKPOINT_LEN_2: | ||
| 331 | *gen_len = HW_BREAKPOINT_LEN_2; | ||
| 332 | break; | ||
| 333 | case ARM_BREAKPOINT_LEN_4: | ||
| 334 | *gen_len = HW_BREAKPOINT_LEN_4; | ||
| 335 | break; | ||
| 336 | case ARM_BREAKPOINT_LEN_8: | ||
| 337 | *gen_len = HW_BREAKPOINT_LEN_8; | ||
| 338 | break; | ||
| 339 | default: | ||
| 340 | return -EINVAL; | ||
| 341 | } | ||
| 342 | |||
| 343 | return 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* | ||
| 347 | * Construct an arch_hw_breakpoint from a perf_event. | ||
| 348 | */ | ||
| 349 | static int arch_build_bp_info(struct perf_event *bp) | ||
| 350 | { | ||
| 351 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
| 352 | |||
| 353 | /* Type */ | ||
| 354 | switch (bp->attr.bp_type) { | ||
| 355 | case HW_BREAKPOINT_X: | ||
| 356 | info->ctrl.type = ARM_BREAKPOINT_EXECUTE; | ||
| 357 | break; | ||
| 358 | case HW_BREAKPOINT_R: | ||
| 359 | info->ctrl.type = ARM_BREAKPOINT_LOAD; | ||
| 360 | break; | ||
| 361 | case HW_BREAKPOINT_W: | ||
| 362 | info->ctrl.type = ARM_BREAKPOINT_STORE; | ||
| 363 | break; | ||
| 364 | case HW_BREAKPOINT_RW: | ||
| 365 | info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; | ||
| 366 | break; | ||
| 367 | default: | ||
| 368 | return -EINVAL; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* Len */ | ||
| 372 | switch (bp->attr.bp_len) { | ||
| 373 | case HW_BREAKPOINT_LEN_1: | ||
| 374 | info->ctrl.len = ARM_BREAKPOINT_LEN_1; | ||
| 375 | break; | ||
| 376 | case HW_BREAKPOINT_LEN_2: | ||
| 377 | info->ctrl.len = ARM_BREAKPOINT_LEN_2; | ||
| 378 | break; | ||
| 379 | case HW_BREAKPOINT_LEN_4: | ||
| 380 | info->ctrl.len = ARM_BREAKPOINT_LEN_4; | ||
| 381 | break; | ||
| 382 | case HW_BREAKPOINT_LEN_8: | ||
| 383 | info->ctrl.len = ARM_BREAKPOINT_LEN_8; | ||
| 384 | break; | ||
| 385 | default: | ||
| 386 | return -EINVAL; | ||
| 387 | } | ||
| 388 | |||
| 389 | /* | ||
| 390 | * On AArch64, we only permit breakpoints of length 4, whereas | ||
| 391 | * AArch32 also requires breakpoints of length 2 for Thumb. | ||
| 392 | * Watchpoints can be of length 1, 2, 4 or 8 bytes. | ||
| 393 | */ | ||
| 394 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { | ||
| 395 | if (is_compat_task()) { | ||
| 396 | if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 && | ||
| 397 | info->ctrl.len != ARM_BREAKPOINT_LEN_4) | ||
| 398 | return -EINVAL; | ||
| 399 | } else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) { | ||
| 400 | /* | ||
| 401 | * FIXME: Some tools (I'm looking at you perf) assume | ||
| 402 | * that breakpoints should be sizeof(long). This | ||
| 403 | * is nonsense. For now, we fix up the parameter | ||
| 404 | * but we should probably return -EINVAL instead. | ||
| 405 | */ | ||
| 406 | info->ctrl.len = ARM_BREAKPOINT_LEN_4; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | /* Address */ | ||
| 411 | info->address = bp->attr.bp_addr; | ||
| 412 | |||
| 413 | /* | ||
| 414 | * Privilege | ||
| 415 | * Note that we disallow combined EL0/EL1 breakpoints because | ||
| 416 | * that would complicate the stepping code. | ||
| 417 | */ | ||
| 418 | if (arch_check_bp_in_kernelspace(bp)) | ||
| 419 | info->ctrl.privilege = AARCH64_BREAKPOINT_EL1; | ||
| 420 | else | ||
| 421 | info->ctrl.privilege = AARCH64_BREAKPOINT_EL0; | ||
| 422 | |||
| 423 | /* Enabled? */ | ||
| 424 | info->ctrl.enabled = !bp->attr.disabled; | ||
| 425 | |||
| 426 | return 0; | ||
| 427 | } | ||
| 428 | |||
| 429 | /* | ||
| 430 | * Validate the arch-specific HW Breakpoint register settings. | ||
| 431 | */ | ||
| 432 | int arch_validate_hwbkpt_settings(struct perf_event *bp) | ||
| 433 | { | ||
| 434 | struct arch_hw_breakpoint *info = counter_arch_bp(bp); | ||
| 435 | int ret; | ||
| 436 | u64 alignment_mask, offset; | ||
| 437 | |||
| 438 | /* Build the arch_hw_breakpoint. */ | ||
| 439 | ret = arch_build_bp_info(bp); | ||
| 440 | if (ret) | ||
| 441 | return ret; | ||
| 442 | |||
| 443 | /* | ||
| 444 | * Check address alignment. | ||
| 445 | * We don't do any clever alignment correction for watchpoints | ||
| 446 | * because using 64-bit unaligned addresses is deprecated for | ||
| 447 | * AArch64. | ||
| 448 | * | ||
| 449 | * AArch32 tasks expect some simple alignment fixups, so emulate | ||
| 450 | * that here. | ||
| 451 | */ | ||
| 452 | if (is_compat_task()) { | ||
| 453 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) | ||
| 454 | alignment_mask = 0x7; | ||
| 455 | else | ||
| 456 | alignment_mask = 0x3; | ||
| 457 | offset = info->address & alignment_mask; | ||
| 458 | switch (offset) { | ||
| 459 | case 0: | ||
| 460 | /* Aligned */ | ||
| 461 | break; | ||
| 462 | case 1: | ||
| 463 | /* Allow single byte watchpoint. */ | ||
| 464 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) | ||
| 465 | break; | ||
| 466 | case 2: | ||
| 467 | /* Allow halfword watchpoints and breakpoints. */ | ||
| 468 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) | ||
| 469 | break; | ||
| 470 | default: | ||
| 471 | return -EINVAL; | ||
| 472 | } | ||
| 473 | |||
| 474 | info->address &= ~alignment_mask; | ||
| 475 | info->ctrl.len <<= offset; | ||
| 476 | } else { | ||
| 477 | if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) | ||
| 478 | alignment_mask = 0x3; | ||
| 479 | else | ||
| 480 | alignment_mask = 0x7; | ||
| 481 | if (info->address & alignment_mask) | ||
| 482 | return -EINVAL; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* | ||
| 486 | * Disallow per-task kernel breakpoints since these would | ||
| 487 | * complicate the stepping code. | ||
| 488 | */ | ||
| 489 | if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.bp_target) | ||
| 490 | return -EINVAL; | ||
| 491 | |||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | /* | ||
| 496 | * Enable/disable all of the breakpoints active at the specified | ||
| 497 | * exception level at the register level. | ||
| 498 | * This is used when single-stepping after a breakpoint exception. | ||
| 499 | */ | ||
| 500 | static void toggle_bp_registers(int reg, enum debug_el el, int enable) | ||
| 501 | { | ||
| 502 | int i, max_slots, privilege; | ||
| 503 | u32 ctrl; | ||
| 504 | struct perf_event **slots; | ||
| 505 | |||
| 506 | switch (reg) { | ||
| 507 | case AARCH64_DBG_REG_BCR: | ||
| 508 | slots = __get_cpu_var(bp_on_reg); | ||
| 509 | max_slots = core_num_brps; | ||
| 510 | break; | ||
| 511 | case AARCH64_DBG_REG_WCR: | ||
| 512 | slots = __get_cpu_var(wp_on_reg); | ||
| 513 | max_slots = core_num_wrps; | ||
| 514 | break; | ||
| 515 | default: | ||
| 516 | return; | ||
| 517 | } | ||
| 518 | |||
| 519 | for (i = 0; i < max_slots; ++i) { | ||
| 520 | if (!slots[i]) | ||
| 521 | continue; | ||
| 522 | |||
| 523 | privilege = counter_arch_bp(slots[i])->ctrl.privilege; | ||
| 524 | if (debug_exception_level(privilege) != el) | ||
| 525 | continue; | ||
| 526 | |||
| 527 | ctrl = read_wb_reg(reg, i); | ||
| 528 | if (enable) | ||
| 529 | ctrl |= 0x1; | ||
| 530 | else | ||
| 531 | ctrl &= ~0x1; | ||
| 532 | write_wb_reg(reg, i, ctrl); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | /* | ||
| 537 | * Debug exception handlers. | ||
| 538 | */ | ||
| 539 | static int breakpoint_handler(unsigned long unused, unsigned int esr, | ||
| 540 | struct pt_regs *regs) | ||
| 541 | { | ||
| 542 | int i, step = 0, *kernel_step; | ||
| 543 | u32 ctrl_reg; | ||
| 544 | u64 addr, val; | ||
| 545 | struct perf_event *bp, **slots; | ||
| 546 | struct debug_info *debug_info; | ||
| 547 | struct arch_hw_breakpoint_ctrl ctrl; | ||
| 548 | |||
| 549 | slots = (struct perf_event **)__get_cpu_var(bp_on_reg); | ||
| 550 | addr = instruction_pointer(regs); | ||
| 551 | debug_info = ¤t->thread.debug; | ||
| 552 | |||
| 553 | for (i = 0; i < core_num_brps; ++i) { | ||
| 554 | rcu_read_lock(); | ||
| 555 | |||
| 556 | bp = slots[i]; | ||
| 557 | |||
| 558 | if (bp == NULL) | ||
| 559 | goto unlock; | ||
| 560 | |||
| 561 | /* Check if the breakpoint value matches. */ | ||
| 562 | val = read_wb_reg(AARCH64_DBG_REG_BVR, i); | ||
| 563 | if (val != (addr & ~0x3)) | ||
| 564 | goto unlock; | ||
| 565 | |||
| 566 | /* Possible match, check the byte address select to confirm. */ | ||
| 567 | ctrl_reg = read_wb_reg(AARCH64_DBG_REG_BCR, i); | ||
| 568 | decode_ctrl_reg(ctrl_reg, &ctrl); | ||
| 569 | if (!((1 << (addr & 0x3)) & ctrl.len)) | ||
| 570 | goto unlock; | ||
| 571 | |||
| 572 | counter_arch_bp(bp)->trigger = addr; | ||
| 573 | perf_bp_event(bp, regs); | ||
| 574 | |||
| 575 | /* Do we need to handle the stepping? */ | ||
| 576 | if (!bp->overflow_handler) | ||
| 577 | step = 1; | ||
| 578 | unlock: | ||
| 579 | rcu_read_unlock(); | ||
| 580 | } | ||
| 581 | |||
| 582 | if (!step) | ||
| 583 | return 0; | ||
| 584 | |||
| 585 | if (user_mode(regs)) { | ||
| 586 | debug_info->bps_disabled = 1; | ||
| 587 | toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 0); | ||
| 588 | |||
| 589 | /* If we're already stepping a watchpoint, just return. */ | ||
| 590 | if (debug_info->wps_disabled) | ||
| 591 | return 0; | ||
| 592 | |||
| 593 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
| 594 | debug_info->suspended_step = 1; | ||
| 595 | else | ||
| 596 | user_enable_single_step(current); | ||
| 597 | } else { | ||
| 598 | toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL1, 0); | ||
| 599 | kernel_step = &__get_cpu_var(stepping_kernel_bp); | ||
| 600 | |||
| 601 | if (*kernel_step != ARM_KERNEL_STEP_NONE) | ||
| 602 | return 0; | ||
| 603 | |||
| 604 | if (kernel_active_single_step()) { | ||
| 605 | *kernel_step = ARM_KERNEL_STEP_SUSPEND; | ||
| 606 | } else { | ||
| 607 | *kernel_step = ARM_KERNEL_STEP_ACTIVE; | ||
| 608 | kernel_enable_single_step(regs); | ||
| 609 | } | ||
| 610 | } | ||
| 611 | |||
| 612 | return 0; | ||
| 613 | } | ||
| 614 | |||
| 615 | static int watchpoint_handler(unsigned long addr, unsigned int esr, | ||
| 616 | struct pt_regs *regs) | ||
| 617 | { | ||
| 618 | int i, step = 0, *kernel_step, access; | ||
| 619 | u32 ctrl_reg; | ||
| 620 | u64 val, alignment_mask; | ||
| 621 | struct perf_event *wp, **slots; | ||
| 622 | struct debug_info *debug_info; | ||
| 623 | struct arch_hw_breakpoint *info; | ||
| 624 | struct arch_hw_breakpoint_ctrl ctrl; | ||
| 625 | |||
| 626 | slots = (struct perf_event **)__get_cpu_var(wp_on_reg); | ||
| 627 | debug_info = ¤t->thread.debug; | ||
| 628 | |||
| 629 | for (i = 0; i < core_num_wrps; ++i) { | ||
| 630 | rcu_read_lock(); | ||
| 631 | |||
| 632 | wp = slots[i]; | ||
| 633 | |||
| 634 | if (wp == NULL) | ||
| 635 | goto unlock; | ||
| 636 | |||
| 637 | info = counter_arch_bp(wp); | ||
| 638 | /* AArch32 watchpoints are either 4 or 8 bytes aligned. */ | ||
| 639 | if (is_compat_task()) { | ||
| 640 | if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) | ||
| 641 | alignment_mask = 0x7; | ||
| 642 | else | ||
| 643 | alignment_mask = 0x3; | ||
| 644 | } else { | ||
| 645 | alignment_mask = 0x7; | ||
| 646 | } | ||
| 647 | |||
| 648 | /* Check if the watchpoint value matches. */ | ||
| 649 | val = read_wb_reg(AARCH64_DBG_REG_WVR, i); | ||
| 650 | if (val != (addr & ~alignment_mask)) | ||
| 651 | goto unlock; | ||
| 652 | |||
| 653 | /* Possible match, check the byte address select to confirm. */ | ||
| 654 | ctrl_reg = read_wb_reg(AARCH64_DBG_REG_WCR, i); | ||
| 655 | decode_ctrl_reg(ctrl_reg, &ctrl); | ||
| 656 | if (!((1 << (addr & alignment_mask)) & ctrl.len)) | ||
| 657 | goto unlock; | ||
| 658 | |||
| 659 | /* | ||
| 660 | * Check that the access type matches. | ||
| 661 | * 0 => load, otherwise => store | ||
| 662 | */ | ||
| 663 | access = (esr & AARCH64_ESR_ACCESS_MASK) ? HW_BREAKPOINT_W : | ||
| 664 | HW_BREAKPOINT_R; | ||
| 665 | if (!(access & hw_breakpoint_type(wp))) | ||
| 666 | goto unlock; | ||
| 667 | |||
| 668 | info->trigger = addr; | ||
| 669 | perf_bp_event(wp, regs); | ||
| 670 | |||
| 671 | /* Do we need to handle the stepping? */ | ||
| 672 | if (!wp->overflow_handler) | ||
| 673 | step = 1; | ||
| 674 | |||
| 675 | unlock: | ||
| 676 | rcu_read_unlock(); | ||
| 677 | } | ||
| 678 | |||
| 679 | if (!step) | ||
| 680 | return 0; | ||
| 681 | |||
| 682 | /* | ||
| 683 | * We always disable EL0 watchpoints because the kernel can | ||
| 684 | * cause these to fire via an unprivileged access. | ||
| 685 | */ | ||
| 686 | toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 0); | ||
| 687 | |||
| 688 | if (user_mode(regs)) { | ||
| 689 | debug_info->wps_disabled = 1; | ||
| 690 | |||
| 691 | /* If we're already stepping a breakpoint, just return. */ | ||
| 692 | if (debug_info->bps_disabled) | ||
| 693 | return 0; | ||
| 694 | |||
| 695 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
| 696 | debug_info->suspended_step = 1; | ||
| 697 | else | ||
| 698 | user_enable_single_step(current); | ||
| 699 | } else { | ||
| 700 | toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL1, 0); | ||
| 701 | kernel_step = &__get_cpu_var(stepping_kernel_bp); | ||
| 702 | |||
| 703 | if (*kernel_step != ARM_KERNEL_STEP_NONE) | ||
| 704 | return 0; | ||
| 705 | |||
| 706 | if (kernel_active_single_step()) { | ||
| 707 | *kernel_step = ARM_KERNEL_STEP_SUSPEND; | ||
| 708 | } else { | ||
| 709 | *kernel_step = ARM_KERNEL_STEP_ACTIVE; | ||
| 710 | kernel_enable_single_step(regs); | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | return 0; | ||
| 715 | } | ||
| 716 | |||
| 717 | /* | ||
| 718 | * Handle single-step exception. | ||
| 719 | */ | ||
| 720 | int reinstall_suspended_bps(struct pt_regs *regs) | ||
| 721 | { | ||
| 722 | struct debug_info *debug_info = ¤t->thread.debug; | ||
| 723 | int handled_exception = 0, *kernel_step; | ||
| 724 | |||
| 725 | kernel_step = &__get_cpu_var(stepping_kernel_bp); | ||
| 726 | |||
| 727 | /* | ||
| 728 | * Called from single-step exception handler. | ||
| 729 | * Return 0 if execution can resume, 1 if a SIGTRAP should be | ||
| 730 | * reported. | ||
| 731 | */ | ||
| 732 | if (user_mode(regs)) { | ||
| 733 | if (debug_info->bps_disabled) { | ||
| 734 | debug_info->bps_disabled = 0; | ||
| 735 | toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL0, 1); | ||
| 736 | handled_exception = 1; | ||
| 737 | } | ||
| 738 | |||
| 739 | if (debug_info->wps_disabled) { | ||
| 740 | debug_info->wps_disabled = 0; | ||
| 741 | toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1); | ||
| 742 | handled_exception = 1; | ||
| 743 | } | ||
| 744 | |||
| 745 | if (handled_exception) { | ||
| 746 | if (debug_info->suspended_step) { | ||
| 747 | debug_info->suspended_step = 0; | ||
| 748 | /* Allow exception handling to fall-through. */ | ||
| 749 | handled_exception = 0; | ||
| 750 | } else { | ||
| 751 | user_disable_single_step(current); | ||
| 752 | } | ||
| 753 | } | ||
| 754 | } else if (*kernel_step != ARM_KERNEL_STEP_NONE) { | ||
| 755 | toggle_bp_registers(AARCH64_DBG_REG_BCR, DBG_ACTIVE_EL1, 1); | ||
| 756 | toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL1, 1); | ||
| 757 | |||
| 758 | if (!debug_info->wps_disabled) | ||
| 759 | toggle_bp_registers(AARCH64_DBG_REG_WCR, DBG_ACTIVE_EL0, 1); | ||
| 760 | |||
| 761 | if (*kernel_step != ARM_KERNEL_STEP_SUSPEND) { | ||
| 762 | kernel_disable_single_step(); | ||
| 763 | handled_exception = 1; | ||
| 764 | } else { | ||
| 765 | handled_exception = 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | *kernel_step = ARM_KERNEL_STEP_NONE; | ||
| 769 | } | ||
| 770 | |||
| 771 | return !handled_exception; | ||
| 772 | } | ||
| 773 | |||
| 774 | /* | ||
| 775 | * Context-switcher for restoring suspended breakpoints. | ||
| 776 | */ | ||
| 777 | void hw_breakpoint_thread_switch(struct task_struct *next) | ||
| 778 | { | ||
| 779 | /* | ||
| 780 | * current next | ||
| 781 | * disabled: 0 0 => The usual case, NOTIFY_DONE | ||
| 782 | * 0 1 => Disable the registers | ||
| 783 | * 1 0 => Enable the registers | ||
| 784 | * 1 1 => NOTIFY_DONE. per-task bps will | ||
| 785 | * get taken care of by perf. | ||
| 786 | */ | ||
| 787 | |||
| 788 | struct debug_info *current_debug_info, *next_debug_info; | ||
| 789 | |||
| 790 | current_debug_info = ¤t->thread.debug; | ||
| 791 | next_debug_info = &next->thread.debug; | ||
| 792 | |||
| 793 | /* Update breakpoints. */ | ||
| 794 | if (current_debug_info->bps_disabled != next_debug_info->bps_disabled) | ||
| 795 | toggle_bp_registers(AARCH64_DBG_REG_BCR, | ||
| 796 | DBG_ACTIVE_EL0, | ||
| 797 | !next_debug_info->bps_disabled); | ||
| 798 | |||
| 799 | /* Update watchpoints. */ | ||
| 800 | if (current_debug_info->wps_disabled != next_debug_info->wps_disabled) | ||
| 801 | toggle_bp_registers(AARCH64_DBG_REG_WCR, | ||
| 802 | DBG_ACTIVE_EL0, | ||
| 803 | !next_debug_info->wps_disabled); | ||
| 804 | } | ||
| 805 | |||
| 806 | /* | ||
| 807 | * CPU initialisation. | ||
| 808 | */ | ||
| 809 | static void reset_ctrl_regs(void *unused) | ||
| 810 | { | ||
| 811 | int i; | ||
| 812 | |||
| 813 | for (i = 0; i < core_num_brps; ++i) { | ||
| 814 | write_wb_reg(AARCH64_DBG_REG_BCR, i, 0UL); | ||
| 815 | write_wb_reg(AARCH64_DBG_REG_BVR, i, 0UL); | ||
| 816 | } | ||
| 817 | |||
| 818 | for (i = 0; i < core_num_wrps; ++i) { | ||
| 819 | write_wb_reg(AARCH64_DBG_REG_WCR, i, 0UL); | ||
| 820 | write_wb_reg(AARCH64_DBG_REG_WVR, i, 0UL); | ||
| 821 | } | ||
| 822 | } | ||
| 823 | |||
| 824 | static int __cpuinit hw_breakpoint_reset_notify(struct notifier_block *self, | ||
| 825 | unsigned long action, | ||
| 826 | void *hcpu) | ||
| 827 | { | ||
| 828 | int cpu = (long)hcpu; | ||
| 829 | if (action == CPU_ONLINE) | ||
| 830 | smp_call_function_single(cpu, reset_ctrl_regs, NULL, 1); | ||
| 831 | return NOTIFY_OK; | ||
| 832 | } | ||
| 833 | |||
| 834 | static struct notifier_block __cpuinitdata hw_breakpoint_reset_nb = { | ||
| 835 | .notifier_call = hw_breakpoint_reset_notify, | ||
| 836 | }; | ||
| 837 | |||
| 838 | /* | ||
| 839 | * One-time initialisation. | ||
| 840 | */ | ||
| 841 | static int __init arch_hw_breakpoint_init(void) | ||
| 842 | { | ||
| 843 | core_num_brps = get_num_brps(); | ||
| 844 | core_num_wrps = get_num_wrps(); | ||
| 845 | |||
| 846 | pr_info("found %d breakpoint and %d watchpoint registers.\n", | ||
| 847 | core_num_brps, core_num_wrps); | ||
| 848 | |||
| 849 | /* | ||
| 850 | * Reset the breakpoint resources. We assume that a halting | ||
| 851 | * debugger will leave the world in a nice state for us. | ||
| 852 | */ | ||
| 853 | smp_call_function(reset_ctrl_regs, NULL, 1); | ||
| 854 | reset_ctrl_regs(NULL); | ||
| 855 | |||
| 856 | /* Register debug fault handlers. */ | ||
| 857 | hook_debug_fault_code(DBG_ESR_EVT_HWBP, breakpoint_handler, SIGTRAP, | ||
| 858 | TRAP_HWBKPT, "hw-breakpoint handler"); | ||
| 859 | hook_debug_fault_code(DBG_ESR_EVT_HWWP, watchpoint_handler, SIGTRAP, | ||
| 860 | TRAP_HWBKPT, "hw-watchpoint handler"); | ||
| 861 | |||
| 862 | /* Register hotplug notifier. */ | ||
| 863 | register_cpu_notifier(&hw_breakpoint_reset_nb); | ||
| 864 | |||
| 865 | return 0; | ||
| 866 | } | ||
| 867 | arch_initcall(arch_hw_breakpoint_init); | ||
| 868 | |||
| 869 | void hw_breakpoint_pmu_read(struct perf_event *bp) | ||
| 870 | { | ||
| 871 | } | ||
| 872 | |||
| 873 | /* | ||
| 874 | * Dummy function to register with die_notifier. | ||
| 875 | */ | ||
| 876 | int hw_breakpoint_exceptions_notify(struct notifier_block *unused, | ||
| 877 | unsigned long val, void *data) | ||
| 878 | { | ||
| 879 | return NOTIFY_DONE; | ||
| 880 | } | ||
diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c new file mode 100644 index 000000000000..7d37ead4d199 --- /dev/null +++ b/arch/arm64/kernel/io.c | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/io.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/export.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Copy data from IO memory space to "real" memory space. | ||
| 25 | */ | ||
| 26 | void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) | ||
| 27 | { | ||
| 28 | unsigned char *t = to; | ||
| 29 | while (count) { | ||
| 30 | count--; | ||
| 31 | *t = readb(from); | ||
| 32 | t++; | ||
| 33 | from++; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | EXPORT_SYMBOL(__memcpy_fromio); | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Copy data from "real" memory space to IO memory space. | ||
| 40 | */ | ||
| 41 | void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) | ||
| 42 | { | ||
| 43 | const unsigned char *f = from; | ||
| 44 | while (count) { | ||
| 45 | count--; | ||
| 46 | writeb(*f, to); | ||
| 47 | f++; | ||
| 48 | to++; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | EXPORT_SYMBOL(__memcpy_toio); | ||
| 52 | |||
| 53 | /* | ||
| 54 | * "memset" on IO memory space. | ||
| 55 | */ | ||
| 56 | void __memset_io(volatile void __iomem *dst, int c, size_t count) | ||
| 57 | { | ||
| 58 | while (count) { | ||
| 59 | count--; | ||
| 60 | writeb(c, dst); | ||
| 61 | dst++; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL(__memset_io); | ||
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c new file mode 100644 index 000000000000..0373c6609eaf --- /dev/null +++ b/arch/arm64/kernel/irq.c | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/irq.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1992 Linus Torvalds | ||
| 5 | * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. | ||
| 6 | * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation. | ||
| 7 | * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and | ||
| 8 | * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>. | ||
| 9 | * Copyright (C) 2012 ARM Ltd. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License version 2 as | ||
| 13 | * published by the Free Software Foundation. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/kernel_stat.h> | ||
| 25 | #include <linux/irq.h> | ||
| 26 | #include <linux/smp.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/of_irq.h> | ||
| 29 | #include <linux/seq_file.h> | ||
| 30 | #include <linux/ratelimit.h> | ||
| 31 | |||
| 32 | unsigned long irq_err_count; | ||
| 33 | |||
| 34 | int arch_show_interrupts(struct seq_file *p, int prec) | ||
| 35 | { | ||
| 36 | #ifdef CONFIG_SMP | ||
| 37 | show_ipi_list(p, prec); | ||
| 38 | #endif | ||
| 39 | seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | ||
| 44 | * handle_IRQ handles all hardware IRQ's. Decoded IRQs should | ||
| 45 | * not come via this function. Instead, they should provide their | ||
| 46 | * own 'handler'. Used by platform code implementing C-based 1st | ||
| 47 | * level decoding. | ||
| 48 | */ | ||
| 49 | void handle_IRQ(unsigned int irq, struct pt_regs *regs) | ||
| 50 | { | ||
| 51 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
| 52 | |||
| 53 | irq_enter(); | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Some hardware gives randomly wrong interrupts. Rather | ||
| 57 | * than crashing, do something sensible. | ||
| 58 | */ | ||
| 59 | if (unlikely(irq >= nr_irqs)) { | ||
| 60 | pr_warn_ratelimited("Bad IRQ%u\n", irq); | ||
| 61 | ack_bad_irq(irq); | ||
| 62 | } else { | ||
| 63 | generic_handle_irq(irq); | ||
| 64 | } | ||
| 65 | |||
| 66 | irq_exit(); | ||
| 67 | set_irq_regs(old_regs); | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Interrupt controllers supported by the kernel. | ||
| 72 | */ | ||
| 73 | static const struct of_device_id intctrl_of_match[] __initconst = { | ||
| 74 | /* IRQ controllers { .compatible, .data } info to go here */ | ||
| 75 | {} | ||
| 76 | }; | ||
| 77 | |||
| 78 | void __init init_IRQ(void) | ||
| 79 | { | ||
| 80 | of_irq_init(intctrl_of_match); | ||
| 81 | |||
| 82 | if (!handle_arch_irq) | ||
| 83 | panic("No interrupt controller found."); | ||
| 84 | } | ||
diff --git a/arch/arm64/kernel/kuser32.S b/arch/arm64/kernel/kuser32.S new file mode 100644 index 000000000000..8b69ecb1d8bc --- /dev/null +++ b/arch/arm64/kernel/kuser32.S | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * Low-level user helpers placed in the vectors page for AArch32. | ||
| 3 | * Based on the kuser helpers in arch/arm/kernel/entry-armv.S. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2005-2011 Nicolas Pitre <nico@fluxnic.net> | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | * | ||
| 20 | * | ||
| 21 | * AArch32 user helpers. | ||
| 22 | * | ||
| 23 | * Each segment is 32-byte aligned and will be moved to the top of the high | ||
| 24 | * vector page. New segments (if ever needed) must be added in front of | ||
| 25 | * existing ones. This mechanism should be used only for things that are | ||
| 26 | * really small and justified, and not be abused freely. | ||
| 27 | * | ||
| 28 | * See Documentation/arm/kernel_user_helpers.txt for formal definitions. | ||
| 29 | */ | ||
| 30 | .align 5 | ||
| 31 | .globl __kuser_helper_start | ||
| 32 | __kuser_helper_start: | ||
| 33 | |||
| 34 | __kuser_cmpxchg64: // 0xffff0f60 | ||
| 35 | .inst 0xe92d00f0 // push {r4, r5, r6, r7} | ||
| 36 | .inst 0xe1c040d0 // ldrd r4, r5, [r0] | ||
| 37 | .inst 0xe1c160d0 // ldrd r6, r7, [r1] | ||
| 38 | .inst 0xf57ff05f // dmb sy | ||
| 39 | .inst 0xe1b20f9f // 1: ldrexd r0, r1, [r2] | ||
| 40 | .inst 0xe0303004 // eors r3, r0, r4 | ||
| 41 | .inst 0x00313005 // eoreqs r3, r1, r5 | ||
| 42 | .inst 0x01a23f96 // strexdeq r3, r6, [r2] | ||
| 43 | .inst 0x03330001 // teqeq r3, #1 | ||
| 44 | .inst 0x0afffff9 // beq 1b | ||
| 45 | .inst 0xf57ff05f // dmb sy | ||
| 46 | .inst 0xe2730000 // rsbs r0, r3, #0 | ||
| 47 | .inst 0xe8bd00f0 // pop {r4, r5, r6, r7} | ||
| 48 | .inst 0xe12fff1e // bx lr | ||
| 49 | |||
| 50 | .align 5 | ||
| 51 | __kuser_memory_barrier: // 0xffff0fa0 | ||
| 52 | .inst 0xf57ff05f // dmb sy | ||
| 53 | .inst 0xe12fff1e // bx lr | ||
| 54 | |||
| 55 | .align 5 | ||
| 56 | __kuser_cmpxchg: // 0xffff0fc0 | ||
| 57 | .inst 0xf57ff05f // dmb sy | ||
| 58 | .inst 0xe1923f9f // 1: ldrex r3, [r2] | ||
| 59 | .inst 0xe0533000 // subs r3, r3, r0 | ||
| 60 | .inst 0x01823f91 // strexeq r3, r1, [r2] | ||
| 61 | .inst 0x03330001 // teqeq r3, #1 | ||
| 62 | .inst 0x0afffffa // beq 1b | ||
| 63 | .inst 0xe2730000 // rsbs r0, r3, #0 | ||
| 64 | .inst 0xeaffffef // b <__kuser_memory_barrier> | ||
| 65 | |||
| 66 | .align 5 | ||
| 67 | __kuser_get_tls: // 0xffff0fe0 | ||
| 68 | .inst 0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3 | ||
| 69 | .inst 0xe12fff1e // bx lr | ||
| 70 | .rep 5 | ||
| 71 | .word 0 | ||
| 72 | .endr | ||
| 73 | |||
| 74 | __kuser_helper_version: // 0xffff0ffc | ||
| 75 | .word ((__kuser_helper_end - __kuser_helper_start) >> 5) | ||
| 76 | .globl __kuser_helper_end | ||
| 77 | __kuser_helper_end: | ||
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c new file mode 100644 index 000000000000..ca0e3d55da99 --- /dev/null +++ b/arch/arm64/kernel/module.c | |||
| @@ -0,0 +1,456 @@ | |||
| 1 | /* | ||
| 2 | * AArch64 loadable module support. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/bitops.h> | ||
| 22 | #include <linux/elf.h> | ||
| 23 | #include <linux/gfp.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/mm.h> | ||
| 26 | #include <linux/moduleloader.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | |||
| 29 | void *module_alloc(unsigned long size) | ||
| 30 | { | ||
| 31 | return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, | ||
| 32 | GFP_KERNEL, PAGE_KERNEL_EXEC, -1, | ||
| 33 | __builtin_return_address(0)); | ||
| 34 | } | ||
| 35 | |||
| 36 | enum aarch64_reloc_op { | ||
| 37 | RELOC_OP_NONE, | ||
| 38 | RELOC_OP_ABS, | ||
| 39 | RELOC_OP_PREL, | ||
| 40 | RELOC_OP_PAGE, | ||
| 41 | }; | ||
| 42 | |||
| 43 | static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val) | ||
| 44 | { | ||
| 45 | switch (reloc_op) { | ||
| 46 | case RELOC_OP_ABS: | ||
| 47 | return val; | ||
| 48 | case RELOC_OP_PREL: | ||
| 49 | return val - (u64)place; | ||
| 50 | case RELOC_OP_PAGE: | ||
| 51 | return (val & ~0xfff) - ((u64)place & ~0xfff); | ||
| 52 | case RELOC_OP_NONE: | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | pr_err("do_reloc: unknown relocation operation %d\n", reloc_op); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len) | ||
| 61 | { | ||
| 62 | u64 imm_mask = (1 << len) - 1; | ||
| 63 | s64 sval = do_reloc(op, place, val); | ||
| 64 | |||
| 65 | switch (len) { | ||
| 66 | case 16: | ||
| 67 | *(s16 *)place = sval; | ||
| 68 | break; | ||
| 69 | case 32: | ||
| 70 | *(s32 *)place = sval; | ||
| 71 | break; | ||
| 72 | case 64: | ||
| 73 | *(s64 *)place = sval; | ||
| 74 | break; | ||
| 75 | default: | ||
| 76 | pr_err("Invalid length (%d) for data relocation\n", len); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Extract the upper value bits (including the sign bit) and | ||
| 82 | * shift them to bit 0. | ||
| 83 | */ | ||
| 84 | sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Overflow has occurred if the value is not representable in | ||
| 88 | * len bits (i.e the bottom len bits are not sign-extended and | ||
| 89 | * the top bits are not all zero). | ||
| 90 | */ | ||
| 91 | if ((u64)(sval + 1) > 2) | ||
| 92 | return -ERANGE; | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | enum aarch64_imm_type { | ||
| 98 | INSN_IMM_MOVNZ, | ||
| 99 | INSN_IMM_MOVK, | ||
| 100 | INSN_IMM_ADR, | ||
| 101 | INSN_IMM_26, | ||
| 102 | INSN_IMM_19, | ||
| 103 | INSN_IMM_16, | ||
| 104 | INSN_IMM_14, | ||
| 105 | INSN_IMM_12, | ||
| 106 | INSN_IMM_9, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static u32 encode_insn_immediate(enum aarch64_imm_type type, u32 insn, u64 imm) | ||
| 110 | { | ||
| 111 | u32 immlo, immhi, lomask, himask, mask; | ||
| 112 | int shift; | ||
| 113 | |||
| 114 | switch (type) { | ||
| 115 | case INSN_IMM_MOVNZ: | ||
| 116 | /* | ||
| 117 | * For signed MOVW relocations, we have to manipulate the | ||
| 118 | * instruction encoding depending on whether or not the | ||
| 119 | * immediate is less than zero. | ||
| 120 | */ | ||
| 121 | insn &= ~(3 << 29); | ||
| 122 | if ((s64)imm >= 0) { | ||
| 123 | /* >=0: Set the instruction to MOVZ (opcode 10b). */ | ||
| 124 | insn |= 2 << 29; | ||
| 125 | } else { | ||
| 126 | /* | ||
| 127 | * <0: Set the instruction to MOVN (opcode 00b). | ||
| 128 | * Since we've masked the opcode already, we | ||
| 129 | * don't need to do anything other than | ||
| 130 | * inverting the new immediate field. | ||
| 131 | */ | ||
| 132 | imm = ~imm; | ||
| 133 | } | ||
| 134 | case INSN_IMM_MOVK: | ||
| 135 | mask = BIT(16) - 1; | ||
| 136 | shift = 5; | ||
| 137 | break; | ||
| 138 | case INSN_IMM_ADR: | ||
| 139 | lomask = 0x3; | ||
| 140 | himask = 0x7ffff; | ||
| 141 | immlo = imm & lomask; | ||
| 142 | imm >>= 2; | ||
| 143 | immhi = imm & himask; | ||
| 144 | imm = (immlo << 24) | (immhi); | ||
| 145 | mask = (lomask << 24) | (himask); | ||
| 146 | shift = 5; | ||
| 147 | break; | ||
| 148 | case INSN_IMM_26: | ||
| 149 | mask = BIT(26) - 1; | ||
| 150 | shift = 0; | ||
| 151 | break; | ||
| 152 | case INSN_IMM_19: | ||
| 153 | mask = BIT(19) - 1; | ||
| 154 | shift = 5; | ||
| 155 | break; | ||
| 156 | case INSN_IMM_16: | ||
| 157 | mask = BIT(16) - 1; | ||
| 158 | shift = 5; | ||
| 159 | break; | ||
| 160 | case INSN_IMM_14: | ||
| 161 | mask = BIT(14) - 1; | ||
| 162 | shift = 5; | ||
| 163 | break; | ||
| 164 | case INSN_IMM_12: | ||
| 165 | mask = BIT(12) - 1; | ||
| 166 | shift = 10; | ||
| 167 | break; | ||
| 168 | case INSN_IMM_9: | ||
| 169 | mask = BIT(9) - 1; | ||
| 170 | shift = 12; | ||
| 171 | break; | ||
| 172 | default: | ||
| 173 | pr_err("encode_insn_immediate: unknown immediate encoding %d\n", | ||
| 174 | type); | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* Update the immediate field. */ | ||
| 179 | insn &= ~(mask << shift); | ||
| 180 | insn |= (imm & mask) << shift; | ||
| 181 | |||
| 182 | return insn; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val, | ||
| 186 | int lsb, enum aarch64_imm_type imm_type) | ||
| 187 | { | ||
| 188 | u64 imm, limit = 0; | ||
| 189 | s64 sval; | ||
| 190 | u32 insn = *(u32 *)place; | ||
| 191 | |||
| 192 | sval = do_reloc(op, place, val); | ||
| 193 | sval >>= lsb; | ||
| 194 | imm = sval & 0xffff; | ||
| 195 | |||
| 196 | /* Update the instruction with the new encoding. */ | ||
| 197 | *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); | ||
| 198 | |||
| 199 | /* Shift out the immediate field. */ | ||
| 200 | sval >>= 16; | ||
| 201 | |||
| 202 | /* | ||
| 203 | * For unsigned immediates, the overflow check is straightforward. | ||
| 204 | * For signed immediates, the sign bit is actually the bit past the | ||
| 205 | * most significant bit of the field. | ||
| 206 | * The INSN_IMM_16 immediate type is unsigned. | ||
| 207 | */ | ||
| 208 | if (imm_type != INSN_IMM_16) { | ||
| 209 | sval++; | ||
| 210 | limit++; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Check the upper bits depending on the sign of the immediate. */ | ||
| 214 | if ((u64)sval > limit) | ||
| 215 | return -ERANGE; | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int reloc_insn_imm(enum aarch64_reloc_op op, void *place, u64 val, | ||
| 221 | int lsb, int len, enum aarch64_imm_type imm_type) | ||
| 222 | { | ||
| 223 | u64 imm, imm_mask; | ||
| 224 | s64 sval; | ||
| 225 | u32 insn = *(u32 *)place; | ||
| 226 | |||
| 227 | /* Calculate the relocation value. */ | ||
| 228 | sval = do_reloc(op, place, val); | ||
| 229 | sval >>= lsb; | ||
| 230 | |||
| 231 | /* Extract the value bits and shift them to bit 0. */ | ||
| 232 | imm_mask = (BIT(lsb + len) - 1) >> lsb; | ||
| 233 | imm = sval & imm_mask; | ||
| 234 | |||
| 235 | /* Update the instruction's immediate field. */ | ||
| 236 | *(u32 *)place = encode_insn_immediate(imm_type, insn, imm); | ||
| 237 | |||
| 238 | /* | ||
| 239 | * Extract the upper value bits (including the sign bit) and | ||
| 240 | * shift them to bit 0. | ||
| 241 | */ | ||
| 242 | sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1); | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Overflow has occurred if the upper bits are not all equal to | ||
| 246 | * the sign bit of the value. | ||
| 247 | */ | ||
| 248 | if ((u64)(sval + 1) >= 2) | ||
| 249 | return -ERANGE; | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | int apply_relocate_add(Elf64_Shdr *sechdrs, | ||
| 255 | const char *strtab, | ||
| 256 | unsigned int symindex, | ||
| 257 | unsigned int relsec, | ||
| 258 | struct module *me) | ||
| 259 | { | ||
| 260 | unsigned int i; | ||
| 261 | int ovf; | ||
| 262 | bool overflow_check; | ||
| 263 | Elf64_Sym *sym; | ||
| 264 | void *loc; | ||
| 265 | u64 val; | ||
| 266 | Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; | ||
| 267 | |||
| 268 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
| 269 | /* loc corresponds to P in the AArch64 ELF document. */ | ||
| 270 | loc = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
| 271 | + rel[i].r_offset; | ||
| 272 | |||
| 273 | /* sym is the ELF symbol we're referring to. */ | ||
| 274 | sym = (Elf64_Sym *)sechdrs[symindex].sh_addr | ||
| 275 | + ELF64_R_SYM(rel[i].r_info); | ||
| 276 | |||
| 277 | /* val corresponds to (S + A) in the AArch64 ELF document. */ | ||
| 278 | val = sym->st_value + rel[i].r_addend; | ||
| 279 | |||
| 280 | /* Check for overflow by default. */ | ||
| 281 | overflow_check = true; | ||
| 282 | |||
| 283 | /* Perform the static relocation. */ | ||
| 284 | switch (ELF64_R_TYPE(rel[i].r_info)) { | ||
| 285 | /* Null relocations. */ | ||
| 286 | case R_ARM_NONE: | ||
| 287 | case R_AARCH64_NONE: | ||
| 288 | ovf = 0; | ||
| 289 | break; | ||
| 290 | |||
| 291 | /* Data relocations. */ | ||
| 292 | case R_AARCH64_ABS64: | ||
| 293 | overflow_check = false; | ||
| 294 | ovf = reloc_data(RELOC_OP_ABS, loc, val, 64); | ||
| 295 | break; | ||
| 296 | case R_AARCH64_ABS32: | ||
| 297 | ovf = reloc_data(RELOC_OP_ABS, loc, val, 32); | ||
| 298 | break; | ||
| 299 | case R_AARCH64_ABS16: | ||
| 300 | ovf = reloc_data(RELOC_OP_ABS, loc, val, 16); | ||
| 301 | break; | ||
| 302 | case R_AARCH64_PREL64: | ||
| 303 | overflow_check = false; | ||
| 304 | ovf = reloc_data(RELOC_OP_PREL, loc, val, 64); | ||
| 305 | break; | ||
| 306 | case R_AARCH64_PREL32: | ||
| 307 | ovf = reloc_data(RELOC_OP_PREL, loc, val, 32); | ||
| 308 | break; | ||
| 309 | case R_AARCH64_PREL16: | ||
| 310 | ovf = reloc_data(RELOC_OP_PREL, loc, val, 16); | ||
| 311 | break; | ||
| 312 | |||
| 313 | /* MOVW instruction relocations. */ | ||
| 314 | case R_AARCH64_MOVW_UABS_G0_NC: | ||
| 315 | overflow_check = false; | ||
| 316 | case R_AARCH64_MOVW_UABS_G0: | ||
| 317 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, | ||
| 318 | INSN_IMM_16); | ||
| 319 | break; | ||
| 320 | case R_AARCH64_MOVW_UABS_G1_NC: | ||
| 321 | overflow_check = false; | ||
| 322 | case R_AARCH64_MOVW_UABS_G1: | ||
| 323 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, | ||
| 324 | INSN_IMM_16); | ||
| 325 | break; | ||
| 326 | case R_AARCH64_MOVW_UABS_G2_NC: | ||
| 327 | overflow_check = false; | ||
| 328 | case R_AARCH64_MOVW_UABS_G2: | ||
| 329 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, | ||
| 330 | INSN_IMM_16); | ||
| 331 | break; | ||
| 332 | case R_AARCH64_MOVW_UABS_G3: | ||
| 333 | /* We're using the top bits so we can't overflow. */ | ||
| 334 | overflow_check = false; | ||
| 335 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48, | ||
| 336 | INSN_IMM_16); | ||
| 337 | break; | ||
| 338 | case R_AARCH64_MOVW_SABS_G0: | ||
| 339 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0, | ||
| 340 | INSN_IMM_MOVNZ); | ||
| 341 | break; | ||
| 342 | case R_AARCH64_MOVW_SABS_G1: | ||
| 343 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16, | ||
| 344 | INSN_IMM_MOVNZ); | ||
| 345 | break; | ||
| 346 | case R_AARCH64_MOVW_SABS_G2: | ||
| 347 | ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32, | ||
| 348 | INSN_IMM_MOVNZ); | ||
| 349 | break; | ||
| 350 | case R_AARCH64_MOVW_PREL_G0_NC: | ||
| 351 | overflow_check = false; | ||
| 352 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, | ||
| 353 | INSN_IMM_MOVK); | ||
| 354 | break; | ||
| 355 | case R_AARCH64_MOVW_PREL_G0: | ||
| 356 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0, | ||
| 357 | INSN_IMM_MOVNZ); | ||
| 358 | break; | ||
| 359 | case R_AARCH64_MOVW_PREL_G1_NC: | ||
| 360 | overflow_check = false; | ||
| 361 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, | ||
| 362 | INSN_IMM_MOVK); | ||
| 363 | break; | ||
| 364 | case R_AARCH64_MOVW_PREL_G1: | ||
| 365 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16, | ||
| 366 | INSN_IMM_MOVNZ); | ||
| 367 | break; | ||
| 368 | case R_AARCH64_MOVW_PREL_G2_NC: | ||
| 369 | overflow_check = false; | ||
| 370 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, | ||
| 371 | INSN_IMM_MOVK); | ||
| 372 | break; | ||
| 373 | case R_AARCH64_MOVW_PREL_G2: | ||
| 374 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32, | ||
| 375 | INSN_IMM_MOVNZ); | ||
| 376 | break; | ||
| 377 | case R_AARCH64_MOVW_PREL_G3: | ||
| 378 | /* We're using the top bits so we can't overflow. */ | ||
| 379 | overflow_check = false; | ||
| 380 | ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 48, | ||
| 381 | INSN_IMM_MOVNZ); | ||
| 382 | break; | ||
| 383 | |||
| 384 | /* Immediate instruction relocations. */ | ||
| 385 | case R_AARCH64_LD_PREL_LO19: | ||
| 386 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, | ||
| 387 | INSN_IMM_19); | ||
| 388 | break; | ||
| 389 | case R_AARCH64_ADR_PREL_LO21: | ||
| 390 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 0, 21, | ||
| 391 | INSN_IMM_ADR); | ||
| 392 | break; | ||
| 393 | case R_AARCH64_ADR_PREL_PG_HI21_NC: | ||
| 394 | overflow_check = false; | ||
| 395 | case R_AARCH64_ADR_PREL_PG_HI21: | ||
| 396 | ovf = reloc_insn_imm(RELOC_OP_PAGE, loc, val, 12, 21, | ||
| 397 | INSN_IMM_ADR); | ||
| 398 | break; | ||
| 399 | case R_AARCH64_ADD_ABS_LO12_NC: | ||
| 400 | case R_AARCH64_LDST8_ABS_LO12_NC: | ||
| 401 | overflow_check = false; | ||
| 402 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 0, 12, | ||
| 403 | INSN_IMM_12); | ||
| 404 | break; | ||
| 405 | case R_AARCH64_LDST16_ABS_LO12_NC: | ||
| 406 | overflow_check = false; | ||
| 407 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 1, 11, | ||
| 408 | INSN_IMM_12); | ||
| 409 | break; | ||
| 410 | case R_AARCH64_LDST32_ABS_LO12_NC: | ||
| 411 | overflow_check = false; | ||
| 412 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 2, 10, | ||
| 413 | INSN_IMM_12); | ||
| 414 | break; | ||
| 415 | case R_AARCH64_LDST64_ABS_LO12_NC: | ||
| 416 | overflow_check = false; | ||
| 417 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 3, 9, | ||
| 418 | INSN_IMM_12); | ||
| 419 | break; | ||
| 420 | case R_AARCH64_LDST128_ABS_LO12_NC: | ||
| 421 | overflow_check = false; | ||
| 422 | ovf = reloc_insn_imm(RELOC_OP_ABS, loc, val, 4, 8, | ||
| 423 | INSN_IMM_12); | ||
| 424 | break; | ||
| 425 | case R_AARCH64_TSTBR14: | ||
| 426 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 14, | ||
| 427 | INSN_IMM_14); | ||
| 428 | break; | ||
| 429 | case R_AARCH64_CONDBR19: | ||
| 430 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 19, | ||
| 431 | INSN_IMM_19); | ||
| 432 | break; | ||
| 433 | case R_AARCH64_JUMP26: | ||
| 434 | case R_AARCH64_CALL26: | ||
| 435 | ovf = reloc_insn_imm(RELOC_OP_PREL, loc, val, 2, 26, | ||
| 436 | INSN_IMM_26); | ||
| 437 | break; | ||
| 438 | |||
| 439 | default: | ||
| 440 | pr_err("module %s: unsupported RELA relocation: %llu\n", | ||
| 441 | me->name, ELF64_R_TYPE(rel[i].r_info)); | ||
| 442 | return -ENOEXEC; | ||
| 443 | } | ||
| 444 | |||
| 445 | if (overflow_check && ovf == -ERANGE) | ||
| 446 | goto overflow; | ||
| 447 | |||
| 448 | } | ||
| 449 | |||
| 450 | return 0; | ||
| 451 | |||
| 452 | overflow: | ||
| 453 | pr_err("module %s: overflow in relocation type %d val %Lx\n", | ||
| 454 | me->name, (int)ELF64_R_TYPE(rel[i].r_info), val); | ||
| 455 | return -ENOEXEC; | ||
| 456 | } | ||
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c new file mode 100644 index 000000000000..ecbf2d81ec5c --- /dev/null +++ b/arch/arm64/kernel/perf_event.c | |||
| @@ -0,0 +1,1368 @@ | |||
| 1 | /* | ||
| 2 | * PMU support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 6 | * | ||
| 7 | * This code is based heavily on the ARMv7 perf event code. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 20 | */ | ||
| 21 | #define pr_fmt(fmt) "hw perfevents: " fmt | ||
| 22 | |||
| 23 | #include <linux/bitmap.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/export.h> | ||
| 27 | #include <linux/perf_event.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/spinlock.h> | ||
| 30 | #include <linux/uaccess.h> | ||
| 31 | |||
| 32 | #include <asm/cputype.h> | ||
| 33 | #include <asm/irq.h> | ||
| 34 | #include <asm/irq_regs.h> | ||
| 35 | #include <asm/pmu.h> | ||
| 36 | #include <asm/stacktrace.h> | ||
| 37 | |||
| 38 | /* | ||
| 39 | * ARMv8 supports a maximum of 32 events. | ||
| 40 | * The cycle counter is included in this total. | ||
| 41 | */ | ||
| 42 | #define ARMPMU_MAX_HWEVENTS 32 | ||
| 43 | |||
| 44 | static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); | ||
| 45 | static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); | ||
| 46 | static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); | ||
| 47 | |||
| 48 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | ||
| 49 | |||
| 50 | /* Set at runtime when we know what CPU type we are. */ | ||
| 51 | static struct arm_pmu *cpu_pmu; | ||
| 52 | |||
| 53 | int | ||
| 54 | armpmu_get_max_events(void) | ||
| 55 | { | ||
| 56 | int max_events = 0; | ||
| 57 | |||
| 58 | if (cpu_pmu != NULL) | ||
| 59 | max_events = cpu_pmu->num_events; | ||
| 60 | |||
| 61 | return max_events; | ||
| 62 | } | ||
| 63 | EXPORT_SYMBOL_GPL(armpmu_get_max_events); | ||
| 64 | |||
| 65 | int perf_num_counters(void) | ||
| 66 | { | ||
| 67 | return armpmu_get_max_events(); | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
| 70 | |||
| 71 | #define HW_OP_UNSUPPORTED 0xFFFF | ||
| 72 | |||
| 73 | #define C(_x) \ | ||
| 74 | PERF_COUNT_HW_CACHE_##_x | ||
| 75 | |||
| 76 | #define CACHE_OP_UNSUPPORTED 0xFFFF | ||
| 77 | |||
| 78 | static int | ||
| 79 | armpmu_map_cache_event(const unsigned (*cache_map) | ||
| 80 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 81 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 82 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | ||
| 83 | u64 config) | ||
| 84 | { | ||
| 85 | unsigned int cache_type, cache_op, cache_result, ret; | ||
| 86 | |||
| 87 | cache_type = (config >> 0) & 0xff; | ||
| 88 | if (cache_type >= PERF_COUNT_HW_CACHE_MAX) | ||
| 89 | return -EINVAL; | ||
| 90 | |||
| 91 | cache_op = (config >> 8) & 0xff; | ||
| 92 | if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) | ||
| 93 | return -EINVAL; | ||
| 94 | |||
| 95 | cache_result = (config >> 16) & 0xff; | ||
| 96 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
| 97 | return -EINVAL; | ||
| 98 | |||
| 99 | ret = (int)(*cache_map)[cache_type][cache_op][cache_result]; | ||
| 100 | |||
| 101 | if (ret == CACHE_OP_UNSUPPORTED) | ||
| 102 | return -ENOENT; | ||
| 103 | |||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int | ||
| 108 | armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) | ||
| 109 | { | ||
| 110 | int mapping = (*event_map)[config]; | ||
| 111 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int | ||
| 115 | armpmu_map_raw_event(u32 raw_event_mask, u64 config) | ||
| 116 | { | ||
| 117 | return (int)(config & raw_event_mask); | ||
| 118 | } | ||
| 119 | |||
| 120 | static int map_cpu_event(struct perf_event *event, | ||
| 121 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], | ||
| 122 | const unsigned (*cache_map) | ||
| 123 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 124 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 125 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | ||
| 126 | u32 raw_event_mask) | ||
| 127 | { | ||
| 128 | u64 config = event->attr.config; | ||
| 129 | |||
| 130 | switch (event->attr.type) { | ||
| 131 | case PERF_TYPE_HARDWARE: | ||
| 132 | return armpmu_map_event(event_map, config); | ||
| 133 | case PERF_TYPE_HW_CACHE: | ||
| 134 | return armpmu_map_cache_event(cache_map, config); | ||
| 135 | case PERF_TYPE_RAW: | ||
| 136 | return armpmu_map_raw_event(raw_event_mask, config); | ||
| 137 | } | ||
| 138 | |||
| 139 | return -ENOENT; | ||
| 140 | } | ||
| 141 | |||
| 142 | int | ||
| 143 | armpmu_event_set_period(struct perf_event *event, | ||
| 144 | struct hw_perf_event *hwc, | ||
| 145 | int idx) | ||
| 146 | { | ||
| 147 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 148 | s64 left = local64_read(&hwc->period_left); | ||
| 149 | s64 period = hwc->sample_period; | ||
| 150 | int ret = 0; | ||
| 151 | |||
| 152 | if (unlikely(left <= -period)) { | ||
| 153 | left = period; | ||
| 154 | local64_set(&hwc->period_left, left); | ||
| 155 | hwc->last_period = period; | ||
| 156 | ret = 1; | ||
| 157 | } | ||
| 158 | |||
| 159 | if (unlikely(left <= 0)) { | ||
| 160 | left += period; | ||
| 161 | local64_set(&hwc->period_left, left); | ||
| 162 | hwc->last_period = period; | ||
| 163 | ret = 1; | ||
| 164 | } | ||
| 165 | |||
| 166 | if (left > (s64)armpmu->max_period) | ||
| 167 | left = armpmu->max_period; | ||
| 168 | |||
| 169 | local64_set(&hwc->prev_count, (u64)-left); | ||
| 170 | |||
| 171 | armpmu->write_counter(idx, (u64)(-left) & 0xffffffff); | ||
| 172 | |||
| 173 | perf_event_update_userpage(event); | ||
| 174 | |||
| 175 | return ret; | ||
| 176 | } | ||
| 177 | |||
| 178 | u64 | ||
| 179 | armpmu_event_update(struct perf_event *event, | ||
| 180 | struct hw_perf_event *hwc, | ||
| 181 | int idx) | ||
| 182 | { | ||
| 183 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 184 | u64 delta, prev_raw_count, new_raw_count; | ||
| 185 | |||
| 186 | again: | ||
| 187 | prev_raw_count = local64_read(&hwc->prev_count); | ||
| 188 | new_raw_count = armpmu->read_counter(idx); | ||
| 189 | |||
| 190 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | ||
| 191 | new_raw_count) != prev_raw_count) | ||
| 192 | goto again; | ||
| 193 | |||
| 194 | delta = (new_raw_count - prev_raw_count) & armpmu->max_period; | ||
| 195 | |||
| 196 | local64_add(delta, &event->count); | ||
| 197 | local64_sub(delta, &hwc->period_left); | ||
| 198 | |||
| 199 | return new_raw_count; | ||
| 200 | } | ||
| 201 | |||
| 202 | static void | ||
| 203 | armpmu_read(struct perf_event *event) | ||
| 204 | { | ||
| 205 | struct hw_perf_event *hwc = &event->hw; | ||
| 206 | |||
| 207 | /* Don't read disabled counters! */ | ||
| 208 | if (hwc->idx < 0) | ||
| 209 | return; | ||
| 210 | |||
| 211 | armpmu_event_update(event, hwc, hwc->idx); | ||
| 212 | } | ||
| 213 | |||
| 214 | static void | ||
| 215 | armpmu_stop(struct perf_event *event, int flags) | ||
| 216 | { | ||
| 217 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 218 | struct hw_perf_event *hwc = &event->hw; | ||
| 219 | |||
| 220 | /* | ||
| 221 | * ARM pmu always has to update the counter, so ignore | ||
| 222 | * PERF_EF_UPDATE, see comments in armpmu_start(). | ||
| 223 | */ | ||
| 224 | if (!(hwc->state & PERF_HES_STOPPED)) { | ||
| 225 | armpmu->disable(hwc, hwc->idx); | ||
| 226 | barrier(); /* why? */ | ||
| 227 | armpmu_event_update(event, hwc, hwc->idx); | ||
| 228 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | static void | ||
| 233 | armpmu_start(struct perf_event *event, int flags) | ||
| 234 | { | ||
| 235 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 236 | struct hw_perf_event *hwc = &event->hw; | ||
| 237 | |||
| 238 | /* | ||
| 239 | * ARM pmu always has to reprogram the period, so ignore | ||
| 240 | * PERF_EF_RELOAD, see the comment below. | ||
| 241 | */ | ||
| 242 | if (flags & PERF_EF_RELOAD) | ||
| 243 | WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); | ||
| 244 | |||
| 245 | hwc->state = 0; | ||
| 246 | /* | ||
| 247 | * Set the period again. Some counters can't be stopped, so when we | ||
| 248 | * were stopped we simply disabled the IRQ source and the counter | ||
| 249 | * may have been left counting. If we don't do this step then we may | ||
| 250 | * get an interrupt too soon or *way* too late if the overflow has | ||
| 251 | * happened since disabling. | ||
| 252 | */ | ||
| 253 | armpmu_event_set_period(event, hwc, hwc->idx); | ||
| 254 | armpmu->enable(hwc, hwc->idx); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void | ||
| 258 | armpmu_del(struct perf_event *event, int flags) | ||
| 259 | { | ||
| 260 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 261 | struct pmu_hw_events *hw_events = armpmu->get_hw_events(); | ||
| 262 | struct hw_perf_event *hwc = &event->hw; | ||
| 263 | int idx = hwc->idx; | ||
| 264 | |||
| 265 | WARN_ON(idx < 0); | ||
| 266 | |||
| 267 | armpmu_stop(event, PERF_EF_UPDATE); | ||
| 268 | hw_events->events[idx] = NULL; | ||
| 269 | clear_bit(idx, hw_events->used_mask); | ||
| 270 | |||
| 271 | perf_event_update_userpage(event); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int | ||
| 275 | armpmu_add(struct perf_event *event, int flags) | ||
| 276 | { | ||
| 277 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 278 | struct pmu_hw_events *hw_events = armpmu->get_hw_events(); | ||
| 279 | struct hw_perf_event *hwc = &event->hw; | ||
| 280 | int idx; | ||
| 281 | int err = 0; | ||
| 282 | |||
| 283 | perf_pmu_disable(event->pmu); | ||
| 284 | |||
| 285 | /* If we don't have a space for the counter then finish early. */ | ||
| 286 | idx = armpmu->get_event_idx(hw_events, hwc); | ||
| 287 | if (idx < 0) { | ||
| 288 | err = idx; | ||
| 289 | goto out; | ||
| 290 | } | ||
| 291 | |||
| 292 | /* | ||
| 293 | * If there is an event in the counter we are going to use then make | ||
| 294 | * sure it is disabled. | ||
| 295 | */ | ||
| 296 | event->hw.idx = idx; | ||
| 297 | armpmu->disable(hwc, idx); | ||
| 298 | hw_events->events[idx] = event; | ||
| 299 | |||
| 300 | hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; | ||
| 301 | if (flags & PERF_EF_START) | ||
| 302 | armpmu_start(event, PERF_EF_RELOAD); | ||
| 303 | |||
| 304 | /* Propagate our changes to the userspace mapping. */ | ||
| 305 | perf_event_update_userpage(event); | ||
| 306 | |||
| 307 | out: | ||
| 308 | perf_pmu_enable(event->pmu); | ||
| 309 | return err; | ||
| 310 | } | ||
| 311 | |||
| 312 | static int | ||
| 313 | validate_event(struct pmu_hw_events *hw_events, | ||
| 314 | struct perf_event *event) | ||
| 315 | { | ||
| 316 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 317 | struct hw_perf_event fake_event = event->hw; | ||
| 318 | struct pmu *leader_pmu = event->group_leader->pmu; | ||
| 319 | |||
| 320 | if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF) | ||
| 321 | return 1; | ||
| 322 | |||
| 323 | return armpmu->get_event_idx(hw_events, &fake_event) >= 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int | ||
| 327 | validate_group(struct perf_event *event) | ||
| 328 | { | ||
| 329 | struct perf_event *sibling, *leader = event->group_leader; | ||
| 330 | struct pmu_hw_events fake_pmu; | ||
| 331 | DECLARE_BITMAP(fake_used_mask, ARMPMU_MAX_HWEVENTS); | ||
| 332 | |||
| 333 | /* | ||
| 334 | * Initialise the fake PMU. We only need to populate the | ||
| 335 | * used_mask for the purposes of validation. | ||
| 336 | */ | ||
| 337 | memset(fake_used_mask, 0, sizeof(fake_used_mask)); | ||
| 338 | fake_pmu.used_mask = fake_used_mask; | ||
| 339 | |||
| 340 | if (!validate_event(&fake_pmu, leader)) | ||
| 341 | return -EINVAL; | ||
| 342 | |||
| 343 | list_for_each_entry(sibling, &leader->sibling_list, group_entry) { | ||
| 344 | if (!validate_event(&fake_pmu, sibling)) | ||
| 345 | return -EINVAL; | ||
| 346 | } | ||
| 347 | |||
| 348 | if (!validate_event(&fake_pmu, event)) | ||
| 349 | return -EINVAL; | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static void | ||
| 355 | armpmu_release_hardware(struct arm_pmu *armpmu) | ||
| 356 | { | ||
| 357 | int i, irq, irqs; | ||
| 358 | struct platform_device *pmu_device = armpmu->plat_device; | ||
| 359 | |||
| 360 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
| 361 | |||
| 362 | for (i = 0; i < irqs; ++i) { | ||
| 363 | if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs)) | ||
| 364 | continue; | ||
| 365 | irq = platform_get_irq(pmu_device, i); | ||
| 366 | if (irq >= 0) | ||
| 367 | free_irq(irq, armpmu); | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | static int | ||
| 372 | armpmu_reserve_hardware(struct arm_pmu *armpmu) | ||
| 373 | { | ||
| 374 | int i, err, irq, irqs; | ||
| 375 | struct platform_device *pmu_device = armpmu->plat_device; | ||
| 376 | |||
| 377 | if (!pmu_device) { | ||
| 378 | pr_err("no PMU device registered\n"); | ||
| 379 | return -ENODEV; | ||
| 380 | } | ||
| 381 | |||
| 382 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
| 383 | if (irqs < 1) { | ||
| 384 | pr_err("no irqs for PMUs defined\n"); | ||
| 385 | return -ENODEV; | ||
| 386 | } | ||
| 387 | |||
| 388 | for (i = 0; i < irqs; ++i) { | ||
| 389 | err = 0; | ||
| 390 | irq = platform_get_irq(pmu_device, i); | ||
| 391 | if (irq < 0) | ||
| 392 | continue; | ||
| 393 | |||
| 394 | /* | ||
| 395 | * If we have a single PMU interrupt that we can't shift, | ||
| 396 | * assume that we're running on a uniprocessor machine and | ||
| 397 | * continue. Otherwise, continue without this interrupt. | ||
| 398 | */ | ||
| 399 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
| 400 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
| 401 | irq, i); | ||
| 402 | continue; | ||
| 403 | } | ||
| 404 | |||
| 405 | err = request_irq(irq, armpmu->handle_irq, | ||
| 406 | IRQF_NOBALANCING, | ||
| 407 | "arm-pmu", armpmu); | ||
| 408 | if (err) { | ||
| 409 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
| 410 | irq); | ||
| 411 | armpmu_release_hardware(armpmu); | ||
| 412 | return err; | ||
| 413 | } | ||
| 414 | |||
| 415 | cpumask_set_cpu(i, &armpmu->active_irqs); | ||
| 416 | } | ||
| 417 | |||
| 418 | return 0; | ||
| 419 | } | ||
| 420 | |||
| 421 | static void | ||
| 422 | hw_perf_event_destroy(struct perf_event *event) | ||
| 423 | { | ||
| 424 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 425 | atomic_t *active_events = &armpmu->active_events; | ||
| 426 | struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex; | ||
| 427 | |||
| 428 | if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) { | ||
| 429 | armpmu_release_hardware(armpmu); | ||
| 430 | mutex_unlock(pmu_reserve_mutex); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | static int | ||
| 435 | event_requires_mode_exclusion(struct perf_event_attr *attr) | ||
| 436 | { | ||
| 437 | return attr->exclude_idle || attr->exclude_user || | ||
| 438 | attr->exclude_kernel || attr->exclude_hv; | ||
| 439 | } | ||
| 440 | |||
| 441 | static int | ||
| 442 | __hw_perf_event_init(struct perf_event *event) | ||
| 443 | { | ||
| 444 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 445 | struct hw_perf_event *hwc = &event->hw; | ||
| 446 | int mapping, err; | ||
| 447 | |||
| 448 | mapping = armpmu->map_event(event); | ||
| 449 | |||
| 450 | if (mapping < 0) { | ||
| 451 | pr_debug("event %x:%llx not supported\n", event->attr.type, | ||
| 452 | event->attr.config); | ||
| 453 | return mapping; | ||
| 454 | } | ||
| 455 | |||
| 456 | /* | ||
| 457 | * We don't assign an index until we actually place the event onto | ||
| 458 | * hardware. Use -1 to signify that we haven't decided where to put it | ||
| 459 | * yet. For SMP systems, each core has it's own PMU so we can't do any | ||
| 460 | * clever allocation or constraints checking at this point. | ||
| 461 | */ | ||
| 462 | hwc->idx = -1; | ||
| 463 | hwc->config_base = 0; | ||
| 464 | hwc->config = 0; | ||
| 465 | hwc->event_base = 0; | ||
| 466 | |||
| 467 | /* | ||
| 468 | * Check whether we need to exclude the counter from certain modes. | ||
| 469 | */ | ||
| 470 | if ((!armpmu->set_event_filter || | ||
| 471 | armpmu->set_event_filter(hwc, &event->attr)) && | ||
| 472 | event_requires_mode_exclusion(&event->attr)) { | ||
| 473 | pr_debug("ARM performance counters do not support mode exclusion\n"); | ||
| 474 | return -EPERM; | ||
| 475 | } | ||
| 476 | |||
| 477 | /* | ||
| 478 | * Store the event encoding into the config_base field. | ||
| 479 | */ | ||
| 480 | hwc->config_base |= (unsigned long)mapping; | ||
| 481 | |||
| 482 | if (!hwc->sample_period) { | ||
| 483 | /* | ||
| 484 | * For non-sampling runs, limit the sample_period to half | ||
| 485 | * of the counter width. That way, the new counter value | ||
| 486 | * is far less likely to overtake the previous one unless | ||
| 487 | * you have some serious IRQ latency issues. | ||
| 488 | */ | ||
| 489 | hwc->sample_period = armpmu->max_period >> 1; | ||
| 490 | hwc->last_period = hwc->sample_period; | ||
| 491 | local64_set(&hwc->period_left, hwc->sample_period); | ||
| 492 | } | ||
| 493 | |||
| 494 | err = 0; | ||
| 495 | if (event->group_leader != event) { | ||
| 496 | err = validate_group(event); | ||
| 497 | if (err) | ||
| 498 | return -EINVAL; | ||
| 499 | } | ||
| 500 | |||
| 501 | return err; | ||
| 502 | } | ||
| 503 | |||
| 504 | static int armpmu_event_init(struct perf_event *event) | ||
| 505 | { | ||
| 506 | struct arm_pmu *armpmu = to_arm_pmu(event->pmu); | ||
| 507 | int err = 0; | ||
| 508 | atomic_t *active_events = &armpmu->active_events; | ||
| 509 | |||
| 510 | if (armpmu->map_event(event) == -ENOENT) | ||
| 511 | return -ENOENT; | ||
| 512 | |||
| 513 | event->destroy = hw_perf_event_destroy; | ||
| 514 | |||
| 515 | if (!atomic_inc_not_zero(active_events)) { | ||
| 516 | mutex_lock(&armpmu->reserve_mutex); | ||
| 517 | if (atomic_read(active_events) == 0) | ||
| 518 | err = armpmu_reserve_hardware(armpmu); | ||
| 519 | |||
| 520 | if (!err) | ||
| 521 | atomic_inc(active_events); | ||
| 522 | mutex_unlock(&armpmu->reserve_mutex); | ||
| 523 | } | ||
| 524 | |||
| 525 | if (err) | ||
| 526 | return err; | ||
| 527 | |||
| 528 | err = __hw_perf_event_init(event); | ||
| 529 | if (err) | ||
| 530 | hw_perf_event_destroy(event); | ||
| 531 | |||
| 532 | return err; | ||
| 533 | } | ||
| 534 | |||
| 535 | static void armpmu_enable(struct pmu *pmu) | ||
| 536 | { | ||
| 537 | struct arm_pmu *armpmu = to_arm_pmu(pmu); | ||
| 538 | struct pmu_hw_events *hw_events = armpmu->get_hw_events(); | ||
| 539 | int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); | ||
| 540 | |||
| 541 | if (enabled) | ||
| 542 | armpmu->start(); | ||
| 543 | } | ||
| 544 | |||
| 545 | static void armpmu_disable(struct pmu *pmu) | ||
| 546 | { | ||
| 547 | struct arm_pmu *armpmu = to_arm_pmu(pmu); | ||
| 548 | armpmu->stop(); | ||
| 549 | } | ||
| 550 | |||
| 551 | static void __init armpmu_init(struct arm_pmu *armpmu) | ||
| 552 | { | ||
| 553 | atomic_set(&armpmu->active_events, 0); | ||
| 554 | mutex_init(&armpmu->reserve_mutex); | ||
| 555 | |||
| 556 | armpmu->pmu = (struct pmu) { | ||
| 557 | .pmu_enable = armpmu_enable, | ||
| 558 | .pmu_disable = armpmu_disable, | ||
| 559 | .event_init = armpmu_event_init, | ||
| 560 | .add = armpmu_add, | ||
| 561 | .del = armpmu_del, | ||
| 562 | .start = armpmu_start, | ||
| 563 | .stop = armpmu_stop, | ||
| 564 | .read = armpmu_read, | ||
| 565 | }; | ||
| 566 | } | ||
| 567 | |||
| 568 | int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) | ||
| 569 | { | ||
| 570 | armpmu_init(armpmu); | ||
| 571 | return perf_pmu_register(&armpmu->pmu, name, type); | ||
| 572 | } | ||
| 573 | |||
| 574 | /* | ||
| 575 | * ARMv8 PMUv3 Performance Events handling code. | ||
| 576 | * Common event types. | ||
| 577 | */ | ||
| 578 | enum armv8_pmuv3_perf_types { | ||
| 579 | /* Required events. */ | ||
| 580 | ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR = 0x00, | ||
| 581 | ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL = 0x03, | ||
| 582 | ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS = 0x04, | ||
| 583 | ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED = 0x10, | ||
| 584 | ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES = 0x11, | ||
| 585 | ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED = 0x12, | ||
| 586 | |||
| 587 | /* At least one of the following is required. */ | ||
| 588 | ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED = 0x08, | ||
| 589 | ARMV8_PMUV3_PERFCTR_OP_SPEC = 0x1B, | ||
| 590 | |||
| 591 | /* Common architectural events. */ | ||
| 592 | ARMV8_PMUV3_PERFCTR_MEM_READ = 0x06, | ||
| 593 | ARMV8_PMUV3_PERFCTR_MEM_WRITE = 0x07, | ||
| 594 | ARMV8_PMUV3_PERFCTR_EXC_TAKEN = 0x09, | ||
| 595 | ARMV8_PMUV3_PERFCTR_EXC_EXECUTED = 0x0A, | ||
| 596 | ARMV8_PMUV3_PERFCTR_CID_WRITE = 0x0B, | ||
| 597 | ARMV8_PMUV3_PERFCTR_PC_WRITE = 0x0C, | ||
| 598 | ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH = 0x0D, | ||
| 599 | ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN = 0x0E, | ||
| 600 | ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS = 0x0F, | ||
| 601 | ARMV8_PMUV3_PERFCTR_TTBR_WRITE = 0x1C, | ||
| 602 | |||
| 603 | /* Common microarchitectural events. */ | ||
| 604 | ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL = 0x01, | ||
| 605 | ARMV8_PMUV3_PERFCTR_ITLB_REFILL = 0x02, | ||
| 606 | ARMV8_PMUV3_PERFCTR_DTLB_REFILL = 0x05, | ||
| 607 | ARMV8_PMUV3_PERFCTR_MEM_ACCESS = 0x13, | ||
| 608 | ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS = 0x14, | ||
| 609 | ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB = 0x15, | ||
| 610 | ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS = 0x16, | ||
| 611 | ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL = 0x17, | ||
| 612 | ARMV8_PMUV3_PERFCTR_L2_CACHE_WB = 0x18, | ||
| 613 | ARMV8_PMUV3_PERFCTR_BUS_ACCESS = 0x19, | ||
| 614 | ARMV8_PMUV3_PERFCTR_MEM_ERROR = 0x1A, | ||
| 615 | ARMV8_PMUV3_PERFCTR_BUS_CYCLES = 0x1D, | ||
| 616 | |||
| 617 | /* | ||
| 618 | * This isn't an architected event. | ||
| 619 | * We detect this event number and use the cycle counter instead. | ||
| 620 | */ | ||
| 621 | ARMV8_PMUV3_PERFCTR_CPU_CYCLES = 0xFF, | ||
| 622 | }; | ||
| 623 | |||
| 624 | /* PMUv3 HW events mapping. */ | ||
| 625 | static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = { | ||
| 626 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CPU_CYCLES, | ||
| 627 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED, | ||
| 628 | [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, | ||
| 629 | [PERF_COUNT_HW_CACHE_MISSES] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, | ||
| 630 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = HW_OP_UNSUPPORTED, | ||
| 631 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, | ||
| 632 | [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, | ||
| 633 | [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, | ||
| 634 | [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, | ||
| 635 | }; | ||
| 636 | |||
| 637 | static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
| 638 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 639 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
| 640 | [C(L1D)] = { | ||
| 641 | [C(OP_READ)] = { | ||
| 642 | [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, | ||
| 643 | [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, | ||
| 644 | }, | ||
| 645 | [C(OP_WRITE)] = { | ||
| 646 | [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, | ||
| 647 | [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, | ||
| 648 | }, | ||
| 649 | [C(OP_PREFETCH)] = { | ||
| 650 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 651 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 652 | }, | ||
| 653 | }, | ||
| 654 | [C(L1I)] = { | ||
| 655 | [C(OP_READ)] = { | ||
| 656 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 657 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 658 | }, | ||
| 659 | [C(OP_WRITE)] = { | ||
| 660 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 661 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 662 | }, | ||
| 663 | [C(OP_PREFETCH)] = { | ||
| 664 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 665 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 666 | }, | ||
| 667 | }, | ||
| 668 | [C(LL)] = { | ||
| 669 | [C(OP_READ)] = { | ||
| 670 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 671 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 672 | }, | ||
| 673 | [C(OP_WRITE)] = { | ||
| 674 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 675 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 676 | }, | ||
| 677 | [C(OP_PREFETCH)] = { | ||
| 678 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 679 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 680 | }, | ||
| 681 | }, | ||
| 682 | [C(DTLB)] = { | ||
| 683 | [C(OP_READ)] = { | ||
| 684 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 685 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 686 | }, | ||
| 687 | [C(OP_WRITE)] = { | ||
| 688 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 689 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 690 | }, | ||
| 691 | [C(OP_PREFETCH)] = { | ||
| 692 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 693 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 694 | }, | ||
| 695 | }, | ||
| 696 | [C(ITLB)] = { | ||
| 697 | [C(OP_READ)] = { | ||
| 698 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 699 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 700 | }, | ||
| 701 | [C(OP_WRITE)] = { | ||
| 702 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 703 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 704 | }, | ||
| 705 | [C(OP_PREFETCH)] = { | ||
| 706 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 707 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 708 | }, | ||
| 709 | }, | ||
| 710 | [C(BPU)] = { | ||
| 711 | [C(OP_READ)] = { | ||
| 712 | [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, | ||
| 713 | [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, | ||
| 714 | }, | ||
| 715 | [C(OP_WRITE)] = { | ||
| 716 | [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, | ||
| 717 | [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, | ||
| 718 | }, | ||
| 719 | [C(OP_PREFETCH)] = { | ||
| 720 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 721 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 722 | }, | ||
| 723 | }, | ||
| 724 | [C(NODE)] = { | ||
| 725 | [C(OP_READ)] = { | ||
| 726 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 727 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 728 | }, | ||
| 729 | [C(OP_WRITE)] = { | ||
| 730 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 731 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 732 | }, | ||
| 733 | [C(OP_PREFETCH)] = { | ||
| 734 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
| 735 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
| 736 | }, | ||
| 737 | }, | ||
| 738 | }; | ||
| 739 | |||
| 740 | /* | ||
| 741 | * Perf Events' indices | ||
| 742 | */ | ||
| 743 | #define ARMV8_IDX_CYCLE_COUNTER 0 | ||
| 744 | #define ARMV8_IDX_COUNTER0 1 | ||
| 745 | #define ARMV8_IDX_COUNTER_LAST (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1) | ||
| 746 | |||
| 747 | #define ARMV8_MAX_COUNTERS 32 | ||
| 748 | #define ARMV8_COUNTER_MASK (ARMV8_MAX_COUNTERS - 1) | ||
| 749 | |||
| 750 | /* | ||
| 751 | * ARMv8 low level PMU access | ||
| 752 | */ | ||
| 753 | |||
| 754 | /* | ||
| 755 | * Perf Event to low level counters mapping | ||
| 756 | */ | ||
| 757 | #define ARMV8_IDX_TO_COUNTER(x) \ | ||
| 758 | (((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK) | ||
| 759 | |||
| 760 | /* | ||
| 761 | * Per-CPU PMCR: config reg | ||
| 762 | */ | ||
| 763 | #define ARMV8_PMCR_E (1 << 0) /* Enable all counters */ | ||
| 764 | #define ARMV8_PMCR_P (1 << 1) /* Reset all counters */ | ||
| 765 | #define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */ | ||
| 766 | #define ARMV8_PMCR_D (1 << 3) /* CCNT counts every 64th cpu cycle */ | ||
| 767 | #define ARMV8_PMCR_X (1 << 4) /* Export to ETM */ | ||
| 768 | #define ARMV8_PMCR_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ | ||
| 769 | #define ARMV8_PMCR_N_SHIFT 11 /* Number of counters supported */ | ||
| 770 | #define ARMV8_PMCR_N_MASK 0x1f | ||
| 771 | #define ARMV8_PMCR_MASK 0x3f /* Mask for writable bits */ | ||
| 772 | |||
| 773 | /* | ||
| 774 | * PMOVSR: counters overflow flag status reg | ||
| 775 | */ | ||
| 776 | #define ARMV8_OVSR_MASK 0xffffffff /* Mask for writable bits */ | ||
| 777 | #define ARMV8_OVERFLOWED_MASK ARMV8_OVSR_MASK | ||
| 778 | |||
| 779 | /* | ||
| 780 | * PMXEVTYPER: Event selection reg | ||
| 781 | */ | ||
| 782 | #define ARMV8_EVTYPE_MASK 0xc00000ff /* Mask for writable bits */ | ||
| 783 | #define ARMV8_EVTYPE_EVENT 0xff /* Mask for EVENT bits */ | ||
| 784 | |||
| 785 | /* | ||
| 786 | * Event filters for PMUv3 | ||
| 787 | */ | ||
| 788 | #define ARMV8_EXCLUDE_EL1 (1 << 31) | ||
| 789 | #define ARMV8_EXCLUDE_EL0 (1 << 30) | ||
| 790 | #define ARMV8_INCLUDE_EL2 (1 << 27) | ||
| 791 | |||
| 792 | static inline u32 armv8pmu_pmcr_read(void) | ||
| 793 | { | ||
| 794 | u32 val; | ||
| 795 | asm volatile("mrs %0, pmcr_el0" : "=r" (val)); | ||
| 796 | return val; | ||
| 797 | } | ||
| 798 | |||
| 799 | static inline void armv8pmu_pmcr_write(u32 val) | ||
| 800 | { | ||
| 801 | val &= ARMV8_PMCR_MASK; | ||
| 802 | isb(); | ||
| 803 | asm volatile("msr pmcr_el0, %0" :: "r" (val)); | ||
| 804 | } | ||
| 805 | |||
| 806 | static inline int armv8pmu_has_overflowed(u32 pmovsr) | ||
| 807 | { | ||
| 808 | return pmovsr & ARMV8_OVERFLOWED_MASK; | ||
| 809 | } | ||
| 810 | |||
| 811 | static inline int armv8pmu_counter_valid(int idx) | ||
| 812 | { | ||
| 813 | return idx >= ARMV8_IDX_CYCLE_COUNTER && idx <= ARMV8_IDX_COUNTER_LAST; | ||
| 814 | } | ||
| 815 | |||
| 816 | static inline int armv8pmu_counter_has_overflowed(u32 pmnc, int idx) | ||
| 817 | { | ||
| 818 | int ret = 0; | ||
| 819 | u32 counter; | ||
| 820 | |||
| 821 | if (!armv8pmu_counter_valid(idx)) { | ||
| 822 | pr_err("CPU%u checking wrong counter %d overflow status\n", | ||
| 823 | smp_processor_id(), idx); | ||
| 824 | } else { | ||
| 825 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 826 | ret = pmnc & BIT(counter); | ||
| 827 | } | ||
| 828 | |||
| 829 | return ret; | ||
| 830 | } | ||
| 831 | |||
| 832 | static inline int armv8pmu_select_counter(int idx) | ||
| 833 | { | ||
| 834 | u32 counter; | ||
| 835 | |||
| 836 | if (!armv8pmu_counter_valid(idx)) { | ||
| 837 | pr_err("CPU%u selecting wrong PMNC counter %d\n", | ||
| 838 | smp_processor_id(), idx); | ||
| 839 | return -EINVAL; | ||
| 840 | } | ||
| 841 | |||
| 842 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 843 | asm volatile("msr pmselr_el0, %0" :: "r" (counter)); | ||
| 844 | isb(); | ||
| 845 | |||
| 846 | return idx; | ||
| 847 | } | ||
| 848 | |||
| 849 | static inline u32 armv8pmu_read_counter(int idx) | ||
| 850 | { | ||
| 851 | u32 value = 0; | ||
| 852 | |||
| 853 | if (!armv8pmu_counter_valid(idx)) | ||
| 854 | pr_err("CPU%u reading wrong counter %d\n", | ||
| 855 | smp_processor_id(), idx); | ||
| 856 | else if (idx == ARMV8_IDX_CYCLE_COUNTER) | ||
| 857 | asm volatile("mrs %0, pmccntr_el0" : "=r" (value)); | ||
| 858 | else if (armv8pmu_select_counter(idx) == idx) | ||
| 859 | asm volatile("mrs %0, pmxevcntr_el0" : "=r" (value)); | ||
| 860 | |||
| 861 | return value; | ||
| 862 | } | ||
| 863 | |||
| 864 | static inline void armv8pmu_write_counter(int idx, u32 value) | ||
| 865 | { | ||
| 866 | if (!armv8pmu_counter_valid(idx)) | ||
| 867 | pr_err("CPU%u writing wrong counter %d\n", | ||
| 868 | smp_processor_id(), idx); | ||
| 869 | else if (idx == ARMV8_IDX_CYCLE_COUNTER) | ||
| 870 | asm volatile("msr pmccntr_el0, %0" :: "r" (value)); | ||
| 871 | else if (armv8pmu_select_counter(idx) == idx) | ||
| 872 | asm volatile("msr pmxevcntr_el0, %0" :: "r" (value)); | ||
| 873 | } | ||
| 874 | |||
| 875 | static inline void armv8pmu_write_evtype(int idx, u32 val) | ||
| 876 | { | ||
| 877 | if (armv8pmu_select_counter(idx) == idx) { | ||
| 878 | val &= ARMV8_EVTYPE_MASK; | ||
| 879 | asm volatile("msr pmxevtyper_el0, %0" :: "r" (val)); | ||
| 880 | } | ||
| 881 | } | ||
| 882 | |||
| 883 | static inline int armv8pmu_enable_counter(int idx) | ||
| 884 | { | ||
| 885 | u32 counter; | ||
| 886 | |||
| 887 | if (!armv8pmu_counter_valid(idx)) { | ||
| 888 | pr_err("CPU%u enabling wrong PMNC counter %d\n", | ||
| 889 | smp_processor_id(), idx); | ||
| 890 | return -EINVAL; | ||
| 891 | } | ||
| 892 | |||
| 893 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 894 | asm volatile("msr pmcntenset_el0, %0" :: "r" (BIT(counter))); | ||
| 895 | return idx; | ||
| 896 | } | ||
| 897 | |||
| 898 | static inline int armv8pmu_disable_counter(int idx) | ||
| 899 | { | ||
| 900 | u32 counter; | ||
| 901 | |||
| 902 | if (!armv8pmu_counter_valid(idx)) { | ||
| 903 | pr_err("CPU%u disabling wrong PMNC counter %d\n", | ||
| 904 | smp_processor_id(), idx); | ||
| 905 | return -EINVAL; | ||
| 906 | } | ||
| 907 | |||
| 908 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 909 | asm volatile("msr pmcntenclr_el0, %0" :: "r" (BIT(counter))); | ||
| 910 | return idx; | ||
| 911 | } | ||
| 912 | |||
| 913 | static inline int armv8pmu_enable_intens(int idx) | ||
| 914 | { | ||
| 915 | u32 counter; | ||
| 916 | |||
| 917 | if (!armv8pmu_counter_valid(idx)) { | ||
| 918 | pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n", | ||
| 919 | smp_processor_id(), idx); | ||
| 920 | return -EINVAL; | ||
| 921 | } | ||
| 922 | |||
| 923 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 924 | asm volatile("msr pmintenset_el1, %0" :: "r" (BIT(counter))); | ||
| 925 | return idx; | ||
| 926 | } | ||
| 927 | |||
| 928 | static inline int armv8pmu_disable_intens(int idx) | ||
| 929 | { | ||
| 930 | u32 counter; | ||
| 931 | |||
| 932 | if (!armv8pmu_counter_valid(idx)) { | ||
| 933 | pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n", | ||
| 934 | smp_processor_id(), idx); | ||
| 935 | return -EINVAL; | ||
| 936 | } | ||
| 937 | |||
| 938 | counter = ARMV8_IDX_TO_COUNTER(idx); | ||
| 939 | asm volatile("msr pmintenclr_el1, %0" :: "r" (BIT(counter))); | ||
| 940 | isb(); | ||
| 941 | /* Clear the overflow flag in case an interrupt is pending. */ | ||
| 942 | asm volatile("msr pmovsclr_el0, %0" :: "r" (BIT(counter))); | ||
| 943 | isb(); | ||
| 944 | return idx; | ||
| 945 | } | ||
| 946 | |||
| 947 | static inline u32 armv8pmu_getreset_flags(void) | ||
| 948 | { | ||
| 949 | u32 value; | ||
| 950 | |||
| 951 | /* Read */ | ||
| 952 | asm volatile("mrs %0, pmovsclr_el0" : "=r" (value)); | ||
| 953 | |||
| 954 | /* Write to clear flags */ | ||
| 955 | value &= ARMV8_OVSR_MASK; | ||
| 956 | asm volatile("msr pmovsclr_el0, %0" :: "r" (value)); | ||
| 957 | |||
| 958 | return value; | ||
| 959 | } | ||
| 960 | |||
| 961 | static void armv8pmu_enable_event(struct hw_perf_event *hwc, int idx) | ||
| 962 | { | ||
| 963 | unsigned long flags; | ||
| 964 | struct pmu_hw_events *events = cpu_pmu->get_hw_events(); | ||
| 965 | |||
| 966 | /* | ||
| 967 | * Enable counter and interrupt, and set the counter to count | ||
| 968 | * the event that we're interested in. | ||
| 969 | */ | ||
| 970 | raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||
| 971 | |||
| 972 | /* | ||
| 973 | * Disable counter | ||
| 974 | */ | ||
| 975 | armv8pmu_disable_counter(idx); | ||
| 976 | |||
| 977 | /* | ||
| 978 | * Set event (if destined for PMNx counters). | ||
| 979 | */ | ||
| 980 | armv8pmu_write_evtype(idx, hwc->config_base); | ||
| 981 | |||
| 982 | /* | ||
| 983 | * Enable interrupt for this counter | ||
| 984 | */ | ||
| 985 | armv8pmu_enable_intens(idx); | ||
| 986 | |||
| 987 | /* | ||
| 988 | * Enable counter | ||
| 989 | */ | ||
| 990 | armv8pmu_enable_counter(idx); | ||
| 991 | |||
| 992 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||
| 993 | } | ||
| 994 | |||
| 995 | static void armv8pmu_disable_event(struct hw_perf_event *hwc, int idx) | ||
| 996 | { | ||
| 997 | unsigned long flags; | ||
| 998 | struct pmu_hw_events *events = cpu_pmu->get_hw_events(); | ||
| 999 | |||
| 1000 | /* | ||
| 1001 | * Disable counter and interrupt | ||
| 1002 | */ | ||
| 1003 | raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||
| 1004 | |||
| 1005 | /* | ||
| 1006 | * Disable counter | ||
| 1007 | */ | ||
| 1008 | armv8pmu_disable_counter(idx); | ||
| 1009 | |||
| 1010 | /* | ||
| 1011 | * Disable interrupt for this counter | ||
| 1012 | */ | ||
| 1013 | armv8pmu_disable_intens(idx); | ||
| 1014 | |||
| 1015 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) | ||
| 1019 | { | ||
| 1020 | u32 pmovsr; | ||
| 1021 | struct perf_sample_data data; | ||
| 1022 | struct pmu_hw_events *cpuc; | ||
| 1023 | struct pt_regs *regs; | ||
| 1024 | int idx; | ||
| 1025 | |||
| 1026 | /* | ||
| 1027 | * Get and reset the IRQ flags | ||
| 1028 | */ | ||
| 1029 | pmovsr = armv8pmu_getreset_flags(); | ||
| 1030 | |||
| 1031 | /* | ||
| 1032 | * Did an overflow occur? | ||
| 1033 | */ | ||
| 1034 | if (!armv8pmu_has_overflowed(pmovsr)) | ||
| 1035 | return IRQ_NONE; | ||
| 1036 | |||
| 1037 | /* | ||
| 1038 | * Handle the counter(s) overflow(s) | ||
| 1039 | */ | ||
| 1040 | regs = get_irq_regs(); | ||
| 1041 | |||
| 1042 | cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 1043 | for (idx = 0; idx < cpu_pmu->num_events; ++idx) { | ||
| 1044 | struct perf_event *event = cpuc->events[idx]; | ||
| 1045 | struct hw_perf_event *hwc; | ||
| 1046 | |||
| 1047 | /* Ignore if we don't have an event. */ | ||
| 1048 | if (!event) | ||
| 1049 | continue; | ||
| 1050 | |||
| 1051 | /* | ||
| 1052 | * We have a single interrupt for all counters. Check that | ||
| 1053 | * each counter has overflowed before we process it. | ||
| 1054 | */ | ||
| 1055 | if (!armv8pmu_counter_has_overflowed(pmovsr, idx)) | ||
| 1056 | continue; | ||
| 1057 | |||
| 1058 | hwc = &event->hw; | ||
| 1059 | armpmu_event_update(event, hwc, idx); | ||
| 1060 | perf_sample_data_init(&data, 0, hwc->last_period); | ||
| 1061 | if (!armpmu_event_set_period(event, hwc, idx)) | ||
| 1062 | continue; | ||
| 1063 | |||
| 1064 | if (perf_event_overflow(event, &data, regs)) | ||
| 1065 | cpu_pmu->disable(hwc, idx); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | /* | ||
| 1069 | * Handle the pending perf events. | ||
| 1070 | * | ||
| 1071 | * Note: this call *must* be run with interrupts disabled. For | ||
| 1072 | * platforms that can have the PMU interrupts raised as an NMI, this | ||
| 1073 | * will not work. | ||
| 1074 | */ | ||
| 1075 | irq_work_run(); | ||
| 1076 | |||
| 1077 | return IRQ_HANDLED; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | static void armv8pmu_start(void) | ||
| 1081 | { | ||
| 1082 | unsigned long flags; | ||
| 1083 | struct pmu_hw_events *events = cpu_pmu->get_hw_events(); | ||
| 1084 | |||
| 1085 | raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||
| 1086 | /* Enable all counters */ | ||
| 1087 | armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_E); | ||
| 1088 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | static void armv8pmu_stop(void) | ||
| 1092 | { | ||
| 1093 | unsigned long flags; | ||
| 1094 | struct pmu_hw_events *events = cpu_pmu->get_hw_events(); | ||
| 1095 | |||
| 1096 | raw_spin_lock_irqsave(&events->pmu_lock, flags); | ||
| 1097 | /* Disable all counters */ | ||
| 1098 | armv8pmu_pmcr_write(armv8pmu_pmcr_read() & ~ARMV8_PMCR_E); | ||
| 1099 | raw_spin_unlock_irqrestore(&events->pmu_lock, flags); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc, | ||
| 1103 | struct hw_perf_event *event) | ||
| 1104 | { | ||
| 1105 | int idx; | ||
| 1106 | unsigned long evtype = event->config_base & ARMV8_EVTYPE_EVENT; | ||
| 1107 | |||
| 1108 | /* Always place a cycle counter into the cycle counter. */ | ||
| 1109 | if (evtype == ARMV8_PMUV3_PERFCTR_CPU_CYCLES) { | ||
| 1110 | if (test_and_set_bit(ARMV8_IDX_CYCLE_COUNTER, cpuc->used_mask)) | ||
| 1111 | return -EAGAIN; | ||
| 1112 | |||
| 1113 | return ARMV8_IDX_CYCLE_COUNTER; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | /* | ||
| 1117 | * For anything other than a cycle counter, try and use | ||
| 1118 | * the events counters | ||
| 1119 | */ | ||
| 1120 | for (idx = ARMV8_IDX_COUNTER0; idx < cpu_pmu->num_events; ++idx) { | ||
| 1121 | if (!test_and_set_bit(idx, cpuc->used_mask)) | ||
| 1122 | return idx; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | /* The counters are all in use. */ | ||
| 1126 | return -EAGAIN; | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | /* | ||
| 1130 | * Add an event filter to a given event. This will only work for PMUv2 PMUs. | ||
| 1131 | */ | ||
| 1132 | static int armv8pmu_set_event_filter(struct hw_perf_event *event, | ||
| 1133 | struct perf_event_attr *attr) | ||
| 1134 | { | ||
| 1135 | unsigned long config_base = 0; | ||
| 1136 | |||
| 1137 | if (attr->exclude_idle) | ||
| 1138 | return -EPERM; | ||
| 1139 | if (attr->exclude_user) | ||
| 1140 | config_base |= ARMV8_EXCLUDE_EL0; | ||
| 1141 | if (attr->exclude_kernel) | ||
| 1142 | config_base |= ARMV8_EXCLUDE_EL1; | ||
| 1143 | if (!attr->exclude_hv) | ||
| 1144 | config_base |= ARMV8_INCLUDE_EL2; | ||
| 1145 | |||
| 1146 | /* | ||
| 1147 | * Install the filter into config_base as this is used to | ||
| 1148 | * construct the event type. | ||
| 1149 | */ | ||
| 1150 | event->config_base = config_base; | ||
| 1151 | |||
| 1152 | return 0; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | static void armv8pmu_reset(void *info) | ||
| 1156 | { | ||
| 1157 | u32 idx, nb_cnt = cpu_pmu->num_events; | ||
| 1158 | |||
| 1159 | /* The counter and interrupt enable registers are unknown at reset. */ | ||
| 1160 | for (idx = ARMV8_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) | ||
| 1161 | armv8pmu_disable_event(NULL, idx); | ||
| 1162 | |||
| 1163 | /* Initialize & Reset PMNC: C and P bits. */ | ||
| 1164 | armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C); | ||
| 1165 | |||
| 1166 | /* Disable access from userspace. */ | ||
| 1167 | asm volatile("msr pmuserenr_el0, %0" :: "r" (0)); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | static int armv8_pmuv3_map_event(struct perf_event *event) | ||
| 1171 | { | ||
| 1172 | return map_cpu_event(event, &armv8_pmuv3_perf_map, | ||
| 1173 | &armv8_pmuv3_perf_cache_map, 0xFF); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | static struct arm_pmu armv8pmu = { | ||
| 1177 | .handle_irq = armv8pmu_handle_irq, | ||
| 1178 | .enable = armv8pmu_enable_event, | ||
| 1179 | .disable = armv8pmu_disable_event, | ||
| 1180 | .read_counter = armv8pmu_read_counter, | ||
| 1181 | .write_counter = armv8pmu_write_counter, | ||
| 1182 | .get_event_idx = armv8pmu_get_event_idx, | ||
| 1183 | .start = armv8pmu_start, | ||
| 1184 | .stop = armv8pmu_stop, | ||
| 1185 | .reset = armv8pmu_reset, | ||
| 1186 | .max_period = (1LLU << 32) - 1, | ||
| 1187 | }; | ||
| 1188 | |||
| 1189 | static u32 __init armv8pmu_read_num_pmnc_events(void) | ||
| 1190 | { | ||
| 1191 | u32 nb_cnt; | ||
| 1192 | |||
| 1193 | /* Read the nb of CNTx counters supported from PMNC */ | ||
| 1194 | nb_cnt = (armv8pmu_pmcr_read() >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK; | ||
| 1195 | |||
| 1196 | /* Add the CPU cycles counter and return */ | ||
| 1197 | return nb_cnt + 1; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | static struct arm_pmu *__init armv8_pmuv3_pmu_init(void) | ||
| 1201 | { | ||
| 1202 | armv8pmu.name = "arm/armv8-pmuv3"; | ||
| 1203 | armv8pmu.map_event = armv8_pmuv3_map_event; | ||
| 1204 | armv8pmu.num_events = armv8pmu_read_num_pmnc_events(); | ||
| 1205 | armv8pmu.set_event_filter = armv8pmu_set_event_filter; | ||
| 1206 | return &armv8pmu; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | /* | ||
| 1210 | * Ensure the PMU has sane values out of reset. | ||
| 1211 | * This requires SMP to be available, so exists as a separate initcall. | ||
| 1212 | */ | ||
| 1213 | static int __init | ||
| 1214 | cpu_pmu_reset(void) | ||
| 1215 | { | ||
| 1216 | if (cpu_pmu && cpu_pmu->reset) | ||
| 1217 | return on_each_cpu(cpu_pmu->reset, NULL, 1); | ||
| 1218 | return 0; | ||
| 1219 | } | ||
| 1220 | arch_initcall(cpu_pmu_reset); | ||
| 1221 | |||
| 1222 | /* | ||
| 1223 | * PMU platform driver and devicetree bindings. | ||
| 1224 | */ | ||
| 1225 | static struct of_device_id armpmu_of_device_ids[] = { | ||
| 1226 | {.compatible = "arm,armv8-pmuv3"}, | ||
| 1227 | {}, | ||
| 1228 | }; | ||
| 1229 | |||
| 1230 | static int __devinit armpmu_device_probe(struct platform_device *pdev) | ||
| 1231 | { | ||
| 1232 | if (!cpu_pmu) | ||
| 1233 | return -ENODEV; | ||
| 1234 | |||
| 1235 | cpu_pmu->plat_device = pdev; | ||
| 1236 | return 0; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | static struct platform_driver armpmu_driver = { | ||
| 1240 | .driver = { | ||
| 1241 | .name = "arm-pmu", | ||
| 1242 | .of_match_table = armpmu_of_device_ids, | ||
| 1243 | }, | ||
| 1244 | .probe = armpmu_device_probe, | ||
| 1245 | }; | ||
| 1246 | |||
| 1247 | static int __init register_pmu_driver(void) | ||
| 1248 | { | ||
| 1249 | return platform_driver_register(&armpmu_driver); | ||
| 1250 | } | ||
| 1251 | device_initcall(register_pmu_driver); | ||
| 1252 | |||
| 1253 | static struct pmu_hw_events *armpmu_get_cpu_events(void) | ||
| 1254 | { | ||
| 1255 | return &__get_cpu_var(cpu_hw_events); | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | static void __init cpu_pmu_init(struct arm_pmu *armpmu) | ||
| 1259 | { | ||
| 1260 | int cpu; | ||
| 1261 | for_each_possible_cpu(cpu) { | ||
| 1262 | struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); | ||
| 1263 | events->events = per_cpu(hw_events, cpu); | ||
| 1264 | events->used_mask = per_cpu(used_mask, cpu); | ||
| 1265 | raw_spin_lock_init(&events->pmu_lock); | ||
| 1266 | } | ||
| 1267 | armpmu->get_hw_events = armpmu_get_cpu_events; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | static int __init init_hw_perf_events(void) | ||
| 1271 | { | ||
| 1272 | u64 dfr = read_cpuid(ID_AA64DFR0_EL1); | ||
| 1273 | |||
| 1274 | switch ((dfr >> 8) & 0xf) { | ||
| 1275 | case 0x1: /* PMUv3 */ | ||
| 1276 | cpu_pmu = armv8_pmuv3_pmu_init(); | ||
| 1277 | break; | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | if (cpu_pmu) { | ||
| 1281 | pr_info("enabled with %s PMU driver, %d counters available\n", | ||
| 1282 | cpu_pmu->name, cpu_pmu->num_events); | ||
| 1283 | cpu_pmu_init(cpu_pmu); | ||
| 1284 | armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW); | ||
| 1285 | } else { | ||
| 1286 | pr_info("no hardware support available\n"); | ||
| 1287 | } | ||
| 1288 | |||
| 1289 | return 0; | ||
| 1290 | } | ||
| 1291 | early_initcall(init_hw_perf_events); | ||
| 1292 | |||
| 1293 | /* | ||
| 1294 | * Callchain handling code. | ||
| 1295 | */ | ||
| 1296 | struct frame_tail { | ||
| 1297 | struct frame_tail __user *fp; | ||
| 1298 | unsigned long lr; | ||
| 1299 | } __attribute__((packed)); | ||
| 1300 | |||
| 1301 | /* | ||
| 1302 | * Get the return address for a single stackframe and return a pointer to the | ||
| 1303 | * next frame tail. | ||
| 1304 | */ | ||
| 1305 | static struct frame_tail __user * | ||
| 1306 | user_backtrace(struct frame_tail __user *tail, | ||
| 1307 | struct perf_callchain_entry *entry) | ||
| 1308 | { | ||
| 1309 | struct frame_tail buftail; | ||
| 1310 | unsigned long err; | ||
| 1311 | |||
| 1312 | /* Also check accessibility of one struct frame_tail beyond */ | ||
| 1313 | if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) | ||
| 1314 | return NULL; | ||
| 1315 | |||
| 1316 | pagefault_disable(); | ||
| 1317 | err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); | ||
| 1318 | pagefault_enable(); | ||
| 1319 | |||
| 1320 | if (err) | ||
| 1321 | return NULL; | ||
| 1322 | |||
| 1323 | perf_callchain_store(entry, buftail.lr); | ||
| 1324 | |||
| 1325 | /* | ||
| 1326 | * Frame pointers should strictly progress back up the stack | ||
| 1327 | * (towards higher addresses). | ||
| 1328 | */ | ||
| 1329 | if (tail >= buftail.fp) | ||
| 1330 | return NULL; | ||
| 1331 | |||
| 1332 | return buftail.fp; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | void perf_callchain_user(struct perf_callchain_entry *entry, | ||
| 1336 | struct pt_regs *regs) | ||
| 1337 | { | ||
| 1338 | struct frame_tail __user *tail; | ||
| 1339 | |||
| 1340 | tail = (struct frame_tail __user *)regs->regs[29]; | ||
| 1341 | |||
| 1342 | while (entry->nr < PERF_MAX_STACK_DEPTH && | ||
| 1343 | tail && !((unsigned long)tail & 0xf)) | ||
| 1344 | tail = user_backtrace(tail, entry); | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | /* | ||
| 1348 | * Gets called by walk_stackframe() for every stackframe. This will be called | ||
| 1349 | * whist unwinding the stackframe and is like a subroutine return so we use | ||
| 1350 | * the PC. | ||
| 1351 | */ | ||
| 1352 | static int callchain_trace(struct stackframe *frame, void *data) | ||
| 1353 | { | ||
| 1354 | struct perf_callchain_entry *entry = data; | ||
| 1355 | perf_callchain_store(entry, frame->pc); | ||
| 1356 | return 0; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | ||
| 1360 | struct pt_regs *regs) | ||
| 1361 | { | ||
| 1362 | struct stackframe frame; | ||
| 1363 | |||
| 1364 | frame.fp = regs->regs[29]; | ||
| 1365 | frame.sp = regs->sp; | ||
| 1366 | frame.pc = regs->pc; | ||
| 1367 | walk_stackframe(&frame, callchain_trace, entry); | ||
| 1368 | } | ||
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c new file mode 100644 index 000000000000..f22965ea1cfc --- /dev/null +++ b/arch/arm64/kernel/process.c | |||
| @@ -0,0 +1,408 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/process.c | ||
| 3 | * | ||
| 4 | * Original Copyright (C) 1995 Linus Torvalds | ||
| 5 | * Copyright (C) 1996-2000 Russell King - Converted to ARM. | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdarg.h> | ||
| 22 | |||
| 23 | #include <linux/export.h> | ||
| 24 | #include <linux/sched.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/mm.h> | ||
| 27 | #include <linux/stddef.h> | ||
| 28 | #include <linux/unistd.h> | ||
| 29 | #include <linux/user.h> | ||
| 30 | #include <linux/delay.h> | ||
| 31 | #include <linux/reboot.h> | ||
| 32 | #include <linux/interrupt.h> | ||
| 33 | #include <linux/kallsyms.h> | ||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/cpu.h> | ||
| 36 | #include <linux/elfcore.h> | ||
| 37 | #include <linux/pm.h> | ||
| 38 | #include <linux/tick.h> | ||
| 39 | #include <linux/utsname.h> | ||
| 40 | #include <linux/uaccess.h> | ||
| 41 | #include <linux/random.h> | ||
| 42 | #include <linux/hw_breakpoint.h> | ||
| 43 | #include <linux/personality.h> | ||
| 44 | #include <linux/notifier.h> | ||
| 45 | |||
| 46 | #include <asm/compat.h> | ||
| 47 | #include <asm/cacheflush.h> | ||
| 48 | #include <asm/processor.h> | ||
| 49 | #include <asm/stacktrace.h> | ||
| 50 | #include <asm/fpsimd.h> | ||
| 51 | |||
| 52 | static void setup_restart(void) | ||
| 53 | { | ||
| 54 | /* | ||
| 55 | * Tell the mm system that we are going to reboot - | ||
| 56 | * we may need it to insert some 1:1 mappings so that | ||
| 57 | * soft boot works. | ||
| 58 | */ | ||
| 59 | setup_mm_for_reboot(); | ||
| 60 | |||
| 61 | /* Clean and invalidate caches */ | ||
| 62 | flush_cache_all(); | ||
| 63 | |||
| 64 | /* Turn D-cache off */ | ||
| 65 | cpu_cache_off(); | ||
| 66 | |||
| 67 | /* Push out any further dirty data, and ensure cache is empty */ | ||
| 68 | flush_cache_all(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void soft_restart(unsigned long addr) | ||
| 72 | { | ||
| 73 | setup_restart(); | ||
| 74 | cpu_reset(addr); | ||
| 75 | } | ||
| 76 | |||
| 77 | /* | ||
| 78 | * Function pointers to optional machine specific functions | ||
| 79 | */ | ||
| 80 | void (*pm_power_off)(void); | ||
| 81 | EXPORT_SYMBOL_GPL(pm_power_off); | ||
| 82 | |||
| 83 | void (*pm_restart)(const char *cmd); | ||
| 84 | EXPORT_SYMBOL_GPL(pm_restart); | ||
| 85 | |||
| 86 | |||
| 87 | /* | ||
| 88 | * This is our default idle handler. | ||
| 89 | */ | ||
| 90 | static void default_idle(void) | ||
| 91 | { | ||
| 92 | /* | ||
| 93 | * This should do all the clock switching and wait for interrupt | ||
| 94 | * tricks | ||
| 95 | */ | ||
| 96 | cpu_do_idle(); | ||
| 97 | local_irq_enable(); | ||
| 98 | } | ||
| 99 | |||
| 100 | void (*pm_idle)(void) = default_idle; | ||
| 101 | EXPORT_SYMBOL_GPL(pm_idle); | ||
| 102 | |||
| 103 | /* | ||
| 104 | * The idle thread, has rather strange semantics for calling pm_idle, | ||
| 105 | * but this is what x86 does and we need to do the same, so that | ||
| 106 | * things like cpuidle get called in the same way. The only difference | ||
| 107 | * is that we always respect 'hlt_counter' to prevent low power idle. | ||
| 108 | */ | ||
| 109 | void cpu_idle(void) | ||
| 110 | { | ||
| 111 | local_fiq_enable(); | ||
| 112 | |||
| 113 | /* endless idle loop with no priority at all */ | ||
| 114 | while (1) { | ||
| 115 | tick_nohz_idle_enter(); | ||
| 116 | rcu_idle_enter(); | ||
| 117 | while (!need_resched()) { | ||
| 118 | /* | ||
| 119 | * We need to disable interrupts here to ensure | ||
| 120 | * we don't miss a wakeup call. | ||
| 121 | */ | ||
| 122 | local_irq_disable(); | ||
| 123 | if (!need_resched()) { | ||
| 124 | stop_critical_timings(); | ||
| 125 | pm_idle(); | ||
| 126 | start_critical_timings(); | ||
| 127 | /* | ||
| 128 | * pm_idle functions should always return | ||
| 129 | * with IRQs enabled. | ||
| 130 | */ | ||
| 131 | WARN_ON(irqs_disabled()); | ||
| 132 | } else { | ||
| 133 | local_irq_enable(); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | rcu_idle_exit(); | ||
| 137 | tick_nohz_idle_exit(); | ||
| 138 | schedule_preempt_disabled(); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void machine_shutdown(void) | ||
| 143 | { | ||
| 144 | #ifdef CONFIG_SMP | ||
| 145 | smp_send_stop(); | ||
| 146 | #endif | ||
| 147 | } | ||
| 148 | |||
| 149 | void machine_halt(void) | ||
| 150 | { | ||
| 151 | machine_shutdown(); | ||
| 152 | while (1); | ||
| 153 | } | ||
| 154 | |||
| 155 | void machine_power_off(void) | ||
| 156 | { | ||
| 157 | machine_shutdown(); | ||
| 158 | if (pm_power_off) | ||
| 159 | pm_power_off(); | ||
| 160 | } | ||
| 161 | |||
| 162 | void machine_restart(char *cmd) | ||
| 163 | { | ||
| 164 | machine_shutdown(); | ||
| 165 | |||
| 166 | /* Disable interrupts first */ | ||
| 167 | local_irq_disable(); | ||
| 168 | local_fiq_disable(); | ||
| 169 | |||
| 170 | /* Now call the architecture specific reboot code. */ | ||
| 171 | if (pm_restart) | ||
| 172 | pm_restart(cmd); | ||
| 173 | |||
| 174 | /* | ||
| 175 | * Whoops - the architecture was unable to reboot. | ||
| 176 | */ | ||
| 177 | printk("Reboot failed -- System halted\n"); | ||
| 178 | while (1); | ||
| 179 | } | ||
| 180 | |||
| 181 | void __show_regs(struct pt_regs *regs) | ||
| 182 | { | ||
| 183 | int i; | ||
| 184 | |||
| 185 | printk("CPU: %d %s (%s %.*s)\n", | ||
| 186 | raw_smp_processor_id(), print_tainted(), | ||
| 187 | init_utsname()->release, | ||
| 188 | (int)strcspn(init_utsname()->version, " "), | ||
| 189 | init_utsname()->version); | ||
| 190 | print_symbol("PC is at %s\n", instruction_pointer(regs)); | ||
| 191 | print_symbol("LR is at %s\n", regs->regs[30]); | ||
| 192 | printk("pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", | ||
| 193 | regs->pc, regs->regs[30], regs->pstate); | ||
| 194 | printk("sp : %016llx\n", regs->sp); | ||
| 195 | for (i = 29; i >= 0; i--) { | ||
| 196 | printk("x%-2d: %016llx ", i, regs->regs[i]); | ||
| 197 | if (i % 2 == 0) | ||
| 198 | printk("\n"); | ||
| 199 | } | ||
| 200 | printk("\n"); | ||
| 201 | } | ||
| 202 | |||
| 203 | void show_regs(struct pt_regs * regs) | ||
| 204 | { | ||
| 205 | printk("\n"); | ||
| 206 | printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm); | ||
| 207 | __show_regs(regs); | ||
| 208 | } | ||
| 209 | |||
| 210 | /* | ||
| 211 | * Free current thread data structures etc.. | ||
| 212 | */ | ||
| 213 | void exit_thread(void) | ||
| 214 | { | ||
| 215 | } | ||
| 216 | |||
| 217 | void flush_thread(void) | ||
| 218 | { | ||
| 219 | fpsimd_flush_thread(); | ||
| 220 | flush_ptrace_hw_breakpoint(current); | ||
| 221 | } | ||
| 222 | |||
| 223 | void release_thread(struct task_struct *dead_task) | ||
| 224 | { | ||
| 225 | } | ||
| 226 | |||
| 227 | int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) | ||
| 228 | { | ||
| 229 | fpsimd_save_state(¤t->thread.fpsimd_state); | ||
| 230 | *dst = *src; | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | asmlinkage void ret_from_fork(void) asm("ret_from_fork"); | ||
| 235 | |||
| 236 | int copy_thread(unsigned long clone_flags, unsigned long stack_start, | ||
| 237 | unsigned long stk_sz, struct task_struct *p, | ||
| 238 | struct pt_regs *regs) | ||
| 239 | { | ||
| 240 | struct pt_regs *childregs = task_pt_regs(p); | ||
| 241 | unsigned long tls = p->thread.tp_value; | ||
| 242 | |||
| 243 | *childregs = *regs; | ||
| 244 | childregs->regs[0] = 0; | ||
| 245 | |||
| 246 | if (is_compat_thread(task_thread_info(p))) | ||
| 247 | childregs->compat_sp = stack_start; | ||
| 248 | else { | ||
| 249 | /* | ||
| 250 | * Read the current TLS pointer from tpidr_el0 as it may be | ||
| 251 | * out-of-sync with the saved value. | ||
| 252 | */ | ||
| 253 | asm("mrs %0, tpidr_el0" : "=r" (tls)); | ||
| 254 | childregs->sp = stack_start; | ||
| 255 | } | ||
| 256 | |||
| 257 | memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context)); | ||
| 258 | p->thread.cpu_context.sp = (unsigned long)childregs; | ||
| 259 | p->thread.cpu_context.pc = (unsigned long)ret_from_fork; | ||
| 260 | |||
| 261 | /* If a TLS pointer was passed to clone, use that for the new thread. */ | ||
| 262 | if (clone_flags & CLONE_SETTLS) | ||
| 263 | tls = regs->regs[3]; | ||
| 264 | p->thread.tp_value = tls; | ||
| 265 | |||
| 266 | ptrace_hw_copy_thread(p); | ||
| 267 | |||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | static void tls_thread_switch(struct task_struct *next) | ||
| 272 | { | ||
| 273 | unsigned long tpidr, tpidrro; | ||
| 274 | |||
| 275 | if (!is_compat_task()) { | ||
| 276 | asm("mrs %0, tpidr_el0" : "=r" (tpidr)); | ||
| 277 | current->thread.tp_value = tpidr; | ||
| 278 | } | ||
| 279 | |||
| 280 | if (is_compat_thread(task_thread_info(next))) { | ||
| 281 | tpidr = 0; | ||
| 282 | tpidrro = next->thread.tp_value; | ||
| 283 | } else { | ||
| 284 | tpidr = next->thread.tp_value; | ||
| 285 | tpidrro = 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | asm( | ||
| 289 | " msr tpidr_el0, %0\n" | ||
| 290 | " msr tpidrro_el0, %1" | ||
| 291 | : : "r" (tpidr), "r" (tpidrro)); | ||
| 292 | } | ||
| 293 | |||
| 294 | /* | ||
| 295 | * Thread switching. | ||
| 296 | */ | ||
| 297 | struct task_struct *__switch_to(struct task_struct *prev, | ||
| 298 | struct task_struct *next) | ||
| 299 | { | ||
| 300 | struct task_struct *last; | ||
| 301 | |||
| 302 | fpsimd_thread_switch(next); | ||
| 303 | tls_thread_switch(next); | ||
| 304 | hw_breakpoint_thread_switch(next); | ||
| 305 | |||
| 306 | /* the actual thread switch */ | ||
| 307 | last = cpu_switch_to(prev, next); | ||
| 308 | |||
| 309 | return last; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * Fill in the task's elfregs structure for a core dump. | ||
| 314 | */ | ||
| 315 | int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs) | ||
| 316 | { | ||
| 317 | elf_core_copy_regs(elfregs, task_pt_regs(t)); | ||
| 318 | return 1; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* | ||
| 322 | * fill in the fpe structure for a core dump... | ||
| 323 | */ | ||
| 324 | int dump_fpu (struct pt_regs *regs, struct user_fp *fp) | ||
| 325 | { | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | EXPORT_SYMBOL(dump_fpu); | ||
| 329 | |||
| 330 | /* | ||
| 331 | * Shuffle the argument into the correct register before calling the | ||
| 332 | * thread function. x1 is the thread argument, x2 is the pointer to | ||
| 333 | * the thread function, and x3 points to the exit function. | ||
| 334 | */ | ||
| 335 | extern void kernel_thread_helper(void); | ||
| 336 | asm( ".section .text\n" | ||
| 337 | " .align\n" | ||
| 338 | " .type kernel_thread_helper, #function\n" | ||
| 339 | "kernel_thread_helper:\n" | ||
| 340 | " mov x0, x1\n" | ||
| 341 | " mov x30, x3\n" | ||
| 342 | " br x2\n" | ||
| 343 | " .size kernel_thread_helper, . - kernel_thread_helper\n" | ||
| 344 | " .previous"); | ||
| 345 | |||
| 346 | #define kernel_thread_exit do_exit | ||
| 347 | |||
| 348 | /* | ||
| 349 | * Create a kernel thread. | ||
| 350 | */ | ||
| 351 | pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
| 352 | { | ||
| 353 | struct pt_regs regs; | ||
| 354 | |||
| 355 | memset(®s, 0, sizeof(regs)); | ||
| 356 | |||
| 357 | regs.regs[1] = (unsigned long)arg; | ||
| 358 | regs.regs[2] = (unsigned long)fn; | ||
| 359 | regs.regs[3] = (unsigned long)kernel_thread_exit; | ||
| 360 | regs.pc = (unsigned long)kernel_thread_helper; | ||
| 361 | regs.pstate = PSR_MODE_EL1h; | ||
| 362 | |||
| 363 | return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
| 364 | } | ||
| 365 | EXPORT_SYMBOL(kernel_thread); | ||
| 366 | |||
| 367 | unsigned long get_wchan(struct task_struct *p) | ||
| 368 | { | ||
| 369 | struct stackframe frame; | ||
| 370 | int count = 0; | ||
| 371 | if (!p || p == current || p->state == TASK_RUNNING) | ||
| 372 | return 0; | ||
| 373 | |||
| 374 | frame.fp = thread_saved_fp(p); | ||
| 375 | frame.sp = thread_saved_sp(p); | ||
| 376 | frame.pc = thread_saved_pc(p); | ||
| 377 | do { | ||
| 378 | int ret = unwind_frame(&frame); | ||
| 379 | if (ret < 0) | ||
| 380 | return 0; | ||
| 381 | if (!in_sched_functions(frame.pc)) | ||
| 382 | return frame.pc; | ||
| 383 | } while (count ++ < 16); | ||
| 384 | return 0; | ||
| 385 | } | ||
| 386 | |||
| 387 | unsigned long arch_align_stack(unsigned long sp) | ||
| 388 | { | ||
| 389 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) | ||
| 390 | sp -= get_random_int() & ~PAGE_MASK; | ||
| 391 | return sp & ~0xf; | ||
| 392 | } | ||
| 393 | |||
| 394 | static unsigned long randomize_base(unsigned long base) | ||
| 395 | { | ||
| 396 | unsigned long range_end = base + (STACK_RND_MASK << PAGE_SHIFT) + 1; | ||
| 397 | return randomize_range(base, range_end, 0) ? : base; | ||
| 398 | } | ||
| 399 | |||
| 400 | unsigned long arch_randomize_brk(struct mm_struct *mm) | ||
| 401 | { | ||
| 402 | return randomize_base(mm->brk); | ||
| 403 | } | ||
| 404 | |||
| 405 | unsigned long randomize_et_dyn(unsigned long base) | ||
| 406 | { | ||
| 407 | return randomize_base(base); | ||
| 408 | } | ||
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c new file mode 100644 index 000000000000..ac3550ecc7b5 --- /dev/null +++ b/arch/arm64/kernel/ptrace.c | |||
| @@ -0,0 +1,1126 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/ptrace.c | ||
| 3 | * | ||
| 4 | * By Ross Biro 1/23/92 | ||
| 5 | * edited by Linus Torvalds | ||
| 6 | * ARM modifications Copyright (C) 2000 Russell King | ||
| 7 | * Copyright (C) 2012 ARM Ltd. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/mm.h> | ||
| 25 | #include <linux/smp.h> | ||
| 26 | #include <linux/ptrace.h> | ||
| 27 | #include <linux/user.h> | ||
| 28 | #include <linux/security.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/signal.h> | ||
| 31 | #include <linux/uaccess.h> | ||
| 32 | #include <linux/perf_event.h> | ||
| 33 | #include <linux/hw_breakpoint.h> | ||
| 34 | #include <linux/regset.h> | ||
| 35 | #include <linux/tracehook.h> | ||
| 36 | #include <linux/elf.h> | ||
| 37 | |||
| 38 | #include <asm/compat.h> | ||
| 39 | #include <asm/debug-monitors.h> | ||
| 40 | #include <asm/pgtable.h> | ||
| 41 | #include <asm/traps.h> | ||
| 42 | #include <asm/system_misc.h> | ||
| 43 | |||
| 44 | /* | ||
| 45 | * TODO: does not yet catch signals sent when the child dies. | ||
| 46 | * in exit.c or in signal.c. | ||
| 47 | */ | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Called by kernel/ptrace.c when detaching.. | ||
| 51 | */ | ||
| 52 | void ptrace_disable(struct task_struct *child) | ||
| 53 | { | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Handle hitting a breakpoint. | ||
| 58 | */ | ||
| 59 | static int ptrace_break(struct pt_regs *regs) | ||
| 60 | { | ||
| 61 | siginfo_t info = { | ||
| 62 | .si_signo = SIGTRAP, | ||
| 63 | .si_errno = 0, | ||
| 64 | .si_code = TRAP_BRKPT, | ||
| 65 | .si_addr = (void __user *)instruction_pointer(regs), | ||
| 66 | }; | ||
| 67 | |||
| 68 | force_sig_info(SIGTRAP, &info, current); | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int arm64_break_trap(unsigned long addr, unsigned int esr, | ||
| 73 | struct pt_regs *regs) | ||
| 74 | { | ||
| 75 | return ptrace_break(regs); | ||
| 76 | } | ||
| 77 | |||
| 78 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 79 | /* | ||
| 80 | * Handle hitting a HW-breakpoint. | ||
| 81 | */ | ||
| 82 | static void ptrace_hbptriggered(struct perf_event *bp, | ||
| 83 | struct perf_sample_data *data, | ||
| 84 | struct pt_regs *regs) | ||
| 85 | { | ||
| 86 | struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp); | ||
| 87 | siginfo_t info = { | ||
| 88 | .si_signo = SIGTRAP, | ||
| 89 | .si_errno = 0, | ||
| 90 | .si_code = TRAP_HWBKPT, | ||
| 91 | .si_addr = (void __user *)(bkpt->trigger), | ||
| 92 | }; | ||
| 93 | |||
| 94 | #ifdef CONFIG_COMPAT | ||
| 95 | int i; | ||
| 96 | |||
| 97 | if (!is_compat_task()) | ||
| 98 | goto send_sig; | ||
| 99 | |||
| 100 | for (i = 0; i < ARM_MAX_BRP; ++i) { | ||
| 101 | if (current->thread.debug.hbp_break[i] == bp) { | ||
| 102 | info.si_errno = (i << 1) + 1; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | for (i = ARM_MAX_BRP; i < ARM_MAX_HBP_SLOTS && !bp; ++i) { | ||
| 107 | if (current->thread.debug.hbp_watch[i] == bp) { | ||
| 108 | info.si_errno = -((i << 1) + 1); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | send_sig: | ||
| 114 | #endif | ||
| 115 | force_sig_info(SIGTRAP, &info, current); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Unregister breakpoints from this task and reset the pointers in | ||
| 120 | * the thread_struct. | ||
| 121 | */ | ||
| 122 | void flush_ptrace_hw_breakpoint(struct task_struct *tsk) | ||
| 123 | { | ||
| 124 | int i; | ||
| 125 | struct thread_struct *t = &tsk->thread; | ||
| 126 | |||
| 127 | for (i = 0; i < ARM_MAX_BRP; i++) { | ||
| 128 | if (t->debug.hbp_break[i]) { | ||
| 129 | unregister_hw_breakpoint(t->debug.hbp_break[i]); | ||
| 130 | t->debug.hbp_break[i] = NULL; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | for (i = 0; i < ARM_MAX_WRP; i++) { | ||
| 135 | if (t->debug.hbp_watch[i]) { | ||
| 136 | unregister_hw_breakpoint(t->debug.hbp_watch[i]); | ||
| 137 | t->debug.hbp_watch[i] = NULL; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | void ptrace_hw_copy_thread(struct task_struct *tsk) | ||
| 143 | { | ||
| 144 | memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); | ||
| 145 | } | ||
| 146 | |||
| 147 | static struct perf_event *ptrace_hbp_get_event(unsigned int note_type, | ||
| 148 | struct task_struct *tsk, | ||
| 149 | unsigned long idx) | ||
| 150 | { | ||
| 151 | struct perf_event *bp = ERR_PTR(-EINVAL); | ||
| 152 | |||
| 153 | switch (note_type) { | ||
| 154 | case NT_ARM_HW_BREAK: | ||
| 155 | if (idx < ARM_MAX_BRP) | ||
| 156 | bp = tsk->thread.debug.hbp_break[idx]; | ||
| 157 | break; | ||
| 158 | case NT_ARM_HW_WATCH: | ||
| 159 | if (idx < ARM_MAX_WRP) | ||
| 160 | bp = tsk->thread.debug.hbp_watch[idx]; | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | |||
| 164 | return bp; | ||
| 165 | } | ||
| 166 | |||
| 167 | static int ptrace_hbp_set_event(unsigned int note_type, | ||
| 168 | struct task_struct *tsk, | ||
| 169 | unsigned long idx, | ||
| 170 | struct perf_event *bp) | ||
| 171 | { | ||
| 172 | int err = -EINVAL; | ||
| 173 | |||
| 174 | switch (note_type) { | ||
| 175 | case NT_ARM_HW_BREAK: | ||
| 176 | if (idx < ARM_MAX_BRP) { | ||
| 177 | tsk->thread.debug.hbp_break[idx] = bp; | ||
| 178 | err = 0; | ||
| 179 | } | ||
| 180 | break; | ||
| 181 | case NT_ARM_HW_WATCH: | ||
| 182 | if (idx < ARM_MAX_WRP) { | ||
| 183 | tsk->thread.debug.hbp_watch[idx] = bp; | ||
| 184 | err = 0; | ||
| 185 | } | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | |||
| 189 | return err; | ||
| 190 | } | ||
| 191 | |||
| 192 | static struct perf_event *ptrace_hbp_create(unsigned int note_type, | ||
| 193 | struct task_struct *tsk, | ||
| 194 | unsigned long idx) | ||
| 195 | { | ||
| 196 | struct perf_event *bp; | ||
| 197 | struct perf_event_attr attr; | ||
| 198 | int err, type; | ||
| 199 | |||
| 200 | switch (note_type) { | ||
| 201 | case NT_ARM_HW_BREAK: | ||
| 202 | type = HW_BREAKPOINT_X; | ||
| 203 | break; | ||
| 204 | case NT_ARM_HW_WATCH: | ||
| 205 | type = HW_BREAKPOINT_RW; | ||
| 206 | break; | ||
| 207 | default: | ||
| 208 | return ERR_PTR(-EINVAL); | ||
| 209 | } | ||
| 210 | |||
| 211 | ptrace_breakpoint_init(&attr); | ||
| 212 | |||
| 213 | /* | ||
| 214 | * Initialise fields to sane defaults | ||
| 215 | * (i.e. values that will pass validation). | ||
| 216 | */ | ||
| 217 | attr.bp_addr = 0; | ||
| 218 | attr.bp_len = HW_BREAKPOINT_LEN_4; | ||
| 219 | attr.bp_type = type; | ||
| 220 | attr.disabled = 1; | ||
| 221 | |||
| 222 | bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk); | ||
| 223 | if (IS_ERR(bp)) | ||
| 224 | return bp; | ||
| 225 | |||
| 226 | err = ptrace_hbp_set_event(note_type, tsk, idx, bp); | ||
| 227 | if (err) | ||
| 228 | return ERR_PTR(err); | ||
| 229 | |||
| 230 | return bp; | ||
| 231 | } | ||
| 232 | |||
| 233 | static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type, | ||
| 234 | struct arch_hw_breakpoint_ctrl ctrl, | ||
| 235 | struct perf_event_attr *attr) | ||
| 236 | { | ||
| 237 | int err, len, type; | ||
| 238 | |||
| 239 | err = arch_bp_generic_fields(ctrl, &len, &type); | ||
| 240 | if (err) | ||
| 241 | return err; | ||
| 242 | |||
| 243 | switch (note_type) { | ||
| 244 | case NT_ARM_HW_BREAK: | ||
| 245 | if ((type & HW_BREAKPOINT_X) != type) | ||
| 246 | return -EINVAL; | ||
| 247 | break; | ||
| 248 | case NT_ARM_HW_WATCH: | ||
| 249 | if ((type & HW_BREAKPOINT_RW) != type) | ||
| 250 | return -EINVAL; | ||
| 251 | break; | ||
| 252 | default: | ||
| 253 | return -EINVAL; | ||
| 254 | } | ||
| 255 | |||
| 256 | attr->bp_len = len; | ||
| 257 | attr->bp_type = type; | ||
| 258 | attr->disabled = !ctrl.enabled; | ||
| 259 | |||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | |||
| 263 | static int ptrace_hbp_get_resource_info(unsigned int note_type, u32 *info) | ||
| 264 | { | ||
| 265 | u8 num; | ||
| 266 | u32 reg = 0; | ||
| 267 | |||
| 268 | switch (note_type) { | ||
| 269 | case NT_ARM_HW_BREAK: | ||
| 270 | num = hw_breakpoint_slots(TYPE_INST); | ||
| 271 | break; | ||
| 272 | case NT_ARM_HW_WATCH: | ||
| 273 | num = hw_breakpoint_slots(TYPE_DATA); | ||
| 274 | break; | ||
| 275 | default: | ||
| 276 | return -EINVAL; | ||
| 277 | } | ||
| 278 | |||
| 279 | reg |= debug_monitors_arch(); | ||
| 280 | reg <<= 8; | ||
| 281 | reg |= num; | ||
| 282 | |||
| 283 | *info = reg; | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int ptrace_hbp_get_ctrl(unsigned int note_type, | ||
| 288 | struct task_struct *tsk, | ||
| 289 | unsigned long idx, | ||
| 290 | u32 *ctrl) | ||
| 291 | { | ||
| 292 | struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); | ||
| 293 | |||
| 294 | if (IS_ERR(bp)) | ||
| 295 | return PTR_ERR(bp); | ||
| 296 | |||
| 297 | *ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0; | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | static int ptrace_hbp_get_addr(unsigned int note_type, | ||
| 302 | struct task_struct *tsk, | ||
| 303 | unsigned long idx, | ||
| 304 | u64 *addr) | ||
| 305 | { | ||
| 306 | struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); | ||
| 307 | |||
| 308 | if (IS_ERR(bp)) | ||
| 309 | return PTR_ERR(bp); | ||
| 310 | |||
| 311 | *addr = bp ? bp->attr.bp_addr : 0; | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type, | ||
| 316 | struct task_struct *tsk, | ||
| 317 | unsigned long idx) | ||
| 318 | { | ||
| 319 | struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx); | ||
| 320 | |||
| 321 | if (!bp) | ||
| 322 | bp = ptrace_hbp_create(note_type, tsk, idx); | ||
| 323 | |||
| 324 | return bp; | ||
| 325 | } | ||
| 326 | |||
| 327 | static int ptrace_hbp_set_ctrl(unsigned int note_type, | ||
| 328 | struct task_struct *tsk, | ||
| 329 | unsigned long idx, | ||
| 330 | u32 uctrl) | ||
| 331 | { | ||
| 332 | int err; | ||
| 333 | struct perf_event *bp; | ||
| 334 | struct perf_event_attr attr; | ||
| 335 | struct arch_hw_breakpoint_ctrl ctrl; | ||
| 336 | |||
| 337 | bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); | ||
| 338 | if (IS_ERR(bp)) { | ||
| 339 | err = PTR_ERR(bp); | ||
| 340 | return err; | ||
| 341 | } | ||
| 342 | |||
| 343 | attr = bp->attr; | ||
| 344 | decode_ctrl_reg(uctrl, &ctrl); | ||
| 345 | err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr); | ||
| 346 | if (err) | ||
| 347 | return err; | ||
| 348 | |||
| 349 | return modify_user_hw_breakpoint(bp, &attr); | ||
| 350 | } | ||
| 351 | |||
| 352 | static int ptrace_hbp_set_addr(unsigned int note_type, | ||
| 353 | struct task_struct *tsk, | ||
| 354 | unsigned long idx, | ||
| 355 | u64 addr) | ||
| 356 | { | ||
| 357 | int err; | ||
| 358 | struct perf_event *bp; | ||
| 359 | struct perf_event_attr attr; | ||
| 360 | |||
| 361 | bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx); | ||
| 362 | if (IS_ERR(bp)) { | ||
| 363 | err = PTR_ERR(bp); | ||
| 364 | return err; | ||
| 365 | } | ||
| 366 | |||
| 367 | attr = bp->attr; | ||
| 368 | attr.bp_addr = addr; | ||
| 369 | err = modify_user_hw_breakpoint(bp, &attr); | ||
| 370 | return err; | ||
| 371 | } | ||
| 372 | |||
| 373 | #define PTRACE_HBP_ADDR_SZ sizeof(u64) | ||
| 374 | #define PTRACE_HBP_CTRL_SZ sizeof(u32) | ||
| 375 | #define PTRACE_HBP_REG_OFF sizeof(u32) | ||
| 376 | |||
| 377 | static int hw_break_get(struct task_struct *target, | ||
| 378 | const struct user_regset *regset, | ||
| 379 | unsigned int pos, unsigned int count, | ||
| 380 | void *kbuf, void __user *ubuf) | ||
| 381 | { | ||
| 382 | unsigned int note_type = regset->core_note_type; | ||
| 383 | int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit; | ||
| 384 | u32 info, ctrl; | ||
| 385 | u64 addr; | ||
| 386 | |||
| 387 | /* Resource info */ | ||
| 388 | ret = ptrace_hbp_get_resource_info(note_type, &info); | ||
| 389 | if (ret) | ||
| 390 | return ret; | ||
| 391 | |||
| 392 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &info, 0, 4); | ||
| 393 | if (ret) | ||
| 394 | return ret; | ||
| 395 | |||
| 396 | /* (address, ctrl) registers */ | ||
| 397 | limit = regset->n * regset->size; | ||
| 398 | while (count && offset < limit) { | ||
| 399 | ret = ptrace_hbp_get_addr(note_type, target, idx, &addr); | ||
| 400 | if (ret) | ||
| 401 | return ret; | ||
| 402 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &addr, | ||
| 403 | offset, offset + PTRACE_HBP_ADDR_SZ); | ||
| 404 | if (ret) | ||
| 405 | return ret; | ||
| 406 | offset += PTRACE_HBP_ADDR_SZ; | ||
| 407 | |||
| 408 | ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl); | ||
| 409 | if (ret) | ||
| 410 | return ret; | ||
| 411 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &ctrl, | ||
| 412 | offset, offset + PTRACE_HBP_CTRL_SZ); | ||
| 413 | if (ret) | ||
| 414 | return ret; | ||
| 415 | offset += PTRACE_HBP_CTRL_SZ; | ||
| 416 | idx++; | ||
| 417 | } | ||
| 418 | |||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | static int hw_break_set(struct task_struct *target, | ||
| 423 | const struct user_regset *regset, | ||
| 424 | unsigned int pos, unsigned int count, | ||
| 425 | const void *kbuf, const void __user *ubuf) | ||
| 426 | { | ||
| 427 | unsigned int note_type = regset->core_note_type; | ||
| 428 | int ret, idx = 0, offset = PTRACE_HBP_REG_OFF, limit; | ||
| 429 | u32 ctrl; | ||
| 430 | u64 addr; | ||
| 431 | |||
| 432 | /* Resource info */ | ||
| 433 | ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, 4); | ||
| 434 | if (ret) | ||
| 435 | return ret; | ||
| 436 | |||
| 437 | /* (address, ctrl) registers */ | ||
| 438 | limit = regset->n * regset->size; | ||
| 439 | while (count && offset < limit) { | ||
| 440 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr, | ||
| 441 | offset, offset + PTRACE_HBP_ADDR_SZ); | ||
| 442 | if (ret) | ||
| 443 | return ret; | ||
| 444 | ret = ptrace_hbp_set_addr(note_type, target, idx, addr); | ||
| 445 | if (ret) | ||
| 446 | return ret; | ||
| 447 | offset += PTRACE_HBP_ADDR_SZ; | ||
| 448 | |||
| 449 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl, | ||
| 450 | offset, offset + PTRACE_HBP_CTRL_SZ); | ||
| 451 | if (ret) | ||
| 452 | return ret; | ||
| 453 | ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl); | ||
| 454 | if (ret) | ||
| 455 | return ret; | ||
| 456 | offset += PTRACE_HBP_CTRL_SZ; | ||
| 457 | idx++; | ||
| 458 | } | ||
| 459 | |||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
| 463 | |||
| 464 | static int gpr_get(struct task_struct *target, | ||
| 465 | const struct user_regset *regset, | ||
| 466 | unsigned int pos, unsigned int count, | ||
| 467 | void *kbuf, void __user *ubuf) | ||
| 468 | { | ||
| 469 | struct user_pt_regs *uregs = &task_pt_regs(target)->user_regs; | ||
| 470 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); | ||
| 471 | } | ||
| 472 | |||
| 473 | static int gpr_set(struct task_struct *target, const struct user_regset *regset, | ||
| 474 | unsigned int pos, unsigned int count, | ||
| 475 | const void *kbuf, const void __user *ubuf) | ||
| 476 | { | ||
| 477 | int ret; | ||
| 478 | struct user_pt_regs newregs; | ||
| 479 | |||
| 480 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1); | ||
| 481 | if (ret) | ||
| 482 | return ret; | ||
| 483 | |||
| 484 | if (!valid_user_regs(&newregs)) | ||
| 485 | return -EINVAL; | ||
| 486 | |||
| 487 | task_pt_regs(target)->user_regs = newregs; | ||
| 488 | return 0; | ||
| 489 | } | ||
| 490 | |||
| 491 | /* | ||
| 492 | * TODO: update fp accessors for lazy context switching (sync/flush hwstate) | ||
| 493 | */ | ||
| 494 | static int fpr_get(struct task_struct *target, const struct user_regset *regset, | ||
| 495 | unsigned int pos, unsigned int count, | ||
| 496 | void *kbuf, void __user *ubuf) | ||
| 497 | { | ||
| 498 | struct user_fpsimd_state *uregs; | ||
| 499 | uregs = &target->thread.fpsimd_state.user_fpsimd; | ||
| 500 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1); | ||
| 501 | } | ||
| 502 | |||
| 503 | static int fpr_set(struct task_struct *target, const struct user_regset *regset, | ||
| 504 | unsigned int pos, unsigned int count, | ||
| 505 | const void *kbuf, const void __user *ubuf) | ||
| 506 | { | ||
| 507 | int ret; | ||
| 508 | struct user_fpsimd_state newstate; | ||
| 509 | |||
| 510 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1); | ||
| 511 | if (ret) | ||
| 512 | return ret; | ||
| 513 | |||
| 514 | target->thread.fpsimd_state.user_fpsimd = newstate; | ||
| 515 | return ret; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int tls_get(struct task_struct *target, const struct user_regset *regset, | ||
| 519 | unsigned int pos, unsigned int count, | ||
| 520 | void *kbuf, void __user *ubuf) | ||
| 521 | { | ||
| 522 | unsigned long *tls = &target->thread.tp_value; | ||
| 523 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, tls, 0, -1); | ||
| 524 | } | ||
| 525 | |||
| 526 | static int tls_set(struct task_struct *target, const struct user_regset *regset, | ||
| 527 | unsigned int pos, unsigned int count, | ||
| 528 | const void *kbuf, const void __user *ubuf) | ||
| 529 | { | ||
| 530 | int ret; | ||
| 531 | unsigned long tls; | ||
| 532 | |||
| 533 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); | ||
| 534 | if (ret) | ||
| 535 | return ret; | ||
| 536 | |||
| 537 | target->thread.tp_value = tls; | ||
| 538 | return ret; | ||
| 539 | } | ||
| 540 | |||
| 541 | enum aarch64_regset { | ||
| 542 | REGSET_GPR, | ||
| 543 | REGSET_FPR, | ||
| 544 | REGSET_TLS, | ||
| 545 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 546 | REGSET_HW_BREAK, | ||
| 547 | REGSET_HW_WATCH, | ||
| 548 | #endif | ||
| 549 | }; | ||
| 550 | |||
| 551 | static const struct user_regset aarch64_regsets[] = { | ||
| 552 | [REGSET_GPR] = { | ||
| 553 | .core_note_type = NT_PRSTATUS, | ||
| 554 | .n = sizeof(struct user_pt_regs) / sizeof(u64), | ||
| 555 | .size = sizeof(u64), | ||
| 556 | .align = sizeof(u64), | ||
| 557 | .get = gpr_get, | ||
| 558 | .set = gpr_set | ||
| 559 | }, | ||
| 560 | [REGSET_FPR] = { | ||
| 561 | .core_note_type = NT_PRFPREG, | ||
| 562 | .n = sizeof(struct user_fpsimd_state) / sizeof(u32), | ||
| 563 | /* | ||
| 564 | * We pretend we have 32-bit registers because the fpsr and | ||
| 565 | * fpcr are 32-bits wide. | ||
| 566 | */ | ||
| 567 | .size = sizeof(u32), | ||
| 568 | .align = sizeof(u32), | ||
| 569 | .get = fpr_get, | ||
| 570 | .set = fpr_set | ||
| 571 | }, | ||
| 572 | [REGSET_TLS] = { | ||
| 573 | .core_note_type = NT_ARM_TLS, | ||
| 574 | .n = 1, | ||
| 575 | .size = sizeof(void *), | ||
| 576 | .align = sizeof(void *), | ||
| 577 | .get = tls_get, | ||
| 578 | .set = tls_set, | ||
| 579 | }, | ||
| 580 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 581 | [REGSET_HW_BREAK] = { | ||
| 582 | .core_note_type = NT_ARM_HW_BREAK, | ||
| 583 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), | ||
| 584 | .size = sizeof(u32), | ||
| 585 | .align = sizeof(u32), | ||
| 586 | .get = hw_break_get, | ||
| 587 | .set = hw_break_set, | ||
| 588 | }, | ||
| 589 | [REGSET_HW_WATCH] = { | ||
| 590 | .core_note_type = NT_ARM_HW_WATCH, | ||
| 591 | .n = sizeof(struct user_hwdebug_state) / sizeof(u32), | ||
| 592 | .size = sizeof(u32), | ||
| 593 | .align = sizeof(u32), | ||
| 594 | .get = hw_break_get, | ||
| 595 | .set = hw_break_set, | ||
| 596 | }, | ||
| 597 | #endif | ||
| 598 | }; | ||
| 599 | |||
| 600 | static const struct user_regset_view user_aarch64_view = { | ||
| 601 | .name = "aarch64", .e_machine = EM_AARCH64, | ||
| 602 | .regsets = aarch64_regsets, .n = ARRAY_SIZE(aarch64_regsets) | ||
| 603 | }; | ||
| 604 | |||
| 605 | #ifdef CONFIG_COMPAT | ||
| 606 | #include <linux/compat.h> | ||
| 607 | |||
| 608 | enum compat_regset { | ||
| 609 | REGSET_COMPAT_GPR, | ||
| 610 | REGSET_COMPAT_VFP, | ||
| 611 | }; | ||
| 612 | |||
| 613 | static int compat_gpr_get(struct task_struct *target, | ||
| 614 | const struct user_regset *regset, | ||
| 615 | unsigned int pos, unsigned int count, | ||
| 616 | void *kbuf, void __user *ubuf) | ||
| 617 | { | ||
| 618 | int ret = 0; | ||
| 619 | unsigned int i, start, num_regs; | ||
| 620 | |||
| 621 | /* Calculate the number of AArch32 registers contained in count */ | ||
| 622 | num_regs = count / regset->size; | ||
| 623 | |||
| 624 | /* Convert pos into an register number */ | ||
| 625 | start = pos / regset->size; | ||
| 626 | |||
| 627 | if (start + num_regs > regset->n) | ||
| 628 | return -EIO; | ||
| 629 | |||
| 630 | for (i = 0; i < num_regs; ++i) { | ||
| 631 | unsigned int idx = start + i; | ||
| 632 | void *reg; | ||
| 633 | |||
| 634 | switch (idx) { | ||
| 635 | case 15: | ||
| 636 | reg = (void *)&task_pt_regs(target)->pc; | ||
| 637 | break; | ||
| 638 | case 16: | ||
| 639 | reg = (void *)&task_pt_regs(target)->pstate; | ||
| 640 | break; | ||
| 641 | case 17: | ||
| 642 | reg = (void *)&task_pt_regs(target)->orig_x0; | ||
| 643 | break; | ||
| 644 | default: | ||
| 645 | reg = (void *)&task_pt_regs(target)->regs[idx]; | ||
| 646 | } | ||
| 647 | |||
| 648 | ret = copy_to_user(ubuf, reg, sizeof(compat_ulong_t)); | ||
| 649 | |||
| 650 | if (ret) | ||
| 651 | break; | ||
| 652 | else | ||
| 653 | ubuf += sizeof(compat_ulong_t); | ||
| 654 | } | ||
| 655 | |||
| 656 | return ret; | ||
| 657 | } | ||
| 658 | |||
| 659 | static int compat_gpr_set(struct task_struct *target, | ||
| 660 | const struct user_regset *regset, | ||
| 661 | unsigned int pos, unsigned int count, | ||
| 662 | const void *kbuf, const void __user *ubuf) | ||
| 663 | { | ||
| 664 | struct pt_regs newregs; | ||
| 665 | int ret = 0; | ||
| 666 | unsigned int i, start, num_regs; | ||
| 667 | |||
| 668 | /* Calculate the number of AArch32 registers contained in count */ | ||
| 669 | num_regs = count / regset->size; | ||
| 670 | |||
| 671 | /* Convert pos into an register number */ | ||
| 672 | start = pos / regset->size; | ||
| 673 | |||
| 674 | if (start + num_regs > regset->n) | ||
| 675 | return -EIO; | ||
| 676 | |||
| 677 | newregs = *task_pt_regs(target); | ||
| 678 | |||
| 679 | for (i = 0; i < num_regs; ++i) { | ||
| 680 | unsigned int idx = start + i; | ||
| 681 | void *reg; | ||
| 682 | |||
| 683 | switch (idx) { | ||
| 684 | case 15: | ||
| 685 | reg = (void *)&newregs.pc; | ||
| 686 | break; | ||
| 687 | case 16: | ||
| 688 | reg = (void *)&newregs.pstate; | ||
| 689 | break; | ||
| 690 | case 17: | ||
| 691 | reg = (void *)&newregs.orig_x0; | ||
| 692 | break; | ||
| 693 | default: | ||
| 694 | reg = (void *)&newregs.regs[idx]; | ||
| 695 | } | ||
| 696 | |||
| 697 | ret = copy_from_user(reg, ubuf, sizeof(compat_ulong_t)); | ||
| 698 | |||
| 699 | if (ret) | ||
| 700 | goto out; | ||
| 701 | else | ||
| 702 | ubuf += sizeof(compat_ulong_t); | ||
| 703 | } | ||
| 704 | |||
| 705 | if (valid_user_regs(&newregs.user_regs)) | ||
| 706 | *task_pt_regs(target) = newregs; | ||
| 707 | else | ||
| 708 | ret = -EINVAL; | ||
| 709 | |||
| 710 | out: | ||
| 711 | return ret; | ||
| 712 | } | ||
| 713 | |||
| 714 | static int compat_vfp_get(struct task_struct *target, | ||
| 715 | const struct user_regset *regset, | ||
| 716 | unsigned int pos, unsigned int count, | ||
| 717 | void *kbuf, void __user *ubuf) | ||
| 718 | { | ||
| 719 | struct user_fpsimd_state *uregs; | ||
| 720 | compat_ulong_t fpscr; | ||
| 721 | int ret; | ||
| 722 | |||
| 723 | uregs = &target->thread.fpsimd_state.user_fpsimd; | ||
| 724 | |||
| 725 | /* | ||
| 726 | * The VFP registers are packed into the fpsimd_state, so they all sit | ||
| 727 | * nicely together for us. We just need to create the fpscr separately. | ||
| 728 | */ | ||
| 729 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, | ||
| 730 | VFP_STATE_SIZE - sizeof(compat_ulong_t)); | ||
| 731 | |||
| 732 | if (count && !ret) { | ||
| 733 | fpscr = (uregs->fpsr & VFP_FPSCR_STAT_MASK) | | ||
| 734 | (uregs->fpcr & VFP_FPSCR_CTRL_MASK); | ||
| 735 | ret = put_user(fpscr, (compat_ulong_t *)ubuf); | ||
| 736 | } | ||
| 737 | |||
| 738 | return ret; | ||
| 739 | } | ||
| 740 | |||
| 741 | static int compat_vfp_set(struct task_struct *target, | ||
| 742 | const struct user_regset *regset, | ||
| 743 | unsigned int pos, unsigned int count, | ||
| 744 | const void *kbuf, const void __user *ubuf) | ||
| 745 | { | ||
| 746 | struct user_fpsimd_state *uregs; | ||
| 747 | compat_ulong_t fpscr; | ||
| 748 | int ret; | ||
| 749 | |||
| 750 | if (pos + count > VFP_STATE_SIZE) | ||
| 751 | return -EIO; | ||
| 752 | |||
| 753 | uregs = &target->thread.fpsimd_state.user_fpsimd; | ||
| 754 | |||
| 755 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, uregs, 0, | ||
| 756 | VFP_STATE_SIZE - sizeof(compat_ulong_t)); | ||
| 757 | |||
| 758 | if (count && !ret) { | ||
| 759 | ret = get_user(fpscr, (compat_ulong_t *)ubuf); | ||
| 760 | uregs->fpsr = fpscr & VFP_FPSCR_STAT_MASK; | ||
| 761 | uregs->fpcr = fpscr & VFP_FPSCR_CTRL_MASK; | ||
| 762 | } | ||
| 763 | |||
| 764 | return ret; | ||
| 765 | } | ||
| 766 | |||
| 767 | static const struct user_regset aarch32_regsets[] = { | ||
| 768 | [REGSET_COMPAT_GPR] = { | ||
| 769 | .core_note_type = NT_PRSTATUS, | ||
| 770 | .n = COMPAT_ELF_NGREG, | ||
| 771 | .size = sizeof(compat_elf_greg_t), | ||
| 772 | .align = sizeof(compat_elf_greg_t), | ||
| 773 | .get = compat_gpr_get, | ||
| 774 | .set = compat_gpr_set | ||
| 775 | }, | ||
| 776 | [REGSET_COMPAT_VFP] = { | ||
| 777 | .core_note_type = NT_ARM_VFP, | ||
| 778 | .n = VFP_STATE_SIZE / sizeof(compat_ulong_t), | ||
| 779 | .size = sizeof(compat_ulong_t), | ||
| 780 | .align = sizeof(compat_ulong_t), | ||
| 781 | .get = compat_vfp_get, | ||
| 782 | .set = compat_vfp_set | ||
| 783 | }, | ||
| 784 | }; | ||
| 785 | |||
| 786 | static const struct user_regset_view user_aarch32_view = { | ||
| 787 | .name = "aarch32", .e_machine = EM_ARM, | ||
| 788 | .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets) | ||
| 789 | }; | ||
| 790 | |||
| 791 | int aarch32_break_trap(struct pt_regs *regs) | ||
| 792 | { | ||
| 793 | unsigned int instr; | ||
| 794 | bool bp = false; | ||
| 795 | void __user *pc = (void __user *)instruction_pointer(regs); | ||
| 796 | |||
| 797 | if (compat_thumb_mode(regs)) { | ||
| 798 | /* get 16-bit Thumb instruction */ | ||
| 799 | get_user(instr, (u16 __user *)pc); | ||
| 800 | if (instr == AARCH32_BREAK_THUMB2_LO) { | ||
| 801 | /* get second half of 32-bit Thumb-2 instruction */ | ||
| 802 | get_user(instr, (u16 __user *)(pc + 2)); | ||
| 803 | bp = instr == AARCH32_BREAK_THUMB2_HI; | ||
| 804 | } else { | ||
| 805 | bp = instr == AARCH32_BREAK_THUMB; | ||
| 806 | } | ||
| 807 | } else { | ||
| 808 | /* 32-bit ARM instruction */ | ||
| 809 | get_user(instr, (u32 __user *)pc); | ||
| 810 | bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM; | ||
| 811 | } | ||
| 812 | |||
| 813 | if (bp) | ||
| 814 | return ptrace_break(regs); | ||
| 815 | return 1; | ||
| 816 | } | ||
| 817 | |||
| 818 | static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, | ||
| 819 | compat_ulong_t __user *ret) | ||
| 820 | { | ||
| 821 | compat_ulong_t tmp; | ||
| 822 | |||
| 823 | if (off & 3) | ||
| 824 | return -EIO; | ||
| 825 | |||
| 826 | if (off == PT_TEXT_ADDR) | ||
| 827 | tmp = tsk->mm->start_code; | ||
| 828 | else if (off == PT_DATA_ADDR) | ||
| 829 | tmp = tsk->mm->start_data; | ||
| 830 | else if (off == PT_TEXT_END_ADDR) | ||
| 831 | tmp = tsk->mm->end_code; | ||
| 832 | else if (off < sizeof(compat_elf_gregset_t)) | ||
| 833 | return copy_regset_to_user(tsk, &user_aarch32_view, | ||
| 834 | REGSET_COMPAT_GPR, off, | ||
| 835 | sizeof(compat_ulong_t), ret); | ||
| 836 | else if (off >= COMPAT_USER_SZ) | ||
| 837 | return -EIO; | ||
| 838 | else | ||
| 839 | tmp = 0; | ||
| 840 | |||
| 841 | return put_user(tmp, ret); | ||
| 842 | } | ||
| 843 | |||
| 844 | static int compat_ptrace_write_user(struct task_struct *tsk, compat_ulong_t off, | ||
| 845 | compat_ulong_t val) | ||
| 846 | { | ||
| 847 | int ret; | ||
| 848 | |||
| 849 | if (off & 3 || off >= COMPAT_USER_SZ) | ||
| 850 | return -EIO; | ||
| 851 | |||
| 852 | if (off >= sizeof(compat_elf_gregset_t)) | ||
| 853 | return 0; | ||
| 854 | |||
| 855 | ret = copy_regset_from_user(tsk, &user_aarch32_view, | ||
| 856 | REGSET_COMPAT_GPR, off, | ||
| 857 | sizeof(compat_ulong_t), | ||
| 858 | &val); | ||
| 859 | return ret; | ||
| 860 | } | ||
| 861 | |||
| 862 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 863 | |||
| 864 | /* | ||
| 865 | * Convert a virtual register number into an index for a thread_info | ||
| 866 | * breakpoint array. Breakpoints are identified using positive numbers | ||
| 867 | * whilst watchpoints are negative. The registers are laid out as pairs | ||
| 868 | * of (address, control), each pair mapping to a unique hw_breakpoint struct. | ||
| 869 | * Register 0 is reserved for describing resource information. | ||
| 870 | */ | ||
| 871 | static int compat_ptrace_hbp_num_to_idx(compat_long_t num) | ||
| 872 | { | ||
| 873 | return (abs(num) - 1) >> 1; | ||
| 874 | } | ||
| 875 | |||
| 876 | static int compat_ptrace_hbp_get_resource_info(u32 *kdata) | ||
| 877 | { | ||
| 878 | u8 num_brps, num_wrps, debug_arch, wp_len; | ||
| 879 | u32 reg = 0; | ||
| 880 | |||
| 881 | num_brps = hw_breakpoint_slots(TYPE_INST); | ||
| 882 | num_wrps = hw_breakpoint_slots(TYPE_DATA); | ||
| 883 | |||
| 884 | debug_arch = debug_monitors_arch(); | ||
| 885 | wp_len = 8; | ||
| 886 | reg |= debug_arch; | ||
| 887 | reg <<= 8; | ||
| 888 | reg |= wp_len; | ||
| 889 | reg <<= 8; | ||
| 890 | reg |= num_wrps; | ||
| 891 | reg <<= 8; | ||
| 892 | reg |= num_brps; | ||
| 893 | |||
| 894 | *kdata = reg; | ||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | |||
| 898 | static int compat_ptrace_hbp_get(unsigned int note_type, | ||
| 899 | struct task_struct *tsk, | ||
| 900 | compat_long_t num, | ||
| 901 | u32 *kdata) | ||
| 902 | { | ||
| 903 | u64 addr = 0; | ||
| 904 | u32 ctrl = 0; | ||
| 905 | |||
| 906 | int err, idx = compat_ptrace_hbp_num_to_idx(num);; | ||
| 907 | |||
| 908 | if (num & 1) { | ||
| 909 | err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr); | ||
| 910 | *kdata = (u32)addr; | ||
| 911 | } else { | ||
| 912 | err = ptrace_hbp_get_ctrl(note_type, tsk, idx, &ctrl); | ||
| 913 | *kdata = ctrl; | ||
| 914 | } | ||
| 915 | |||
| 916 | return err; | ||
| 917 | } | ||
| 918 | |||
| 919 | static int compat_ptrace_hbp_set(unsigned int note_type, | ||
| 920 | struct task_struct *tsk, | ||
| 921 | compat_long_t num, | ||
| 922 | u32 *kdata) | ||
| 923 | { | ||
| 924 | u64 addr; | ||
| 925 | u32 ctrl; | ||
| 926 | |||
| 927 | int err, idx = compat_ptrace_hbp_num_to_idx(num); | ||
| 928 | |||
| 929 | if (num & 1) { | ||
| 930 | addr = *kdata; | ||
| 931 | err = ptrace_hbp_set_addr(note_type, tsk, idx, addr); | ||
| 932 | } else { | ||
| 933 | ctrl = *kdata; | ||
| 934 | err = ptrace_hbp_set_ctrl(note_type, tsk, idx, ctrl); | ||
| 935 | } | ||
| 936 | |||
| 937 | return err; | ||
| 938 | } | ||
| 939 | |||
| 940 | static int compat_ptrace_gethbpregs(struct task_struct *tsk, compat_long_t num, | ||
| 941 | compat_ulong_t __user *data) | ||
| 942 | { | ||
| 943 | int ret; | ||
| 944 | u32 kdata; | ||
| 945 | mm_segment_t old_fs = get_fs(); | ||
| 946 | |||
| 947 | set_fs(KERNEL_DS); | ||
| 948 | /* Watchpoint */ | ||
| 949 | if (num < 0) { | ||
| 950 | ret = compat_ptrace_hbp_get(NT_ARM_HW_WATCH, tsk, num, &kdata); | ||
| 951 | /* Resource info */ | ||
| 952 | } else if (num == 0) { | ||
| 953 | ret = compat_ptrace_hbp_get_resource_info(&kdata); | ||
| 954 | /* Breakpoint */ | ||
| 955 | } else { | ||
| 956 | ret = compat_ptrace_hbp_get(NT_ARM_HW_BREAK, tsk, num, &kdata); | ||
| 957 | } | ||
| 958 | set_fs(old_fs); | ||
| 959 | |||
| 960 | if (!ret) | ||
| 961 | ret = put_user(kdata, data); | ||
| 962 | |||
| 963 | return ret; | ||
| 964 | } | ||
| 965 | |||
| 966 | static int compat_ptrace_sethbpregs(struct task_struct *tsk, compat_long_t num, | ||
| 967 | compat_ulong_t __user *data) | ||
| 968 | { | ||
| 969 | int ret; | ||
| 970 | u32 kdata = 0; | ||
| 971 | mm_segment_t old_fs = get_fs(); | ||
| 972 | |||
| 973 | if (num == 0) | ||
| 974 | return 0; | ||
| 975 | |||
| 976 | ret = get_user(kdata, data); | ||
| 977 | if (ret) | ||
| 978 | return ret; | ||
| 979 | |||
| 980 | set_fs(KERNEL_DS); | ||
| 981 | if (num < 0) | ||
| 982 | ret = compat_ptrace_hbp_set(NT_ARM_HW_WATCH, tsk, num, &kdata); | ||
| 983 | else | ||
| 984 | ret = compat_ptrace_hbp_set(NT_ARM_HW_BREAK, tsk, num, &kdata); | ||
| 985 | set_fs(old_fs); | ||
| 986 | |||
| 987 | return ret; | ||
| 988 | } | ||
| 989 | #endif /* CONFIG_HAVE_HW_BREAKPOINT */ | ||
| 990 | |||
| 991 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | ||
| 992 | compat_ulong_t caddr, compat_ulong_t cdata) | ||
| 993 | { | ||
| 994 | unsigned long addr = caddr; | ||
| 995 | unsigned long data = cdata; | ||
| 996 | void __user *datap = compat_ptr(data); | ||
| 997 | int ret; | ||
| 998 | |||
| 999 | switch (request) { | ||
| 1000 | case PTRACE_PEEKUSR: | ||
| 1001 | ret = compat_ptrace_read_user(child, addr, datap); | ||
| 1002 | break; | ||
| 1003 | |||
| 1004 | case PTRACE_POKEUSR: | ||
| 1005 | ret = compat_ptrace_write_user(child, addr, data); | ||
| 1006 | break; | ||
| 1007 | |||
| 1008 | case COMPAT_PTRACE_GETREGS: | ||
| 1009 | ret = copy_regset_to_user(child, | ||
| 1010 | &user_aarch32_view, | ||
| 1011 | REGSET_COMPAT_GPR, | ||
| 1012 | 0, sizeof(compat_elf_gregset_t), | ||
| 1013 | datap); | ||
| 1014 | break; | ||
| 1015 | |||
| 1016 | case COMPAT_PTRACE_SETREGS: | ||
| 1017 | ret = copy_regset_from_user(child, | ||
| 1018 | &user_aarch32_view, | ||
| 1019 | REGSET_COMPAT_GPR, | ||
| 1020 | 0, sizeof(compat_elf_gregset_t), | ||
| 1021 | datap); | ||
| 1022 | break; | ||
| 1023 | |||
| 1024 | case COMPAT_PTRACE_GET_THREAD_AREA: | ||
| 1025 | ret = put_user((compat_ulong_t)child->thread.tp_value, | ||
| 1026 | (compat_ulong_t __user *)datap); | ||
| 1027 | break; | ||
| 1028 | |||
| 1029 | case COMPAT_PTRACE_SET_SYSCALL: | ||
| 1030 | task_pt_regs(child)->syscallno = data; | ||
| 1031 | ret = 0; | ||
| 1032 | break; | ||
| 1033 | |||
| 1034 | case COMPAT_PTRACE_GETVFPREGS: | ||
| 1035 | ret = copy_regset_to_user(child, | ||
| 1036 | &user_aarch32_view, | ||
| 1037 | REGSET_COMPAT_VFP, | ||
| 1038 | 0, VFP_STATE_SIZE, | ||
| 1039 | datap); | ||
| 1040 | break; | ||
| 1041 | |||
| 1042 | case COMPAT_PTRACE_SETVFPREGS: | ||
| 1043 | ret = copy_regset_from_user(child, | ||
| 1044 | &user_aarch32_view, | ||
| 1045 | REGSET_COMPAT_VFP, | ||
| 1046 | 0, VFP_STATE_SIZE, | ||
| 1047 | datap); | ||
| 1048 | break; | ||
| 1049 | |||
| 1050 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | ||
| 1051 | case COMPAT_PTRACE_GETHBPREGS: | ||
| 1052 | ret = compat_ptrace_gethbpregs(child, addr, datap); | ||
| 1053 | break; | ||
| 1054 | |||
| 1055 | case COMPAT_PTRACE_SETHBPREGS: | ||
| 1056 | ret = compat_ptrace_sethbpregs(child, addr, datap); | ||
| 1057 | break; | ||
| 1058 | #endif | ||
| 1059 | |||
| 1060 | default: | ||
| 1061 | ret = compat_ptrace_request(child, request, addr, | ||
| 1062 | data); | ||
| 1063 | break; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | return ret; | ||
| 1067 | } | ||
| 1068 | #endif /* CONFIG_COMPAT */ | ||
| 1069 | |||
| 1070 | const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
| 1071 | { | ||
| 1072 | #ifdef CONFIG_COMPAT | ||
| 1073 | if (is_compat_thread(task_thread_info(task))) | ||
| 1074 | return &user_aarch32_view; | ||
| 1075 | #endif | ||
| 1076 | return &user_aarch64_view; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | long arch_ptrace(struct task_struct *child, long request, | ||
| 1080 | unsigned long addr, unsigned long data) | ||
| 1081 | { | ||
| 1082 | return ptrace_request(child, request, addr, data); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | |||
| 1086 | static int __init ptrace_break_init(void) | ||
| 1087 | { | ||
| 1088 | hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP, | ||
| 1089 | TRAP_BRKPT, "ptrace BRK handler"); | ||
| 1090 | return 0; | ||
| 1091 | } | ||
| 1092 | core_initcall(ptrace_break_init); | ||
| 1093 | |||
| 1094 | |||
| 1095 | asmlinkage int syscall_trace(int dir, struct pt_regs *regs) | ||
| 1096 | { | ||
| 1097 | unsigned long saved_reg; | ||
| 1098 | |||
| 1099 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
| 1100 | return regs->syscallno; | ||
| 1101 | |||
| 1102 | if (is_compat_task()) { | ||
| 1103 | /* AArch32 uses ip (r12) for scratch */ | ||
| 1104 | saved_reg = regs->regs[12]; | ||
| 1105 | regs->regs[12] = dir; | ||
| 1106 | } else { | ||
| 1107 | /* | ||
| 1108 | * Save X7. X7 is used to denote syscall entry/exit: | ||
| 1109 | * X7 = 0 -> entry, = 1 -> exit | ||
| 1110 | */ | ||
| 1111 | saved_reg = regs->regs[7]; | ||
| 1112 | regs->regs[7] = dir; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | if (dir) | ||
| 1116 | tracehook_report_syscall_exit(regs, 0); | ||
| 1117 | else if (tracehook_report_syscall_entry(regs)) | ||
| 1118 | regs->syscallno = ~0UL; | ||
| 1119 | |||
| 1120 | if (is_compat_task()) | ||
| 1121 | regs->regs[12] = saved_reg; | ||
| 1122 | else | ||
| 1123 | regs->regs[7] = saved_reg; | ||
| 1124 | |||
| 1125 | return regs->syscallno; | ||
| 1126 | } | ||
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c new file mode 100644 index 000000000000..48ffb9fb3fe3 --- /dev/null +++ b/arch/arm64/kernel/setup.c | |||
| @@ -0,0 +1,347 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/setup.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2001 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/export.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/stddef.h> | ||
| 23 | #include <linux/ioport.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/utsname.h> | ||
| 26 | #include <linux/initrd.h> | ||
| 27 | #include <linux/console.h> | ||
| 28 | #include <linux/bootmem.h> | ||
| 29 | #include <linux/seq_file.h> | ||
| 30 | #include <linux/screen_info.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/kexec.h> | ||
| 33 | #include <linux/crash_dump.h> | ||
| 34 | #include <linux/root_dev.h> | ||
| 35 | #include <linux/cpu.h> | ||
| 36 | #include <linux/interrupt.h> | ||
| 37 | #include <linux/smp.h> | ||
| 38 | #include <linux/fs.h> | ||
| 39 | #include <linux/proc_fs.h> | ||
| 40 | #include <linux/memblock.h> | ||
| 41 | #include <linux/of_fdt.h> | ||
| 42 | |||
| 43 | #include <asm/cputype.h> | ||
| 44 | #include <asm/elf.h> | ||
| 45 | #include <asm/cputable.h> | ||
| 46 | #include <asm/sections.h> | ||
| 47 | #include <asm/setup.h> | ||
| 48 | #include <asm/cacheflush.h> | ||
| 49 | #include <asm/tlbflush.h> | ||
| 50 | #include <asm/traps.h> | ||
| 51 | #include <asm/memblock.h> | ||
| 52 | |||
| 53 | unsigned int processor_id; | ||
| 54 | EXPORT_SYMBOL(processor_id); | ||
| 55 | |||
| 56 | unsigned int elf_hwcap __read_mostly; | ||
| 57 | EXPORT_SYMBOL_GPL(elf_hwcap); | ||
| 58 | |||
| 59 | static const char *cpu_name; | ||
| 60 | static const char *machine_name; | ||
| 61 | phys_addr_t __fdt_pointer __initdata; | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Standard memory resources | ||
| 65 | */ | ||
| 66 | static struct resource mem_res[] = { | ||
| 67 | { | ||
| 68 | .name = "Kernel code", | ||
| 69 | .start = 0, | ||
| 70 | .end = 0, | ||
| 71 | .flags = IORESOURCE_MEM | ||
| 72 | }, | ||
| 73 | { | ||
| 74 | .name = "Kernel data", | ||
| 75 | .start = 0, | ||
| 76 | .end = 0, | ||
| 77 | .flags = IORESOURCE_MEM | ||
| 78 | } | ||
| 79 | }; | ||
| 80 | |||
| 81 | #define kernel_code mem_res[0] | ||
| 82 | #define kernel_data mem_res[1] | ||
| 83 | |||
| 84 | void __init early_print(const char *str, ...) | ||
| 85 | { | ||
| 86 | char buf[256]; | ||
| 87 | va_list ap; | ||
| 88 | |||
| 89 | va_start(ap, str); | ||
| 90 | vsnprintf(buf, sizeof(buf), str, ap); | ||
| 91 | va_end(ap); | ||
| 92 | |||
| 93 | printk("%s", buf); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void __init setup_processor(void) | ||
| 97 | { | ||
| 98 | struct cpu_info *cpu_info; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * locate processor in the list of supported processor | ||
| 102 | * types. The linker builds this table for us from the | ||
| 103 | * entries in arch/arm/mm/proc.S | ||
| 104 | */ | ||
| 105 | cpu_info = lookup_processor_type(read_cpuid_id()); | ||
| 106 | if (!cpu_info) { | ||
| 107 | printk("CPU configuration botched (ID %08x), unable to continue.\n", | ||
| 108 | read_cpuid_id()); | ||
| 109 | while (1); | ||
| 110 | } | ||
| 111 | |||
| 112 | cpu_name = cpu_info->cpu_name; | ||
| 113 | |||
| 114 | printk("CPU: %s [%08x] revision %d\n", | ||
| 115 | cpu_name, read_cpuid_id(), read_cpuid_id() & 15); | ||
| 116 | |||
| 117 | sprintf(init_utsname()->machine, "aarch64"); | ||
| 118 | elf_hwcap = 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static void __init setup_machine_fdt(phys_addr_t dt_phys) | ||
| 122 | { | ||
| 123 | struct boot_param_header *devtree; | ||
| 124 | unsigned long dt_root; | ||
| 125 | |||
| 126 | /* Check we have a non-NULL DT pointer */ | ||
| 127 | if (!dt_phys) { | ||
| 128 | early_print("\n" | ||
| 129 | "Error: NULL or invalid device tree blob\n" | ||
| 130 | "The dtb must be 8-byte aligned and passed in the first 512MB of memory\n" | ||
| 131 | "\nPlease check your bootloader.\n"); | ||
| 132 | |||
| 133 | while (true) | ||
| 134 | cpu_relax(); | ||
| 135 | |||
| 136 | } | ||
| 137 | |||
| 138 | devtree = phys_to_virt(dt_phys); | ||
| 139 | |||
| 140 | /* Check device tree validity */ | ||
| 141 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) { | ||
| 142 | early_print("\n" | ||
| 143 | "Error: invalid device tree blob at physical address 0x%p (virtual address 0x%p)\n" | ||
| 144 | "Expected 0x%x, found 0x%x\n" | ||
| 145 | "\nPlease check your bootloader.\n", | ||
| 146 | dt_phys, devtree, OF_DT_HEADER, | ||
| 147 | be32_to_cpu(devtree->magic)); | ||
| 148 | |||
| 149 | while (true) | ||
| 150 | cpu_relax(); | ||
| 151 | } | ||
| 152 | |||
| 153 | initial_boot_params = devtree; | ||
| 154 | dt_root = of_get_flat_dt_root(); | ||
| 155 | |||
| 156 | machine_name = of_get_flat_dt_prop(dt_root, "model", NULL); | ||
| 157 | if (!machine_name) | ||
| 158 | machine_name = of_get_flat_dt_prop(dt_root, "compatible", NULL); | ||
| 159 | if (!machine_name) | ||
| 160 | machine_name = "<unknown>"; | ||
| 161 | pr_info("Machine: %s\n", machine_name); | ||
| 162 | |||
| 163 | /* Retrieve various information from the /chosen node */ | ||
| 164 | of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); | ||
| 165 | /* Initialize {size,address}-cells info */ | ||
| 166 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | ||
| 167 | /* Setup memory, calling early_init_dt_add_memory_arch */ | ||
| 168 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||
| 169 | } | ||
| 170 | |||
| 171 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | ||
| 172 | { | ||
| 173 | size &= PAGE_MASK; | ||
| 174 | memblock_add(base, size); | ||
| 175 | } | ||
| 176 | |||
| 177 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | ||
| 178 | { | ||
| 179 | return __va(memblock_alloc(size, align)); | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Limit the memory size that was specified via FDT. | ||
| 184 | */ | ||
| 185 | static int __init early_mem(char *p) | ||
| 186 | { | ||
| 187 | phys_addr_t limit; | ||
| 188 | |||
| 189 | if (!p) | ||
| 190 | return 1; | ||
| 191 | |||
| 192 | limit = memparse(p, &p) & PAGE_MASK; | ||
| 193 | pr_notice("Memory limited to %lldMB\n", limit >> 20); | ||
| 194 | |||
| 195 | memblock_enforce_memory_limit(limit); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | early_param("mem", early_mem); | ||
| 200 | |||
| 201 | static void __init request_standard_resources(void) | ||
| 202 | { | ||
| 203 | struct memblock_region *region; | ||
| 204 | struct resource *res; | ||
| 205 | |||
| 206 | kernel_code.start = virt_to_phys(_text); | ||
| 207 | kernel_code.end = virt_to_phys(_etext - 1); | ||
| 208 | kernel_data.start = virt_to_phys(_sdata); | ||
| 209 | kernel_data.end = virt_to_phys(_end - 1); | ||
| 210 | |||
| 211 | for_each_memblock(memory, region) { | ||
| 212 | res = alloc_bootmem_low(sizeof(*res)); | ||
| 213 | res->name = "System RAM"; | ||
| 214 | res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region)); | ||
| 215 | res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1; | ||
| 216 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
| 217 | |||
| 218 | request_resource(&iomem_resource, res); | ||
| 219 | |||
| 220 | if (kernel_code.start >= res->start && | ||
| 221 | kernel_code.end <= res->end) | ||
| 222 | request_resource(res, &kernel_code); | ||
| 223 | if (kernel_data.start >= res->start && | ||
| 224 | kernel_data.end <= res->end) | ||
| 225 | request_resource(res, &kernel_data); | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | void __init setup_arch(char **cmdline_p) | ||
| 230 | { | ||
| 231 | setup_processor(); | ||
| 232 | |||
| 233 | setup_machine_fdt(__fdt_pointer); | ||
| 234 | |||
| 235 | init_mm.start_code = (unsigned long) _text; | ||
| 236 | init_mm.end_code = (unsigned long) _etext; | ||
| 237 | init_mm.end_data = (unsigned long) _edata; | ||
| 238 | init_mm.brk = (unsigned long) _end; | ||
| 239 | |||
| 240 | *cmdline_p = boot_command_line; | ||
| 241 | |||
| 242 | parse_early_param(); | ||
| 243 | |||
| 244 | arm64_memblock_init(); | ||
| 245 | |||
| 246 | paging_init(); | ||
| 247 | request_standard_resources(); | ||
| 248 | |||
| 249 | unflatten_device_tree(); | ||
| 250 | |||
| 251 | #ifdef CONFIG_SMP | ||
| 252 | smp_init_cpus(); | ||
| 253 | #endif | ||
| 254 | |||
| 255 | #ifdef CONFIG_VT | ||
| 256 | #if defined(CONFIG_VGA_CONSOLE) | ||
| 257 | conswitchp = &vga_con; | ||
| 258 | #elif defined(CONFIG_DUMMY_CONSOLE) | ||
| 259 | conswitchp = &dummy_con; | ||
| 260 | #endif | ||
| 261 | #endif | ||
| 262 | } | ||
| 263 | |||
| 264 | static DEFINE_PER_CPU(struct cpu, cpu_data); | ||
| 265 | |||
| 266 | static int __init topology_init(void) | ||
| 267 | { | ||
| 268 | int i; | ||
| 269 | |||
| 270 | for_each_possible_cpu(i) { | ||
| 271 | struct cpu *cpu = &per_cpu(cpu_data, i); | ||
| 272 | cpu->hotpluggable = 1; | ||
| 273 | register_cpu(cpu, i); | ||
| 274 | } | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | subsys_initcall(topology_init); | ||
| 279 | |||
| 280 | static const char *hwcap_str[] = { | ||
| 281 | "fp", | ||
| 282 | "asimd", | ||
| 283 | NULL | ||
| 284 | }; | ||
| 285 | |||
| 286 | static int c_show(struct seq_file *m, void *v) | ||
| 287 | { | ||
| 288 | int i; | ||
| 289 | |||
| 290 | seq_printf(m, "Processor\t: %s rev %d (%s)\n", | ||
| 291 | cpu_name, read_cpuid_id() & 15, ELF_PLATFORM); | ||
| 292 | |||
| 293 | for_each_online_cpu(i) { | ||
| 294 | /* | ||
| 295 | * glibc reads /proc/cpuinfo to determine the number of | ||
| 296 | * online processors, looking for lines beginning with | ||
| 297 | * "processor". Give glibc what it expects. | ||
| 298 | */ | ||
| 299 | #ifdef CONFIG_SMP | ||
| 300 | seq_printf(m, "processor\t: %d\n", i); | ||
| 301 | #endif | ||
| 302 | seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", | ||
| 303 | loops_per_jiffy / (500000UL/HZ), | ||
| 304 | loops_per_jiffy / (5000UL/HZ) % 100); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* dump out the processor features */ | ||
| 308 | seq_puts(m, "Features\t: "); | ||
| 309 | |||
| 310 | for (i = 0; hwcap_str[i]; i++) | ||
| 311 | if (elf_hwcap & (1 << i)) | ||
| 312 | seq_printf(m, "%s ", hwcap_str[i]); | ||
| 313 | |||
| 314 | seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24); | ||
| 315 | seq_printf(m, "CPU architecture: AArch64\n"); | ||
| 316 | seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15); | ||
| 317 | seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff); | ||
| 318 | seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15); | ||
| 319 | |||
| 320 | seq_puts(m, "\n"); | ||
| 321 | |||
| 322 | seq_printf(m, "Hardware\t: %s\n", machine_name); | ||
| 323 | |||
| 324 | return 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
| 328 | { | ||
| 329 | return *pos < 1 ? (void *)1 : NULL; | ||
| 330 | } | ||
| 331 | |||
| 332 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 333 | { | ||
| 334 | ++*pos; | ||
| 335 | return NULL; | ||
| 336 | } | ||
| 337 | |||
| 338 | static void c_stop(struct seq_file *m, void *v) | ||
| 339 | { | ||
| 340 | } | ||
| 341 | |||
| 342 | const struct seq_operations cpuinfo_op = { | ||
| 343 | .start = c_start, | ||
| 344 | .next = c_next, | ||
| 345 | .stop = c_stop, | ||
| 346 | .show = c_show | ||
| 347 | }; | ||
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c new file mode 100644 index 000000000000..8807ba2cf262 --- /dev/null +++ b/arch/arm64/kernel/signal.c | |||
| @@ -0,0 +1,437 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/signal.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2009 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/errno.h> | ||
| 21 | #include <linux/signal.h> | ||
| 22 | #include <linux/personality.h> | ||
| 23 | #include <linux/freezer.h> | ||
| 24 | #include <linux/uaccess.h> | ||
| 25 | #include <linux/tracehook.h> | ||
| 26 | #include <linux/ratelimit.h> | ||
| 27 | |||
| 28 | #include <asm/compat.h> | ||
| 29 | #include <asm/debug-monitors.h> | ||
| 30 | #include <asm/elf.h> | ||
| 31 | #include <asm/cacheflush.h> | ||
| 32 | #include <asm/ucontext.h> | ||
| 33 | #include <asm/unistd.h> | ||
| 34 | #include <asm/fpsimd.h> | ||
| 35 | #include <asm/signal32.h> | ||
| 36 | #include <asm/vdso.h> | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Do a signal return; undo the signal stack. These are aligned to 128-bit. | ||
| 40 | */ | ||
| 41 | struct rt_sigframe { | ||
| 42 | struct siginfo info; | ||
| 43 | struct ucontext uc; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) | ||
| 47 | { | ||
| 48 | struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; | ||
| 49 | int err; | ||
| 50 | |||
| 51 | /* dump the hardware registers to the fpsimd_state structure */ | ||
| 52 | fpsimd_save_state(fpsimd); | ||
| 53 | |||
| 54 | /* copy the FP and status/control registers */ | ||
| 55 | err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs)); | ||
| 56 | __put_user_error(fpsimd->fpsr, &ctx->fpsr, err); | ||
| 57 | __put_user_error(fpsimd->fpcr, &ctx->fpcr, err); | ||
| 58 | |||
| 59 | /* copy the magic/size information */ | ||
| 60 | __put_user_error(FPSIMD_MAGIC, &ctx->head.magic, err); | ||
| 61 | __put_user_error(sizeof(struct fpsimd_context), &ctx->head.size, err); | ||
| 62 | |||
| 63 | return err ? -EFAULT : 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int restore_fpsimd_context(struct fpsimd_context __user *ctx) | ||
| 67 | { | ||
| 68 | struct fpsimd_state fpsimd; | ||
| 69 | __u32 magic, size; | ||
| 70 | int err = 0; | ||
| 71 | |||
| 72 | /* check the magic/size information */ | ||
| 73 | __get_user_error(magic, &ctx->head.magic, err); | ||
| 74 | __get_user_error(size, &ctx->head.size, err); | ||
| 75 | if (err) | ||
| 76 | return -EFAULT; | ||
| 77 | if (magic != FPSIMD_MAGIC || size != sizeof(struct fpsimd_context)) | ||
| 78 | return -EINVAL; | ||
| 79 | |||
| 80 | /* copy the FP and status/control registers */ | ||
| 81 | err = __copy_from_user(fpsimd.vregs, ctx->vregs, | ||
| 82 | sizeof(fpsimd.vregs)); | ||
| 83 | __get_user_error(fpsimd.fpsr, &ctx->fpsr, err); | ||
| 84 | __get_user_error(fpsimd.fpcr, &ctx->fpcr, err); | ||
| 85 | |||
| 86 | /* load the hardware registers from the fpsimd_state structure */ | ||
| 87 | if (!err) { | ||
| 88 | preempt_disable(); | ||
| 89 | fpsimd_load_state(&fpsimd); | ||
| 90 | preempt_enable(); | ||
| 91 | } | ||
| 92 | |||
| 93 | return err ? -EFAULT : 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int restore_sigframe(struct pt_regs *regs, | ||
| 97 | struct rt_sigframe __user *sf) | ||
| 98 | { | ||
| 99 | sigset_t set; | ||
| 100 | int i, err; | ||
| 101 | struct aux_context __user *aux = | ||
| 102 | (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; | ||
| 103 | |||
| 104 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); | ||
| 105 | if (err == 0) | ||
| 106 | set_current_blocked(&set); | ||
| 107 | |||
| 108 | for (i = 0; i < 31; i++) | ||
| 109 | __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], | ||
| 110 | err); | ||
| 111 | __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); | ||
| 112 | __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); | ||
| 113 | __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err); | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Avoid sys_rt_sigreturn() restarting. | ||
| 117 | */ | ||
| 118 | regs->syscallno = ~0UL; | ||
| 119 | |||
| 120 | err |= !valid_user_regs(®s->user_regs); | ||
| 121 | |||
| 122 | if (err == 0) | ||
| 123 | err |= restore_fpsimd_context(&aux->fpsimd); | ||
| 124 | |||
| 125 | return err; | ||
| 126 | } | ||
| 127 | |||
| 128 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | ||
| 129 | { | ||
| 130 | struct rt_sigframe __user *frame; | ||
| 131 | |||
| 132 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 133 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Since we stacked the signal on a 128-bit boundary, then 'sp' should | ||
| 137 | * be word aligned here. | ||
| 138 | */ | ||
| 139 | if (regs->sp & 15) | ||
| 140 | goto badframe; | ||
| 141 | |||
| 142 | frame = (struct rt_sigframe __user *)regs->sp; | ||
| 143 | |||
| 144 | if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) | ||
| 145 | goto badframe; | ||
| 146 | |||
| 147 | if (restore_sigframe(regs, frame)) | ||
| 148 | goto badframe; | ||
| 149 | |||
| 150 | if (do_sigaltstack(&frame->uc.uc_stack, | ||
| 151 | NULL, regs->sp) == -EFAULT) | ||
| 152 | goto badframe; | ||
| 153 | |||
| 154 | return regs->regs[0]; | ||
| 155 | |||
| 156 | badframe: | ||
| 157 | if (show_unhandled_signals) | ||
| 158 | pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n", | ||
| 159 | current->comm, task_pid_nr(current), __func__, | ||
| 160 | regs->pc, regs->sp); | ||
| 161 | force_sig(SIGSEGV, current); | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | ||
| 166 | unsigned long sp) | ||
| 167 | { | ||
| 168 | return do_sigaltstack(uss, uoss, sp); | ||
| 169 | } | ||
| 170 | |||
| 171 | static int setup_sigframe(struct rt_sigframe __user *sf, | ||
| 172 | struct pt_regs *regs, sigset_t *set) | ||
| 173 | { | ||
| 174 | int i, err = 0; | ||
| 175 | struct aux_context __user *aux = | ||
| 176 | (struct aux_context __user *)sf->uc.uc_mcontext.__reserved; | ||
| 177 | |||
| 178 | for (i = 0; i < 31; i++) | ||
| 179 | __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], | ||
| 180 | err); | ||
| 181 | __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); | ||
| 182 | __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); | ||
| 183 | __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err); | ||
| 184 | |||
| 185 | __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err); | ||
| 186 | |||
| 187 | err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); | ||
| 188 | |||
| 189 | if (err == 0) | ||
| 190 | err |= preserve_fpsimd_context(&aux->fpsimd); | ||
| 191 | |||
| 192 | /* set the "end" magic */ | ||
| 193 | __put_user_error(0, &aux->end.magic, err); | ||
| 194 | __put_user_error(0, &aux->end.size, err); | ||
| 195 | |||
| 196 | return err; | ||
| 197 | } | ||
| 198 | |||
| 199 | static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
| 200 | int framesize) | ||
| 201 | { | ||
| 202 | unsigned long sp, sp_top; | ||
| 203 | void __user *frame; | ||
| 204 | |||
| 205 | sp = sp_top = regs->sp; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * This is the X/Open sanctioned signal stack switching. | ||
| 209 | */ | ||
| 210 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | ||
| 211 | sp = sp_top = current->sas_ss_sp + current->sas_ss_size; | ||
| 212 | |||
| 213 | /* room for stack frame (FP, LR) */ | ||
| 214 | sp -= 16; | ||
| 215 | |||
| 216 | sp = (sp - framesize) & ~15; | ||
| 217 | frame = (void __user *)sp; | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Check that we can actually write to the signal frame. | ||
| 221 | */ | ||
| 222 | if (!access_ok(VERIFY_WRITE, frame, sp_top - sp)) | ||
| 223 | frame = NULL; | ||
| 224 | |||
| 225 | return frame; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, | ||
| 229 | void __user *frame, int usig) | ||
| 230 | { | ||
| 231 | int err = 0; | ||
| 232 | __sigrestore_t sigtramp; | ||
| 233 | unsigned long __user *sp = (unsigned long __user *)regs->sp; | ||
| 234 | |||
| 235 | /* set up the stack frame */ | ||
| 236 | __put_user_error(regs->regs[29], sp - 2, err); | ||
| 237 | __put_user_error(regs->regs[30], sp - 1, err); | ||
| 238 | |||
| 239 | regs->regs[0] = usig; | ||
| 240 | regs->regs[29] = regs->sp - 16; | ||
| 241 | regs->sp = (unsigned long)frame; | ||
| 242 | regs->pc = (unsigned long)ka->sa.sa_handler; | ||
| 243 | |||
| 244 | if (ka->sa.sa_flags & SA_RESTORER) | ||
| 245 | sigtramp = ka->sa.sa_restorer; | ||
| 246 | else | ||
| 247 | sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp); | ||
| 248 | |||
| 249 | regs->regs[30] = (unsigned long)sigtramp; | ||
| 250 | |||
| 251 | return err; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | ||
| 255 | sigset_t *set, struct pt_regs *regs) | ||
| 256 | { | ||
| 257 | struct rt_sigframe __user *frame; | ||
| 258 | stack_t stack; | ||
| 259 | int err = 0; | ||
| 260 | |||
| 261 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
| 262 | if (!frame) | ||
| 263 | return 1; | ||
| 264 | |||
| 265 | __put_user_error(0, &frame->uc.uc_flags, err); | ||
| 266 | __put_user_error(NULL, &frame->uc.uc_link, err); | ||
| 267 | |||
| 268 | memset(&stack, 0, sizeof(stack)); | ||
| 269 | stack.ss_sp = (void __user *)current->sas_ss_sp; | ||
| 270 | stack.ss_flags = sas_ss_flags(regs->sp); | ||
| 271 | stack.ss_size = current->sas_ss_size; | ||
| 272 | err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); | ||
| 273 | |||
| 274 | err |= setup_sigframe(frame, regs, set); | ||
| 275 | if (err == 0) | ||
| 276 | err = setup_return(regs, ka, frame, usig); | ||
| 277 | |||
| 278 | if (err == 0 && ka->sa.sa_flags & SA_SIGINFO) { | ||
| 279 | err |= copy_siginfo_to_user(&frame->info, info); | ||
| 280 | regs->regs[1] = (unsigned long)&frame->info; | ||
| 281 | regs->regs[2] = (unsigned long)&frame->uc; | ||
| 282 | } | ||
| 283 | |||
| 284 | return err; | ||
| 285 | } | ||
| 286 | |||
| 287 | static void setup_restart_syscall(struct pt_regs *regs) | ||
| 288 | { | ||
| 289 | if (is_compat_task()) | ||
| 290 | compat_setup_restart_syscall(regs); | ||
| 291 | else | ||
| 292 | regs->regs[8] = __NR_restart_syscall; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * OK, we're invoking a handler | ||
| 297 | */ | ||
| 298 | static void handle_signal(unsigned long sig, struct k_sigaction *ka, | ||
| 299 | siginfo_t *info, struct pt_regs *regs) | ||
| 300 | { | ||
| 301 | struct thread_info *thread = current_thread_info(); | ||
| 302 | struct task_struct *tsk = current; | ||
| 303 | sigset_t *oldset = sigmask_to_save(); | ||
| 304 | int usig = sig; | ||
| 305 | int ret; | ||
| 306 | |||
| 307 | /* | ||
| 308 | * translate the signal | ||
| 309 | */ | ||
| 310 | if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) | ||
| 311 | usig = thread->exec_domain->signal_invmap[usig]; | ||
| 312 | |||
| 313 | /* | ||
| 314 | * Set up the stack frame | ||
| 315 | */ | ||
| 316 | if (is_compat_task()) { | ||
| 317 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
| 318 | ret = compat_setup_rt_frame(usig, ka, info, oldset, | ||
| 319 | regs); | ||
| 320 | else | ||
| 321 | ret = compat_setup_frame(usig, ka, oldset, regs); | ||
| 322 | } else { | ||
| 323 | ret = setup_rt_frame(usig, ka, info, oldset, regs); | ||
| 324 | } | ||
| 325 | |||
| 326 | /* | ||
| 327 | * Check that the resulting registers are actually sane. | ||
| 328 | */ | ||
| 329 | ret |= !valid_user_regs(®s->user_regs); | ||
| 330 | |||
| 331 | if (ret != 0) { | ||
| 332 | force_sigsegv(sig, tsk); | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | |||
| 336 | /* | ||
| 337 | * Fast forward the stepping logic so we step into the signal | ||
| 338 | * handler. | ||
| 339 | */ | ||
| 340 | user_fastforward_single_step(tsk); | ||
| 341 | |||
| 342 | signal_delivered(sig, info, ka, regs, 0); | ||
| 343 | } | ||
| 344 | |||
| 345 | /* | ||
| 346 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
| 347 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
| 348 | * mistake. | ||
| 349 | * | ||
| 350 | * Note that we go through the signals twice: once to check the signals that | ||
| 351 | * the kernel can handle, and then we build all the user-level signal handling | ||
| 352 | * stack-frames in one go after that. | ||
| 353 | */ | ||
| 354 | static void do_signal(struct pt_regs *regs) | ||
| 355 | { | ||
| 356 | unsigned long continue_addr = 0, restart_addr = 0; | ||
| 357 | struct k_sigaction ka; | ||
| 358 | siginfo_t info; | ||
| 359 | int signr, retval = 0; | ||
| 360 | int syscall = (int)regs->syscallno; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * If we were from a system call, check for system call restarting... | ||
| 364 | */ | ||
| 365 | if (syscall >= 0) { | ||
| 366 | continue_addr = regs->pc; | ||
| 367 | restart_addr = continue_addr - (compat_thumb_mode(regs) ? 2 : 4); | ||
| 368 | retval = regs->regs[0]; | ||
| 369 | |||
| 370 | /* | ||
| 371 | * Avoid additional syscall restarting via ret_to_user. | ||
| 372 | */ | ||
| 373 | regs->syscallno = ~0UL; | ||
| 374 | |||
| 375 | /* | ||
| 376 | * Prepare for system call restart. We do this here so that a | ||
| 377 | * debugger will see the already changed PC. | ||
| 378 | */ | ||
| 379 | switch (retval) { | ||
| 380 | case -ERESTARTNOHAND: | ||
| 381 | case -ERESTARTSYS: | ||
| 382 | case -ERESTARTNOINTR: | ||
| 383 | case -ERESTART_RESTARTBLOCK: | ||
| 384 | regs->regs[0] = regs->orig_x0; | ||
| 385 | regs->pc = restart_addr; | ||
| 386 | break; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | |||
| 390 | /* | ||
| 391 | * Get the signal to deliver. When running under ptrace, at this point | ||
| 392 | * the debugger may change all of our registers. | ||
| 393 | */ | ||
| 394 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
| 395 | if (signr > 0) { | ||
| 396 | /* | ||
| 397 | * Depending on the signal settings, we may need to revert the | ||
| 398 | * decision to restart the system call, but skip this if a | ||
| 399 | * debugger has chosen to restart at a different PC. | ||
| 400 | */ | ||
| 401 | if (regs->pc == restart_addr && | ||
| 402 | (retval == -ERESTARTNOHAND || | ||
| 403 | retval == -ERESTART_RESTARTBLOCK || | ||
| 404 | (retval == -ERESTARTSYS && | ||
| 405 | !(ka.sa.sa_flags & SA_RESTART)))) { | ||
| 406 | regs->regs[0] = -EINTR; | ||
| 407 | regs->pc = continue_addr; | ||
| 408 | } | ||
| 409 | |||
| 410 | handle_signal(signr, &ka, &info, regs); | ||
| 411 | return; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* | ||
| 415 | * Handle restarting a different system call. As above, if a debugger | ||
| 416 | * has chosen to restart at a different PC, ignore the restart. | ||
| 417 | */ | ||
| 418 | if (syscall >= 0 && regs->pc == restart_addr) { | ||
| 419 | if (retval == -ERESTART_RESTARTBLOCK) | ||
| 420 | setup_restart_syscall(regs); | ||
| 421 | user_rewind_single_step(current); | ||
| 422 | } | ||
| 423 | |||
| 424 | restore_saved_sigmask(); | ||
| 425 | } | ||
| 426 | |||
| 427 | asmlinkage void do_notify_resume(struct pt_regs *regs, | ||
| 428 | unsigned int thread_flags) | ||
| 429 | { | ||
| 430 | if (thread_flags & _TIF_SIGPENDING) | ||
| 431 | do_signal(regs); | ||
| 432 | |||
| 433 | if (thread_flags & _TIF_NOTIFY_RESUME) { | ||
| 434 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
| 435 | tracehook_notify_resume(regs); | ||
| 436 | } | ||
| 437 | } | ||
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c new file mode 100644 index 000000000000..ac74c2f261e3 --- /dev/null +++ b/arch/arm64/kernel/signal32.c | |||
| @@ -0,0 +1,876 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/signal.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2009 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * Modified by Will Deacon <will.deacon@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define __SYSCALL_COMPAT | ||
| 22 | |||
| 23 | #include <linux/compat.h> | ||
| 24 | #include <linux/signal.h> | ||
| 25 | #include <linux/syscalls.h> | ||
| 26 | #include <linux/ratelimit.h> | ||
| 27 | |||
| 28 | #include <asm/fpsimd.h> | ||
| 29 | #include <asm/signal32.h> | ||
| 30 | #include <asm/uaccess.h> | ||
| 31 | #include <asm/unistd.h> | ||
| 32 | |||
| 33 | typedef struct compat_siginfo { | ||
| 34 | int si_signo; | ||
| 35 | int si_errno; | ||
| 36 | int si_code; | ||
| 37 | |||
| 38 | union { | ||
| 39 | /* The padding is the same size as AArch64. */ | ||
| 40 | int _pad[SI_PAD_SIZE]; | ||
| 41 | |||
| 42 | /* kill() */ | ||
| 43 | struct { | ||
| 44 | compat_pid_t _pid; /* sender's pid */ | ||
| 45 | __compat_uid32_t _uid; /* sender's uid */ | ||
| 46 | } _kill; | ||
| 47 | |||
| 48 | /* POSIX.1b timers */ | ||
| 49 | struct { | ||
| 50 | compat_timer_t _tid; /* timer id */ | ||
| 51 | int _overrun; /* overrun count */ | ||
| 52 | compat_sigval_t _sigval; /* same as below */ | ||
| 53 | int _sys_private; /* not to be passed to user */ | ||
| 54 | } _timer; | ||
| 55 | |||
| 56 | /* POSIX.1b signals */ | ||
| 57 | struct { | ||
| 58 | compat_pid_t _pid; /* sender's pid */ | ||
| 59 | __compat_uid32_t _uid; /* sender's uid */ | ||
| 60 | compat_sigval_t _sigval; | ||
| 61 | } _rt; | ||
| 62 | |||
| 63 | /* SIGCHLD */ | ||
| 64 | struct { | ||
| 65 | compat_pid_t _pid; /* which child */ | ||
| 66 | __compat_uid32_t _uid; /* sender's uid */ | ||
| 67 | int _status; /* exit code */ | ||
| 68 | compat_clock_t _utime; | ||
| 69 | compat_clock_t _stime; | ||
| 70 | } _sigchld; | ||
| 71 | |||
| 72 | /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ | ||
| 73 | struct { | ||
| 74 | compat_uptr_t _addr; /* faulting insn/memory ref. */ | ||
| 75 | short _addr_lsb; /* LSB of the reported address */ | ||
| 76 | } _sigfault; | ||
| 77 | |||
| 78 | /* SIGPOLL */ | ||
| 79 | struct { | ||
| 80 | compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */ | ||
| 81 | int _fd; | ||
| 82 | } _sigpoll; | ||
| 83 | } _sifields; | ||
| 84 | } compat_siginfo_t; | ||
| 85 | |||
| 86 | struct compat_sigaction { | ||
| 87 | compat_uptr_t sa_handler; | ||
| 88 | compat_ulong_t sa_flags; | ||
| 89 | compat_uptr_t sa_restorer; | ||
| 90 | compat_sigset_t sa_mask; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct compat_old_sigaction { | ||
| 94 | compat_uptr_t sa_handler; | ||
| 95 | compat_old_sigset_t sa_mask; | ||
| 96 | compat_ulong_t sa_flags; | ||
| 97 | compat_uptr_t sa_restorer; | ||
| 98 | }; | ||
| 99 | |||
| 100 | typedef struct compat_sigaltstack { | ||
| 101 | compat_uptr_t ss_sp; | ||
| 102 | int ss_flags; | ||
| 103 | compat_size_t ss_size; | ||
| 104 | } compat_stack_t; | ||
| 105 | |||
| 106 | struct compat_sigcontext { | ||
| 107 | /* We always set these two fields to 0 */ | ||
| 108 | compat_ulong_t trap_no; | ||
| 109 | compat_ulong_t error_code; | ||
| 110 | |||
| 111 | compat_ulong_t oldmask; | ||
| 112 | compat_ulong_t arm_r0; | ||
| 113 | compat_ulong_t arm_r1; | ||
| 114 | compat_ulong_t arm_r2; | ||
| 115 | compat_ulong_t arm_r3; | ||
| 116 | compat_ulong_t arm_r4; | ||
| 117 | compat_ulong_t arm_r5; | ||
| 118 | compat_ulong_t arm_r6; | ||
| 119 | compat_ulong_t arm_r7; | ||
| 120 | compat_ulong_t arm_r8; | ||
| 121 | compat_ulong_t arm_r9; | ||
| 122 | compat_ulong_t arm_r10; | ||
| 123 | compat_ulong_t arm_fp; | ||
| 124 | compat_ulong_t arm_ip; | ||
| 125 | compat_ulong_t arm_sp; | ||
| 126 | compat_ulong_t arm_lr; | ||
| 127 | compat_ulong_t arm_pc; | ||
| 128 | compat_ulong_t arm_cpsr; | ||
| 129 | compat_ulong_t fault_address; | ||
| 130 | }; | ||
| 131 | |||
| 132 | struct compat_ucontext { | ||
| 133 | compat_ulong_t uc_flags; | ||
| 134 | struct compat_ucontext *uc_link; | ||
| 135 | compat_stack_t uc_stack; | ||
| 136 | struct compat_sigcontext uc_mcontext; | ||
| 137 | compat_sigset_t uc_sigmask; | ||
| 138 | int __unused[32 - (sizeof (compat_sigset_t) / sizeof (int))]; | ||
| 139 | compat_ulong_t uc_regspace[128] __attribute__((__aligned__(8))); | ||
| 140 | }; | ||
| 141 | |||
| 142 | struct compat_vfp_sigframe { | ||
| 143 | compat_ulong_t magic; | ||
| 144 | compat_ulong_t size; | ||
| 145 | struct compat_user_vfp { | ||
| 146 | compat_u64 fpregs[32]; | ||
| 147 | compat_ulong_t fpscr; | ||
| 148 | } ufp; | ||
| 149 | struct compat_user_vfp_exc { | ||
| 150 | compat_ulong_t fpexc; | ||
| 151 | compat_ulong_t fpinst; | ||
| 152 | compat_ulong_t fpinst2; | ||
| 153 | } ufp_exc; | ||
| 154 | } __attribute__((__aligned__(8))); | ||
| 155 | |||
| 156 | #define VFP_MAGIC 0x56465001 | ||
| 157 | #define VFP_STORAGE_SIZE sizeof(struct compat_vfp_sigframe) | ||
| 158 | |||
| 159 | struct compat_aux_sigframe { | ||
| 160 | struct compat_vfp_sigframe vfp; | ||
| 161 | |||
| 162 | /* Something that isn't a valid magic number for any coprocessor. */ | ||
| 163 | unsigned long end_magic; | ||
| 164 | } __attribute__((__aligned__(8))); | ||
| 165 | |||
| 166 | struct compat_sigframe { | ||
| 167 | struct compat_ucontext uc; | ||
| 168 | compat_ulong_t retcode[2]; | ||
| 169 | }; | ||
| 170 | |||
| 171 | struct compat_rt_sigframe { | ||
| 172 | struct compat_siginfo info; | ||
| 173 | struct compat_sigframe sig; | ||
| 174 | }; | ||
| 175 | |||
| 176 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
| 177 | |||
| 178 | /* | ||
| 179 | * For ARM syscalls, the syscall number has to be loaded into r7. | ||
| 180 | * We do not support an OABI userspace. | ||
| 181 | */ | ||
| 182 | #define MOV_R7_NR_SIGRETURN (0xe3a07000 | __NR_sigreturn) | ||
| 183 | #define SVC_SYS_SIGRETURN (0xef000000 | __NR_sigreturn) | ||
| 184 | #define MOV_R7_NR_RT_SIGRETURN (0xe3a07000 | __NR_rt_sigreturn) | ||
| 185 | #define SVC_SYS_RT_SIGRETURN (0xef000000 | __NR_rt_sigreturn) | ||
| 186 | |||
| 187 | /* | ||
| 188 | * For Thumb syscalls, we also pass the syscall number via r7. We therefore | ||
| 189 | * need two 16-bit instructions. | ||
| 190 | */ | ||
| 191 | #define SVC_THUMB_SIGRETURN (((0xdf00 | __NR_sigreturn) << 16) | \ | ||
| 192 | 0x2700 | __NR_sigreturn) | ||
| 193 | #define SVC_THUMB_RT_SIGRETURN (((0xdf00 | __NR_rt_sigreturn) << 16) | \ | ||
| 194 | 0x2700 | __NR_rt_sigreturn) | ||
| 195 | |||
| 196 | const compat_ulong_t aarch32_sigret_code[6] = { | ||
| 197 | /* | ||
| 198 | * AArch32 sigreturn code. | ||
| 199 | * We don't construct an OABI SWI - instead we just set the imm24 field | ||
| 200 | * to the EABI syscall number so that we create a sane disassembly. | ||
| 201 | */ | ||
| 202 | MOV_R7_NR_SIGRETURN, SVC_SYS_SIGRETURN, SVC_THUMB_SIGRETURN, | ||
| 203 | MOV_R7_NR_RT_SIGRETURN, SVC_SYS_RT_SIGRETURN, SVC_THUMB_RT_SIGRETURN, | ||
| 204 | }; | ||
| 205 | |||
| 206 | static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set) | ||
| 207 | { | ||
| 208 | compat_sigset_t cset; | ||
| 209 | |||
| 210 | cset.sig[0] = set->sig[0] & 0xffffffffull; | ||
| 211 | cset.sig[1] = set->sig[0] >> 32; | ||
| 212 | |||
| 213 | return copy_to_user(uset, &cset, sizeof(*uset)); | ||
| 214 | } | ||
| 215 | |||
| 216 | static inline int get_sigset_t(sigset_t *set, | ||
| 217 | const compat_sigset_t __user *uset) | ||
| 218 | { | ||
| 219 | compat_sigset_t s32; | ||
| 220 | |||
| 221 | if (copy_from_user(&s32, uset, sizeof(*uset))) | ||
| 222 | return -EFAULT; | ||
| 223 | |||
| 224 | set->sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32); | ||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | ||
| 229 | { | ||
| 230 | int err; | ||
| 231 | |||
| 232 | if (!access_ok(VERIFY_WRITE, to, sizeof(*to))) | ||
| 233 | return -EFAULT; | ||
| 234 | |||
| 235 | /* If you change siginfo_t structure, please be sure | ||
| 236 | * this code is fixed accordingly. | ||
| 237 | * It should never copy any pad contained in the structure | ||
| 238 | * to avoid security leaks, but must copy the generic | ||
| 239 | * 3 ints plus the relevant union member. | ||
| 240 | * This routine must convert siginfo from 64bit to 32bit as well | ||
| 241 | * at the same time. | ||
| 242 | */ | ||
| 243 | err = __put_user(from->si_signo, &to->si_signo); | ||
| 244 | err |= __put_user(from->si_errno, &to->si_errno); | ||
| 245 | err |= __put_user((short)from->si_code, &to->si_code); | ||
| 246 | if (from->si_code < 0) | ||
| 247 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, | ||
| 248 | SI_PAD_SIZE); | ||
| 249 | else switch (from->si_code & __SI_MASK) { | ||
| 250 | case __SI_KILL: | ||
| 251 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 252 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 253 | break; | ||
| 254 | case __SI_TIMER: | ||
| 255 | err |= __put_user(from->si_tid, &to->si_tid); | ||
| 256 | err |= __put_user(from->si_overrun, &to->si_overrun); | ||
| 257 | err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, | ||
| 258 | &to->si_ptr); | ||
| 259 | break; | ||
| 260 | case __SI_POLL: | ||
| 261 | err |= __put_user(from->si_band, &to->si_band); | ||
| 262 | err |= __put_user(from->si_fd, &to->si_fd); | ||
| 263 | break; | ||
| 264 | case __SI_FAULT: | ||
| 265 | err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr, | ||
| 266 | &to->si_addr); | ||
| 267 | #ifdef BUS_MCEERR_AO | ||
| 268 | /* | ||
| 269 | * Other callers might not initialize the si_lsb field, | ||
| 270 | * so check explicitely for the right codes here. | ||
| 271 | */ | ||
| 272 | if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO) | ||
| 273 | err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); | ||
| 274 | #endif | ||
| 275 | break; | ||
| 276 | case __SI_CHLD: | ||
| 277 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 278 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 279 | err |= __put_user(from->si_status, &to->si_status); | ||
| 280 | err |= __put_user(from->si_utime, &to->si_utime); | ||
| 281 | err |= __put_user(from->si_stime, &to->si_stime); | ||
| 282 | break; | ||
| 283 | case __SI_RT: /* This is not generated by the kernel as of now. */ | ||
| 284 | case __SI_MESGQ: /* But this is */ | ||
| 285 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 286 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 287 | err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr); | ||
| 288 | break; | ||
| 289 | default: /* this is just in case for now ... */ | ||
| 290 | err |= __put_user(from->si_pid, &to->si_pid); | ||
| 291 | err |= __put_user(from->si_uid, &to->si_uid); | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | return err; | ||
| 295 | } | ||
| 296 | |||
| 297 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) | ||
| 298 | { | ||
| 299 | memset(to, 0, sizeof *to); | ||
| 300 | |||
| 301 | if (copy_from_user(to, from, __ARCH_SI_PREAMBLE_SIZE) || | ||
| 302 | copy_from_user(to->_sifields._pad, | ||
| 303 | from->_sifields._pad, SI_PAD_SIZE)) | ||
| 304 | return -EFAULT; | ||
| 305 | |||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | |||
| 309 | /* | ||
| 310 | * VFP save/restore code. | ||
| 311 | */ | ||
| 312 | static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame) | ||
| 313 | { | ||
| 314 | struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; | ||
| 315 | compat_ulong_t magic = VFP_MAGIC; | ||
| 316 | compat_ulong_t size = VFP_STORAGE_SIZE; | ||
| 317 | compat_ulong_t fpscr, fpexc; | ||
| 318 | int err = 0; | ||
| 319 | |||
| 320 | /* | ||
| 321 | * Save the hardware registers to the fpsimd_state structure. | ||
| 322 | * Note that this also saves V16-31, which aren't visible | ||
| 323 | * in AArch32. | ||
| 324 | */ | ||
| 325 | fpsimd_save_state(fpsimd); | ||
| 326 | |||
| 327 | /* Place structure header on the stack */ | ||
| 328 | __put_user_error(magic, &frame->magic, err); | ||
| 329 | __put_user_error(size, &frame->size, err); | ||
| 330 | |||
| 331 | /* | ||
| 332 | * Now copy the FP registers. Since the registers are packed, | ||
| 333 | * we can copy the prefix we want (V0-V15) as it is. | ||
| 334 | * FIXME: Won't work if big endian. | ||
| 335 | */ | ||
| 336 | err |= __copy_to_user(&frame->ufp.fpregs, fpsimd->vregs, | ||
| 337 | sizeof(frame->ufp.fpregs)); | ||
| 338 | |||
| 339 | /* Create an AArch32 fpscr from the fpsr and the fpcr. */ | ||
| 340 | fpscr = (fpsimd->fpsr & VFP_FPSCR_STAT_MASK) | | ||
| 341 | (fpsimd->fpcr & VFP_FPSCR_CTRL_MASK); | ||
| 342 | __put_user_error(fpscr, &frame->ufp.fpscr, err); | ||
| 343 | |||
| 344 | /* | ||
| 345 | * The exception register aren't available so we fake up a | ||
| 346 | * basic FPEXC and zero everything else. | ||
| 347 | */ | ||
| 348 | fpexc = (1 << 30); | ||
| 349 | __put_user_error(fpexc, &frame->ufp_exc.fpexc, err); | ||
| 350 | __put_user_error(0, &frame->ufp_exc.fpinst, err); | ||
| 351 | __put_user_error(0, &frame->ufp_exc.fpinst2, err); | ||
| 352 | |||
| 353 | return err ? -EFAULT : 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame) | ||
| 357 | { | ||
| 358 | struct fpsimd_state fpsimd; | ||
| 359 | compat_ulong_t magic = VFP_MAGIC; | ||
| 360 | compat_ulong_t size = VFP_STORAGE_SIZE; | ||
| 361 | compat_ulong_t fpscr; | ||
| 362 | int err = 0; | ||
| 363 | |||
| 364 | __get_user_error(magic, &frame->magic, err); | ||
| 365 | __get_user_error(size, &frame->size, err); | ||
| 366 | |||
| 367 | if (err) | ||
| 368 | return -EFAULT; | ||
| 369 | if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) | ||
| 370 | return -EINVAL; | ||
| 371 | |||
| 372 | /* | ||
| 373 | * Copy the FP registers into the start of the fpsimd_state. | ||
| 374 | * FIXME: Won't work if big endian. | ||
| 375 | */ | ||
| 376 | err |= __copy_from_user(fpsimd.vregs, frame->ufp.fpregs, | ||
| 377 | sizeof(frame->ufp.fpregs)); | ||
| 378 | |||
| 379 | /* Extract the fpsr and the fpcr from the fpscr */ | ||
| 380 | __get_user_error(fpscr, &frame->ufp.fpscr, err); | ||
| 381 | fpsimd.fpsr = fpscr & VFP_FPSCR_STAT_MASK; | ||
| 382 | fpsimd.fpcr = fpscr & VFP_FPSCR_CTRL_MASK; | ||
| 383 | |||
| 384 | /* | ||
| 385 | * We don't need to touch the exception register, so | ||
| 386 | * reload the hardware state. | ||
| 387 | */ | ||
| 388 | if (!err) { | ||
| 389 | preempt_disable(); | ||
| 390 | fpsimd_load_state(&fpsimd); | ||
| 391 | preempt_enable(); | ||
| 392 | } | ||
| 393 | |||
| 394 | return err ? -EFAULT : 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | /* | ||
| 398 | * atomically swap in the new signal mask, and wait for a signal. | ||
| 399 | */ | ||
| 400 | asmlinkage int compat_sys_sigsuspend(int restart, compat_ulong_t oldmask, | ||
| 401 | compat_old_sigset_t mask) | ||
| 402 | { | ||
| 403 | sigset_t blocked; | ||
| 404 | |||
| 405 | siginitset(¤t->blocked, mask); | ||
| 406 | return sigsuspend(&blocked); | ||
| 407 | } | ||
| 408 | |||
| 409 | asmlinkage int compat_sys_sigaction(int sig, | ||
| 410 | const struct compat_old_sigaction __user *act, | ||
| 411 | struct compat_old_sigaction __user *oact) | ||
| 412 | { | ||
| 413 | struct k_sigaction new_ka, old_ka; | ||
| 414 | int ret; | ||
| 415 | compat_old_sigset_t mask; | ||
| 416 | compat_uptr_t handler, restorer; | ||
| 417 | |||
| 418 | if (act) { | ||
| 419 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
| 420 | __get_user(handler, &act->sa_handler) || | ||
| 421 | __get_user(restorer, &act->sa_restorer) || | ||
| 422 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
| 423 | __get_user(mask, &act->sa_mask)) | ||
| 424 | return -EFAULT; | ||
| 425 | |||
| 426 | new_ka.sa.sa_handler = compat_ptr(handler); | ||
| 427 | new_ka.sa.sa_restorer = compat_ptr(restorer); | ||
| 428 | siginitset(&new_ka.sa.sa_mask, mask); | ||
| 429 | } | ||
| 430 | |||
| 431 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
| 432 | |||
| 433 | if (!ret && oact) { | ||
| 434 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
| 435 | __put_user(ptr_to_compat(old_ka.sa.sa_handler), | ||
| 436 | &oact->sa_handler) || | ||
| 437 | __put_user(ptr_to_compat(old_ka.sa.sa_restorer), | ||
| 438 | &oact->sa_restorer) || | ||
| 439 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
| 440 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
| 441 | return -EFAULT; | ||
| 442 | } | ||
| 443 | |||
| 444 | return ret; | ||
| 445 | } | ||
| 446 | |||
| 447 | asmlinkage int compat_sys_rt_sigaction(int sig, | ||
| 448 | const struct compat_sigaction __user *act, | ||
| 449 | struct compat_sigaction __user *oact, | ||
| 450 | compat_size_t sigsetsize) | ||
| 451 | { | ||
| 452 | struct k_sigaction new_ka, old_ka; | ||
| 453 | int ret; | ||
| 454 | |||
| 455 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
| 456 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
| 457 | return -EINVAL; | ||
| 458 | |||
| 459 | if (act) { | ||
| 460 | compat_uptr_t handler, restorer; | ||
| 461 | |||
| 462 | ret = get_user(handler, &act->sa_handler); | ||
| 463 | new_ka.sa.sa_handler = compat_ptr(handler); | ||
| 464 | ret |= get_user(restorer, &act->sa_restorer); | ||
| 465 | new_ka.sa.sa_restorer = compat_ptr(restorer); | ||
| 466 | ret |= get_sigset_t(&new_ka.sa.sa_mask, &act->sa_mask); | ||
| 467 | ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
| 468 | if (ret) | ||
| 469 | return -EFAULT; | ||
| 470 | } | ||
| 471 | |||
| 472 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
| 473 | if (!ret && oact) { | ||
| 474 | ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler); | ||
| 475 | ret |= put_sigset_t(&oact->sa_mask, &old_ka.sa.sa_mask); | ||
| 476 | ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
| 477 | } | ||
| 478 | return ret; | ||
| 479 | } | ||
| 480 | |||
| 481 | int compat_do_sigaltstack(compat_uptr_t compat_uss, compat_uptr_t compat_uoss, | ||
| 482 | compat_ulong_t sp) | ||
| 483 | { | ||
| 484 | compat_stack_t __user *newstack = compat_ptr(compat_uss); | ||
| 485 | compat_stack_t __user *oldstack = compat_ptr(compat_uoss); | ||
| 486 | compat_uptr_t ss_sp; | ||
| 487 | int ret; | ||
| 488 | mm_segment_t old_fs; | ||
| 489 | stack_t uss, uoss; | ||
| 490 | |||
| 491 | /* Marshall the compat new stack into a stack_t */ | ||
| 492 | if (newstack) { | ||
| 493 | if (get_user(ss_sp, &newstack->ss_sp) || | ||
| 494 | __get_user(uss.ss_flags, &newstack->ss_flags) || | ||
| 495 | __get_user(uss.ss_size, &newstack->ss_size)) | ||
| 496 | return -EFAULT; | ||
| 497 | uss.ss_sp = compat_ptr(ss_sp); | ||
| 498 | } | ||
| 499 | |||
| 500 | old_fs = get_fs(); | ||
| 501 | set_fs(KERNEL_DS); | ||
| 502 | /* The __user pointer casts are valid because of the set_fs() */ | ||
| 503 | ret = do_sigaltstack( | ||
| 504 | newstack ? (stack_t __user *) &uss : NULL, | ||
| 505 | oldstack ? (stack_t __user *) &uoss : NULL, | ||
| 506 | (unsigned long)sp); | ||
| 507 | set_fs(old_fs); | ||
| 508 | |||
| 509 | /* Convert the old stack_t into a compat stack. */ | ||
| 510 | if (!ret && oldstack && | ||
| 511 | (put_user(ptr_to_compat(uoss.ss_sp), &oldstack->ss_sp) || | ||
| 512 | __put_user(uoss.ss_flags, &oldstack->ss_flags) || | ||
| 513 | __put_user(uoss.ss_size, &oldstack->ss_size))) | ||
| 514 | return -EFAULT; | ||
| 515 | return ret; | ||
| 516 | } | ||
| 517 | |||
| 518 | static int compat_restore_sigframe(struct pt_regs *regs, | ||
| 519 | struct compat_sigframe __user *sf) | ||
| 520 | { | ||
| 521 | int err; | ||
| 522 | sigset_t set; | ||
| 523 | struct compat_aux_sigframe __user *aux; | ||
| 524 | |||
| 525 | err = get_sigset_t(&set, &sf->uc.uc_sigmask); | ||
| 526 | if (err == 0) { | ||
| 527 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
| 528 | set_current_blocked(&set); | ||
| 529 | } | ||
| 530 | |||
| 531 | __get_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err); | ||
| 532 | __get_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err); | ||
| 533 | __get_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err); | ||
| 534 | __get_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err); | ||
| 535 | __get_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err); | ||
| 536 | __get_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err); | ||
| 537 | __get_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err); | ||
| 538 | __get_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err); | ||
| 539 | __get_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err); | ||
| 540 | __get_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err); | ||
| 541 | __get_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err); | ||
| 542 | __get_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err); | ||
| 543 | __get_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err); | ||
| 544 | __get_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err); | ||
| 545 | __get_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err); | ||
| 546 | __get_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err); | ||
| 547 | __get_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err); | ||
| 548 | |||
| 549 | /* | ||
| 550 | * Avoid compat_sys_sigreturn() restarting. | ||
| 551 | */ | ||
| 552 | regs->syscallno = ~0UL; | ||
| 553 | |||
| 554 | err |= !valid_user_regs(®s->user_regs); | ||
| 555 | |||
| 556 | aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace; | ||
| 557 | if (err == 0) | ||
| 558 | err |= compat_restore_vfp_context(&aux->vfp); | ||
| 559 | |||
| 560 | return err; | ||
| 561 | } | ||
| 562 | |||
| 563 | asmlinkage int compat_sys_sigreturn(struct pt_regs *regs) | ||
| 564 | { | ||
| 565 | struct compat_sigframe __user *frame; | ||
| 566 | |||
| 567 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 568 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 569 | |||
| 570 | /* | ||
| 571 | * Since we stacked the signal on a 64-bit boundary, | ||
| 572 | * then 'sp' should be word aligned here. If it's | ||
| 573 | * not, then the user is trying to mess with us. | ||
| 574 | */ | ||
| 575 | if (regs->compat_sp & 7) | ||
| 576 | goto badframe; | ||
| 577 | |||
| 578 | frame = (struct compat_sigframe __user *)regs->compat_sp; | ||
| 579 | |||
| 580 | if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) | ||
| 581 | goto badframe; | ||
| 582 | |||
| 583 | if (compat_restore_sigframe(regs, frame)) | ||
| 584 | goto badframe; | ||
| 585 | |||
| 586 | return regs->regs[0]; | ||
| 587 | |||
| 588 | badframe: | ||
| 589 | if (show_unhandled_signals) | ||
| 590 | pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n", | ||
| 591 | current->comm, task_pid_nr(current), __func__, | ||
| 592 | regs->pc, regs->sp); | ||
| 593 | force_sig(SIGSEGV, current); | ||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | |||
| 597 | asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs) | ||
| 598 | { | ||
| 599 | struct compat_rt_sigframe __user *frame; | ||
| 600 | |||
| 601 | /* Always make any pending restarted system calls return -EINTR */ | ||
| 602 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
| 603 | |||
| 604 | /* | ||
| 605 | * Since we stacked the signal on a 64-bit boundary, | ||
| 606 | * then 'sp' should be word aligned here. If it's | ||
| 607 | * not, then the user is trying to mess with us. | ||
| 608 | */ | ||
| 609 | if (regs->compat_sp & 7) | ||
| 610 | goto badframe; | ||
| 611 | |||
| 612 | frame = (struct compat_rt_sigframe __user *)regs->compat_sp; | ||
| 613 | |||
| 614 | if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) | ||
| 615 | goto badframe; | ||
| 616 | |||
| 617 | if (compat_restore_sigframe(regs, &frame->sig)) | ||
| 618 | goto badframe; | ||
| 619 | |||
| 620 | if (compat_do_sigaltstack(ptr_to_compat(&frame->sig.uc.uc_stack), | ||
| 621 | ptr_to_compat((void __user *)NULL), | ||
| 622 | regs->compat_sp) == -EFAULT) | ||
| 623 | goto badframe; | ||
| 624 | |||
| 625 | return regs->regs[0]; | ||
| 626 | |||
| 627 | badframe: | ||
| 628 | if (show_unhandled_signals) | ||
| 629 | pr_info_ratelimited("%s[%d]: bad frame in %s: pc=%08llx sp=%08llx\n", | ||
| 630 | current->comm, task_pid_nr(current), __func__, | ||
| 631 | regs->pc, regs->sp); | ||
| 632 | force_sig(SIGSEGV, current); | ||
| 633 | return 0; | ||
| 634 | } | ||
| 635 | |||
| 636 | static inline void __user *compat_get_sigframe(struct k_sigaction *ka, | ||
| 637 | struct pt_regs *regs, | ||
| 638 | int framesize) | ||
| 639 | { | ||
| 640 | compat_ulong_t sp = regs->compat_sp; | ||
| 641 | void __user *frame; | ||
| 642 | |||
| 643 | /* | ||
| 644 | * This is the X/Open sanctioned signal stack switching. | ||
| 645 | */ | ||
| 646 | if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) | ||
| 647 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
| 648 | |||
| 649 | /* | ||
| 650 | * ATPCS B01 mandates 8-byte alignment | ||
| 651 | */ | ||
| 652 | frame = compat_ptr((compat_uptr_t)((sp - framesize) & ~7)); | ||
| 653 | |||
| 654 | /* | ||
| 655 | * Check that we can actually write to the signal frame. | ||
| 656 | */ | ||
| 657 | if (!access_ok(VERIFY_WRITE, frame, framesize)) | ||
| 658 | frame = NULL; | ||
| 659 | |||
| 660 | return frame; | ||
| 661 | } | ||
| 662 | |||
| 663 | static int compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, | ||
| 664 | compat_ulong_t __user *rc, void __user *frame, | ||
| 665 | int usig) | ||
| 666 | { | ||
| 667 | compat_ulong_t handler = ptr_to_compat(ka->sa.sa_handler); | ||
| 668 | compat_ulong_t retcode; | ||
| 669 | compat_ulong_t spsr = regs->pstate & ~PSR_f; | ||
| 670 | int thumb; | ||
| 671 | |||
| 672 | /* Check if the handler is written for ARM or Thumb */ | ||
| 673 | thumb = handler & 1; | ||
| 674 | |||
| 675 | if (thumb) { | ||
| 676 | spsr |= COMPAT_PSR_T_BIT; | ||
| 677 | spsr &= ~COMPAT_PSR_IT_MASK; | ||
| 678 | } else { | ||
| 679 | spsr &= ~COMPAT_PSR_T_BIT; | ||
| 680 | } | ||
| 681 | |||
| 682 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
| 683 | retcode = ptr_to_compat(ka->sa.sa_restorer); | ||
| 684 | } else { | ||
| 685 | /* Set up sigreturn pointer */ | ||
| 686 | unsigned int idx = thumb << 1; | ||
| 687 | |||
| 688 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
| 689 | idx += 3; | ||
| 690 | |||
| 691 | retcode = AARCH32_VECTORS_BASE + | ||
| 692 | AARCH32_KERN_SIGRET_CODE_OFFSET + | ||
| 693 | (idx << 2) + thumb; | ||
| 694 | } | ||
| 695 | |||
| 696 | regs->regs[0] = usig; | ||
| 697 | regs->compat_sp = ptr_to_compat(frame); | ||
| 698 | regs->compat_lr = retcode; | ||
| 699 | regs->pc = handler; | ||
| 700 | regs->pstate = spsr; | ||
| 701 | |||
| 702 | return 0; | ||
| 703 | } | ||
| 704 | |||
| 705 | static int compat_setup_sigframe(struct compat_sigframe __user *sf, | ||
| 706 | struct pt_regs *regs, sigset_t *set) | ||
| 707 | { | ||
| 708 | struct compat_aux_sigframe __user *aux; | ||
| 709 | int err = 0; | ||
| 710 | |||
| 711 | __put_user_error(regs->regs[0], &sf->uc.uc_mcontext.arm_r0, err); | ||
| 712 | __put_user_error(regs->regs[1], &sf->uc.uc_mcontext.arm_r1, err); | ||
| 713 | __put_user_error(regs->regs[2], &sf->uc.uc_mcontext.arm_r2, err); | ||
| 714 | __put_user_error(regs->regs[3], &sf->uc.uc_mcontext.arm_r3, err); | ||
| 715 | __put_user_error(regs->regs[4], &sf->uc.uc_mcontext.arm_r4, err); | ||
| 716 | __put_user_error(regs->regs[5], &sf->uc.uc_mcontext.arm_r5, err); | ||
| 717 | __put_user_error(regs->regs[6], &sf->uc.uc_mcontext.arm_r6, err); | ||
| 718 | __put_user_error(regs->regs[7], &sf->uc.uc_mcontext.arm_r7, err); | ||
| 719 | __put_user_error(regs->regs[8], &sf->uc.uc_mcontext.arm_r8, err); | ||
| 720 | __put_user_error(regs->regs[9], &sf->uc.uc_mcontext.arm_r9, err); | ||
| 721 | __put_user_error(regs->regs[10], &sf->uc.uc_mcontext.arm_r10, err); | ||
| 722 | __put_user_error(regs->regs[11], &sf->uc.uc_mcontext.arm_fp, err); | ||
| 723 | __put_user_error(regs->regs[12], &sf->uc.uc_mcontext.arm_ip, err); | ||
| 724 | __put_user_error(regs->compat_sp, &sf->uc.uc_mcontext.arm_sp, err); | ||
| 725 | __put_user_error(regs->compat_lr, &sf->uc.uc_mcontext.arm_lr, err); | ||
| 726 | __put_user_error(regs->pc, &sf->uc.uc_mcontext.arm_pc, err); | ||
| 727 | __put_user_error(regs->pstate, &sf->uc.uc_mcontext.arm_cpsr, err); | ||
| 728 | |||
| 729 | __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.trap_no, err); | ||
| 730 | __put_user_error((compat_ulong_t)0, &sf->uc.uc_mcontext.error_code, err); | ||
| 731 | __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err); | ||
| 732 | __put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err); | ||
| 733 | |||
| 734 | err |= put_sigset_t(&sf->uc.uc_sigmask, set); | ||
| 735 | |||
| 736 | aux = (struct compat_aux_sigframe __user *) sf->uc.uc_regspace; | ||
| 737 | |||
| 738 | if (err == 0) | ||
| 739 | err |= compat_preserve_vfp_context(&aux->vfp); | ||
| 740 | __put_user_error(0, &aux->end_magic, err); | ||
| 741 | |||
| 742 | return err; | ||
| 743 | } | ||
| 744 | |||
| 745 | /* | ||
| 746 | * 32-bit signal handling routines called from signal.c | ||
| 747 | */ | ||
| 748 | int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, | ||
| 749 | sigset_t *set, struct pt_regs *regs) | ||
| 750 | { | ||
| 751 | struct compat_rt_sigframe __user *frame; | ||
| 752 | compat_stack_t stack; | ||
| 753 | int err = 0; | ||
| 754 | |||
| 755 | frame = compat_get_sigframe(ka, regs, sizeof(*frame)); | ||
| 756 | |||
| 757 | if (!frame) | ||
| 758 | return 1; | ||
| 759 | |||
| 760 | err |= copy_siginfo_to_user32(&frame->info, info); | ||
| 761 | |||
| 762 | __put_user_error(0, &frame->sig.uc.uc_flags, err); | ||
| 763 | __put_user_error(NULL, &frame->sig.uc.uc_link, err); | ||
| 764 | |||
| 765 | memset(&stack, 0, sizeof(stack)); | ||
| 766 | stack.ss_sp = (compat_uptr_t)current->sas_ss_sp; | ||
| 767 | stack.ss_flags = sas_ss_flags(regs->compat_sp); | ||
| 768 | stack.ss_size = current->sas_ss_size; | ||
| 769 | err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack)); | ||
| 770 | |||
| 771 | err |= compat_setup_sigframe(&frame->sig, regs, set); | ||
| 772 | if (err == 0) | ||
| 773 | err = compat_setup_return(regs, ka, frame->sig.retcode, frame, | ||
| 774 | usig); | ||
| 775 | |||
| 776 | if (err == 0) { | ||
| 777 | regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info; | ||
| 778 | regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc; | ||
| 779 | } | ||
| 780 | |||
| 781 | return err; | ||
| 782 | } | ||
| 783 | |||
| 784 | int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, | ||
| 785 | struct pt_regs *regs) | ||
| 786 | { | ||
| 787 | struct compat_sigframe __user *frame; | ||
| 788 | int err = 0; | ||
| 789 | |||
| 790 | frame = compat_get_sigframe(ka, regs, sizeof(*frame)); | ||
| 791 | |||
| 792 | if (!frame) | ||
| 793 | return 1; | ||
| 794 | |||
| 795 | __put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err); | ||
| 796 | |||
| 797 | err |= compat_setup_sigframe(frame, regs, set); | ||
| 798 | if (err == 0) | ||
| 799 | err = compat_setup_return(regs, ka, frame->retcode, frame, usig); | ||
| 800 | |||
| 801 | return err; | ||
| 802 | } | ||
| 803 | |||
| 804 | /* | ||
| 805 | * RT signals don't have generic compat wrappers. | ||
| 806 | * See arch/powerpc/kernel/signal_32.c | ||
| 807 | */ | ||
| 808 | asmlinkage int compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set, | ||
| 809 | compat_sigset_t __user *oset, | ||
| 810 | compat_size_t sigsetsize) | ||
| 811 | { | ||
| 812 | sigset_t s; | ||
| 813 | sigset_t __user *up; | ||
| 814 | int ret; | ||
| 815 | mm_segment_t old_fs = get_fs(); | ||
| 816 | |||
| 817 | if (set) { | ||
| 818 | if (get_sigset_t(&s, set)) | ||
| 819 | return -EFAULT; | ||
| 820 | } | ||
| 821 | |||
| 822 | set_fs(KERNEL_DS); | ||
| 823 | /* This is valid because of the set_fs() */ | ||
| 824 | up = (sigset_t __user *) &s; | ||
| 825 | ret = sys_rt_sigprocmask(how, set ? up : NULL, oset ? up : NULL, | ||
| 826 | sigsetsize); | ||
| 827 | set_fs(old_fs); | ||
| 828 | if (ret) | ||
| 829 | return ret; | ||
| 830 | if (oset) { | ||
| 831 | if (put_sigset_t(oset, &s)) | ||
| 832 | return -EFAULT; | ||
| 833 | } | ||
| 834 | return 0; | ||
| 835 | } | ||
| 836 | |||
| 837 | asmlinkage int compat_sys_rt_sigpending(compat_sigset_t __user *set, | ||
| 838 | compat_size_t sigsetsize) | ||
| 839 | { | ||
| 840 | sigset_t s; | ||
| 841 | int ret; | ||
| 842 | mm_segment_t old_fs = get_fs(); | ||
| 843 | |||
| 844 | set_fs(KERNEL_DS); | ||
| 845 | /* The __user pointer cast is valid because of the set_fs() */ | ||
| 846 | ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize); | ||
| 847 | set_fs(old_fs); | ||
| 848 | if (!ret) { | ||
| 849 | if (put_sigset_t(set, &s)) | ||
| 850 | return -EFAULT; | ||
| 851 | } | ||
| 852 | return ret; | ||
| 853 | } | ||
| 854 | |||
| 855 | asmlinkage int compat_sys_rt_sigqueueinfo(int pid, int sig, | ||
| 856 | compat_siginfo_t __user *uinfo) | ||
| 857 | { | ||
| 858 | siginfo_t info; | ||
| 859 | int ret; | ||
| 860 | mm_segment_t old_fs = get_fs(); | ||
| 861 | |||
| 862 | ret = copy_siginfo_from_user32(&info, uinfo); | ||
| 863 | if (unlikely(ret)) | ||
| 864 | return ret; | ||
| 865 | |||
| 866 | set_fs (KERNEL_DS); | ||
| 867 | /* The __user pointer cast is valid because of the set_fs() */ | ||
| 868 | ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info); | ||
| 869 | set_fs (old_fs); | ||
| 870 | return ret; | ||
| 871 | } | ||
| 872 | |||
| 873 | void compat_setup_restart_syscall(struct pt_regs *regs) | ||
| 874 | { | ||
| 875 | regs->regs[7] = __NR_restart_syscall; | ||
| 876 | } | ||
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c new file mode 100644 index 000000000000..b711525be21f --- /dev/null +++ b/arch/arm64/kernel/smp.c | |||
| @@ -0,0 +1,469 @@ | |||
| 1 | /* | ||
| 2 | * SMP initialisation and IPI support | ||
| 3 | * Based on arch/arm/kernel/smp.c | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/cache.h> | ||
| 26 | #include <linux/profile.h> | ||
| 27 | #include <linux/errno.h> | ||
| 28 | #include <linux/mm.h> | ||
| 29 | #include <linux/err.h> | ||
| 30 | #include <linux/cpu.h> | ||
| 31 | #include <linux/smp.h> | ||
| 32 | #include <linux/seq_file.h> | ||
| 33 | #include <linux/irq.h> | ||
| 34 | #include <linux/percpu.h> | ||
| 35 | #include <linux/clockchips.h> | ||
| 36 | #include <linux/completion.h> | ||
| 37 | #include <linux/of.h> | ||
| 38 | |||
| 39 | #include <asm/atomic.h> | ||
| 40 | #include <asm/cacheflush.h> | ||
| 41 | #include <asm/cputype.h> | ||
| 42 | #include <asm/mmu_context.h> | ||
| 43 | #include <asm/pgtable.h> | ||
| 44 | #include <asm/pgalloc.h> | ||
| 45 | #include <asm/processor.h> | ||
| 46 | #include <asm/sections.h> | ||
| 47 | #include <asm/tlbflush.h> | ||
| 48 | #include <asm/ptrace.h> | ||
| 49 | #include <asm/mmu_context.h> | ||
| 50 | |||
| 51 | /* | ||
| 52 | * as from 2.5, kernels no longer have an init_tasks structure | ||
| 53 | * so we need some other way of telling a new secondary core | ||
| 54 | * where to place its SVC stack | ||
| 55 | */ | ||
| 56 | struct secondary_data secondary_data; | ||
| 57 | volatile unsigned long secondary_holding_pen_release = -1; | ||
| 58 | |||
| 59 | enum ipi_msg_type { | ||
| 60 | IPI_RESCHEDULE, | ||
| 61 | IPI_CALL_FUNC, | ||
| 62 | IPI_CALL_FUNC_SINGLE, | ||
| 63 | IPI_CPU_STOP, | ||
| 64 | }; | ||
| 65 | |||
| 66 | static DEFINE_RAW_SPINLOCK(boot_lock); | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Write secondary_holding_pen_release in a way that is guaranteed to be | ||
| 70 | * visible to all observers, irrespective of whether they're taking part | ||
| 71 | * in coherency or not. This is necessary for the hotplug code to work | ||
| 72 | * reliably. | ||
| 73 | */ | ||
| 74 | static void __cpuinit write_pen_release(int val) | ||
| 75 | { | ||
| 76 | void *start = (void *)&secondary_holding_pen_release; | ||
| 77 | unsigned long size = sizeof(secondary_holding_pen_release); | ||
| 78 | |||
| 79 | secondary_holding_pen_release = val; | ||
| 80 | __flush_dcache_area(start, size); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Boot a secondary CPU, and assign it the specified idle task. | ||
| 85 | * This also gives us the initial stack to use for this CPU. | ||
| 86 | */ | ||
| 87 | static int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
| 88 | { | ||
| 89 | unsigned long timeout; | ||
| 90 | |||
| 91 | /* | ||
| 92 | * Set synchronisation state between this boot processor | ||
| 93 | * and the secondary one | ||
| 94 | */ | ||
| 95 | raw_spin_lock(&boot_lock); | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Update the pen release flag. | ||
| 99 | */ | ||
| 100 | write_pen_release(cpu); | ||
| 101 | |||
| 102 | /* | ||
| 103 | * Send an event, causing the secondaries to read pen_release. | ||
| 104 | */ | ||
| 105 | sev(); | ||
| 106 | |||
| 107 | timeout = jiffies + (1 * HZ); | ||
| 108 | while (time_before(jiffies, timeout)) { | ||
| 109 | if (secondary_holding_pen_release == -1UL) | ||
| 110 | break; | ||
| 111 | udelay(10); | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 115 | * Now the secondary core is starting up let it run its | ||
| 116 | * calibrations, then wait for it to finish | ||
| 117 | */ | ||
| 118 | raw_spin_unlock(&boot_lock); | ||
| 119 | |||
| 120 | return secondary_holding_pen_release != -1 ? -ENOSYS : 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static DECLARE_COMPLETION(cpu_running); | ||
| 124 | |||
| 125 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle) | ||
| 126 | { | ||
| 127 | int ret; | ||
| 128 | |||
| 129 | /* | ||
| 130 | * We need to tell the secondary core where to find its stack and the | ||
| 131 | * page tables. | ||
| 132 | */ | ||
| 133 | secondary_data.stack = task_stack_page(idle) + THREAD_START_SP; | ||
| 134 | __flush_dcache_area(&secondary_data, sizeof(secondary_data)); | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Now bring the CPU into our world. | ||
| 138 | */ | ||
| 139 | ret = boot_secondary(cpu, idle); | ||
| 140 | if (ret == 0) { | ||
| 141 | /* | ||
| 142 | * CPU was successfully started, wait for it to come online or | ||
| 143 | * time out. | ||
| 144 | */ | ||
| 145 | wait_for_completion_timeout(&cpu_running, | ||
| 146 | msecs_to_jiffies(1000)); | ||
| 147 | |||
| 148 | if (!cpu_online(cpu)) { | ||
| 149 | pr_crit("CPU%u: failed to come online\n", cpu); | ||
| 150 | ret = -EIO; | ||
| 151 | } | ||
| 152 | } else { | ||
| 153 | pr_err("CPU%u: failed to boot: %d\n", cpu, ret); | ||
| 154 | } | ||
| 155 | |||
| 156 | secondary_data.stack = NULL; | ||
| 157 | |||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | |||
| 161 | /* | ||
| 162 | * This is the secondary CPU boot entry. We're using this CPUs | ||
| 163 | * idle thread stack, but a set of temporary page tables. | ||
| 164 | */ | ||
| 165 | asmlinkage void __cpuinit secondary_start_kernel(void) | ||
| 166 | { | ||
| 167 | struct mm_struct *mm = &init_mm; | ||
| 168 | unsigned int cpu = smp_processor_id(); | ||
| 169 | |||
| 170 | printk("CPU%u: Booted secondary processor\n", cpu); | ||
| 171 | |||
| 172 | /* | ||
| 173 | * All kernel threads share the same mm context; grab a | ||
| 174 | * reference and switch to it. | ||
| 175 | */ | ||
| 176 | atomic_inc(&mm->mm_count); | ||
| 177 | current->active_mm = mm; | ||
| 178 | cpumask_set_cpu(cpu, mm_cpumask(mm)); | ||
| 179 | |||
| 180 | /* | ||
| 181 | * TTBR0 is only used for the identity mapping at this stage. Make it | ||
| 182 | * point to zero page to avoid speculatively fetching new entries. | ||
| 183 | */ | ||
| 184 | cpu_set_reserved_ttbr0(); | ||
| 185 | flush_tlb_all(); | ||
| 186 | |||
| 187 | preempt_disable(); | ||
| 188 | trace_hardirqs_off(); | ||
| 189 | |||
| 190 | /* | ||
| 191 | * Let the primary processor know we're out of the | ||
| 192 | * pen, then head off into the C entry point | ||
| 193 | */ | ||
| 194 | write_pen_release(-1); | ||
| 195 | |||
| 196 | /* | ||
| 197 | * Synchronise with the boot thread. | ||
| 198 | */ | ||
| 199 | raw_spin_lock(&boot_lock); | ||
| 200 | raw_spin_unlock(&boot_lock); | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Enable local interrupts. | ||
| 204 | */ | ||
| 205 | notify_cpu_starting(cpu); | ||
| 206 | local_irq_enable(); | ||
| 207 | local_fiq_enable(); | ||
| 208 | |||
| 209 | /* | ||
| 210 | * OK, now it's safe to let the boot CPU continue. Wait for | ||
| 211 | * the CPU migration code to notice that the CPU is online | ||
| 212 | * before we continue. | ||
| 213 | */ | ||
| 214 | set_cpu_online(cpu, true); | ||
| 215 | while (!cpu_active(cpu)) | ||
| 216 | cpu_relax(); | ||
| 217 | |||
| 218 | /* | ||
| 219 | * OK, it's off to the idle thread for us | ||
| 220 | */ | ||
| 221 | cpu_idle(); | ||
| 222 | } | ||
| 223 | |||
| 224 | void __init smp_cpus_done(unsigned int max_cpus) | ||
| 225 | { | ||
| 226 | unsigned long bogosum = loops_per_jiffy * num_online_cpus(); | ||
| 227 | |||
| 228 | pr_info("SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", | ||
| 229 | num_online_cpus(), bogosum / (500000/HZ), | ||
| 230 | (bogosum / (5000/HZ)) % 100); | ||
| 231 | } | ||
| 232 | |||
| 233 | void __init smp_prepare_boot_cpu(void) | ||
| 234 | { | ||
| 235 | } | ||
| 236 | |||
| 237 | static void (*smp_cross_call)(const struct cpumask *, unsigned int); | ||
| 238 | static phys_addr_t cpu_release_addr[NR_CPUS]; | ||
| 239 | |||
| 240 | /* | ||
| 241 | * Enumerate the possible CPU set from the device tree. | ||
| 242 | */ | ||
| 243 | void __init smp_init_cpus(void) | ||
| 244 | { | ||
| 245 | const char *enable_method; | ||
| 246 | struct device_node *dn = NULL; | ||
| 247 | int cpu = 0; | ||
| 248 | |||
| 249 | while ((dn = of_find_node_by_type(dn, "cpu"))) { | ||
| 250 | if (cpu >= NR_CPUS) | ||
| 251 | goto next; | ||
| 252 | |||
| 253 | /* | ||
| 254 | * We currently support only the "spin-table" enable-method. | ||
| 255 | */ | ||
| 256 | enable_method = of_get_property(dn, "enable-method", NULL); | ||
| 257 | if (!enable_method || strcmp(enable_method, "spin-table")) { | ||
| 258 | pr_err("CPU %d: missing or invalid enable-method property: %s\n", | ||
| 259 | cpu, enable_method); | ||
| 260 | goto next; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* | ||
| 264 | * Determine the address from which the CPU is polling. | ||
| 265 | */ | ||
| 266 | if (of_property_read_u64(dn, "cpu-release-addr", | ||
| 267 | &cpu_release_addr[cpu])) { | ||
| 268 | pr_err("CPU %d: missing or invalid cpu-release-addr property\n", | ||
| 269 | cpu); | ||
| 270 | goto next; | ||
| 271 | } | ||
| 272 | |||
| 273 | set_cpu_possible(cpu, true); | ||
| 274 | next: | ||
| 275 | cpu++; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* sanity check */ | ||
| 279 | if (cpu > NR_CPUS) | ||
| 280 | pr_warning("no. of cores (%d) greater than configured maximum of %d - clipping\n", | ||
| 281 | cpu, NR_CPUS); | ||
| 282 | } | ||
| 283 | |||
| 284 | void __init smp_prepare_cpus(unsigned int max_cpus) | ||
| 285 | { | ||
| 286 | int cpu; | ||
| 287 | void **release_addr; | ||
| 288 | unsigned int ncores = num_possible_cpus(); | ||
| 289 | |||
| 290 | /* | ||
| 291 | * are we trying to boot more cores than exist? | ||
| 292 | */ | ||
| 293 | if (max_cpus > ncores) | ||
| 294 | max_cpus = ncores; | ||
| 295 | |||
| 296 | /* | ||
| 297 | * Initialise the present map (which describes the set of CPUs | ||
| 298 | * actually populated at the present time) and release the | ||
| 299 | * secondaries from the bootloader. | ||
| 300 | */ | ||
| 301 | for_each_possible_cpu(cpu) { | ||
| 302 | if (max_cpus == 0) | ||
| 303 | break; | ||
| 304 | |||
| 305 | if (!cpu_release_addr[cpu]) | ||
| 306 | continue; | ||
| 307 | |||
| 308 | release_addr = __va(cpu_release_addr[cpu]); | ||
| 309 | release_addr[0] = (void *)__pa(secondary_holding_pen); | ||
| 310 | __flush_dcache_area(release_addr, sizeof(release_addr[0])); | ||
| 311 | |||
| 312 | set_cpu_present(cpu, true); | ||
| 313 | max_cpus--; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Send an event to wake up the secondaries. | ||
| 318 | */ | ||
| 319 | sev(); | ||
| 320 | } | ||
| 321 | |||
| 322 | |||
| 323 | void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int)) | ||
| 324 | { | ||
| 325 | smp_cross_call = fn; | ||
| 326 | } | ||
| 327 | |||
| 328 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) | ||
| 329 | { | ||
| 330 | smp_cross_call(mask, IPI_CALL_FUNC); | ||
| 331 | } | ||
| 332 | |||
| 333 | void arch_send_call_function_single_ipi(int cpu) | ||
| 334 | { | ||
| 335 | smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); | ||
| 336 | } | ||
| 337 | |||
| 338 | static const char *ipi_types[NR_IPI] = { | ||
| 339 | #define S(x,s) [x - IPI_RESCHEDULE] = s | ||
| 340 | S(IPI_RESCHEDULE, "Rescheduling interrupts"), | ||
| 341 | S(IPI_CALL_FUNC, "Function call interrupts"), | ||
| 342 | S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"), | ||
| 343 | S(IPI_CPU_STOP, "CPU stop interrupts"), | ||
| 344 | }; | ||
| 345 | |||
| 346 | void show_ipi_list(struct seq_file *p, int prec) | ||
| 347 | { | ||
| 348 | unsigned int cpu, i; | ||
| 349 | |||
| 350 | for (i = 0; i < NR_IPI; i++) { | ||
| 351 | seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i + IPI_RESCHEDULE, | ||
| 352 | prec >= 4 ? " " : ""); | ||
| 353 | for_each_present_cpu(cpu) | ||
| 354 | seq_printf(p, "%10u ", | ||
| 355 | __get_irq_stat(cpu, ipi_irqs[i])); | ||
| 356 | seq_printf(p, " %s\n", ipi_types[i]); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | u64 smp_irq_stat_cpu(unsigned int cpu) | ||
| 361 | { | ||
| 362 | u64 sum = 0; | ||
| 363 | int i; | ||
| 364 | |||
| 365 | for (i = 0; i < NR_IPI; i++) | ||
| 366 | sum += __get_irq_stat(cpu, ipi_irqs[i]); | ||
| 367 | |||
| 368 | return sum; | ||
| 369 | } | ||
| 370 | |||
| 371 | static DEFINE_RAW_SPINLOCK(stop_lock); | ||
| 372 | |||
| 373 | /* | ||
| 374 | * ipi_cpu_stop - handle IPI from smp_send_stop() | ||
| 375 | */ | ||
| 376 | static void ipi_cpu_stop(unsigned int cpu) | ||
| 377 | { | ||
| 378 | if (system_state == SYSTEM_BOOTING || | ||
| 379 | system_state == SYSTEM_RUNNING) { | ||
| 380 | raw_spin_lock(&stop_lock); | ||
| 381 | pr_crit("CPU%u: stopping\n", cpu); | ||
| 382 | dump_stack(); | ||
| 383 | raw_spin_unlock(&stop_lock); | ||
| 384 | } | ||
| 385 | |||
| 386 | set_cpu_online(cpu, false); | ||
| 387 | |||
| 388 | local_fiq_disable(); | ||
| 389 | local_irq_disable(); | ||
| 390 | |||
| 391 | while (1) | ||
| 392 | cpu_relax(); | ||
| 393 | } | ||
| 394 | |||
| 395 | /* | ||
| 396 | * Main handler for inter-processor interrupts | ||
| 397 | */ | ||
| 398 | void handle_IPI(int ipinr, struct pt_regs *regs) | ||
| 399 | { | ||
| 400 | unsigned int cpu = smp_processor_id(); | ||
| 401 | struct pt_regs *old_regs = set_irq_regs(regs); | ||
| 402 | |||
| 403 | if (ipinr >= IPI_RESCHEDULE && ipinr < IPI_RESCHEDULE + NR_IPI) | ||
| 404 | __inc_irq_stat(cpu, ipi_irqs[ipinr - IPI_RESCHEDULE]); | ||
| 405 | |||
| 406 | switch (ipinr) { | ||
| 407 | case IPI_RESCHEDULE: | ||
| 408 | scheduler_ipi(); | ||
| 409 | break; | ||
| 410 | |||
| 411 | case IPI_CALL_FUNC: | ||
| 412 | irq_enter(); | ||
| 413 | generic_smp_call_function_interrupt(); | ||
| 414 | irq_exit(); | ||
| 415 | break; | ||
| 416 | |||
| 417 | case IPI_CALL_FUNC_SINGLE: | ||
| 418 | irq_enter(); | ||
| 419 | generic_smp_call_function_single_interrupt(); | ||
| 420 | irq_exit(); | ||
| 421 | break; | ||
| 422 | |||
| 423 | case IPI_CPU_STOP: | ||
| 424 | irq_enter(); | ||
| 425 | ipi_cpu_stop(cpu); | ||
| 426 | irq_exit(); | ||
| 427 | break; | ||
| 428 | |||
| 429 | default: | ||
| 430 | pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); | ||
| 431 | break; | ||
| 432 | } | ||
| 433 | set_irq_regs(old_regs); | ||
| 434 | } | ||
| 435 | |||
| 436 | void smp_send_reschedule(int cpu) | ||
| 437 | { | ||
| 438 | smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE); | ||
| 439 | } | ||
| 440 | |||
| 441 | void smp_send_stop(void) | ||
| 442 | { | ||
| 443 | unsigned long timeout; | ||
| 444 | |||
| 445 | if (num_online_cpus() > 1) { | ||
| 446 | cpumask_t mask; | ||
| 447 | |||
| 448 | cpumask_copy(&mask, cpu_online_mask); | ||
| 449 | cpu_clear(smp_processor_id(), mask); | ||
| 450 | |||
| 451 | smp_cross_call(&mask, IPI_CPU_STOP); | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Wait up to one second for other CPUs to stop */ | ||
| 455 | timeout = USEC_PER_SEC; | ||
| 456 | while (num_online_cpus() > 1 && timeout--) | ||
| 457 | udelay(1); | ||
| 458 | |||
| 459 | if (num_online_cpus() > 1) | ||
| 460 | pr_warning("SMP: failed to stop secondary CPUs\n"); | ||
| 461 | } | ||
| 462 | |||
| 463 | /* | ||
| 464 | * not supported here | ||
| 465 | */ | ||
| 466 | int setup_profiling_timer(unsigned int multiplier) | ||
| 467 | { | ||
| 468 | return -EINVAL; | ||
| 469 | } | ||
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c new file mode 100644 index 000000000000..d25459ff57fc --- /dev/null +++ b/arch/arm64/kernel/stacktrace.c | |||
| @@ -0,0 +1,127 @@ | |||
| 1 | /* | ||
| 2 | * Stack tracing support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/export.h> | ||
| 20 | #include <linux/sched.h> | ||
| 21 | #include <linux/stacktrace.h> | ||
| 22 | |||
| 23 | #include <asm/stacktrace.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * AArch64 PCS assigns the frame pointer to x29. | ||
| 27 | * | ||
| 28 | * A simple function prologue looks like this: | ||
| 29 | * sub sp, sp, #0x10 | ||
| 30 | * stp x29, x30, [sp] | ||
| 31 | * mov x29, sp | ||
| 32 | * | ||
| 33 | * A simple function epilogue looks like this: | ||
| 34 | * mov sp, x29 | ||
| 35 | * ldp x29, x30, [sp] | ||
| 36 | * add sp, sp, #0x10 | ||
| 37 | */ | ||
| 38 | int unwind_frame(struct stackframe *frame) | ||
| 39 | { | ||
| 40 | unsigned long high, low; | ||
| 41 | unsigned long fp = frame->fp; | ||
| 42 | |||
| 43 | low = frame->sp; | ||
| 44 | high = ALIGN(low, THREAD_SIZE); | ||
| 45 | |||
| 46 | if (fp < low || fp > high || fp & 0xf) | ||
| 47 | return -EINVAL; | ||
| 48 | |||
| 49 | frame->sp = fp + 0x10; | ||
| 50 | frame->fp = *(unsigned long *)(fp); | ||
| 51 | frame->pc = *(unsigned long *)(fp + 8); | ||
| 52 | |||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | void notrace walk_stackframe(struct stackframe *frame, | ||
| 57 | int (*fn)(struct stackframe *, void *), void *data) | ||
| 58 | { | ||
| 59 | while (1) { | ||
| 60 | int ret; | ||
| 61 | |||
| 62 | if (fn(frame, data)) | ||
| 63 | break; | ||
| 64 | ret = unwind_frame(frame); | ||
| 65 | if (ret < 0) | ||
| 66 | break; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL(walk_stackframe); | ||
| 70 | |||
| 71 | #ifdef CONFIG_STACKTRACE | ||
| 72 | struct stack_trace_data { | ||
| 73 | struct stack_trace *trace; | ||
| 74 | unsigned int no_sched_functions; | ||
| 75 | unsigned int skip; | ||
| 76 | }; | ||
| 77 | |||
| 78 | static int save_trace(struct stackframe *frame, void *d) | ||
| 79 | { | ||
| 80 | struct stack_trace_data *data = d; | ||
| 81 | struct stack_trace *trace = data->trace; | ||
| 82 | unsigned long addr = frame->pc; | ||
| 83 | |||
| 84 | if (data->no_sched_functions && in_sched_functions(addr)) | ||
| 85 | return 0; | ||
| 86 | if (data->skip) { | ||
| 87 | data->skip--; | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | trace->entries[trace->nr_entries++] = addr; | ||
| 92 | |||
| 93 | return trace->nr_entries >= trace->max_entries; | ||
| 94 | } | ||
| 95 | |||
| 96 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
| 97 | { | ||
| 98 | struct stack_trace_data data; | ||
| 99 | struct stackframe frame; | ||
| 100 | |||
| 101 | data.trace = trace; | ||
| 102 | data.skip = trace->skip; | ||
| 103 | |||
| 104 | if (tsk != current) { | ||
| 105 | data.no_sched_functions = 1; | ||
| 106 | frame.fp = thread_saved_fp(tsk); | ||
| 107 | frame.sp = thread_saved_sp(tsk); | ||
| 108 | frame.pc = thread_saved_pc(tsk); | ||
| 109 | } else { | ||
| 110 | register unsigned long current_sp asm("sp"); | ||
| 111 | data.no_sched_functions = 0; | ||
| 112 | frame.fp = (unsigned long)__builtin_frame_address(0); | ||
| 113 | frame.sp = current_sp; | ||
| 114 | frame.pc = (unsigned long)save_stack_trace_tsk; | ||
| 115 | } | ||
| 116 | |||
| 117 | walk_stackframe(&frame, save_trace, &data); | ||
| 118 | if (trace->nr_entries < trace->max_entries) | ||
| 119 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
| 120 | } | ||
| 121 | |||
| 122 | void save_stack_trace(struct stack_trace *trace) | ||
| 123 | { | ||
| 124 | save_stack_trace_tsk(current, trace); | ||
| 125 | } | ||
| 126 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
| 127 | #endif | ||
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c new file mode 100644 index 000000000000..905fcfb0ddd0 --- /dev/null +++ b/arch/arm64/kernel/sys.c | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | /* | ||
| 2 | * AArch64-specific system calls implementation | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/compiler.h> | ||
| 21 | #include <linux/errno.h> | ||
| 22 | #include <linux/fs.h> | ||
| 23 | #include <linux/mm.h> | ||
| 24 | #include <linux/export.h> | ||
| 25 | #include <linux/sched.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/syscalls.h> | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Clone a task - this clones the calling program thread. | ||
| 31 | */ | ||
| 32 | asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 33 | int __user *parent_tidptr, unsigned long tls_val, | ||
| 34 | int __user *child_tidptr, struct pt_regs *regs) | ||
| 35 | { | ||
| 36 | if (!newsp) | ||
| 37 | newsp = regs->sp; | ||
| 38 | /* 16-byte aligned stack mandatory on AArch64 */ | ||
| 39 | if (newsp & 15) | ||
| 40 | return -EINVAL; | ||
| 41 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* | ||
| 45 | * sys_execve() executes a new program. | ||
| 46 | */ | ||
| 47 | asmlinkage long sys_execve(const char __user *filenamei, | ||
| 48 | const char __user *const __user *argv, | ||
| 49 | const char __user *const __user *envp, | ||
| 50 | struct pt_regs *regs) | ||
| 51 | { | ||
| 52 | long error; | ||
| 53 | char * filename; | ||
| 54 | |||
| 55 | filename = getname(filenamei); | ||
| 56 | error = PTR_ERR(filename); | ||
| 57 | if (IS_ERR(filename)) | ||
| 58 | goto out; | ||
| 59 | error = do_execve(filename, argv, envp, regs); | ||
| 60 | putname(filename); | ||
| 61 | out: | ||
| 62 | return error; | ||
| 63 | } | ||
| 64 | |||
| 65 | int kernel_execve(const char *filename, | ||
| 66 | const char *const argv[], | ||
| 67 | const char *const envp[]) | ||
| 68 | { | ||
| 69 | struct pt_regs regs; | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | memset(®s, 0, sizeof(struct pt_regs)); | ||
| 73 | ret = do_execve(filename, | ||
| 74 | (const char __user *const __user *)argv, | ||
| 75 | (const char __user *const __user *)envp, ®s); | ||
| 76 | if (ret < 0) | ||
| 77 | goto out; | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Save argc to the register structure for userspace. | ||
| 81 | */ | ||
| 82 | regs.regs[0] = ret; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * We were successful. We won't be returning to our caller, but | ||
| 86 | * instead to user space by manipulating the kernel stack. | ||
| 87 | */ | ||
| 88 | asm( "add x0, %0, %1\n\t" | ||
| 89 | "mov x1, %2\n\t" | ||
| 90 | "mov x2, %3\n\t" | ||
| 91 | "bl memmove\n\t" /* copy regs to top of stack */ | ||
| 92 | "mov x27, #0\n\t" /* not a syscall */ | ||
| 93 | "mov x28, %0\n\t" /* thread structure */ | ||
| 94 | "mov sp, x0\n\t" /* reposition stack pointer */ | ||
| 95 | "b ret_to_user" | ||
| 96 | : | ||
| 97 | : "r" (current_thread_info()), | ||
| 98 | "Ir" (THREAD_START_SP - sizeof(regs)), | ||
| 99 | "r" (®s), | ||
| 100 | "Ir" (sizeof(regs)) | ||
| 101 | : "x0", "x1", "x2", "x27", "x28", "x30", "memory"); | ||
| 102 | |||
| 103 | out: | ||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | EXPORT_SYMBOL(kernel_execve); | ||
| 107 | |||
| 108 | asmlinkage long sys_mmap(unsigned long addr, unsigned long len, | ||
| 109 | unsigned long prot, unsigned long flags, | ||
| 110 | unsigned long fd, off_t off) | ||
| 111 | { | ||
| 112 | if (offset_in_page(off) != 0) | ||
| 113 | return -EINVAL; | ||
| 114 | |||
| 115 | return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); | ||
| 116 | } | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Wrappers to pass the pt_regs argument. | ||
| 120 | */ | ||
| 121 | #define sys_execve sys_execve_wrapper | ||
| 122 | #define sys_clone sys_clone_wrapper | ||
| 123 | #define sys_rt_sigreturn sys_rt_sigreturn_wrapper | ||
| 124 | #define sys_sigaltstack sys_sigaltstack_wrapper | ||
| 125 | |||
| 126 | #include <asm/syscalls.h> | ||
| 127 | |||
| 128 | #undef __SYSCALL | ||
| 129 | #define __SYSCALL(nr, sym) [nr] = sym, | ||
| 130 | |||
| 131 | /* | ||
| 132 | * The sys_call_table array must be 4K aligned to be accessible from | ||
| 133 | * kernel/entry.S. | ||
| 134 | */ | ||
| 135 | void *sys_call_table[__NR_syscalls] __aligned(4096) = { | ||
| 136 | [0 ... __NR_syscalls - 1] = sys_ni_syscall, | ||
| 137 | #include <asm/unistd.h> | ||
| 138 | }; | ||
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S new file mode 100644 index 000000000000..5e4dc93cc31f --- /dev/null +++ b/arch/arm64/kernel/sys32.S | |||
| @@ -0,0 +1,282 @@ | |||
| 1 | /* | ||
| 2 | * Compat system call wrappers | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Authors: Will Deacon <will.deacon@arm.com> | ||
| 6 | * Catalin Marinas <catalin.marinas@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/linkage.h> | ||
| 22 | |||
| 23 | #include <asm/assembler.h> | ||
| 24 | #include <asm/asm-offsets.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * System call wrappers for the AArch32 compatibility layer. | ||
| 28 | */ | ||
| 29 | compat_sys_fork_wrapper: | ||
| 30 | mov x0, sp | ||
| 31 | b compat_sys_fork | ||
| 32 | ENDPROC(compat_sys_fork_wrapper) | ||
| 33 | |||
| 34 | compat_sys_vfork_wrapper: | ||
| 35 | mov x0, sp | ||
| 36 | b compat_sys_vfork | ||
| 37 | ENDPROC(compat_sys_vfork_wrapper) | ||
| 38 | |||
| 39 | compat_sys_execve_wrapper: | ||
| 40 | mov x3, sp | ||
| 41 | b compat_sys_execve | ||
| 42 | ENDPROC(compat_sys_execve_wrapper) | ||
| 43 | |||
| 44 | compat_sys_clone_wrapper: | ||
| 45 | mov x5, sp | ||
| 46 | b compat_sys_clone | ||
| 47 | ENDPROC(compat_sys_clone_wrapper) | ||
| 48 | |||
| 49 | compat_sys_sigreturn_wrapper: | ||
| 50 | mov x0, sp | ||
| 51 | mov x27, #0 // prevent syscall restart handling (why) | ||
| 52 | b compat_sys_sigreturn | ||
| 53 | ENDPROC(compat_sys_sigreturn_wrapper) | ||
| 54 | |||
| 55 | compat_sys_rt_sigreturn_wrapper: | ||
| 56 | mov x0, sp | ||
| 57 | mov x27, #0 // prevent syscall restart handling (why) | ||
| 58 | b compat_sys_rt_sigreturn | ||
| 59 | ENDPROC(compat_sys_rt_sigreturn_wrapper) | ||
| 60 | |||
| 61 | compat_sys_sigaltstack_wrapper: | ||
| 62 | ldr x2, [sp, #S_COMPAT_SP] | ||
| 63 | b compat_do_sigaltstack | ||
| 64 | ENDPROC(compat_sys_sigaltstack_wrapper) | ||
| 65 | |||
| 66 | compat_sys_statfs64_wrapper: | ||
| 67 | mov w3, #84 | ||
| 68 | cmp w1, #88 | ||
| 69 | csel w1, w3, w1, eq | ||
| 70 | b compat_sys_statfs64 | ||
| 71 | ENDPROC(compat_sys_statfs64_wrapper) | ||
| 72 | |||
| 73 | compat_sys_fstatfs64_wrapper: | ||
| 74 | mov w3, #84 | ||
| 75 | cmp w1, #88 | ||
| 76 | csel w1, w3, w1, eq | ||
| 77 | b compat_sys_fstatfs64 | ||
| 78 | ENDPROC(compat_sys_fstatfs64_wrapper) | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Wrappers for AArch32 syscalls that either take 64-bit parameters | ||
| 82 | * in registers or that take 32-bit parameters which require sign | ||
| 83 | * extension. | ||
| 84 | */ | ||
| 85 | compat_sys_lseek_wrapper: | ||
| 86 | sxtw x1, w1 | ||
| 87 | b sys_lseek | ||
| 88 | ENDPROC(compat_sys_lseek_wrapper) | ||
| 89 | |||
| 90 | compat_sys_pread64_wrapper: | ||
| 91 | orr x3, x4, x5, lsl #32 | ||
| 92 | b sys_pread64 | ||
| 93 | ENDPROC(compat_sys_pread64_wrapper) | ||
| 94 | |||
| 95 | compat_sys_pwrite64_wrapper: | ||
| 96 | orr x3, x4, x5, lsl #32 | ||
| 97 | b sys_pwrite64 | ||
| 98 | ENDPROC(compat_sys_pwrite64_wrapper) | ||
| 99 | |||
| 100 | compat_sys_truncate64_wrapper: | ||
| 101 | orr x1, x2, x3, lsl #32 | ||
| 102 | b sys_truncate | ||
| 103 | ENDPROC(compat_sys_truncate64_wrapper) | ||
| 104 | |||
| 105 | compat_sys_ftruncate64_wrapper: | ||
| 106 | orr x1, x2, x3, lsl #32 | ||
| 107 | b sys_ftruncate | ||
| 108 | ENDPROC(compat_sys_ftruncate64_wrapper) | ||
| 109 | |||
| 110 | compat_sys_readahead_wrapper: | ||
| 111 | orr x1, x2, x3, lsl #32 | ||
| 112 | mov w2, w4 | ||
| 113 | b sys_readahead | ||
| 114 | ENDPROC(compat_sys_readahead_wrapper) | ||
| 115 | |||
| 116 | compat_sys_lookup_dcookie: | ||
| 117 | orr x0, x0, x1, lsl #32 | ||
| 118 | mov w1, w2 | ||
| 119 | mov w2, w3 | ||
| 120 | b sys_lookup_dcookie | ||
| 121 | ENDPROC(compat_sys_lookup_dcookie) | ||
| 122 | |||
| 123 | compat_sys_fadvise64_64_wrapper: | ||
| 124 | mov w6, w1 | ||
| 125 | orr x1, x2, x3, lsl #32 | ||
| 126 | orr x2, x4, x5, lsl #32 | ||
| 127 | mov w3, w6 | ||
| 128 | b sys_fadvise64_64 | ||
| 129 | ENDPROC(compat_sys_fadvise64_64_wrapper) | ||
| 130 | |||
| 131 | compat_sys_sync_file_range2_wrapper: | ||
| 132 | orr x2, x2, x3, lsl #32 | ||
| 133 | orr x3, x4, x5, lsl #32 | ||
| 134 | b sys_sync_file_range2 | ||
| 135 | ENDPROC(compat_sys_sync_file_range2_wrapper) | ||
| 136 | |||
| 137 | compat_sys_fallocate_wrapper: | ||
| 138 | orr x2, x2, x3, lsl #32 | ||
| 139 | orr x3, x4, x5, lsl #32 | ||
| 140 | b sys_fallocate | ||
| 141 | ENDPROC(compat_sys_fallocate_wrapper) | ||
| 142 | |||
| 143 | compat_sys_fanotify_mark_wrapper: | ||
| 144 | orr x2, x2, x3, lsl #32 | ||
| 145 | mov w3, w4 | ||
| 146 | mov w4, w5 | ||
| 147 | b sys_fanotify_mark | ||
| 148 | ENDPROC(compat_sys_fanotify_mark_wrapper) | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Use the compat system call wrappers. | ||
| 152 | */ | ||
| 153 | #define sys_fork compat_sys_fork_wrapper | ||
| 154 | #define sys_open compat_sys_open | ||
| 155 | #define sys_execve compat_sys_execve_wrapper | ||
| 156 | #define sys_lseek compat_sys_lseek_wrapper | ||
| 157 | #define sys_mount compat_sys_mount | ||
| 158 | #define sys_ptrace compat_sys_ptrace | ||
| 159 | #define sys_times compat_sys_times | ||
| 160 | #define sys_ioctl compat_sys_ioctl | ||
| 161 | #define sys_fcntl compat_sys_fcntl | ||
| 162 | #define sys_ustat compat_sys_ustat | ||
| 163 | #define sys_sigaction compat_sys_sigaction | ||
| 164 | #define sys_sigsuspend compat_sys_sigsuspend | ||
| 165 | #define sys_sigpending compat_sys_sigpending | ||
| 166 | #define sys_setrlimit compat_sys_setrlimit | ||
| 167 | #define sys_getrusage compat_sys_getrusage | ||
| 168 | #define sys_gettimeofday compat_sys_gettimeofday | ||
| 169 | #define sys_settimeofday compat_sys_settimeofday | ||
| 170 | #define sys_statfs compat_sys_statfs | ||
| 171 | #define sys_fstatfs compat_sys_fstatfs | ||
| 172 | #define sys_setitimer compat_sys_setitimer | ||
| 173 | #define sys_getitimer compat_sys_getitimer | ||
| 174 | #define sys_newstat compat_sys_newstat | ||
| 175 | #define sys_newlstat compat_sys_newlstat | ||
| 176 | #define sys_newfstat compat_sys_newfstat | ||
| 177 | #define sys_wait4 compat_sys_wait4 | ||
| 178 | #define sys_sysinfo compat_sys_sysinfo | ||
| 179 | #define sys_sigreturn compat_sys_sigreturn_wrapper | ||
| 180 | #define sys_clone compat_sys_clone_wrapper | ||
| 181 | #define sys_adjtimex compat_sys_adjtimex | ||
| 182 | #define sys_sigprocmask compat_sys_sigprocmask | ||
| 183 | #define sys_getdents compat_sys_getdents | ||
| 184 | #define sys_select compat_sys_select | ||
| 185 | #define sys_readv compat_sys_readv | ||
| 186 | #define sys_writev compat_sys_writev | ||
| 187 | #define sys_sysctl compat_sys_sysctl | ||
| 188 | #define sys_sched_rr_get_interval compat_sys_sched_rr_get_interval | ||
| 189 | #define sys_nanosleep compat_sys_nanosleep | ||
| 190 | #define sys_rt_sigreturn compat_sys_rt_sigreturn_wrapper | ||
| 191 | #define sys_rt_sigaction compat_sys_rt_sigaction | ||
| 192 | #define sys_rt_sigprocmask compat_sys_rt_sigprocmask | ||
| 193 | #define sys_rt_sigpending compat_sys_rt_sigpending | ||
| 194 | #define sys_rt_sigtimedwait compat_sys_rt_sigtimedwait | ||
| 195 | #define sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo | ||
| 196 | #define sys_rt_sigsuspend compat_sys_rt_sigsuspend | ||
| 197 | #define sys_pread64 compat_sys_pread64_wrapper | ||
| 198 | #define sys_pwrite64 compat_sys_pwrite64_wrapper | ||
| 199 | #define sys_sigaltstack compat_sys_sigaltstack_wrapper | ||
| 200 | #define sys_sendfile compat_sys_sendfile | ||
| 201 | #define sys_vfork compat_sys_vfork_wrapper | ||
| 202 | #define sys_getrlimit compat_sys_getrlimit | ||
| 203 | #define sys_mmap2 sys_mmap_pgoff | ||
| 204 | #define sys_truncate64 compat_sys_truncate64_wrapper | ||
| 205 | #define sys_ftruncate64 compat_sys_ftruncate64_wrapper | ||
| 206 | #define sys_getdents64 compat_sys_getdents64 | ||
| 207 | #define sys_fcntl64 compat_sys_fcntl64 | ||
| 208 | #define sys_readahead compat_sys_readahead_wrapper | ||
| 209 | #define sys_futex compat_sys_futex | ||
| 210 | #define sys_sched_setaffinity compat_sys_sched_setaffinity | ||
| 211 | #define sys_sched_getaffinity compat_sys_sched_getaffinity | ||
| 212 | #define sys_io_setup compat_sys_io_setup | ||
| 213 | #define sys_io_getevents compat_sys_io_getevents | ||
| 214 | #define sys_io_submit compat_sys_io_submit | ||
| 215 | #define sys_lookup_dcookie compat_sys_lookup_dcookie | ||
| 216 | #define sys_timer_create compat_sys_timer_create | ||
| 217 | #define sys_timer_settime compat_sys_timer_settime | ||
| 218 | #define sys_timer_gettime compat_sys_timer_gettime | ||
| 219 | #define sys_clock_settime compat_sys_clock_settime | ||
| 220 | #define sys_clock_gettime compat_sys_clock_gettime | ||
| 221 | #define sys_clock_getres compat_sys_clock_getres | ||
| 222 | #define sys_clock_nanosleep compat_sys_clock_nanosleep | ||
| 223 | #define sys_statfs64 compat_sys_statfs64_wrapper | ||
| 224 | #define sys_fstatfs64 compat_sys_fstatfs64_wrapper | ||
| 225 | #define sys_utimes compat_sys_utimes | ||
| 226 | #define sys_fadvise64_64 compat_sys_fadvise64_64_wrapper | ||
| 227 | #define sys_mq_open compat_sys_mq_open | ||
| 228 | #define sys_mq_timedsend compat_sys_mq_timedsend | ||
| 229 | #define sys_mq_timedreceive compat_sys_mq_timedreceive | ||
| 230 | #define sys_mq_notify compat_sys_mq_notify | ||
| 231 | #define sys_mq_getsetattr compat_sys_mq_getsetattr | ||
| 232 | #define sys_waitid compat_sys_waitid | ||
| 233 | #define sys_recv compat_sys_recv | ||
| 234 | #define sys_recvfrom compat_sys_recvfrom | ||
| 235 | #define sys_setsockopt compat_sys_setsockopt | ||
| 236 | #define sys_getsockopt compat_sys_getsockopt | ||
| 237 | #define sys_sendmsg compat_sys_sendmsg | ||
| 238 | #define sys_recvmsg compat_sys_recvmsg | ||
| 239 | #define sys_semctl compat_sys_semctl | ||
| 240 | #define sys_msgsnd compat_sys_msgsnd | ||
| 241 | #define sys_msgrcv compat_sys_msgrcv | ||
| 242 | #define sys_msgctl compat_sys_msgctl | ||
| 243 | #define sys_shmat compat_sys_shmat | ||
| 244 | #define sys_shmctl compat_sys_shmctl | ||
| 245 | #define sys_keyctl compat_sys_keyctl | ||
| 246 | #define sys_semtimedop compat_sys_semtimedop | ||
| 247 | #define sys_mbind compat_sys_mbind | ||
| 248 | #define sys_get_mempolicy compat_sys_get_mempolicy | ||
| 249 | #define sys_set_mempolicy compat_sys_set_mempolicy | ||
| 250 | #define sys_openat compat_sys_openat | ||
| 251 | #define sys_futimesat compat_sys_futimesat | ||
| 252 | #define sys_pselect6 compat_sys_pselect6 | ||
| 253 | #define sys_ppoll compat_sys_ppoll | ||
| 254 | #define sys_set_robust_list compat_sys_set_robust_list | ||
| 255 | #define sys_get_robust_list compat_sys_get_robust_list | ||
| 256 | #define sys_sync_file_range2 compat_sys_sync_file_range2_wrapper | ||
| 257 | #define sys_vmsplice compat_sys_vmsplice | ||
| 258 | #define sys_move_pages compat_sys_move_pages | ||
| 259 | #define sys_epoll_pwait compat_sys_epoll_pwait | ||
| 260 | #define sys_kexec_load compat_sys_kexec_load | ||
| 261 | #define sys_utimensat compat_sys_utimensat | ||
| 262 | #define sys_signalfd compat_sys_signalfd | ||
| 263 | #define sys_fallocate compat_sys_fallocate_wrapper | ||
| 264 | #define sys_timerfd_settime compat_sys_timerfd_settime | ||
| 265 | #define sys_timerfd_gettime compat_sys_timerfd_gettime | ||
| 266 | #define sys_signalfd4 compat_sys_signalfd4 | ||
| 267 | #define sys_preadv compat_sys_preadv | ||
| 268 | #define sys_pwritev compat_sys_pwritev | ||
| 269 | #define sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo | ||
| 270 | #define sys_recvmmsg compat_sys_recvmmsg | ||
| 271 | #define sys_fanotify_mark compat_sys_fanotify_mark_wrapper | ||
| 272 | |||
| 273 | #undef __SYSCALL | ||
| 274 | #define __SYSCALL(x, y) .quad y // x | ||
| 275 | #define __SYSCALL_COMPAT | ||
| 276 | |||
| 277 | /* | ||
| 278 | * The system calls table must be 4KB aligned. | ||
| 279 | */ | ||
| 280 | .align 12 | ||
| 281 | ENTRY(compat_sys_call_table) | ||
| 282 | #include <asm/unistd.h> | ||
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c new file mode 100644 index 000000000000..967e92fdff01 --- /dev/null +++ b/arch/arm64/kernel/sys_compat.c | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/sys_arm.c | ||
| 3 | * | ||
| 4 | * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c | ||
| 5 | * Copyright (C) 1995, 1996 Russell King. | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define __SYSCALL_COMPAT | ||
| 22 | |||
| 23 | #include <linux/compat.h> | ||
| 24 | #include <linux/personality.h> | ||
| 25 | #include <linux/sched.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/syscalls.h> | ||
| 28 | #include <linux/uaccess.h> | ||
| 29 | |||
| 30 | #include <asm/cacheflush.h> | ||
| 31 | #include <asm/unistd.h> | ||
| 32 | |||
| 33 | asmlinkage int compat_sys_fork(struct pt_regs *regs) | ||
| 34 | { | ||
| 35 | return do_fork(SIGCHLD, regs->compat_sp, regs, 0, NULL, NULL); | ||
| 36 | } | ||
| 37 | |||
| 38 | asmlinkage int compat_sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
| 39 | int __user *parent_tidptr, int tls_val, | ||
| 40 | int __user *child_tidptr, struct pt_regs *regs) | ||
| 41 | { | ||
| 42 | if (!newsp) | ||
| 43 | newsp = regs->compat_sp; | ||
| 44 | |||
| 45 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | ||
| 46 | } | ||
| 47 | |||
| 48 | asmlinkage int compat_sys_vfork(struct pt_regs *regs) | ||
| 49 | { | ||
| 50 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->compat_sp, | ||
| 51 | regs, 0, NULL, NULL); | ||
| 52 | } | ||
| 53 | |||
| 54 | asmlinkage int compat_sys_execve(const char __user *filenamei, | ||
| 55 | compat_uptr_t argv, compat_uptr_t envp, | ||
| 56 | struct pt_regs *regs) | ||
| 57 | { | ||
| 58 | int error; | ||
| 59 | char * filename; | ||
| 60 | |||
| 61 | filename = getname(filenamei); | ||
| 62 | error = PTR_ERR(filename); | ||
| 63 | if (IS_ERR(filename)) | ||
| 64 | goto out; | ||
| 65 | error = compat_do_execve(filename, compat_ptr(argv), compat_ptr(envp), | ||
| 66 | regs); | ||
| 67 | putname(filename); | ||
| 68 | out: | ||
| 69 | return error; | ||
| 70 | } | ||
| 71 | |||
| 72 | asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid, | ||
| 73 | struct compat_timespec __user *interval) | ||
| 74 | { | ||
| 75 | struct timespec t; | ||
| 76 | int ret; | ||
| 77 | mm_segment_t old_fs = get_fs(); | ||
| 78 | |||
| 79 | set_fs(KERNEL_DS); | ||
| 80 | ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t); | ||
| 81 | set_fs(old_fs); | ||
| 82 | if (put_compat_timespec(&t, interval)) | ||
| 83 | return -EFAULT; | ||
| 84 | return ret; | ||
| 85 | } | ||
| 86 | |||
| 87 | asmlinkage int compat_sys_sendfile(int out_fd, int in_fd, | ||
| 88 | compat_off_t __user *offset, s32 count) | ||
| 89 | { | ||
| 90 | mm_segment_t old_fs = get_fs(); | ||
| 91 | int ret; | ||
| 92 | off_t of; | ||
| 93 | |||
| 94 | if (offset && get_user(of, offset)) | ||
| 95 | return -EFAULT; | ||
| 96 | |||
| 97 | set_fs(KERNEL_DS); | ||
| 98 | ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, | ||
| 99 | count); | ||
| 100 | set_fs(old_fs); | ||
| 101 | |||
| 102 | if (offset && put_user(of, offset)) | ||
| 103 | return -EFAULT; | ||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline void | ||
| 108 | do_compat_cache_op(unsigned long start, unsigned long end, int flags) | ||
| 109 | { | ||
| 110 | struct mm_struct *mm = current->active_mm; | ||
| 111 | struct vm_area_struct *vma; | ||
| 112 | |||
| 113 | if (end < start || flags) | ||
| 114 | return; | ||
| 115 | |||
| 116 | down_read(&mm->mmap_sem); | ||
| 117 | vma = find_vma(mm, start); | ||
| 118 | if (vma && vma->vm_start < end) { | ||
| 119 | if (start < vma->vm_start) | ||
| 120 | start = vma->vm_start; | ||
| 121 | if (end > vma->vm_end) | ||
| 122 | end = vma->vm_end; | ||
| 123 | up_read(&mm->mmap_sem); | ||
| 124 | __flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end)); | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | up_read(&mm->mmap_sem); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * Handle all unrecognised system calls. | ||
| 132 | */ | ||
| 133 | long compat_arm_syscall(struct pt_regs *regs) | ||
| 134 | { | ||
| 135 | unsigned int no = regs->regs[7]; | ||
| 136 | |||
| 137 | switch (no) { | ||
| 138 | /* | ||
| 139 | * Flush a region from virtual address 'r0' to virtual address 'r1' | ||
| 140 | * _exclusive_. There is no alignment requirement on either address; | ||
| 141 | * user space does not need to know the hardware cache layout. | ||
| 142 | * | ||
| 143 | * r2 contains flags. It should ALWAYS be passed as ZERO until it | ||
| 144 | * is defined to be something else. For now we ignore it, but may | ||
| 145 | * the fires of hell burn in your belly if you break this rule. ;) | ||
| 146 | * | ||
| 147 | * (at a later date, we may want to allow this call to not flush | ||
| 148 | * various aspects of the cache. Passing '0' will guarantee that | ||
| 149 | * everything necessary gets flushed to maintain consistency in | ||
| 150 | * the specified region). | ||
| 151 | */ | ||
| 152 | case __ARM_NR_compat_cacheflush: | ||
| 153 | do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]); | ||
| 154 | return 0; | ||
| 155 | |||
| 156 | case __ARM_NR_compat_set_tls: | ||
| 157 | current->thread.tp_value = regs->regs[0]; | ||
| 158 | asm ("msr tpidrro_el0, %0" : : "r" (regs->regs[0])); | ||
| 159 | return 0; | ||
| 160 | |||
| 161 | default: | ||
| 162 | return -ENOSYS; | ||
| 163 | } | ||
| 164 | } | ||
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c new file mode 100644 index 000000000000..3b4b7258f492 --- /dev/null +++ b/arch/arm64/kernel/time.c | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/time.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
| 5 | * Modifications for ARM (C) 1994-2001 Russell King | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/export.h> | ||
| 22 | #include <linux/kernel.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/time.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/sched.h> | ||
| 27 | #include <linux/smp.h> | ||
| 28 | #include <linux/timex.h> | ||
| 29 | #include <linux/errno.h> | ||
| 30 | #include <linux/profile.h> | ||
| 31 | #include <linux/syscore_ops.h> | ||
| 32 | #include <linux/timer.h> | ||
| 33 | #include <linux/irq.h> | ||
| 34 | |||
| 35 | #include <clocksource/arm_generic.h> | ||
| 36 | |||
| 37 | #include <asm/thread_info.h> | ||
| 38 | #include <asm/stacktrace.h> | ||
| 39 | |||
| 40 | #ifdef CONFIG_SMP | ||
| 41 | unsigned long profile_pc(struct pt_regs *regs) | ||
| 42 | { | ||
| 43 | struct stackframe frame; | ||
| 44 | |||
| 45 | if (!in_lock_functions(regs->pc)) | ||
| 46 | return regs->pc; | ||
| 47 | |||
| 48 | frame.fp = regs->regs[29]; | ||
| 49 | frame.sp = regs->sp; | ||
| 50 | frame.pc = regs->pc; | ||
| 51 | do { | ||
| 52 | int ret = unwind_frame(&frame); | ||
| 53 | if (ret < 0) | ||
| 54 | return 0; | ||
| 55 | } while (in_lock_functions(frame.pc)); | ||
| 56 | |||
| 57 | return frame.pc; | ||
| 58 | } | ||
| 59 | EXPORT_SYMBOL(profile_pc); | ||
| 60 | #endif | ||
| 61 | |||
| 62 | void __init time_init(void) | ||
| 63 | { | ||
| 64 | arm_generic_timer_init(); | ||
| 65 | } | ||
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c new file mode 100644 index 000000000000..3883f842434f --- /dev/null +++ b/arch/arm64/kernel/traps.c | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/kernel/traps.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2009 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/signal.h> | ||
| 21 | #include <linux/personality.h> | ||
| 22 | #include <linux/kallsyms.h> | ||
| 23 | #include <linux/spinlock.h> | ||
| 24 | #include <linux/uaccess.h> | ||
| 25 | #include <linux/hardirq.h> | ||
| 26 | #include <linux/kdebug.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kexec.h> | ||
| 29 | #include <linux/delay.h> | ||
| 30 | #include <linux/init.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/syscalls.h> | ||
| 33 | |||
| 34 | #include <asm/atomic.h> | ||
| 35 | #include <asm/traps.h> | ||
| 36 | #include <asm/stacktrace.h> | ||
| 37 | #include <asm/exception.h> | ||
| 38 | #include <asm/system_misc.h> | ||
| 39 | |||
| 40 | static const char *handler[]= { | ||
| 41 | "Synchronous Abort", | ||
| 42 | "IRQ", | ||
| 43 | "FIQ", | ||
| 44 | "Error" | ||
| 45 | }; | ||
| 46 | |||
| 47 | int show_unhandled_signals = 1; | ||
| 48 | |||
| 49 | /* | ||
| 50 | * Dump out the contents of some memory nicely... | ||
| 51 | */ | ||
| 52 | static void dump_mem(const char *lvl, const char *str, unsigned long bottom, | ||
| 53 | unsigned long top) | ||
| 54 | { | ||
| 55 | unsigned long first; | ||
| 56 | mm_segment_t fs; | ||
| 57 | int i; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * We need to switch to kernel mode so that we can use __get_user | ||
| 61 | * to safely read from kernel space. Note that we now dump the | ||
| 62 | * code first, just in case the backtrace kills us. | ||
| 63 | */ | ||
| 64 | fs = get_fs(); | ||
| 65 | set_fs(KERNEL_DS); | ||
| 66 | |||
| 67 | printk("%s%s(0x%016lx to 0x%016lx)\n", lvl, str, bottom, top); | ||
| 68 | |||
| 69 | for (first = bottom & ~31; first < top; first += 32) { | ||
| 70 | unsigned long p; | ||
| 71 | char str[sizeof(" 12345678") * 8 + 1]; | ||
| 72 | |||
| 73 | memset(str, ' ', sizeof(str)); | ||
| 74 | str[sizeof(str) - 1] = '\0'; | ||
| 75 | |||
| 76 | for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { | ||
| 77 | if (p >= bottom && p < top) { | ||
| 78 | unsigned int val; | ||
| 79 | if (__get_user(val, (unsigned int *)p) == 0) | ||
| 80 | sprintf(str + i * 9, " %08x", val); | ||
| 81 | else | ||
| 82 | sprintf(str + i * 9, " ????????"); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | printk("%s%04lx:%s\n", lvl, first & 0xffff, str); | ||
| 86 | } | ||
| 87 | |||
| 88 | set_fs(fs); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void dump_backtrace_entry(unsigned long where, unsigned long stack) | ||
| 92 | { | ||
| 93 | print_ip_sym(where); | ||
| 94 | if (in_exception_text(where)) | ||
| 95 | dump_mem("", "Exception stack", stack, | ||
| 96 | stack + sizeof(struct pt_regs)); | ||
| 97 | } | ||
| 98 | |||
| 99 | static void dump_instr(const char *lvl, struct pt_regs *regs) | ||
| 100 | { | ||
| 101 | unsigned long addr = instruction_pointer(regs); | ||
| 102 | mm_segment_t fs; | ||
| 103 | char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; | ||
| 104 | int i; | ||
| 105 | |||
| 106 | /* | ||
| 107 | * We need to switch to kernel mode so that we can use __get_user | ||
| 108 | * to safely read from kernel space. Note that we now dump the | ||
| 109 | * code first, just in case the backtrace kills us. | ||
| 110 | */ | ||
| 111 | fs = get_fs(); | ||
| 112 | set_fs(KERNEL_DS); | ||
| 113 | |||
| 114 | for (i = -4; i < 1; i++) { | ||
| 115 | unsigned int val, bad; | ||
| 116 | |||
| 117 | bad = __get_user(val, &((u32 *)addr)[i]); | ||
| 118 | |||
| 119 | if (!bad) | ||
| 120 | p += sprintf(p, i == 0 ? "(%08x) " : "%08x ", val); | ||
| 121 | else { | ||
| 122 | p += sprintf(p, "bad PC value"); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | printk("%sCode: %s\n", lvl, str); | ||
| 127 | |||
| 128 | set_fs(fs); | ||
| 129 | } | ||
| 130 | |||
| 131 | static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) | ||
| 132 | { | ||
| 133 | struct stackframe frame; | ||
| 134 | const register unsigned long current_sp asm ("sp"); | ||
| 135 | |||
| 136 | pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk); | ||
| 137 | |||
| 138 | if (!tsk) | ||
| 139 | tsk = current; | ||
| 140 | |||
| 141 | if (regs) { | ||
| 142 | frame.fp = regs->regs[29]; | ||
| 143 | frame.sp = regs->sp; | ||
| 144 | frame.pc = regs->pc; | ||
| 145 | } else if (tsk == current) { | ||
| 146 | frame.fp = (unsigned long)__builtin_frame_address(0); | ||
| 147 | frame.sp = current_sp; | ||
| 148 | frame.pc = (unsigned long)dump_backtrace; | ||
| 149 | } else { | ||
| 150 | /* | ||
| 151 | * task blocked in __switch_to | ||
| 152 | */ | ||
| 153 | frame.fp = thread_saved_fp(tsk); | ||
| 154 | frame.sp = thread_saved_sp(tsk); | ||
| 155 | frame.pc = thread_saved_pc(tsk); | ||
| 156 | } | ||
| 157 | |||
| 158 | printk("Call trace:\n"); | ||
| 159 | while (1) { | ||
| 160 | unsigned long where = frame.pc; | ||
| 161 | int ret; | ||
| 162 | |||
| 163 | ret = unwind_frame(&frame); | ||
| 164 | if (ret < 0) | ||
| 165 | break; | ||
| 166 | dump_backtrace_entry(where, frame.sp); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | void dump_stack(void) | ||
| 171 | { | ||
| 172 | dump_backtrace(NULL, NULL); | ||
| 173 | } | ||
| 174 | |||
| 175 | EXPORT_SYMBOL(dump_stack); | ||
| 176 | |||
| 177 | void show_stack(struct task_struct *tsk, unsigned long *sp) | ||
| 178 | { | ||
| 179 | dump_backtrace(NULL, tsk); | ||
| 180 | barrier(); | ||
| 181 | } | ||
| 182 | |||
| 183 | #ifdef CONFIG_PREEMPT | ||
| 184 | #define S_PREEMPT " PREEMPT" | ||
| 185 | #else | ||
| 186 | #define S_PREEMPT "" | ||
| 187 | #endif | ||
| 188 | #ifdef CONFIG_SMP | ||
| 189 | #define S_SMP " SMP" | ||
| 190 | #else | ||
| 191 | #define S_SMP "" | ||
| 192 | #endif | ||
| 193 | |||
| 194 | static int __die(const char *str, int err, struct thread_info *thread, | ||
| 195 | struct pt_regs *regs) | ||
| 196 | { | ||
| 197 | struct task_struct *tsk = thread->task; | ||
| 198 | static int die_counter; | ||
| 199 | int ret; | ||
| 200 | |||
| 201 | pr_emerg("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", | ||
| 202 | str, err, ++die_counter); | ||
| 203 | |||
| 204 | /* trap and error numbers are mostly meaningless on ARM */ | ||
| 205 | ret = notify_die(DIE_OOPS, str, regs, err, 0, SIGSEGV); | ||
| 206 | if (ret == NOTIFY_STOP) | ||
| 207 | return ret; | ||
| 208 | |||
| 209 | print_modules(); | ||
| 210 | __show_regs(regs); | ||
| 211 | pr_emerg("Process %.*s (pid: %d, stack limit = 0x%p)\n", | ||
| 212 | TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); | ||
| 213 | |||
| 214 | if (!user_mode(regs) || in_interrupt()) { | ||
| 215 | dump_mem(KERN_EMERG, "Stack: ", regs->sp, | ||
| 216 | THREAD_SIZE + (unsigned long)task_stack_page(tsk)); | ||
| 217 | dump_backtrace(regs, tsk); | ||
| 218 | dump_instr(KERN_EMERG, regs); | ||
| 219 | } | ||
| 220 | |||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | |||
| 224 | static DEFINE_RAW_SPINLOCK(die_lock); | ||
| 225 | |||
| 226 | /* | ||
| 227 | * This function is protected against re-entrancy. | ||
| 228 | */ | ||
| 229 | void die(const char *str, struct pt_regs *regs, int err) | ||
| 230 | { | ||
| 231 | struct thread_info *thread = current_thread_info(); | ||
| 232 | int ret; | ||
| 233 | |||
| 234 | oops_enter(); | ||
| 235 | |||
| 236 | raw_spin_lock_irq(&die_lock); | ||
| 237 | console_verbose(); | ||
| 238 | bust_spinlocks(1); | ||
| 239 | ret = __die(str, err, thread, regs); | ||
| 240 | |||
| 241 | if (regs && kexec_should_crash(thread->task)) | ||
| 242 | crash_kexec(regs); | ||
| 243 | |||
| 244 | bust_spinlocks(0); | ||
| 245 | add_taint(TAINT_DIE); | ||
| 246 | raw_spin_unlock_irq(&die_lock); | ||
| 247 | oops_exit(); | ||
| 248 | |||
| 249 | if (in_interrupt()) | ||
| 250 | panic("Fatal exception in interrupt"); | ||
| 251 | if (panic_on_oops) | ||
| 252 | panic("Fatal exception"); | ||
| 253 | if (ret != NOTIFY_STOP) | ||
| 254 | do_exit(SIGSEGV); | ||
| 255 | } | ||
| 256 | |||
| 257 | void arm64_notify_die(const char *str, struct pt_regs *regs, | ||
| 258 | struct siginfo *info, int err) | ||
| 259 | { | ||
| 260 | if (user_mode(regs)) | ||
| 261 | force_sig_info(info->si_signo, info, current); | ||
| 262 | else | ||
| 263 | die(str, regs, err); | ||
| 264 | } | ||
| 265 | |||
| 266 | asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | ||
| 267 | { | ||
| 268 | siginfo_t info; | ||
| 269 | void __user *pc = (void __user *)instruction_pointer(regs); | ||
| 270 | |||
| 271 | #ifdef CONFIG_COMPAT | ||
| 272 | /* check for AArch32 breakpoint instructions */ | ||
| 273 | if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0) | ||
| 274 | return; | ||
| 275 | #endif | ||
| 276 | |||
| 277 | if (show_unhandled_signals) { | ||
| 278 | pr_info("%s[%d]: undefined instruction: pc=%p\n", | ||
| 279 | current->comm, task_pid_nr(current), pc); | ||
| 280 | dump_instr(KERN_INFO, regs); | ||
| 281 | } | ||
| 282 | |||
| 283 | info.si_signo = SIGILL; | ||
| 284 | info.si_errno = 0; | ||
| 285 | info.si_code = ILL_ILLOPC; | ||
| 286 | info.si_addr = pc; | ||
| 287 | |||
| 288 | arm64_notify_die("Oops - undefined instruction", regs, &info, 0); | ||
| 289 | } | ||
| 290 | |||
| 291 | long compat_arm_syscall(struct pt_regs *regs); | ||
| 292 | |||
| 293 | asmlinkage long do_ni_syscall(struct pt_regs *regs) | ||
| 294 | { | ||
| 295 | #ifdef CONFIG_COMPAT | ||
| 296 | long ret; | ||
| 297 | if (is_compat_task()) { | ||
| 298 | ret = compat_arm_syscall(regs); | ||
| 299 | if (ret != -ENOSYS) | ||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | #endif | ||
| 303 | |||
| 304 | if (show_unhandled_signals) { | ||
| 305 | pr_info("%s[%d]: syscall %d\n", current->comm, | ||
| 306 | task_pid_nr(current), (int)regs->syscallno); | ||
| 307 | dump_instr("", regs); | ||
| 308 | if (user_mode(regs)) | ||
| 309 | __show_regs(regs); | ||
| 310 | } | ||
| 311 | |||
| 312 | return sys_ni_syscall(); | ||
| 313 | } | ||
| 314 | |||
| 315 | /* | ||
| 316 | * bad_mode handles the impossible case in the exception vector. | ||
| 317 | */ | ||
| 318 | asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr) | ||
| 319 | { | ||
| 320 | console_verbose(); | ||
| 321 | |||
| 322 | pr_crit("Bad mode in %s handler detected, code 0x%08x\n", | ||
| 323 | handler[reason], esr); | ||
| 324 | |||
| 325 | die("Oops - bad mode", regs, 0); | ||
| 326 | local_irq_disable(); | ||
| 327 | panic("bad mode"); | ||
| 328 | } | ||
| 329 | |||
| 330 | void __pte_error(const char *file, int line, unsigned long val) | ||
| 331 | { | ||
| 332 | printk("%s:%d: bad pte %016lx.\n", file, line, val); | ||
| 333 | } | ||
| 334 | |||
| 335 | void __pmd_error(const char *file, int line, unsigned long val) | ||
| 336 | { | ||
| 337 | printk("%s:%d: bad pmd %016lx.\n", file, line, val); | ||
| 338 | } | ||
| 339 | |||
| 340 | void __pgd_error(const char *file, int line, unsigned long val) | ||
| 341 | { | ||
| 342 | printk("%s:%d: bad pgd %016lx.\n", file, line, val); | ||
| 343 | } | ||
| 344 | |||
| 345 | void __init trap_init(void) | ||
| 346 | { | ||
| 347 | return; | ||
| 348 | } | ||
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c new file mode 100644 index 000000000000..17948fc7d663 --- /dev/null +++ b/arch/arm64/kernel/vdso.c | |||
| @@ -0,0 +1,261 @@ | |||
| 1 | /* | ||
| 2 | * VDSO implementation for AArch64 and vector page setup for AArch32. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/clocksource.h> | ||
| 23 | #include <linux/elf.h> | ||
| 24 | #include <linux/err.h> | ||
| 25 | #include <linux/errno.h> | ||
| 26 | #include <linux/gfp.h> | ||
| 27 | #include <linux/mm.h> | ||
| 28 | #include <linux/sched.h> | ||
| 29 | #include <linux/signal.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/vmalloc.h> | ||
| 32 | |||
| 33 | #include <asm/cacheflush.h> | ||
| 34 | #include <asm/signal32.h> | ||
| 35 | #include <asm/vdso.h> | ||
| 36 | #include <asm/vdso_datapage.h> | ||
| 37 | |||
| 38 | extern char vdso_start, vdso_end; | ||
| 39 | static unsigned long vdso_pages; | ||
| 40 | static struct page **vdso_pagelist; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * The vDSO data page. | ||
| 44 | */ | ||
| 45 | static union { | ||
| 46 | struct vdso_data data; | ||
| 47 | u8 page[PAGE_SIZE]; | ||
| 48 | } vdso_data_store __page_aligned_data; | ||
| 49 | struct vdso_data *vdso_data = &vdso_data_store.data; | ||
| 50 | |||
| 51 | #ifdef CONFIG_COMPAT | ||
| 52 | /* | ||
| 53 | * Create and map the vectors page for AArch32 tasks. | ||
| 54 | */ | ||
| 55 | static struct page *vectors_page[1]; | ||
| 56 | |||
| 57 | static int alloc_vectors_page(void) | ||
| 58 | { | ||
| 59 | extern char __kuser_helper_start[], __kuser_helper_end[]; | ||
| 60 | int kuser_sz = __kuser_helper_end - __kuser_helper_start; | ||
| 61 | unsigned long vpage; | ||
| 62 | |||
| 63 | vpage = get_zeroed_page(GFP_ATOMIC); | ||
| 64 | |||
| 65 | if (!vpage) | ||
| 66 | return -ENOMEM; | ||
| 67 | |||
| 68 | /* kuser helpers */ | ||
| 69 | memcpy((void *)vpage + 0x1000 - kuser_sz, __kuser_helper_start, | ||
| 70 | kuser_sz); | ||
| 71 | |||
| 72 | /* sigreturn code */ | ||
| 73 | memcpy((void *)vpage + AARCH32_KERN_SIGRET_CODE_OFFSET, | ||
| 74 | aarch32_sigret_code, sizeof(aarch32_sigret_code)); | ||
| 75 | |||
| 76 | flush_icache_range(vpage, vpage + PAGE_SIZE); | ||
| 77 | vectors_page[0] = virt_to_page(vpage); | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | arch_initcall(alloc_vectors_page); | ||
| 82 | |||
| 83 | int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp) | ||
| 84 | { | ||
| 85 | struct mm_struct *mm = current->mm; | ||
| 86 | unsigned long addr = AARCH32_VECTORS_BASE; | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | down_write(&mm->mmap_sem); | ||
| 90 | current->mm->context.vdso = (void *)addr; | ||
| 91 | |||
| 92 | /* Map vectors page at the high address. */ | ||
| 93 | ret = install_special_mapping(mm, addr, PAGE_SIZE, | ||
| 94 | VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC, | ||
| 95 | vectors_page); | ||
| 96 | |||
| 97 | up_write(&mm->mmap_sem); | ||
| 98 | |||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | #endif /* CONFIG_COMPAT */ | ||
| 102 | |||
| 103 | static int __init vdso_init(void) | ||
| 104 | { | ||
| 105 | struct page *pg; | ||
| 106 | char *vbase; | ||
| 107 | int i, ret = 0; | ||
| 108 | |||
| 109 | vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; | ||
| 110 | pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n", | ||
| 111 | vdso_pages + 1, vdso_pages, 1L, &vdso_start); | ||
| 112 | |||
| 113 | /* Allocate the vDSO pagelist, plus a page for the data. */ | ||
| 114 | vdso_pagelist = kzalloc(sizeof(struct page *) * (vdso_pages + 1), | ||
| 115 | GFP_KERNEL); | ||
| 116 | if (vdso_pagelist == NULL) { | ||
| 117 | pr_err("Failed to allocate vDSO pagelist!\n"); | ||
| 118 | return -ENOMEM; | ||
| 119 | } | ||
| 120 | |||
| 121 | /* Grab the vDSO code pages. */ | ||
| 122 | for (i = 0; i < vdso_pages; i++) { | ||
| 123 | pg = virt_to_page(&vdso_start + i*PAGE_SIZE); | ||
| 124 | ClearPageReserved(pg); | ||
| 125 | get_page(pg); | ||
| 126 | vdso_pagelist[i] = pg; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Sanity check the shared object header. */ | ||
| 130 | vbase = vmap(vdso_pagelist, 1, 0, PAGE_KERNEL); | ||
| 131 | if (vbase == NULL) { | ||
| 132 | pr_err("Failed to map vDSO pagelist!\n"); | ||
| 133 | return -ENOMEM; | ||
| 134 | } else if (memcmp(vbase, "\177ELF", 4)) { | ||
| 135 | pr_err("vDSO is not a valid ELF object!\n"); | ||
| 136 | ret = -EINVAL; | ||
| 137 | goto unmap; | ||
| 138 | } | ||
| 139 | |||
| 140 | /* Grab the vDSO data page. */ | ||
| 141 | pg = virt_to_page(vdso_data); | ||
| 142 | get_page(pg); | ||
| 143 | vdso_pagelist[i] = pg; | ||
| 144 | |||
| 145 | unmap: | ||
| 146 | vunmap(vbase); | ||
| 147 | return ret; | ||
| 148 | } | ||
| 149 | arch_initcall(vdso_init); | ||
| 150 | |||
| 151 | int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
| 152 | int uses_interp) | ||
| 153 | { | ||
| 154 | struct mm_struct *mm = current->mm; | ||
| 155 | unsigned long vdso_base, vdso_mapping_len; | ||
| 156 | int ret; | ||
| 157 | |||
| 158 | /* Be sure to map the data page */ | ||
| 159 | vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT; | ||
| 160 | |||
| 161 | down_write(&mm->mmap_sem); | ||
| 162 | vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); | ||
| 163 | if (IS_ERR_VALUE(vdso_base)) { | ||
| 164 | ret = vdso_base; | ||
| 165 | goto up_fail; | ||
| 166 | } | ||
| 167 | mm->context.vdso = (void *)vdso_base; | ||
| 168 | |||
| 169 | ret = install_special_mapping(mm, vdso_base, vdso_mapping_len, | ||
| 170 | VM_READ|VM_EXEC| | ||
| 171 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, | ||
| 172 | vdso_pagelist); | ||
| 173 | if (ret) { | ||
| 174 | mm->context.vdso = NULL; | ||
| 175 | goto up_fail; | ||
| 176 | } | ||
| 177 | |||
| 178 | up_fail: | ||
| 179 | up_write(&mm->mmap_sem); | ||
| 180 | |||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | const char *arch_vma_name(struct vm_area_struct *vma) | ||
| 185 | { | ||
| 186 | /* | ||
| 187 | * We can re-use the vdso pointer in mm_context_t for identifying | ||
| 188 | * the vectors page for compat applications. The vDSO will always | ||
| 189 | * sit above TASK_UNMAPPED_BASE and so we don't need to worry about | ||
| 190 | * it conflicting with the vectors base. | ||
| 191 | */ | ||
| 192 | if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) { | ||
| 193 | #ifdef CONFIG_COMPAT | ||
| 194 | if (vma->vm_start == AARCH32_VECTORS_BASE) | ||
| 195 | return "[vectors]"; | ||
| 196 | #endif | ||
| 197 | return "[vdso]"; | ||
| 198 | } | ||
| 199 | |||
| 200 | return NULL; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* | ||
| 204 | * We define AT_SYSINFO_EHDR, so we need these function stubs to keep | ||
| 205 | * Linux happy. | ||
| 206 | */ | ||
| 207 | int in_gate_area_no_mm(unsigned long addr) | ||
| 208 | { | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | |||
| 212 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
| 213 | { | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
| 218 | { | ||
| 219 | return NULL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Update the vDSO data page to keep in sync with kernel timekeeping. | ||
| 224 | */ | ||
| 225 | void update_vsyscall(struct timespec *ts, struct timespec *wtm, | ||
| 226 | struct clocksource *clock, u32 mult) | ||
| 227 | { | ||
| 228 | struct timespec xtime_coarse; | ||
| 229 | u32 use_syscall = strcmp(clock->name, "arch_sys_counter"); | ||
| 230 | |||
| 231 | ++vdso_data->tb_seq_count; | ||
| 232 | smp_wmb(); | ||
| 233 | |||
| 234 | xtime_coarse = __current_kernel_time(); | ||
| 235 | vdso_data->use_syscall = use_syscall; | ||
| 236 | vdso_data->xtime_coarse_sec = xtime_coarse.tv_sec; | ||
| 237 | vdso_data->xtime_coarse_nsec = xtime_coarse.tv_nsec; | ||
| 238 | |||
| 239 | if (!use_syscall) { | ||
| 240 | vdso_data->cs_cycle_last = clock->cycle_last; | ||
| 241 | vdso_data->xtime_clock_sec = ts->tv_sec; | ||
| 242 | vdso_data->xtime_clock_nsec = ts->tv_nsec; | ||
| 243 | vdso_data->cs_mult = mult; | ||
| 244 | vdso_data->cs_shift = clock->shift; | ||
| 245 | vdso_data->wtm_clock_sec = wtm->tv_sec; | ||
| 246 | vdso_data->wtm_clock_nsec = wtm->tv_nsec; | ||
| 247 | } | ||
| 248 | |||
| 249 | smp_wmb(); | ||
| 250 | ++vdso_data->tb_seq_count; | ||
| 251 | } | ||
| 252 | |||
| 253 | void update_vsyscall_tz(void) | ||
| 254 | { | ||
| 255 | ++vdso_data->tb_seq_count; | ||
| 256 | smp_wmb(); | ||
| 257 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | ||
| 258 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | ||
| 259 | smp_wmb(); | ||
| 260 | ++vdso_data->tb_seq_count; | ||
| 261 | } | ||
diff --git a/arch/arm64/kernel/vdso/.gitignore b/arch/arm64/kernel/vdso/.gitignore new file mode 100644 index 000000000000..b8cc94e9698b --- /dev/null +++ b/arch/arm64/kernel/vdso/.gitignore | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | vdso.lds | ||
| 2 | vdso-offsets.h | ||
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile new file mode 100644 index 000000000000..d8064af42e62 --- /dev/null +++ b/arch/arm64/kernel/vdso/Makefile | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | # | ||
| 2 | # Building a vDSO image for AArch64. | ||
| 3 | # | ||
| 4 | # Author: Will Deacon <will.deacon@arm.com> | ||
| 5 | # Heavily based on the vDSO Makefiles for other archs. | ||
| 6 | # | ||
| 7 | |||
| 8 | obj-vdso := gettimeofday.o note.o sigreturn.o | ||
| 9 | |||
| 10 | # Build rules | ||
| 11 | targets := $(obj-vdso) vdso.so vdso.so.dbg | ||
| 12 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | ||
| 13 | |||
| 14 | ccflags-y := -shared -fno-common -fno-builtin | ||
| 15 | ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \ | ||
| 16 | $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
| 17 | |||
| 18 | obj-y += vdso.o | ||
| 19 | extra-y += vdso.lds vdso-offsets.h | ||
| 20 | CPPFLAGS_vdso.lds += -P -C -U$(ARCH) | ||
| 21 | |||
| 22 | # Force dependency (incbin is bad) | ||
| 23 | $(obj)/vdso.o : $(obj)/vdso.so | ||
| 24 | |||
| 25 | # Link rule for the .so file, .lds has to be first | ||
| 26 | $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) | ||
| 27 | $(call if_changed,vdsold) | ||
| 28 | |||
| 29 | # Strip rule for the .so file | ||
| 30 | $(obj)/%.so: OBJCOPYFLAGS := -S | ||
| 31 | $(obj)/%.so: $(obj)/%.so.dbg FORCE | ||
| 32 | $(call if_changed,objcopy) | ||
| 33 | |||
| 34 | # Generate VDSO offsets using helper script | ||
| 35 | gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh | ||
| 36 | quiet_cmd_vdsosym = VDSOSYM $@ | ||
| 37 | define cmd_vdsosym | ||
| 38 | $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ && \ | ||
| 39 | cp $@ include/generated/ | ||
| 40 | endef | ||
| 41 | |||
| 42 | $(obj)/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE | ||
| 43 | $(call if_changed,vdsosym) | ||
| 44 | |||
| 45 | # Assembly rules for the .S files | ||
| 46 | $(obj-vdso): %.o: %.S | ||
| 47 | $(call if_changed_dep,vdsoas) | ||
| 48 | |||
| 49 | # Actual build commands | ||
| 50 | quiet_cmd_vdsold = VDSOL $@ | ||
| 51 | cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@ | ||
| 52 | quiet_cmd_vdsoas = VDSOA $@ | ||
| 53 | cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< | ||
| 54 | |||
| 55 | # Install commands for the unstripped file | ||
| 56 | quiet_cmd_vdso_install = INSTALL $@ | ||
| 57 | cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||
| 58 | |||
| 59 | vdso.so: $(obj)/vdso.so.dbg | ||
| 60 | @mkdir -p $(MODLIB)/vdso | ||
| 61 | $(call cmd,vdso_install) | ||
| 62 | |||
| 63 | vdso_install: vdso.so | ||
diff --git a/arch/arm64/kernel/vdso/gen_vdso_offsets.sh b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh new file mode 100755 index 000000000000..01924ff071ad --- /dev/null +++ b/arch/arm64/kernel/vdso/gen_vdso_offsets.sh | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # | ||
| 4 | # Match symbols in the DSO that look like VDSO_*; produce a header file | ||
| 5 | # of constant offsets into the shared object. | ||
| 6 | # | ||
| 7 | # Doing this inside the Makefile will break the $(filter-out) function, | ||
| 8 | # causing Kbuild to rebuild the vdso-offsets header file every time. | ||
| 9 | # | ||
| 10 | # Author: Will Deacon <will.deacon@arm.com | ||
| 11 | # | ||
| 12 | |||
| 13 | LC_ALL=C | ||
| 14 | sed -n -e 's/^00*/0/' -e \ | ||
| 15 | 's/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso_offset_\2\t0x\1/p' | ||
diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S new file mode 100644 index 000000000000..dcb8c203a3b2 --- /dev/null +++ b/arch/arm64/kernel/vdso/gettimeofday.S | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /* | ||
| 2 | * Userspace implementations of gettimeofday() and friends. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/linkage.h> | ||
| 22 | #include <asm/asm-offsets.h> | ||
| 23 | #include <asm/unistd.h> | ||
| 24 | |||
| 25 | #define NSEC_PER_SEC_LO16 0xca00 | ||
| 26 | #define NSEC_PER_SEC_HI16 0x3b9a | ||
| 27 | |||
| 28 | vdso_data .req x6 | ||
| 29 | use_syscall .req w7 | ||
| 30 | seqcnt .req w8 | ||
| 31 | |||
| 32 | .macro seqcnt_acquire | ||
| 33 | 9999: ldr seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT] | ||
| 34 | tbnz seqcnt, #0, 9999b | ||
| 35 | dmb ishld | ||
| 36 | ldr use_syscall, [vdso_data, #VDSO_USE_SYSCALL] | ||
| 37 | .endm | ||
| 38 | |||
| 39 | .macro seqcnt_read, cnt | ||
| 40 | dmb ishld | ||
| 41 | ldr \cnt, [vdso_data, #VDSO_TB_SEQ_COUNT] | ||
| 42 | .endm | ||
| 43 | |||
| 44 | .macro seqcnt_check, cnt, fail | ||
| 45 | cmp \cnt, seqcnt | ||
| 46 | b.ne \fail | ||
| 47 | .endm | ||
| 48 | |||
| 49 | .text | ||
| 50 | |||
| 51 | /* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */ | ||
| 52 | ENTRY(__kernel_gettimeofday) | ||
| 53 | .cfi_startproc | ||
| 54 | mov x2, x30 | ||
| 55 | .cfi_register x30, x2 | ||
| 56 | |||
| 57 | /* Acquire the sequence counter and get the timespec. */ | ||
| 58 | adr vdso_data, _vdso_data | ||
| 59 | 1: seqcnt_acquire | ||
| 60 | cbnz use_syscall, 4f | ||
| 61 | |||
| 62 | /* If tv is NULL, skip to the timezone code. */ | ||
| 63 | cbz x0, 2f | ||
| 64 | bl __do_get_tspec | ||
| 65 | seqcnt_check w13, 1b | ||
| 66 | |||
| 67 | /* Convert ns to us. */ | ||
| 68 | mov x11, #1000 | ||
| 69 | udiv x10, x10, x11 | ||
| 70 | stp x9, x10, [x0, #TVAL_TV_SEC] | ||
| 71 | 2: | ||
| 72 | /* If tz is NULL, return 0. */ | ||
| 73 | cbz x1, 3f | ||
| 74 | ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST] | ||
| 75 | seqcnt_read w13 | ||
| 76 | seqcnt_check w13, 1b | ||
| 77 | stp w4, w5, [x1, #TZ_MINWEST] | ||
| 78 | 3: | ||
| 79 | mov x0, xzr | ||
| 80 | ret x2 | ||
| 81 | 4: | ||
| 82 | /* Syscall fallback. */ | ||
| 83 | mov x8, #__NR_gettimeofday | ||
| 84 | svc #0 | ||
| 85 | ret x2 | ||
| 86 | .cfi_endproc | ||
| 87 | ENDPROC(__kernel_gettimeofday) | ||
| 88 | |||
| 89 | /* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */ | ||
| 90 | ENTRY(__kernel_clock_gettime) | ||
| 91 | .cfi_startproc | ||
| 92 | cmp w0, #CLOCK_REALTIME | ||
| 93 | ccmp w0, #CLOCK_MONOTONIC, #0x4, ne | ||
| 94 | b.ne 2f | ||
| 95 | |||
| 96 | mov x2, x30 | ||
| 97 | .cfi_register x30, x2 | ||
| 98 | |||
| 99 | /* Get kernel timespec. */ | ||
| 100 | adr vdso_data, _vdso_data | ||
| 101 | 1: seqcnt_acquire | ||
| 102 | cbnz use_syscall, 7f | ||
| 103 | |||
| 104 | bl __do_get_tspec | ||
| 105 | seqcnt_check w13, 1b | ||
| 106 | |||
| 107 | cmp w0, #CLOCK_MONOTONIC | ||
| 108 | b.ne 6f | ||
| 109 | |||
| 110 | /* Get wtm timespec. */ | ||
| 111 | ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC] | ||
| 112 | |||
| 113 | /* Check the sequence counter. */ | ||
| 114 | seqcnt_read w13 | ||
| 115 | seqcnt_check w13, 1b | ||
| 116 | b 4f | ||
| 117 | 2: | ||
| 118 | cmp w0, #CLOCK_REALTIME_COARSE | ||
| 119 | ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne | ||
| 120 | b.ne 8f | ||
| 121 | |||
| 122 | /* Get coarse timespec. */ | ||
| 123 | adr vdso_data, _vdso_data | ||
| 124 | 3: seqcnt_acquire | ||
| 125 | ldp x9, x10, [vdso_data, #VDSO_XTIME_CRS_SEC] | ||
| 126 | |||
| 127 | cmp w0, #CLOCK_MONOTONIC_COARSE | ||
| 128 | b.ne 6f | ||
| 129 | |||
| 130 | /* Get wtm timespec. */ | ||
| 131 | ldp x14, x15, [vdso_data, #VDSO_WTM_CLK_SEC] | ||
| 132 | |||
| 133 | /* Check the sequence counter. */ | ||
| 134 | seqcnt_read w13 | ||
| 135 | seqcnt_check w13, 3b | ||
| 136 | 4: | ||
| 137 | /* Add on wtm timespec. */ | ||
| 138 | add x9, x9, x14 | ||
| 139 | add x10, x10, x15 | ||
| 140 | |||
| 141 | /* Normalise the new timespec. */ | ||
| 142 | mov x14, #NSEC_PER_SEC_LO16 | ||
| 143 | movk x14, #NSEC_PER_SEC_HI16, lsl #16 | ||
| 144 | cmp x10, x14 | ||
| 145 | b.lt 5f | ||
| 146 | sub x10, x10, x14 | ||
| 147 | add x9, x9, #1 | ||
| 148 | 5: | ||
| 149 | cmp x10, #0 | ||
| 150 | b.ge 6f | ||
| 151 | add x10, x10, x14 | ||
| 152 | sub x9, x9, #1 | ||
| 153 | |||
| 154 | 6: /* Store to the user timespec. */ | ||
| 155 | stp x9, x10, [x1, #TSPEC_TV_SEC] | ||
| 156 | mov x0, xzr | ||
| 157 | ret x2 | ||
| 158 | 7: | ||
| 159 | mov x30, x2 | ||
| 160 | 8: /* Syscall fallback. */ | ||
| 161 | mov x8, #__NR_clock_gettime | ||
| 162 | svc #0 | ||
| 163 | ret | ||
| 164 | .cfi_endproc | ||
| 165 | ENDPROC(__kernel_clock_gettime) | ||
| 166 | |||
| 167 | /* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */ | ||
| 168 | ENTRY(__kernel_clock_getres) | ||
| 169 | .cfi_startproc | ||
| 170 | cbz w1, 3f | ||
| 171 | |||
| 172 | cmp w0, #CLOCK_REALTIME | ||
| 173 | ccmp w0, #CLOCK_MONOTONIC, #0x4, ne | ||
| 174 | b.ne 1f | ||
| 175 | |||
| 176 | ldr x2, 5f | ||
| 177 | b 2f | ||
| 178 | 1: | ||
| 179 | cmp w0, #CLOCK_REALTIME_COARSE | ||
| 180 | ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne | ||
| 181 | b.ne 4f | ||
| 182 | ldr x2, 6f | ||
| 183 | 2: | ||
| 184 | stp xzr, x2, [x1] | ||
| 185 | |||
| 186 | 3: /* res == NULL. */ | ||
| 187 | mov w0, wzr | ||
| 188 | ret | ||
| 189 | |||
| 190 | 4: /* Syscall fallback. */ | ||
| 191 | mov x8, #__NR_clock_getres | ||
| 192 | svc #0 | ||
| 193 | ret | ||
| 194 | 5: | ||
| 195 | .quad CLOCK_REALTIME_RES | ||
| 196 | 6: | ||
| 197 | .quad CLOCK_COARSE_RES | ||
| 198 | .cfi_endproc | ||
| 199 | ENDPROC(__kernel_clock_getres) | ||
| 200 | |||
| 201 | /* | ||
| 202 | * Read the current time from the architected counter. | ||
| 203 | * Expects vdso_data to be initialised. | ||
| 204 | * Clobbers the temporary registers (x9 - x15). | ||
| 205 | * Returns: | ||
| 206 | * - (x9, x10) = (ts->tv_sec, ts->tv_nsec) | ||
| 207 | * - (x11, x12) = (xtime->tv_sec, xtime->tv_nsec) | ||
| 208 | * - w13 = vDSO sequence counter | ||
| 209 | */ | ||
| 210 | ENTRY(__do_get_tspec) | ||
| 211 | .cfi_startproc | ||
| 212 | |||
| 213 | /* Read from the vDSO data page. */ | ||
| 214 | ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST] | ||
| 215 | ldp x11, x12, [vdso_data, #VDSO_XTIME_CLK_SEC] | ||
| 216 | ldp w14, w15, [vdso_data, #VDSO_CS_MULT] | ||
| 217 | seqcnt_read w13 | ||
| 218 | |||
| 219 | /* Read the physical counter. */ | ||
| 220 | isb | ||
| 221 | mrs x9, cntpct_el0 | ||
| 222 | |||
| 223 | /* Calculate cycle delta and convert to ns. */ | ||
| 224 | sub x10, x9, x10 | ||
| 225 | /* We can only guarantee 56 bits of precision. */ | ||
| 226 | movn x9, #0xff0, lsl #48 | ||
| 227 | and x10, x9, x10 | ||
| 228 | mul x10, x10, x14 | ||
| 229 | lsr x10, x10, x15 | ||
| 230 | |||
| 231 | /* Use the kernel time to calculate the new timespec. */ | ||
| 232 | add x10, x12, x10 | ||
| 233 | mov x14, #NSEC_PER_SEC_LO16 | ||
| 234 | movk x14, #NSEC_PER_SEC_HI16, lsl #16 | ||
| 235 | udiv x15, x10, x14 | ||
| 236 | add x9, x15, x11 | ||
| 237 | mul x14, x14, x15 | ||
| 238 | sub x10, x10, x14 | ||
| 239 | |||
| 240 | ret | ||
| 241 | .cfi_endproc | ||
| 242 | ENDPROC(__do_get_tspec) | ||
diff --git a/arch/arm64/kernel/vdso/note.S b/arch/arm64/kernel/vdso/note.S new file mode 100644 index 000000000000..b82c85e5d972 --- /dev/null +++ b/arch/arm64/kernel/vdso/note.S | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Limited | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 17 | * | ||
| 18 | * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. | ||
| 19 | * Here we can supply some information useful to userland. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/uts.h> | ||
| 23 | #include <linux/version.h> | ||
| 24 | #include <linux/elfnote.h> | ||
| 25 | |||
| 26 | ELFNOTE_START(Linux, 0, "a") | ||
| 27 | .long LINUX_VERSION_CODE | ||
| 28 | ELFNOTE_END | ||
diff --git a/arch/arm64/kernel/vdso/sigreturn.S b/arch/arm64/kernel/vdso/sigreturn.S new file mode 100644 index 000000000000..20d98effa7dd --- /dev/null +++ b/arch/arm64/kernel/vdso/sigreturn.S | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * Sigreturn trampoline for returning from a signal when the SA_RESTORER | ||
| 3 | * flag is not set. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 ARM Limited | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | * | ||
| 19 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/linkage.h> | ||
| 23 | #include <asm/unistd.h> | ||
| 24 | |||
| 25 | .text | ||
| 26 | |||
| 27 | nop | ||
| 28 | ENTRY(__kernel_rt_sigreturn) | ||
| 29 | .cfi_startproc | ||
| 30 | .cfi_signal_frame | ||
| 31 | .cfi_def_cfa x29, 0 | ||
| 32 | .cfi_offset x29, 0 * 8 | ||
| 33 | .cfi_offset x30, 1 * 8 | ||
| 34 | mov x8, #__NR_rt_sigreturn | ||
| 35 | svc #0 | ||
| 36 | .cfi_endproc | ||
| 37 | ENDPROC(__kernel_rt_sigreturn) | ||
diff --git a/arch/arm64/kernel/vdso/vdso.S b/arch/arm64/kernel/vdso/vdso.S new file mode 100644 index 000000000000..60c1db54b41a --- /dev/null +++ b/arch/arm64/kernel/vdso/vdso.S | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Limited | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | * | ||
| 16 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/linkage.h> | ||
| 21 | #include <linux/const.h> | ||
| 22 | #include <asm/page.h> | ||
| 23 | |||
| 24 | __PAGE_ALIGNED_DATA | ||
| 25 | |||
| 26 | .globl vdso_start, vdso_end | ||
| 27 | .balign PAGE_SIZE | ||
| 28 | vdso_start: | ||
| 29 | .incbin "arch/arm64/kernel/vdso/vdso.so" | ||
| 30 | .balign PAGE_SIZE | ||
| 31 | vdso_end: | ||
| 32 | |||
| 33 | .previous | ||
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S new file mode 100644 index 000000000000..8154b8d1c826 --- /dev/null +++ b/arch/arm64/kernel/vdso/vdso.lds.S | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * GNU linker script for the VDSO library. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | * Heavily based on the vDSO linker scripts for other archs. | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/const.h> | ||
| 23 | #include <asm/page.h> | ||
| 24 | #include <asm/vdso.h> | ||
| 25 | |||
| 26 | OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") | ||
| 27 | OUTPUT_ARCH(aarch64) | ||
| 28 | |||
| 29 | SECTIONS | ||
| 30 | { | ||
| 31 | . = VDSO_LBASE + SIZEOF_HEADERS; | ||
| 32 | |||
| 33 | .hash : { *(.hash) } :text | ||
| 34 | .gnu.hash : { *(.gnu.hash) } | ||
| 35 | .dynsym : { *(.dynsym) } | ||
| 36 | .dynstr : { *(.dynstr) } | ||
| 37 | .gnu.version : { *(.gnu.version) } | ||
| 38 | .gnu.version_d : { *(.gnu.version_d) } | ||
| 39 | .gnu.version_r : { *(.gnu.version_r) } | ||
| 40 | |||
| 41 | .note : { *(.note.*) } :text :note | ||
| 42 | |||
| 43 | . = ALIGN(16); | ||
| 44 | |||
| 45 | .text : { *(.text*) } :text =0xd503201f | ||
| 46 | PROVIDE (__etext = .); | ||
| 47 | PROVIDE (_etext = .); | ||
| 48 | PROVIDE (etext = .); | ||
| 49 | |||
| 50 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | ||
| 51 | .eh_frame : { KEEP (*(.eh_frame)) } :text | ||
| 52 | |||
| 53 | .dynamic : { *(.dynamic) } :text :dynamic | ||
| 54 | |||
| 55 | .rodata : { *(.rodata*) } :text | ||
| 56 | |||
| 57 | _end = .; | ||
| 58 | PROVIDE(end = .); | ||
| 59 | |||
| 60 | . = ALIGN(PAGE_SIZE); | ||
| 61 | PROVIDE(_vdso_data = .); | ||
| 62 | |||
| 63 | /DISCARD/ : { | ||
| 64 | *(.note.GNU-stack) | ||
| 65 | *(.data .data.* .gnu.linkonce.d.* .sdata*) | ||
| 66 | *(.bss .sbss .dynbss .dynsbss) | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * We must supply the ELF program headers explicitly to get just one | ||
| 72 | * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||
| 73 | */ | ||
| 74 | PHDRS | ||
| 75 | { | ||
| 76 | text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ | ||
| 77 | dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ | ||
| 78 | note PT_NOTE FLAGS(4); /* PF_R */ | ||
| 79 | eh_frame_hdr PT_GNU_EH_FRAME; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* | ||
| 83 | * This controls what symbols we export from the DSO. | ||
| 84 | */ | ||
| 85 | VERSION | ||
| 86 | { | ||
| 87 | LINUX_2.6.39 { | ||
| 88 | global: | ||
| 89 | __kernel_rt_sigreturn; | ||
| 90 | __kernel_gettimeofday; | ||
| 91 | __kernel_clock_gettime; | ||
| 92 | __kernel_clock_getres; | ||
| 93 | local: *; | ||
| 94 | }; | ||
| 95 | } | ||
| 96 | |||
| 97 | /* | ||
| 98 | * Make the sigreturn code visible to the kernel. | ||
| 99 | */ | ||
| 100 | VDSO_sigtramp = __kernel_rt_sigreturn; | ||
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..3fae2be8b016 --- /dev/null +++ b/arch/arm64/kernel/vmlinux.lds.S | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* | ||
| 2 | * ld script to make ARM Linux kernel | ||
| 3 | * taken from the i386 version by Russell King | ||
| 4 | * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <asm-generic/vmlinux.lds.h> | ||
| 8 | #include <asm/thread_info.h> | ||
| 9 | #include <asm/memory.h> | ||
| 10 | #include <asm/page.h> | ||
| 11 | |||
| 12 | #define ARM_EXIT_KEEP(x) | ||
| 13 | #define ARM_EXIT_DISCARD(x) x | ||
| 14 | |||
| 15 | OUTPUT_ARCH(aarch64) | ||
| 16 | ENTRY(stext) | ||
| 17 | |||
| 18 | jiffies = jiffies_64; | ||
| 19 | |||
| 20 | SECTIONS | ||
| 21 | { | ||
| 22 | /* | ||
| 23 | * XXX: The linker does not define how output sections are | ||
| 24 | * assigned to input sections when there are multiple statements | ||
| 25 | * matching the same input section name. There is no documented | ||
| 26 | * order of matching. | ||
| 27 | */ | ||
| 28 | /DISCARD/ : { | ||
| 29 | ARM_EXIT_DISCARD(EXIT_TEXT) | ||
| 30 | ARM_EXIT_DISCARD(EXIT_DATA) | ||
| 31 | EXIT_CALL | ||
| 32 | *(.discard) | ||
| 33 | *(.discard.*) | ||
| 34 | } | ||
| 35 | |||
| 36 | . = PAGE_OFFSET + TEXT_OFFSET; | ||
| 37 | |||
| 38 | .head.text : { | ||
| 39 | _text = .; | ||
| 40 | HEAD_TEXT | ||
| 41 | } | ||
| 42 | .text : { /* Real text segment */ | ||
| 43 | _stext = .; /* Text and read-only data */ | ||
| 44 | *(.smp.pen.text) | ||
| 45 | __exception_text_start = .; | ||
| 46 | *(.exception.text) | ||
| 47 | __exception_text_end = .; | ||
| 48 | IRQENTRY_TEXT | ||
| 49 | TEXT_TEXT | ||
| 50 | SCHED_TEXT | ||
| 51 | LOCK_TEXT | ||
| 52 | *(.fixup) | ||
| 53 | *(.gnu.warning) | ||
| 54 | . = ALIGN(16); | ||
| 55 | *(.got) /* Global offset table */ | ||
| 56 | } | ||
| 57 | |||
| 58 | RO_DATA(PAGE_SIZE) | ||
| 59 | |||
| 60 | _etext = .; /* End of text and rodata section */ | ||
| 61 | |||
| 62 | . = ALIGN(PAGE_SIZE); | ||
| 63 | __init_begin = .; | ||
| 64 | |||
| 65 | INIT_TEXT_SECTION(8) | ||
| 66 | .exit.text : { | ||
| 67 | ARM_EXIT_KEEP(EXIT_TEXT) | ||
| 68 | } | ||
| 69 | . = ALIGN(16); | ||
| 70 | .init.data : { | ||
| 71 | INIT_DATA | ||
| 72 | INIT_SETUP(16) | ||
| 73 | INIT_CALLS | ||
| 74 | CON_INITCALL | ||
| 75 | SECURITY_INITCALL | ||
| 76 | INIT_RAM_FS | ||
| 77 | } | ||
| 78 | .exit.data : { | ||
| 79 | ARM_EXIT_KEEP(EXIT_DATA) | ||
| 80 | } | ||
| 81 | |||
| 82 | PERCPU_SECTION(64) | ||
| 83 | |||
| 84 | __init_end = .; | ||
| 85 | . = ALIGN(THREAD_SIZE); | ||
| 86 | __data_loc = .; | ||
| 87 | |||
| 88 | .data : AT(__data_loc) { | ||
| 89 | _data = .; /* address in memory */ | ||
| 90 | _sdata = .; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * first, the init task union, aligned | ||
| 94 | * to an 8192 byte boundary. | ||
| 95 | */ | ||
| 96 | INIT_TASK_DATA(THREAD_SIZE) | ||
| 97 | NOSAVE_DATA | ||
| 98 | CACHELINE_ALIGNED_DATA(64) | ||
| 99 | READ_MOSTLY_DATA(64) | ||
| 100 | |||
| 101 | /* | ||
| 102 | * The exception fixup table (might need resorting at runtime) | ||
| 103 | */ | ||
| 104 | . = ALIGN(32); | ||
| 105 | __start___ex_table = .; | ||
| 106 | *(__ex_table) | ||
| 107 | __stop___ex_table = .; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * and the usual data section | ||
| 111 | */ | ||
| 112 | DATA_DATA | ||
| 113 | CONSTRUCTORS | ||
| 114 | |||
| 115 | _edata = .; | ||
| 116 | } | ||
| 117 | _edata_loc = __data_loc + SIZEOF(.data); | ||
| 118 | |||
| 119 | NOTES | ||
| 120 | |||
| 121 | BSS_SECTION(0, 0, 0) | ||
| 122 | _end = .; | ||
| 123 | |||
| 124 | STABS_DEBUG | ||
| 125 | .comment 0 : { *(.comment) } | ||
| 126 | } | ||
diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile new file mode 100644 index 000000000000..2fb7f6092aae --- /dev/null +++ b/arch/arm64/lib/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | lib-y := bitops.o delay.o \ | ||
| 2 | strncpy_from_user.o strnlen_user.o clear_user.o \ | ||
| 3 | copy_from_user.o copy_to_user.o copy_in_user.o \ | ||
| 4 | copy_page.o clear_page.o | ||
diff --git a/arch/arm64/lib/bitops.c b/arch/arm64/lib/bitops.c new file mode 100644 index 000000000000..aa4965e60acc --- /dev/null +++ b/arch/arm64/lib/bitops.c | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Limited | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/spinlock.h> | ||
| 19 | #include <linux/atomic.h> | ||
| 20 | |||
| 21 | #ifdef CONFIG_SMP | ||
| 22 | arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = { | ||
| 23 | [0 ... (ATOMIC_HASH_SIZE-1)] = __ARCH_SPIN_LOCK_UNLOCKED | ||
| 24 | }; | ||
| 25 | #endif | ||
diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S new file mode 100644 index 000000000000..ef08e905e35b --- /dev/null +++ b/arch/arm64/lib/clear_page.S | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <linux/const.h> | ||
| 19 | #include <asm/assembler.h> | ||
| 20 | #include <asm/page.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Clear page @dest | ||
| 24 | * | ||
| 25 | * Parameters: | ||
| 26 | * x0 - dest | ||
| 27 | */ | ||
| 28 | ENTRY(clear_page) | ||
| 29 | mrs x1, dczid_el0 | ||
| 30 | and w1, w1, #0xf | ||
| 31 | mov x2, #4 | ||
| 32 | lsl x1, x2, x1 | ||
| 33 | |||
| 34 | 1: dc zva, x0 | ||
| 35 | add x0, x0, x1 | ||
| 36 | tst x0, #(PAGE_SIZE - 1) | ||
| 37 | b.ne 1b | ||
| 38 | ret | ||
| 39 | ENDPROC(clear_page) | ||
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S new file mode 100644 index 000000000000..6e0ed93d51fe --- /dev/null +++ b/arch/arm64/lib/clear_user.S | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/lib/clear_user.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | #include <linux/linkage.h> | ||
| 19 | #include <asm/assembler.h> | ||
| 20 | |||
| 21 | .text | ||
| 22 | |||
| 23 | /* Prototype: int __clear_user(void *addr, size_t sz) | ||
| 24 | * Purpose : clear some user memory | ||
| 25 | * Params : addr - user memory address to clear | ||
| 26 | * : sz - number of bytes to clear | ||
| 27 | * Returns : number of bytes NOT cleared | ||
| 28 | * | ||
| 29 | * Alignment fixed up by hardware. | ||
| 30 | */ | ||
| 31 | ENTRY(__clear_user) | ||
| 32 | mov x2, x1 // save the size for fixup return | ||
| 33 | subs x1, x1, #8 | ||
| 34 | b.mi 2f | ||
| 35 | 1: | ||
| 36 | USER(9f, str xzr, [x0], #8 ) | ||
| 37 | subs x1, x1, #8 | ||
| 38 | b.pl 1b | ||
| 39 | 2: adds x1, x1, #4 | ||
| 40 | b.mi 3f | ||
| 41 | USER(9f, str wzr, [x0], #4 ) | ||
| 42 | sub x1, x1, #4 | ||
| 43 | 3: adds x1, x1, #2 | ||
| 44 | b.mi 4f | ||
| 45 | USER(9f, strh wzr, [x0], #2 ) | ||
| 46 | sub x1, x1, #2 | ||
| 47 | 4: adds x1, x1, #1 | ||
| 48 | b.mi 5f | ||
| 49 | strb wzr, [x0] | ||
| 50 | 5: mov x0, #0 | ||
| 51 | ret | ||
| 52 | ENDPROC(__clear_user) | ||
| 53 | |||
| 54 | .section .fixup,"ax" | ||
| 55 | .align 2 | ||
| 56 | 9: mov x0, x2 // return the original size | ||
| 57 | ret | ||
| 58 | .previous | ||
diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S new file mode 100644 index 000000000000..5e27add9d362 --- /dev/null +++ b/arch/arm64/lib/copy_from_user.S | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <asm/assembler.h> | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Copy from user space to a kernel buffer (alignment handled by the hardware) | ||
| 22 | * | ||
| 23 | * Parameters: | ||
| 24 | * x0 - to | ||
| 25 | * x1 - from | ||
| 26 | * x2 - n | ||
| 27 | * Returns: | ||
| 28 | * x0 - bytes not copied | ||
| 29 | */ | ||
| 30 | ENTRY(__copy_from_user) | ||
| 31 | add x4, x1, x2 // upper user buffer boundary | ||
| 32 | subs x2, x2, #8 | ||
| 33 | b.mi 2f | ||
| 34 | 1: | ||
| 35 | USER(9f, ldr x3, [x1], #8 ) | ||
| 36 | subs x2, x2, #8 | ||
| 37 | str x3, [x0], #8 | ||
| 38 | b.pl 1b | ||
| 39 | 2: adds x2, x2, #4 | ||
| 40 | b.mi 3f | ||
| 41 | USER(9f, ldr w3, [x1], #4 ) | ||
| 42 | sub x2, x2, #4 | ||
| 43 | str w3, [x0], #4 | ||
| 44 | 3: adds x2, x2, #2 | ||
| 45 | b.mi 4f | ||
| 46 | USER(9f, ldrh w3, [x1], #2 ) | ||
| 47 | sub x2, x2, #2 | ||
| 48 | strh w3, [x0], #2 | ||
| 49 | 4: adds x2, x2, #1 | ||
| 50 | b.mi 5f | ||
| 51 | USER(9f, ldrb w3, [x1] ) | ||
| 52 | strb w3, [x0] | ||
| 53 | 5: mov x0, #0 | ||
| 54 | ret | ||
| 55 | ENDPROC(__copy_from_user) | ||
| 56 | |||
| 57 | .section .fixup,"ax" | ||
| 58 | .align 2 | ||
| 59 | 9: sub x2, x4, x1 | ||
| 60 | mov x3, x2 | ||
| 61 | 10: strb wzr, [x0], #1 // zero remaining buffer space | ||
| 62 | subs x3, x3, #1 | ||
| 63 | b.ne 10b | ||
| 64 | mov x0, x2 // bytes not copied | ||
| 65 | ret | ||
| 66 | .previous | ||
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S new file mode 100644 index 000000000000..84b6c9bb9b93 --- /dev/null +++ b/arch/arm64/lib/copy_in_user.S | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* | ||
| 2 | * Copy from user space to user space | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/linkage.h> | ||
| 20 | #include <asm/assembler.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Copy from user space to user space (alignment handled by the hardware) | ||
| 24 | * | ||
| 25 | * Parameters: | ||
| 26 | * x0 - to | ||
| 27 | * x1 - from | ||
| 28 | * x2 - n | ||
| 29 | * Returns: | ||
| 30 | * x0 - bytes not copied | ||
| 31 | */ | ||
| 32 | ENTRY(__copy_in_user) | ||
| 33 | add x4, x0, x2 // upper user buffer boundary | ||
| 34 | subs x2, x2, #8 | ||
| 35 | b.mi 2f | ||
| 36 | 1: | ||
| 37 | USER(9f, ldr x3, [x1], #8 ) | ||
| 38 | subs x2, x2, #8 | ||
| 39 | USER(9f, str x3, [x0], #8 ) | ||
| 40 | b.pl 1b | ||
| 41 | 2: adds x2, x2, #4 | ||
| 42 | b.mi 3f | ||
| 43 | USER(9f, ldr w3, [x1], #4 ) | ||
| 44 | sub x2, x2, #4 | ||
| 45 | USER(9f, str w3, [x0], #4 ) | ||
| 46 | 3: adds x2, x2, #2 | ||
| 47 | b.mi 4f | ||
| 48 | USER(9f, ldrh w3, [x1], #2 ) | ||
| 49 | sub x2, x2, #2 | ||
| 50 | USER(9f, strh w3, [x0], #2 ) | ||
| 51 | 4: adds x2, x2, #1 | ||
| 52 | b.mi 5f | ||
| 53 | USER(9f, ldrb w3, [x1] ) | ||
| 54 | USER(9f, strb w3, [x0] ) | ||
| 55 | 5: mov x0, #0 | ||
| 56 | ret | ||
| 57 | ENDPROC(__copy_in_user) | ||
| 58 | |||
| 59 | .section .fixup,"ax" | ||
| 60 | .align 2 | ||
| 61 | 9: sub x0, x4, x0 // bytes not copied | ||
| 62 | ret | ||
| 63 | .previous | ||
diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S new file mode 100644 index 000000000000..512b9a7b980e --- /dev/null +++ b/arch/arm64/lib/copy_page.S | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <linux/const.h> | ||
| 19 | #include <asm/assembler.h> | ||
| 20 | #include <asm/page.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * Copy a page from src to dest (both are page aligned) | ||
| 24 | * | ||
| 25 | * Parameters: | ||
| 26 | * x0 - dest | ||
| 27 | * x1 - src | ||
| 28 | */ | ||
| 29 | ENTRY(copy_page) | ||
| 30 | /* Assume cache line size is 64 bytes. */ | ||
| 31 | prfm pldl1strm, [x1, #64] | ||
| 32 | 1: ldp x2, x3, [x1] | ||
| 33 | ldp x4, x5, [x1, #16] | ||
| 34 | ldp x6, x7, [x1, #32] | ||
| 35 | ldp x8, x9, [x1, #48] | ||
| 36 | add x1, x1, #64 | ||
| 37 | prfm pldl1strm, [x1, #64] | ||
| 38 | stnp x2, x3, [x0] | ||
| 39 | stnp x4, x5, [x0, #16] | ||
| 40 | stnp x6, x7, [x0, #32] | ||
| 41 | stnp x8, x9, [x0, #48] | ||
| 42 | add x0, x0, #64 | ||
| 43 | tst x1, #(PAGE_SIZE - 1) | ||
| 44 | b.ne 1b | ||
| 45 | ret | ||
| 46 | ENDPROC(copy_page) | ||
diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S new file mode 100644 index 000000000000..a0aeeb9b7a28 --- /dev/null +++ b/arch/arm64/lib/copy_to_user.S | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/linkage.h> | ||
| 18 | #include <asm/assembler.h> | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Copy to user space from a kernel buffer (alignment handled by the hardware) | ||
| 22 | * | ||
| 23 | * Parameters: | ||
| 24 | * x0 - to | ||
| 25 | * x1 - from | ||
| 26 | * x2 - n | ||
| 27 | * Returns: | ||
| 28 | * x0 - bytes not copied | ||
| 29 | */ | ||
| 30 | ENTRY(__copy_to_user) | ||
| 31 | add x4, x0, x2 // upper user buffer boundary | ||
| 32 | subs x2, x2, #8 | ||
| 33 | b.mi 2f | ||
| 34 | 1: | ||
| 35 | ldr x3, [x1], #8 | ||
| 36 | subs x2, x2, #8 | ||
| 37 | USER(9f, str x3, [x0], #8 ) | ||
| 38 | b.pl 1b | ||
| 39 | 2: adds x2, x2, #4 | ||
| 40 | b.mi 3f | ||
| 41 | ldr w3, [x1], #4 | ||
| 42 | sub x2, x2, #4 | ||
| 43 | USER(9f, str w3, [x0], #4 ) | ||
| 44 | 3: adds x2, x2, #2 | ||
| 45 | b.mi 4f | ||
| 46 | ldrh w3, [x1], #2 | ||
| 47 | sub x2, x2, #2 | ||
| 48 | USER(9f, strh w3, [x0], #2 ) | ||
| 49 | 4: adds x2, x2, #1 | ||
| 50 | b.mi 5f | ||
| 51 | ldrb w3, [x1] | ||
| 52 | USER(9f, strb w3, [x0] ) | ||
| 53 | 5: mov x0, #0 | ||
| 54 | ret | ||
| 55 | ENDPROC(__copy_to_user) | ||
| 56 | |||
| 57 | .section .fixup,"ax" | ||
| 58 | .align 2 | ||
| 59 | 9: sub x0, x4, x0 // bytes not copied | ||
| 60 | ret | ||
| 61 | .previous | ||
diff --git a/arch/arm64/lib/delay.c b/arch/arm64/lib/delay.c new file mode 100644 index 000000000000..dad4ec9bbfd1 --- /dev/null +++ b/arch/arm64/lib/delay.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * Delay loops based on the OpenRISC implementation. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Limited | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: Will Deacon <will.deacon@arm.com> | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/timex.h> | ||
| 26 | |||
| 27 | void __delay(unsigned long cycles) | ||
| 28 | { | ||
| 29 | cycles_t start = get_cycles(); | ||
| 30 | |||
| 31 | while ((get_cycles() - start) < cycles) | ||
| 32 | cpu_relax(); | ||
| 33 | } | ||
| 34 | EXPORT_SYMBOL(__delay); | ||
| 35 | |||
| 36 | inline void __const_udelay(unsigned long xloops) | ||
| 37 | { | ||
| 38 | unsigned long loops; | ||
| 39 | |||
| 40 | loops = xloops * loops_per_jiffy * HZ; | ||
| 41 | __delay(loops >> 32); | ||
| 42 | } | ||
| 43 | EXPORT_SYMBOL(__const_udelay); | ||
| 44 | |||
| 45 | void __udelay(unsigned long usecs) | ||
| 46 | { | ||
| 47 | __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */ | ||
| 48 | } | ||
| 49 | EXPORT_SYMBOL(__udelay); | ||
| 50 | |||
| 51 | void __ndelay(unsigned long nsecs) | ||
| 52 | { | ||
| 53 | __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */ | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL(__ndelay); | ||
diff --git a/arch/arm64/lib/strncpy_from_user.S b/arch/arm64/lib/strncpy_from_user.S new file mode 100644 index 000000000000..56e448a831a0 --- /dev/null +++ b/arch/arm64/lib/strncpy_from_user.S | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/lib/strncpy_from_user.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2000 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/linkage.h> | ||
| 21 | #include <asm/assembler.h> | ||
| 22 | #include <asm/errno.h> | ||
| 23 | |||
| 24 | .text | ||
| 25 | .align 5 | ||
| 26 | |||
| 27 | /* | ||
| 28 | * Copy a string from user space to kernel space. | ||
| 29 | * x0 = dst, x1 = src, x2 = byte length | ||
| 30 | * returns the number of characters copied (strlen of copied string), | ||
| 31 | * -EFAULT on exception, or "len" if we fill the whole buffer | ||
| 32 | */ | ||
| 33 | ENTRY(__strncpy_from_user) | ||
| 34 | mov x4, x1 | ||
| 35 | 1: subs x2, x2, #1 | ||
| 36 | bmi 2f | ||
| 37 | USER(9f, ldrb w3, [x1], #1 ) | ||
| 38 | strb w3, [x0], #1 | ||
| 39 | cbnz w3, 1b | ||
| 40 | sub x1, x1, #1 // take NUL character out of count | ||
| 41 | 2: sub x0, x1, x4 | ||
| 42 | ret | ||
| 43 | ENDPROC(__strncpy_from_user) | ||
| 44 | |||
| 45 | .section .fixup,"ax" | ||
| 46 | .align 0 | ||
| 47 | 9: strb wzr, [x0] // null terminate | ||
| 48 | mov x0, #-EFAULT | ||
| 49 | ret | ||
| 50 | .previous | ||
diff --git a/arch/arm64/lib/strnlen_user.S b/arch/arm64/lib/strnlen_user.S new file mode 100644 index 000000000000..7f7b176a5646 --- /dev/null +++ b/arch/arm64/lib/strnlen_user.S | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/lib/strnlen_user.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2000 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/linkage.h> | ||
| 21 | #include <asm/assembler.h> | ||
| 22 | #include <asm/errno.h> | ||
| 23 | |||
| 24 | .text | ||
| 25 | .align 5 | ||
| 26 | |||
| 27 | /* Prototype: unsigned long __strnlen_user(const char *str, long n) | ||
| 28 | * Purpose : get length of a string in user memory | ||
| 29 | * Params : str - address of string in user memory | ||
| 30 | * Returns : length of string *including terminator* | ||
| 31 | * or zero on exception, or n if too long | ||
| 32 | */ | ||
| 33 | ENTRY(__strnlen_user) | ||
| 34 | mov x2, x0 | ||
| 35 | 1: subs x1, x1, #1 | ||
| 36 | b.mi 2f | ||
| 37 | USER(9f, ldrb w3, [x0], #1 ) | ||
| 38 | cbnz w3, 1b | ||
| 39 | 2: sub x0, x0, x2 | ||
| 40 | ret | ||
| 41 | ENDPROC(__strnlen_user) | ||
| 42 | |||
| 43 | .section .fixup,"ax" | ||
| 44 | .align 0 | ||
| 45 | 9: mov x0, #0 | ||
| 46 | ret | ||
| 47 | .previous | ||
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile new file mode 100644 index 000000000000..3140a2abcdc2 --- /dev/null +++ b/arch/arm64/mm/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | obj-y := dma-mapping.o extable.o fault.o init.o \ | ||
| 2 | cache.o copypage.o flush.o \ | ||
| 3 | ioremap.o mmap.o pgd.o mmu.o \ | ||
| 4 | context.o tlb.o proc.o | ||
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S new file mode 100644 index 000000000000..abe69b80cf7f --- /dev/null +++ b/arch/arm64/mm/cache.S | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | /* | ||
| 2 | * Cache maintenance | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 Deep Blue Solutions Ltd. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/linkage.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <asm/assembler.h> | ||
| 23 | |||
| 24 | #include "proc-macros.S" | ||
| 25 | |||
| 26 | /* | ||
| 27 | * __flush_dcache_all() | ||
| 28 | * | ||
| 29 | * Flush the whole D-cache. | ||
| 30 | * | ||
| 31 | * Corrupted registers: x0-x7, x9-x11 | ||
| 32 | */ | ||
| 33 | ENTRY(__flush_dcache_all) | ||
| 34 | dsb sy // ensure ordering with previous memory accesses | ||
| 35 | mrs x0, clidr_el1 // read clidr | ||
| 36 | and x3, x0, #0x7000000 // extract loc from clidr | ||
| 37 | lsr x3, x3, #23 // left align loc bit field | ||
| 38 | cbz x3, finished // if loc is 0, then no need to clean | ||
| 39 | mov x10, #0 // start clean at cache level 0 | ||
| 40 | loop1: | ||
| 41 | add x2, x10, x10, lsr #1 // work out 3x current cache level | ||
| 42 | lsr x1, x0, x2 // extract cache type bits from clidr | ||
| 43 | and x1, x1, #7 // mask of the bits for current cache only | ||
| 44 | cmp x1, #2 // see what cache we have at this level | ||
| 45 | b.lt skip // skip if no cache, or just i-cache | ||
| 46 | save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic | ||
| 47 | msr csselr_el1, x10 // select current cache level in csselr | ||
| 48 | isb // isb to sych the new cssr&csidr | ||
| 49 | mrs x1, ccsidr_el1 // read the new ccsidr | ||
| 50 | restore_irqs x9 | ||
| 51 | and x2, x1, #7 // extract the length of the cache lines | ||
| 52 | add x2, x2, #4 // add 4 (line length offset) | ||
| 53 | mov x4, #0x3ff | ||
| 54 | and x4, x4, x1, lsr #3 // find maximum number on the way size | ||
| 55 | clz x5, x4 // find bit position of way size increment | ||
| 56 | mov x7, #0x7fff | ||
| 57 | and x7, x7, x1, lsr #13 // extract max number of the index size | ||
| 58 | loop2: | ||
| 59 | mov x9, x4 // create working copy of max way size | ||
| 60 | loop3: | ||
| 61 | lsl x6, x9, x5 | ||
| 62 | orr x11, x10, x6 // factor way and cache number into x11 | ||
| 63 | lsl x6, x7, x2 | ||
| 64 | orr x11, x11, x6 // factor index number into x11 | ||
| 65 | dc cisw, x11 // clean & invalidate by set/way | ||
| 66 | subs x9, x9, #1 // decrement the way | ||
| 67 | b.ge loop3 | ||
| 68 | subs x7, x7, #1 // decrement the index | ||
| 69 | b.ge loop2 | ||
| 70 | skip: | ||
| 71 | add x10, x10, #2 // increment cache number | ||
| 72 | cmp x3, x10 | ||
| 73 | b.gt loop1 | ||
| 74 | finished: | ||
| 75 | mov x10, #0 // swith back to cache level 0 | ||
| 76 | msr csselr_el1, x10 // select current cache level in csselr | ||
| 77 | dsb sy | ||
| 78 | isb | ||
| 79 | ret | ||
| 80 | ENDPROC(__flush_dcache_all) | ||
| 81 | |||
| 82 | /* | ||
| 83 | * flush_cache_all() | ||
| 84 | * | ||
| 85 | * Flush the entire cache system. The data cache flush is now achieved | ||
| 86 | * using atomic clean / invalidates working outwards from L1 cache. This | ||
| 87 | * is done using Set/Way based cache maintainance instructions. The | ||
| 88 | * instruction cache can still be invalidated back to the point of | ||
| 89 | * unification in a single instruction. | ||
| 90 | */ | ||
| 91 | ENTRY(flush_cache_all) | ||
| 92 | mov x12, lr | ||
| 93 | bl __flush_dcache_all | ||
| 94 | mov x0, #0 | ||
| 95 | ic ialluis // I+BTB cache invalidate | ||
| 96 | ret x12 | ||
| 97 | ENDPROC(flush_cache_all) | ||
| 98 | |||
| 99 | /* | ||
| 100 | * flush_icache_range(start,end) | ||
| 101 | * | ||
| 102 | * Ensure that the I and D caches are coherent within specified region. | ||
| 103 | * This is typically used when code has been written to a memory region, | ||
| 104 | * and will be executed. | ||
| 105 | * | ||
| 106 | * - start - virtual start address of region | ||
| 107 | * - end - virtual end address of region | ||
| 108 | */ | ||
| 109 | ENTRY(flush_icache_range) | ||
| 110 | /* FALLTHROUGH */ | ||
| 111 | |||
| 112 | /* | ||
| 113 | * __flush_cache_user_range(start,end) | ||
| 114 | * | ||
| 115 | * Ensure that the I and D caches are coherent within specified region. | ||
| 116 | * This is typically used when code has been written to a memory region, | ||
| 117 | * and will be executed. | ||
| 118 | * | ||
| 119 | * - start - virtual start address of region | ||
| 120 | * - end - virtual end address of region | ||
| 121 | */ | ||
| 122 | ENTRY(__flush_cache_user_range) | ||
| 123 | dcache_line_size x2, x3 | ||
| 124 | sub x3, x2, #1 | ||
| 125 | bic x4, x0, x3 | ||
| 126 | 1: | ||
| 127 | USER(9f, dc cvau, x4 ) // clean D line to PoU | ||
| 128 | add x4, x4, x2 | ||
| 129 | cmp x4, x1 | ||
| 130 | b.lo 1b | ||
| 131 | dsb sy | ||
| 132 | |||
| 133 | icache_line_size x2, x3 | ||
| 134 | sub x3, x2, #1 | ||
| 135 | bic x4, x0, x3 | ||
| 136 | 1: | ||
| 137 | USER(9f, ic ivau, x4 ) // invalidate I line PoU | ||
| 138 | add x4, x4, x2 | ||
| 139 | cmp x4, x1 | ||
| 140 | b.lo 1b | ||
| 141 | 9: // ignore any faulting cache operation | ||
| 142 | dsb sy | ||
| 143 | isb | ||
| 144 | ret | ||
| 145 | ENDPROC(flush_icache_range) | ||
| 146 | ENDPROC(__flush_cache_user_range) | ||
| 147 | |||
| 148 | /* | ||
| 149 | * __flush_kern_dcache_page(kaddr) | ||
| 150 | * | ||
| 151 | * Ensure that the data held in the page kaddr is written back to the | ||
| 152 | * page in question. | ||
| 153 | * | ||
| 154 | * - kaddr - kernel address | ||
| 155 | * - size - size in question | ||
| 156 | */ | ||
| 157 | ENTRY(__flush_dcache_area) | ||
| 158 | dcache_line_size x2, x3 | ||
| 159 | add x1, x0, x1 | ||
| 160 | sub x3, x2, #1 | ||
| 161 | bic x0, x0, x3 | ||
| 162 | 1: dc civac, x0 // clean & invalidate D line / unified line | ||
| 163 | add x0, x0, x2 | ||
| 164 | cmp x0, x1 | ||
| 165 | b.lo 1b | ||
| 166 | dsb sy | ||
| 167 | ret | ||
| 168 | ENDPROC(__flush_dcache_area) | ||
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c new file mode 100644 index 000000000000..baa758d37021 --- /dev/null +++ b/arch/arm64/mm/context.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/context.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/mm.h> | ||
| 23 | #include <linux/smp.h> | ||
| 24 | #include <linux/percpu.h> | ||
| 25 | |||
| 26 | #include <asm/mmu_context.h> | ||
| 27 | #include <asm/tlbflush.h> | ||
| 28 | #include <asm/cachetype.h> | ||
| 29 | |||
| 30 | #define asid_bits(reg) \ | ||
| 31 | (((read_cpuid(ID_AA64MMFR0_EL1) & 0xf0) >> 2) + 8) | ||
| 32 | |||
| 33 | #define ASID_FIRST_VERSION (1 << MAX_ASID_BITS) | ||
| 34 | |||
| 35 | static DEFINE_RAW_SPINLOCK(cpu_asid_lock); | ||
| 36 | unsigned int cpu_last_asid = ASID_FIRST_VERSION; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * We fork()ed a process, and we need a new context for the child to run in. | ||
| 40 | */ | ||
| 41 | void __init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
| 42 | { | ||
| 43 | mm->context.id = 0; | ||
| 44 | raw_spin_lock_init(&mm->context.id_lock); | ||
| 45 | } | ||
| 46 | |||
| 47 | static void flush_context(void) | ||
| 48 | { | ||
| 49 | /* set the reserved TTBR0 before flushing the TLB */ | ||
| 50 | cpu_set_reserved_ttbr0(); | ||
| 51 | flush_tlb_all(); | ||
| 52 | if (icache_is_aivivt()) | ||
| 53 | __flush_icache_all(); | ||
| 54 | } | ||
| 55 | |||
| 56 | #ifdef CONFIG_SMP | ||
| 57 | |||
| 58 | static void set_mm_context(struct mm_struct *mm, unsigned int asid) | ||
| 59 | { | ||
| 60 | unsigned long flags; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Locking needed for multi-threaded applications where the same | ||
| 64 | * mm->context.id could be set from different CPUs during the | ||
| 65 | * broadcast. This function is also called via IPI so the | ||
| 66 | * mm->context.id_lock has to be IRQ-safe. | ||
| 67 | */ | ||
| 68 | raw_spin_lock_irqsave(&mm->context.id_lock, flags); | ||
| 69 | if (likely((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS)) { | ||
| 70 | /* | ||
| 71 | * Old version of ASID found. Set the new one and reset | ||
| 72 | * mm_cpumask(mm). | ||
| 73 | */ | ||
| 74 | mm->context.id = asid; | ||
| 75 | cpumask_clear(mm_cpumask(mm)); | ||
| 76 | } | ||
| 77 | raw_spin_unlock_irqrestore(&mm->context.id_lock, flags); | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Set the mm_cpumask(mm) bit for the current CPU. | ||
| 81 | */ | ||
| 82 | cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); | ||
| 83 | } | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Reset the ASID on the current CPU. This function call is broadcast from the | ||
| 87 | * CPU handling the ASID rollover and holding cpu_asid_lock. | ||
| 88 | */ | ||
| 89 | static void reset_context(void *info) | ||
| 90 | { | ||
| 91 | unsigned int asid; | ||
| 92 | unsigned int cpu = smp_processor_id(); | ||
| 93 | struct mm_struct *mm = current->active_mm; | ||
| 94 | |||
| 95 | smp_rmb(); | ||
| 96 | asid = cpu_last_asid + cpu; | ||
| 97 | |||
| 98 | flush_context(); | ||
| 99 | set_mm_context(mm, asid); | ||
| 100 | |||
| 101 | /* set the new ASID */ | ||
| 102 | cpu_switch_mm(mm->pgd, mm); | ||
| 103 | } | ||
| 104 | |||
| 105 | #else | ||
| 106 | |||
| 107 | static inline void set_mm_context(struct mm_struct *mm, unsigned int asid) | ||
| 108 | { | ||
| 109 | mm->context.id = asid; | ||
| 110 | cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id())); | ||
| 111 | } | ||
| 112 | |||
| 113 | #endif | ||
| 114 | |||
| 115 | void __new_context(struct mm_struct *mm) | ||
| 116 | { | ||
| 117 | unsigned int asid; | ||
| 118 | unsigned int bits = asid_bits(); | ||
| 119 | |||
| 120 | raw_spin_lock(&cpu_asid_lock); | ||
| 121 | #ifdef CONFIG_SMP | ||
| 122 | /* | ||
| 123 | * Check the ASID again, in case the change was broadcast from another | ||
| 124 | * CPU before we acquired the lock. | ||
| 125 | */ | ||
| 126 | if (!unlikely((mm->context.id ^ cpu_last_asid) >> MAX_ASID_BITS)) { | ||
| 127 | cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm)); | ||
| 128 | raw_spin_unlock(&cpu_asid_lock); | ||
| 129 | return; | ||
| 130 | } | ||
| 131 | #endif | ||
| 132 | /* | ||
| 133 | * At this point, it is guaranteed that the current mm (with an old | ||
| 134 | * ASID) isn't active on any other CPU since the ASIDs are changed | ||
| 135 | * simultaneously via IPI. | ||
| 136 | */ | ||
| 137 | asid = ++cpu_last_asid; | ||
| 138 | |||
| 139 | /* | ||
| 140 | * If we've used up all our ASIDs, we need to start a new version and | ||
| 141 | * flush the TLB. | ||
| 142 | */ | ||
| 143 | if (unlikely((asid & ((1 << bits) - 1)) == 0)) { | ||
| 144 | /* increment the ASID version */ | ||
| 145 | cpu_last_asid += (1 << MAX_ASID_BITS) - (1 << bits); | ||
| 146 | if (cpu_last_asid == 0) | ||
| 147 | cpu_last_asid = ASID_FIRST_VERSION; | ||
| 148 | asid = cpu_last_asid + smp_processor_id(); | ||
| 149 | flush_context(); | ||
| 150 | #ifdef CONFIG_SMP | ||
| 151 | smp_wmb(); | ||
| 152 | smp_call_function(reset_context, NULL, 1); | ||
| 153 | #endif | ||
| 154 | cpu_last_asid += NR_CPUS - 1; | ||
| 155 | } | ||
| 156 | |||
| 157 | set_mm_context(mm, asid); | ||
| 158 | raw_spin_unlock(&cpu_asid_lock); | ||
| 159 | } | ||
diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c new file mode 100644 index 000000000000..9aecbace4128 --- /dev/null +++ b/arch/arm64/mm/copypage.c | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/copypage.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 Deep Blue Solutions Ltd, All Rights Reserved. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/mm.h> | ||
| 21 | |||
| 22 | #include <asm/page.h> | ||
| 23 | #include <asm/cacheflush.h> | ||
| 24 | |||
| 25 | void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) | ||
| 26 | { | ||
| 27 | copy_page(kto, kfrom); | ||
| 28 | __flush_dcache_area(kto, PAGE_SIZE); | ||
| 29 | } | ||
| 30 | |||
| 31 | void __cpu_clear_user_page(void *kaddr, unsigned long vaddr) | ||
| 32 | { | ||
| 33 | clear_page(kaddr); | ||
| 34 | } | ||
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c new file mode 100644 index 000000000000..5eb244453a5b --- /dev/null +++ b/arch/arm64/mm/dma-mapping.c | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* | ||
| 2 | * SWIOTLB-based DMA API implementation | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/gfp.h> | ||
| 21 | #include <linux/export.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/dma-mapping.h> | ||
| 24 | #include <linux/vmalloc.h> | ||
| 25 | #include <linux/swiotlb.h> | ||
| 26 | |||
| 27 | #include <asm/cacheflush.h> | ||
| 28 | |||
| 29 | struct dma_map_ops *dma_ops; | ||
| 30 | EXPORT_SYMBOL(dma_ops); | ||
| 31 | |||
| 32 | static void *arm64_swiotlb_alloc_coherent(struct device *dev, size_t size, | ||
| 33 | dma_addr_t *dma_handle, gfp_t flags, | ||
| 34 | struct dma_attrs *attrs) | ||
| 35 | { | ||
| 36 | if (IS_ENABLED(CONFIG_ZONE_DMA32) && | ||
| 37 | dev->coherent_dma_mask <= DMA_BIT_MASK(32)) | ||
| 38 | flags |= GFP_DMA32; | ||
| 39 | return swiotlb_alloc_coherent(dev, size, dma_handle, flags); | ||
| 40 | } | ||
| 41 | |||
| 42 | static void arm64_swiotlb_free_coherent(struct device *dev, size_t size, | ||
| 43 | void *vaddr, dma_addr_t dma_handle, | ||
| 44 | struct dma_attrs *attrs) | ||
| 45 | { | ||
| 46 | swiotlb_free_coherent(dev, size, vaddr, dma_handle); | ||
| 47 | } | ||
| 48 | |||
| 49 | static struct dma_map_ops arm64_swiotlb_dma_ops = { | ||
| 50 | .alloc = arm64_swiotlb_alloc_coherent, | ||
| 51 | .free = arm64_swiotlb_free_coherent, | ||
| 52 | .map_page = swiotlb_map_page, | ||
| 53 | .unmap_page = swiotlb_unmap_page, | ||
| 54 | .map_sg = swiotlb_map_sg_attrs, | ||
| 55 | .unmap_sg = swiotlb_unmap_sg_attrs, | ||
| 56 | .sync_single_for_cpu = swiotlb_sync_single_for_cpu, | ||
| 57 | .sync_single_for_device = swiotlb_sync_single_for_device, | ||
| 58 | .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu, | ||
| 59 | .sync_sg_for_device = swiotlb_sync_sg_for_device, | ||
| 60 | .dma_supported = swiotlb_dma_supported, | ||
| 61 | .mapping_error = swiotlb_dma_mapping_error, | ||
| 62 | }; | ||
| 63 | |||
| 64 | void __init swiotlb_init_with_default_size(size_t default_size, int verbose); | ||
| 65 | |||
| 66 | void __init arm64_swiotlb_init(size_t max_size) | ||
| 67 | { | ||
| 68 | dma_ops = &arm64_swiotlb_dma_ops; | ||
| 69 | swiotlb_init_with_default_size(min((size_t)SZ_64M, max_size), 1); | ||
| 70 | } | ||
| 71 | |||
| 72 | #define PREALLOC_DMA_DEBUG_ENTRIES 4096 | ||
| 73 | |||
| 74 | static int __init dma_debug_do_init(void) | ||
| 75 | { | ||
| 76 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | fs_initcall(dma_debug_do_init); | ||
diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c new file mode 100644 index 000000000000..79444279ba8c --- /dev/null +++ b/arch/arm64/mm/extable.c | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/extable.c | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/module.h> | ||
| 6 | #include <linux/uaccess.h> | ||
| 7 | |||
| 8 | int fixup_exception(struct pt_regs *regs) | ||
| 9 | { | ||
| 10 | const struct exception_table_entry *fixup; | ||
| 11 | |||
| 12 | fixup = search_exception_tables(instruction_pointer(regs)); | ||
| 13 | if (fixup) | ||
| 14 | regs->pc = fixup->fixup; | ||
| 15 | |||
| 16 | return fixup != NULL; | ||
| 17 | } | ||
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c new file mode 100644 index 000000000000..1909a69983ca --- /dev/null +++ b/arch/arm64/mm/fault.c | |||
| @@ -0,0 +1,534 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/fault.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995 Linus Torvalds | ||
| 5 | * Copyright (C) 1995-2004 Russell King | ||
| 6 | * Copyright (C) 2012 ARM Ltd. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/signal.h> | ||
| 23 | #include <linux/mm.h> | ||
| 24 | #include <linux/hardirq.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/kprobes.h> | ||
| 27 | #include <linux/uaccess.h> | ||
| 28 | #include <linux/page-flags.h> | ||
| 29 | #include <linux/sched.h> | ||
| 30 | #include <linux/highmem.h> | ||
| 31 | #include <linux/perf_event.h> | ||
| 32 | |||
| 33 | #include <asm/exception.h> | ||
| 34 | #include <asm/debug-monitors.h> | ||
| 35 | #include <asm/system_misc.h> | ||
| 36 | #include <asm/pgtable.h> | ||
| 37 | #include <asm/tlbflush.h> | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Dump out the page tables associated with 'addr' in mm 'mm'. | ||
| 41 | */ | ||
| 42 | void show_pte(struct mm_struct *mm, unsigned long addr) | ||
| 43 | { | ||
| 44 | pgd_t *pgd; | ||
| 45 | |||
| 46 | if (!mm) | ||
| 47 | mm = &init_mm; | ||
| 48 | |||
| 49 | pr_alert("pgd = %p\n", mm->pgd); | ||
| 50 | pgd = pgd_offset(mm, addr); | ||
| 51 | pr_alert("[%08lx] *pgd=%016llx", addr, pgd_val(*pgd)); | ||
| 52 | |||
| 53 | do { | ||
| 54 | pud_t *pud; | ||
| 55 | pmd_t *pmd; | ||
| 56 | pte_t *pte; | ||
| 57 | |||
| 58 | if (pgd_none_or_clear_bad(pgd)) | ||
| 59 | break; | ||
| 60 | |||
| 61 | pud = pud_offset(pgd, addr); | ||
| 62 | if (pud_none_or_clear_bad(pud)) | ||
| 63 | break; | ||
| 64 | |||
| 65 | pmd = pmd_offset(pud, addr); | ||
| 66 | printk(", *pmd=%016llx", pmd_val(*pmd)); | ||
| 67 | if (pmd_none_or_clear_bad(pmd)) | ||
| 68 | break; | ||
| 69 | |||
| 70 | pte = pte_offset_map(pmd, addr); | ||
| 71 | printk(", *pte=%016llx", pte_val(*pte)); | ||
| 72 | pte_unmap(pte); | ||
| 73 | } while(0); | ||
| 74 | |||
| 75 | printk("\n"); | ||
| 76 | } | ||
| 77 | |||
| 78 | /* | ||
| 79 | * The kernel tried to access some page that wasn't present. | ||
| 80 | */ | ||
| 81 | static void __do_kernel_fault(struct mm_struct *mm, unsigned long addr, | ||
| 82 | unsigned int esr, struct pt_regs *regs) | ||
| 83 | { | ||
| 84 | /* | ||
| 85 | * Are we prepared to handle this kernel fault? | ||
| 86 | */ | ||
| 87 | if (fixup_exception(regs)) | ||
| 88 | return; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * No handler, we'll have to terminate things with extreme prejudice. | ||
| 92 | */ | ||
| 93 | bust_spinlocks(1); | ||
| 94 | pr_alert("Unable to handle kernel %s at virtual address %08lx\n", | ||
| 95 | (addr < PAGE_SIZE) ? "NULL pointer dereference" : | ||
| 96 | "paging request", addr); | ||
| 97 | |||
| 98 | show_pte(mm, addr); | ||
| 99 | die("Oops", regs, esr); | ||
| 100 | bust_spinlocks(0); | ||
| 101 | do_exit(SIGKILL); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Something tried to access memory that isn't in our memory map. User mode | ||
| 106 | * accesses just cause a SIGSEGV | ||
| 107 | */ | ||
| 108 | static void __do_user_fault(struct task_struct *tsk, unsigned long addr, | ||
| 109 | unsigned int esr, unsigned int sig, int code, | ||
| 110 | struct pt_regs *regs) | ||
| 111 | { | ||
| 112 | struct siginfo si; | ||
| 113 | |||
| 114 | if (show_unhandled_signals) { | ||
| 115 | pr_info("%s[%d]: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n", | ||
| 116 | tsk->comm, task_pid_nr(tsk), sig, addr, esr); | ||
| 117 | show_pte(tsk->mm, addr); | ||
| 118 | show_regs(regs); | ||
| 119 | } | ||
| 120 | |||
| 121 | tsk->thread.fault_address = addr; | ||
| 122 | si.si_signo = sig; | ||
| 123 | si.si_errno = 0; | ||
| 124 | si.si_code = code; | ||
| 125 | si.si_addr = (void __user *)addr; | ||
| 126 | force_sig_info(sig, &si, tsk); | ||
| 127 | } | ||
| 128 | |||
| 129 | void do_bad_area(unsigned long addr, unsigned int esr, struct pt_regs *regs) | ||
| 130 | { | ||
| 131 | struct task_struct *tsk = current; | ||
| 132 | struct mm_struct *mm = tsk->active_mm; | ||
| 133 | |||
| 134 | /* | ||
| 135 | * If we are in kernel mode at this point, we have no context to | ||
| 136 | * handle this fault with. | ||
| 137 | */ | ||
| 138 | if (user_mode(regs)) | ||
| 139 | __do_user_fault(tsk, addr, esr, SIGSEGV, SEGV_MAPERR, regs); | ||
| 140 | else | ||
| 141 | __do_kernel_fault(mm, addr, esr, regs); | ||
| 142 | } | ||
| 143 | |||
| 144 | #define VM_FAULT_BADMAP 0x010000 | ||
| 145 | #define VM_FAULT_BADACCESS 0x020000 | ||
| 146 | |||
| 147 | #define ESR_WRITE (1 << 6) | ||
| 148 | #define ESR_LNX_EXEC (1 << 24) | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Check that the permissions on the VMA allow for the fault which occurred. | ||
| 152 | * If we encountered a write fault, we must have write permission, otherwise | ||
| 153 | * we allow any permission. | ||
| 154 | */ | ||
| 155 | static inline bool access_error(unsigned int esr, struct vm_area_struct *vma) | ||
| 156 | { | ||
| 157 | unsigned int mask = VM_READ | VM_WRITE | VM_EXEC; | ||
| 158 | |||
| 159 | if (esr & ESR_WRITE) | ||
| 160 | mask = VM_WRITE; | ||
| 161 | if (esr & ESR_LNX_EXEC) | ||
| 162 | mask = VM_EXEC; | ||
| 163 | |||
| 164 | return vma->vm_flags & mask ? false : true; | ||
| 165 | } | ||
| 166 | |||
| 167 | static int __do_page_fault(struct mm_struct *mm, unsigned long addr, | ||
| 168 | unsigned int esr, unsigned int flags, | ||
| 169 | struct task_struct *tsk) | ||
| 170 | { | ||
| 171 | struct vm_area_struct *vma; | ||
| 172 | int fault; | ||
| 173 | |||
| 174 | vma = find_vma(mm, addr); | ||
| 175 | fault = VM_FAULT_BADMAP; | ||
| 176 | if (unlikely(!vma)) | ||
| 177 | goto out; | ||
| 178 | if (unlikely(vma->vm_start > addr)) | ||
| 179 | goto check_stack; | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Ok, we have a good vm_area for this memory access, so we can handle | ||
| 183 | * it. | ||
| 184 | */ | ||
| 185 | good_area: | ||
| 186 | if (access_error(esr, vma)) { | ||
| 187 | fault = VM_FAULT_BADACCESS; | ||
| 188 | goto out; | ||
| 189 | } | ||
| 190 | |||
| 191 | return handle_mm_fault(mm, vma, addr & PAGE_MASK, flags); | ||
| 192 | |||
| 193 | check_stack: | ||
| 194 | if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) | ||
| 195 | goto good_area; | ||
| 196 | out: | ||
| 197 | return fault; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, | ||
| 201 | struct pt_regs *regs) | ||
| 202 | { | ||
| 203 | struct task_struct *tsk; | ||
| 204 | struct mm_struct *mm; | ||
| 205 | int fault, sig, code; | ||
| 206 | int write = esr & ESR_WRITE; | ||
| 207 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | | ||
| 208 | (write ? FAULT_FLAG_WRITE : 0); | ||
| 209 | |||
| 210 | tsk = current; | ||
| 211 | mm = tsk->mm; | ||
| 212 | |||
| 213 | /* Enable interrupts if they were enabled in the parent context. */ | ||
| 214 | if (interrupts_enabled(regs)) | ||
| 215 | local_irq_enable(); | ||
| 216 | |||
| 217 | /* | ||
| 218 | * If we're in an interrupt or have no user context, we must not take | ||
| 219 | * the fault. | ||
| 220 | */ | ||
| 221 | if (in_atomic() || !mm) | ||
| 222 | goto no_context; | ||
| 223 | |||
| 224 | /* | ||
| 225 | * As per x86, we may deadlock here. However, since the kernel only | ||
| 226 | * validly references user space from well defined areas of the code, | ||
| 227 | * we can bug out early if this is from code which shouldn't. | ||
| 228 | */ | ||
| 229 | if (!down_read_trylock(&mm->mmap_sem)) { | ||
| 230 | if (!user_mode(regs) && !search_exception_tables(regs->pc)) | ||
| 231 | goto no_context; | ||
| 232 | retry: | ||
| 233 | down_read(&mm->mmap_sem); | ||
| 234 | } else { | ||
| 235 | /* | ||
| 236 | * The above down_read_trylock() might have succeeded in which | ||
| 237 | * case, we'll have missed the might_sleep() from down_read(). | ||
| 238 | */ | ||
| 239 | might_sleep(); | ||
| 240 | #ifdef CONFIG_DEBUG_VM | ||
| 241 | if (!user_mode(regs) && !search_exception_tables(regs->pc)) | ||
| 242 | goto no_context; | ||
| 243 | #endif | ||
| 244 | } | ||
| 245 | |||
| 246 | fault = __do_page_fault(mm, addr, esr, flags, tsk); | ||
| 247 | |||
| 248 | /* | ||
| 249 | * If we need to retry but a fatal signal is pending, handle the | ||
| 250 | * signal first. We do not need to release the mmap_sem because it | ||
| 251 | * would already be released in __lock_page_or_retry in mm/filemap.c. | ||
| 252 | */ | ||
| 253 | if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) | ||
| 254 | return 0; | ||
| 255 | |||
| 256 | /* | ||
| 257 | * Major/minor page fault accounting is only done on the initial | ||
| 258 | * attempt. If we go through a retry, it is extremely likely that the | ||
| 259 | * page will be found in page cache at that point. | ||
| 260 | */ | ||
| 261 | |||
| 262 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); | ||
| 263 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | ||
| 264 | if (fault & VM_FAULT_MAJOR) { | ||
| 265 | tsk->maj_flt++; | ||
| 266 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, | ||
| 267 | addr); | ||
| 268 | } else { | ||
| 269 | tsk->min_flt++; | ||
| 270 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, | ||
| 271 | addr); | ||
| 272 | } | ||
| 273 | if (fault & VM_FAULT_RETRY) { | ||
| 274 | /* | ||
| 275 | * Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk of | ||
| 276 | * starvation. | ||
| 277 | */ | ||
| 278 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | ||
| 279 | goto retry; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | up_read(&mm->mmap_sem); | ||
| 284 | |||
| 285 | /* | ||
| 286 | * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR | ||
| 287 | */ | ||
| 288 | if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | | ||
| 289 | VM_FAULT_BADACCESS)))) | ||
| 290 | return 0; | ||
| 291 | |||
| 292 | if (fault & VM_FAULT_OOM) { | ||
| 293 | /* | ||
| 294 | * We ran out of memory, call the OOM killer, and return to | ||
| 295 | * userspace (which will retry the fault, or kill us if we got | ||
| 296 | * oom-killed). | ||
| 297 | */ | ||
| 298 | pagefault_out_of_memory(); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 303 | * If we are in kernel mode at this point, we have no context to | ||
| 304 | * handle this fault with. | ||
| 305 | */ | ||
| 306 | if (!user_mode(regs)) | ||
| 307 | goto no_context; | ||
| 308 | |||
| 309 | if (fault & VM_FAULT_SIGBUS) { | ||
| 310 | /* | ||
| 311 | * We had some memory, but were unable to successfully fix up | ||
| 312 | * this page fault. | ||
| 313 | */ | ||
| 314 | sig = SIGBUS; | ||
| 315 | code = BUS_ADRERR; | ||
| 316 | } else { | ||
| 317 | /* | ||
| 318 | * Something tried to access memory that isn't in our memory | ||
| 319 | * map. | ||
| 320 | */ | ||
| 321 | sig = SIGSEGV; | ||
| 322 | code = fault == VM_FAULT_BADACCESS ? | ||
| 323 | SEGV_ACCERR : SEGV_MAPERR; | ||
| 324 | } | ||
| 325 | |||
| 326 | __do_user_fault(tsk, addr, esr, sig, code, regs); | ||
| 327 | return 0; | ||
| 328 | |||
| 329 | no_context: | ||
| 330 | __do_kernel_fault(mm, addr, esr, regs); | ||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | /* | ||
| 335 | * First Level Translation Fault Handler | ||
| 336 | * | ||
| 337 | * We enter here because the first level page table doesn't contain a valid | ||
| 338 | * entry for the address. | ||
| 339 | * | ||
| 340 | * If the address is in kernel space (>= TASK_SIZE), then we are probably | ||
| 341 | * faulting in the vmalloc() area. | ||
| 342 | * | ||
| 343 | * If the init_task's first level page tables contains the relevant entry, we | ||
| 344 | * copy the it to this task. If not, we send the process a signal, fixup the | ||
| 345 | * exception, or oops the kernel. | ||
| 346 | * | ||
| 347 | * NOTE! We MUST NOT take any locks for this case. We may be in an interrupt | ||
| 348 | * or a critical region, and should only copy the information from the master | ||
| 349 | * page table, nothing more. | ||
| 350 | */ | ||
| 351 | static int __kprobes do_translation_fault(unsigned long addr, | ||
| 352 | unsigned int esr, | ||
| 353 | struct pt_regs *regs) | ||
| 354 | { | ||
| 355 | if (addr < TASK_SIZE) | ||
| 356 | return do_page_fault(addr, esr, regs); | ||
| 357 | |||
| 358 | do_bad_area(addr, esr, regs); | ||
| 359 | return 0; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Some section permission faults need to be handled gracefully. They can | ||
| 364 | * happen due to a __{get,put}_user during an oops. | ||
| 365 | */ | ||
| 366 | static int do_sect_fault(unsigned long addr, unsigned int esr, | ||
| 367 | struct pt_regs *regs) | ||
| 368 | { | ||
| 369 | do_bad_area(addr, esr, regs); | ||
| 370 | return 0; | ||
| 371 | } | ||
| 372 | |||
| 373 | /* | ||
| 374 | * This abort handler always returns "fault". | ||
| 375 | */ | ||
| 376 | static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs) | ||
| 377 | { | ||
| 378 | return 1; | ||
| 379 | } | ||
| 380 | |||
| 381 | static struct fault_info { | ||
| 382 | int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs); | ||
| 383 | int sig; | ||
| 384 | int code; | ||
| 385 | const char *name; | ||
| 386 | } fault_info[] = { | ||
| 387 | { do_bad, SIGBUS, 0, "ttbr address size fault" }, | ||
| 388 | { do_bad, SIGBUS, 0, "level 1 address size fault" }, | ||
| 389 | { do_bad, SIGBUS, 0, "level 2 address size fault" }, | ||
| 390 | { do_bad, SIGBUS, 0, "level 3 address size fault" }, | ||
| 391 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "input address range fault" }, | ||
| 392 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" }, | ||
| 393 | { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" }, | ||
| 394 | { do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" }, | ||
| 395 | { do_bad, SIGBUS, 0, "reserved access flag fault" }, | ||
| 396 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" }, | ||
| 397 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" }, | ||
| 398 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" }, | ||
| 399 | { do_bad, SIGBUS, 0, "reserved permission fault" }, | ||
| 400 | { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" }, | ||
| 401 | { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" }, | ||
| 402 | { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" }, | ||
| 403 | { do_bad, SIGBUS, 0, "synchronous external abort" }, | ||
| 404 | { do_bad, SIGBUS, 0, "asynchronous external abort" }, | ||
| 405 | { do_bad, SIGBUS, 0, "unknown 18" }, | ||
| 406 | { do_bad, SIGBUS, 0, "unknown 19" }, | ||
| 407 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
| 408 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
| 409 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
| 410 | { do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" }, | ||
| 411 | { do_bad, SIGBUS, 0, "synchronous parity error" }, | ||
| 412 | { do_bad, SIGBUS, 0, "asynchronous parity error" }, | ||
| 413 | { do_bad, SIGBUS, 0, "unknown 26" }, | ||
| 414 | { do_bad, SIGBUS, 0, "unknown 27" }, | ||
| 415 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
| 416 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
| 417 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
| 418 | { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" }, | ||
| 419 | { do_bad, SIGBUS, 0, "unknown 32" }, | ||
| 420 | { do_bad, SIGBUS, BUS_ADRALN, "alignment fault" }, | ||
| 421 | { do_bad, SIGBUS, 0, "debug event" }, | ||
| 422 | { do_bad, SIGBUS, 0, "unknown 35" }, | ||
| 423 | { do_bad, SIGBUS, 0, "unknown 36" }, | ||
| 424 | { do_bad, SIGBUS, 0, "unknown 37" }, | ||
| 425 | { do_bad, SIGBUS, 0, "unknown 38" }, | ||
| 426 | { do_bad, SIGBUS, 0, "unknown 39" }, | ||
| 427 | { do_bad, SIGBUS, 0, "unknown 40" }, | ||
| 428 | { do_bad, SIGBUS, 0, "unknown 41" }, | ||
| 429 | { do_bad, SIGBUS, 0, "unknown 42" }, | ||
| 430 | { do_bad, SIGBUS, 0, "unknown 43" }, | ||
| 431 | { do_bad, SIGBUS, 0, "unknown 44" }, | ||
| 432 | { do_bad, SIGBUS, 0, "unknown 45" }, | ||
| 433 | { do_bad, SIGBUS, 0, "unknown 46" }, | ||
| 434 | { do_bad, SIGBUS, 0, "unknown 47" }, | ||
| 435 | { do_bad, SIGBUS, 0, "unknown 48" }, | ||
| 436 | { do_bad, SIGBUS, 0, "unknown 49" }, | ||
| 437 | { do_bad, SIGBUS, 0, "unknown 50" }, | ||
| 438 | { do_bad, SIGBUS, 0, "unknown 51" }, | ||
| 439 | { do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" }, | ||
| 440 | { do_bad, SIGBUS, 0, "unknown 53" }, | ||
| 441 | { do_bad, SIGBUS, 0, "unknown 54" }, | ||
| 442 | { do_bad, SIGBUS, 0, "unknown 55" }, | ||
| 443 | { do_bad, SIGBUS, 0, "unknown 56" }, | ||
| 444 | { do_bad, SIGBUS, 0, "unknown 57" }, | ||
| 445 | { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" }, | ||
| 446 | { do_bad, SIGBUS, 0, "unknown 59" }, | ||
| 447 | { do_bad, SIGBUS, 0, "unknown 60" }, | ||
| 448 | { do_bad, SIGBUS, 0, "unknown 61" }, | ||
| 449 | { do_bad, SIGBUS, 0, "unknown 62" }, | ||
| 450 | { do_bad, SIGBUS, 0, "unknown 63" }, | ||
| 451 | }; | ||
| 452 | |||
| 453 | /* | ||
| 454 | * Dispatch a data abort to the relevant handler. | ||
| 455 | */ | ||
| 456 | asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, | ||
| 457 | struct pt_regs *regs) | ||
| 458 | { | ||
| 459 | const struct fault_info *inf = fault_info + (esr & 63); | ||
| 460 | struct siginfo info; | ||
| 461 | |||
| 462 | if (!inf->fn(addr, esr, regs)) | ||
| 463 | return; | ||
| 464 | |||
| 465 | pr_alert("Unhandled fault: %s (0x%08x) at 0x%016lx\n", | ||
| 466 | inf->name, esr, addr); | ||
| 467 | |||
| 468 | info.si_signo = inf->sig; | ||
| 469 | info.si_errno = 0; | ||
| 470 | info.si_code = inf->code; | ||
| 471 | info.si_addr = (void __user *)addr; | ||
| 472 | arm64_notify_die("", regs, &info, esr); | ||
| 473 | } | ||
| 474 | |||
| 475 | /* | ||
| 476 | * Handle stack alignment exceptions. | ||
| 477 | */ | ||
| 478 | asmlinkage void __exception do_sp_pc_abort(unsigned long addr, | ||
| 479 | unsigned int esr, | ||
| 480 | struct pt_regs *regs) | ||
| 481 | { | ||
| 482 | struct siginfo info; | ||
| 483 | |||
| 484 | info.si_signo = SIGBUS; | ||
| 485 | info.si_errno = 0; | ||
| 486 | info.si_code = BUS_ADRALN; | ||
| 487 | info.si_addr = (void __user *)addr; | ||
| 488 | arm64_notify_die("", regs, &info, esr); | ||
| 489 | } | ||
| 490 | |||
| 491 | static struct fault_info debug_fault_info[] = { | ||
| 492 | { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware breakpoint" }, | ||
| 493 | { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware single-step" }, | ||
| 494 | { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware watchpoint" }, | ||
| 495 | { do_bad, SIGBUS, 0, "unknown 3" }, | ||
| 496 | { do_bad, SIGTRAP, TRAP_BRKPT, "aarch32 BKPT" }, | ||
| 497 | { do_bad, SIGTRAP, 0, "aarch32 vector catch" }, | ||
| 498 | { do_bad, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" }, | ||
| 499 | { do_bad, SIGBUS, 0, "unknown 7" }, | ||
| 500 | }; | ||
| 501 | |||
| 502 | void __init hook_debug_fault_code(int nr, | ||
| 503 | int (*fn)(unsigned long, unsigned int, struct pt_regs *), | ||
| 504 | int sig, int code, const char *name) | ||
| 505 | { | ||
| 506 | BUG_ON(nr < 0 || nr >= ARRAY_SIZE(debug_fault_info)); | ||
| 507 | |||
| 508 | debug_fault_info[nr].fn = fn; | ||
| 509 | debug_fault_info[nr].sig = sig; | ||
| 510 | debug_fault_info[nr].code = code; | ||
| 511 | debug_fault_info[nr].name = name; | ||
| 512 | } | ||
| 513 | |||
| 514 | asmlinkage int __exception do_debug_exception(unsigned long addr, | ||
| 515 | unsigned int esr, | ||
| 516 | struct pt_regs *regs) | ||
| 517 | { | ||
| 518 | const struct fault_info *inf = debug_fault_info + DBG_ESR_EVT(esr); | ||
| 519 | struct siginfo info; | ||
| 520 | |||
| 521 | if (!inf->fn(addr, esr, regs)) | ||
| 522 | return 1; | ||
| 523 | |||
| 524 | pr_alert("Unhandled debug exception: %s (0x%08x) at 0x%016lx\n", | ||
| 525 | inf->name, esr, addr); | ||
| 526 | |||
| 527 | info.si_signo = inf->sig; | ||
| 528 | info.si_errno = 0; | ||
| 529 | info.si_code = inf->code; | ||
| 530 | info.si_addr = (void __user *)addr; | ||
| 531 | arm64_notify_die("", regs, &info, esr); | ||
| 532 | |||
| 533 | return 0; | ||
| 534 | } | ||
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c new file mode 100644 index 000000000000..c144adb1682f --- /dev/null +++ b/arch/arm64/mm/flush.c | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/flush.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2002 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/export.h> | ||
| 21 | #include <linux/mm.h> | ||
| 22 | #include <linux/pagemap.h> | ||
| 23 | |||
| 24 | #include <asm/cacheflush.h> | ||
| 25 | #include <asm/cachetype.h> | ||
| 26 | #include <asm/tlbflush.h> | ||
| 27 | |||
| 28 | #include "mm.h" | ||
| 29 | |||
| 30 | void flush_cache_mm(struct mm_struct *mm) | ||
| 31 | { | ||
| 32 | } | ||
| 33 | |||
| 34 | void flush_cache_range(struct vm_area_struct *vma, unsigned long start, | ||
| 35 | unsigned long end) | ||
| 36 | { | ||
| 37 | if (vma->vm_flags & VM_EXEC) | ||
| 38 | __flush_icache_all(); | ||
| 39 | } | ||
| 40 | |||
| 41 | void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, | ||
| 42 | unsigned long pfn) | ||
| 43 | { | ||
| 44 | } | ||
| 45 | |||
| 46 | static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, | ||
| 47 | unsigned long uaddr, void *kaddr, | ||
| 48 | unsigned long len) | ||
| 49 | { | ||
| 50 | if (vma->vm_flags & VM_EXEC) { | ||
| 51 | unsigned long addr = (unsigned long)kaddr; | ||
| 52 | if (icache_is_aliasing()) { | ||
| 53 | __flush_dcache_area(kaddr, len); | ||
| 54 | __flush_icache_all(); | ||
| 55 | } else { | ||
| 56 | flush_icache_range(addr, addr + len); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | /* | ||
| 62 | * Copy user data from/to a page which is mapped into a different processes | ||
| 63 | * address space. Really, we want to allow our "user space" model to handle | ||
| 64 | * this. | ||
| 65 | * | ||
| 66 | * Note that this code needs to run on the current CPU. | ||
| 67 | */ | ||
| 68 | void copy_to_user_page(struct vm_area_struct *vma, struct page *page, | ||
| 69 | unsigned long uaddr, void *dst, const void *src, | ||
| 70 | unsigned long len) | ||
| 71 | { | ||
| 72 | #ifdef CONFIG_SMP | ||
| 73 | preempt_disable(); | ||
| 74 | #endif | ||
| 75 | memcpy(dst, src, len); | ||
| 76 | flush_ptrace_access(vma, page, uaddr, dst, len); | ||
| 77 | #ifdef CONFIG_SMP | ||
| 78 | preempt_enable(); | ||
| 79 | #endif | ||
| 80 | } | ||
| 81 | |||
| 82 | void __flush_dcache_page(struct page *page) | ||
| 83 | { | ||
| 84 | __flush_dcache_area(page_address(page), PAGE_SIZE); | ||
| 85 | } | ||
| 86 | |||
| 87 | void __sync_icache_dcache(pte_t pte, unsigned long addr) | ||
| 88 | { | ||
| 89 | unsigned long pfn; | ||
| 90 | struct page *page; | ||
| 91 | |||
| 92 | pfn = pte_pfn(pte); | ||
| 93 | if (!pfn_valid(pfn)) | ||
| 94 | return; | ||
| 95 | |||
| 96 | page = pfn_to_page(pfn); | ||
| 97 | if (!test_and_set_bit(PG_dcache_clean, &page->flags)) { | ||
| 98 | __flush_dcache_page(page); | ||
| 99 | __flush_icache_all(); | ||
| 100 | } else if (icache_is_aivivt()) { | ||
| 101 | __flush_icache_all(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Ensure cache coherency between kernel mapping and userspace mapping of this | ||
| 107 | * page. | ||
| 108 | */ | ||
| 109 | void flush_dcache_page(struct page *page) | ||
| 110 | { | ||
| 111 | struct address_space *mapping; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * The zero page is never written to, so never has any dirty cache | ||
| 115 | * lines, and therefore never needs to be flushed. | ||
| 116 | */ | ||
| 117 | if (page == ZERO_PAGE(0)) | ||
| 118 | return; | ||
| 119 | |||
| 120 | mapping = page_mapping(page); | ||
| 121 | if (mapping && mapping_mapped(mapping)) { | ||
| 122 | __flush_dcache_page(page); | ||
| 123 | __flush_icache_all(); | ||
| 124 | set_bit(PG_dcache_clean, &page->flags); | ||
| 125 | } else { | ||
| 126 | clear_bit(PG_dcache_clean, &page->flags); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | EXPORT_SYMBOL(flush_dcache_page); | ||
| 130 | |||
| 131 | /* | ||
| 132 | * Additional functions defined in assembly. | ||
| 133 | */ | ||
| 134 | EXPORT_SYMBOL(flush_cache_all); | ||
| 135 | EXPORT_SYMBOL(flush_icache_range); | ||
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c new file mode 100644 index 000000000000..5f719ba949bc --- /dev/null +++ b/arch/arm64/mm/init.c | |||
| @@ -0,0 +1,437 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/init.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2005 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/export.h> | ||
| 22 | #include <linux/errno.h> | ||
| 23 | #include <linux/swap.h> | ||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/bootmem.h> | ||
| 26 | #include <linux/mman.h> | ||
| 27 | #include <linux/nodemask.h> | ||
| 28 | #include <linux/initrd.h> | ||
| 29 | #include <linux/gfp.h> | ||
| 30 | #include <linux/memblock.h> | ||
| 31 | #include <linux/sort.h> | ||
| 32 | #include <linux/of_fdt.h> | ||
| 33 | |||
| 34 | #include <asm/prom.h> | ||
| 35 | #include <asm/sections.h> | ||
| 36 | #include <asm/setup.h> | ||
| 37 | #include <asm/sizes.h> | ||
| 38 | #include <asm/tlb.h> | ||
| 39 | |||
| 40 | #include "mm.h" | ||
| 41 | |||
| 42 | static unsigned long phys_initrd_start __initdata = 0; | ||
| 43 | static unsigned long phys_initrd_size __initdata = 0; | ||
| 44 | |||
| 45 | phys_addr_t memstart_addr __read_mostly = 0; | ||
| 46 | |||
| 47 | void __init early_init_dt_setup_initrd_arch(unsigned long start, | ||
| 48 | unsigned long end) | ||
| 49 | { | ||
| 50 | phys_initrd_start = start; | ||
| 51 | phys_initrd_size = end - start; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int __init early_initrd(char *p) | ||
| 55 | { | ||
| 56 | unsigned long start, size; | ||
| 57 | char *endp; | ||
| 58 | |||
| 59 | start = memparse(p, &endp); | ||
| 60 | if (*endp == ',') { | ||
| 61 | size = memparse(endp + 1, NULL); | ||
| 62 | |||
| 63 | phys_initrd_start = start; | ||
| 64 | phys_initrd_size = size; | ||
| 65 | } | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | early_param("initrd", early_initrd); | ||
| 69 | |||
| 70 | #define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT) | ||
| 71 | |||
| 72 | static void __init zone_sizes_init(unsigned long min, unsigned long max) | ||
| 73 | { | ||
| 74 | struct memblock_region *reg; | ||
| 75 | unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; | ||
| 76 | unsigned long max_dma32 = min; | ||
| 77 | |||
| 78 | memset(zone_size, 0, sizeof(zone_size)); | ||
| 79 | |||
| 80 | #ifdef CONFIG_ZONE_DMA32 | ||
| 81 | /* 4GB maximum for 32-bit only capable devices */ | ||
| 82 | max_dma32 = min(max, MAX_DMA32_PFN); | ||
| 83 | zone_size[ZONE_DMA32] = max_dma32 - min; | ||
| 84 | #endif | ||
| 85 | zone_size[ZONE_NORMAL] = max - max_dma32; | ||
| 86 | |||
| 87 | memcpy(zhole_size, zone_size, sizeof(zhole_size)); | ||
| 88 | |||
| 89 | for_each_memblock(memory, reg) { | ||
| 90 | unsigned long start = memblock_region_memory_base_pfn(reg); | ||
| 91 | unsigned long end = memblock_region_memory_end_pfn(reg); | ||
| 92 | |||
| 93 | if (start >= max) | ||
| 94 | continue; | ||
| 95 | #ifdef CONFIG_ZONE_DMA32 | ||
| 96 | if (start < max_dma32) { | ||
| 97 | unsigned long dma_end = min(end, max_dma32); | ||
| 98 | zhole_size[ZONE_DMA32] -= dma_end - start; | ||
| 99 | } | ||
| 100 | #endif | ||
| 101 | if (end > max_dma32) { | ||
| 102 | unsigned long normal_end = min(end, max); | ||
| 103 | unsigned long normal_start = max(start, max_dma32); | ||
| 104 | zhole_size[ZONE_NORMAL] -= normal_end - normal_start; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | free_area_init_node(0, zone_size, min, zhole_size); | ||
| 109 | } | ||
| 110 | |||
| 111 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID | ||
| 112 | int pfn_valid(unsigned long pfn) | ||
| 113 | { | ||
| 114 | return memblock_is_memory(pfn << PAGE_SHIFT); | ||
| 115 | } | ||
| 116 | EXPORT_SYMBOL(pfn_valid); | ||
| 117 | #endif | ||
| 118 | |||
| 119 | #ifndef CONFIG_SPARSEMEM | ||
| 120 | static void arm64_memory_present(void) | ||
| 121 | { | ||
| 122 | } | ||
| 123 | #else | ||
| 124 | static void arm64_memory_present(void) | ||
| 125 | { | ||
| 126 | struct memblock_region *reg; | ||
| 127 | |||
| 128 | for_each_memblock(memory, reg) | ||
| 129 | memory_present(0, memblock_region_memory_base_pfn(reg), | ||
| 130 | memblock_region_memory_end_pfn(reg)); | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | |||
| 134 | void __init arm64_memblock_init(void) | ||
| 135 | { | ||
| 136 | u64 *reserve_map, base, size; | ||
| 137 | |||
| 138 | /* Register the kernel text, kernel data and initrd with memblock */ | ||
| 139 | memblock_reserve(__pa(_text), _end - _text); | ||
| 140 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 141 | if (phys_initrd_size) { | ||
| 142 | memblock_reserve(phys_initrd_start, phys_initrd_size); | ||
| 143 | |||
| 144 | /* Now convert initrd to virtual addresses */ | ||
| 145 | initrd_start = __phys_to_virt(phys_initrd_start); | ||
| 146 | initrd_end = initrd_start + phys_initrd_size; | ||
| 147 | } | ||
| 148 | #endif | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Reserve the page tables. These are already in use, | ||
| 152 | * and can only be in node 0. | ||
| 153 | */ | ||
| 154 | memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE); | ||
| 155 | memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); | ||
| 156 | |||
| 157 | /* Reserve the dtb region */ | ||
| 158 | memblock_reserve(virt_to_phys(initial_boot_params), | ||
| 159 | be32_to_cpu(initial_boot_params->totalsize)); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * Process the reserve map. This will probably overlap the initrd | ||
| 163 | * and dtb locations which are already reserved, but overlapping | ||
| 164 | * doesn't hurt anything | ||
| 165 | */ | ||
| 166 | reserve_map = ((void*)initial_boot_params) + | ||
| 167 | be32_to_cpu(initial_boot_params->off_mem_rsvmap); | ||
| 168 | while (1) { | ||
| 169 | base = be64_to_cpup(reserve_map++); | ||
| 170 | size = be64_to_cpup(reserve_map++); | ||
| 171 | if (!size) | ||
| 172 | break; | ||
| 173 | memblock_reserve(base, size); | ||
| 174 | } | ||
| 175 | |||
| 176 | memblock_allow_resize(); | ||
| 177 | memblock_dump_all(); | ||
| 178 | } | ||
| 179 | |||
| 180 | void __init bootmem_init(void) | ||
| 181 | { | ||
| 182 | unsigned long min, max; | ||
| 183 | |||
| 184 | min = PFN_UP(memblock_start_of_DRAM()); | ||
| 185 | max = PFN_DOWN(memblock_end_of_DRAM()); | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Sparsemem tries to allocate bootmem in memory_present(), so must be | ||
| 189 | * done after the fixed reservations. | ||
| 190 | */ | ||
| 191 | arm64_memory_present(); | ||
| 192 | |||
| 193 | sparse_init(); | ||
| 194 | zone_sizes_init(min, max); | ||
| 195 | |||
| 196 | high_memory = __va((max << PAGE_SHIFT) - 1) + 1; | ||
| 197 | max_pfn = max_low_pfn = max; | ||
| 198 | } | ||
| 199 | |||
| 200 | static inline int free_area(unsigned long pfn, unsigned long end, char *s) | ||
| 201 | { | ||
| 202 | unsigned int pages = 0, size = (end - pfn) << (PAGE_SHIFT - 10); | ||
| 203 | |||
| 204 | for (; pfn < end; pfn++) { | ||
| 205 | struct page *page = pfn_to_page(pfn); | ||
| 206 | ClearPageReserved(page); | ||
| 207 | init_page_count(page); | ||
| 208 | __free_page(page); | ||
| 209 | pages++; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (size && s) | ||
| 213 | pr_info("Freeing %s memory: %dK\n", s, size); | ||
| 214 | |||
| 215 | return pages; | ||
| 216 | } | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Poison init memory with an undefined instruction (0x0). | ||
| 220 | */ | ||
| 221 | static inline void poison_init_mem(void *s, size_t count) | ||
| 222 | { | ||
| 223 | memset(s, 0, count); | ||
| 224 | } | ||
| 225 | |||
| 226 | #ifndef CONFIG_SPARSEMEM_VMEMMAP | ||
| 227 | static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn) | ||
| 228 | { | ||
| 229 | struct page *start_pg, *end_pg; | ||
| 230 | unsigned long pg, pgend; | ||
| 231 | |||
| 232 | /* | ||
| 233 | * Convert start_pfn/end_pfn to a struct page pointer. | ||
| 234 | */ | ||
| 235 | start_pg = pfn_to_page(start_pfn - 1) + 1; | ||
| 236 | end_pg = pfn_to_page(end_pfn - 1) + 1; | ||
| 237 | |||
| 238 | /* | ||
| 239 | * Convert to physical addresses, and round start upwards and end | ||
| 240 | * downwards. | ||
| 241 | */ | ||
| 242 | pg = (unsigned long)PAGE_ALIGN(__pa(start_pg)); | ||
| 243 | pgend = (unsigned long)__pa(end_pg) & PAGE_MASK; | ||
| 244 | |||
| 245 | /* | ||
| 246 | * If there are free pages between these, free the section of the | ||
| 247 | * memmap array. | ||
| 248 | */ | ||
| 249 | if (pg < pgend) | ||
| 250 | free_bootmem(pg, pgend - pg); | ||
| 251 | } | ||
| 252 | |||
| 253 | /* | ||
| 254 | * The mem_map array can get very big. Free the unused area of the memory map. | ||
| 255 | */ | ||
| 256 | static void __init free_unused_memmap(void) | ||
| 257 | { | ||
| 258 | unsigned long start, prev_end = 0; | ||
| 259 | struct memblock_region *reg; | ||
| 260 | |||
| 261 | for_each_memblock(memory, reg) { | ||
| 262 | start = __phys_to_pfn(reg->base); | ||
| 263 | |||
| 264 | #ifdef CONFIG_SPARSEMEM | ||
| 265 | /* | ||
| 266 | * Take care not to free memmap entries that don't exist due | ||
| 267 | * to SPARSEMEM sections which aren't present. | ||
| 268 | */ | ||
| 269 | start = min(start, ALIGN(prev_end, PAGES_PER_SECTION)); | ||
| 270 | #endif | ||
| 271 | /* | ||
| 272 | * If we had a previous bank, and there is a space between the | ||
| 273 | * current bank and the previous, free it. | ||
| 274 | */ | ||
| 275 | if (prev_end && prev_end < start) | ||
| 276 | free_memmap(prev_end, start); | ||
| 277 | |||
| 278 | /* | ||
| 279 | * Align up here since the VM subsystem insists that the | ||
| 280 | * memmap entries are valid from the bank end aligned to | ||
| 281 | * MAX_ORDER_NR_PAGES. | ||
| 282 | */ | ||
| 283 | prev_end = ALIGN(start + __phys_to_pfn(reg->size), | ||
| 284 | MAX_ORDER_NR_PAGES); | ||
| 285 | } | ||
| 286 | |||
| 287 | #ifdef CONFIG_SPARSEMEM | ||
| 288 | if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) | ||
| 289 | free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION)); | ||
| 290 | #endif | ||
| 291 | } | ||
| 292 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ | ||
| 293 | |||
| 294 | /* | ||
| 295 | * mem_init() marks the free areas in the mem_map and tells us how much memory | ||
| 296 | * is free. This is done after various parts of the system have claimed their | ||
| 297 | * memory after the kernel image. | ||
| 298 | */ | ||
| 299 | void __init mem_init(void) | ||
| 300 | { | ||
| 301 | unsigned long reserved_pages, free_pages; | ||
| 302 | struct memblock_region *reg; | ||
| 303 | |||
| 304 | #if CONFIG_SWIOTLB | ||
| 305 | extern void __init arm64_swiotlb_init(size_t max_size); | ||
| 306 | arm64_swiotlb_init(max_pfn << (PAGE_SHIFT - 1)); | ||
| 307 | #endif | ||
| 308 | |||
| 309 | max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map; | ||
| 310 | |||
| 311 | #ifndef CONFIG_SPARSEMEM_VMEMMAP | ||
| 312 | /* this will put all unused low memory onto the freelists */ | ||
| 313 | free_unused_memmap(); | ||
| 314 | #endif | ||
| 315 | |||
| 316 | totalram_pages += free_all_bootmem(); | ||
| 317 | |||
| 318 | reserved_pages = free_pages = 0; | ||
| 319 | |||
| 320 | for_each_memblock(memory, reg) { | ||
| 321 | unsigned int pfn1, pfn2; | ||
| 322 | struct page *page, *end; | ||
| 323 | |||
| 324 | pfn1 = __phys_to_pfn(reg->base); | ||
| 325 | pfn2 = pfn1 + __phys_to_pfn(reg->size); | ||
| 326 | |||
| 327 | page = pfn_to_page(pfn1); | ||
| 328 | end = pfn_to_page(pfn2 - 1) + 1; | ||
| 329 | |||
| 330 | do { | ||
| 331 | if (PageReserved(page)) | ||
| 332 | reserved_pages++; | ||
| 333 | else if (!page_count(page)) | ||
| 334 | free_pages++; | ||
| 335 | page++; | ||
| 336 | } while (page < end); | ||
| 337 | } | ||
| 338 | |||
| 339 | /* | ||
| 340 | * Since our memory may not be contiguous, calculate the real number | ||
| 341 | * of pages we have in this system. | ||
| 342 | */ | ||
| 343 | pr_info("Memory:"); | ||
| 344 | num_physpages = 0; | ||
| 345 | for_each_memblock(memory, reg) { | ||
| 346 | unsigned long pages = memblock_region_memory_end_pfn(reg) - | ||
| 347 | memblock_region_memory_base_pfn(reg); | ||
| 348 | num_physpages += pages; | ||
| 349 | printk(" %ldMB", pages >> (20 - PAGE_SHIFT)); | ||
| 350 | } | ||
| 351 | printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); | ||
| 352 | |||
| 353 | pr_notice("Memory: %luk/%luk available, %luk reserved\n", | ||
| 354 | nr_free_pages() << (PAGE_SHIFT-10), | ||
| 355 | free_pages << (PAGE_SHIFT-10), | ||
| 356 | reserved_pages << (PAGE_SHIFT-10)); | ||
| 357 | |||
| 358 | #define MLK(b, t) b, t, ((t) - (b)) >> 10 | ||
| 359 | #define MLM(b, t) b, t, ((t) - (b)) >> 20 | ||
| 360 | #define MLK_ROUNDUP(b, t) b, t, DIV_ROUND_UP(((t) - (b)), SZ_1K) | ||
| 361 | |||
| 362 | pr_notice("Virtual kernel memory layout:\n" | ||
| 363 | " vmalloc : 0x%16lx - 0x%16lx (%6ld MB)\n" | ||
| 364 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | ||
| 365 | " vmemmap : 0x%16lx - 0x%16lx (%6ld MB)\n" | ||
| 366 | #endif | ||
| 367 | " modules : 0x%16lx - 0x%16lx (%6ld MB)\n" | ||
| 368 | " memory : 0x%16lx - 0x%16lx (%6ld MB)\n" | ||
| 369 | " .init : 0x%p" " - 0x%p" " (%6ld kB)\n" | ||
| 370 | " .text : 0x%p" " - 0x%p" " (%6ld kB)\n" | ||
| 371 | " .data : 0x%p" " - 0x%p" " (%6ld kB)\n", | ||
| 372 | MLM(VMALLOC_START, VMALLOC_END), | ||
| 373 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | ||
| 374 | MLM((unsigned long)virt_to_page(PAGE_OFFSET), | ||
| 375 | (unsigned long)virt_to_page(high_memory)), | ||
| 376 | #endif | ||
| 377 | MLM(MODULES_VADDR, MODULES_END), | ||
| 378 | MLM(PAGE_OFFSET, (unsigned long)high_memory), | ||
| 379 | |||
| 380 | MLK_ROUNDUP(__init_begin, __init_end), | ||
| 381 | MLK_ROUNDUP(_text, _etext), | ||
| 382 | MLK_ROUNDUP(_sdata, _edata)); | ||
| 383 | |||
| 384 | #undef MLK | ||
| 385 | #undef MLM | ||
| 386 | #undef MLK_ROUNDUP | ||
| 387 | |||
| 388 | /* | ||
| 389 | * Check boundaries twice: Some fundamental inconsistencies can be | ||
| 390 | * detected at build time already. | ||
| 391 | */ | ||
| 392 | #ifdef CONFIG_COMPAT | ||
| 393 | BUILD_BUG_ON(TASK_SIZE_32 > TASK_SIZE_64); | ||
| 394 | #endif | ||
| 395 | BUILD_BUG_ON(TASK_SIZE_64 > MODULES_VADDR); | ||
| 396 | BUG_ON(TASK_SIZE_64 > MODULES_VADDR); | ||
| 397 | |||
| 398 | if (PAGE_SIZE >= 16384 && num_physpages <= 128) { | ||
| 399 | extern int sysctl_overcommit_memory; | ||
| 400 | /* | ||
| 401 | * On a machine this small we won't get anywhere without | ||
| 402 | * overcommit, so turn it on by default. | ||
| 403 | */ | ||
| 404 | sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 408 | void free_initmem(void) | ||
| 409 | { | ||
| 410 | poison_init_mem(__init_begin, __init_end - __init_begin); | ||
| 411 | totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)), | ||
| 412 | __phys_to_pfn(__pa(__init_end)), | ||
| 413 | "init"); | ||
| 414 | } | ||
| 415 | |||
| 416 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 417 | |||
| 418 | static int keep_initrd; | ||
| 419 | |||
| 420 | void free_initrd_mem(unsigned long start, unsigned long end) | ||
| 421 | { | ||
| 422 | if (!keep_initrd) { | ||
| 423 | poison_init_mem((void *)start, PAGE_ALIGN(end) - start); | ||
| 424 | totalram_pages += free_area(__phys_to_pfn(__pa(start)), | ||
| 425 | __phys_to_pfn(__pa(end)), | ||
| 426 | "initrd"); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | |||
| 430 | static int __init keepinitrd_setup(char *__unused) | ||
| 431 | { | ||
| 432 | keep_initrd = 1; | ||
| 433 | return 1; | ||
| 434 | } | ||
| 435 | |||
| 436 | __setup("keepinitrd", keepinitrd_setup); | ||
| 437 | #endif | ||
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c new file mode 100644 index 000000000000..1725cd6db37a --- /dev/null +++ b/arch/arm64/mm/ioremap.c | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/ioremap.c | ||
| 3 | * | ||
| 4 | * (C) Copyright 1995 1996 Linus Torvalds | ||
| 5 | * Hacked for ARM by Phil Blundell <philb@gnu.org> | ||
| 6 | * Hacked to allow all architectures to build, and various cleanups | ||
| 7 | * by Russell King | ||
| 8 | * Copyright (C) 2012 ARM Ltd. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/export.h> | ||
| 24 | #include <linux/mm.h> | ||
| 25 | #include <linux/vmalloc.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | |||
| 28 | static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, | ||
| 29 | pgprot_t prot, void *caller) | ||
| 30 | { | ||
| 31 | unsigned long last_addr; | ||
| 32 | unsigned long offset = phys_addr & ~PAGE_MASK; | ||
| 33 | int err; | ||
| 34 | unsigned long addr; | ||
| 35 | struct vm_struct *area; | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Page align the mapping address and size, taking account of any | ||
| 39 | * offset. | ||
| 40 | */ | ||
| 41 | phys_addr &= PAGE_MASK; | ||
| 42 | size = PAGE_ALIGN(size + offset); | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Don't allow wraparound, zero size or outside PHYS_MASK. | ||
| 46 | */ | ||
| 47 | last_addr = phys_addr + size - 1; | ||
| 48 | if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK)) | ||
| 49 | return NULL; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Don't allow RAM to be mapped. | ||
| 53 | */ | ||
| 54 | if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr)))) | ||
| 55 | return NULL; | ||
| 56 | |||
| 57 | area = get_vm_area_caller(size, VM_IOREMAP, caller); | ||
| 58 | if (!area) | ||
| 59 | return NULL; | ||
| 60 | addr = (unsigned long)area->addr; | ||
| 61 | |||
| 62 | err = ioremap_page_range(addr, addr + size, phys_addr, prot); | ||
| 63 | if (err) { | ||
| 64 | vunmap((void *)addr); | ||
| 65 | return NULL; | ||
| 66 | } | ||
| 67 | |||
| 68 | return (void __iomem *)(offset + addr); | ||
| 69 | } | ||
| 70 | |||
| 71 | void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot) | ||
| 72 | { | ||
| 73 | return __ioremap_caller(phys_addr, size, prot, | ||
| 74 | __builtin_return_address(0)); | ||
| 75 | } | ||
| 76 | EXPORT_SYMBOL(__ioremap); | ||
| 77 | |||
| 78 | void __iounmap(volatile void __iomem *io_addr) | ||
| 79 | { | ||
| 80 | void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); | ||
| 81 | |||
| 82 | vunmap(addr); | ||
| 83 | } | ||
| 84 | EXPORT_SYMBOL(__iounmap); | ||
diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h new file mode 100644 index 000000000000..d8d6e7851c14 --- /dev/null +++ b/arch/arm64/mm/mm.h | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | extern void __flush_dcache_page(struct page *page); | ||
| 2 | extern void __init bootmem_init(void); | ||
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c new file mode 100644 index 000000000000..7c7be7855638 --- /dev/null +++ b/arch/arm64/mm/mmap.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/mmap.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/elf.h> | ||
| 20 | #include <linux/fs.h> | ||
| 21 | #include <linux/mm.h> | ||
| 22 | #include <linux/mman.h> | ||
| 23 | #include <linux/export.h> | ||
| 24 | #include <linux/shm.h> | ||
| 25 | #include <linux/sched.h> | ||
| 26 | #include <linux/io.h> | ||
| 27 | #include <linux/personality.h> | ||
| 28 | #include <linux/random.h> | ||
| 29 | |||
| 30 | #include <asm/cputype.h> | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Leave enough space between the mmap area and the stack to honour ulimit in | ||
| 34 | * the face of randomisation. | ||
| 35 | */ | ||
| 36 | #define MIN_GAP (SZ_128M + ((STACK_RND_MASK << PAGE_SHIFT) + 1)) | ||
| 37 | #define MAX_GAP (STACK_TOP/6*5) | ||
| 38 | |||
| 39 | static int mmap_is_legacy(void) | ||
| 40 | { | ||
| 41 | if (current->personality & ADDR_COMPAT_LAYOUT) | ||
| 42 | return 1; | ||
| 43 | |||
| 44 | if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) | ||
| 45 | return 1; | ||
| 46 | |||
| 47 | return sysctl_legacy_va_layout; | ||
| 48 | } | ||
| 49 | |||
| 50 | /* | ||
| 51 | * Since get_random_int() returns the same value within a 1 jiffy window, we | ||
| 52 | * will almost always get the same randomisation for the stack and mmap | ||
| 53 | * region. This will mean the relative distance between stack and mmap will be | ||
| 54 | * the same. | ||
| 55 | * | ||
| 56 | * To avoid this we can shift the randomness by 1 bit. | ||
| 57 | */ | ||
| 58 | static unsigned long mmap_rnd(void) | ||
| 59 | { | ||
| 60 | unsigned long rnd = 0; | ||
| 61 | |||
| 62 | if (current->flags & PF_RANDOMIZE) | ||
| 63 | rnd = (long)get_random_int() & (STACK_RND_MASK >> 1); | ||
| 64 | |||
| 65 | return rnd << (PAGE_SHIFT + 1); | ||
| 66 | } | ||
| 67 | |||
| 68 | static unsigned long mmap_base(void) | ||
| 69 | { | ||
| 70 | unsigned long gap = rlimit(RLIMIT_STACK); | ||
| 71 | |||
| 72 | if (gap < MIN_GAP) | ||
| 73 | gap = MIN_GAP; | ||
| 74 | else if (gap > MAX_GAP) | ||
| 75 | gap = MAX_GAP; | ||
| 76 | |||
| 77 | return PAGE_ALIGN(STACK_TOP - gap - mmap_rnd()); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * This function, called very early during the creation of a new process VM | ||
| 82 | * image, sets up which VM layout function to use: | ||
| 83 | */ | ||
| 84 | void arch_pick_mmap_layout(struct mm_struct *mm) | ||
| 85 | { | ||
| 86 | /* | ||
| 87 | * Fall back to the standard layout if the personality bit is set, or | ||
| 88 | * if the expected stack growth is unlimited: | ||
| 89 | */ | ||
| 90 | if (mmap_is_legacy()) { | ||
| 91 | mm->mmap_base = TASK_UNMAPPED_BASE; | ||
| 92 | mm->get_unmapped_area = arch_get_unmapped_area; | ||
| 93 | mm->unmap_area = arch_unmap_area; | ||
| 94 | } else { | ||
| 95 | mm->mmap_base = mmap_base(); | ||
| 96 | mm->get_unmapped_area = arch_get_unmapped_area_topdown; | ||
| 97 | mm->unmap_area = arch_unmap_area_topdown; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | EXPORT_SYMBOL_GPL(arch_pick_mmap_layout); | ||
| 101 | |||
| 102 | |||
| 103 | /* | ||
| 104 | * You really shouldn't be using read() or write() on /dev/mem. This might go | ||
| 105 | * away in the future. | ||
| 106 | */ | ||
| 107 | int valid_phys_addr_range(unsigned long addr, size_t size) | ||
| 108 | { | ||
| 109 | if (addr < PHYS_OFFSET) | ||
| 110 | return 0; | ||
| 111 | if (addr + size > __pa(high_memory - 1) + 1) | ||
| 112 | return 0; | ||
| 113 | |||
| 114 | return 1; | ||
| 115 | } | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Do not allow /dev/mem mappings beyond the supported physical range. | ||
| 119 | */ | ||
| 120 | int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) | ||
| 121 | { | ||
| 122 | return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK); | ||
| 123 | } | ||
| 124 | |||
| 125 | #ifdef CONFIG_STRICT_DEVMEM | ||
| 126 | |||
| 127 | #include <linux/ioport.h> | ||
| 128 | |||
| 129 | /* | ||
| 130 | * devmem_is_allowed() checks to see if /dev/mem access to a certain address | ||
| 131 | * is valid. The argument is a physical page number. We mimic x86 here by | ||
| 132 | * disallowing access to system RAM as well as device-exclusive MMIO regions. | ||
| 133 | * This effectively disable read()/write() on /dev/mem. | ||
| 134 | */ | ||
| 135 | int devmem_is_allowed(unsigned long pfn) | ||
| 136 | { | ||
| 137 | if (iomem_is_exclusive(pfn << PAGE_SHIFT)) | ||
| 138 | return 0; | ||
| 139 | if (!page_is_ram(pfn)) | ||
| 140 | return 1; | ||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | #endif | ||
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c new file mode 100644 index 000000000000..a6885d896ab6 --- /dev/null +++ b/arch/arm64/mm/mmu.c | |||
| @@ -0,0 +1,395 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/mmu.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995-2005 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/export.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/errno.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/mman.h> | ||
| 25 | #include <linux/nodemask.h> | ||
| 26 | #include <linux/memblock.h> | ||
| 27 | #include <linux/fs.h> | ||
| 28 | |||
| 29 | #include <asm/cputype.h> | ||
| 30 | #include <asm/sections.h> | ||
| 31 | #include <asm/setup.h> | ||
| 32 | #include <asm/sizes.h> | ||
| 33 | #include <asm/tlb.h> | ||
| 34 | #include <asm/mmu_context.h> | ||
| 35 | |||
| 36 | #include "mm.h" | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Empty_zero_page is a special page that is used for zero-initialized data | ||
| 40 | * and COW. | ||
| 41 | */ | ||
| 42 | struct page *empty_zero_page; | ||
| 43 | EXPORT_SYMBOL(empty_zero_page); | ||
| 44 | |||
| 45 | pgprot_t pgprot_default; | ||
| 46 | EXPORT_SYMBOL(pgprot_default); | ||
| 47 | |||
| 48 | static pmdval_t prot_sect_kernel; | ||
| 49 | |||
| 50 | struct cachepolicy { | ||
| 51 | const char policy[16]; | ||
| 52 | u64 mair; | ||
| 53 | u64 tcr; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct cachepolicy cache_policies[] __initdata = { | ||
| 57 | { | ||
| 58 | .policy = "uncached", | ||
| 59 | .mair = 0x44, /* inner, outer non-cacheable */ | ||
| 60 | .tcr = TCR_IRGN_NC | TCR_ORGN_NC, | ||
| 61 | }, { | ||
| 62 | .policy = "writethrough", | ||
| 63 | .mair = 0xaa, /* inner, outer write-through, read-allocate */ | ||
| 64 | .tcr = TCR_IRGN_WT | TCR_ORGN_WT, | ||
| 65 | }, { | ||
| 66 | .policy = "writeback", | ||
| 67 | .mair = 0xee, /* inner, outer write-back, read-allocate */ | ||
| 68 | .tcr = TCR_IRGN_WBnWA | TCR_ORGN_WBnWA, | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | |||
| 72 | /* | ||
| 73 | * These are useful for identifying cache coherency problems by allowing the | ||
| 74 | * cache or the cache and writebuffer to be turned off. It changes the Normal | ||
| 75 | * memory caching attributes in the MAIR_EL1 register. | ||
| 76 | */ | ||
| 77 | static int __init early_cachepolicy(char *p) | ||
| 78 | { | ||
| 79 | int i; | ||
| 80 | u64 tmp; | ||
| 81 | |||
| 82 | for (i = 0; i < ARRAY_SIZE(cache_policies); i++) { | ||
| 83 | int len = strlen(cache_policies[i].policy); | ||
| 84 | |||
| 85 | if (memcmp(p, cache_policies[i].policy, len) == 0) | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | if (i == ARRAY_SIZE(cache_policies)) { | ||
| 89 | pr_err("ERROR: unknown or unsupported cache policy: %s\n", p); | ||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | flush_cache_all(); | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Modify MT_NORMAL attributes in MAIR_EL1. | ||
| 97 | */ | ||
| 98 | asm volatile( | ||
| 99 | " mrs %0, mair_el1\n" | ||
| 100 | " bfi %0, %1, #%2, #8\n" | ||
| 101 | " msr mair_el1, %0\n" | ||
| 102 | " isb\n" | ||
| 103 | : "=&r" (tmp) | ||
| 104 | : "r" (cache_policies[i].mair), "i" (MT_NORMAL * 8)); | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Modify TCR PTW cacheability attributes. | ||
| 108 | */ | ||
| 109 | asm volatile( | ||
| 110 | " mrs %0, tcr_el1\n" | ||
| 111 | " bic %0, %0, %2\n" | ||
| 112 | " orr %0, %0, %1\n" | ||
| 113 | " msr tcr_el1, %0\n" | ||
| 114 | " isb\n" | ||
| 115 | : "=&r" (tmp) | ||
| 116 | : "r" (cache_policies[i].tcr), "r" (TCR_IRGN_MASK | TCR_ORGN_MASK)); | ||
| 117 | |||
| 118 | flush_cache_all(); | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | early_param("cachepolicy", early_cachepolicy); | ||
| 123 | |||
| 124 | /* | ||
| 125 | * Adjust the PMD section entries according to the CPU in use. | ||
| 126 | */ | ||
| 127 | static void __init init_mem_pgprot(void) | ||
| 128 | { | ||
| 129 | pteval_t default_pgprot; | ||
| 130 | int i; | ||
| 131 | |||
| 132 | default_pgprot = PTE_ATTRINDX(MT_NORMAL); | ||
| 133 | prot_sect_kernel = PMD_TYPE_SECT | PMD_SECT_AF | PMD_ATTRINDX(MT_NORMAL); | ||
| 134 | |||
| 135 | #ifdef CONFIG_SMP | ||
| 136 | /* | ||
| 137 | * Mark memory with the "shared" attribute for SMP systems | ||
| 138 | */ | ||
| 139 | default_pgprot |= PTE_SHARED; | ||
| 140 | prot_sect_kernel |= PMD_SECT_S; | ||
| 141 | #endif | ||
| 142 | |||
| 143 | for (i = 0; i < 16; i++) { | ||
| 144 | unsigned long v = pgprot_val(protection_map[i]); | ||
| 145 | protection_map[i] = __pgprot(v | default_pgprot); | ||
| 146 | } | ||
| 147 | |||
| 148 | pgprot_default = __pgprot(PTE_TYPE_PAGE | PTE_AF | default_pgprot); | ||
| 149 | } | ||
| 150 | |||
| 151 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | ||
| 152 | unsigned long size, pgprot_t vma_prot) | ||
| 153 | { | ||
| 154 | if (!pfn_valid(pfn)) | ||
| 155 | return pgprot_noncached(vma_prot); | ||
| 156 | else if (file->f_flags & O_SYNC) | ||
| 157 | return pgprot_writecombine(vma_prot); | ||
| 158 | return vma_prot; | ||
| 159 | } | ||
| 160 | EXPORT_SYMBOL(phys_mem_access_prot); | ||
| 161 | |||
| 162 | static void __init *early_alloc(unsigned long sz) | ||
| 163 | { | ||
| 164 | void *ptr = __va(memblock_alloc(sz, sz)); | ||
| 165 | memset(ptr, 0, sz); | ||
| 166 | return ptr; | ||
| 167 | } | ||
| 168 | |||
| 169 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | ||
| 170 | unsigned long end, unsigned long pfn) | ||
| 171 | { | ||
| 172 | pte_t *pte; | ||
| 173 | |||
| 174 | if (pmd_none(*pmd)) { | ||
| 175 | pte = early_alloc(PTRS_PER_PTE * sizeof(pte_t)); | ||
| 176 | __pmd_populate(pmd, __pa(pte), PMD_TYPE_TABLE); | ||
| 177 | } | ||
| 178 | BUG_ON(pmd_bad(*pmd)); | ||
| 179 | |||
| 180 | pte = pte_offset_kernel(pmd, addr); | ||
| 181 | do { | ||
| 182 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); | ||
| 183 | pfn++; | ||
| 184 | } while (pte++, addr += PAGE_SIZE, addr != end); | ||
| 185 | } | ||
| 186 | |||
| 187 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | ||
| 188 | unsigned long end, phys_addr_t phys) | ||
| 189 | { | ||
| 190 | pmd_t *pmd; | ||
| 191 | unsigned long next; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Check for initial section mappings in the pgd/pud and remove them. | ||
| 195 | */ | ||
| 196 | if (pud_none(*pud) || pud_bad(*pud)) { | ||
| 197 | pmd = early_alloc(PTRS_PER_PMD * sizeof(pmd_t)); | ||
| 198 | pud_populate(&init_mm, pud, pmd); | ||
| 199 | } | ||
| 200 | |||
| 201 | pmd = pmd_offset(pud, addr); | ||
| 202 | do { | ||
| 203 | next = pmd_addr_end(addr, end); | ||
| 204 | /* try section mapping first */ | ||
| 205 | if (((addr | next | phys) & ~SECTION_MASK) == 0) | ||
| 206 | set_pmd(pmd, __pmd(phys | prot_sect_kernel)); | ||
| 207 | else | ||
| 208 | alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys)); | ||
| 209 | phys += next - addr; | ||
| 210 | } while (pmd++, addr = next, addr != end); | ||
| 211 | } | ||
| 212 | |||
| 213 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, | ||
| 214 | unsigned long end, unsigned long phys) | ||
| 215 | { | ||
| 216 | pud_t *pud = pud_offset(pgd, addr); | ||
| 217 | unsigned long next; | ||
| 218 | |||
| 219 | do { | ||
| 220 | next = pud_addr_end(addr, end); | ||
| 221 | alloc_init_pmd(pud, addr, next, phys); | ||
| 222 | phys += next - addr; | ||
| 223 | } while (pud++, addr = next, addr != end); | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Create the page directory entries and any necessary page tables for the | ||
| 228 | * mapping specified by 'md'. | ||
| 229 | */ | ||
| 230 | static void __init create_mapping(phys_addr_t phys, unsigned long virt, | ||
| 231 | phys_addr_t size) | ||
| 232 | { | ||
| 233 | unsigned long addr, length, end, next; | ||
| 234 | pgd_t *pgd; | ||
| 235 | |||
| 236 | if (virt < VMALLOC_START) { | ||
| 237 | pr_warning("BUG: not creating mapping for 0x%016llx at 0x%016lx - outside kernel range\n", | ||
| 238 | phys, virt); | ||
| 239 | return; | ||
| 240 | } | ||
| 241 | |||
| 242 | addr = virt & PAGE_MASK; | ||
| 243 | length = PAGE_ALIGN(size + (virt & ~PAGE_MASK)); | ||
| 244 | |||
| 245 | pgd = pgd_offset_k(addr); | ||
| 246 | end = addr + length; | ||
| 247 | do { | ||
| 248 | next = pgd_addr_end(addr, end); | ||
| 249 | alloc_init_pud(pgd, addr, next, phys); | ||
| 250 | phys += next - addr; | ||
| 251 | } while (pgd++, addr = next, addr != end); | ||
| 252 | } | ||
| 253 | |||
| 254 | static void __init map_mem(void) | ||
| 255 | { | ||
| 256 | struct memblock_region *reg; | ||
| 257 | |||
| 258 | /* map all the memory banks */ | ||
| 259 | for_each_memblock(memory, reg) { | ||
| 260 | phys_addr_t start = reg->base; | ||
| 261 | phys_addr_t end = start + reg->size; | ||
| 262 | |||
| 263 | if (start >= end) | ||
| 264 | break; | ||
| 265 | |||
| 266 | create_mapping(start, __phys_to_virt(start), end - start); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 271 | * paging_init() sets up the page tables, initialises the zone memory | ||
| 272 | * maps and sets up the zero page. | ||
| 273 | */ | ||
| 274 | void __init paging_init(void) | ||
| 275 | { | ||
| 276 | void *zero_page; | ||
| 277 | |||
| 278 | /* | ||
| 279 | * Maximum PGDIR_SIZE addressable via the initial direct kernel | ||
| 280 | * mapping in swapper_pg_dir. | ||
| 281 | */ | ||
| 282 | memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE); | ||
| 283 | |||
| 284 | init_mem_pgprot(); | ||
| 285 | map_mem(); | ||
| 286 | |||
| 287 | /* | ||
| 288 | * Finally flush the caches and tlb to ensure that we're in a | ||
| 289 | * consistent state. | ||
| 290 | */ | ||
| 291 | flush_cache_all(); | ||
| 292 | flush_tlb_all(); | ||
| 293 | |||
| 294 | /* allocate the zero page. */ | ||
| 295 | zero_page = early_alloc(PAGE_SIZE); | ||
| 296 | |||
| 297 | bootmem_init(); | ||
| 298 | |||
| 299 | empty_zero_page = virt_to_page(zero_page); | ||
| 300 | __flush_dcache_page(empty_zero_page); | ||
| 301 | |||
| 302 | /* | ||
| 303 | * TTBR0 is only used for the identity mapping at this stage. Make it | ||
| 304 | * point to zero page to avoid speculatively fetching new entries. | ||
| 305 | */ | ||
| 306 | cpu_set_reserved_ttbr0(); | ||
| 307 | flush_tlb_all(); | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Enable the identity mapping to allow the MMU disabling. | ||
| 312 | */ | ||
| 313 | void setup_mm_for_reboot(void) | ||
| 314 | { | ||
| 315 | cpu_switch_mm(idmap_pg_dir, &init_mm); | ||
| 316 | flush_tlb_all(); | ||
| 317 | } | ||
| 318 | |||
| 319 | /* | ||
| 320 | * Check whether a kernel address is valid (derived from arch/x86/). | ||
| 321 | */ | ||
| 322 | int kern_addr_valid(unsigned long addr) | ||
| 323 | { | ||
| 324 | pgd_t *pgd; | ||
| 325 | pud_t *pud; | ||
| 326 | pmd_t *pmd; | ||
| 327 | pte_t *pte; | ||
| 328 | |||
| 329 | if ((((long)addr) >> VA_BITS) != -1UL) | ||
| 330 | return 0; | ||
| 331 | |||
| 332 | pgd = pgd_offset_k(addr); | ||
| 333 | if (pgd_none(*pgd)) | ||
| 334 | return 0; | ||
| 335 | |||
| 336 | pud = pud_offset(pgd, addr); | ||
| 337 | if (pud_none(*pud)) | ||
| 338 | return 0; | ||
| 339 | |||
| 340 | pmd = pmd_offset(pud, addr); | ||
| 341 | if (pmd_none(*pmd)) | ||
| 342 | return 0; | ||
| 343 | |||
| 344 | pte = pte_offset_kernel(pmd, addr); | ||
| 345 | if (pte_none(*pte)) | ||
| 346 | return 0; | ||
| 347 | |||
| 348 | return pfn_valid(pte_pfn(*pte)); | ||
| 349 | } | ||
| 350 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | ||
| 351 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 352 | int __meminit vmemmap_populate(struct page *start_page, | ||
| 353 | unsigned long size, int node) | ||
| 354 | { | ||
| 355 | return vmemmap_populate_basepages(start_page, size, node); | ||
| 356 | } | ||
| 357 | #else /* !CONFIG_ARM64_64K_PAGES */ | ||
| 358 | int __meminit vmemmap_populate(struct page *start_page, | ||
| 359 | unsigned long size, int node) | ||
| 360 | { | ||
| 361 | unsigned long addr = (unsigned long)start_page; | ||
| 362 | unsigned long end = (unsigned long)(start_page + size); | ||
| 363 | unsigned long next; | ||
| 364 | pgd_t *pgd; | ||
| 365 | pud_t *pud; | ||
| 366 | pmd_t *pmd; | ||
| 367 | |||
| 368 | do { | ||
| 369 | next = pmd_addr_end(addr, end); | ||
| 370 | |||
| 371 | pgd = vmemmap_pgd_populate(addr, node); | ||
| 372 | if (!pgd) | ||
| 373 | return -ENOMEM; | ||
| 374 | |||
| 375 | pud = vmemmap_pud_populate(pgd, addr, node); | ||
| 376 | if (!pud) | ||
| 377 | return -ENOMEM; | ||
| 378 | |||
| 379 | pmd = pmd_offset(pud, addr); | ||
| 380 | if (pmd_none(*pmd)) { | ||
| 381 | void *p = NULL; | ||
| 382 | |||
| 383 | p = vmemmap_alloc_block_buf(PMD_SIZE, node); | ||
| 384 | if (!p) | ||
| 385 | return -ENOMEM; | ||
| 386 | |||
| 387 | set_pmd(pmd, __pmd(__pa(p) | prot_sect_kernel)); | ||
| 388 | } else | ||
| 389 | vmemmap_verify((pte_t *)pmd, node, addr, next); | ||
| 390 | } while (addr = next, addr != end); | ||
| 391 | |||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | #endif /* CONFIG_ARM64_64K_PAGES */ | ||
| 395 | #endif /* CONFIG_SPARSEMEM_VMEMMAP */ | ||
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c new file mode 100644 index 000000000000..7083cdada657 --- /dev/null +++ b/arch/arm64/mm/pgd.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * PGD allocation/freeing | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/mm.h> | ||
| 21 | #include <linux/gfp.h> | ||
| 22 | #include <linux/highmem.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | |||
| 25 | #include <asm/pgalloc.h> | ||
| 26 | #include <asm/page.h> | ||
| 27 | #include <asm/tlbflush.h> | ||
| 28 | |||
| 29 | #include "mm.h" | ||
| 30 | |||
| 31 | #define PGD_SIZE (PTRS_PER_PGD * sizeof(pgd_t)) | ||
| 32 | |||
| 33 | pgd_t *pgd_alloc(struct mm_struct *mm) | ||
| 34 | { | ||
| 35 | pgd_t *new_pgd; | ||
| 36 | |||
| 37 | if (PGD_SIZE == PAGE_SIZE) | ||
| 38 | new_pgd = (pgd_t *)get_zeroed_page(GFP_KERNEL); | ||
| 39 | else | ||
| 40 | new_pgd = kzalloc(PGD_SIZE, GFP_KERNEL); | ||
| 41 | |||
| 42 | if (!new_pgd) | ||
| 43 | return NULL; | ||
| 44 | |||
| 45 | return new_pgd; | ||
| 46 | } | ||
| 47 | |||
| 48 | void pgd_free(struct mm_struct *mm, pgd_t *pgd) | ||
| 49 | { | ||
| 50 | if (PGD_SIZE == PAGE_SIZE) | ||
| 51 | free_page((unsigned long)pgd); | ||
| 52 | else | ||
| 53 | kfree(pgd); | ||
| 54 | } | ||
diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S new file mode 100644 index 000000000000..8957b822010b --- /dev/null +++ b/arch/arm64/mm/proc-macros.S | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/proc-macros.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <asm/asm-offsets.h> | ||
| 20 | #include <asm/thread_info.h> | ||
| 21 | |||
| 22 | /* | ||
| 23 | * vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm) | ||
| 24 | */ | ||
| 25 | .macro vma_vm_mm, rd, rn | ||
| 26 | ldr \rd, [\rn, #VMA_VM_MM] | ||
| 27 | .endm | ||
| 28 | |||
| 29 | /* | ||
| 30 | * mmid - get context id from mm pointer (mm->context.id) | ||
| 31 | */ | ||
| 32 | .macro mmid, rd, rn | ||
| 33 | ldr \rd, [\rn, #MM_CONTEXT_ID] | ||
| 34 | .endm | ||
| 35 | |||
| 36 | /* | ||
| 37 | * dcache_line_size - get the minimum D-cache line size from the CTR register. | ||
| 38 | */ | ||
| 39 | .macro dcache_line_size, reg, tmp | ||
| 40 | mrs \tmp, ctr_el0 // read CTR | ||
| 41 | lsr \tmp, \tmp, #16 | ||
| 42 | and \tmp, \tmp, #0xf // cache line size encoding | ||
| 43 | mov \reg, #4 // bytes per word | ||
| 44 | lsl \reg, \reg, \tmp // actual cache line size | ||
| 45 | .endm | ||
| 46 | |||
| 47 | /* | ||
| 48 | * icache_line_size - get the minimum I-cache line size from the CTR register. | ||
| 49 | */ | ||
| 50 | .macro icache_line_size, reg, tmp | ||
| 51 | mrs \tmp, ctr_el0 // read CTR | ||
| 52 | and \tmp, \tmp, #0xf // cache line size encoding | ||
| 53 | mov \reg, #4 // bytes per word | ||
| 54 | lsl \reg, \reg, \tmp // actual cache line size | ||
| 55 | .endm | ||
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S new file mode 100644 index 000000000000..f1d8b9bbfdad --- /dev/null +++ b/arch/arm64/mm/proc.S | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/proc.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 Deep Blue Solutions Ltd. | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * Author: Catalin Marinas <catalin.marinas@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/linkage.h> | ||
| 23 | #include <asm/assembler.h> | ||
| 24 | #include <asm/asm-offsets.h> | ||
| 25 | #include <asm/hwcap.h> | ||
| 26 | #include <asm/pgtable-hwdef.h> | ||
| 27 | #include <asm/pgtable.h> | ||
| 28 | |||
| 29 | #include "proc-macros.S" | ||
| 30 | |||
| 31 | #ifndef CONFIG_SMP | ||
| 32 | /* PTWs cacheable, inner/outer WBWA not shareable */ | ||
| 33 | #define TCR_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA | ||
| 34 | #else | ||
| 35 | /* PTWs cacheable, inner/outer WBWA shareable */ | ||
| 36 | #define TCR_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #define MAIR(attr, mt) ((attr) << ((mt) * 8)) | ||
| 40 | |||
| 41 | /* | ||
| 42 | * cpu_cache_off() | ||
| 43 | * | ||
| 44 | * Turn the CPU D-cache off. | ||
| 45 | */ | ||
| 46 | ENTRY(cpu_cache_off) | ||
| 47 | mrs x0, sctlr_el1 | ||
| 48 | bic x0, x0, #1 << 2 // clear SCTLR.C | ||
| 49 | msr sctlr_el1, x0 | ||
| 50 | isb | ||
| 51 | ret | ||
| 52 | ENDPROC(cpu_cache_off) | ||
| 53 | |||
| 54 | /* | ||
| 55 | * cpu_reset(loc) | ||
| 56 | * | ||
| 57 | * Perform a soft reset of the system. Put the CPU into the same state | ||
| 58 | * as it would be if it had been reset, and branch to what would be the | ||
| 59 | * reset vector. It must be executed with the flat identity mapping. | ||
| 60 | * | ||
| 61 | * - loc - location to jump to for soft reset | ||
| 62 | */ | ||
| 63 | .align 5 | ||
| 64 | ENTRY(cpu_reset) | ||
| 65 | mrs x1, sctlr_el1 | ||
| 66 | bic x1, x1, #1 | ||
| 67 | msr sctlr_el1, x1 // disable the MMU | ||
| 68 | isb | ||
| 69 | ret x0 | ||
| 70 | ENDPROC(cpu_reset) | ||
| 71 | |||
| 72 | /* | ||
| 73 | * cpu_do_idle() | ||
| 74 | * | ||
| 75 | * Idle the processor (wait for interrupt). | ||
| 76 | */ | ||
| 77 | ENTRY(cpu_do_idle) | ||
| 78 | dsb sy // WFI may enter a low-power mode | ||
| 79 | wfi | ||
| 80 | ret | ||
| 81 | ENDPROC(cpu_do_idle) | ||
| 82 | |||
| 83 | /* | ||
| 84 | * cpu_switch_mm(pgd_phys, tsk) | ||
| 85 | * | ||
| 86 | * Set the translation table base pointer to be pgd_phys. | ||
| 87 | * | ||
| 88 | * - pgd_phys - physical address of new TTB | ||
| 89 | */ | ||
| 90 | ENTRY(cpu_do_switch_mm) | ||
| 91 | mmid w1, x1 // get mm->context.id | ||
| 92 | bfi x0, x1, #48, #16 // set the ASID | ||
| 93 | msr ttbr0_el1, x0 // set TTBR0 | ||
| 94 | isb | ||
| 95 | ret | ||
| 96 | ENDPROC(cpu_do_switch_mm) | ||
| 97 | |||
| 98 | cpu_name: | ||
| 99 | .ascii "AArch64 Processor" | ||
| 100 | .align | ||
| 101 | |||
| 102 | .section ".text.init", #alloc, #execinstr | ||
| 103 | |||
| 104 | /* | ||
| 105 | * __cpu_setup | ||
| 106 | * | ||
| 107 | * Initialise the processor for turning the MMU on. Return in x0 the | ||
| 108 | * value of the SCTLR_EL1 register. | ||
| 109 | */ | ||
| 110 | ENTRY(__cpu_setup) | ||
| 111 | /* | ||
| 112 | * Preserve the link register across the function call. | ||
| 113 | */ | ||
| 114 | mov x28, lr | ||
| 115 | bl __flush_dcache_all | ||
| 116 | mov lr, x28 | ||
| 117 | ic iallu // I+BTB cache invalidate | ||
| 118 | dsb sy | ||
| 119 | |||
| 120 | mov x0, #3 << 20 | ||
| 121 | msr cpacr_el1, x0 // Enable FP/ASIMD | ||
| 122 | mov x0, #1 | ||
| 123 | msr oslar_el1, x0 // Set the debug OS lock | ||
| 124 | tlbi vmalle1is // invalidate I + D TLBs | ||
| 125 | /* | ||
| 126 | * Memory region attributes for LPAE: | ||
| 127 | * | ||
| 128 | * n = AttrIndx[2:0] | ||
| 129 | * n MAIR | ||
| 130 | * DEVICE_nGnRnE 000 00000000 | ||
| 131 | * DEVICE_nGnRE 001 00000100 | ||
| 132 | * DEVICE_GRE 010 00001100 | ||
| 133 | * NORMAL_NC 011 01000100 | ||
| 134 | * NORMAL 100 11111111 | ||
| 135 | */ | ||
| 136 | ldr x5, =MAIR(0x00, MT_DEVICE_nGnRnE) | \ | ||
| 137 | MAIR(0x04, MT_DEVICE_nGnRE) | \ | ||
| 138 | MAIR(0x0c, MT_DEVICE_GRE) | \ | ||
| 139 | MAIR(0x44, MT_NORMAL_NC) | \ | ||
| 140 | MAIR(0xff, MT_NORMAL) | ||
| 141 | msr mair_el1, x5 | ||
| 142 | /* | ||
| 143 | * Prepare SCTLR | ||
| 144 | */ | ||
| 145 | adr x5, crval | ||
| 146 | ldp w5, w6, [x5] | ||
| 147 | mrs x0, sctlr_el1 | ||
| 148 | bic x0, x0, x5 // clear bits | ||
| 149 | orr x0, x0, x6 // set bits | ||
| 150 | /* | ||
| 151 | * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for | ||
| 152 | * both user and kernel. | ||
| 153 | */ | ||
| 154 | ldr x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | TCR_IPS_40BIT | \ | ||
| 155 | TCR_ASID16 | (1 << 31) | ||
| 156 | #ifdef CONFIG_ARM64_64K_PAGES | ||
| 157 | orr x10, x10, TCR_TG0_64K | ||
| 158 | orr x10, x10, TCR_TG1_64K | ||
| 159 | #endif | ||
| 160 | msr tcr_el1, x10 | ||
| 161 | ret // return to head.S | ||
| 162 | ENDPROC(__cpu_setup) | ||
| 163 | |||
| 164 | /* | ||
| 165 | * n n T | ||
| 166 | * U E WT T UD US IHBS | ||
| 167 | * CE0 XWHW CZ ME TEEA S | ||
| 168 | * .... .IEE .... NEAI TE.I ..AD DEN0 ACAM | ||
| 169 | * 0011 0... 1101 ..0. ..0. 10.. .... .... < hardware reserved | ||
| 170 | * .... .100 .... 01.1 11.1 ..01 0001 1101 < software settings | ||
| 171 | */ | ||
| 172 | .type crval, #object | ||
| 173 | crval: | ||
| 174 | .word 0x030802e2 // clear | ||
| 175 | .word 0x0405d11d // set | ||
diff --git a/arch/arm64/mm/tlb.S b/arch/arm64/mm/tlb.S new file mode 100644 index 000000000000..8ae80a18e8ec --- /dev/null +++ b/arch/arm64/mm/tlb.S | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* | ||
| 2 | * Based on arch/arm/mm/tlb.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1997-2002 Russell King | ||
| 5 | * Copyright (C) 2012 ARM Ltd. | ||
| 6 | * Written by Catalin Marinas <catalin.marinas@arm.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | #include <linux/linkage.h> | ||
| 21 | #include <asm/assembler.h> | ||
| 22 | #include <asm/asm-offsets.h> | ||
| 23 | #include <asm/page.h> | ||
| 24 | #include <asm/tlbflush.h> | ||
| 25 | #include "proc-macros.S" | ||
| 26 | |||
| 27 | /* | ||
| 28 | * __cpu_flush_user_tlb_range(start, end, vma) | ||
| 29 | * | ||
| 30 | * Invalidate a range of TLB entries in the specified address space. | ||
| 31 | * | ||
| 32 | * - start - start address (may not be aligned) | ||
| 33 | * - end - end address (exclusive, may not be aligned) | ||
| 34 | * - vma - vma_struct describing address range | ||
| 35 | */ | ||
| 36 | ENTRY(__cpu_flush_user_tlb_range) | ||
| 37 | vma_vm_mm x3, x2 // get vma->vm_mm | ||
| 38 | mmid x3, x3 // get vm_mm->context.id | ||
| 39 | dsb sy | ||
| 40 | lsr x0, x0, #12 // align address | ||
| 41 | lsr x1, x1, #12 | ||
| 42 | bfi x0, x3, #48, #16 // start VA and ASID | ||
| 43 | bfi x1, x3, #48, #16 // end VA and ASID | ||
| 44 | 1: tlbi vae1is, x0 // TLB invalidate by address and ASID | ||
| 45 | add x0, x0, #1 | ||
| 46 | cmp x0, x1 | ||
| 47 | b.lo 1b | ||
| 48 | dsb sy | ||
| 49 | ret | ||
| 50 | ENDPROC(__cpu_flush_user_tlb_range) | ||
| 51 | |||
| 52 | /* | ||
| 53 | * __cpu_flush_kern_tlb_range(start,end) | ||
| 54 | * | ||
| 55 | * Invalidate a range of kernel TLB entries. | ||
| 56 | * | ||
| 57 | * - start - start address (may not be aligned) | ||
| 58 | * - end - end address (exclusive, may not be aligned) | ||
| 59 | */ | ||
| 60 | ENTRY(__cpu_flush_kern_tlb_range) | ||
| 61 | dsb sy | ||
| 62 | lsr x0, x0, #12 // align address | ||
| 63 | lsr x1, x1, #12 | ||
| 64 | 1: tlbi vaae1is, x0 // TLB invalidate by address | ||
| 65 | add x0, x0, #1 | ||
| 66 | cmp x0, x1 | ||
| 67 | b.lo 1b | ||
| 68 | dsb sy | ||
| 69 | isb | ||
| 70 | ret | ||
| 71 | ENDPROC(__cpu_flush_kern_tlb_range) | ||
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d53cd0afc200..6a78073c3808 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -35,3 +35,8 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | |||
| 35 | default y | 35 | default y |
| 36 | help | 36 | help |
| 37 | Use the always on PRCMU Timer as sched_clock | 37 | Use the always on PRCMU Timer as sched_clock |
| 38 | |||
| 39 | config CLKSRC_ARM_GENERIC | ||
| 40 | def_bool y if ARM64 | ||
| 41 | help | ||
| 42 | This option enables support for the ARM generic timer. | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index b65d0c56ab35..65919901a301 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -13,3 +13,4 @@ obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | |||
| 13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o | 13 | obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o |
| 14 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o | 14 | obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o |
| 15 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | 15 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o |
| 16 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o | ||
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c new file mode 100644 index 000000000000..c4d9f9566c64 --- /dev/null +++ b/drivers/clocksource/arm_generic.c | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | /* | ||
| 2 | * Generic timers support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 ARM Ltd. | ||
| 5 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/delay.h> | ||
| 23 | #include <linux/device.h> | ||
| 24 | #include <linux/smp.h> | ||
| 25 | #include <linux/cpu.h> | ||
| 26 | #include <linux/jiffies.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <linux/clockchips.h> | ||
| 29 | #include <linux/of_irq.h> | ||
| 30 | #include <linux/io.h> | ||
| 31 | |||
| 32 | #include <clocksource/arm_generic.h> | ||
| 33 | |||
| 34 | #include <asm/arm_generic.h> | ||
| 35 | |||
| 36 | static u32 arch_timer_rate; | ||
| 37 | static u64 sched_clock_mult __read_mostly; | ||
| 38 | static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt); | ||
| 39 | static int arch_timer_ppi; | ||
| 40 | |||
| 41 | static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id) | ||
| 42 | { | ||
| 43 | struct clock_event_device *evt = dev_id; | ||
| 44 | unsigned long ctrl; | ||
| 45 | |||
| 46 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 47 | if (ctrl & ARCH_TIMER_CTRL_ISTATUS) { | ||
| 48 | ctrl |= ARCH_TIMER_CTRL_IMASK; | ||
| 49 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 50 | evt->event_handler(evt); | ||
| 51 | return IRQ_HANDLED; | ||
| 52 | } | ||
| 53 | |||
| 54 | return IRQ_NONE; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void arch_timer_stop(void) | ||
| 58 | { | ||
| 59 | unsigned long ctrl; | ||
| 60 | |||
| 61 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 62 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | ||
| 63 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 64 | } | ||
| 65 | |||
| 66 | static void arch_timer_set_mode(enum clock_event_mode mode, | ||
| 67 | struct clock_event_device *clk) | ||
| 68 | { | ||
| 69 | switch (mode) { | ||
| 70 | case CLOCK_EVT_MODE_UNUSED: | ||
| 71 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 72 | arch_timer_stop(); | ||
| 73 | break; | ||
| 74 | default: | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | static int arch_timer_set_next_event(unsigned long evt, | ||
| 80 | struct clock_event_device *unused) | ||
| 81 | { | ||
| 82 | unsigned long ctrl; | ||
| 83 | |||
| 84 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
| 85 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | ||
| 86 | ctrl &= ~ARCH_TIMER_CTRL_IMASK; | ||
| 87 | |||
| 88 | arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt); | ||
| 89 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void __cpuinit arch_timer_setup(struct clock_event_device *clk) | ||
| 95 | { | ||
| 96 | /* Let's make sure the timer is off before doing anything else */ | ||
| 97 | arch_timer_stop(); | ||
| 98 | |||
| 99 | clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; | ||
| 100 | clk->name = "arch_sys_timer"; | ||
| 101 | clk->rating = 400; | ||
| 102 | clk->set_mode = arch_timer_set_mode; | ||
| 103 | clk->set_next_event = arch_timer_set_next_event; | ||
| 104 | clk->irq = arch_timer_ppi; | ||
| 105 | clk->cpumask = cpumask_of(smp_processor_id()); | ||
| 106 | |||
| 107 | clockevents_config_and_register(clk, arch_timer_rate, | ||
| 108 | 0xf, 0x7fffffff); | ||
| 109 | |||
| 110 | enable_percpu_irq(clk->irq, 0); | ||
| 111 | |||
| 112 | /* Ensure the physical counter is visible to userspace for the vDSO. */ | ||
| 113 | arch_counter_enable_user_access(); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void __init arch_timer_calibrate(void) | ||
| 117 | { | ||
| 118 | if (arch_timer_rate == 0) { | ||
| 119 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0); | ||
| 120 | arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ); | ||
| 121 | |||
| 122 | /* Check the timer frequency. */ | ||
| 123 | if (arch_timer_rate == 0) | ||
| 124 | panic("Architected timer frequency is set to zero.\n" | ||
| 125 | "You must set this in your .dts file\n"); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ | ||
| 129 | |||
| 130 | sched_clock_mult = NSEC_PER_SEC / arch_timer_rate; | ||
| 131 | |||
| 132 | pr_info("Architected local timer running at %u.%02uMHz.\n", | ||
| 133 | arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); | ||
| 134 | } | ||
| 135 | |||
| 136 | static cycle_t arch_counter_read(struct clocksource *cs) | ||
| 137 | { | ||
| 138 | return arch_counter_get_cntpct(); | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct clocksource clocksource_counter = { | ||
| 142 | .name = "arch_sys_counter", | ||
| 143 | .rating = 400, | ||
| 144 | .read = arch_counter_read, | ||
| 145 | .mask = CLOCKSOURCE_MASK(56), | ||
| 146 | .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES), | ||
| 147 | }; | ||
| 148 | |||
| 149 | int read_current_timer(unsigned long *timer_value) | ||
| 150 | { | ||
| 151 | *timer_value = arch_counter_get_cntpct(); | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | unsigned long long notrace sched_clock(void) | ||
| 156 | { | ||
| 157 | return arch_counter_get_cntvct() * sched_clock_mult; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | ||
| 161 | unsigned long action, void *hcpu) | ||
| 162 | { | ||
| 163 | int cpu = (long)hcpu; | ||
| 164 | struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu); | ||
| 165 | |||
| 166 | switch(action) { | ||
| 167 | case CPU_STARTING: | ||
| 168 | case CPU_STARTING_FROZEN: | ||
| 169 | arch_timer_setup(clk); | ||
| 170 | break; | ||
| 171 | |||
| 172 | case CPU_DYING: | ||
| 173 | case CPU_DYING_FROZEN: | ||
| 174 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | ||
| 175 | clk->irq, cpu); | ||
| 176 | disable_percpu_irq(clk->irq); | ||
| 177 | arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | |||
| 181 | return NOTIFY_OK; | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { | ||
| 185 | .notifier_call = arch_timer_cpu_notify, | ||
| 186 | }; | ||
| 187 | |||
| 188 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
| 189 | { .compatible = "arm,armv8-timer" }, | ||
| 190 | {}, | ||
| 191 | }; | ||
| 192 | |||
| 193 | int __init arm_generic_timer_init(void) | ||
| 194 | { | ||
| 195 | struct device_node *np; | ||
| 196 | int err; | ||
| 197 | u32 freq; | ||
| 198 | |||
| 199 | np = of_find_matching_node(NULL, arch_timer_of_match); | ||
| 200 | if (!np) { | ||
| 201 | pr_err("arch_timer: can't find DT node\n"); | ||
| 202 | return -ENODEV; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Try to determine the frequency from the device tree or CNTFRQ */ | ||
| 206 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
| 207 | arch_timer_rate = freq; | ||
| 208 | arch_timer_calibrate(); | ||
| 209 | |||
| 210 | arch_timer_ppi = irq_of_parse_and_map(np, 0); | ||
| 211 | pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi); | ||
| 212 | |||
| 213 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq, | ||
| 214 | np->name, &arch_timer_evt); | ||
| 215 | if (err) { | ||
| 216 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | ||
| 217 | arch_timer_ppi, err); | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
| 222 | |||
| 223 | /* Calibrate the delay loop directly */ | ||
| 224 | lpj_fine = arch_timer_rate / HZ; | ||
| 225 | |||
| 226 | /* Immediately configure the timer on the boot CPU */ | ||
| 227 | arch_timer_setup(per_cpu_ptr(&arch_timer_evt, smp_processor_id())); | ||
| 228 | |||
| 229 | register_cpu_notifier(&arch_timer_cpu_nb); | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| @@ -326,7 +326,7 @@ SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, | |||
| 326 | 326 | ||
| 327 | 327 | ||
| 328 | /* ---------- LFS-64 ----------- */ | 328 | /* ---------- LFS-64 ----------- */ |
| 329 | #ifdef __ARCH_WANT_STAT64 | 329 | #if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) |
| 330 | 330 | ||
| 331 | #ifndef INIT_STRUCT_STAT64_PADDING | 331 | #ifndef INIT_STRUCT_STAT64_PADDING |
| 332 | # define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) | 332 | # define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) |
| @@ -415,7 +415,7 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, | |||
| 415 | return error; | 415 | return error; |
| 416 | return cp_new_stat64(&stat, statbuf); | 416 | return cp_new_stat64(&stat, statbuf); |
| 417 | } | 417 | } |
| 418 | #endif /* __ARCH_WANT_STAT64 */ | 418 | #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ |
| 419 | 419 | ||
| 420 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ | 420 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ |
| 421 | void __inode_add_bytes(struct inode *inode, loff_t bytes) | 421 | void __inode_add_bytes(struct inode *inode, loff_t bytes) |
diff --git a/include/asm-generic/bitops/builtin-__ffs.h b/include/asm-generic/bitops/builtin-__ffs.h new file mode 100644 index 000000000000..90041e3a41f0 --- /dev/null +++ b/include/asm-generic/bitops/builtin-__ffs.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef _ASM_GENERIC_BITOPS_BUILTIN___FFS_H_ | ||
| 2 | #define _ASM_GENERIC_BITOPS_BUILTIN___FFS_H_ | ||
| 3 | |||
| 4 | /** | ||
| 5 | * __ffs - find first bit in word. | ||
| 6 | * @word: The word to search | ||
| 7 | * | ||
| 8 | * Undefined if no bit exists, so code should check against 0 first. | ||
| 9 | */ | ||
| 10 | static __always_inline unsigned long __ffs(unsigned long word) | ||
| 11 | { | ||
| 12 | return __builtin_ctzl(word); | ||
| 13 | } | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/include/asm-generic/bitops/builtin-__fls.h b/include/asm-generic/bitops/builtin-__fls.h new file mode 100644 index 000000000000..0248f386635f --- /dev/null +++ b/include/asm-generic/bitops/builtin-__fls.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #ifndef _ASM_GENERIC_BITOPS_BUILTIN___FLS_H_ | ||
| 2 | #define _ASM_GENERIC_BITOPS_BUILTIN___FLS_H_ | ||
| 3 | |||
| 4 | /** | ||
| 5 | * __fls - find last (most-significant) set bit in a long word | ||
| 6 | * @word: the word to search | ||
| 7 | * | ||
| 8 | * Undefined if no set bit exists, so code should check against 0 first. | ||
| 9 | */ | ||
| 10 | static __always_inline unsigned long __fls(unsigned long word) | ||
| 11 | { | ||
| 12 | return (sizeof(word) * 8) - 1 - __builtin_clzl(word); | ||
| 13 | } | ||
| 14 | |||
| 15 | #endif | ||
diff --git a/include/asm-generic/bitops/builtin-ffs.h b/include/asm-generic/bitops/builtin-ffs.h new file mode 100644 index 000000000000..064825829e1c --- /dev/null +++ b/include/asm-generic/bitops/builtin-ffs.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | #ifndef _ASM_GENERIC_BITOPS_BUILTIN_FFS_H_ | ||
| 2 | #define _ASM_GENERIC_BITOPS_BUILTIN_FFS_H_ | ||
| 3 | |||
| 4 | /** | ||
| 5 | * ffs - find first bit set | ||
| 6 | * @x: the word to search | ||
| 7 | * | ||
| 8 | * This is defined the same way as | ||
| 9 | * the libc and compiler builtin ffs routines, therefore | ||
| 10 | * differs in spirit from the above ffz (man ffs). | ||
| 11 | */ | ||
| 12 | static __always_inline int ffs(int x) | ||
| 13 | { | ||
| 14 | return __builtin_ffs(x); | ||
| 15 | } | ||
| 16 | |||
| 17 | #endif | ||
diff --git a/include/asm-generic/bitops/builtin-fls.h b/include/asm-generic/bitops/builtin-fls.h new file mode 100644 index 000000000000..eda652d0ac7f --- /dev/null +++ b/include/asm-generic/bitops/builtin-fls.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef _ASM_GENERIC_BITOPS_BUILTIN_FLS_H_ | ||
| 2 | #define _ASM_GENERIC_BITOPS_BUILTIN_FLS_H_ | ||
| 3 | |||
| 4 | /** | ||
| 5 | * fls - find last (most-significant) bit set | ||
| 6 | * @x: the word to search | ||
| 7 | * | ||
| 8 | * This is defined the same way as ffs. | ||
| 9 | * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. | ||
| 10 | */ | ||
| 11 | static __always_inline int fls(int x) | ||
| 12 | { | ||
| 13 | return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; | ||
| 14 | } | ||
| 15 | |||
| 16 | #endif | ||
diff --git a/include/clocksource/arm_generic.h b/include/clocksource/arm_generic.h new file mode 100644 index 000000000000..5b41b0d27f0f --- /dev/null +++ b/include/clocksource/arm_generic.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 ARM Ltd. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #ifndef __CLKSOURCE_ARM_GENERIC_H | ||
| 17 | #define __CLKSOURCE_ARM_GENERIC_H | ||
| 18 | |||
| 19 | extern int arm_generic_timer_init(void); | ||
| 20 | |||
| 21 | #endif | ||
diff --git a/include/linux/elf.h b/include/linux/elf.h index f930b1a390ab..0a05051a8924 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
| @@ -389,6 +389,9 @@ typedef struct elf64_shdr { | |||
| 389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ | 389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ |
| 390 | #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ | 390 | #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ |
| 391 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ | 391 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ |
| 392 | #define NT_ARM_TLS 0x401 /* ARM TLS register */ | ||
| 393 | #define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ | ||
| 394 | #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ | ||
| 392 | 395 | ||
| 393 | 396 | ||
| 394 | /* Note header in a PT_NOTE section */ | 397 | /* Note header in a PT_NOTE section */ |
diff --git a/init/Kconfig b/init/Kconfig index 3466a6e017b7..495e6e9632db 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
| @@ -1216,7 +1216,8 @@ menuconfig EXPERT | |||
| 1216 | 1216 | ||
| 1217 | config UID16 | 1217 | config UID16 |
| 1218 | bool "Enable 16-bit UID system calls" if EXPERT | 1218 | bool "Enable 16-bit UID system calls" if EXPERT |
| 1219 | depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) | 1219 | depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) \ |
| 1220 | || AARCH32_EMULATION | ||
| 1220 | default y | 1221 | default y |
| 1221 | help | 1222 | help |
| 1222 | This enables the legacy 16-bit UID syscall wrappers. | 1223 | This enables the legacy 16-bit UID syscall wrappers. |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 81c7b1a1a307..84c76a34e41c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -1544,7 +1544,7 @@ static struct ctl_table fs_table[] = { | |||
| 1544 | 1544 | ||
| 1545 | static struct ctl_table debug_table[] = { | 1545 | static struct ctl_table debug_table[] = { |
| 1546 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ | 1546 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ |
| 1547 | defined(CONFIG_S390) || defined(CONFIG_TILE) | 1547 | defined(CONFIG_S390) || defined(CONFIG_TILE) || defined(CONFIG_ARM64) |
| 1548 | { | 1548 | { |
| 1549 | .procname = "exception-trace", | 1549 | .procname = "exception-trace", |
| 1550 | .data = &show_unhandled_signals, | 1550 | .data = &show_unhandled_signals, |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index dacbbe4d7a80..35c4565ee8fa 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -452,7 +452,8 @@ config SLUB_STATS | |||
| 452 | config DEBUG_KMEMLEAK | 452 | config DEBUG_KMEMLEAK |
| 453 | bool "Kernel memory leak detector" | 453 | bool "Kernel memory leak detector" |
| 454 | depends on DEBUG_KERNEL && EXPERIMENTAL && \ | 454 | depends on DEBUG_KERNEL && EXPERIMENTAL && \ |
| 455 | (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || MICROBLAZE || TILE) | 455 | (X86 || ARM || PPC || MIPS || S390 || SPARC64 || SUPERH || \ |
| 456 | MICROBLAZE || TILE || ARM64) | ||
| 456 | 457 | ||
| 457 | select DEBUG_FS | 458 | select DEBUG_FS |
| 458 | select STACKTRACE if STACKTRACE_SUPPORT | 459 | select STACKTRACE if STACKTRACE_SUPPORT |
| @@ -753,7 +754,8 @@ config DEBUG_BUGVERBOSE | |||
| 753 | bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT | 754 | bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT |
| 754 | depends on BUG | 755 | depends on BUG |
| 755 | depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \ | 756 | depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \ |
| 756 | FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || TILE | 757 | FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || \ |
| 758 | TILE || ARM64 | ||
| 757 | default y | 759 | default y |
| 758 | help | 760 | help |
| 759 | Say Y here to make BUG() panics output the file name and line number | 761 | Say Y here to make BUG() panics output the file name and line number |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 87f4ec6d1f36..a89cbbb61801 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
| @@ -88,6 +88,12 @@ void get_term_dimensions(struct winsize *ws); | |||
| 88 | #define CPUINFO_PROC "Processor" | 88 | #define CPUINFO_PROC "Processor" |
| 89 | #endif | 89 | #endif |
| 90 | 90 | ||
| 91 | #ifdef __aarch64__ | ||
| 92 | #include "../../arch/arm64/include/asm/unistd.h" | ||
| 93 | #define rmb() asm volatile("dmb ld" ::: "memory") | ||
| 94 | #define cpu_relax() asm volatile("yield" ::: "memory") | ||
| 95 | #endif | ||
| 96 | |||
| 91 | #ifdef __mips__ | 97 | #ifdef __mips__ |
| 92 | #include "../../arch/mips/include/asm/unistd.h" | 98 | #include "../../arch/mips/include/asm/unistd.h" |
| 93 | #define rmb() asm volatile( \ | 99 | #define rmb() asm volatile( \ |
