--- /dev/null
+.section .text
+
+.extern __v3_hvm_ros_signal_handler
+
+/*
+ This is the entry point for signal dispatch
+ from the VMM.
+
+ VMM invokes this stub when a user signal is
+ raised and: the relevant address space
+ is active, and we are at user-level.
+ It will be invoked on exactly one core,
+ although there are no guarantees on which one.
+
+*/
+
+
+#define GPR_SAVE() \
+ pushq %rbp ; \
+ pushq %rax ; \
+ pushq %rbx ; \
+ pushq %rcx ; \
+ pushq %rdx ; \
+ pushq %rsi ; \
+ pushq %rdi ; \
+ pushq %r8 ; \
+ pushq %r9 ; \
+ pushq %r10 ; \
+ pushq %r11 ; \
+ pushq %r12 ; \
+ pushq %r13 ; \
+ pushq %r14 ; \
+ pushq %r15 ; \
+
+#define GPR_LOAD() \
+ popq %r15 ; \
+ popq %r14 ; \
+ popq %r13 ; \
+ popq %r12 ; \
+ popq %r11 ; \
+ popq %r10 ; \
+ popq %r9 ; \
+ popq %r8 ; \
+ popq %rdi ; \
+ popq %rsi ; \
+ popq %rdx ; \
+ popq %rcx ; \
+ popq %rbx ; \
+ popq %rax ; \
+ popq %rbp ;
+
+
+/*
+ The VMM puts us here with what looks like a long mode
+ interrupt dispatch, but it's from CPL 3 to CPL 3 and
+ it's not done as an interrupt injection per se, so
+ we can be interrupted, and deliverable interrupts
+ automatically prioritize over us.
+
+ 48bitsblank | return SS (16 bits)
+ Return RSP
+ Return RFLAGS
+ 48bitsblank | return CS (16 bits)
+ Return RIP
+ ERROR CODE (HVM-specific non-zero number here) <- RSP on entry
+
+ We then need simply to do this:
+
+ save regs
+ call the handler (if installed)
+ restore regs
+ iret
+
+*/
+
+.global __v3_hvm_ros_signal_handler_stub
+__v3_hvm_ros_signal_handler_stub:
+ GPR_SAVE()
+ movabs __v3_hvm_ros_signal_handler, %rax
+ testq %rax, %rax
+ jz skip_handler
+ movq 120(%rsp), %rdi /* error code becomes argument */
+ callq *%rax
+skip_handler:
+ GPR_LOAD()
+ addq $8, %rsp /* nuke the error code */
+ iretq
+