diff options
-rw-r--r-- | hw/hyperv/hyperv.c | 32 | ||||
-rw-r--r-- | include/hw/hyperv/hyperv.h | 4 |
2 files changed, 36 insertions, 0 deletions
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 654ca4ffc5..2b0e593bf9 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -12,6 +12,7 @@ #include "qapi/error.h" #include "exec/address-spaces.h" #include "sysemu/kvm.h" +#include "qemu/bitops.h" #include "hw/hyperv/hyperv.h" typedef struct SynICState { @@ -310,6 +311,37 @@ static void sint_ack_handler(EventNotifier *notifier) aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh, sint_route); } +/* + * Set given event flag for a given sint on a given vcpu, and signal the sint. + */ +int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno) +{ + int ret; + SynICState *synic = sint_route->synic; + unsigned long *flags, set_mask; + unsigned set_idx; + + if (eventno > HV_EVENT_FLAGS_COUNT) { + return -EINVAL; + } + if (!synic->enabled || !synic->event_page_addr) { + return -ENXIO; + } + + set_idx = BIT_WORD(eventno); + set_mask = BIT_MASK(eventno); + flags = synic->event_page->slot[sint_route->sint].flags; + + if ((atomic_fetch_or(&flags[set_idx], set_mask) & set_mask) != set_mask) { + memory_region_set_dirty(&synic->event_page_mr, 0, + sizeof(*synic->event_page)); + ret = hyperv_sint_route_set_sint(sint_route); + } else { + ret = 0; + } + return ret; +} + HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint, HvSintMsgCb cb, void *cb_data) { diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h index 82d561fc88..757c85eb8f 100644 --- a/include/hw/hyperv/hyperv.h +++ b/include/hw/hyperv/hyperv.h @@ -34,6 +34,10 @@ int hyperv_sint_route_set_sint(HvSintRoute *sint_route); * with the @sint_route; until then no more messages are accepted. */ int hyperv_post_msg(HvSintRoute *sint_route, struct hyperv_message *msg); +/* + * Set event flag @eventno, and signal the SINT if the flag has changed. + */ +int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno); static inline uint32_t hyperv_vp_index(CPUState *cs) { |