2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2013, 2014
7 * Jan Kiszka <jan.kiszka@siemens.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
13 #include <jailhouse/processor.h>
14 #include <jailhouse/printk.h>
15 #include <jailhouse/entry.h>
16 #include <jailhouse/paging.h>
17 #include <jailhouse/control.h>
18 #include <jailhouse/string.h>
19 #include <generated/version.h>
20 #include <asm/spinlock.h>
22 extern u8 __text_start[], __hv_core_end[];
24 static const __attribute__((aligned(PAGE_SIZE))) u8 empty_page[PAGE_SIZE];
26 static DEFINE_SPINLOCK(init_lock);
27 static unsigned int master_cpu_id = -1;
28 static volatile unsigned int initialized_cpus;
29 static volatile int error;
31 static void init_early(unsigned int cpu_id)
33 unsigned long core_and_percpu_size;
34 struct jailhouse_memory hv_page;
36 master_cpu_id = cpu_id;
38 arch_dbg_write_init();
40 printk("\nInitializing Jailhouse hypervisor %s on CPU %d\n",
41 JAILHOUSE_VERSION, cpu_id);
42 printk("Code location: %p\n", __text_start);
44 error = paging_init();
48 root_cell.config = &system_config->root_cell;
50 error = check_mem_regions(&system_config->root_cell);
55 error = cell_init(&root_cell);
59 error = arch_init_early();
64 * Back the region of the hypervisor core and per-CPU page with empty
65 * pages for Linux. This allows to fault-in the hypervisor region into
66 * Linux' page table before shutdown without triggering violations.
68 hv_page.phys_start = paging_hvirt2phys(empty_page);
69 hv_page.virt_start = paging_hvirt2phys(&hypervisor_header);
70 hv_page.size = PAGE_SIZE;
71 hv_page.flags = JAILHOUSE_MEM_READ;
72 core_and_percpu_size = (unsigned long)system_config - JAILHOUSE_BASE;
73 while (core_and_percpu_size > 0) {
74 error = arch_map_memory_region(&root_cell, &hv_page);
77 core_and_percpu_size -= PAGE_SIZE;
78 hv_page.virt_start += PAGE_SIZE;
81 paging_dump_stats("after early setup");
82 printk("Initializing processors:\n");
85 static void cpu_init(struct per_cpu *cpu_data)
89 printk(" CPU %d... ", cpu_data->cpu_id);
91 if (!cpu_id_valid(cpu_data->cpu_id))
94 cpu_data->cell = &root_cell;
96 err = arch_cpu_init(cpu_data);
103 * If this CPU is last, make sure everything was committed before we
104 * signal the other CPUs spinning on initialized_cpus that they can
116 int map_root_memory_regions(void)
118 const struct jailhouse_memory *mem;
122 for_each_mem_region(mem, root_cell.config, n) {
123 err = arch_map_memory_region(&root_cell, mem);
130 static void init_late(void)
132 unsigned int cpu, expected_cpus = 0;
134 for_each_cpu(cpu, root_cell.cpu_set)
136 if (hypervisor_header.online_cpus != expected_cpus) {
141 error = arch_init_late();
145 config_commit(&root_cell);
147 paging_dump_stats("after late setup");
150 int entry(unsigned int cpu_id, struct per_cpu *cpu_data)
152 static volatile bool activate;
155 cpu_data->cpu_id = cpu_id;
157 spin_lock(&init_lock);
159 if (master_cpu_id == -1) {
167 spin_unlock(&init_lock);
169 while (!error && initialized_cpus < hypervisor_header.online_cpus)
172 if (!error && master) {
176 * Make sure everything was committed before we signal
177 * the other CPUs that they can continue.
183 while (!error && !activate)
190 arch_cpu_restore(cpu_data, error);
195 printk("Activating hypervisor\n");
197 /* point of no return */
198 arch_cpu_activate_vmm(cpu_data);
201 /** Hypervisor description header. */
202 struct jailhouse_header __attribute__((section(".header")))
203 hypervisor_header = {
204 .signature = JAILHOUSE_SIGNATURE,
205 .core_size = (unsigned long)__hv_core_end - JAILHOUSE_BASE,
206 .percpu_size = sizeof(struct per_cpu),