VMM: Userspace msr emulation changes to handle ICR writes.

Change-Id: I1a5484025a11749d2067ee72cb0c8ffec3055db8
Signed-off-by: Gan Shun Lim <ganshun@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/user/vmm/vmxmsr.c b/user/vmm/vmxmsr.c
index db8afce..e0b9175 100644
--- a/user/vmm/vmxmsr.c
+++ b/user/vmm/vmxmsr.c
@@ -28,6 +28,7 @@
 #include <vmm/virtio_ids.h>
 #include <vmm/virtio_config.h>
 #include <vmm/sched.h>
+#include <vmm/vmm.h>
 #include <ros/arch/trapframe.h>
 
 struct emmsr {
@@ -48,7 +49,7 @@
 static inline void write_msr(uint32_t reg, uint64_t val)
 {
 	asm volatile("wrmsr" : : "d"((uint32_t)(val >> 32)),
-	                         "a"((uint32_t)(val & 0xFFFFFFFF)), 
+	                         "a"((uint32_t)(val & 0xFFFFFFFF)),
 	                         "c"(reg));
 }
 
@@ -233,6 +234,38 @@
 			((uint32_t *)(gpci->vapic_addr))[apic_offset] =
 			                                       (uint32_t)(vm_tf->tf_rax);
 		else {
+			/* We currently only handle physical destinations.
+			 * TODO(ganshun): Support logical destinations if needed. */
+			struct virtual_machine *vm = gth_to_vm(vm_thread);
+			uint32_t destination = vm_tf->tf_rdx & 0xffffffff;
+			uint8_t vector = vm_tf->tf_rax & 0xff;
+			uint8_t type = (vm_tf->tf_rax >> 8) & 0x7;
+
+			if (destination >= vm->nr_gpcs && destination != 0xffffffff) {
+				fprintf(stderr, "UNSUPPORTED DESTINATION 0x%02x!\n",
+						destination);
+				return SHUTDOWN_UNHANDLED_EXIT_REASON;
+			}
+			switch (type) {
+				case 0:
+					/* Send IPI */
+					if (destination == 0xffffffff) {
+						/* Broadcast */
+						for (int i = 0; i < vm->nr_gpcs; i++)
+							vmm_interrupt_guest(vm, i, vector);
+					} else {
+						/* Send individual IPI */
+						vmm_interrupt_guest(vm, destination, vector);
+					}
+					break;
+				default:
+					/* This is not a terrible error, we don't currently support
+					 * SIPIs and INIT IPIs. The guest is allowed to try to make
+					 * them for now even though we don't do anything. */
+					fprintf(stderr, "Unsupported IPI type %d!\n", type);
+					break;
+			}
+
 			((uint32_t *)(gpci->vapic_addr))[apic_offset] =
 			                                       (uint32_t)(vm_tf->tf_rax);
 			((uint32_t *)(gpci->vapic_addr))[apic_offset + 1] =