ARM
GIC = ARM Generic Interrupt Controller
The GICv3 architecture defines a virtual GIC (vGIC) interface for each CPU that provides virtual interrupt management capabilities to a hypervisor. When virtual interrupts are enabled, all physical interrupts are routed to EL2.
Before the target VM is scheduled on a physical CPU, the hypervisor signals for a virtual interrupt to be delivered once execution has returned to EL1. If a VM attempts to configure the GIC distributor through the MMIO interface, the second stage of translation will trap execution into EL2 where the hypervisor can emulate the operation.
VM accesses to the GIC system registers are routed to a set of virtual system registers, which control virtual interrupt delivery. During a virtual CPU context switch, the hypervisor must save the writable virtual system register state, the state of any pending virtual interrupts, and the VM specific virtual interrupt configuration.

XEN
Interrupts are virtualized by mapping them to event channels, which are delivered asynchronously to the target domain using a callback supplied via the set_callbacks() hypercall.
- Event channels are the basic primitive provided by Xen for event notifications.
- An event is the Xen equivalent of a hardware interrupt.
- Notifications are received by a guest via an upcall from Xen, indicating when an event arrives (setting the bit)
https://wiki.xenproject.org/wiki/Event_Channel_Internals
There are four kinds of events which can be mapped into event channels in Linux:
- Inter-domain notifications. This includes all the virtual device events, since they’re driven by front-ends in another domain (typically dom0).
- VIRQs, typically used for timers. These are per-cpu events.
- IPIs.
- PIRQs - Hardware interrupts.
Events are stored in a bitmap shared between guest and hypervisor. Several tricks such as N-level search path and per-cpu mask are used to speed up search process.
https://mirage.io/docs/xen-events
![[Untitled 1105.png|https://www.slideshare.net/xen_com_mgr/linux-pv-on-hvm]]
Remember that on ARM, exceptions/interrupts have their own handlers defined on the “Exception Vector Table”, pointed out by VBAR. Memory/Instruction trapping generates exceptions:
https://developer.arm.com/documentation/100933/0100/AArch64-Exception-and-Interrupt-Handling
LibVMI
Specifics:
--------------------------------------------------------------------------------
In the case of Xen, a ring buffer is provided to hold VM events for consumption
by an external service which accesses this buffer from an observation VM.
Within its Xen driver, LibVMI enables event delivery when the initialization
mode has the VMI_INIT_EVENTS mode set:
vmi_init_complete(&vmi, vm_name, VMI_INIT_DOMAINNAME | VMI_INIT_EVENTS,
NULL, VMI_CONFIG_GLOBAL_FILE_ENTRY, NULL, NULL))
Using LibVMI events is possible in four general steps:
1) The allocation of an event structure to configure delivery of
events (frequency, synchronous vs asynchronous, access mode, callback).
Specific options for configuration are event-specific.
2) The registration of this event with LibVMI via vmi_register_event().
Upon receipt of an event matching one configured via vmi_event_t,
it is passed to the configured callback.
3) Invocation of the LibVMI function vmi_events_listen() which checks for
incoming events and, if found, passes each to the appropriate callback.
The event passed to its registered callback is augmented with
information aiding in its interpretation (e.g., the page upon which
a write operation was invoked, the VCPU used to execute an
instruction, and/or the relevant instruction pointer.
4) When use of the events subsystem has completed, unregistration of
an individual event must be performed via vmi_clear_event or
implicitly via vmi_destroy at program exit.
An example vmi_event_t allocation and subsequent configuration is shown below.
For full demonstrations, please consult the examples/ directory within the
LibVMI source tree.
vmi_event_t *cr3_write_event = calloc(1, sizeof(vmi_event_t));
cr3_write_event->version = VMI_EVENTS_VERSION;
cr3_write_event->type = VMI_EVENT_REGISTER;
cr3_write_event->reg_event.reg = CR3;
cr3_write_event->reg_event.in_access = VMI_REGACCESS_W;
cr3_write_event->callback = cr3_change_cb;
Where cr3_change_cb is a pointer to a function with the prototype:
void callback_name(vmi_instance_t vmi, vmi_event_t *event)
All event callbacks must use this prototype; its return is not inspected
by the vmi_events_listen() after invocation.
After creation, an event must be registered:
vmi_register_event(vmi, cr3_write_event);
Next, the library user must await event delivery (exiting if interrupted
by a signal or other error/exit condition):
while(!interrupted){
vmi_events_listen(vmi, 1000);
}
Finally, the library user MUST call vmi_destroy(vmi) upon exit. While this
action will cleanly unregister for all events, it is also recommended that
the library user call vmi_clear_event for each event structure when event
listening has concluded. This operation will unregister for the given event
type and remove the pointer to the event from tracking structures within
LibVMI. For some event types, vmi_event_clear may be required within the
callback to ensure VM execution continues (though the same event structure
can be re-used and re-registered as needed).
NOTE:
All memory management of vmi_event_t structures is the responsibility
of the library user - LibVMI only tracks pointers to these structures.
---libVMI supports the track of the following events:
#define VMI_EVENT_INVALID 0
#define VMI_EVENT_MEMORY 1 /**< Read/write/execute on a region of memory */
#define VMI_EVENT_REGISTER 2 /**< Read/write of a specific register */
#define VMI_EVENT_SINGLESTEP 3 /**< Instructions being executed on a set of VCPUs */
#define VMI_EVENT_INTERRUPT 4 /**< Interrupts being delivered */
#define VMI_EVENT_GUEST_REQUEST 5 /**< Guest-requested event */
#define VMI_EVENT_CPUID 6 /**< CPUID event */
#define VMI_EVENT_DEBUG_EXCEPTION 7 /**< Debug exception event */
#define VMI_EVENT_PRIVILEGED_CALL 8 /**< Privileged call (ie. SMC on ARM) */
#define VMI_EVENT_DESCRIPTOR_ACCESS 9 /**< A descriptor table register was accessed */
#define VMI_EVENT_FAILED_EMULATION 10 /**< Emulation failed when requested by VMI_EVENT_RESPONSE_EMULATE */
#define VMI_EVENT_DOMAIN_WATCH 11 /**< Watch create/destroy events */
#define VMI_EVENT_VMEXIT 12 /**< VMEXIT */Used by:
vmi_events_listen - xen_events_listen
drakvuf_loop - drakvuf_vmi_event_callback