]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
core: Implement cell destruction
authorJan Kiszka <jan.kiszka@siemens.com>
Sat, 7 Dec 2013 09:13:25 +0000 (10:13 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Thu, 12 Dec 2013 16:36:48 +0000 (17:36 +0100)
When a cell is destroyed, we need to stop its CPUs and assigned all
its resources that Linux used to have before back to that cell. Like for
shutdown, access control is still missing.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/setup.c
hypervisor/arch/x86/apic.c
hypervisor/arch/x86/control.c
hypervisor/arch/x86/include/asm/vmx.h
hypervisor/arch/x86/vmx.c
hypervisor/control.c
hypervisor/include/jailhouse/control.h
hypervisor/include/jailhouse/entry.h

index 3c5cf369707471d73cedf5ec593c41d9062e30ff..ceda3f6a80e50c419d326cbf06d9ffe8c00de605 100644 (file)
@@ -46,8 +46,10 @@ int phys_processor_id(void) { return 0; }
 void arch_suspend_cpu(unsigned int cpu_id) {}
 void arch_resume_cpu(unsigned int cpu_id) {}
 void arch_reset_cpu(unsigned int cpu_id) {}
+void arch_park_cpu(unsigned int cpu_id) {}
 void arch_shutdown_cpu(unsigned int cpu_id) {}
 int arch_cell_create(struct per_cpu *cpu_data, struct cell *new_cell)
 { return -ENOSYS; }
+void arch_cell_destroy(struct per_cpu *cpu_data, struct cell *new_cell) {}
 void *memcpy(void *dest, const void *src, unsigned long n) { return NULL; }
 void arch_dbg_write(const char *msg) {}
index 04b47830cd587d2e3d17190ac681a4c4d9261938..56d074741d3cfa0002edf136d2fd60aee992bab0 100644 (file)
@@ -187,6 +187,16 @@ void arch_reset_cpu(unsigned int cpu_id)
        arch_resume_cpu(cpu_id);
 }
 
+void arch_park_cpu(unsigned int cpu_id)
+{
+       per_cpu(cpu_id)->init_signaled = true;
+
+       /* make state change visible before signaling the CPU */
+       memory_barrier();
+
+       apic_send_nmi_ipi(per_cpu(cpu_id));
+}
+
 void arch_shutdown_cpu(unsigned int cpu_id)
 {
        arch_suspend_cpu(cpu_id);
index df6515a4d45af697ddb28a5823458b97e28ce87f..6c27f86db43e26c97645b903fc6b5223985ea403 100644 (file)
@@ -27,3 +27,9 @@ int arch_cell_create(struct per_cpu *cpu_data, struct cell *cell)
        flush_linux_cpu_caches(cpu_data);
        return vmx_cell_init(cell);
 }
+
+void arch_cell_destroy(struct per_cpu *cpu_data, struct cell *cell)
+{
+       vmx_cell_exit(cell);
+       flush_linux_cpu_caches(cpu_data);
+}
index 7e46b90bfcd502fe1ce9229f77f57f64dbf89598..b3e52105a02d090a04d2e12db4d9314a10f03682 100644 (file)
@@ -284,6 +284,7 @@ void vmx_init(void);
 
 int vmx_cell_init(struct cell *cell);
 void vmx_cell_shrink(struct cell *cell, struct jailhouse_cell_desc *config);
+void vmx_cell_exit(struct cell *cell);
 
 int vmx_cpu_init(struct per_cpu *cpu_data);
 void vmx_cpu_exit(struct per_cpu *cpu_data);
index d1baf0cf740d0d74ebc8394a4653e00ebbfa84b5..7aa74d2babbffb55b82b6e7afeb2cfd0f51dbc9f 100644 (file)
@@ -256,6 +256,90 @@ void vmx_cell_shrink(struct cell *cell, struct jailhouse_cell_desc *config)
        vmx_invept();
 }
 
+static bool address_in_region(unsigned long addr,
+                             struct jailhouse_memory *region)
+{
+       return addr >= region->phys_start &&
+              addr < (region->phys_start + region->size);
+}
+
+static void vmx_remap_to_linux(struct jailhouse_memory *mem)
+{
+       struct jailhouse_memory *linux_mem, overlap;
+       int n, err;
+
+       linux_mem = (void *)linux_cell.config +
+               sizeof(struct jailhouse_cell_desc) +
+               linux_cell.config->cpu_set_size;
+
+       for (n = 0; n < linux_cell.config->num_memory_regions;
+            n++, linux_mem++) {
+               if (address_in_region(mem->phys_start, linux_mem)) {
+                       overlap.phys_start = mem->phys_start;
+                       overlap.size = linux_mem->size -
+                               (overlap.phys_start - linux_mem->phys_start);
+                       if (overlap.size > mem->size)
+                               overlap.size = mem->size;
+               } else if (address_in_region(linux_mem->phys_start, mem)) {
+                       overlap.phys_start = linux_mem->phys_start;
+                       overlap.size = mem->size -
+                               (overlap.phys_start - mem->phys_start);
+                       if (overlap.size > linux_mem->size)
+                               overlap.size = linux_mem->size;
+               } else
+                       continue;
+
+               overlap.virt_start = linux_mem->virt_start +
+                       overlap.phys_start - linux_mem->phys_start;
+               overlap.access_flags = linux_mem->access_flags;
+
+               err = vmx_map_memory_region(&linux_cell, &overlap);
+               if (err)
+                       printk("WARNING: Failed to re-assign memory region "
+                              "to Linux cell\n");
+       }
+}
+
+void vmx_cell_exit(struct cell *cell)
+{
+       struct jailhouse_cell_desc *config = cell->config;
+       u8 *pio_bitmap, *linux_pio_bitmap, *b;
+       struct jailhouse_memory *mem;
+       u32 pio_bitmap_size;
+       int n;
+
+       mem = (void *)config + sizeof(struct jailhouse_cell_desc) +
+               config->cpu_set_size;
+
+       for (n = 0; n < config->num_memory_regions; n++, mem++) {
+               page_map_destroy(cell->vmx.ept, mem->virt_start, mem->size,
+                                PAGE_DIR_LEVELS);
+               vmx_remap_to_linux(mem);
+       }
+       page_map_destroy(cell->vmx.ept, XAPIC_BASE, PAGE_SIZE,
+                        PAGE_DIR_LEVELS);
+
+       pio_bitmap = (void *)mem +
+               config->num_irq_lines * sizeof(struct jailhouse_irq_line);
+       pio_bitmap_size = config->pio_bitmap_size;
+
+       linux_pio_bitmap = (void *)linux_cell.config +
+               sizeof(struct jailhouse_cell_desc) +
+               linux_cell.config->cpu_set_size +
+               linux_cell.config->num_memory_regions *
+                       sizeof(struct jailhouse_memory) +
+               linux_cell.config->num_irq_lines *
+                       sizeof(struct jailhouse_irq_line);
+       if (linux_cell.config->pio_bitmap_size < pio_bitmap_size)
+               pio_bitmap_size = linux_cell.config->pio_bitmap_size;
+
+       for (b = linux_cell.vmx.io_bitmap; pio_bitmap_size > 0;
+            b++, pio_bitmap++, linux_pio_bitmap++, pio_bitmap_size--)
+               *b &= *pio_bitmap | *linux_pio_bitmap;
+
+       page_free(&mem_pool, cell->vmx.ept, 1);
+}
+
 void vmx_invept(void)
 {
        unsigned long ept_cap = read_msr(MSR_IA32_VMX_EPT_VPID_CAP);
index 25c5934485ba577d6b1c25d67095761377797b31..0d89e5883dd1028e1a575d8c0027520639d766e6 100644 (file)
@@ -260,7 +260,68 @@ err_free_cell:
 
 int cell_destroy(struct per_cpu *cpu_data, unsigned long name_address)
 {
-       return -ENOSYS;
+       unsigned long mapping_addr = FOREIGN_MAPPING_BASE +
+               cpu_data->cpu_id * PAGE_SIZE * NUM_FOREIGN_PAGES;
+       struct cell *cell, *previous;
+       unsigned long name_size;
+       const char *name;
+       unsigned int cpu;
+       int err = 0;
+
+       // TODO: access control
+
+       /* We do not support destruction over non-Linux cells so far */
+       if (cpu_data->cell != &linux_cell)
+               return -EINVAL;
+
+       cell_suspend(cpu_data);
+
+       name_size = (name_address & ~PAGE_MASK) + JAILHOUSE_CELL_NAME_MAXLEN;
+
+       err = page_map_create(hv_page_table, name_address & PAGE_MASK,
+                             name_size, mapping_addr, PAGE_READONLY_FLAGS,
+                             PAGE_DEFAULT_FLAGS, PAGE_DIR_LEVELS);
+       if (err)
+               goto resume_out;
+
+       name = (const char *)(mapping_addr + (name_address & ~PAGE_MASK));
+
+       cell = cell_find(name);
+       if (!cell) {
+               err = -ENOENT;
+               goto resume_out;
+       }
+
+       /* Linux cell cannot be destroyed */
+       if (cell == &linux_cell) {
+               err = -EINVAL;
+               goto resume_out;
+       }
+
+       printk("Closing cell \"%s\"\n", name);
+
+       for_each_cpu(cpu, cell->cpu_set) {
+               printk(" Parking CPU %d\n", cpu);
+               arch_park_cpu(cpu);
+
+               set_bit(cpu, linux_cell.cpu_set->bitmap);
+               per_cpu(cpu)->cell = &linux_cell;
+       }
+
+       arch_cell_destroy(cpu_data, cell);
+
+       previous = &linux_cell;
+       while (previous->next != cell)
+               previous = previous->next;
+       previous->next = cell->next;
+
+       page_free(&mem_pool, cell, cell->data_pages);
+       page_map_dump_stats("after cell destruction");
+
+resume_out:
+       cell_resume(cpu_data);
+
+       return err;
 }
 
 int shutdown(struct per_cpu *cpu_data)
index 5677c296a05e3ecf03f0b0fcaba25d121cf12616..121f6b94934075946fb7be277675cd55697b3d7f 100644 (file)
@@ -42,6 +42,8 @@ int shutdown(struct per_cpu *cpu_data);
 void arch_suspend_cpu(unsigned int cpu_id);
 void arch_resume_cpu(unsigned int cpu_id);
 void arch_reset_cpu(unsigned int cpu_id);
+void arch_park_cpu(unsigned int cpu_id);
 void arch_shutdown_cpu(unsigned int cpu_id);
 
-int arch_cell_create(struct per_cpu *cpu_data, struct cell *new_cell);
+int arch_cell_create(struct per_cpu *cpu_data, struct cell *cell);
+void arch_cell_destroy(struct per_cpu *cpu_data, struct cell *cell);
index d1d49c53338aa71d13053973541e32cf6034bf0b..274abd7ca13ffbd2783321359c84635a4b79c961 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <jailhouse/cell-config.h>
 
+#define ENOENT         2
 #define EIO            5
 #define E2BIG          7
 #define ENOMEM         12