2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2013-2015
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 <linux/cpu.h>
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
17 #include <asm/cacheflush.h>
24 #include <jailhouse/hypercall.h>
26 struct cell *root_cell;
28 static LIST_HEAD(cells);
29 static cpumask_t offlined_cpus;
31 void jailhouse_cell_kobj_release(struct kobject *kobj)
33 struct cell *cell = container_of(kobj, struct cell, kobj);
35 jailhouse_pci_cell_cleanup(cell);
36 vfree(cell->memory_regions);
40 struct cell *jailhouse_cell_create(const struct jailhouse_cell_desc *cell_desc)
45 if (cell_desc->num_memory_regions >=
46 ULONG_MAX / sizeof(struct jailhouse_memory))
47 return ERR_PTR(-EINVAL);
49 cell = kzalloc(sizeof(*cell), GFP_KERNEL);
51 return ERR_PTR(-ENOMEM);
53 INIT_LIST_HEAD(&cell->entry);
55 bitmap_copy(cpumask_bits(&cell->cpus_assigned),
56 jailhouse_cell_cpu_set(cell_desc),
57 min(nr_cpumask_bits, (int)cell_desc->cpu_set_size * 8));
59 cell->num_memory_regions = cell_desc->num_memory_regions;
60 cell->memory_regions = vmalloc(sizeof(struct jailhouse_memory) *
61 cell->num_memory_regions);
62 if (!cell->memory_regions) {
64 return ERR_PTR(-ENOMEM);
67 memcpy(cell->memory_regions, jailhouse_cell_mem_regions(cell_desc),
68 sizeof(struct jailhouse_memory) * cell->num_memory_regions);
70 err = jailhouse_pci_cell_setup(cell, cell_desc);
72 vfree(cell->memory_regions);
77 err = jailhouse_sysfs_cell_create(cell, cell_desc->name);
79 /* cleanup done by jailhouse_sysfs_cell_create */
85 void jailhouse_cell_register(struct cell *cell)
87 list_add_tail(&cell->entry, &cells);
88 jailhouse_sysfs_cell_register(cell);
91 static struct cell *find_cell(struct jailhouse_cell_id *cell_id)
95 list_for_each_entry(cell, &cells, entry)
96 if (cell_id->id == cell->id ||
97 (cell_id->id == JAILHOUSE_CELL_ID_UNUSED &&
98 strcmp(kobject_name(&cell->kobj), cell_id->name) == 0))
103 void jailhouse_cell_delete(struct cell *cell)
105 list_del(&cell->entry);
106 jailhouse_sysfs_cell_delete(cell);
109 int jailhouse_cell_prepare_root(const struct jailhouse_cell_desc *cell_desc)
111 root_cell = jailhouse_cell_create(cell_desc);
112 if (IS_ERR(root_cell))
113 return PTR_ERR(root_cell);
115 cpumask_and(&root_cell->cpus_assigned, &root_cell->cpus_assigned,
121 void jailhouse_cell_register_root(void)
123 jailhouse_pci_do_all_devices(root_cell, JAILHOUSE_PCI_TYPE_IVSHMEM,
124 JAILHOUSE_PCI_ACTION_ADD);
127 jailhouse_cell_register(root_cell);
130 void jailhouse_cell_delete_root(void)
132 jailhouse_cell_delete(root_cell);
135 void jailhouse_cell_delete_all(void)
137 struct cell *cell, *tmp;
140 jailhouse_pci_do_all_devices(root_cell, JAILHOUSE_PCI_TYPE_IVSHMEM,
141 JAILHOUSE_PCI_ACTION_DEL);
143 jailhouse_pci_do_all_devices(root_cell, JAILHOUSE_PCI_TYPE_DEVICE,
144 JAILHOUSE_PCI_ACTION_RELEASE);
146 list_for_each_entry_safe(cell, tmp, &cells, entry)
147 jailhouse_cell_delete(cell);
149 for_each_cpu(cpu, &offlined_cpus) {
150 if (cpu_up(cpu) != 0)
151 pr_err("Jailhouse: failed to bring CPU %d back "
153 cpumask_clear_cpu(cpu, &offlined_cpus);
157 int jailhouse_cmd_cell_create(struct jailhouse_cell_create __user *arg)
159 struct jailhouse_cell_create cell_params;
160 struct jailhouse_cell_desc *config;
161 struct jailhouse_cell_id cell_id;
162 void __user *user_config;
167 if (copy_from_user(&cell_params, arg, sizeof(cell_params)))
170 config = kmalloc(cell_params.config_size, GFP_USER | __GFP_NOWARN);
174 user_config = (void __user *)(unsigned long)cell_params.config_address;
175 if (copy_from_user(config, user_config, cell_params.config_size)) {
177 goto kfree_config_out;
180 if (memcmp(config->signature, JAILHOUSE_CELL_DESC_SIGNATURE,
181 sizeof(config->signature)) != 0) {
182 pr_err("jailhouse: Not a cell configuration\n");
184 goto kfree_config_out;
187 config->name[JAILHOUSE_CELL_NAME_MAXLEN] = 0;
189 if (mutex_lock_interruptible(&jailhouse_lock) != 0) {
191 goto kfree_config_out;
194 if (!jailhouse_enabled) {
199 cell_id.id = JAILHOUSE_CELL_ID_UNUSED;
200 memcpy(cell_id.name, config->name, sizeof(cell_id.name));
201 if (find_cell(&cell_id) != NULL) {
206 cell = jailhouse_cell_create(config);
212 if (!cpumask_subset(&cell->cpus_assigned, &root_cell->cpus_assigned)) {
214 goto error_cell_delete;
217 for_each_cpu(cpu, &cell->cpus_assigned) {
218 if (cpu_online(cpu)) {
221 goto error_cpu_online;
222 cpumask_set_cpu(cpu, &offlined_cpus);
224 cpumask_clear_cpu(cpu, &root_cell->cpus_assigned);
227 jailhouse_pci_do_all_devices(cell, JAILHOUSE_PCI_TYPE_DEVICE,
228 JAILHOUSE_PCI_ACTION_CLAIM);
230 id = jailhouse_call_arg1(JAILHOUSE_HC_CELL_CREATE, __pa(config));
233 goto error_cpu_online;
237 jailhouse_cell_register(cell);
239 pr_info("Created Jailhouse cell \"%s\"\n", config->name);
242 mutex_unlock(&jailhouse_lock);
250 for_each_cpu(cpu, &cell->cpus_assigned) {
251 if (!cpu_online(cpu) && cpu_up(cpu) == 0)
252 cpumask_clear_cpu(cpu, &offlined_cpus);
253 cpumask_set_cpu(cpu, &root_cell->cpus_assigned);
257 jailhouse_cell_delete(cell);
261 static int cell_management_prologue(struct jailhouse_cell_id *cell_id,
262 struct cell **cell_ptr)
264 cell_id->name[JAILHOUSE_CELL_ID_NAMELEN] = 0;
266 if (mutex_lock_interruptible(&jailhouse_lock) != 0)
269 if (!jailhouse_enabled) {
270 mutex_unlock(&jailhouse_lock);
274 *cell_ptr = find_cell(cell_id);
275 if (*cell_ptr == NULL) {
276 mutex_unlock(&jailhouse_lock);
282 #define MEM_REQ_FLAGS (JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_LOADABLE)
284 static int load_image(struct cell *cell,
285 struct jailhouse_preload_image __user *uimage)
287 struct jailhouse_preload_image image;
288 const struct jailhouse_memory *mem;
289 unsigned int regions, page_offs;
290 u64 image_offset, phys_start;
294 if (copy_from_user(&image, uimage, sizeof(image)))
297 mem = cell->memory_regions;
298 for (regions = cell->num_memory_regions; regions > 0; regions--) {
299 image_offset = image.target_address - mem->virt_start;
300 if (image.target_address >= mem->virt_start &&
301 image_offset < mem->size) {
302 if (image.size > mem->size - image_offset ||
303 (mem->flags & MEM_REQ_FLAGS) != MEM_REQ_FLAGS)
312 phys_start = (mem->phys_start + image_offset) & PAGE_MASK;
313 page_offs = offset_in_page(image_offset);
314 image_mem = jailhouse_ioremap(phys_start, 0,
315 PAGE_ALIGN(image.size + page_offs));
317 pr_err("jailhouse: Unable to map cell RAM at %08llx "
318 "for image loading\n",
319 (unsigned long long)(mem->phys_start + image_offset));
323 if (copy_from_user(image_mem + page_offs,
324 (void __user *)(unsigned long)image.source_address,
328 * ARMv8 requires to clean D-cache and invalidate I-cache for memory
329 * containing new instructions. On x86 this is a NOP. On ARMv7 the
330 * firmware does its own cache maintenance, so it is an
331 * extraneous (but harmless) flush.
333 flush_icache_range((unsigned long)(image_mem + page_offs),
334 (unsigned long)(image_mem + page_offs) + image.size);
341 int jailhouse_cmd_cell_load(struct jailhouse_cell_load __user *arg)
343 struct jailhouse_preload_image __user *image = arg->image;
344 struct jailhouse_cell_load cell_load;
349 if (copy_from_user(&cell_load, arg, sizeof(cell_load)))
352 err = cell_management_prologue(&cell_load.cell_id, &cell);
356 err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_SET_LOADABLE, cell->id);
360 for (n = cell_load.num_preload_images; n > 0; n--, image++) {
361 err = load_image(cell, image);
367 mutex_unlock(&jailhouse_lock);
372 int jailhouse_cmd_cell_start(const char __user *arg)
374 struct jailhouse_cell_id cell_id;
378 if (copy_from_user(&cell_id, arg, sizeof(cell_id)))
381 err = cell_management_prologue(&cell_id, &cell);
385 err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_START, cell->id);
387 mutex_unlock(&jailhouse_lock);
392 int jailhouse_cmd_cell_destroy(const char __user *arg)
394 struct jailhouse_cell_id cell_id;
399 if (copy_from_user(&cell_id, arg, sizeof(cell_id)))
402 err = cell_management_prologue(&cell_id, &cell);
406 err = jailhouse_call_arg1(JAILHOUSE_HC_CELL_DESTROY, cell->id);
410 for_each_cpu(cpu, &cell->cpus_assigned) {
411 if (cpumask_test_cpu(cpu, &offlined_cpus)) {
412 if (cpu_up(cpu) != 0)
413 pr_err("Jailhouse: failed to bring CPU %d "
414 "back online\n", cpu);
415 cpumask_clear_cpu(cpu, &offlined_cpus);
417 cpumask_set_cpu(cpu, &root_cell->cpus_assigned);
420 jailhouse_pci_do_all_devices(cell, JAILHOUSE_PCI_TYPE_DEVICE,
421 JAILHOUSE_PCI_ACTION_RELEASE);
423 pr_info("Destroyed Jailhouse cell \"%s\"\n",
424 kobject_name(&cell->kobj));
426 jailhouse_cell_delete(cell);
429 mutex_unlock(&jailhouse_lock);