Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


HRT image replacement from ROS application
Peter Dinda [Thu, 17 Sep 2015 20:52:54 +0000 (15:52 -0500)]
This adds the capability for a ROS application to dynamically replace
the HRT image within the HVM.  Combined with HRT boot and other
capabilities, this allows the ROS to essentially fork and exec an
HRT that operates over its address space.

guest/linux/hvm-ros/v3_hvm_ros_user.c
guest/linux/hvm-ros/v3_hvm_ros_user.h
palacios/include/palacios/vmm_hvm.h
palacios/include/palacios/vmm_multiboot.h
palacios/src/palacios/vmm_hvm.c
palacios/src/palacios/vmm_multiboot.c

index 74e6a5a..345f8cb 100644 (file)
@@ -239,6 +239,32 @@ static void wait_for_completion()
   }
 }
 
+
+int v3_hvm_ros_install_hrt_image(void *image, uint64_t size)
+{
+    unsigned long long rc, num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
+    unsigned long long i;
+    volatile long long sum=0;
+
+    num = 0xf00d;
+    a1 = 0x8; // install image
+    a2 = (unsigned long long) image;
+    a3 = size;
+
+    // touch the whoel image to make it has ptes
+    for (i=0;i<size;i++) { 
+       sum+=((char*)image)[i];
+    }
+
+    HCALL(rc,num,a1,a2,a3,a4,a5,a6,a7,a8);
+
+    if (rc) { 
+       return -1;
+    } else {
+       return 0;
+    }
+}
+
 int v3_hvm_ros_reset(reset_type what)
 {
     unsigned long long num, a1=0, a2=0, a3=0, a4=0, a5=0, a6=0, a7=0, a8=0;
index 2101108..96c8262 100644 (file)
@@ -13,6 +13,11 @@ int v3_hvm_ros_user_init();
 int v3_hvm_ros_user_deinit();
 
 
+// Replace the existing HRT with a new one
+//  - this does not boot the new HRT
+//  - the intial image is the one given in the .pal config
+int v3_hvm_ros_install_hrt_image(void *image, uint64_t size);
+
 typedef enum {RESET_HRT, RESET_ROS, RESET_BOTH} reset_type;
 
 int v3_hvm_ros_reset(reset_type what);
index a206d54..9d441d6 100644 (file)
@@ -45,7 +45,9 @@ struct v3_vm_hvm {
     uint8_t   is_hvm;
     uint32_t  first_hrt_core;
     uint64_t  first_hrt_gpa;
-    struct v3_cfg_file *hrt_file;
+    struct v3_cfg_file *hrt_file;  // image provided via PAL file, if any
+    void      *hrt_image;          // image provided by ROS, if any
+    uint64_t  hrt_image_size;      //   size of this image
     uint64_t  hrt_entry_addr;
     enum { HRT_BLOB, HRT_ELF64, HRT_MBOOT2, HRT_MBOOT64 } hrt_type;
 
@@ -192,6 +194,10 @@ int v3_handle_hvm_reset(struct guest_info *core);
    0x1  =>  Reboot ROS
    0x2  =>  Reboot HRT
    0x3  =>  Reboot Both
+
+   0x8  =>  Replace HRT image
+            pass in pointer (gva) and length of new image
+
    0xf  =>  Get HRT transaction state and current ROS event
             first argument is pointer to the ROS event state 
            to be filled out
index 7feeb50..6803e80 100644 (file)
@@ -295,8 +295,8 @@ int v3_setup_multiboot_core_for_boot(struct guest_info *core);
 int v3_handle_multiboot_reset(struct guest_info *core);
 
 // The following are utility functions that HVM builds on
-int      v3_parse_multiboot_header(struct v3_cfg_file *file, mb_data_t *result);
-int      v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, struct v3_cfg_file *file, 
+int      v3_parse_multiboot_header(void *data, uint64_t len, mb_data_t *result);
+int      v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, void *data, uint64_t len,
                                   void *base, uint64_t limit);
 // The multiboot table is prepared from the perspective of the given
 // core - this allows it to be generated appropriately for ROS and HRT cores
index ff5b34f..3818663 100644 (file)
@@ -104,6 +104,7 @@ static int hvm_hcall_handler(struct guest_info * core , hcall_id_t hcall_id, voi
     uint64_t bitness = core->vm_regs.rbx;
     uint64_t a1 = core->vm_regs.rcx;
     uint64_t a2 = core->vm_regs.rdx;
+    uint64_t a3 = core->vm_regs.rsi;
     struct v3_vm_hvm *h = &core->vm_info->hvm_state;
 
 
@@ -155,6 +156,40 @@ static int hvm_hcall_handler(struct guest_info * core , hcall_id_t hcall_id, voi
            }
            break;
            
+       case 0x8: // replace HRT image
+           // a2 = gva of image
+           // a3 = size of image
+           PrintDebug(core->vm_info,core,"hvm: request replacement HRT image addr=0x%llx size=0x%llx\n",a2,a3);
+
+           if (h->hrt_image) { 
+               // delete old
+               V3_VFree(h->hrt_image);
+               h->hrt_image = 0;
+           }
+
+           h->hrt_image = V3_VMalloc(a3);
+
+           if (!(h->hrt_image)) {
+               PrintError(core->vm_info,core, "hvm: failed to allocate space for replacement image\n");
+               core->vm_regs.rax = -1;
+           } else {
+               if (v3_read_gva_memory(core, a2, a3, (uint8_t*) h->hrt_image)!=a3) { 
+                   PrintError(core->vm_info, core, "hvm: cannot read replacement image\n");
+                   core->vm_regs.rax = -1;
+               } else {
+                   h->hrt_image_size = a3; 
+                   core->vm_regs.rax = 0;
+               }
+           }
+
+           if (core->vm_regs.rax) { 
+               PrintError(core->vm_info,core,"hvm: Failed to replace HRT image\n");
+           } else {
+               PrintDebug(core->vm_info,core,"hvm: HRT image successfully replaced\n");
+           }
+
+           break;
+
        case 0xf: // get HRT state
            core->vm_regs.rax = h->trans_state;
            if (v3_write_gva_memory(core, a2, sizeof(h->ros_event), (uint8_t*) &h->ros_event)!=sizeof(h->ros_event)) { 
@@ -520,6 +555,12 @@ int v3_deinit_hvm_vm(struct v3_vm_info *vm)
 {
     PrintDebug(vm, VCORE_NONE, "hvm: HVM VM deinit\n");
 
+    if (vm->hvm_state.hrt_image) { 
+       V3_VFree(vm->hvm_state.hrt_image);
+       vm->hvm_state.hrt_image=0;
+       vm->hvm_state.hrt_image_size=0;
+    }
+
     v3_remove_hypercall(vm,HVM_HCALL);
 
     if (vm->hvm_state.comm_page_hpa) { 
@@ -1346,21 +1387,26 @@ static int configure_hrt(struct v3_vm_info *vm, mb_data_t *mb)
 
 }
 
-static int setup_mb_kernel_hrt(struct v3_vm_info *vm)
+static int setup_mb_kernel_hrt(struct v3_vm_info *vm, void *data, uint64_t size)
 {
     mb_data_t mb;
 
-    if (v3_parse_multiboot_header(vm->hvm_state.hrt_file,&mb)) { 
+    if (v3_parse_multiboot_header(data, size, &mb)) { 
        PrintError(vm,VCORE_NONE, "hvm: failed to parse multiboot kernel header\n");
        return -1;
     }
 
+    if (!mb.mb64_hrt) { 
+       PrintError(vm,VCORE_NONE,"hvm: invalid HRT - there is no MB64_HRT tag\n");
+       return -1;
+    }
+
     if (configure_hrt(vm,&mb)) {
        PrintError(vm,VCORE_NONE, "hvm: cannot configure HRT\n");
        return -1;
     }
     
-    if (v3_write_multiboot_kernel(vm,&mb,vm->hvm_state.hrt_file,
+    if (v3_write_multiboot_kernel(vm,&mb,data,size,
                                  (void*)vm->hvm_state.first_hrt_gpa,
                                  vm->mem_size-vm->hvm_state.first_hrt_gpa)) {
        PrintError(vm,VCORE_NONE, "hvm: failed to write multiboot kernel into memory\n");
@@ -1382,11 +1428,23 @@ static int setup_mb_kernel_hrt(struct v3_vm_info *vm)
 
 static int setup_hrt(struct v3_vm_info *vm)
 {
-    if (is_elf(vm->hvm_state.hrt_file->data,vm->hvm_state.hrt_file->size) && 
-       find_mb_header(vm->hvm_state.hrt_file->data,vm->hvm_state.hrt_file->size)) { 
+    void *data;
+    uint64_t size;
+
+    // If the ROS has installed an image, it takes priority
+    if (vm->hvm_state.hrt_image) { 
+       data = vm->hvm_state.hrt_image;
+       size = vm->hvm_state.hrt_image_size;
+    } else {
+       data = vm->hvm_state.hrt_file->data;
+       size = vm->hvm_state.hrt_file->size;
+    }
+       
+    if (is_elf(data,size) &&
+       find_mb_header(data,size)) {
 
        PrintDebug(vm,VCORE_NONE,"hvm: appears to be a multiboot kernel\n");
-       if (setup_mb_kernel_hrt(vm)) { 
+       if (setup_mb_kernel_hrt(vm,data,size)) { 
            PrintError(vm,VCORE_NONE,"hvm: multiboot kernel setup failed\n");
            return -1;
        } 
index 611ccaa..0959c48 100644 (file)
@@ -181,7 +181,7 @@ static int checksum4_ok(uint32_t *data, uint64_t size)
     return sum==0;
 }
 
-static int parse_multiboot_kernel(uint8_t *data, uint64_t size, mb_data_t *mb)
+int v3_parse_multiboot_header(void *data, uint64_t size, mb_data_t *mb)
 {
     uint64_t i;
 
@@ -327,11 +327,6 @@ static int parse_multiboot_kernel(uint8_t *data, uint64_t size, mb_data_t *mb)
 }
 
 
-int v3_parse_multiboot_header(struct v3_cfg_file *file, mb_data_t *result)
-{
-    return parse_multiboot_kernel(file->data,file->size,result);
-}
-
 
 #define APIC_BASE     0xfee00000
 #define IOAPIC_BASE   0xfec00000
@@ -541,11 +536,11 @@ uint64_t v3_build_multiboot_table(struct guest_info *core, uint8_t *dest, uint64
 }
 
 
-int v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, struct v3_cfg_file *file,
+int v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, void *data, uint64_t len,
                              void *base, uint64_t limit)
 {
     uint32_t offset=0;
-    uint32_t header_offset = (uint32_t) ((uint64_t)(mb->header) - (uint64_t)(file->data));
+    uint32_t header_offset = (uint32_t) ((uint64_t)(mb->header) - (uint64_t)(data));
     uint32_t size;
 
     if (!mb->addr || !mb->entry) { 
@@ -563,15 +558,15 @@ int v3_write_multiboot_kernel(struct v3_vm_info *vm, mb_data_t *mb, struct v3_cf
     offset = header_offset - (mb->addr->header_addr - mb->addr->load_addr);
     size = mb->addr->load_end_addr - mb->addr->load_addr;
     
-    if (size != file->size-offset) { 
-       V3_Print(vm,VCORE_NONE,"multiboot: strange: size computed as %u, but file->size-offset = %llu\n",size,file->size-offset);
+    if (size != len-offset) { 
+       V3_Print(vm,VCORE_NONE,"multiboot: strange: size computed as %u, but len-offset = %llu\n",size,len-offset);
     }
 
     // We are trying to do as little ELF loading here as humanly possible
     v3_write_gpa_memory(&vm->cores[0],
                        (addr_t)(mb->addr->load_addr),
                        size,
-                       file->data+offset);
+                       data+offset);
 
     PrintDebug(vm,VCORE_NONE,
               "multiboot: wrote 0x%llx bytes starting at offset 0x%llx to %p\n",
@@ -615,11 +610,11 @@ static int setup_multiboot_kernel(struct v3_vm_info *vm)
     } else {
        if (find_mb_header(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size)) { 
            PrintDebug(vm,VCORE_NONE,"multiboot: appears to be a multiboot kernel\n");
-           if (v3_parse_multiboot_header(vm->mb_state.mb_file,&vm->mb_state.mb_data)) { 
+           if (v3_parse_multiboot_header(vm->mb_state.mb_file->data,vm->mb_state.mb_file->size,&vm->mb_state.mb_data)) { 
                PrintError(vm,VCORE_NONE,"multiboot: cannot parse multiboot kernel header\n");
                return -1;
            }
-           if (v3_write_multiboot_kernel(vm, &(vm->mb_state.mb_data),vm->mb_state.mb_file,base,limit)) { 
+           if (v3_write_multiboot_kernel(vm, &(vm->mb_state.mb_data),vm->mb_state.mb_file->data,vm->mb_state.mb_file->size,base,limit)) { 
                PrintError(vm,VCORE_NONE,"multiboot: multiboot kernel setup failed\n");
                return -1;
            }