diff options
Diffstat (limited to 'arch/arm64')
32 files changed, 1112 insertions, 276 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e759af5d7098..e384ab9b3862 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig | |||
@@ -112,6 +112,9 @@ config IOMMU_HELPER | |||
112 | config KERNEL_MODE_NEON | 112 | config KERNEL_MODE_NEON |
113 | def_bool y | 113 | def_bool y |
114 | 114 | ||
115 | config FIX_EARLYCON_MEM | ||
116 | def_bool y | ||
117 | |||
115 | source "init/Kconfig" | 118 | source "init/Kconfig" |
116 | 119 | ||
117 | source "kernel/Kconfig.freezer" | 120 | source "kernel/Kconfig.freezer" |
@@ -280,6 +283,20 @@ config CMDLINE_FORCE | |||
280 | This is useful if you cannot or don't want to change the | 283 | This is useful if you cannot or don't want to change the |
281 | command-line options your boot loader passes to the kernel. | 284 | command-line options your boot loader passes to the kernel. |
282 | 285 | ||
286 | config EFI | ||
287 | bool "UEFI runtime support" | ||
288 | depends on OF && !CPU_BIG_ENDIAN | ||
289 | select LIBFDT | ||
290 | select UCS2_STRING | ||
291 | select EFI_PARAMS_FROM_FDT | ||
292 | default y | ||
293 | help | ||
294 | This option provides support for runtime services provided | ||
295 | by UEFI firmware (such as non-volatile variables, realtime | ||
296 | clock, and platform reset). A UEFI stub is also provided to | ||
297 | allow the kernel to be booted as an EFI application. This | ||
298 | is only useful on systems that have UEFI firmware. | ||
299 | |||
283 | endmenu | 300 | endmenu |
284 | 301 | ||
285 | menu "Userspace binary formats" | 302 | menu "Userspace binary formats" |
@@ -331,6 +348,8 @@ source "net/Kconfig" | |||
331 | 348 | ||
332 | source "drivers/Kconfig" | 349 | source "drivers/Kconfig" |
333 | 350 | ||
351 | source "drivers/firmware/Kconfig" | ||
352 | |||
334 | source "fs/Kconfig" | 353 | source "fs/Kconfig" |
335 | 354 | ||
336 | source "arch/arm64/kvm/Kconfig" | 355 | source "arch/arm64/kvm/Kconfig" |
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index d10ec334c93b..1c1b75629842 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug | |||
@@ -20,15 +20,6 @@ config STRICT_DEVMEM | |||
20 | 20 | ||
21 | If in doubt, say Y. | 21 | If in doubt, say Y. |
22 | 22 | ||
23 | config EARLY_PRINTK | ||
24 | bool "Early printk support" | ||
25 | default y | ||
26 | help | ||
27 | Say Y here if you want to have an early console using the | ||
28 | earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It | ||
29 | is assumed that the early console device has been initialised | ||
30 | by the boot loader prior to starting the Linux kernel. | ||
31 | |||
32 | config PID_IN_CONTEXTIDR | 23 | config PID_IN_CONTEXTIDR |
33 | bool "Write the current PID to the CONTEXTIDR register" | 24 | bool "Write the current PID to the CONTEXTIDR register" |
34 | help | 25 | help |
diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi index 2f2ecd217363..ac2cb2418025 100644 --- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi +++ b/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi | |||
@@ -200,7 +200,7 @@ | |||
200 | }; | 200 | }; |
201 | 201 | ||
202 | mcc { | 202 | mcc { |
203 | compatible = "arm,vexpress,config-bus", "simple-bus"; | 203 | compatible = "arm,vexpress,config-bus"; |
204 | arm,vexpress,config-bridge = <&v2m_sysreg>; | 204 | arm,vexpress,config-bridge = <&v2m_sysreg>; |
205 | 205 | ||
206 | v2m_oscclk1: osc@1 { | 206 | v2m_oscclk1: osc@1 { |
diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 0237f0867e37..57e8cb49824c 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h | |||
@@ -152,11 +152,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
152 | 152 | ||
153 | #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) | 153 | #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) |
154 | 154 | ||
155 | #define smp_mb__before_atomic_dec() smp_mb() | ||
156 | #define smp_mb__after_atomic_dec() smp_mb() | ||
157 | #define smp_mb__before_atomic_inc() smp_mb() | ||
158 | #define smp_mb__after_atomic_inc() smp_mb() | ||
159 | |||
160 | /* | 155 | /* |
161 | * 64-bit atomic operations. | 156 | * 64-bit atomic operations. |
162 | */ | 157 | */ |
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 66eb7648043b..48b9e704af7c 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h | |||
@@ -98,6 +98,9 @@ do { \ | |||
98 | #define set_mb(var, value) do { var = value; smp_mb(); } while (0) | 98 | #define set_mb(var, value) do { var = value; smp_mb(); } while (0) |
99 | #define nop() asm volatile("nop"); | 99 | #define nop() asm volatile("nop"); |
100 | 100 | ||
101 | #define smp_mb__before_atomic() smp_mb() | ||
102 | #define smp_mb__after_atomic() smp_mb() | ||
103 | |||
101 | #endif /* __ASSEMBLY__ */ | 104 | #endif /* __ASSEMBLY__ */ |
102 | 105 | ||
103 | #endif /* __ASM_BARRIER_H */ | 106 | #endif /* __ASM_BARRIER_H */ |
diff --git a/arch/arm64/include/asm/bitops.h b/arch/arm64/include/asm/bitops.h index aa5b59d6ba43..9c19594ce7cb 100644 --- a/arch/arm64/include/asm/bitops.h +++ b/arch/arm64/include/asm/bitops.h | |||
@@ -17,17 +17,8 @@ | |||
17 | #define __ASM_BITOPS_H | 17 | #define __ASM_BITOPS_H |
18 | 18 | ||
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | |||
21 | #include <asm/barrier.h> | 20 | #include <asm/barrier.h> |
22 | 21 | ||
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 | 22 | #ifndef _LINUX_BITOPS_H |
32 | #error only <linux/bitops.h> can be included directly | 23 | #error only <linux/bitops.h> can be included directly |
33 | #endif | 24 | #endif |
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index 152413076503..d7b4b38a8e86 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h | |||
@@ -39,6 +39,7 @@ struct device_node; | |||
39 | * from the cpu to be killed. | 39 | * from the cpu to be killed. |
40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the | 40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the |
41 | * cpu being killed. | 41 | * cpu being killed. |
42 | * @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu. | ||
42 | * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing | 43 | * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing |
43 | * to wrong parameters or error conditions. Called from the | 44 | * to wrong parameters or error conditions. Called from the |
44 | * CPU being suspended. Must be called with IRQs disabled. | 45 | * CPU being suspended. Must be called with IRQs disabled. |
@@ -52,6 +53,7 @@ struct cpu_operations { | |||
52 | #ifdef CONFIG_HOTPLUG_CPU | 53 | #ifdef CONFIG_HOTPLUG_CPU |
53 | int (*cpu_disable)(unsigned int cpu); | 54 | int (*cpu_disable)(unsigned int cpu); |
54 | void (*cpu_die)(unsigned int cpu); | 55 | void (*cpu_die)(unsigned int cpu); |
56 | int (*cpu_kill)(unsigned int cpu); | ||
55 | #endif | 57 | #endif |
56 | #ifdef CONFIG_ARM64_CPU_SUSPEND | 58 | #ifdef CONFIG_ARM64_CPU_SUSPEND |
57 | int (*cpu_suspend)(unsigned long); | 59 | int (*cpu_suspend)(unsigned long); |
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index c404fb0df3a6..27f54a7cc81b 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | #define ARM_CPU_PART_AEM_V8 0xD0F0 | 42 | #define ARM_CPU_PART_AEM_V8 0xD0F0 |
43 | #define ARM_CPU_PART_FOUNDATION 0xD000 | 43 | #define ARM_CPU_PART_FOUNDATION 0xD000 |
44 | #define ARM_CPU_PART_CORTEX_A53 0xD030 | ||
44 | #define ARM_CPU_PART_CORTEX_A57 0xD070 | 45 | #define ARM_CPU_PART_CORTEX_A57 0xD070 |
45 | 46 | ||
46 | #define APM_CPU_PART_POTENZA 0x0000 | 47 | #define APM_CPU_PART_POTENZA 0x0000 |
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h new file mode 100644 index 000000000000..5a46c4e7f539 --- /dev/null +++ b/arch/arm64/include/asm/efi.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef _ASM_EFI_H | ||
2 | #define _ASM_EFI_H | ||
3 | |||
4 | #include <asm/io.h> | ||
5 | |||
6 | #ifdef CONFIG_EFI | ||
7 | extern void efi_init(void); | ||
8 | extern void efi_idmap_init(void); | ||
9 | #else | ||
10 | #define efi_init() | ||
11 | #define efi_idmap_init() | ||
12 | #endif | ||
13 | |||
14 | #endif /* _ASM_EFI_H */ | ||
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0a1d69751562..92242ce06309 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <kvm/arm_vgic.h> | 39 | #include <kvm/arm_vgic.h> |
40 | #include <kvm/arm_arch_timer.h> | 40 | #include <kvm/arm_arch_timer.h> |
41 | 41 | ||
42 | #define KVM_VCPU_MAX_FEATURES 2 | 42 | #define KVM_VCPU_MAX_FEATURES 3 |
43 | 43 | ||
44 | struct kvm_vcpu; | 44 | struct kvm_vcpu; |
45 | int kvm_target_cpu(void); | 45 | int kvm_target_cpu(void); |
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h index e301a4816355..bc39e557c56c 100644 --- a/arch/arm64/include/asm/kvm_psci.h +++ b/arch/arm64/include/asm/kvm_psci.h | |||
@@ -18,6 +18,10 @@ | |||
18 | #ifndef __ARM64_KVM_PSCI_H__ | 18 | #ifndef __ARM64_KVM_PSCI_H__ |
19 | #define __ARM64_KVM_PSCI_H__ | 19 | #define __ARM64_KVM_PSCI_H__ |
20 | 20 | ||
21 | bool kvm_psci_call(struct kvm_vcpu *vcpu); | 21 | #define KVM_ARM_PSCI_0_1 1 |
22 | #define KVM_ARM_PSCI_0_2 2 | ||
23 | |||
24 | int kvm_psci_version(struct kvm_vcpu *vcpu); | ||
25 | int kvm_psci_call(struct kvm_vcpu *vcpu); | ||
22 | 26 | ||
23 | #endif /* __ARM64_KVM_PSCI_H__ */ | 27 | #endif /* __ARM64_KVM_PSCI_H__ */ |
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index aff0292c8f4d..c2f006c48bdb 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h | |||
@@ -31,5 +31,7 @@ extern void paging_init(void); | |||
31 | extern void setup_mm_for_reboot(void); | 31 | extern void setup_mm_for_reboot(void); |
32 | extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); | 32 | extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); |
33 | extern void init_mem_pgprot(void); | 33 | extern void init_mem_pgprot(void); |
34 | /* create an identity mapping for memory (or io if map_io is true) */ | ||
35 | extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io); | ||
34 | 36 | ||
35 | #endif | 37 | #endif |
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 7b1c67a0b485..e2f96748859b 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h | |||
@@ -406,7 +406,7 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; | |||
406 | 406 | ||
407 | /* | 407 | /* |
408 | * Ensure that there are not more swap files than can be encoded in the kernel | 408 | * Ensure that there are not more swap files than can be encoded in the kernel |
409 | * the PTEs. | 409 | * PTEs. |
410 | */ | 410 | */ |
411 | #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) | 411 | #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS) |
412 | 412 | ||
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index d15ab8b46336..e5312ea0ec1a 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h | |||
@@ -14,6 +14,6 @@ | |||
14 | #ifndef __ASM_PSCI_H | 14 | #ifndef __ASM_PSCI_H |
15 | #define __ASM_PSCI_H | 15 | #define __ASM_PSCI_H |
16 | 16 | ||
17 | void psci_init(void); | 17 | int psci_init(void); |
18 | 18 | ||
19 | #endif /* __ASM_PSCI_H */ | 19 | #endif /* __ASM_PSCI_H */ |
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 720e70b66ffd..7b8e3a2a00fb 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h | |||
@@ -95,13 +95,11 @@ static inline struct thread_info *current_thread_info(void) | |||
95 | * TIF_NEED_RESCHED - rescheduling necessary | 95 | * TIF_NEED_RESCHED - rescheduling necessary |
96 | * TIF_NOTIFY_RESUME - callback before returning to user | 96 | * TIF_NOTIFY_RESUME - callback before returning to user |
97 | * TIF_USEDFPU - FPU was used by this task this quantum (SMP) | 97 | * TIF_USEDFPU - FPU was used by this task this quantum (SMP) |
98 | * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED | ||
99 | */ | 98 | */ |
100 | #define TIF_SIGPENDING 0 | 99 | #define TIF_SIGPENDING 0 |
101 | #define TIF_NEED_RESCHED 1 | 100 | #define TIF_NEED_RESCHED 1 |
102 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ | 101 | #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ |
103 | #define TIF_SYSCALL_TRACE 8 | 102 | #define TIF_SYSCALL_TRACE 8 |
104 | #define TIF_POLLING_NRFLAG 16 | ||
105 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ | 103 | #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ |
106 | #define TIF_FREEZE 19 | 104 | #define TIF_FREEZE 19 |
107 | #define TIF_RESTORE_SIGMASK 20 | 105 | #define TIF_RESTORE_SIGMASK 20 |
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index eaf54a30bedc..e633ff8cdec8 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h | |||
@@ -31,6 +31,7 @@ | |||
31 | #define KVM_NR_SPSR 5 | 31 | #define KVM_NR_SPSR 5 |
32 | 32 | ||
33 | #ifndef __ASSEMBLY__ | 33 | #ifndef __ASSEMBLY__ |
34 | #include <linux/psci.h> | ||
34 | #include <asm/types.h> | 35 | #include <asm/types.h> |
35 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
36 | 37 | ||
@@ -56,8 +57,9 @@ struct kvm_regs { | |||
56 | #define KVM_ARM_TARGET_FOUNDATION_V8 1 | 57 | #define KVM_ARM_TARGET_FOUNDATION_V8 1 |
57 | #define KVM_ARM_TARGET_CORTEX_A57 2 | 58 | #define KVM_ARM_TARGET_CORTEX_A57 2 |
58 | #define KVM_ARM_TARGET_XGENE_POTENZA 3 | 59 | #define KVM_ARM_TARGET_XGENE_POTENZA 3 |
60 | #define KVM_ARM_TARGET_CORTEX_A53 4 | ||
59 | 61 | ||
60 | #define KVM_ARM_NUM_TARGETS 4 | 62 | #define KVM_ARM_NUM_TARGETS 5 |
61 | 63 | ||
62 | /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ | 64 | /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ |
63 | #define KVM_ARM_DEVICE_TYPE_SHIFT 0 | 65 | #define KVM_ARM_DEVICE_TYPE_SHIFT 0 |
@@ -77,6 +79,7 @@ struct kvm_regs { | |||
77 | 79 | ||
78 | #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ | 80 | #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ |
79 | #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ | 81 | #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ |
82 | #define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ | ||
80 | 83 | ||
81 | struct kvm_vcpu_init { | 84 | struct kvm_vcpu_init { |
82 | __u32 target; | 85 | __u32 target; |
@@ -186,10 +189,10 @@ struct kvm_arch_memory_slot { | |||
186 | #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) | 189 | #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) |
187 | #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) | 190 | #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) |
188 | 191 | ||
189 | #define KVM_PSCI_RET_SUCCESS 0 | 192 | #define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS |
190 | #define KVM_PSCI_RET_NI ((unsigned long)-1) | 193 | #define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED |
191 | #define KVM_PSCI_RET_INVAL ((unsigned long)-2) | 194 | #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS |
192 | #define KVM_PSCI_RET_DENIED ((unsigned long)-3) | 195 | #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED |
193 | 196 | ||
194 | #endif | 197 | #endif |
195 | 198 | ||
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7d811d9522bc..ba5e17a522d5 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile | |||
@@ -4,6 +4,8 @@ | |||
4 | 4 | ||
5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) | 5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) |
6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
7 | CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \ | ||
8 | -I$(src)/../../../scripts/dtc/libfdt | ||
7 | 9 | ||
8 | # Object file lists. | 10 | # Object file lists. |
9 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ | 11 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ |
@@ -18,10 +20,10 @@ arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o | |||
18 | arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o | 20 | arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o |
19 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 21 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
20 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o | 22 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o |
21 | arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
22 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o | 23 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o |
23 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 24 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
24 | arm64-obj-$(CONFIG_KGDB) += kgdb.o | 25 | arm64-obj-$(CONFIG_KGDB) += kgdb.o |
26 | arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o | ||
25 | 27 | ||
26 | obj-y += $(arm64-obj-y) vdso/ | 28 | obj-y += $(arm64-obj-y) vdso/ |
27 | obj-m += $(arm64-obj-m) | 29 | obj-m += $(arm64-obj-m) |
diff --git a/arch/arm64/kernel/early_printk.c b/arch/arm64/kernel/early_printk.c deleted file mode 100644 index 2dc36d00addf..000000000000 --- a/arch/arm64/kernel/early_printk.c +++ /dev/null | |||
@@ -1,156 +0,0 @@ | |||
1 | /* | ||
2 | * Earlyprintk support. | ||
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 | #include <linux/kernel.h> | ||
20 | #include <linux/console.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <linux/amba/serial.h> | ||
27 | #include <linux/serial_reg.h> | ||
28 | |||
29 | #include <asm/fixmap.h> | ||
30 | |||
31 | static void __iomem *early_base; | ||
32 | static void (*printch)(char ch); | ||
33 | |||
34 | /* | ||
35 | * PL011 single character TX. | ||
36 | */ | ||
37 | static void pl011_printch(char ch) | ||
38 | { | ||
39 | while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_TXFF) | ||
40 | ; | ||
41 | writeb_relaxed(ch, early_base + UART01x_DR); | ||
42 | while (readl_relaxed(early_base + UART01x_FR) & UART01x_FR_BUSY) | ||
43 | ; | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Semihosting-based debug console | ||
48 | */ | ||
49 | static void smh_printch(char ch) | ||
50 | { | ||
51 | asm volatile("mov x1, %0\n" | ||
52 | "mov x0, #3\n" | ||
53 | "hlt 0xf000\n" | ||
54 | : : "r" (&ch) : "x0", "x1", "memory"); | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * 8250/16550 (8-bit aligned registers) single character TX. | ||
59 | */ | ||
60 | static void uart8250_8bit_printch(char ch) | ||
61 | { | ||
62 | while (!(readb_relaxed(early_base + UART_LSR) & UART_LSR_THRE)) | ||
63 | ; | ||
64 | writeb_relaxed(ch, early_base + UART_TX); | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * 8250/16550 (32-bit aligned registers) single character TX. | ||
69 | */ | ||
70 | static void uart8250_32bit_printch(char ch) | ||
71 | { | ||
72 | while (!(readl_relaxed(early_base + (UART_LSR << 2)) & UART_LSR_THRE)) | ||
73 | ; | ||
74 | writel_relaxed(ch, early_base + (UART_TX << 2)); | ||
75 | } | ||
76 | |||
77 | struct earlycon_match { | ||
78 | const char *name; | ||
79 | void (*printch)(char ch); | ||
80 | }; | ||
81 | |||
82 | static const struct earlycon_match earlycon_match[] __initconst = { | ||
83 | { .name = "pl011", .printch = pl011_printch, }, | ||
84 | { .name = "smh", .printch = smh_printch, }, | ||
85 | { .name = "uart8250-8bit", .printch = uart8250_8bit_printch, }, | ||
86 | { .name = "uart8250-32bit", .printch = uart8250_32bit_printch, }, | ||
87 | {} | ||
88 | }; | ||
89 | |||
90 | static void early_write(struct console *con, const char *s, unsigned n) | ||
91 | { | ||
92 | while (n-- > 0) { | ||
93 | if (*s == '\n') | ||
94 | printch('\r'); | ||
95 | printch(*s); | ||
96 | s++; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static struct console early_console_dev = { | ||
101 | .name = "earlycon", | ||
102 | .write = early_write, | ||
103 | .flags = CON_PRINTBUFFER | CON_BOOT, | ||
104 | .index = -1, | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * Parse earlyprintk=... parameter in the format: | ||
109 | * | ||
110 | * <name>[,<addr>][,<options>] | ||
111 | * | ||
112 | * and register the early console. It is assumed that the UART has been | ||
113 | * initialised by the bootloader already. | ||
114 | */ | ||
115 | static int __init setup_early_printk(char *buf) | ||
116 | { | ||
117 | const struct earlycon_match *match = earlycon_match; | ||
118 | phys_addr_t paddr = 0; | ||
119 | |||
120 | if (!buf) { | ||
121 | pr_warning("No earlyprintk arguments passed.\n"); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | while (match->name) { | ||
126 | size_t len = strlen(match->name); | ||
127 | if (!strncmp(buf, match->name, len)) { | ||
128 | buf += len; | ||
129 | break; | ||
130 | } | ||
131 | match++; | ||
132 | } | ||
133 | if (!match->name) { | ||
134 | pr_warning("Unknown earlyprintk arguments: %s\n", buf); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /* I/O address */ | ||
139 | if (!strncmp(buf, ",0x", 3)) { | ||
140 | char *e; | ||
141 | paddr = simple_strtoul(buf + 1, &e, 16); | ||
142 | buf = e; | ||
143 | } | ||
144 | /* no options parsing yet */ | ||
145 | |||
146 | if (paddr) | ||
147 | early_base = (void __iomem *)set_fixmap_offset_io(FIX_EARLYCON_MEM_BASE, paddr); | ||
148 | |||
149 | printch = match->printch; | ||
150 | early_console = &early_console_dev; | ||
151 | register_console(&early_console_dev); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | early_param("earlyprintk", setup_early_printk); | ||
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S new file mode 100644 index 000000000000..66716c9b9e5f --- /dev/null +++ b/arch/arm64/kernel/efi-entry.S | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * EFI entry point. | ||
3 | * | ||
4 | * Copyright (C) 2013, 2014 Red Hat, Inc. | ||
5 | * Author: Mark Salter <msalter@redhat.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 | */ | ||
12 | #include <linux/linkage.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/assembler.h> | ||
16 | |||
17 | #define EFI_LOAD_ERROR 0x8000000000000001 | ||
18 | |||
19 | __INIT | ||
20 | |||
21 | /* | ||
22 | * We arrive here from the EFI boot manager with: | ||
23 | * | ||
24 | * * CPU in little-endian mode | ||
25 | * * MMU on with identity-mapped RAM | ||
26 | * * Icache and Dcache on | ||
27 | * | ||
28 | * We will most likely be running from some place other than where | ||
29 | * we want to be. The kernel image wants to be placed at TEXT_OFFSET | ||
30 | * from start of RAM. | ||
31 | */ | ||
32 | ENTRY(efi_stub_entry) | ||
33 | /* | ||
34 | * Create a stack frame to save FP/LR with extra space | ||
35 | * for image_addr variable passed to efi_entry(). | ||
36 | */ | ||
37 | stp x29, x30, [sp, #-32]! | ||
38 | |||
39 | /* | ||
40 | * Call efi_entry to do the real work. | ||
41 | * x0 and x1 are already set up by firmware. Current runtime | ||
42 | * address of image is calculated and passed via *image_addr. | ||
43 | * | ||
44 | * unsigned long efi_entry(void *handle, | ||
45 | * efi_system_table_t *sys_table, | ||
46 | * unsigned long *image_addr) ; | ||
47 | */ | ||
48 | adrp x8, _text | ||
49 | add x8, x8, #:lo12:_text | ||
50 | add x2, sp, 16 | ||
51 | str x8, [x2] | ||
52 | bl efi_entry | ||
53 | cmn x0, #1 | ||
54 | b.eq efi_load_fail | ||
55 | |||
56 | /* | ||
57 | * efi_entry() will have relocated the kernel image if necessary | ||
58 | * and we return here with device tree address in x0 and the kernel | ||
59 | * entry point stored at *image_addr. Save those values in registers | ||
60 | * which are callee preserved. | ||
61 | */ | ||
62 | mov x20, x0 // DTB address | ||
63 | ldr x0, [sp, #16] // relocated _text address | ||
64 | mov x21, x0 | ||
65 | |||
66 | /* | ||
67 | * Flush dcache covering current runtime addresses | ||
68 | * of kernel text/data. Then flush all of icache. | ||
69 | */ | ||
70 | adrp x1, _text | ||
71 | add x1, x1, #:lo12:_text | ||
72 | adrp x2, _edata | ||
73 | add x2, x2, #:lo12:_edata | ||
74 | sub x1, x2, x1 | ||
75 | |||
76 | bl __flush_dcache_area | ||
77 | ic ialluis | ||
78 | |||
79 | /* Turn off Dcache and MMU */ | ||
80 | mrs x0, CurrentEL | ||
81 | cmp x0, #PSR_MODE_EL2t | ||
82 | ccmp x0, #PSR_MODE_EL2h, #0x4, ne | ||
83 | b.ne 1f | ||
84 | mrs x0, sctlr_el2 | ||
85 | bic x0, x0, #1 << 0 // clear SCTLR.M | ||
86 | bic x0, x0, #1 << 2 // clear SCTLR.C | ||
87 | msr sctlr_el2, x0 | ||
88 | isb | ||
89 | b 2f | ||
90 | 1: | ||
91 | mrs x0, sctlr_el1 | ||
92 | bic x0, x0, #1 << 0 // clear SCTLR.M | ||
93 | bic x0, x0, #1 << 2 // clear SCTLR.C | ||
94 | msr sctlr_el1, x0 | ||
95 | isb | ||
96 | 2: | ||
97 | /* Jump to kernel entry point */ | ||
98 | mov x0, x20 | ||
99 | mov x1, xzr | ||
100 | mov x2, xzr | ||
101 | mov x3, xzr | ||
102 | br x21 | ||
103 | |||
104 | efi_load_fail: | ||
105 | mov x0, #EFI_LOAD_ERROR | ||
106 | ldp x29, x30, [sp], #32 | ||
107 | ret | ||
108 | |||
109 | ENDPROC(efi_stub_entry) | ||
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c new file mode 100644 index 000000000000..60e98a639ac5 --- /dev/null +++ b/arch/arm64/kernel/efi-stub.c | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org> | ||
3 | * | ||
4 | * This file implements the EFI boot stub for the arm64 kernel. | ||
5 | * Adapted from ARM version by Mark Salter <msalter@redhat.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 | */ | ||
12 | #include <linux/efi.h> | ||
13 | #include <linux/libfdt.h> | ||
14 | #include <asm/sections.h> | ||
15 | #include <generated/compile.h> | ||
16 | #include <generated/utsrelease.h> | ||
17 | |||
18 | /* | ||
19 | * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from | ||
20 | * start of kernel and may not cross a 2MiB boundary. We set alignment to | ||
21 | * 2MiB so we know it won't cross a 2MiB boundary. | ||
22 | */ | ||
23 | #define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */ | ||
24 | #define MAX_FDT_OFFSET SZ_512M | ||
25 | |||
26 | #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) | ||
27 | |||
28 | static void efi_char16_printk(efi_system_table_t *sys_table_arg, | ||
29 | efi_char16_t *str); | ||
30 | |||
31 | static efi_status_t efi_open_volume(efi_system_table_t *sys_table, | ||
32 | void *__image, void **__fh); | ||
33 | static efi_status_t efi_file_close(void *handle); | ||
34 | |||
35 | static efi_status_t | ||
36 | efi_file_read(void *handle, unsigned long *size, void *addr); | ||
37 | |||
38 | static efi_status_t | ||
39 | efi_file_size(efi_system_table_t *sys_table, void *__fh, | ||
40 | efi_char16_t *filename_16, void **handle, u64 *file_sz); | ||
41 | |||
42 | /* Include shared EFI stub code */ | ||
43 | #include "../../../drivers/firmware/efi/efi-stub-helper.c" | ||
44 | #include "../../../drivers/firmware/efi/fdt.c" | ||
45 | #include "../../../drivers/firmware/efi/arm-stub.c" | ||
46 | |||
47 | |||
48 | static efi_status_t handle_kernel_image(efi_system_table_t *sys_table, | ||
49 | unsigned long *image_addr, | ||
50 | unsigned long *image_size, | ||
51 | unsigned long *reserve_addr, | ||
52 | unsigned long *reserve_size, | ||
53 | unsigned long dram_base, | ||
54 | efi_loaded_image_t *image) | ||
55 | { | ||
56 | efi_status_t status; | ||
57 | unsigned long kernel_size, kernel_memsize = 0; | ||
58 | |||
59 | /* Relocate the image, if required. */ | ||
60 | kernel_size = _edata - _text; | ||
61 | if (*image_addr != (dram_base + TEXT_OFFSET)) { | ||
62 | kernel_memsize = kernel_size + (_end - _edata); | ||
63 | status = efi_relocate_kernel(sys_table, image_addr, | ||
64 | kernel_size, kernel_memsize, | ||
65 | dram_base + TEXT_OFFSET, | ||
66 | PAGE_SIZE); | ||
67 | if (status != EFI_SUCCESS) { | ||
68 | pr_efi_err(sys_table, "Failed to relocate kernel\n"); | ||
69 | return status; | ||
70 | } | ||
71 | if (*image_addr != (dram_base + TEXT_OFFSET)) { | ||
72 | pr_efi_err(sys_table, "Failed to alloc kernel memory\n"); | ||
73 | efi_free(sys_table, kernel_memsize, *image_addr); | ||
74 | return EFI_ERROR; | ||
75 | } | ||
76 | *image_size = kernel_memsize; | ||
77 | } | ||
78 | |||
79 | |||
80 | return EFI_SUCCESS; | ||
81 | } | ||
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c new file mode 100644 index 000000000000..14db1f6e8d7f --- /dev/null +++ b/arch/arm64/kernel/efi.c | |||
@@ -0,0 +1,469 @@ | |||
1 | /* | ||
2 | * Extensible Firmware Interface | ||
3 | * | ||
4 | * Based on Extensible Firmware Interface Specification version 2.4 | ||
5 | * | ||
6 | * Copyright (C) 2013, 2014 Linaro 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 | */ | ||
13 | |||
14 | #include <linux/efi.h> | ||
15 | #include <linux/export.h> | ||
16 | #include <linux/memblock.h> | ||
17 | #include <linux/bootmem.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_fdt.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include <asm/cacheflush.h> | ||
24 | #include <asm/efi.h> | ||
25 | #include <asm/tlbflush.h> | ||
26 | #include <asm/mmu_context.h> | ||
27 | |||
28 | struct efi_memory_map memmap; | ||
29 | |||
30 | static efi_runtime_services_t *runtime; | ||
31 | |||
32 | static u64 efi_system_table; | ||
33 | |||
34 | static int uefi_debug __initdata; | ||
35 | static int __init uefi_debug_setup(char *str) | ||
36 | { | ||
37 | uefi_debug = 1; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | early_param("uefi_debug", uefi_debug_setup); | ||
42 | |||
43 | static int __init is_normal_ram(efi_memory_desc_t *md) | ||
44 | { | ||
45 | if (md->attribute & EFI_MEMORY_WB) | ||
46 | return 1; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static void __init efi_setup_idmap(void) | ||
51 | { | ||
52 | struct memblock_region *r; | ||
53 | efi_memory_desc_t *md; | ||
54 | u64 paddr, npages, size; | ||
55 | |||
56 | for_each_memblock(memory, r) | ||
57 | create_id_mapping(r->base, r->size, 0); | ||
58 | |||
59 | /* map runtime io spaces */ | ||
60 | for_each_efi_memory_desc(&memmap, md) { | ||
61 | if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md)) | ||
62 | continue; | ||
63 | paddr = md->phys_addr; | ||
64 | npages = md->num_pages; | ||
65 | memrange_efi_to_native(&paddr, &npages); | ||
66 | size = npages << PAGE_SHIFT; | ||
67 | create_id_mapping(paddr, size, 1); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static int __init uefi_init(void) | ||
72 | { | ||
73 | efi_char16_t *c16; | ||
74 | char vendor[100] = "unknown"; | ||
75 | int i, retval; | ||
76 | |||
77 | efi.systab = early_memremap(efi_system_table, | ||
78 | sizeof(efi_system_table_t)); | ||
79 | if (efi.systab == NULL) { | ||
80 | pr_warn("Unable to map EFI system table.\n"); | ||
81 | return -ENOMEM; | ||
82 | } | ||
83 | |||
84 | set_bit(EFI_BOOT, &efi.flags); | ||
85 | set_bit(EFI_64BIT, &efi.flags); | ||
86 | |||
87 | /* | ||
88 | * Verify the EFI Table | ||
89 | */ | ||
90 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { | ||
91 | pr_err("System table signature incorrect\n"); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | if ((efi.systab->hdr.revision >> 16) < 2) | ||
95 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", | ||
96 | efi.systab->hdr.revision >> 16, | ||
97 | efi.systab->hdr.revision & 0xffff); | ||
98 | |||
99 | /* Show what we know for posterity */ | ||
100 | c16 = early_memremap(efi.systab->fw_vendor, | ||
101 | sizeof(vendor)); | ||
102 | if (c16) { | ||
103 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) | ||
104 | vendor[i] = c16[i]; | ||
105 | vendor[i] = '\0'; | ||
106 | } | ||
107 | |||
108 | pr_info("EFI v%u.%.02u by %s\n", | ||
109 | efi.systab->hdr.revision >> 16, | ||
110 | efi.systab->hdr.revision & 0xffff, vendor); | ||
111 | |||
112 | retval = efi_config_init(NULL); | ||
113 | if (retval == 0) | ||
114 | set_bit(EFI_CONFIG_TABLES, &efi.flags); | ||
115 | |||
116 | early_memunmap(c16, sizeof(vendor)); | ||
117 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); | ||
118 | |||
119 | return retval; | ||
120 | } | ||
121 | |||
122 | static __initdata char memory_type_name[][32] = { | ||
123 | {"Reserved"}, | ||
124 | {"Loader Code"}, | ||
125 | {"Loader Data"}, | ||
126 | {"Boot Code"}, | ||
127 | {"Boot Data"}, | ||
128 | {"Runtime Code"}, | ||
129 | {"Runtime Data"}, | ||
130 | {"Conventional Memory"}, | ||
131 | {"Unusable Memory"}, | ||
132 | {"ACPI Reclaim Memory"}, | ||
133 | {"ACPI Memory NVS"}, | ||
134 | {"Memory Mapped I/O"}, | ||
135 | {"MMIO Port Space"}, | ||
136 | {"PAL Code"}, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Return true for RAM regions we want to permanently reserve. | ||
141 | */ | ||
142 | static __init int is_reserve_region(efi_memory_desc_t *md) | ||
143 | { | ||
144 | if (!is_normal_ram(md)) | ||
145 | return 0; | ||
146 | |||
147 | if (md->attribute & EFI_MEMORY_RUNTIME) | ||
148 | return 1; | ||
149 | |||
150 | if (md->type == EFI_ACPI_RECLAIM_MEMORY || | ||
151 | md->type == EFI_RESERVED_TYPE) | ||
152 | return 1; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static __init void reserve_regions(void) | ||
158 | { | ||
159 | efi_memory_desc_t *md; | ||
160 | u64 paddr, npages, size; | ||
161 | |||
162 | if (uefi_debug) | ||
163 | pr_info("Processing EFI memory map:\n"); | ||
164 | |||
165 | for_each_efi_memory_desc(&memmap, md) { | ||
166 | paddr = md->phys_addr; | ||
167 | npages = md->num_pages; | ||
168 | |||
169 | if (uefi_debug) | ||
170 | pr_info(" 0x%012llx-0x%012llx [%s]", | ||
171 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, | ||
172 | memory_type_name[md->type]); | ||
173 | |||
174 | memrange_efi_to_native(&paddr, &npages); | ||
175 | size = npages << PAGE_SHIFT; | ||
176 | |||
177 | if (is_normal_ram(md)) | ||
178 | early_init_dt_add_memory_arch(paddr, size); | ||
179 | |||
180 | if (is_reserve_region(md) || | ||
181 | md->type == EFI_BOOT_SERVICES_CODE || | ||
182 | md->type == EFI_BOOT_SERVICES_DATA) { | ||
183 | memblock_reserve(paddr, size); | ||
184 | if (uefi_debug) | ||
185 | pr_cont("*"); | ||
186 | } | ||
187 | |||
188 | if (uefi_debug) | ||
189 | pr_cont("\n"); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | |||
194 | static u64 __init free_one_region(u64 start, u64 end) | ||
195 | { | ||
196 | u64 size = end - start; | ||
197 | |||
198 | if (uefi_debug) | ||
199 | pr_info(" EFI freeing: 0x%012llx-0x%012llx\n", start, end - 1); | ||
200 | |||
201 | free_bootmem_late(start, size); | ||
202 | return size; | ||
203 | } | ||
204 | |||
205 | static u64 __init free_region(u64 start, u64 end) | ||
206 | { | ||
207 | u64 map_start, map_end, total = 0; | ||
208 | |||
209 | if (end <= start) | ||
210 | return total; | ||
211 | |||
212 | map_start = (u64)memmap.phys_map; | ||
213 | map_end = PAGE_ALIGN(map_start + (memmap.map_end - memmap.map)); | ||
214 | map_start &= PAGE_MASK; | ||
215 | |||
216 | if (start < map_end && end > map_start) { | ||
217 | /* region overlaps UEFI memmap */ | ||
218 | if (start < map_start) | ||
219 | total += free_one_region(start, map_start); | ||
220 | |||
221 | if (map_end < end) | ||
222 | total += free_one_region(map_end, end); | ||
223 | } else | ||
224 | total += free_one_region(start, end); | ||
225 | |||
226 | return total; | ||
227 | } | ||
228 | |||
229 | static void __init free_boot_services(void) | ||
230 | { | ||
231 | u64 total_freed = 0; | ||
232 | u64 keep_end, free_start, free_end; | ||
233 | efi_memory_desc_t *md; | ||
234 | |||
235 | /* | ||
236 | * If kernel uses larger pages than UEFI, we have to be careful | ||
237 | * not to inadvertantly free memory we want to keep if there is | ||
238 | * overlap at the kernel page size alignment. We do not want to | ||
239 | * free is_reserve_region() memory nor the UEFI memmap itself. | ||
240 | * | ||
241 | * The memory map is sorted, so we keep track of the end of | ||
242 | * any previous region we want to keep, remember any region | ||
243 | * we want to free and defer freeing it until we encounter | ||
244 | * the next region we want to keep. This way, before freeing | ||
245 | * it, we can clip it as needed to avoid freeing memory we | ||
246 | * want to keep for UEFI. | ||
247 | */ | ||
248 | |||
249 | keep_end = 0; | ||
250 | free_start = 0; | ||
251 | |||
252 | for_each_efi_memory_desc(&memmap, md) { | ||
253 | u64 paddr, npages, size; | ||
254 | |||
255 | if (is_reserve_region(md)) { | ||
256 | /* | ||
257 | * We don't want to free any memory from this region. | ||
258 | */ | ||
259 | if (free_start) { | ||
260 | /* adjust free_end then free region */ | ||
261 | if (free_end > md->phys_addr) | ||
262 | free_end -= PAGE_SIZE; | ||
263 | total_freed += free_region(free_start, free_end); | ||
264 | free_start = 0; | ||
265 | } | ||
266 | keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); | ||
267 | continue; | ||
268 | } | ||
269 | |||
270 | if (md->type != EFI_BOOT_SERVICES_CODE && | ||
271 | md->type != EFI_BOOT_SERVICES_DATA) { | ||
272 | /* no need to free this region */ | ||
273 | continue; | ||
274 | } | ||
275 | |||
276 | /* | ||
277 | * We want to free memory from this region. | ||
278 | */ | ||
279 | paddr = md->phys_addr; | ||
280 | npages = md->num_pages; | ||
281 | memrange_efi_to_native(&paddr, &npages); | ||
282 | size = npages << PAGE_SHIFT; | ||
283 | |||
284 | if (free_start) { | ||
285 | if (paddr <= free_end) | ||
286 | free_end = paddr + size; | ||
287 | else { | ||
288 | total_freed += free_region(free_start, free_end); | ||
289 | free_start = paddr; | ||
290 | free_end = paddr + size; | ||
291 | } | ||
292 | } else { | ||
293 | free_start = paddr; | ||
294 | free_end = paddr + size; | ||
295 | } | ||
296 | if (free_start < keep_end) { | ||
297 | free_start += PAGE_SIZE; | ||
298 | if (free_start >= free_end) | ||
299 | free_start = 0; | ||
300 | } | ||
301 | } | ||
302 | if (free_start) | ||
303 | total_freed += free_region(free_start, free_end); | ||
304 | |||
305 | if (total_freed) | ||
306 | pr_info("Freed 0x%llx bytes of EFI boot services memory", | ||
307 | total_freed); | ||
308 | } | ||
309 | |||
310 | void __init efi_init(void) | ||
311 | { | ||
312 | struct efi_fdt_params params; | ||
313 | |||
314 | /* Grab UEFI information placed in FDT by stub */ | ||
315 | if (!efi_get_fdt_params(¶ms, uefi_debug)) | ||
316 | return; | ||
317 | |||
318 | efi_system_table = params.system_table; | ||
319 | |||
320 | memblock_reserve(params.mmap & PAGE_MASK, | ||
321 | PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); | ||
322 | memmap.phys_map = (void *)params.mmap; | ||
323 | memmap.map = early_memremap(params.mmap, params.mmap_size); | ||
324 | memmap.map_end = memmap.map + params.mmap_size; | ||
325 | memmap.desc_size = params.desc_size; | ||
326 | memmap.desc_version = params.desc_ver; | ||
327 | |||
328 | if (uefi_init() < 0) | ||
329 | return; | ||
330 | |||
331 | reserve_regions(); | ||
332 | } | ||
333 | |||
334 | void __init efi_idmap_init(void) | ||
335 | { | ||
336 | if (!efi_enabled(EFI_BOOT)) | ||
337 | return; | ||
338 | |||
339 | /* boot time idmap_pg_dir is incomplete, so fill in missing parts */ | ||
340 | efi_setup_idmap(); | ||
341 | } | ||
342 | |||
343 | static int __init remap_region(efi_memory_desc_t *md, void **new) | ||
344 | { | ||
345 | u64 paddr, vaddr, npages, size; | ||
346 | |||
347 | paddr = md->phys_addr; | ||
348 | npages = md->num_pages; | ||
349 | memrange_efi_to_native(&paddr, &npages); | ||
350 | size = npages << PAGE_SHIFT; | ||
351 | |||
352 | if (is_normal_ram(md)) | ||
353 | vaddr = (__force u64)ioremap_cache(paddr, size); | ||
354 | else | ||
355 | vaddr = (__force u64)ioremap(paddr, size); | ||
356 | |||
357 | if (!vaddr) { | ||
358 | pr_err("Unable to remap 0x%llx pages @ %p\n", | ||
359 | npages, (void *)paddr); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | /* adjust for any rounding when EFI and system pagesize differs */ | ||
364 | md->virt_addr = vaddr + (md->phys_addr - paddr); | ||
365 | |||
366 | if (uefi_debug) | ||
367 | pr_info(" EFI remap 0x%012llx => %p\n", | ||
368 | md->phys_addr, (void *)md->virt_addr); | ||
369 | |||
370 | memcpy(*new, md, memmap.desc_size); | ||
371 | *new += memmap.desc_size; | ||
372 | |||
373 | return 1; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Switch UEFI from an identity map to a kernel virtual map | ||
378 | */ | ||
379 | static int __init arm64_enter_virtual_mode(void) | ||
380 | { | ||
381 | efi_memory_desc_t *md; | ||
382 | phys_addr_t virtmap_phys; | ||
383 | void *virtmap, *virt_md; | ||
384 | efi_status_t status; | ||
385 | u64 mapsize; | ||
386 | int count = 0; | ||
387 | unsigned long flags; | ||
388 | |||
389 | if (!efi_enabled(EFI_BOOT)) { | ||
390 | pr_info("EFI services will not be available.\n"); | ||
391 | return -1; | ||
392 | } | ||
393 | |||
394 | pr_info("Remapping and enabling EFI services.\n"); | ||
395 | |||
396 | /* replace early memmap mapping with permanent mapping */ | ||
397 | mapsize = memmap.map_end - memmap.map; | ||
398 | early_memunmap(memmap.map, mapsize); | ||
399 | memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, | ||
400 | mapsize); | ||
401 | memmap.map_end = memmap.map + mapsize; | ||
402 | |||
403 | efi.memmap = &memmap; | ||
404 | |||
405 | /* Map the runtime regions */ | ||
406 | virtmap = kmalloc(mapsize, GFP_KERNEL); | ||
407 | if (!virtmap) { | ||
408 | pr_err("Failed to allocate EFI virtual memmap\n"); | ||
409 | return -1; | ||
410 | } | ||
411 | virtmap_phys = virt_to_phys(virtmap); | ||
412 | virt_md = virtmap; | ||
413 | |||
414 | for_each_efi_memory_desc(&memmap, md) { | ||
415 | if (!(md->attribute & EFI_MEMORY_RUNTIME)) | ||
416 | continue; | ||
417 | if (remap_region(md, &virt_md)) | ||
418 | ++count; | ||
419 | } | ||
420 | |||
421 | efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table); | ||
422 | if (efi.systab) | ||
423 | set_bit(EFI_SYSTEM_TABLES, &efi.flags); | ||
424 | |||
425 | local_irq_save(flags); | ||
426 | cpu_switch_mm(idmap_pg_dir, &init_mm); | ||
427 | |||
428 | /* Call SetVirtualAddressMap with the physical address of the map */ | ||
429 | runtime = efi.systab->runtime; | ||
430 | efi.set_virtual_address_map = runtime->set_virtual_address_map; | ||
431 | |||
432 | status = efi.set_virtual_address_map(count * memmap.desc_size, | ||
433 | memmap.desc_size, | ||
434 | memmap.desc_version, | ||
435 | (efi_memory_desc_t *)virtmap_phys); | ||
436 | cpu_set_reserved_ttbr0(); | ||
437 | flush_tlb_all(); | ||
438 | local_irq_restore(flags); | ||
439 | |||
440 | kfree(virtmap); | ||
441 | |||
442 | free_boot_services(); | ||
443 | |||
444 | if (status != EFI_SUCCESS) { | ||
445 | pr_err("Failed to set EFI virtual address map! [%lx]\n", | ||
446 | status); | ||
447 | return -1; | ||
448 | } | ||
449 | |||
450 | /* Set up runtime services function pointers */ | ||
451 | runtime = efi.systab->runtime; | ||
452 | efi.get_time = runtime->get_time; | ||
453 | efi.set_time = runtime->set_time; | ||
454 | efi.get_wakeup_time = runtime->get_wakeup_time; | ||
455 | efi.set_wakeup_time = runtime->set_wakeup_time; | ||
456 | efi.get_variable = runtime->get_variable; | ||
457 | efi.get_next_variable = runtime->get_next_variable; | ||
458 | efi.set_variable = runtime->set_variable; | ||
459 | efi.query_variable_info = runtime->query_variable_info; | ||
460 | efi.update_capsule = runtime->update_capsule; | ||
461 | efi.query_capsule_caps = runtime->query_capsule_caps; | ||
462 | efi.get_next_high_mono_count = runtime->get_next_high_mono_count; | ||
463 | efi.reset_system = runtime->reset_system; | ||
464 | |||
465 | set_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | early_initcall(arm64_enter_virtual_mode); | ||
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 0fd565000772..738291b5be29 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S | |||
@@ -108,8 +108,18 @@ | |||
108 | /* | 108 | /* |
109 | * DO NOT MODIFY. Image header expected by Linux boot-loaders. | 109 | * DO NOT MODIFY. Image header expected by Linux boot-loaders. |
110 | */ | 110 | */ |
111 | #ifdef CONFIG_EFI | ||
112 | efi_head: | ||
113 | /* | ||
114 | * This add instruction has no meaningful effect except that | ||
115 | * its opcode forms the magic "MZ" signature required by UEFI. | ||
116 | */ | ||
117 | add x13, x18, #0x16 | ||
118 | b stext | ||
119 | #else | ||
111 | b stext // branch to kernel start, magic | 120 | b stext // branch to kernel start, magic |
112 | .long 0 // reserved | 121 | .long 0 // reserved |
122 | #endif | ||
113 | .quad TEXT_OFFSET // Image load offset from start of RAM | 123 | .quad TEXT_OFFSET // Image load offset from start of RAM |
114 | .quad 0 // reserved | 124 | .quad 0 // reserved |
115 | .quad 0 // reserved | 125 | .quad 0 // reserved |
@@ -120,7 +130,109 @@ | |||
120 | .byte 0x52 | 130 | .byte 0x52 |
121 | .byte 0x4d | 131 | .byte 0x4d |
122 | .byte 0x64 | 132 | .byte 0x64 |
133 | #ifdef CONFIG_EFI | ||
134 | .long pe_header - efi_head // Offset to the PE header. | ||
135 | #else | ||
123 | .word 0 // reserved | 136 | .word 0 // reserved |
137 | #endif | ||
138 | |||
139 | #ifdef CONFIG_EFI | ||
140 | .align 3 | ||
141 | pe_header: | ||
142 | .ascii "PE" | ||
143 | .short 0 | ||
144 | coff_header: | ||
145 | .short 0xaa64 // AArch64 | ||
146 | .short 2 // nr_sections | ||
147 | .long 0 // TimeDateStamp | ||
148 | .long 0 // PointerToSymbolTable | ||
149 | .long 1 // NumberOfSymbols | ||
150 | .short section_table - optional_header // SizeOfOptionalHeader | ||
151 | .short 0x206 // Characteristics. | ||
152 | // IMAGE_FILE_DEBUG_STRIPPED | | ||
153 | // IMAGE_FILE_EXECUTABLE_IMAGE | | ||
154 | // IMAGE_FILE_LINE_NUMS_STRIPPED | ||
155 | optional_header: | ||
156 | .short 0x20b // PE32+ format | ||
157 | .byte 0x02 // MajorLinkerVersion | ||
158 | .byte 0x14 // MinorLinkerVersion | ||
159 | .long _edata - stext // SizeOfCode | ||
160 | .long 0 // SizeOfInitializedData | ||
161 | .long 0 // SizeOfUninitializedData | ||
162 | .long efi_stub_entry - efi_head // AddressOfEntryPoint | ||
163 | .long stext - efi_head // BaseOfCode | ||
164 | |||
165 | extra_header_fields: | ||
166 | .quad 0 // ImageBase | ||
167 | .long 0x20 // SectionAlignment | ||
168 | .long 0x8 // FileAlignment | ||
169 | .short 0 // MajorOperatingSystemVersion | ||
170 | .short 0 // MinorOperatingSystemVersion | ||
171 | .short 0 // MajorImageVersion | ||
172 | .short 0 // MinorImageVersion | ||
173 | .short 0 // MajorSubsystemVersion | ||
174 | .short 0 // MinorSubsystemVersion | ||
175 | .long 0 // Win32VersionValue | ||
176 | |||
177 | .long _edata - efi_head // SizeOfImage | ||
178 | |||
179 | // Everything before the kernel image is considered part of the header | ||
180 | .long stext - efi_head // SizeOfHeaders | ||
181 | .long 0 // CheckSum | ||
182 | .short 0xa // Subsystem (EFI application) | ||
183 | .short 0 // DllCharacteristics | ||
184 | .quad 0 // SizeOfStackReserve | ||
185 | .quad 0 // SizeOfStackCommit | ||
186 | .quad 0 // SizeOfHeapReserve | ||
187 | .quad 0 // SizeOfHeapCommit | ||
188 | .long 0 // LoaderFlags | ||
189 | .long 0x6 // NumberOfRvaAndSizes | ||
190 | |||
191 | .quad 0 // ExportTable | ||
192 | .quad 0 // ImportTable | ||
193 | .quad 0 // ResourceTable | ||
194 | .quad 0 // ExceptionTable | ||
195 | .quad 0 // CertificationTable | ||
196 | .quad 0 // BaseRelocationTable | ||
197 | |||
198 | // Section table | ||
199 | section_table: | ||
200 | |||
201 | /* | ||
202 | * The EFI application loader requires a relocation section | ||
203 | * because EFI applications must be relocatable. This is a | ||
204 | * dummy section as far as we are concerned. | ||
205 | */ | ||
206 | .ascii ".reloc" | ||
207 | .byte 0 | ||
208 | .byte 0 // end of 0 padding of section name | ||
209 | .long 0 | ||
210 | .long 0 | ||
211 | .long 0 // SizeOfRawData | ||
212 | .long 0 // PointerToRawData | ||
213 | .long 0 // PointerToRelocations | ||
214 | .long 0 // PointerToLineNumbers | ||
215 | .short 0 // NumberOfRelocations | ||
216 | .short 0 // NumberOfLineNumbers | ||
217 | .long 0x42100040 // Characteristics (section flags) | ||
218 | |||
219 | |||
220 | .ascii ".text" | ||
221 | .byte 0 | ||
222 | .byte 0 | ||
223 | .byte 0 // end of 0 padding of section name | ||
224 | .long _edata - stext // VirtualSize | ||
225 | .long stext - efi_head // VirtualAddress | ||
226 | .long _edata - stext // SizeOfRawData | ||
227 | .long stext - efi_head // PointerToRawData | ||
228 | |||
229 | .long 0 // PointerToRelocations (0 for executables) | ||
230 | .long 0 // PointerToLineNumbers (0 for executables) | ||
231 | .short 0 // NumberOfRelocations (0 for executables) | ||
232 | .short 0 // NumberOfLineNumbers (0 for executables) | ||
233 | .long 0xe0500020 // Characteristics (section flags) | ||
234 | .align 5 | ||
235 | #endif | ||
124 | 236 | ||
125 | ENTRY(stext) | 237 | ENTRY(stext) |
126 | mov x21, x0 // x21=FDT | 238 | mov x21, x0 // x21=FDT |
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index ea4828a4aa96..9e9798f91172 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c | |||
@@ -18,12 +18,17 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
21 | #include <linux/reboot.h> | ||
22 | #include <linux/pm.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <uapi/linux/psci.h> | ||
21 | 25 | ||
22 | #include <asm/compiler.h> | 26 | #include <asm/compiler.h> |
23 | #include <asm/cpu_ops.h> | 27 | #include <asm/cpu_ops.h> |
24 | #include <asm/errno.h> | 28 | #include <asm/errno.h> |
25 | #include <asm/psci.h> | 29 | #include <asm/psci.h> |
26 | #include <asm/smp_plat.h> | 30 | #include <asm/smp_plat.h> |
31 | #include <asm/system_misc.h> | ||
27 | 32 | ||
28 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 | 33 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 |
29 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 | 34 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 |
@@ -40,58 +45,52 @@ struct psci_operations { | |||
40 | int (*cpu_off)(struct psci_power_state state); | 45 | int (*cpu_off)(struct psci_power_state state); |
41 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); | 46 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); |
42 | int (*migrate)(unsigned long cpuid); | 47 | int (*migrate)(unsigned long cpuid); |
48 | int (*affinity_info)(unsigned long target_affinity, | ||
49 | unsigned long lowest_affinity_level); | ||
50 | int (*migrate_info_type)(void); | ||
43 | }; | 51 | }; |
44 | 52 | ||
45 | static struct psci_operations psci_ops; | 53 | static struct psci_operations psci_ops; |
46 | 54 | ||
47 | static int (*invoke_psci_fn)(u64, u64, u64, u64); | 55 | static int (*invoke_psci_fn)(u64, u64, u64, u64); |
56 | typedef int (*psci_initcall_t)(const struct device_node *); | ||
48 | 57 | ||
49 | enum psci_function { | 58 | enum psci_function { |
50 | PSCI_FN_CPU_SUSPEND, | 59 | PSCI_FN_CPU_SUSPEND, |
51 | PSCI_FN_CPU_ON, | 60 | PSCI_FN_CPU_ON, |
52 | PSCI_FN_CPU_OFF, | 61 | PSCI_FN_CPU_OFF, |
53 | PSCI_FN_MIGRATE, | 62 | PSCI_FN_MIGRATE, |
63 | PSCI_FN_AFFINITY_INFO, | ||
64 | PSCI_FN_MIGRATE_INFO_TYPE, | ||
54 | PSCI_FN_MAX, | 65 | PSCI_FN_MAX, |
55 | }; | 66 | }; |
56 | 67 | ||
57 | static u32 psci_function_id[PSCI_FN_MAX]; | 68 | static u32 psci_function_id[PSCI_FN_MAX]; |
58 | 69 | ||
59 | #define PSCI_RET_SUCCESS 0 | ||
60 | #define PSCI_RET_EOPNOTSUPP -1 | ||
61 | #define PSCI_RET_EINVAL -2 | ||
62 | #define PSCI_RET_EPERM -3 | ||
63 | |||
64 | static int psci_to_linux_errno(int errno) | 70 | static int psci_to_linux_errno(int errno) |
65 | { | 71 | { |
66 | switch (errno) { | 72 | switch (errno) { |
67 | case PSCI_RET_SUCCESS: | 73 | case PSCI_RET_SUCCESS: |
68 | return 0; | 74 | return 0; |
69 | case PSCI_RET_EOPNOTSUPP: | 75 | case PSCI_RET_NOT_SUPPORTED: |
70 | return -EOPNOTSUPP; | 76 | return -EOPNOTSUPP; |
71 | case PSCI_RET_EINVAL: | 77 | case PSCI_RET_INVALID_PARAMS: |
72 | return -EINVAL; | 78 | return -EINVAL; |
73 | case PSCI_RET_EPERM: | 79 | case PSCI_RET_DENIED: |
74 | return -EPERM; | 80 | return -EPERM; |
75 | }; | 81 | }; |
76 | 82 | ||
77 | return -EINVAL; | 83 | return -EINVAL; |
78 | } | 84 | } |
79 | 85 | ||
80 | #define PSCI_POWER_STATE_ID_MASK 0xffff | ||
81 | #define PSCI_POWER_STATE_ID_SHIFT 0 | ||
82 | #define PSCI_POWER_STATE_TYPE_MASK 0x1 | ||
83 | #define PSCI_POWER_STATE_TYPE_SHIFT 16 | ||
84 | #define PSCI_POWER_STATE_AFFL_MASK 0x3 | ||
85 | #define PSCI_POWER_STATE_AFFL_SHIFT 24 | ||
86 | |||
87 | static u32 psci_power_state_pack(struct psci_power_state state) | 86 | static u32 psci_power_state_pack(struct psci_power_state state) |
88 | { | 87 | { |
89 | return ((state.id & PSCI_POWER_STATE_ID_MASK) | 88 | return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT) |
90 | << PSCI_POWER_STATE_ID_SHIFT) | | 89 | & PSCI_0_2_POWER_STATE_ID_MASK) | |
91 | ((state.type & PSCI_POWER_STATE_TYPE_MASK) | 90 | ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT) |
92 | << PSCI_POWER_STATE_TYPE_SHIFT) | | 91 | & PSCI_0_2_POWER_STATE_TYPE_MASK) | |
93 | ((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK) | 92 | ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
94 | << PSCI_POWER_STATE_AFFL_SHIFT); | 93 | & PSCI_0_2_POWER_STATE_AFFL_MASK); |
95 | } | 94 | } |
96 | 95 | ||
97 | /* | 96 | /* |
@@ -128,6 +127,14 @@ static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, | |||
128 | return function_id; | 127 | return function_id; |
129 | } | 128 | } |
130 | 129 | ||
130 | static int psci_get_version(void) | ||
131 | { | ||
132 | int err; | ||
133 | |||
134 | err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); | ||
135 | return err; | ||
136 | } | ||
137 | |||
131 | static int psci_cpu_suspend(struct psci_power_state state, | 138 | static int psci_cpu_suspend(struct psci_power_state state, |
132 | unsigned long entry_point) | 139 | unsigned long entry_point) |
133 | { | 140 | { |
@@ -171,26 +178,36 @@ static int psci_migrate(unsigned long cpuid) | |||
171 | return psci_to_linux_errno(err); | 178 | return psci_to_linux_errno(err); |
172 | } | 179 | } |
173 | 180 | ||
174 | static const struct of_device_id psci_of_match[] __initconst = { | 181 | static int psci_affinity_info(unsigned long target_affinity, |
175 | { .compatible = "arm,psci", }, | 182 | unsigned long lowest_affinity_level) |
176 | {}, | 183 | { |
177 | }; | 184 | int err; |
185 | u32 fn; | ||
186 | |||
187 | fn = psci_function_id[PSCI_FN_AFFINITY_INFO]; | ||
188 | err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0); | ||
189 | return err; | ||
190 | } | ||
178 | 191 | ||
179 | void __init psci_init(void) | 192 | static int psci_migrate_info_type(void) |
180 | { | 193 | { |
181 | struct device_node *np; | 194 | int err; |
182 | const char *method; | 195 | u32 fn; |
183 | u32 id; | ||
184 | 196 | ||
185 | np = of_find_matching_node(NULL, psci_of_match); | 197 | fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE]; |
186 | if (!np) | 198 | err = invoke_psci_fn(fn, 0, 0, 0); |
187 | return; | 199 | return err; |
200 | } | ||
188 | 201 | ||
189 | pr_info("probing function IDs from device-tree\n"); | 202 | static int get_set_conduit_method(struct device_node *np) |
203 | { | ||
204 | const char *method; | ||
205 | |||
206 | pr_info("probing for conduit method from DT.\n"); | ||
190 | 207 | ||
191 | if (of_property_read_string(np, "method", &method)) { | 208 | if (of_property_read_string(np, "method", &method)) { |
192 | pr_warning("missing \"method\" property\n"); | 209 | pr_warn("missing \"method\" property\n"); |
193 | goto out_put_node; | 210 | return -ENXIO; |
194 | } | 211 | } |
195 | 212 | ||
196 | if (!strcmp("hvc", method)) { | 213 | if (!strcmp("hvc", method)) { |
@@ -198,10 +215,99 @@ void __init psci_init(void) | |||
198 | } else if (!strcmp("smc", method)) { | 215 | } else if (!strcmp("smc", method)) { |
199 | invoke_psci_fn = __invoke_psci_fn_smc; | 216 | invoke_psci_fn = __invoke_psci_fn_smc; |
200 | } else { | 217 | } else { |
201 | pr_warning("invalid \"method\" property: %s\n", method); | 218 | pr_warn("invalid \"method\" property: %s\n", method); |
219 | return -EINVAL; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) | ||
225 | { | ||
226 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); | ||
227 | } | ||
228 | |||
229 | static void psci_sys_poweroff(void) | ||
230 | { | ||
231 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * PSCI Function IDs for v0.2+ are well defined so use | ||
236 | * standard values. | ||
237 | */ | ||
238 | static int psci_0_2_init(struct device_node *np) | ||
239 | { | ||
240 | int err, ver; | ||
241 | |||
242 | err = get_set_conduit_method(np); | ||
243 | |||
244 | if (err) | ||
245 | goto out_put_node; | ||
246 | |||
247 | ver = psci_get_version(); | ||
248 | |||
249 | if (ver == PSCI_RET_NOT_SUPPORTED) { | ||
250 | /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ | ||
251 | pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); | ||
252 | err = -EOPNOTSUPP; | ||
202 | goto out_put_node; | 253 | goto out_put_node; |
254 | } else { | ||
255 | pr_info("PSCIv%d.%d detected in firmware.\n", | ||
256 | PSCI_VERSION_MAJOR(ver), | ||
257 | PSCI_VERSION_MINOR(ver)); | ||
258 | |||
259 | if (PSCI_VERSION_MAJOR(ver) == 0 && | ||
260 | PSCI_VERSION_MINOR(ver) < 2) { | ||
261 | err = -EINVAL; | ||
262 | pr_err("Conflicting PSCI version detected.\n"); | ||
263 | goto out_put_node; | ||
264 | } | ||
203 | } | 265 | } |
204 | 266 | ||
267 | pr_info("Using standard PSCI v0.2 function IDs\n"); | ||
268 | psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; | ||
269 | psci_ops.cpu_suspend = psci_cpu_suspend; | ||
270 | |||
271 | psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; | ||
272 | psci_ops.cpu_off = psci_cpu_off; | ||
273 | |||
274 | psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; | ||
275 | psci_ops.cpu_on = psci_cpu_on; | ||
276 | |||
277 | psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; | ||
278 | psci_ops.migrate = psci_migrate; | ||
279 | |||
280 | psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO; | ||
281 | psci_ops.affinity_info = psci_affinity_info; | ||
282 | |||
283 | psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = | ||
284 | PSCI_0_2_FN_MIGRATE_INFO_TYPE; | ||
285 | psci_ops.migrate_info_type = psci_migrate_info_type; | ||
286 | |||
287 | arm_pm_restart = psci_sys_reset; | ||
288 | |||
289 | pm_power_off = psci_sys_poweroff; | ||
290 | |||
291 | out_put_node: | ||
292 | of_node_put(np); | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * PSCI < v0.2 get PSCI Function IDs via DT. | ||
298 | */ | ||
299 | static int psci_0_1_init(struct device_node *np) | ||
300 | { | ||
301 | u32 id; | ||
302 | int err; | ||
303 | |||
304 | err = get_set_conduit_method(np); | ||
305 | |||
306 | if (err) | ||
307 | goto out_put_node; | ||
308 | |||
309 | pr_info("Using PSCI v0.1 Function IDs from DT\n"); | ||
310 | |||
205 | if (!of_property_read_u32(np, "cpu_suspend", &id)) { | 311 | if (!of_property_read_u32(np, "cpu_suspend", &id)) { |
206 | psci_function_id[PSCI_FN_CPU_SUSPEND] = id; | 312 | psci_function_id[PSCI_FN_CPU_SUSPEND] = id; |
207 | psci_ops.cpu_suspend = psci_cpu_suspend; | 313 | psci_ops.cpu_suspend = psci_cpu_suspend; |
@@ -224,7 +330,28 @@ void __init psci_init(void) | |||
224 | 330 | ||
225 | out_put_node: | 331 | out_put_node: |
226 | of_node_put(np); | 332 | of_node_put(np); |
227 | return; | 333 | return err; |
334 | } | ||
335 | |||
336 | static const struct of_device_id psci_of_match[] __initconst = { | ||
337 | { .compatible = "arm,psci", .data = psci_0_1_init}, | ||
338 | { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, | ||
339 | {}, | ||
340 | }; | ||
341 | |||
342 | int __init psci_init(void) | ||
343 | { | ||
344 | struct device_node *np; | ||
345 | const struct of_device_id *matched_np; | ||
346 | psci_initcall_t init_fn; | ||
347 | |||
348 | np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); | ||
349 | |||
350 | if (!np) | ||
351 | return -ENODEV; | ||
352 | |||
353 | init_fn = (psci_initcall_t)matched_np->data; | ||
354 | return init_fn(np); | ||
228 | } | 355 | } |
229 | 356 | ||
230 | #ifdef CONFIG_SMP | 357 | #ifdef CONFIG_SMP |
@@ -277,6 +404,35 @@ static void cpu_psci_cpu_die(unsigned int cpu) | |||
277 | 404 | ||
278 | pr_crit("unable to power off CPU%u (%d)\n", cpu, ret); | 405 | pr_crit("unable to power off CPU%u (%d)\n", cpu, ret); |
279 | } | 406 | } |
407 | |||
408 | static int cpu_psci_cpu_kill(unsigned int cpu) | ||
409 | { | ||
410 | int err, i; | ||
411 | |||
412 | if (!psci_ops.affinity_info) | ||
413 | return 1; | ||
414 | /* | ||
415 | * cpu_kill could race with cpu_die and we can | ||
416 | * potentially end up declaring this cpu undead | ||
417 | * while it is dying. So, try again a few times. | ||
418 | */ | ||
419 | |||
420 | for (i = 0; i < 10; i++) { | ||
421 | err = psci_ops.affinity_info(cpu_logical_map(cpu), 0); | ||
422 | if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) { | ||
423 | pr_info("CPU%d killed.\n", cpu); | ||
424 | return 1; | ||
425 | } | ||
426 | |||
427 | msleep(10); | ||
428 | pr_info("Retrying again to check for CPU kill\n"); | ||
429 | } | ||
430 | |||
431 | pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n", | ||
432 | cpu, err); | ||
433 | /* Make op_cpu_kill() fail. */ | ||
434 | return 0; | ||
435 | } | ||
280 | #endif | 436 | #endif |
281 | 437 | ||
282 | const struct cpu_operations cpu_psci_ops = { | 438 | const struct cpu_operations cpu_psci_ops = { |
@@ -287,6 +443,7 @@ const struct cpu_operations cpu_psci_ops = { | |||
287 | #ifdef CONFIG_HOTPLUG_CPU | 443 | #ifdef CONFIG_HOTPLUG_CPU |
288 | .cpu_disable = cpu_psci_cpu_disable, | 444 | .cpu_disable = cpu_psci_cpu_disable, |
289 | .cpu_die = cpu_psci_cpu_die, | 445 | .cpu_die = cpu_psci_cpu_die, |
446 | .cpu_kill = cpu_psci_cpu_kill, | ||
290 | #endif | 447 | #endif |
291 | }; | 448 | }; |
292 | 449 | ||
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 7ec784653b29..e578171b22ff 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/memblock.h> | 41 | #include <linux/memblock.h> |
42 | #include <linux/of_fdt.h> | 42 | #include <linux/of_fdt.h> |
43 | #include <linux/of_platform.h> | 43 | #include <linux/of_platform.h> |
44 | #include <linux/efi.h> | ||
44 | 45 | ||
45 | #include <asm/fixmap.h> | 46 | #include <asm/fixmap.h> |
46 | #include <asm/cputype.h> | 47 | #include <asm/cputype.h> |
@@ -55,6 +56,7 @@ | |||
55 | #include <asm/traps.h> | 56 | #include <asm/traps.h> |
56 | #include <asm/memblock.h> | 57 | #include <asm/memblock.h> |
57 | #include <asm/psci.h> | 58 | #include <asm/psci.h> |
59 | #include <asm/efi.h> | ||
58 | 60 | ||
59 | unsigned int processor_id; | 61 | unsigned int processor_id; |
60 | EXPORT_SYMBOL(processor_id); | 62 | EXPORT_SYMBOL(processor_id); |
@@ -366,11 +368,14 @@ void __init setup_arch(char **cmdline_p) | |||
366 | 368 | ||
367 | parse_early_param(); | 369 | parse_early_param(); |
368 | 370 | ||
371 | efi_init(); | ||
369 | arm64_memblock_init(); | 372 | arm64_memblock_init(); |
370 | 373 | ||
371 | paging_init(); | 374 | paging_init(); |
372 | request_standard_resources(); | 375 | request_standard_resources(); |
373 | 376 | ||
377 | efi_idmap_init(); | ||
378 | |||
374 | unflatten_device_tree(); | 379 | unflatten_device_tree(); |
375 | 380 | ||
376 | psci_init(); | 381 | psci_init(); |
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index f0a141dd5655..c3cb160edc69 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
@@ -228,6 +228,19 @@ int __cpu_disable(void) | |||
228 | return 0; | 228 | return 0; |
229 | } | 229 | } |
230 | 230 | ||
231 | static int op_cpu_kill(unsigned int cpu) | ||
232 | { | ||
233 | /* | ||
234 | * If we have no means of synchronising with the dying CPU, then assume | ||
235 | * that it is really dead. We can only wait for an arbitrary length of | ||
236 | * time and hope that it's dead, so let's skip the wait and just hope. | ||
237 | */ | ||
238 | if (!cpu_ops[cpu]->cpu_kill) | ||
239 | return 1; | ||
240 | |||
241 | return cpu_ops[cpu]->cpu_kill(cpu); | ||
242 | } | ||
243 | |||
231 | static DECLARE_COMPLETION(cpu_died); | 244 | static DECLARE_COMPLETION(cpu_died); |
232 | 245 | ||
233 | /* | 246 | /* |
@@ -241,6 +254,15 @@ void __cpu_die(unsigned int cpu) | |||
241 | return; | 254 | return; |
242 | } | 255 | } |
243 | pr_notice("CPU%u: shutdown\n", cpu); | 256 | pr_notice("CPU%u: shutdown\n", cpu); |
257 | |||
258 | /* | ||
259 | * Now that the dying CPU is beyond the point of no return w.r.t. | ||
260 | * in-kernel synchronisation, try to get the firwmare to help us to | ||
261 | * verify that it has really left the kernel before we consider | ||
262 | * clobbering anything it might still be using. | ||
263 | */ | ||
264 | if (!op_cpu_kill(cpu)) | ||
265 | pr_warn("CPU%d may not have shut down cleanly\n", cpu); | ||
244 | } | 266 | } |
245 | 267 | ||
246 | /* | 268 | /* |
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 08745578d54d..60b5c31f3c10 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c | |||
@@ -214,6 +214,8 @@ int __attribute_const__ kvm_target_cpu(void) | |||
214 | return KVM_ARM_TARGET_AEM_V8; | 214 | return KVM_ARM_TARGET_AEM_V8; |
215 | case ARM_CPU_PART_FOUNDATION: | 215 | case ARM_CPU_PART_FOUNDATION: |
216 | return KVM_ARM_TARGET_FOUNDATION_V8; | 216 | return KVM_ARM_TARGET_FOUNDATION_V8; |
217 | case ARM_CPU_PART_CORTEX_A53: | ||
218 | return KVM_ARM_TARGET_CORTEX_A53; | ||
217 | case ARM_CPU_PART_CORTEX_A57: | 219 | case ARM_CPU_PART_CORTEX_A57: |
218 | return KVM_ARM_TARGET_CORTEX_A57; | 220 | return KVM_ARM_TARGET_CORTEX_A57; |
219 | }; | 221 | }; |
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7bc41eab4c64..182415e1a952 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c | |||
@@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); | |||
30 | 30 | ||
31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
32 | { | 32 | { |
33 | if (kvm_psci_call(vcpu)) | 33 | int ret; |
34 | |||
35 | ret = kvm_psci_call(vcpu); | ||
36 | if (ret < 0) { | ||
37 | kvm_inject_undefined(vcpu); | ||
34 | return 1; | 38 | return 1; |
39 | } | ||
35 | 40 | ||
36 | kvm_inject_undefined(vcpu); | 41 | return ret; |
37 | return 1; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 44 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c index 8fe6f76b0edc..475fd2929310 100644 --- a/arch/arm64/kvm/sys_regs_generic_v8.c +++ b/arch/arm64/kvm/sys_regs_generic_v8.c | |||
@@ -88,6 +88,8 @@ static int __init sys_reg_genericv8_init(void) | |||
88 | &genericv8_target_table); | 88 | &genericv8_target_table); |
89 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8, | 89 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8, |
90 | &genericv8_target_table); | 90 | &genericv8_target_table); |
91 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A53, | ||
92 | &genericv8_target_table); | ||
91 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57, | 93 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57, |
92 | &genericv8_target_table); | 94 | &genericv8_target_table); |
93 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_XGENE_POTENZA, | 95 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_XGENE_POTENZA, |
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 31eb959e9aa8..023747bf4dd7 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c | |||
@@ -58,11 +58,6 @@ int pud_huge(pud_t pud) | |||
58 | #endif | 58 | #endif |
59 | } | 59 | } |
60 | 60 | ||
61 | int pmd_huge_support(void) | ||
62 | { | ||
63 | return 1; | ||
64 | } | ||
65 | |||
66 | static __init int setup_hugepagesz(char *opt) | 61 | static __init int setup_hugepagesz(char *opt) |
67 | { | 62 | { |
68 | unsigned long ps = memparse(opt, &opt); | 63 | unsigned long ps = memparse(opt, &opt); |
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 51d5352e6ad5..091d428d64ac 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c | |||
@@ -126,8 +126,6 @@ static void arm64_memory_present(void) | |||
126 | 126 | ||
127 | void __init arm64_memblock_init(void) | 127 | void __init arm64_memblock_init(void) |
128 | { | 128 | { |
129 | u64 *reserve_map, base, size; | ||
130 | |||
131 | /* Register the kernel text, kernel data and initrd with memblock */ | 129 | /* Register the kernel text, kernel data and initrd with memblock */ |
132 | memblock_reserve(__pa(_text), _end - _text); | 130 | memblock_reserve(__pa(_text), _end - _text); |
133 | #ifdef CONFIG_BLK_DEV_INITRD | 131 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -142,25 +140,6 @@ void __init arm64_memblock_init(void) | |||
142 | memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE); | 140 | memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE); |
143 | memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); | 141 | memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE); |
144 | 142 | ||
145 | /* Reserve the dtb region */ | ||
146 | memblock_reserve(virt_to_phys(initial_boot_params), | ||
147 | be32_to_cpu(initial_boot_params->totalsize)); | ||
148 | |||
149 | /* | ||
150 | * Process the reserve map. This will probably overlap the initrd | ||
151 | * and dtb locations which are already reserved, but overlapping | ||
152 | * doesn't hurt anything | ||
153 | */ | ||
154 | reserve_map = ((void*)initial_boot_params) + | ||
155 | be32_to_cpu(initial_boot_params->off_mem_rsvmap); | ||
156 | while (1) { | ||
157 | base = be64_to_cpup(reserve_map++); | ||
158 | size = be64_to_cpup(reserve_map++); | ||
159 | if (!size) | ||
160 | break; | ||
161 | memblock_reserve(base, size); | ||
162 | } | ||
163 | |||
164 | early_init_fdt_scan_reserved_mem(); | 143 | early_init_fdt_scan_reserved_mem(); |
165 | dma_contiguous_reserve(0); | 144 | dma_contiguous_reserve(0); |
166 | 145 | ||
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 0a472c41a67f..4a829a210bb6 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c | |||
@@ -168,7 +168,8 @@ static void __init *early_alloc(unsigned long sz) | |||
168 | } | 168 | } |
169 | 169 | ||
170 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | 170 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, |
171 | unsigned long end, unsigned long pfn) | 171 | unsigned long end, unsigned long pfn, |
172 | pgprot_t prot) | ||
172 | { | 173 | { |
173 | pte_t *pte; | 174 | pte_t *pte; |
174 | 175 | ||
@@ -180,16 +181,28 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | |||
180 | 181 | ||
181 | pte = pte_offset_kernel(pmd, addr); | 182 | pte = pte_offset_kernel(pmd, addr); |
182 | do { | 183 | do { |
183 | set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); | 184 | set_pte(pte, pfn_pte(pfn, prot)); |
184 | pfn++; | 185 | pfn++; |
185 | } while (pte++, addr += PAGE_SIZE, addr != end); | 186 | } while (pte++, addr += PAGE_SIZE, addr != end); |
186 | } | 187 | } |
187 | 188 | ||
188 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | 189 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, |
189 | unsigned long end, phys_addr_t phys) | 190 | unsigned long end, phys_addr_t phys, |
191 | int map_io) | ||
190 | { | 192 | { |
191 | pmd_t *pmd; | 193 | pmd_t *pmd; |
192 | unsigned long next; | 194 | unsigned long next; |
195 | pmdval_t prot_sect; | ||
196 | pgprot_t prot_pte; | ||
197 | |||
198 | if (map_io) { | ||
199 | prot_sect = PMD_TYPE_SECT | PMD_SECT_AF | | ||
200 | PMD_ATTRINDX(MT_DEVICE_nGnRE); | ||
201 | prot_pte = __pgprot(PROT_DEVICE_nGnRE); | ||
202 | } else { | ||
203 | prot_sect = prot_sect_kernel; | ||
204 | prot_pte = PAGE_KERNEL_EXEC; | ||
205 | } | ||
193 | 206 | ||
194 | /* | 207 | /* |
195 | * Check for initial section mappings in the pgd/pud and remove them. | 208 | * Check for initial section mappings in the pgd/pud and remove them. |
@@ -205,7 +218,7 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | |||
205 | /* try section mapping first */ | 218 | /* try section mapping first */ |
206 | if (((addr | next | phys) & ~SECTION_MASK) == 0) { | 219 | if (((addr | next | phys) & ~SECTION_MASK) == 0) { |
207 | pmd_t old_pmd =*pmd; | 220 | pmd_t old_pmd =*pmd; |
208 | set_pmd(pmd, __pmd(phys | prot_sect_kernel)); | 221 | set_pmd(pmd, __pmd(phys | prot_sect)); |
209 | /* | 222 | /* |
210 | * Check for previous table entries created during | 223 | * Check for previous table entries created during |
211 | * boot (__create_page_tables) and flush them. | 224 | * boot (__create_page_tables) and flush them. |
@@ -213,21 +226,23 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | |||
213 | if (!pmd_none(old_pmd)) | 226 | if (!pmd_none(old_pmd)) |
214 | flush_tlb_all(); | 227 | flush_tlb_all(); |
215 | } else { | 228 | } else { |
216 | alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys)); | 229 | alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), |
230 | prot_pte); | ||
217 | } | 231 | } |
218 | phys += next - addr; | 232 | phys += next - addr; |
219 | } while (pmd++, addr = next, addr != end); | 233 | } while (pmd++, addr = next, addr != end); |
220 | } | 234 | } |
221 | 235 | ||
222 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, | 236 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, |
223 | unsigned long end, unsigned long phys) | 237 | unsigned long end, unsigned long phys, |
238 | int map_io) | ||
224 | { | 239 | { |
225 | pud_t *pud = pud_offset(pgd, addr); | 240 | pud_t *pud = pud_offset(pgd, addr); |
226 | unsigned long next; | 241 | unsigned long next; |
227 | 242 | ||
228 | do { | 243 | do { |
229 | next = pud_addr_end(addr, end); | 244 | next = pud_addr_end(addr, end); |
230 | alloc_init_pmd(pud, addr, next, phys); | 245 | alloc_init_pmd(pud, addr, next, phys, map_io); |
231 | phys += next - addr; | 246 | phys += next - addr; |
232 | } while (pud++, addr = next, addr != end); | 247 | } while (pud++, addr = next, addr != end); |
233 | } | 248 | } |
@@ -236,30 +251,44 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, | |||
236 | * Create the page directory entries and any necessary page tables for the | 251 | * Create the page directory entries and any necessary page tables for the |
237 | * mapping specified by 'md'. | 252 | * mapping specified by 'md'. |
238 | */ | 253 | */ |
239 | static void __init create_mapping(phys_addr_t phys, unsigned long virt, | 254 | static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys, |
240 | phys_addr_t size) | 255 | unsigned long virt, phys_addr_t size, |
256 | int map_io) | ||
241 | { | 257 | { |
242 | unsigned long addr, length, end, next; | 258 | unsigned long addr, length, end, next; |
243 | pgd_t *pgd; | ||
244 | |||
245 | if (virt < VMALLOC_START) { | ||
246 | pr_warning("BUG: not creating mapping for 0x%016llx at 0x%016lx - outside kernel range\n", | ||
247 | phys, virt); | ||
248 | return; | ||
249 | } | ||
250 | 259 | ||
251 | addr = virt & PAGE_MASK; | 260 | addr = virt & PAGE_MASK; |
252 | length = PAGE_ALIGN(size + (virt & ~PAGE_MASK)); | 261 | length = PAGE_ALIGN(size + (virt & ~PAGE_MASK)); |
253 | 262 | ||
254 | pgd = pgd_offset_k(addr); | ||
255 | end = addr + length; | 263 | end = addr + length; |
256 | do { | 264 | do { |
257 | next = pgd_addr_end(addr, end); | 265 | next = pgd_addr_end(addr, end); |
258 | alloc_init_pud(pgd, addr, next, phys); | 266 | alloc_init_pud(pgd, addr, next, phys, map_io); |
259 | phys += next - addr; | 267 | phys += next - addr; |
260 | } while (pgd++, addr = next, addr != end); | 268 | } while (pgd++, addr = next, addr != end); |
261 | } | 269 | } |
262 | 270 | ||
271 | static void __init create_mapping(phys_addr_t phys, unsigned long virt, | ||
272 | phys_addr_t size) | ||
273 | { | ||
274 | if (virt < VMALLOC_START) { | ||
275 | pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n", | ||
276 | &phys, virt); | ||
277 | return; | ||
278 | } | ||
279 | __create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0); | ||
280 | } | ||
281 | |||
282 | void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io) | ||
283 | { | ||
284 | if ((addr >> PGDIR_SHIFT) >= ARRAY_SIZE(idmap_pg_dir)) { | ||
285 | pr_warn("BUG: not creating id mapping for %pa\n", &addr); | ||
286 | return; | ||
287 | } | ||
288 | __create_mapping(&idmap_pg_dir[pgd_index(addr)], | ||
289 | addr, addr, size, map_io); | ||
290 | } | ||
291 | |||
263 | static void __init map_mem(void) | 292 | static void __init map_mem(void) |
264 | { | 293 | { |
265 | struct memblock_region *reg; | 294 | struct memblock_region *reg; |
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S index 531342ec4bcf..8bbe9401f4f0 100644 --- a/arch/arm64/xen/hypercall.S +++ b/arch/arm64/xen/hypercall.S | |||
@@ -80,6 +80,7 @@ HYPERCALL2(memory_op); | |||
80 | HYPERCALL2(physdev_op); | 80 | HYPERCALL2(physdev_op); |
81 | HYPERCALL3(vcpu_op); | 81 | HYPERCALL3(vcpu_op); |
82 | HYPERCALL1(tmem_op); | 82 | HYPERCALL1(tmem_op); |
83 | HYPERCALL2(multicall); | ||
83 | 84 | ||
84 | ENTRY(privcmd_call) | 85 | ENTRY(privcmd_call) |
85 | mov x16, x0 | 86 | mov x16, x0 |