Commit d157f4a5 authored by Marc Zyngier's avatar Marc Zyngier Committed by Christoffer Dall

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: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarChristoffer Dall <cdall@cs.columbia.edu>
parent 5a677ce0
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
int create_hyp_mappings(void *from, void *to); int create_hyp_mappings(void *from, void *to);
int create_hyp_io_mappings(void *from, void *to, phys_addr_t); int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
void free_boot_hyp_pgd(void);
void free_hyp_pgds(void); void free_hyp_pgds(void);
int kvm_alloc_stage2_pgd(struct kvm *kvm); int kvm_alloc_stage2_pgd(struct kvm *kvm);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
#include <linux/cpu.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
...@@ -785,7 +786,7 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -785,7 +786,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
} }
} }
static void cpu_init_hyp_mode(void *vector) static void cpu_init_hyp_mode(void *dummy)
{ {
unsigned long long boot_pgd_ptr; unsigned long long boot_pgd_ptr;
unsigned long long pgd_ptr; unsigned long long pgd_ptr;
...@@ -805,12 +806,28 @@ static void cpu_init_hyp_mode(void *vector) ...@@ -805,12 +806,28 @@ static void cpu_init_hyp_mode(void *vector)
__cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
} }
static int hyp_init_cpu_notify(struct notifier_block *self,
unsigned long action, void *cpu)
{
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
cpu_init_hyp_mode(NULL);
break;
}
return NOTIFY_OK;
}
static struct notifier_block hyp_init_cpu_nb = {
.notifier_call = hyp_init_cpu_notify,
};
/** /**
* Inits Hyp-mode on all online CPUs * Inits Hyp-mode on all online CPUs
*/ */
static int init_hyp_mode(void) static int init_hyp_mode(void)
{ {
phys_addr_t init_phys_addr;
int cpu; int cpu;
int err = 0; int err = 0;
...@@ -842,19 +859,6 @@ static int init_hyp_mode(void) ...@@ -842,19 +859,6 @@ static int init_hyp_mode(void)
per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page; per_cpu(kvm_arm_hyp_stack_page, cpu) = stack_page;
} }
/*
* Execute the init code on each CPU.
*
* Note: The stack is not mapped yet, so don't do anything else than
* initializing the hypervisor mode on each CPU using a local stack
* space for temporary storage.
*/
init_phys_addr = virt_to_phys(__kvm_hyp_init);
for_each_online_cpu(cpu) {
smp_call_function_single(cpu, cpu_init_hyp_mode,
(void *)(long)init_phys_addr, 1);
}
/* /*
* Map the Hyp-code called directly from the host * Map the Hyp-code called directly from the host
*/ */
...@@ -899,6 +903,11 @@ static int init_hyp_mode(void) ...@@ -899,6 +903,11 @@ static int init_hyp_mode(void)
} }
} }
/*
* Execute the init code on each CPU.
*/
on_each_cpu(cpu_init_hyp_mode, NULL, 1);
/* /*
* Init HYP view of VGIC * Init HYP view of VGIC
*/ */
...@@ -917,6 +926,10 @@ static int init_hyp_mode(void) ...@@ -917,6 +926,10 @@ static int init_hyp_mode(void)
if (err) if (err)
goto out_free_mappings; goto out_free_mappings;
#ifndef CONFIG_HOTPLUG_CPU
free_boot_hyp_pgd();
#endif
kvm_perf_init(); kvm_perf_init();
kvm_info("Hyp mode initialized successfully\n"); kvm_info("Hyp mode initialized successfully\n");
...@@ -955,6 +968,12 @@ int kvm_arch_init(void *opaque) ...@@ -955,6 +968,12 @@ int kvm_arch_init(void *opaque)
if (err) if (err)
goto out_err; goto out_err;
err = register_cpu_notifier(&hyp_init_cpu_nb);
if (err) {
kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
goto out_err;
}
kvm_coproc_table_init(); kvm_coproc_table_init();
return 0; return 0;
out_err: out_err:
......
...@@ -155,6 +155,31 @@ static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size) ...@@ -155,6 +155,31 @@ static void unmap_range(pgd_t *pgdp, unsigned long long start, u64 size)
} }
} }
/**
* free_boot_hyp_pgd - free HYP boot page tables
*
* Free the HYP boot page tables. The bounce page is also freed.
*/
void free_boot_hyp_pgd(void)
{
mutex_lock(&kvm_hyp_pgd_mutex);
if (boot_hyp_pgd) {
unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
kfree(boot_hyp_pgd);
boot_hyp_pgd = NULL;
}
if (hyp_pgd)
unmap_range(hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
kfree(init_bounce_page);
init_bounce_page = NULL;
mutex_unlock(&kvm_hyp_pgd_mutex);
}
/** /**
* free_hyp_pgds - free Hyp-mode page tables * free_hyp_pgds - free Hyp-mode page tables
* *
...@@ -169,13 +194,9 @@ void free_hyp_pgds(void) ...@@ -169,13 +194,9 @@ void free_hyp_pgds(void)
{ {
unsigned long addr; unsigned long addr;
mutex_lock(&kvm_hyp_pgd_mutex); free_boot_hyp_pgd();
if (boot_hyp_pgd) { mutex_lock(&kvm_hyp_pgd_mutex);
unmap_range(boot_hyp_pgd, hyp_idmap_start, PAGE_SIZE);
unmap_range(boot_hyp_pgd, TRAMPOLINE_VA, PAGE_SIZE);
kfree(boot_hyp_pgd);
}
if (hyp_pgd) { if (hyp_pgd) {
for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE) for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE)
...@@ -183,9 +204,9 @@ void free_hyp_pgds(void) ...@@ -183,9 +204,9 @@ void free_hyp_pgds(void)
for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE) for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE); unmap_range(hyp_pgd, KERN_TO_HYP(addr), PGDIR_SIZE);
kfree(hyp_pgd); kfree(hyp_pgd);
hyp_pgd = NULL;
} }
kfree(init_bounce_page);
mutex_unlock(&kvm_hyp_pgd_mutex); mutex_unlock(&kvm_hyp_pgd_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment