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 0x2f: // function exec done
+ case 0x28: // setup for synchronous operation (ROS->HRT)
+ case 0x29: // teardown for synchronous operation (ROS->HRT)
+ if (v3_is_hvm_hrt_core(core)) {
+ PrintError(core->vm_info,core,"hvm: %ssynchronization invocation not supported from HRT core\n",a1==0x29 ? "de" : "");
+ core->vm_regs.rax = -1;
+ } else {
+ if (ENFORCE_STATE_MACHINE &&
+ ((a1==0x28 && h->trans_state!=HRT_IDLE) || (a1==0x29 && h->trans_state!=HRT_SYNC))) {
+ PrintError(core->vm_info,core, "hvm: cannot invoke %ssynchronization in state %d\n",a1==0x29 ? "de" : "", h->trans_state);
+ core->vm_regs.rax = -1;
+ } else {
+ uint64_t *page = (uint64_t *) h->comm_page_hva;
+ uint64_t first, last, cur;
+
+ PrintDebug(core->vm_info,core, "hvm: invoke %ssynchronization on address %p\n",a1==0x29 ? "de" : "",(void*)a2);
+ page[0] = a1;
+ page[1] = a2;
+
+ first=last=h->first_hrt_core; // initially we will sync only with BSP
+
+ core->vm_regs.rax = 0;
+
+ h->trans_count = last-first+1;
+
+ for (cur=first;cur<=last;cur++) {
+
+#if USE_UPCALL_MAGIC_PF
+ PrintDebug(core->vm_info,core,"hvm: injecting magic #PF into core %llu\n",cur);
+ core->vm_info->cores[cur].ctrl_regs.cr2 = UPCALL_MAGIC_ADDRESS;
+ if (v3_raise_exception_with_error(&core->vm_info->cores[cur],
+ PF_EXCEPTION,
+ UPCALL_MAGIC_ERROR)) {
+ PrintError(core->vm_info,core, "hvm: cannot inject HRT #PF to core %llu\n",cur);
+ core->vm_regs.rax = -1;
+ break;
+ }
+#else
+ PrintDebug(core->vm_info,core,"hvm: injecting SW intr 0x%u into core %llu\n",h->hrt_int_vector,cur);
+ if (v3_raise_swintr(&core->vm_info->cores[cur],h->hrt_int_vector)) {
+ PrintError(core->vm_info,core, "hvm: cannot inject HRT interrupt to core %llu\n",cur);
+ core->vm_regs.rax = -1;
+ break;
+ }
+#endif
+ // Force core to exit now
+ v3_interrupt_cpu(core->vm_info,core->vm_info->cores[cur].pcpu_id,0);
+
+ }
+ if (core->vm_regs.rax==0) {
+ if (a1==0x28) {
+ h->trans_state = HRT_SYNCSETUP;
+ } else {
+ h->trans_state = HRT_SYNCTEARDOWN;
+ }
+ } else {
+ PrintError(core->vm_info,core,"hvm: in inconsistent state due to HRT call failure\n");
+ h->trans_state = HRT_IDLE;
+ h->trans_count = 0;
+ }
+ }
+ }
+ break;
+
+ case 0x2f: // function exec or sync done
if (v3_is_hvm_ros_core(core)) {
- PrintError(core->vm_info,core, "hvm: request for exec done from ROS core\n");
+ PrintError(core->vm_info,core, "hvm: request for exec or sync done from ROS core\n");
core->vm_regs.rax=-1;
} else {
- if (ENFORCE_STATE_MACHINE && h->trans_state!=HRT_CALL && h->trans_state!=HRT_PARCALL) {
- PrintError(core->vm_info,core,"hvm: function completion when not in HRT_CALL or HRT_PARCALL state\n");
+ if (ENFORCE_STATE_MACHINE &&
+ h->trans_state!=HRT_CALL &&
+ h->trans_state!=HRT_PARCALL &&
+ h->trans_state!=HRT_SYNCSETUP &&
+ h->trans_state!=HRT_SYNCTEARDOWN) {
+ PrintError(core->vm_info,core,"hvm: function or sync completion when not in HRT_CALL, HRT_PARCALL, HRT_SYNCSETUP, or HRT_SYNCTEARDOWN state\n");
core->vm_regs.rax=-1;
} else {
uint64_t one=1;
- PrintDebug(core->vm_info,core, "hvm: function complete\n");
+ PrintDebug(core->vm_info,core, "hvm: function or sync complete\n");
if (__sync_fetch_and_sub(&h->trans_count,one)==1) {
// last one, switch state
- h->trans_state=HRT_IDLE;
- PrintDebug(core->vm_info,core, "hvm: function complete - back to idle\n");
+ if (h->trans_state==HRT_SYNCSETUP) {
+ h->trans_state=HRT_SYNC;
+ PrintDebug(core->vm_info,core, "hvm: function complete - now synchronous\n");
+ } else {
+ h->trans_state=HRT_IDLE;
+ }
}
core->vm_regs.rax=0;
}
{
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) {
int v3_is_hvm_ros_mem_gpa(struct v3_vm_info *vm, addr_t gpa)
{
if (vm->hvm_state.is_hvm) {
- return gpa>=0 && gpa<vm->hvm_state.first_hrt_gpa;
+ return gpa<vm->hvm_state.first_hrt_gpa;
} else {
return 1;
}
}
-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;
}