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;
}
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)) {
}
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);
{
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) {
}
-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");
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;
}
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;
+ }
+ }
+}
+
+
+