aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2013-04-12 14:12:07 -0400
committerChristoffer Dall <cdall@cs.columbia.edu>2013-04-29 01:23:11 -0400
commitd157f4a5155f4fbd0d1da66b3d2f504c13bd194d (patch)
treedd0a619e12202f2ce972a0412401b2b4d2329992 /arch
parent5a677ce044f18a341ab942e23516e52ad89f7687 (diff)
ARM: KVM: perform HYP initilization for hotplugged CPUs
Now that we have the necessary infrastructure to boot a hotplugged CPU at any point in time, wire a CPU notifier that will perform the HYP init for the incoming CPU. Note that this depends on the platform code and/or firmware to boot the incoming CPU with HYP mode enabled and return to the kernel by following the normal boot path (HYP stub installed). Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/include/asm/kvm_mmu.h1
-rw-r--r--arch/arm/kvm/arm.c49
-rw-r--r--arch/arm/kvm/mmu.c35
3 files changed, 63 insertions, 22 deletions
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 24b767a8cdb9..472ac7091003 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -44,6 +44,7 @@
44 44
45int create_hyp_mappings(void *from, void *to); 45int create_hyp_mappings(void *from, void *to);
46int create_hyp_io_mappings(void *from, void *to, phys_addr_t); 46int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
47void free_boot_hyp_pgd(void);
47void free_hyp_pgds(void); 48void free_hyp_pgds(void);
48 49
49int kvm_alloc_stage2_pgd(struct kvm *kvm); 50int kvm_alloc_stage2_pgd(struct kvm *kvm);
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index fc47bd721ab0..6ea2aed0d29f 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -16,6 +16,7 @@
16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */ 17 */
18 18
19#include <linux/cpu.h>
19#include <linux/errno.h> 20#include <linux/errno.h>
20#include <linux/err.h> 21#include <linux/err.h>
21#include <linux/kvm_host.h> 22#include <linux/kvm_host.h>
@@ -785,7 +786,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
785 } 786 }
786} 787}
787 788
788static void cpu_init_hyp_mode(void *vector) 789static void cpu_init_hyp_mode(void *dummy)
789{ 790{
790 unsigned long long boot_pgd_ptr; 791 unsigned long long boot_pgd_ptr;
791 unsigned long long pgd_ptr; 792 unsigned long long pgd_ptr;
@@ -805,12 +806,28 @@ static void cpu_init_hyp_mode(void *vector)
805 __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); 806 __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
806} 807}
807 808
809static int hyp_init_cpu_notify(struct notifier_block *self,
810 unsigned long action, void *cpu)
811{
812 switch (action) {
813 case CPU_STARTING:
814 case CPU_STARTING_FROZEN:
815 cpu_init_hyp_mode(NULL);
816 break;
817 }
818
819 return NOTIFY_OK;
820}
821
822static struct notifier_block hyp_init_cpu_nb = {
823 .notifier_call = hyp_init_cpu_notify,
824};
825
808/** 826/**
809 * Inits Hyp-mode on all online CPUs 827 * Inits Hyp-mode on all online CPUs
810 */ 828 */
811static int init_hyp_mode(void) 829static int init_hyp_mode(void)
812{ 830{
813 phys_addr_t init_phys_addr;
814 int cpu; 831 int cpu;
815 int err = 0; 832 int err = 0;
816 833
@@ -843,19 +860,6 @@ static int init_hyp_mode(void)
843 } 860 }
844 861
845 /* 862 /*
846 * Execute the init code on each CPU.
847 *
848 * Note: The stack is not mapped yet, so don't do anything else than
849 * initializing the hypervisor mode on each CPU using a local stack
850 * space for temporary storage.
851 */
852 init_phys_addr = virt_to_phys(__kvm_hyp_init);
853 for_each_online_cpu(cpu) {
854 smp_call_function_single(cpu, cpu_init_hyp_mode,
855 (void *)(long)init_phys_addr, 1);
856 }
857
858 /*
859 * Map the Hyp-code called directly from the host 863 * Map the Hyp-code called directly from the host
860 */ 864 */
861 err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); 865 err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end);
@@ -900,6 +904,11 @@ static int init_hyp_mode(void)
900 } 904 }
901 905
902 /* 906 /*
907 * Execute the init code on each CPU.
908 */
909 on_each_cpu(cpu_init_hyp_mode, NULL, 1);
910
911 /*
903 * Init HYP view of VGIC 912 * Init HYP view of VGIC
904 */ 913 */
905 err = kvm_vgic_hyp_init(); 914 err = kvm_vgic_hyp_init();
@@ -917,6 +926,10 @@ static int init_hyp_mode(void)
917 if (err) 926 if (err)
918 goto out_free_mappings; 927 goto out_free_mappings;
919 928
929#ifndef CONFIG_HOTPLUG_CPU
930 free_boot_hyp_pgd();
931#endif
932
920 kvm_perf_init(); 933 kvm_perf_init();
921 934
922 kvm_info("Hyp mode initialized successfully\n"); 935 kvm_info("Hyp mode initialized successfully\n");
@@ -955,6 +968,12 @@ int kvm_arch_init(void *opaque)
955 if (err) 968 if (err)
956 goto out_err; 969 goto out_err;
957 970
971 err = register_cpu_notifier(&hyp_init_cpu_nb);
972 if (err) {
973 kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
974 goto out_err;
975 }
976
958 kvm_coproc_table_init(); 977 kvm_coproc_table_init();
959 return 0; 978 return 0;
960out_err: 979out_err:
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 4646c17f571c..965706578f13 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -156,6 +156,31 @@ static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size)
156} 156}
157 157
158/** 158/**
159 * free_boot_hyp_pgd - free HYP boot page tables
160 *
161 * Free the HYP boot page tables. The bounce page is also freed.
162 */
163void free_boot_hyp_pgd(void)
164{
165 mutex_lock(&kvm_hyp_pgd_mutex);
166
167 if (boot_hyp_pgd) {
168 unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
169 unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
170 kfree(boot_hyp_pgd);
171 boot_hyp_pgd = NULL;
172 }
173
174 if (hyp_pgd)
175 unmap_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
176
177 kfree(init_bounce_page);
178 init_bounce_page = NULL;
179
180 mutex_unlock(&kvm_hyp_pgd_mutex);
181}
182
183/**
159 * free_hyp_pgds - free Hyp-mode page tables 184 * free_hyp_pgds - free Hyp-mode page tables
160 * 185 *
161 * Assumes hyp_pgd is a page table used strictly in Hyp-mode and 186 * Assumes hyp_pgd is a page table used strictly in Hyp-mode and
@@ -169,13 +194,9 @@ void free_hyp_pgds(void)
169{ 194{
170 unsigned long addr; 195 unsigned long addr;
171 196
172 mutex_lock(&kvm_hyp_pgd_mutex); 197 free_boot_hyp_pgd();
173 198
174 if (boot_hyp_pgd) { 199 mutex_lock(&kvm_hyp_pgd_mutex);
175 unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
176 unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
177 kfree(boot_hyp_pgd);
178 }
179 200
180 if (hyp_pgd) { 201 if (hyp_pgd) {
181 for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) 202 for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE)
@@ -183,9 +204,9 @@ void free_hyp_pgds(void)
183 for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) 204 for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
184 unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); 205 unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
185 kfree(hyp_pgd); 206 kfree(hyp_pgd);
207 hyp_pgd = NULL;
186 } 208 }
187 209
188 kfree(init_bounce_page);
189 mutex_unlock(&kvm_hyp_pgd_mutex); 210 mutex_unlock(&kvm_hyp_pgd_mutex);
190} 211}
191 212