diff --git a/include/system/penguin.h b/include/system/penguin.h index e4fdb54ca5..a7eaecba0f 100644 --- a/include/system/penguin.h +++ b/include/system/penguin.h @@ -21,6 +21,11 @@ typedef int (*kvm_penguin_hypercall_cb_t)(CPUState *cs, uint64_t nr, uint64_t a4, uint64_t a5, uint64_t *ret); +typedef uint64_t (*penguin_mmio_read_cb_t)(uint64_t addr, unsigned size, + void *opaque); +typedef void (*penguin_mmio_write_cb_t)(uint64_t addr, uint64_t data, + unsigned size, void *opaque); + void set_penguin_guest_hypercall_callback(penguin_guest_hypercall_cb_t cb, void *opaque); void set_kvm_penguin_hypercall_callback(kvm_penguin_hypercall_cb_t cb); @@ -31,4 +36,10 @@ bool penguin_handle_guest_hypercall(CPUState *cs, uint64_t nr, uint64_t a4, uint64_t a5, uint64_t *ret); +int penguin_qemu_add_mmio_region(uint64_t base, uint64_t size, + const char *name, + penguin_mmio_read_cb_t read_cb, + penguin_mmio_write_cb_t write_cb, + void *opaque); + #endif /* QEMU_SYSTEM_PENGUIN_H */ diff --git a/scripts/penguin-cffi-gen.py b/scripts/penguin-cffi-gen.py index 55cbfa6dee..d4b2f9c49a 100644 --- a/scripts/penguin-cffi-gen.py +++ b/scripts/penguin-cffi-gen.py @@ -74,6 +74,10 @@ typedef int (*kvm_penguin_after_guest_init_cb_t)(MachineState *machine, void *opaque); +typedef uint64_t (*penguin_mmio_read_cb_t)(uint64_t addr, unsigned size, + void *opaque); +typedef void (*penguin_mmio_write_cb_t)(uint64_t addr, uint64_t data, + unsigned size, void *opaque); extern MachineState *current_machine; extern int (*qemu_main)(void); @@ -105,6 +109,11 @@ uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5, uint64_t *ret); +int penguin_qemu_add_mmio_region(uint64_t base, uint64_t size, + const char *name, + penguin_mmio_read_cb_t read_cb, + penguin_mmio_write_cb_t write_cb, + void *opaque); """ diff --git a/system/penguin.c b/system/penguin.c index 0079d1f70a..b345b58099 100644 --- a/system/penguin.c +++ b/system/penguin.c @@ -1,5 +1,16 @@ #include "qemu/osdep.h" #include "system/penguin.h" +#include "system/address-spaces.h" +#include "system/memory.h" + +typedef struct PenguinMmioRegion { + MemoryRegion mr; + MemoryRegionOps ops; + penguin_mmio_read_cb_t read_cb; + penguin_mmio_write_cb_t write_cb; + void *opaque; + char *name; +} PenguinMmioRegion; static penguin_guest_hypercall_cb_t penguin_guest_hypercall_cb; static void *penguin_guest_hypercall_opaque; @@ -38,3 +49,59 @@ bool penguin_handle_guest_hypercall(CPUState *cs, uint64_t nr, return false; } + +static uint64_t penguin_mmio_read(void *opaque, hwaddr addr, unsigned size) +{ + PenguinMmioRegion *region = opaque; + + if (!region->read_cb) { + return 0; + } + + return region->read_cb(addr, size, region->opaque); +} + +static void penguin_mmio_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) +{ + PenguinMmioRegion *region = opaque; + + if (!region->write_cb) { + return; + } + + region->write_cb(addr, data, size, region->opaque); +} + +int __attribute__((visibility("default"))) +penguin_qemu_add_mmio_region(uint64_t base, uint64_t size, + const char *name, + penguin_mmio_read_cb_t read_cb, + penguin_mmio_write_cb_t write_cb, + void *opaque) +{ + PenguinMmioRegion *region; + + if (!size || !name || (!read_cb && !write_cb)) { + return -1; + } + + region = g_new0(PenguinMmioRegion, 1); + region->read_cb = read_cb; + region->write_cb = write_cb; + region->opaque = opaque; + region->name = g_strdup(name); + region->ops.read = penguin_mmio_read; + region->ops.write = penguin_mmio_write; + region->ops.endianness = DEVICE_NATIVE_ENDIAN; + region->ops.valid.min_access_size = 1; + region->ops.valid.max_access_size = 8; + region->ops.impl.min_access_size = 1; + region->ops.impl.max_access_size = 8; + + memory_region_init_io(®ion->mr, NULL, ®ion->ops, region, + region->name, size); + memory_region_add_subregion_overlap(get_system_memory(), base, + ®ion->mr, -1000); + return 0; +} diff --git a/system/vl.c b/system/vl.c index d4fe5c57e6..45be92c202 100644 --- a/system/vl.c +++ b/system/vl.c @@ -230,10 +230,17 @@ static void kvm_penguin_run_after_guest_init_callback(void) * This hook runs after board and CLI device construction, but before * qemu_machine_creation_done() closes the normal machine construction * window. Hold BQL so embedders can safely mutate QEMU global state. + * qemu_init() may already be running with BQL held, so avoid taking it + * recursively in debug builds. */ - BQL_LOCK_GUARD(); - ret = kvm_penguin_after_guest_init_cb(current_machine, - kvm_penguin_after_guest_init_opaque); + if (bql_locked()) { + ret = kvm_penguin_after_guest_init_cb( + current_machine, kvm_penguin_after_guest_init_opaque); + } else { + BQL_LOCK_GUARD(); + ret = kvm_penguin_after_guest_init_cb( + current_machine, kvm_penguin_after_guest_init_opaque); + } if (ret) { error_report("Penguin after guest init callback failed: %d", ret); exit(1);