diff options
| -rw-r--r-- | MAINTAINERS | 9 | ||||
| -rw-r--r-- | block/ssh.c | 1 | ||||
| -rw-r--r-- | hw/9pfs/9p-synth.c | 52 | ||||
| -rw-r--r-- | hw/9pfs/9p-synth.h | 13 | ||||
| -rw-r--r-- | hw/9pfs/9p.c | 25 | ||||
| -rw-r--r-- | hw/9pfs/9p.h | 10 | ||||
| -rw-r--r-- | hw/9pfs/trace-events | 1 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-device.c | 8 | ||||
| -rw-r--r-- | hw/9pfs/xen-9p-backend.c | 3 | ||||
| -rw-r--r-- | hw/arm/musicpal.c | 3 | ||||
| -rw-r--r-- | hw/arm/spitz.c | 3 | ||||
| -rw-r--r-- | hw/arm/z2.c | 3 | ||||
| -rw-r--r-- | hw/audio/marvell_88w8618.c | 1 | ||||
| -rw-r--r-- | hw/audio/sb16.c | 79 | ||||
| -rw-r--r-- | hw/audio/wm8750.c | 6 | ||||
| -rw-r--r-- | hw/ipmi/ipmi_bmc_extern.c | 5 | ||||
| -rw-r--r-- | hw/ipmi/ipmi_bmc_sim.c | 58 | ||||
| -rw-r--r-- | hw/ipmi/isa_ipmi_bt.c | 12 | ||||
| -rw-r--r-- | include/hw/audio/wm8750.h | 30 | ||||
| -rw-r--r-- | include/hw/i2c/i2c.h | 9 | ||||
| -rw-r--r-- | scripts/dump-guest-memory.py | 2 | ||||
| -rw-r--r-- | tests/libqos/virtio.c | 25 | ||||
| -rw-r--r-- | tests/libqos/virtio.h | 3 | ||||
| -rwxr-xr-x | tests/qemu-iotests/200 | 2 | ||||
| -rw-r--r-- | tests/virtio-9p-test.c | 294 | ||||
| -rw-r--r-- | tests/virtio-blk-test.c | 24 | ||||
| -rw-r--r-- | tests/virtio-net-test.c | 6 | ||||
| -rw-r--r-- | tests/virtio-scsi-test.c | 3 |
28 files changed, 538 insertions, 152 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index f8deaf638c..0f952d46ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -941,6 +941,15 @@ F: tests/ahci-test.c F: tests/libqos/ahci* T: git git://github.com/jnsnow/qemu.git ide +IPMI +M: Corey Minyard <minyard@acm.org> +S: Maintained +F: include/hw/ipmi/* +F: hw/ipmi/* +F: hw/smbios/smbios_type_38.c +F: tests/ipmi* +T: git git://github.com/cminyard/qemu.git master-ipmi-rebase + Floppy M: John Snow <jsnow@redhat.com> L: qemu-block@nongnu.org diff --git a/block/ssh.c b/block/ssh.c index b049a16eb9..8890a0c4ba 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -556,6 +556,7 @@ static QemuOptsList ssh_runtime_opts = { .type = QEMU_OPT_STRING, .help = "Defines how and what to check the host key against", }, + { /* end of list */ } }, }; diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 8f255e91c0..18082dffe8 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -19,6 +19,7 @@ #include "qemu/rcu.h" #include "qemu/rcu_queue.h" #include "qemu/cutils.h" +#include "sysemu/qtest.h" /* Root node for synth file system */ static V9fsSynthNode synth_root = { @@ -514,6 +515,26 @@ static int synth_unlinkat(FsContext *ctx, V9fsPath *dir, return -1; } +static ssize_t v9fs_synth_qtest_write(void *buf, int len, off_t offset, + void *arg) +{ + return 1; +} + +static ssize_t v9fs_synth_qtest_flush_write(void *buf, int len, off_t offset, + void *arg) +{ + bool should_block = !!*(uint8_t *)buf; + + if (should_block) { + /* This will cause the server to call us again until we're cancelled */ + errno = EINTR; + return -1; + } + + return 1; +} + static int synth_init(FsContext *ctx, Error **errp) { QLIST_INIT(&synth_root.child); @@ -527,6 +548,37 @@ static int synth_init(FsContext *ctx, Error **errp) /* Mark the subsystem is ready for use */ synth_fs = 1; + + if (qtest_enabled()) { + V9fsSynthNode *node = NULL; + int i, ret; + + /* Directory hierarchy for WALK test */ + for (i = 0; i < P9_MAXWELEM; i++) { + char *name = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); + + ret = qemu_v9fs_synth_mkdir(node, 0700, name, &node); + assert(!ret); + g_free(name); + } + + /* File for LOPEN test */ + ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_LOPEN_FILE, + NULL, NULL, ctx); + assert(!ret); + + /* File for WRITE test */ + ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_WRITE_FILE, + NULL, v9fs_synth_qtest_write, ctx); + assert(!ret); + + /* File for FLUSH test */ + ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_FLUSH_FILE, + NULL, v9fs_synth_qtest_flush_write, + ctx); + assert(!ret); + } + return 0; } diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 49c2fc7b27..af7a993a1e 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -49,4 +49,17 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, const char *name, v9fs_synth_read read, v9fs_synth_write write, void *arg); +/* qtest stuff */ + +#define QTEST_V9FS_SYNTH_WALK_FILE "WALK%d" +#define QTEST_V9FS_SYNTH_LOPEN_FILE "LOPEN" +#define QTEST_V9FS_SYNTH_WRITE_FILE "WRITE" + +/* Any write to the "FLUSH" file is handled one byte at a time by the + * backend. If the byte is zero, the backend returns success (ie, 1), + * otherwise it forces the server to try again forever. Thus allowing + * the client to cancel the request. + */ +#define QTEST_V9FS_SYNTH_FLUSH_FILE "FLUSH" + #endif diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 909a611394..85a1ed8171 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -24,6 +24,7 @@ #include "coth.h" #include "trace.h" #include "migration/blocker.h" +#include "sysemu/qtest.h" int open_fd_hw; int total_open_fd; @@ -630,6 +631,24 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len) V9fsState *s = pdu->s; int ret; + /* + * The 9p spec requires that successfully cancelled pdus receive no reply. + * Sending a reply would confuse clients because they would + * assume that any EINTR is the actual result of the operation, + * rather than a consequence of the cancellation. However, if + * the operation completed (succesfully or with an error other + * than caused be cancellation), we do send out that reply, both + * for efficiency and to avoid confusing the rest of the state machine + * that assumes passing a non-error here will mean a successful + * transmission of the reply. + */ + bool discard = pdu->cancelled && len == -EINTR; + if (discard) { + trace_v9fs_rcancel(pdu->tag, pdu->id); + pdu->size = 0; + goto out_notify; + } + if (len < 0) { int err = -len; len = 7; @@ -3485,7 +3504,8 @@ void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr) } /* Returns 0 on success, 1 on failure. */ -int v9fs_device_realize_common(V9fsState *s, Error **errp) +int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, + Error **errp) { int i, len; struct stat stat; @@ -3493,6 +3513,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp) V9fsPath path; int rc = 1; + assert(!s->transport); + s->transport = t; + /* initialize pdu allocator */ QLIST_INIT(&s->free_list); QLIST_INIT(&s->active_list); diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index ffe658ab89..5ced427d86 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -346,7 +346,8 @@ void v9fs_path_sprintf(V9fsPath *path, const char *fmt, ...); void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs); int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, const char *name, V9fsPath *path); -int v9fs_device_realize_common(V9fsState *s, Error **errp); +int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, + Error **errp); void v9fs_device_unrealize_common(V9fsState *s, Error **errp); V9fsPDU *pdu_alloc(V9fsState *s); @@ -366,11 +367,4 @@ struct V9fsTransport { void (*push_and_notify)(V9fsPDU *pdu); }; -static inline int v9fs_register_transport(V9fsState *s, const V9fsTransport *t) -{ - assert(!s->transport); - s->transport = t; - return 0; -} - #endif diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events index 08a4abf22e..1aee350c42 100644 --- a/hw/9pfs/trace-events +++ b/hw/9pfs/trace-events @@ -1,6 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/9pfs/virtio-9p.c +v9fs_rcancel(uint16_t tag, uint8_t id) "tag %d id %d" v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d" v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s" diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 43f4e53f33..775e8ff766 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -198,17 +198,13 @@ static void virtio_9p_device_realize(DeviceState *dev, Error **errp) V9fsVirtioState *v = VIRTIO_9P(dev); V9fsState *s = &v->state; - if (v9fs_device_realize_common(s, errp)) { - goto out; + if (v9fs_device_realize_common(s, &virtio_9p_transport, errp)) { + return; } v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); - v9fs_register_transport(s, &virtio_9p_transport); - -out: - return; } static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index df2a4100bf..14f0d6a50e 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -446,7 +446,6 @@ static int xen_9pfs_connect(struct XenDevice *xendev) xen_9pdev->id = s->fsconf.fsdev_id = g_strdup_printf("xen9p%d", xendev->dev); xen_9pdev->tag = s->fsconf.tag = xenstore_read_fe_str(xendev, "tag"); - v9fs_register_transport(s, &xen_9p_transport); fsdev = qemu_opts_create(qemu_find_opts("fsdev"), s->fsconf.tag, 1, NULL); @@ -455,7 +454,7 @@ static int xen_9pfs_connect(struct XenDevice *xendev) qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL); qemu_opts_set_id(fsdev, s->fsconf.fsdev_id); qemu_fsdev_add(fsdev); - v9fs_device_realize_common(s, NULL); + v9fs_device_realize_common(s, &xen_9p_transport, NULL); return 0; diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index b648770882..4172caf5db 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -25,6 +25,7 @@ #include "hw/block/flash.h" #include "ui/console.h" #include "hw/i2c/i2c.h" +#include "hw/audio/wm8750.h" #include "sysemu/block-backend.h" #include "exec/address-spaces.h" #include "ui/pixel_ops.h" @@ -1691,7 +1692,7 @@ static void musicpal_init(MachineState *machine) qdev_connect_gpio_out(key_dev, i, qdev_get_gpio_in(dev, i + 15)); } - wm8750_dev = i2c_create_slave(i2c, "wm8750", MP_WM_ADDR); + wm8750_dev = i2c_create_slave(i2c, TYPE_WM8750, MP_WM_ADDR); dev = qdev_create(NULL, "mv88w8618_audio"); s = SYS_BUS_DEVICE(dev); qdev_prop_set_ptr(dev, "wm8750", wm8750_dev); diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index ac1e15cbbc..e419e3c00e 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -24,6 +24,7 @@ #include "hw/devices.h" #include "hw/arm/sharpsl.h" #include "ui/console.h" +#include "hw/audio/wm8750.h" #include "audio/audio.h" #include "hw/boards.h" #include "sysemu/block-backend.h" @@ -745,7 +746,7 @@ static void spitz_i2c_setup(PXA2xxState *cpu) DeviceState *wm; /* Attach a WM8750 to the bus */ - wm = i2c_create_slave(bus, "wm8750", 0); + wm = i2c_create_slave(bus, TYPE_WM8750, 0); spitz_wm8750_addr(wm, 0, 0); qdev_connect_gpio_out(cpu->gpio, SPITZ_GPIO_WM, diff --git a/hw/arm/z2.c b/hw/arm/z2.c index 60561c7b7c..300e933c82 100644 --- a/hw/arm/z2.c +++ b/hw/arm/z2.c @@ -23,6 +23,7 @@ #include "hw/block/flash.h" #include "sysemu/block-backend.h" #include "ui/console.h" +#include "hw/audio/wm8750.h" #include "audio/audio.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" @@ -346,7 +347,7 @@ static void z2_init(MachineState *machine) z2_lcd = ssi_create_slave(mpu->ssp[1], "zipit-lcd"); bus = pxa2xx_i2c_bus(mpu->i2c[0]); i2c_create_slave(bus, TYPE_AER915, 0x55); - wm = i2c_create_slave(bus, "wm8750", 0x1b); + wm = i2c_create_slave(bus, TYPE_WM8750, 0x1b); mpu->i2s->opaque = wm; mpu->i2s->codec_out = wm8750_dac_dat; mpu->i2s->codec_in = wm8750_adc_dat; diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index 4f65f8c199..e546892d3c 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -13,6 +13,7 @@ #include "hw/sysbus.h" #include "hw/hw.h" #include "hw/i2c/i2c.h" +#include "hw/audio/wm8750.h" #include "audio/audio.h" #define MP_AUDIO_SIZE 0x00001000 diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 6ab2f6f89a..31de264ab7 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -29,6 +29,8 @@ #include "hw/qdev.h" #include "qemu/timer.h" #include "qemu/host-utils.h" +#include "qemu/log.h" +#include "qapi/error.h" #define dolog(...) AUD_log ("sb16", __VA_ARGS__) @@ -123,7 +125,7 @@ static int magic_of_irq (int irq) case 10: return 8; default: - dolog ("bad irq %d\n", irq); + qemu_log_mask(LOG_GUEST_ERROR, "bad irq %d\n", irq); return 2; } } @@ -140,7 +142,7 @@ static int irq_of_magic (int magic) case 8: return 10; default: - dolog ("bad irq magic %d\n", magic); + qemu_log_mask(LOG_GUEST_ERROR, "bad irq magic %d\n", magic); return -1; } } @@ -258,8 +260,8 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len) s->align = (1 << s->fmt_stereo) - 1; if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); + qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d," + " alignment %d\n", s->block_size, s->align + 1); } ldebug ("freq %d, stereo %d, sign %d, bits %d, " @@ -338,8 +340,8 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) s->highspeed = 0; s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); + qemu_log_mask(LOG_GUEST_ERROR, "warning: misaligned block size %d," + " alignment %d\n", s->block_size, s->align + 1); } if (s->freq) { @@ -391,7 +393,8 @@ static void command (SB16State *s, uint8_t cmd) if (cmd > 0xaf && cmd < 0xd0) { if (cmd & 8) { - dolog ("ADC not yet supported (command %#x)\n", cmd); + qemu_log_mask(LOG_UNIMP, "ADC not yet supported (command %#x)\n", + cmd); } switch (cmd >> 4) { @@ -399,7 +402,7 @@ static void command (SB16State *s, uint8_t cmd) case 12: break; default: - dolog ("%#x wrong bits\n", cmd); + qemu_log_mask(LOG_GUEST_ERROR, "%#x wrong bits\n", cmd); } s->needed_bytes = 3; } @@ -453,7 +456,7 @@ static void command (SB16State *s, uint8_t cmd) goto warn; case 0x35: - dolog ("0x35 - MIDI command not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x35 - MIDI command not implemented\n"); break; case 0x40: @@ -487,34 +490,38 @@ static void command (SB16State *s, uint8_t cmd) case 0x74: s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */ - dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x75 - DMA DAC, 4-bit ADPCM not" + " implemented\n"); break; case 0x75: /* DMA DAC, 4-bit ADPCM Reference */ s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 4-bit ADPCM Reference not" + " implemented\n"); break; case 0x76: /* DMA DAC, 2.6-bit ADPCM */ s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM not" + " implemented\n"); break; case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */ s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x74 - DMA DAC, 2.6-bit ADPCM Reference" + " not implemented\n"); break; case 0x7d: - dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"); - dolog ("not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 4-bit" + " ADPCM Reference\n"); + qemu_log_mask(LOG_UNIMP, "not implemented\n"); break; case 0x7f: - dolog ( - "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n" - ); - dolog ("not implemented\n"); + qemu_log_mask(LOG_UNIMP, "0x7d - Autio-Initialize DMA DAC, 2.6-bit" + " ADPCM Reference\n"); + qemu_log_mask(LOG_UNIMP, "not implemented\n"); break; case 0x80: @@ -586,7 +593,7 @@ static void command (SB16State *s, uint8_t cmd) break; case 0xe7: - dolog ("Attempt to probe for ESS (0xe7)?\n"); + qemu_log_mask(LOG_UNIMP, "Attempt to probe for ESS (0xe7)?\n"); break; case 0xe8: /* read test reg */ @@ -613,7 +620,7 @@ static void command (SB16State *s, uint8_t cmd) goto warn; default: - dolog ("Unrecognized command %#x\n", cmd); + qemu_log_mask(LOG_UNIMP, "Unrecognized command %#x\n", cmd); break; } } @@ -632,8 +639,8 @@ static void command (SB16State *s, uint8_t cmd) return; warn: - dolog ("warning: command %#x,%d is not truly understood yet\n", - cmd, s->needed_bytes); + qemu_log_mask(LOG_UNIMP, "warning: command %#x,%d is not truly understood" + " yet\n", cmd, s->needed_bytes); goto exit; } @@ -735,9 +742,8 @@ static void complete (SB16State *s) break; case 0x42: /* FT2 sets output freq with this, go figure */ -#if 0 - dolog ("cmd 0x42 might not do what it think it should\n"); -#endif + qemu_log_mask(LOG_UNIMP, "cmd 0x42 might not do what it think it" + " should\n"); case 0x41: s->freq = dsp_get_hilo (s); ldebug ("set freq %d\n", s->freq); @@ -820,7 +826,8 @@ static void complete (SB16State *s) break; default: - dolog ("complete: unrecognized command %#x\n", s->cmd); + qemu_log_mask(LOG_UNIMP, "complete: unrecognized command %#x\n", + s->cmd); return; } } @@ -1095,10 +1102,9 @@ static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val) dma = ctz32 (val & 0xf); hdma = ctz32 (val & 0xf0); if (dma != s->dma || hdma != s->hdma) { - dolog ( - "attempt to change DMA " - "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", - dma, s->dma, hdma, s->hdma, val); + qemu_log_mask(LOG_GUEST_ERROR, "attempt to change DMA 8bit" + " %d(%d), 16bit %d(%d) (val=%#x)\n", dma, s->dma, + hdma, s->hdma, val); } #if 0 s->dma = dma; @@ -1108,8 +1114,8 @@ static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val) break; case 0x82: - dolog ("attempt to write into IRQ status register (val=%#x)\n", - val); + qemu_log_mask(LOG_GUEST_ERROR, "attempt to write into IRQ status" + " register (val=%#x)\n", val); return; default: @@ -1181,8 +1187,9 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) int till, copy, written, free; if (s->block_size <= 0) { - dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n", - s->block_size, nchan, dma_pos, dma_len); + qemu_log_mask(LOG_GUEST_ERROR, "invalid block size=%d nchan=%d" + " dma_pos=%d dma_len=%d\n", s->block_size, nchan, + dma_pos, dma_len); return dma_pos; } @@ -1376,7 +1383,7 @@ static void sb16_realizefn (DeviceState *dev, Error **errp) reset_mixer (s); s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s); if (!s->aux_ts) { - dolog ("warning: Could not create auxiliary timer\n"); + error_setg(errp, "warning: Could not create auxiliary timer"); } isa_register_portio_list(isadev, &s->portio_list, s->port, diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index 6d8b728923..416a78e869 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -8,8 +8,8 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" #include "hw/i2c/i2c.h" +#include "hw/audio/wm8750.h" #include "audio/audio.h" #define IN_PORT_N 3 @@ -24,7 +24,6 @@ typedef struct { int dac_hz; } WMRate; -#define TYPE_WM8750 "wm8750" #define WM8750(obj) OBJECT_CHECK(WM8750State, (obj), TYPE_WM8750) typedef struct WM8750State { @@ -639,8 +638,7 @@ static void wm8750_fini(I2CSlave *i2c) } #endif -void wm8750_data_req_set(DeviceState *dev, - void (*data_req)(void *, int, int), void *opaque) +void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque) { WM8750State *s = WM8750(dev); diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index 8c0535d3dd..bf0b7ee0f5 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -425,6 +425,11 @@ static void chr_event(void *opaque, int event) return; } ibe->connected = false; + /* + * Don't hang the OS trying to handle the ATN bit, other end will + * resend on a reconnect. + */ + k->set_atn(s, 0, 0); if (ibe->waiting_rsp) { ibe->waiting_rsp = false; ibe->inbuf[1] = ibe->outbuf[1] | 0x04; diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 277c28cb40..9b509f829b 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -38,6 +38,7 @@ #define IPMI_NETFN_SENSOR_EVENT 0x04 +#define IPMI_CMD_PLATFORM_EVENT_MSG 0x02 #define IPMI_CMD_SET_SENSOR_EVT_ENABLE 0x28 #define IPMI_CMD_GET_SENSOR_EVT_ENABLE 0x29 #define IPMI_CMD_REARM_SENSOR_EVTS 0x2a @@ -213,8 +214,8 @@ struct IPMIBmcSim { uint8_t device_rev; uint8_t fwrev1; uint8_t fwrev2; - uint8_t mfg_id[3]; - uint8_t product_id[2]; + uint32_t mfg_id; + uint16_t product_id; uint8_t restart_cause; @@ -443,16 +444,21 @@ static void sel_inc_reservation(IPMISel *sel) /* Returns 1 if the SEL is full and can't hold the event. */ static int sel_add_event(IPMIBmcSim *ibs, uint8_t *event) { + uint8_t ts[4]; + event[0] = 0xff; event[1] = 0xff; - set_timestamp(ibs, event + 3); + set_timestamp(ibs, ts); + if (event[2] < 0xe0) { /* Don't set timestamps for type 0xe0-0xff. */ + memcpy(event + 3, ts, 4); + } if (ibs->sel.next_free == MAX_SEL_SIZE) { ibs->sel.overflow = 1; return 1; } event[0] = ibs->sel.next_free & 0xff; event[1] = (ibs->sel.next_free >> 8) & 0xff; - memcpy(ibs->sel.last_addition, event + 3, 4); + memcpy(ibs->sel.last_addition, ts, 4); memcpy(ibs->sel.sel[ibs->sel.next_free], event, 16); ibs->sel.next_free++; sel_inc_reservation(&ibs->sel); @@ -861,11 +867,11 @@ static void get_device_id(IPMIBmcSim *ibs, rsp_buffer_push(rsp, ibs->fwrev2); rsp_buffer_push(rsp, ibs->ipmi_version); rsp_buffer_push(rsp, 0x07); /* sensor, SDR, and SEL. */ - rsp_buffer_push(rsp, ibs->mfg_id[0]); - rsp_buffer_push(rsp, ibs->mfg_id[1]); - rsp_buffer_push(rsp, ibs->mfg_id[2]); - rsp_buffer_push(rsp, ibs->product_id[0]); - rsp_buffer_push(rsp, ibs->product_id[1]); + rsp_buffer_push(rsp, ibs->mfg_id & 0xff); + rsp_buffer_push(rsp, (ibs->mfg_id >> 8) & 0xff); + rsp_buffer_push(rsp, (ibs->mfg_id >> 16) & 0xff); + rsp_buffer_push(rsp, ibs->product_id & 0xff); + rsp_buffer_push(rsp, (ibs->product_id >> 8) & 0xff); } static void set_global_enables(IPMIBmcSim *ibs, uint8_t val) @@ -1576,6 +1582,28 @@ static void set_sel_time(IPMIBmcSim *ibs, ibs->sel.time_offset = now.tv_sec - ((long) val); } +static void platform_event_msg(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + RspBuffer *rsp) +{ + uint8_t event[16]; + + event[2] = 2; /* System event record */ + event[7] = cmd[2]; /* Generator ID */ + event[8] = 0; + event[9] = cmd[3]; /* EvMRev */ + event[10] = cmd[4]; /* Sensor type */ + event[11] = cmd[5]; /* Sensor number */ + event[12] = cmd[6]; /* Event dir / Event type */ + event[13] = cmd[7]; /* Event data 1 */ + event[14] = cmd[8]; /* Event data 2 */ + event[15] = cmd[9]; /* Event data 3 */ + + if (sel_add_event(ibs, event)) { + rsp_buffer_set_error(rsp, IPMI_CC_OUT_OF_SPACE); + } +} + static void set_sensor_evt_enable(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, RspBuffer *rsp) @@ -1752,6 +1780,7 @@ static const IPMINetfn chassis_netfn = { }; static const IPMICmdHandler sensor_event_cmds[] = { + [IPMI_CMD_PLATFORM_EVENT_MSG] = { platform_event_msg, 10 }, [IPMI_CMD_SET_SENSOR_EVT_ENABLE] = { set_sensor_evt_enable, 4 }, [IPMI_CMD_GET_SENSOR_EVT_ENABLE] = { get_sensor_evt_enable, 3 }, [IPMI_CMD_REARM_SENSOR_EVTS] = { rearm_sensor_evts, 4 }, @@ -1802,8 +1831,8 @@ static const IPMICmdHandler storage_cmds[] = { [IPMI_CMD_GET_SEL_ENTRY] = { get_sel_entry, 8 }, [IPMI_CMD_ADD_SEL_ENTRY] = { add_sel_entry, 18 }, [IPMI_CMD_CLEAR_SEL] = { clear_sel, 8 }, - [IPMI_CMD_GET_SEL_TIME] = { get_sel_time, 6 }, - [IPMI_CMD_SET_SEL_TIME] = { set_sel_time }, + [IPMI_CMD_GET_SEL_TIME] = { get_sel_time }, + [IPMI_CMD_SET_SEL_TIME] = { set_sel_time, 6 }, }; static const IPMINetfn storage_netfn = { @@ -1968,6 +1997,13 @@ static Property ipmi_sim_properties[] = { DEFINE_PROP_UINT16("fruareasize", IPMIBmcSim, fru.areasize, 1024), DEFINE_PROP_STRING("frudatafile", IPMIBmcSim, fru.filename), DEFINE_PROP_STRING("sdrfile", IPMIBmcSim, sdr_filename), + DEFINE_PROP_UINT8("device_id", IPMIBmcSim, device_id, 0x20), + DEFINE_PROP_UINT8("ipmi_version", IPMIBmcSim, ipmi_version, 0x02), + DEFINE_PROP_UINT8("device_rev", IPMIBmcSim, device_rev, 0), + DEFINE_PROP_UINT8("fwrev1", IPMIBmcSim, fwrev1, 0), + DEFINE_PROP_UINT8("fwrev2", IPMIBmcSim, fwrev2, 0), + DEFINE_PROP_UINT32("mfg_id", IPMIBmcSim, mfg_id, 0), + DEFINE_PROP_UINT16("product_id", IPMIBmcSim, product_id, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index e098fd5206..e946030e84 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -45,21 +45,21 @@ #define IPMI_BT_B2H_ATN_MASK (1 << IPMI_BT_B2H_ATN_BIT) #define IPMI_BT_GET_B2H_ATN(d) (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1) #define IPMI_BT_SET_B2H_ATN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \ - (((v) & 1) << IPMI_BT_B2H_ATN_BIT))) + (!!(v) << IPMI_BT_B2H_ATN_BIT))) #define IPMI_BT_SMS_ATN_MASK (1 << IPMI_BT_SMS_ATN_BIT) #define IPMI_BT_GET_SMS_ATN(d) (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1) #define IPMI_BT_SET_SMS_ATN(d, v) ((d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \ - (((v) & 1) << IPMI_BT_SMS_ATN_BIT))) + (!!(v) << IPMI_BT_SMS_ATN_BIT))) #define IPMI_BT_HBUSY_MASK (1 << IPMI_BT_HBUSY_BIT) #define IPMI_BT_GET_HBUSY(d) (((d) >> IPMI_BT_HBUSY_BIT) & 0x1) #define IPMI_BT_SET_HBUSY(d, v) ((d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \ - (((v) & 1) << IPMI_BT_HBUSY_BIT))) + (!!(v) << IPMI_BT_HBUSY_BIT))) #define IPMI_BT_BBUSY_MASK (1 << IPMI_BT_BBUSY_BIT) #define IPMI_BT_SET_BBUSY(d, v) ((d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \ - (((v) & 1) << IPMI_BT_BBUSY_BIT))) + (!!(v) << IPMI_BT_BBUSY_BIT))) /* Mask register */ @@ -69,12 +69,12 @@ #define IPMI_BT_B2H_IRQ_EN_MASK (1 << IPMI_BT_B2H_IRQ_EN_BIT) #define IPMI_BT_GET_B2H_IRQ_EN(d) (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1) #define IPMI_BT_SET_B2H_IRQ_EN(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) |\ - (((v) & 1) << IPMI_BT_B2H_IRQ_EN_BIT))) + (!!(v) << IPMI_BT_B2H_IRQ_EN_BIT))) #define IPMI_BT_B2H_IRQ_MASK (1 << IPMI_BT_B2H_IRQ_BIT) #define IPMI_BT_GET_B2H_IRQ(d) (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1) #define IPMI_BT_SET_B2H_IRQ(d, v) ((d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \ - (((v) & 1) << IPMI_BT_B2H_IRQ_BIT))) + (!!(v) << IPMI_BT_B2H_IRQ_BIT))) typedef struct IPMIBT { IPMIBmc *bmc; diff --git a/include/hw/audio/wm8750.h b/include/hw/audio/wm8750.h new file mode 100644 index 0000000000..84e7a119bb --- /dev/null +++ b/include/hw/audio/wm8750.h @@ -0,0 +1,30 @@ +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HW_DAC_WM8750_H +#define HW_DAC_WM8750_H + +#include "hw/hw.h" + +#define TYPE_WM8750 "wm8750" + +typedef void data_req_cb(void *opaque, int free_out, int free_in); + +void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque); +void wm8750_dac_dat(void *opaque, uint32_t sample); +uint32_t wm8750_adc_dat(void *opaque); +void *wm8750_dac_buffer(void *opaque, int samples); +void wm8750_dac_commit(void *opaque); +void wm8750_set_bclk_in(void *opaque, int new_hz); + +#endif diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h index 2ce611d4c8..24e95d0155 100644 --- a/include/hw/i2c/i2c.h +++ b/include/hw/i2c/i2c.h @@ -70,15 +70,6 @@ int i2c_recv(I2CBus *bus); DeviceState *i2c_create_slave(I2CBus *bus, const char *name, uint8_t addr); -/* wm8750.c */ -void wm8750_data_req_set(DeviceState *dev, - void (*data_req)(void *, int, int), void *opaque); -void wm8750_dac_dat(void *opaque, uint32_t sample); -uint32_t wm8750_adc_dat(void *opaque); -void *wm8750_dac_buffer(void *opaque, int samples); -void wm8750_dac_commit(void *opaque); -void wm8750_set_bclk_in(void *opaque, int new_hz); - /* lm832x.c */ void lm832x_key_event(DeviceState *dev, int key, int state); diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py index 03fbf69f8a..51acfcd0c0 100644 --- a/scripts/dump-guest-memory.py +++ b/scripts/dump-guest-memory.py @@ -546,6 +546,8 @@ shape and this command should mostly work.""" return None def add_vmcoreinfo(self): + if gdb.lookup_symbol("vmcoreinfo_realize")[0] is None: + return vmci = 'vmcoreinfo_realize::vmcoreinfo_state' if not gdb.parse_and_eval("%s" % vmci) \ or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 0879a621c8..0dad5c19ac 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -119,6 +119,8 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, /* * qvirtio_wait_used_elem: * @desc_idx: The next expected vq->desc[] index in the used ring + * @len: A pointer that is filled with the length written into the buffer, may + * be NULL * @timeout_us: How many microseconds to wait before failing * * This function waits for the next completed request on the used ring. @@ -126,6 +128,7 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, void qvirtio_wait_used_elem(QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, + uint32_t *len, gint64 timeout_us) { gint64 start_time = g_get_monotonic_time(); @@ -136,7 +139,7 @@ void qvirtio_wait_used_elem(QVirtioDevice *d, clock_step(100); if (d->bus->get_queue_isr_status(d, vq) && - qvirtqueue_get_buf(vq, &got_desc_idx)) { + qvirtqueue_get_buf(vq, &got_desc_idx, len)) { g_assert_cmpint(got_desc_idx, ==, desc_idx); return; } @@ -304,30 +307,36 @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) /* * qvirtqueue_get_buf: * @desc_idx: A pointer that is filled with the vq->desc[] index, may be NULL + * @len: A pointer that is filled with the length written into the buffer, may + * be NULL * * This function gets the next used element if there is one ready. * * Returns: true if an element was ready, false otherwise */ -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx) +bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len) { uint16_t idx; + uint64_t elem_addr; idx = readw(vq->used + offsetof(struct vring_used, idx)); if (idx == vq->last_used_idx) { return false; } - if (desc_idx) { - uint64_t elem_addr; + elem_addr = vq->used + + offsetof(struct vring_used, ring) + + (vq->last_used_idx % vq->size) * + sizeof(struct vring_used_elem); - elem_addr = vq->used + - offsetof(struct vring_used, ring) + - (vq->last_used_idx % vq->size) * - sizeof(struct vring_used_elem); + if (desc_idx) { *desc_idx = readl(elem_addr + offsetof(struct vring_used_elem, id)); } + if (len) { + *len = readw(elem_addr + offsetof(struct vring_used_elem, len)); + } + vq->last_used_idx++; return true; } diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 0a04740adf..69b5b13840 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -124,6 +124,7 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, void qvirtio_wait_used_elem(QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, + uint32_t *len, gint64 timeout_us); void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us); QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, @@ -140,7 +141,7 @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, bool next); uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect); void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx); +bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len); void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200 index d8787ddb46..ddbdedc476 100755 --- a/tests/qemu-iotests/200 +++ b/tests/qemu-iotests/200 @@ -60,7 +60,7 @@ qemu_comm_method="qmp" _launch_qemu -device pci-bridge,id=bridge1,chassis_nr=1,bus=pci.0 \ -object iothread,id=iothread0 \ -device virtio-scsi-pci,bus=bridge1,addr=0x1f,id=scsi0,iothread=iothread0 \ - -drive file="${TEST_IMG}",media=disk,if=none,cache=none,id=drive_sysdisk,aio=native,format=$IMGFMT \ + -drive file="${TEST_IMG}",media=disk,if=none,cache=$CACHEMODE,id=drive_sysdisk,format=$IMGFMT \ -device scsi-hd,drive=drive_sysdisk,bus=scsi0.0,id=sysdisk,bootindex=0 h1=$QEMU_HANDLE diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 00f00f7246..54edcb9955 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -17,6 +17,7 @@ #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/virtio_pci.h" #include "hw/9pfs/9p.h" +#include "hw/9pfs/9p-synth.h" #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) @@ -26,24 +27,19 @@ typedef struct { QVirtioDevice *dev; QOSState *qs; QVirtQueue *vq; - char *test_share; - uint16_t p9_req_tag; } QVirtIO9P; static QVirtIO9P *qvirtio_9p_start(const char *driver) { const char *arch = qtest_get_arch(); - const char *cmd = "-fsdev local,id=fsdev0,security_model=none,path=%s " + const char *cmd = "-fsdev synth,id=fsdev0 " "-device %s,fsdev=fsdev0,mount_tag=%s"; QVirtIO9P *v9p = g_new0(QVirtIO9P, 1); - v9p->test_share = g_strdup("/tmp/qtest.XXXXXX"); - g_assert_nonnull(mkdtemp(v9p->test_share)); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - v9p->qs = qtest_pc_boot(cmd, v9p->test_share, driver, mount_tag); + v9p->qs = qtest_pc_boot(cmd, driver, mount_tag); } else if (strcmp(arch, "ppc64") == 0) { - v9p->qs = qtest_spapr_boot(cmd, v9p->test_share, driver, mount_tag); + v9p->qs = qtest_spapr_boot(cmd, driver, mount_tag); } else { g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); exit(EXIT_FAILURE); @@ -55,8 +51,6 @@ static QVirtIO9P *qvirtio_9p_start(const char *driver) static void qvirtio_9p_stop(QVirtIO9P *v9p) { qtest_shutdown(v9p->qs); - rmdir(v9p->test_share); - g_free(v9p->test_share); g_free(v9p); } @@ -156,6 +150,13 @@ static void v9fs_uint32_write(P9Req *req, uint32_t val) v9fs_memwrite(req, &le_val, 4); } +static void v9fs_uint64_write(P9Req *req, uint64_t val) +{ + uint64_t le_val = cpu_to_le64(val); + + v9fs_memwrite(req, &le_val, 8); +} + static void v9fs_uint32_read(P9Req *req, uint32_t *val) { v9fs_memread(req, val, 4); @@ -167,7 +168,7 @@ static uint16_t v9fs_string_size(const char *string) { size_t len = strlen(string); - g_assert_cmpint(len, <=, UINT16_MAX); + g_assert_cmpint(len, <=, UINT16_MAX - 2); return 2 + len; } @@ -208,17 +209,20 @@ static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id, uint16_t tag) { P9Req *req = g_new0(P9Req, 1); - uint32_t t_size = 7 + size; /* 9P header has well-known size of 7 bytes */ + uint32_t total_size = 7; /* 9P header has well-known size of 7 bytes */ P9Hdr hdr = { - .size = cpu_to_le32(t_size), .id = id, .tag = cpu_to_le16(tag) }; - g_assert_cmpint(t_size, <=, P9_MAX_SIZE); + g_assert_cmpint(total_size, <=, UINT32_MAX - size); + total_size += size; + hdr.size = cpu_to_le32(total_size); + + g_assert_cmpint(total_size, <=, P9_MAX_SIZE); req->v9p = v9p; - req->t_size = t_size; + req->t_size = total_size; req->t_msg = guest_alloc(v9p->qs->alloc, req->t_size); v9fs_memwrite(req, &hdr, 7); req->tag = tag; @@ -244,16 +248,23 @@ static const char *rmessage_name(uint8_t id) id == P9_RVERSION ? "RVERSION" : id == P9_RATTACH ? "RATTACH" : id == P9_RWALK ? "RWALK" : + id == P9_RLOPEN ? "RLOPEN" : + id == P9_RWRITE ? "RWRITE" : + id == P9_RFLUSH ? "RFLUSH" : "<unknown>"; } -static void v9fs_req_recv(P9Req *req, uint8_t id) +static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) { QVirtIO9P *v9p = req->v9p; - P9Hdr hdr; - qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, + qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, len, QVIRTIO_9P_TIMEOUT_US); +} + +static void v9fs_req_recv(P9Req *req, uint8_t id) +{ + P9Hdr hdr; v9fs_memread(req, &hdr, 7); hdr.size = ldl_le_p(&hdr.size); @@ -294,10 +305,16 @@ static void v9fs_rlerror(P9Req *req, uint32_t *err) } /* size[4] Tversion tag[2] msize[4] version[s] */ -static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version) +static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version, + uint16_t tag) { - P9Req *req = v9fs_req_init(v9p, 4 + v9fs_string_size(version), P9_TVERSION, - P9_NOTAG); + P9Req *req; + uint32_t body_size = 4; + uint16_t string_size = v9fs_string_size(version); + + g_assert_cmpint(body_size, <=, UINT32_MAX - string_size); + body_size += string_size; + req = v9fs_req_init(v9p, body_size, P9_TVERSION, tag); v9fs_uint32_write(req, msize); v9fs_string_write(req, version); @@ -323,12 +340,12 @@ static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) } /* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ -static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname) +static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname, + uint16_t tag) { const char *uname = ""; /* ignored by QEMU */ const char *aname = ""; /* ignored by QEMU */ - P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, - ++(v9p->p9_req_tag)); + P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag); v9fs_uint32_write(req, fid); v9fs_uint32_write(req, P9_NOFID); @@ -353,16 +370,19 @@ static void v9fs_rattach(P9Req *req, v9fs_qid *qid) /* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid, - uint16_t nwname, char *const wnames[]) + uint16_t nwname, char *const wnames[], uint16_t tag) { P9Req *req; int i; - uint32_t size = 4 + 4 + 2; + uint32_t body_size = 4 + 4 + 2; for (i = 0; i < nwname; i++) { - size += v9fs_string_size(wnames[i]); + uint16_t wname_size = v9fs_string_size(wnames[i]); + + g_assert_cmpint(body_size, <=, UINT32_MAX - wname_size); + body_size += wname_size; } - req = v9fs_req_init(v9p, size, P9_TWALK, ++(v9p->p9_req_tag)); + req = v9fs_req_init(v9p, body_size, P9_TWALK, tag); v9fs_uint32_write(req, fid); v9fs_uint32_write(req, newfid); v9fs_uint16_write(req, nwname); @@ -390,6 +410,80 @@ static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) v9fs_req_free(req); } +/* size[4] Tlopen tag[2] fid[4] flags[4] */ +static P9Req *v9fs_tlopen(QVirtIO9P *v9p, uint32_t fid, uint32_t flags, + uint16_t tag) +{ + P9Req *req; + + req = v9fs_req_init(v9p, 4 + 4, P9_TLOPEN, tag); + v9fs_uint32_write(req, fid); + v9fs_uint32_write(req, flags); + v9fs_req_send(req); + return req; +} + +/* size[4] Rlopen tag[2] qid[13] iounit[4] */ +static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) +{ + v9fs_req_recv(req, P9_RLOPEN); + if (qid) { + v9fs_memread(req, qid, 13); + } else { + v9fs_memskip(req, 13); + } + if (iounit) { + v9fs_uint32_read(req, iounit); + } + v9fs_req_free(req); +} + +/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */ +static P9Req *v9fs_twrite(QVirtIO9P *v9p, uint32_t fid, uint64_t offset, + uint32_t count, const void *data, uint16_t tag) +{ + P9Req *req; + uint32_t body_size = 4 + 8 + 4; + + g_assert_cmpint(body_size, <=, UINT32_MAX - count); + body_size += count; + req = v9fs_req_init(v9p, body_size, P9_TWRITE, tag); + v9fs_uint32_write(req, fid); + v9fs_uint64_write(req, offset); + v9fs_uint32_write(req, count); + v9fs_memwrite(req, data, count); + v9fs_req_send(req); + return req; +} + +/* size[4] Rwrite tag[2] count[4] */ +static void v9fs_rwrite(P9Req *req, uint32_t *count) +{ + v9fs_req_recv(req, P9_RWRITE); + if (count) { + v9fs_uint32_read(req, count); + } + v9fs_req_free(req); +} + +/* size[4] Tflush tag[2] oldtag[2] */ +static P9Req *v9fs_tflush(QVirtIO9P *v9p, uint16_t oldtag, uint16_t tag) +{ + P9Req *req; + + req = v9fs_req_init(v9p, 2, P9_TFLUSH, tag); + v9fs_uint32_write(req, oldtag); + v9fs_req_send(req); + return req; +} + +/* size[4] Rflush tag[2] */ +static void v9fs_rflush(P9Req *req) +{ + v9fs_req_recv(req, P9_RFLUSH); + v9fs_req_free(req); +} + static void fs_version(QVirtIO9P *v9p) { const char *version = "9P2000.L"; @@ -397,7 +491,8 @@ static void fs_version(QVirtIO9P *v9p) char *server_version; P9Req *req; - req = v9fs_tversion(v9p, P9_MAX_SIZE, version); + req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); + v9fs_req_wait_for_reply(req, NULL); v9fs_rversion(req, &server_len, &server_version); g_assert_cmpmem(server_version, server_len, version, strlen(version)); @@ -410,34 +505,31 @@ static void fs_attach(QVirtIO9P *v9p) P9Req *req; fs_version(v9p); - req = v9fs_tattach(v9p, 0, getuid()); + req = v9fs_tattach(v9p, 0, getuid(), 0); + v9fs_req_wait_for_reply(req, NULL); v9fs_rattach(req, NULL); } static void fs_walk(QVirtIO9P *v9p) { - char *wnames[P9_MAXWELEM], *paths[P9_MAXWELEM]; - char *last_path = v9p->test_share; + char *wnames[P9_MAXWELEM]; uint16_t nwqid; v9fs_qid *wqid; int i; P9Req *req; for (i = 0; i < P9_MAXWELEM; i++) { - wnames[i] = g_strdup_printf("%s%d", __func__, i); - last_path = paths[i] = g_strdup_printf("%s/%s", last_path, wnames[i]); - g_assert(!mkdir(paths[i], 0700)); + wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); } fs_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames); + req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); v9fs_rwalk(req, &nwqid, &wqid); g_assert_cmpint(nwqid, ==, P9_MAXWELEM); for (i = 0; i < P9_MAXWELEM; i++) { - rmdir(paths[P9_MAXWELEM - i - 1]); - g_free(paths[P9_MAXWELEM - i - 1]); g_free(wnames[i]); } @@ -451,7 +543,8 @@ static void fs_walk_no_slash(QVirtIO9P *v9p) uint32_t err; fs_attach(v9p); - req = v9fs_twalk(v9p, 0, 1, 1, wnames); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); v9fs_rlerror(req, &err); g_assert_cmpint(err, ==, ENOENT); @@ -466,10 +559,12 @@ static void fs_walk_dotdot(QVirtIO9P *v9p) P9Req *req; fs_version(v9p); - req = v9fs_tattach(v9p, 0, getuid()); + req = v9fs_tattach(v9p, 0, getuid(), 0); + v9fs_req_wait_for_reply(req, NULL); v9fs_rattach(req, &root_qid); - req = v9fs_twalk(v9p, 0, 1, 1, wnames); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); v9fs_rwalk(req, NULL, &wqid); /* We now we'll get one qid */ g_assert_cmpmem(&root_qid, 13, wqid[0], 13); @@ -478,6 +573,119 @@ static void fs_walk_dotdot(QVirtIO9P *v9p) g_free(wnames[0]); } +static void fs_lopen(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; + P9Req *req; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwalk(req, NULL, NULL); + + req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rlopen(req, NULL, NULL); + + g_free(wnames[0]); +} + +static void fs_write(QVirtIO9P *v9p) +{ + static const uint32_t write_count = P9_MAX_SIZE / 2; + char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; + char *buf = g_malloc0(write_count); + uint32_t count; + P9Req *req; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwalk(req, NULL, NULL); + + req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rlopen(req, NULL, NULL); + + req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwrite(req, &count); + g_assert_cmpint(count, ==, write_count); + + g_free(buf); + g_free(wnames[0]); +} + +static void fs_flush_success(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + P9Req *req, *flush_req; + uint32_t reply_len; + uint8_t should_block; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwalk(req, NULL, NULL); + + req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rlopen(req, NULL, NULL); + + /* This will cause the 9p server to try to write data to the backend, + * until the write request gets cancelled. + */ + should_block = 1; + req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + + flush_req = v9fs_tflush(v9p, req->tag, 1); + + /* The write request is supposed to be flushed: the server should just + * mark the write request as used and reply to the flush request. + */ + v9fs_req_wait_for_reply(req, &reply_len); + g_assert_cmpint(reply_len, ==, 0); + v9fs_req_free(req); + v9fs_rflush(flush_req); + + g_free(wnames[0]); +} + +static void fs_flush_ignored(QVirtIO9P *v9p) +{ + char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_FLUSH_FILE) }; + P9Req *req, *flush_req; + uint32_t count; + uint8_t should_block; + + fs_attach(v9p); + req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwalk(req, NULL, NULL); + + req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); + v9fs_req_wait_for_reply(req, NULL); + v9fs_rlopen(req, NULL, NULL); + + /* This will cause the write request to complete right away, before it + * could be actually cancelled. + */ + should_block = 0; + req = v9fs_twrite(v9p, 1, 0, sizeof(should_block), &should_block, 0); + + flush_req = v9fs_tflush(v9p, req->tag, 1); + + /* The write request is supposed to complete. The server should + * reply to the write request and the flush request. + */ + v9fs_req_wait_for_reply(req, NULL); + v9fs_rwrite(req, &count); + g_assert_cmpint(count, ==, sizeof(should_block)); + v9fs_rflush(flush_req); + + g_free(wnames[0]); +} + typedef void (*v9fs_test_fn)(QVirtIO9P *v9p); static void v9fs_run_pci_test(gconstpointer data) @@ -507,6 +715,10 @@ int main(int argc, char **argv) v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash); v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root", fs_walk_dotdot); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/lopen/basic", fs_lopen); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/write/basic", fs_write); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/flush/success", fs_flush_success); + v9fs_qtest_pci_add("/virtio/9p/pci/fs/flush/ignored", fs_flush_ignored); return g_test_run(); } diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 45f368dcd9..2ac64e5e25 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -193,7 +193,7 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, qvirtqueue_kick(dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -215,7 +215,7 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, qvirtqueue_kick(dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -243,7 +243,8 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, qvirtqueue_add(vq, req_addr + 528, 1, true, false); qvirtqueue_kick(dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -264,7 +265,8 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, qvirtqueue_kick(dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -345,7 +347,7 @@ static void pci_indirect(void) free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect); qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -370,7 +372,7 @@ static void pci_indirect(void) free_head = qvirtqueue_add_indirect(&vqpci->vq, indirect); qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -481,7 +483,7 @@ static void pci_msix(void) qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false); qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); @@ -506,7 +508,7 @@ static void pci_msix(void) qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); @@ -580,7 +582,7 @@ static void pci_idx(void) qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false); qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); /* Write request */ @@ -627,9 +629,9 @@ static void pci_idx(void) qvirtqueue_kick(&dev->vdev, &vqpci->vq, free_head); /* We get just one notification for both requests */ - qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head, + qvirtio_wait_used_elem(&dev->vdev, &vqpci->vq, write_head, NULL, QVIRTIO_BLK_TIMEOUT_US); - g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx)); + g_assert(qvirtqueue_get_buf(&vqpci->vq, &desc_idx, NULL)); g_assert_cmpint(desc_idx, ==, free_head); status = readb(req_addr + 528); diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 635b942c36..ea634dc05a 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -108,7 +108,7 @@ static void rx_test(QVirtioDevice *dev, ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); g_assert_cmpstr(buffer, ==, "TEST"); @@ -131,7 +131,7 @@ static void tx_test(QVirtioDevice *dev, free_head = qvirtqueue_add(vq, req_addr, 64, false, false); qvirtqueue_kick(dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); guest_free(alloc, req_addr); ret = qemu_recv(socket, &len, sizeof(len), 0); @@ -182,7 +182,7 @@ static void rx_stop_cont_test(QVirtioDevice *dev, rsp = qmp("{ 'execute' : 'cont'}"); QDECREF(rsp); - qvirtio_wait_used_elem(dev, vq, free_head, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); g_assert_cmpstr(buffer, ==, "TEST"); diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index 2934305b2b..bcf408fbb6 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -121,7 +121,8 @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb, } qvirtqueue_kick(vs->dev, vq, free_head); - qvirtio_wait_used_elem(vs->dev, vq, free_head, QVIRTIO_SCSI_TIMEOUT_US); + qvirtio_wait_used_elem(vs->dev, vq, free_head, NULL, + QVIRTIO_SCSI_TIMEOUT_US); response = readb(resp_addr + offsetof(struct virtio_scsi_cmd_resp, response)); |