]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/setup.c
core: Introduce and use for_each_mem_region
[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         unsigned int n;
120         int err;
121
122         for_each_mem_region(mem, root_cell.config, n) {
123                 err = arch_map_memory_region(&root_cell, mem);
124                 if (err)
125                         return err;
126         }
127         return 0;
128 }
129
130 static void init_late(void)
131 {
132         unsigned int cpu, expected_cpus = 0;
133
134         for_each_cpu(cpu, root_cell.cpu_set)
135                 expected_cpus++;
136         if (hypervisor_header.online_cpus != expected_cpus) {
137                 error = -EINVAL;
138                 return;
139         }
140
141         error = arch_init_late();
142         if (error)
143                 return;
144
145         config_commit(&root_cell);
146
147         paging_dump_stats("after late setup");
148 }
149
150 int entry(unsigned int cpu_id, struct per_cpu *cpu_data)
151 {
152         static volatile bool activate;
153         bool master = false;
154
155         cpu_data->cpu_id = cpu_id;
156
157         spin_lock(&init_lock);
158
159         if (master_cpu_id == -1) {
160                 master = true;
161                 init_early(cpu_id);
162         }
163
164         if (!error)
165                 cpu_init(cpu_data);
166
167         spin_unlock(&init_lock);
168
169         while (!error && initialized_cpus < hypervisor_header.online_cpus)
170                 cpu_relax();
171
172         if (!error && master) {
173                 init_late();
174                 if (!error) {
175                         /*
176                          * Make sure everything was committed before we signal
177                          * the other CPUs that they can continue.
178                          */
179                         memory_barrier();
180                         activate = true;
181                 }
182         } else {
183                 while (!error && !activate)
184                         cpu_relax();
185         }
186
187         if (error) {
188                 if (master)
189                         arch_shutdown();
190                 arch_cpu_restore(cpu_data, error);
191                 return error;
192         }
193
194         if (master)
195                 printk("Activating hypervisor\n");
196
197         /* point of no return */
198         arch_cpu_activate_vmm(cpu_data);
199 }
200
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),
207         .entry = arch_entry,
208 };