diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2013-04-12 14:12:07 -0400 |
---|---|---|
committer | Christoffer Dall <cdall@cs.columbia.edu> | 2013-04-29 01:23:11 -0400 |
commit | d157f4a5155f4fbd0d1da66b3d2f504c13bd194d (patch) | |
tree | dd0a619e12202f2ce972a0412401b2b4d2329992 /arch | |
parent | 5a677ce044f18a341ab942e23516e52ad89f7687 (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.h | 1 | ||||
-rw-r--r-- | arch/arm/kvm/arm.c | 49 | ||||
-rw-r--r-- | arch/arm/kvm/mmu.c | 35 |
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 | ||
45 | int create_hyp_mappings(void *from, void *to); | 45 | int create_hyp_mappings(void *from, void *to); |
46 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); | 46 | int create_hyp_io_mappings(void *from, void *to, phys_addr_t); |
47 | void free_boot_hyp_pgd(void); | ||
47 | void free_hyp_pgds(void); | 48 | void free_hyp_pgds(void); |
48 | 49 | ||
49 | int kvm_alloc_stage2_pgd(struct kvm *kvm); | 50 | int 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 | ||
788 | static void cpu_init_hyp_mode(void *vector) | 789 | static 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 | ||
809 | static 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 | |||
822 | static 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 | */ |
811 | static int init_hyp_mode(void) | 829 | static 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; |
960 | out_err: | 979 | out_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 | */ | ||
163 | void 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 | ||