X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmm_hvm.c;h=43e7c332a0efd87f01a00b35a5c5bb49b4d48a57;hb=4e43946f01f687361197dc9571b7df02ae20de30;hp=43a86724f65effc2e5ec99d1ad7586c3be7219be;hpb=4b7f19c51325601d7e7569e6101c7bfcdf984ef7;p=palacios.git diff --git a/palacios/src/palacios/vmm_hvm.c b/palacios/src/palacios/vmm_hvm.c index 43a8672..43e7c33 100644 --- a/palacios/src/palacios/vmm_hvm.c +++ b/palacios/src/palacios/vmm_hvm.c @@ -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,11 +156,70 @@ 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)) { + PrintError(core->vm_info, core, "hvm: cannot write back ROS event state to %p - continuing\n",(void*)a2); + } //PrintDebug(core->vm_info,core,"hvm: get HRT transaction state 0x%llx\n",core->vm_regs.rax); break; + case 0x10: + PrintDebug(core->vm_info, core, "hvm: ROS event request\n"); + if (h->ros_event.event_type!=ROS_NONE) { + PrintError(core->vm_info, core, "hvm: ROS event is already in progress\n"); + core->vm_regs.rax = -1; + } else { + if (v3_read_gva_memory(core, a2, sizeof(h->ros_event), (uint8_t*)&h->ros_event)!=sizeof(h->ros_event)) { + PrintError(core->vm_info, core, "hvm: cannot read ROS event from %p\n",(void*)a2); + core->vm_regs.rax = -1; + } else { + core->vm_regs.rax = 0; + } + } + + break; + + case 0x1f: + PrintDebug(core->vm_info, core, "hvm: completion of ROS event (rc=0x%llx)\n",a2); + h->ros_event.event_type=ROS_NONE; + h->ros_event.last_ros_event_result = a2; + break; + case 0x20: // invoke function (ROS->HRT) case 0x21: // invoke parallel function (ROS->HRT) if (v3_is_hvm_hrt_core(core)) { @@ -384,6 +444,40 @@ static int hvm_hcall_handler(struct guest_info * core , hcall_id_t hcall_id, voi } break; + + case 0x40: // install or remove signal handler + if (v3_is_hvm_hrt_core(core)) { + PrintError(core->vm_info,core, "hvm: HRT cannot install signal handler...\n"); + core->vm_regs.rax=-1; + } else { + PrintDebug(core->vm_info,core,"hvm: install signal handler for CR3=%p, handler=%p, stack=%p\n",(void*)core->ctrl_regs.cr3, (void*)a2, (void*)a3); + if (h->ros_signal.code) { + PrintError(core->vm_info,core,"hvm: signal is pending...\n"); + core->vm_regs.rax=-1; + } else { + if ((a2 || a3) && (h->ros_signal.handler || h->ros_signal.stack)) { + PrintError(core->vm_info,core,"hvm: attempt to replace existing handler without removing it first\n"); + core->vm_regs.rax=-1; + } else { + // actually make the change + h->ros_signal.handler=a2; + h->ros_signal.stack=a3; + h->ros_signal.cr3=core->ctrl_regs.cr3; + core->vm_regs.rax=0; + + // test by signalling back a hello + // if (a2 && a3) { + // v3_hvm_signal_ros(core->vm_info,0xf00d); + //} + } + } + } + break; + + case 0x41: // raise signal in the ROS from HRT or ROS + PrintDebug(core->vm_info,core,"hvm: HRT raises signal code=0x%llx\n", a2); + core->vm_regs.rax = v3_hvm_signal_ros(core->vm_info,a2); + break; default: PrintError(core->vm_info,core,"hvm: unknown hypercall %llx\n",a1); @@ -495,6 +589,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) { @@ -563,7 +663,7 @@ uint32_t v3_get_hvm_hrt_cores(struct v3_vm_info *vm) int v3_is_hvm_ros_mem_gpa(struct v3_vm_info *vm, addr_t gpa) { if (vm->hvm_state.is_hvm) { - return gpa>=0 && gpahvm_state.first_hrt_gpa; + return gpahvm_state.first_hrt_gpa; } else { return 1; } @@ -1321,21 +1421,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"); @@ -1357,11 +1462,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; } @@ -1722,3 +1839,111 @@ int v3_handle_hvm_reset(struct guest_info *core) return 0; } } + + +int v3_handle_hvm_entry(struct guest_info *core) +{ + if (!core->vm_info->hvm_state.is_hvm // not relevant to non-HVM + || core->hvm_state.is_hrt // not relevant to an HRT in an HVM + || !core->vm_info->hvm_state.ros_signal.code) { // not relevant if there is no code to inject + + // Note that above check for code could race with a writer, but + // if that happens, we'll simply inject at the next opportunity instead of + // this one (see below for atomic update) + return 0; + } else { + struct v3_ros_signal *s = &core->vm_info->hvm_state.ros_signal; + + // HVM ROS + if (! (s->handler && // handler installed + s->cr3 && // process installed + s->stack && // stack installed + core->cpl == 3 && // user mode + core->ctrl_regs.cr3 == s->cr3) // right process active + ) { + // Cannot inject at this time + return 0; + } else { + // We can inject now, let's atomically see if we have something + // and commit to doing it if we do + uint64_t code; + + // Get code, reset to allow next one + code = __sync_fetch_and_and(&(s->code), 0); + + if (!code) { + // nothing to do after all + return 0; + } else { + + // actually do inject + + uint64_t rsp; + uint64_t frame[6]; + + PrintDebug(core->vm_info,core,"hvm: ROS interrupt starting with rip=%p rsp=%p\n", (void*) core->rip, (void*) core->vm_regs.rsp); + // build interrupt frame + frame[0] = code; + frame[1] = core->rip; + frame[2] = core->segments.cs.selector; // return cs + frame[3] = core->ctrl_regs.rflags; + frame[4] = core->vm_regs.rsp; + frame[5] = core->segments.ss.selector; // return ss + + rsp = (s->stack - 8) & (~0x7); // make sure we are aligned + rsp -= sizeof(frame); + + + if (v3_write_gva_memory(core,(addr_t)rsp,sizeof(frame),(uint8_t*)frame)!=sizeof(frame)) { + PrintError(core->vm_info,core,"hvm: failed to write interrupt frame\n"); + // we just lost this inject + return -1; + } + + // now make us look like we are jumping to the entry + core->rip = s->handler; + core->vm_regs.rsp = rsp; + + PrintDebug(core->vm_info,core,"hvm: ROS frame is 0x%llx|0x%llx|0x%llx|0x%llx|0x%llx|0x%llx and and on entry rip=%p and rsp=%p\n", frame[0],frame[1],frame[2],frame[3],frame[4],frame[5],(void*) core->rip, (void*) core->vm_regs.rsp); + + // and we should be good to go + return 0; + } + } + } +} + +int v3_handle_hvm_exit(struct guest_info *core) +{ + // currently nothing + return 0; +} + +int v3_hvm_signal_ros(struct v3_vm_info *vm, uint64_t code) +{ + struct v3_ros_signal *s = &vm->hvm_state.ros_signal; + + if (!code) { + PrintError(vm,VCORE_NONE,"hvm: cannot signal ros with code zero\n"); + return -1; + } + + // handler, etc, must exist + if (!s->handler || !s->stack) { + PrintError(vm,VCORE_NONE,"hvm: cannot signal ros with no installed handler\n"); + return -1; + } else { + // we set the code only if we are idle (code 0), + // and we do so only + if (!__sync_bool_compare_and_swap(&(s->code), 0, code)) { + PrintError(vm,VCORE_NONE,"hvm: signal was already asserted\n"); + return -1; + } else { + PrintDebug(vm,VCORE_NONE,"hvm: raised signal 0x%llx to the ROS\n",code); + return 0; + } + } +} + + +