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;
51 error = cell_init(&root_cell);
55 error = arch_init_early();
60 * Back the region of the hypervisor core and per-CPU page with empty
61 * pages for Linux. This allows to fault-in the hypervisor region into
62 * Linux' page table before shutdown without triggering violations.
64 hv_page.phys_start = paging_hvirt2phys(empty_page);
65 hv_page.virt_start = paging_hvirt2phys(&hypervisor_header);
66 hv_page.size = PAGE_SIZE;
67 hv_page.flags = JAILHOUSE_MEM_READ;
68 core_and_percpu_size = (unsigned long)system_config - JAILHOUSE_BASE;
69 while (core_and_percpu_size > 0) {
70 error = arch_map_memory_region(&root_cell, &hv_page);
73 core_and_percpu_size -= PAGE_SIZE;
74 hv_page.virt_start += PAGE_SIZE;
77 paging_dump_stats("after early setup");
78 printk("Initializing processors:\n");
81 static void cpu_init(struct per_cpu *cpu_data)
85 printk(" CPU %d... ", cpu_data->cpu_id);
87 if (!cpu_id_valid(cpu_data->cpu_id))
90 cpu_data->cell = &root_cell;
92 err = arch_cpu_init(cpu_data);
99 * If this CPU is last, make sure everything was committed before we
100 * signal the other CPUs spinning on initialized_cpus that they can
112 int map_root_memory_regions(void)
114 const struct jailhouse_memory *mem;
118 for_each_mem_region(mem, root_cell.config, n) {
119 err = arch_map_memory_region(&root_cell, mem);
126 static void init_late(void)
128 unsigned int cpu, expected_cpus = 0;
130 for_each_cpu(cpu, root_cell.cpu_set)
132 if (hypervisor_header.online_cpus != expected_cpus) {
137 error = arch_init_late();
141 config_commit(&root_cell);
143 paging_dump_stats("after late setup");
146 int entry(unsigned int cpu_id, struct per_cpu *cpu_data)
148 static volatile bool activate;
151 cpu_data->cpu_id = cpu_id;
153 spin_lock(&init_lock);
155 if (master_cpu_id == -1) {
163 spin_unlock(&init_lock);
165 while (!error && initialized_cpus < hypervisor_header.online_cpus)
168 if (!error && master) {
172 * Make sure everything was committed before we signal
173 * the other CPUs that they can continue.
179 while (!error && !activate)
186 arch_cpu_restore(cpu_data, error);
191 printk("Activating hypervisor\n");
193 /* point of no return */
194 arch_cpu_activate_vmm(cpu_data);
197 /** Hypervisor description header. */
198 struct jailhouse_header __attribute__((section(".header")))
199 hypervisor_header = {
200 .signature = JAILHOUSE_SIGNATURE,
201 .core_size = (unsigned long)__hv_core_end - JAILHOUSE_BASE,
202 .percpu_size = sizeof(struct per_cpu),