]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/setup.c
core/driver: Move version.h to generated directory
[jailhouse.git] / hypervisor / setup.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013, 2014
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
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>
21
22 extern u8 __text_start[], __hv_core_end[];
23
24 static const __attribute__((aligned(PAGE_SIZE))) u8 empty_page[PAGE_SIZE];
25
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;
30
31 static void init_early(unsigned int cpu_id)
32 {
33         unsigned long core_and_percpu_size;
34         struct jailhouse_memory hv_page;
35
36         master_cpu_id = cpu_id;
37
38         arch_dbg_write_init();
39
40         printk("\nInitializing Jailhouse hypervisor %s on CPU %d\n",
41                JAILHOUSE_VERSION, cpu_id);
42         printk("Code location: %p\n", __text_start);
43
44         error = paging_init();
45         if (error)
46                 return;
47
48         root_cell.config = &system_config->root_cell;
49
50         error = check_mem_regions(&system_config->root_cell);
51         if (error)
52                 return;
53
54         root_cell.id = -1;
55         error = cell_init(&root_cell);
56         if (error)
57                 return;
58
59         error = arch_init_early();
60         if (error)
61                 return;
62
63         /*
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.
67          */
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);
75                 if (error)
76                         return;
77                 core_and_percpu_size -= PAGE_SIZE;
78                 hv_page.virt_start += PAGE_SIZE;
79         }
80
81         paging_dump_stats("after early setup");
82         printk("Initializing processors:\n");
83 }
84
85 static void cpu_init(struct per_cpu *cpu_data)
86 {
87         int err = -EINVAL;
88
89         printk(" CPU %d... ", cpu_data->cpu_id);
90
91         if (!cpu_id_valid(cpu_data->cpu_id))
92                 goto failed;
93
94         cpu_data->cell = &root_cell;
95
96         err = arch_cpu_init(cpu_data);
97         if (err)
98                 goto failed;
99
100         printk("OK\n");
101
102         /*
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
105          * continue.
106          */
107         memory_barrier();
108         initialized_cpus++;
109         return;
110
111 failed:
112         printk("FAILED\n");
113         error = err;
114 }
115
116 int map_root_memory_regions(void)
117 {
118         const struct jailhouse_memory *mem =
119                 jailhouse_cell_mem_regions(root_cell.config);
120         unsigned int n;
121         int err;
122
123         for (n = 0; n < root_cell.config->num_memory_regions; n++, mem++) {
124                 err = arch_map_memory_region(&root_cell, mem);
125                 if (err)
126                         return err;
127         }
128         return 0;
129 }
130
131 static void init_late(void)
132 {
133         unsigned int cpu, expected_cpus = 0;
134
135         for_each_cpu(cpu, root_cell.cpu_set)
136                 expected_cpus++;
137         if (hypervisor_header.online_cpus != expected_cpus) {
138                 error = -EINVAL;
139                 return;
140         }
141
142         error = arch_init_late();
143         if (error)
144                 return;
145
146         config_commit(&root_cell);
147
148         paging_dump_stats("after late setup");
149 }
150
151 int entry(unsigned int cpu_id, struct per_cpu *cpu_data)
152 {
153         static volatile bool activate;
154         bool master = false;
155
156         cpu_data->cpu_id = cpu_id;
157
158         spin_lock(&init_lock);
159
160         if (master_cpu_id == -1) {
161                 master = true;
162                 init_early(cpu_id);
163         }
164
165         if (!error)
166                 cpu_init(cpu_data);
167
168         spin_unlock(&init_lock);
169
170         while (!error && initialized_cpus < hypervisor_header.online_cpus)
171                 cpu_relax();
172
173         if (!error && master) {
174                 init_late();
175                 if (!error) {
176                         /*
177                          * Make sure everything was committed before we signal
178                          * the other CPUs that they can continue.
179                          */
180                         memory_barrier();
181                         activate = true;
182                 }
183         } else {
184                 while (!error && !activate)
185                         cpu_relax();
186         }
187
188         if (error) {
189                 if (master)
190                         arch_shutdown();
191                 arch_cpu_restore(cpu_data, error);
192                 return error;
193         }
194
195         if (master)
196                 printk("Activating hypervisor\n");
197
198         /* point of no return */
199         arch_cpu_activate_vmm(cpu_data);
200 }
201
202 /** Hypervisor description header. */
203 struct jailhouse_header __attribute__((section(".header")))
204 hypervisor_header = {
205         .signature = JAILHOUSE_SIGNATURE,
206         .core_size = (unsigned long)__hv_core_end - JAILHOUSE_BASE,
207         .percpu_size = sizeof(struct per_cpu),
208         .entry = arch_entry,
209 };