diff options
79 files changed, 1793 insertions, 1269 deletions
@@ -229,6 +229,7 @@ KEYCODEMAP_FILES = \ ui/input-keymap-linux-to-qcode.c \ ui/input-keymap-qcode-to-qnum.c \ ui/input-keymap-qnum-to-qcode.c \ + ui/input-keymap-qcode-to-linux.c \ $(NULL) GENERATED_FILES += $(KEYCODEMAP_FILES) diff --git a/hmp-commands.hx b/hmp-commands.hx index 4afd57cf5f..6d5ebdf6ab 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -666,39 +666,6 @@ Compute the checksum of a memory region. ETEXI { - .name = "usb_add", - .args_type = "devname:s", - .params = "device", - .help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')", - .cmd = hmp_usb_add, - }, - -STEXI -@item usb_add @var{devname} -@findex usb_add -Add the USB device @var{devname}. This command is deprecated, please -use @code{device_add} instead. For details of available devices see -@ref{usb_devices} -ETEXI - - { - .name = "usb_del", - .args_type = "devname:s", - .params = "device", - .help = "remove USB device 'bus.addr'", - .cmd = hmp_usb_del, - }, - -STEXI -@item usb_del @var{devname} -@findex usb_del -Remove the USB device @var{devname} from the QEMU virtual USB -hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor -command @code{info usb} to see the devices you can remove. This -command is deprecated, please use @code{device_del} instead. -ETEXI - - { .name = "device_add", .args_type = "device:O", .params = "driver[,prop=value][,...]", diff --git a/hw/block/trace-events b/hw/block/trace-events index cb6767b3ee..962a3bfa24 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -10,3 +10,10 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6 # hw/block/hd-geometry.c hd_geometry_lchs_guess(void *blk, int cyls, int heads, int secs) "blk %p LCHS %d %d %d" hd_geometry_guess(void *blk, uint32_t cyls, uint32_t heads, uint32_t secs, int trans) "blk %p CHS %u %u %u trans %d" + +# hw/block/xen_disk.c +xen_disk_alloc(char *name) "%s" +xen_disk_init(char *name) "%s" +xen_disk_connect(char *name) "%s" +xen_disk_disconnect(char *name) "%s" +xen_disk_free(char *name) "%s" diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c index e431bd89e8..f74fcd42d1 100644 --- a/hw/block/xen_disk.c +++ b/hw/block/xen_disk.c @@ -27,10 +27,12 @@ #include "hw/xen/xen_backend.h" #include "xen_blkif.h" #include "sysemu/blockdev.h" +#include "sysemu/iothread.h" #include "sysemu/block-backend.h" #include "qapi/error.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" +#include "trace.h" /* ------------------------------------------------------------- */ @@ -125,6 +127,9 @@ struct XenBlkDev { DriveInfo *dinfo; BlockBackend *blk; QEMUBH *bh; + + IOThread *iothread; + AioContext *ctx; }; /* ------------------------------------------------------------- */ @@ -596,9 +601,12 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq); static void qemu_aio_complete(void *opaque, int ret) { struct ioreq *ioreq = opaque; + struct XenBlkDev *blkdev = ioreq->blkdev; + + aio_context_acquire(blkdev->ctx); if (ret != 0) { - xen_pv_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n", + xen_pv_printf(&blkdev->xendev, 0, "%s I/O error\n", ioreq->req.operation == BLKIF_OP_READ ? "read" : "write"); ioreq->aio_errors++; } @@ -607,10 +615,10 @@ static void qemu_aio_complete(void *opaque, int ret) if (ioreq->presync) { ioreq->presync = 0; ioreq_runio_qemu_aio(ioreq); - return; + goto done; } if (ioreq->aio_inflight > 0) { - return; + goto done; } if (xen_feature_grant_copy) { @@ -647,16 +655,19 @@ static void qemu_aio_complete(void *opaque, int ret) } case BLKIF_OP_READ: if (ioreq->status == BLKIF_RSP_OKAY) { - block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct); + block_acct_done(blk_get_stats(blkdev->blk), &ioreq->acct); } else { - block_acct_failed(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct); + block_acct_failed(blk_get_stats(blkdev->blk), &ioreq->acct); } break; case BLKIF_OP_DISCARD: default: break; } - qemu_bh_schedule(ioreq->blkdev->bh); + qemu_bh_schedule(blkdev->bh); + +done: + aio_context_release(blkdev->ctx); } static bool blk_split_discard(struct ioreq *ioreq, blkif_sector_t sector_number, @@ -913,17 +924,29 @@ static void blk_handle_requests(struct XenBlkDev *blkdev) static void blk_bh(void *opaque) { struct XenBlkDev *blkdev = opaque; + + aio_context_acquire(blkdev->ctx); blk_handle_requests(blkdev); + aio_context_release(blkdev->ctx); } static void blk_alloc(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + Error *err = NULL; + + trace_xen_disk_alloc(xendev->name); QLIST_INIT(&blkdev->inflight); QLIST_INIT(&blkdev->finished); QLIST_INIT(&blkdev->freelist); - blkdev->bh = qemu_bh_new(blk_bh, blkdev); + + blkdev->iothread = iothread_create(xendev->name, &err); + assert(!err); + + blkdev->ctx = iothread_get_aio_context(blkdev->iothread); + blkdev->bh = aio_bh_new(blkdev->ctx, blk_bh, blkdev); + if (xen_mode != XEN_EMULATE) { batch_maps = 1; } @@ -950,6 +973,8 @@ static int blk_init(struct XenDevice *xendev) int info = 0; char *directiosafe = NULL; + trace_xen_disk_init(xendev->name); + /* read xenstore entries */ if (blkdev->params == NULL) { char *h = NULL; @@ -1062,6 +1087,8 @@ static int blk_connect(struct XenDevice *xendev) unsigned int i; uint32_t *domids; + trace_xen_disk_connect(xendev->name); + /* read-only ? */ if (blkdev->directiosafe) { qflags = BDRV_O_NOCACHE | BDRV_O_NATIVE_AIO; @@ -1287,6 +1314,8 @@ static int blk_connect(struct XenDevice *xendev) blkdev->persistent_gnt_count = 0; } + blk_set_aio_context(blkdev->blk, blkdev->ctx); + xen_be_bind_evtchn(&blkdev->xendev); xen_pv_printf(&blkdev->xendev, 1, "ok: proto %s, nr-ring-ref %u, " @@ -1300,13 +1329,20 @@ static void blk_disconnect(struct XenDevice *xendev) { struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); + trace_xen_disk_disconnect(xendev->name); + + aio_context_acquire(blkdev->ctx); + if (blkdev->blk) { + blk_set_aio_context(blkdev->blk, qemu_get_aio_context()); blk_detach_dev(blkdev->blk, blkdev); blk_unref(blkdev->blk); blkdev->blk = NULL; } xen_pv_unbind_evtchn(&blkdev->xendev); + aio_context_release(blkdev->ctx); + if (blkdev->sring) { xengnttab_unmap(blkdev->xendev.gnttabdev, blkdev->sring, blkdev->nr_ring_ref); @@ -1345,6 +1381,8 @@ static int blk_free(struct XenDevice *xendev) struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev); struct ioreq *ioreq; + trace_xen_disk_free(xendev->name); + blk_disconnect(xendev); while (!QLIST_EMPTY(&blkdev->freelist)) { @@ -1360,6 +1398,7 @@ static int blk_free(struct XenDevice *xendev) g_free(blkdev->dev); g_free(blkdev->devtype); qemu_bh_delete(blkdev->bh); + iothread_destroy(blkdev->iothread); return 0; } diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 8e2547ac05..d4fc0fa5f2 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "hw/hw.h" +#include "ui/input.h" #include "ui/console.h" #include "hw/xen/xen_backend.h" @@ -51,9 +52,11 @@ struct common { struct XenInput { struct common c; int abs_pointer_wanted; /* Whether guest supports absolute pointer */ - int button_state; /* Last seen pointer button state */ - int extended; - QEMUPutMouseEntry *qmouse; + int raw_pointer_wanted; /* Whether guest supports raw (unscaled) pointer */ + QemuInputHandlerState *qkbd; + QemuInputHandlerState *qmou; + int axis[INPUT_AXIS__MAX]; + int wheel; }; #define UP_QUEUE 8 @@ -119,79 +122,6 @@ static void common_unbind(struct common *c) } /* -------------------------------------------------------------------- */ - -#if 0 -/* - * These two tables are not needed any more, but left in here - * intentionally as documentation, to show how scancode2linux[] - * was generated. - * - * Tables to map from scancode to Linux input layer keycode. - * Scancodes are hardware-specific. These maps assumes a - * standard AT or PS/2 keyboard which is what QEMU feeds us. - */ -const unsigned char atkbd_set2_keycode[512] = { - - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, - 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, - 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, - 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, - 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142, - 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, - -}; - -const unsigned char atkbd_unxlate_table[128] = { - - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 - -}; -#endif - -/* - * for (i = 0; i < 128; i++) { - * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]]; - * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80]; - * } - */ -static const unsigned char scancode2linux[512] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0, - 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0, - 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107, - 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142, - 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - /* Send an event to the keyboard frontend driver */ static int xenfb_kbd_event(struct XenInput *xenfb, union xenkbd_in_event *event) @@ -262,36 +192,28 @@ static int xenfb_send_position(struct XenInput *xenfb, /* * Send a key event from the client to the guest OS - * QEMU gives us a raw scancode from an AT / PS/2 style keyboard. + * QEMU gives us a QCode. * We have to turn this into a Linux Input layer keycode. * - * Extra complexity from the fact that with extended scancodes - * (like those produced by arrow keys) this method gets called - * twice, but we only want to send a single event. So we have to - * track the '0xe0' scancode state & collapse the extended keys - * as needed. - * * Wish we could just send scancodes straight to the guest which * already has code for dealing with this... */ -static void xenfb_key_event(void *opaque, int scancode) +static void xenfb_key_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - struct XenInput *xenfb = opaque; - int down = 1; + struct XenInput *xenfb = (struct XenInput *)dev; + InputKeyEvent *key = evt->u.key.data; + int qcode = qemu_input_key_value_to_qcode(key->key); + int lnx; - if (scancode == 0xe0) { - xenfb->extended = 1; - return; - } else if (scancode & 0x80) { - scancode &= 0x7f; - down = 0; - } - if (xenfb->extended) { - scancode |= 0x80; - xenfb->extended = 0; + if (qcode < qemu_input_map_qcode_to_linux_len) { + lnx = qemu_input_map_qcode_to_linux[qcode]; + + if (lnx) { + trace_xenfb_key_event(xenfb, lnx, key->down); + xenfb_send_key(xenfb, key->down, lnx); + } } - trace_xenfb_key_event(opaque, scancode2linux[scancode], down); - xenfb_send_key(xenfb, down, scancode2linux[scancode]); } /* @@ -303,48 +225,126 @@ static void xenfb_key_event(void *opaque, int scancode) * given any button up/down events, so have to track changes in * the button state. */ -static void xenfb_mouse_event(void *opaque, - int dx, int dy, int dz, int button_state) +static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - struct XenInput *xenfb = opaque; - QemuConsole *con = qemu_console_lookup_by_index(0); + struct XenInput *xenfb = (struct XenInput *)dev; + InputBtnEvent *btn; + InputMoveEvent *move; + QemuConsole *con; DisplaySurface *surface; - int dw, dh, i; + int scale; + + switch (evt->type) { + case INPUT_EVENT_KIND_BTN: + btn = evt->u.btn.data; + switch (btn->button) { + case INPUT_BUTTON_LEFT: + xenfb_send_key(xenfb, btn->down, BTN_LEFT); + break; + case INPUT_BUTTON_RIGHT: + xenfb_send_key(xenfb, btn->down, BTN_LEFT + 1); + break; + case INPUT_BUTTON_MIDDLE: + xenfb_send_key(xenfb, btn->down, BTN_LEFT + 2); + break; + case INPUT_BUTTON_WHEEL_UP: + if (btn->down) { + xenfb->wheel--; + } + break; + case INPUT_BUTTON_WHEEL_DOWN: + if (btn->down) { + xenfb->wheel++; + } + break; + default: + break; + } + break; + + case INPUT_EVENT_KIND_ABS: + move = evt->u.abs.data; + if (xenfb->raw_pointer_wanted) { + xenfb->axis[move->axis] = move->value; + } else { + con = qemu_console_lookup_by_index(0); + if (!con) { + xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available"); + return; + } + surface = qemu_console_surface(con); + switch (move->axis) { + case INPUT_AXIS_X: + scale = surface_width(surface) - 1; + break; + case INPUT_AXIS_Y: + scale = surface_height(surface) - 1; + break; + default: + scale = 0x8000; + break; + } + xenfb->axis[move->axis] = move->value * scale / 0x7fff; + } + break; - if (!con) { - xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available"); - return; + case INPUT_EVENT_KIND_REL: + move = evt->u.rel.data; + xenfb->axis[move->axis] += move->value; + break; + + default: + break; } +} - surface = qemu_console_surface(con); - dw = surface_width(surface); - dh = surface_height(surface); +static void xenfb_mouse_sync(DeviceState *dev) +{ + struct XenInput *xenfb = (struct XenInput *)dev; - trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state, + trace_xenfb_mouse_event(xenfb, xenfb->axis[INPUT_AXIS_X], + xenfb->axis[INPUT_AXIS_Y], + xenfb->wheel, 0, xenfb->abs_pointer_wanted); - if (xenfb->abs_pointer_wanted) - xenfb_send_position(xenfb, - dx * (dw - 1) / 0x7fff, - dy * (dh - 1) / 0x7fff, - dz); - else - xenfb_send_motion(xenfb, dx, dy, dz); - - for (i = 0 ; i < 8 ; i++) { - int lastDown = xenfb->button_state & (1 << i); - int down = button_state & (1 << i); - if (down == lastDown) - continue; - - if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) - return; - } - xenfb->button_state = button_state; + if (xenfb->abs_pointer_wanted) { + xenfb_send_position(xenfb, xenfb->axis[INPUT_AXIS_X], + xenfb->axis[INPUT_AXIS_Y], + xenfb->wheel); + } else { + xenfb_send_motion(xenfb, xenfb->axis[INPUT_AXIS_X], + xenfb->axis[INPUT_AXIS_Y], + xenfb->wheel); + xenfb->axis[INPUT_AXIS_X] = 0; + xenfb->axis[INPUT_AXIS_Y] = 0; + } + xenfb->wheel = 0; } +static QemuInputHandler xenfb_keyboard = { + .name = "Xen PV Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = xenfb_key_event, +}; + +static QemuInputHandler xenfb_abs_mouse = { + .name = "Xen PV Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, + .event = xenfb_mouse_event, + .sync = xenfb_mouse_sync, +}; + +static QemuInputHandler xenfb_rel_mouse = { + .name = "Xen PV Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = xenfb_mouse_event, + .sync = xenfb_mouse_sync, +}; + static int input_init(struct XenDevice *xendev) { xenstore_write_be_int(xendev, "feature-abs-pointer", 1); + xenstore_write_be_int(xendev, "feature-raw-pointer", 1); return 0; } @@ -357,7 +357,6 @@ static int input_initialise(struct XenDevice *xendev) if (rc != 0) return rc; - qemu_add_kbd_event_handler(xenfb_key_event, in); return 0; } @@ -369,25 +368,44 @@ static void input_connected(struct XenDevice *xendev) &in->abs_pointer_wanted) == -1) { in->abs_pointer_wanted = 0; } + if (xenstore_read_fe_int(xendev, "request-raw-pointer", + &in->raw_pointer_wanted) == -1) { + in->raw_pointer_wanted = 0; + } + if (in->raw_pointer_wanted && in->abs_pointer_wanted == 0) { + xen_pv_printf(xendev, 0, "raw pointer set without abs pointer"); + } - if (in->qmouse) { - qemu_remove_mouse_event_handler(in->qmouse); + if (in->qkbd) { + qemu_input_handler_unregister(in->qkbd); + } + if (in->qmou) { + qemu_input_handler_unregister(in->qmou); } trace_xenfb_input_connected(xendev, in->abs_pointer_wanted); - in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in, - in->abs_pointer_wanted, - "Xen PVFB Mouse"); + + in->qkbd = qemu_input_handler_register((DeviceState *)in, &xenfb_keyboard); + in->qmou = qemu_input_handler_register((DeviceState *)in, + in->abs_pointer_wanted ? &xenfb_abs_mouse : &xenfb_rel_mouse); + + if (in->raw_pointer_wanted) { + qemu_input_handler_activate(in->qkbd); + qemu_input_handler_activate(in->qmou); + } } static void input_disconnect(struct XenDevice *xendev) { struct XenInput *in = container_of(xendev, struct XenInput, c.xendev); - if (in->qmouse) { - qemu_remove_mouse_event_handler(in->qmouse); - in->qmouse = NULL; + if (in->qkbd) { + qemu_input_handler_unregister(in->qkbd); + in->qkbd = NULL; + } + if (in->qmou) { + qemu_input_handler_unregister(in->qmou); + in->qmou = NULL; } - qemu_add_kbd_event_handler(NULL, NULL); common_unbind(&in->c); } diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 10d6e871fb..9159a06f07 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -46,6 +46,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/log.h" #include "qemu/timer.h" +#include "qemu/error-report.h" //#define DEBUG_OPENPIC @@ -58,8 +59,7 @@ static const int debug_openpic = 0; static int get_current_cpu(void); #define DPRINTF(fmt, ...) do { \ if (debug_openpic) { \ - printf("Core%d: ", get_current_cpu()); \ - printf(fmt , ## __VA_ARGS__); \ + info_report("Core%d: " fmt, get_current_cpu(), ## __VA_ARGS__); \ } \ } while (0) @@ -173,7 +173,7 @@ static int inttgt_to_output(int inttgt) } } - fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt); + error_report("%s: unsupported inttgt %d", __func__, inttgt); return OPENPIC_OUTPUT_INT; } @@ -372,7 +372,7 @@ static void IRQ_check(OpenPICState *opp, IRQQueue *q) break; } - DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", + DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d", irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { @@ -403,11 +403,11 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, dst = &opp->dst[n_CPU]; src = &opp->src[n_IRQ]; - DPRINTF("%s: IRQ %d active %d was %d\n", + DPRINTF("%s: IRQ %d active %d was %d", __func__, n_IRQ, active, was_active); if (src->output != OPENPIC_OUTPUT_INT) { - DPRINTF("%s: output %d irq %d active %d was %d count %d\n", + DPRINTF("%s: output %d irq %d active %d was %d count %d", __func__, src->output, n_IRQ, active, was_active, dst->outputs_active[src->output]); @@ -417,13 +417,13 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, */ if (active) { if (!was_active && dst->outputs_active[src->output]++ == 0) { - DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", + DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d", __func__, src->output, n_CPU, n_IRQ); qemu_irq_raise(dst->irqs[src->output]); } } else { if (was_active && --dst->outputs_active[src->output] == 0) { - DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", + DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d", __func__, src->output, n_CPU, n_IRQ); qemu_irq_lower(dst->irqs[src->output]); } @@ -446,7 +446,7 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, IRQ_check(opp, &dst->raised); if (active && priority <= dst->ctpr) { - DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", + DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d", __func__, n_IRQ, priority, dst->ctpr, n_CPU); active = 0; } @@ -454,10 +454,10 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, if (active) { if (IRQ_get_next(opp, &dst->servicing) >= 0 && priority <= dst->servicing.priority) { - DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", + DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d", __func__, n_IRQ, dst->servicing.next, n_CPU); } else { - DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d", __func__, n_CPU, n_IRQ, dst->raised.next); qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } @@ -465,12 +465,12 @@ static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, IRQ_get_next(opp, &dst->servicing); if (dst->raised.priority > dst->ctpr && dst->raised.priority > dst->servicing.priority) { - DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", + DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d", __func__, n_IRQ, dst->raised.next, dst->raised.priority, dst->ctpr, dst->servicing.priority, n_CPU); /* IRQ line stays asserted */ } else { - DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", + DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d", __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } @@ -489,7 +489,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { /* Interrupt source is disabled */ - DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); + DPRINTF("%s: IRQ %d is disabled", __func__, n_IRQ); active = false; } @@ -500,7 +500,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) * ctpr may have changed and we need to withdraw the interrupt. */ if (!active && !was_active) { - DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); + DPRINTF("%s: IRQ %d is already inactive", __func__, n_IRQ); return; } @@ -512,7 +512,7 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) if (src->destmask == 0) { /* No target */ - DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); + DPRINTF("%s: IRQ %d has no target", __func__, n_IRQ); return; } @@ -547,12 +547,12 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) IRQSource *src; if (n_IRQ >= OPENPIC_MAX_IRQ) { - fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); + error_report("%s: IRQ %d out of range", __func__, n_IRQ); abort(); } src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", + DPRINTF("openpic: set irq %d = %d ivpr=0x%08x", n_IRQ, level, src->ivpr); if (src->level) { /* level-sensitive irq */ @@ -612,13 +612,13 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } src->idr = val & mask; - DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); + DPRINTF("Set IDR %d to 0x%08x", n_IRQ, src->idr); if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { if (src->idr & crit_mask) { if (src->idr & normal_mask) { DPRINTF("%s: IRQ configured for multiple output types, using " - "critical\n", __func__); + "critical", __func__); } src->output = OPENPIC_OUTPUT_CINT; @@ -648,7 +648,7 @@ static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) IRQSource *src = &opp->src[n_IRQ]; src->output = inttgt_to_output(val & ILR_INTTGT_MASK); - DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, + DPRINTF("Set ILR %d to 0x%08x, output %d", n_IRQ, src->idr, src->output); /* TODO: on MPIC v4.0 only, set nomask for non-INT */ @@ -688,7 +688,7 @@ static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) } openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, + DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x", n_IRQ, val, opp->src[n_IRQ].ivpr); } @@ -719,7 +719,7 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, IRQDest *dst; int idx; - DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64, __func__, addr, val); if (addr & 0xF) { return; @@ -747,11 +747,11 @@ static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, case 0x1090: /* PIR */ for (idx = 0; idx < opp->nb_cpus; idx++) { if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { - DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); + DPRINTF("Raise OpenPIC RESET output for CPU %d", idx); dst = &opp->dst[idx]; qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { - DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); + DPRINTF("Lower OpenPIC RESET output for CPU %d", idx); dst = &opp->dst[idx]; qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); } @@ -781,7 +781,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) OpenPICState *opp = opaque; uint32_t retval; - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr); retval = 0xFFFFFFFF; if (addr & 0xF) { return retval; @@ -828,7 +828,7 @@ static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) default: break; } - DPRINTF("%s: => 0x%08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x", __func__, retval); return retval; } @@ -843,7 +843,7 @@ static void qemu_timer_cb(void *opaque) uint32_t val = tmr->tbcr & ~TBCR_CI; uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggle. */ - DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ); + DPRINTF("%s n_IRQ=%d", __func__, n_IRQ); /* Reload current count from base count and setup timer. */ tmr->tccr = val | tog; openpic_tmr_set_tmr(tmr, val, /*enabled=*/true); @@ -898,7 +898,7 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64, __func__, (addr + 0x10f0), val); if (addr & 0xF) { return; @@ -943,7 +943,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) uint32_t retval = -1; int idx; - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0); + DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr + 0x10f0); if (addr & 0xF) { goto out; } @@ -970,7 +970,7 @@ static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) } out: - DPRINTF("%s: => 0x%08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x", __func__, retval); return retval; } @@ -981,7 +981,7 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; - DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64, __func__, addr, val); addr = addr & 0xffff; @@ -1006,7 +1006,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) uint32_t retval; int idx; - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr); retval = 0xFFFFFFFF; addr = addr & 0xffff; @@ -1024,7 +1024,7 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) break; } - DPRINTF("%s: => 0x%08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x", __func__, retval); return retval; } @@ -1035,7 +1035,7 @@ static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, int idx = opp->irq_msi; int srs, ibs; - DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64, __func__, addr, val); if (addr & 0xF) { return; @@ -1061,7 +1061,7 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) uint64_t r = 0; int i, srs; - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr); if (addr & 0xF) { return -1; } @@ -1096,7 +1096,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) { uint64_t r = 0; - DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + DPRINTF("%s: addr %#" HWADDR_PRIx, __func__, addr); /* TODO: EISR/EIMR */ @@ -1106,7 +1106,7 @@ static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64, __func__, addr, val); /* TODO: EISR/EIMR */ @@ -1120,7 +1120,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IRQDest *dst; int s_IRQ, n_IRQ; - DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x", __func__, idx, addr, val); if (idx < 0 || idx >= opp->nb_cpus) { @@ -1146,16 +1146,16 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x80: /* CTPR */ dst->ctpr = val & 0x0000000F; - DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", + DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d", __func__, idx, dst->ctpr, dst->raised.priority, dst->servicing.priority); if (dst->raised.priority <= dst->ctpr) { - DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", + DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr", __func__, idx); qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); } else if (dst->raised.priority > dst->servicing.priority) { - DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", + DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d", __func__, idx, dst->raised.next); qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); } @@ -1168,11 +1168,11 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, /* Read-only register */ break; case 0xB0: /* EOI */ - DPRINTF("EOI\n"); + DPRINTF("EOI"); s_IRQ = IRQ_get_next(opp, &dst->servicing); if (s_IRQ < 0) { - DPRINTF("%s: EOI with no interrupt in service\n", __func__); + DPRINTF("%s: EOI with no interrupt in service", __func__); break; } @@ -1185,7 +1185,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, if (n_IRQ != -1 && (s_IRQ == -1 || IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { - DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", + DPRINTF("Raise OpenPIC INT output cpu %d irq %d", idx, n_IRQ); qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); } @@ -1207,11 +1207,11 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) IRQSource *src; int retval, irq; - DPRINTF("Lower OpenPIC INT output\n"); + DPRINTF("Lower OpenPIC INT output"); qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); irq = IRQ_get_next(opp, &dst->raised); - DPRINTF("IACK: irq=%d\n", irq); + DPRINTF("IACK: irq=%d", irq); if (irq == -1) { /* No more interrupt pending */ @@ -1221,7 +1221,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) src = &opp->src[irq]; if (!(src->ivpr & IVPR_ACTIVITY_MASK) || !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { - fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", + error_report("%s: bad raised IRQ %d ctpr %d ivpr 0x%08x", __func__, irq, dst->ctpr, src->ivpr); openpic_update_irq(opp, irq); retval = opp->spve; @@ -1241,7 +1241,7 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) /* Timers and IPIs support multicast. */ if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) || ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) { - DPRINTF("irq is IPI or TMR\n"); + DPRINTF("irq is IPI or TMR"); src->destmask &= ~(1 << cpu); if (src->destmask && !src->level) { /* trigger on CPUs that didn't know about it yet */ @@ -1262,7 +1262,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, IRQDest *dst; uint32_t retval; - DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); + DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx, __func__, idx, addr); retval = 0xFFFFFFFF; if (idx < 0 || idx >= opp->nb_cpus) { @@ -1290,7 +1290,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, default: break; } - DPRINTF("%s: => 0x%08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x", __func__, retval); return retval; } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index b298fac7c6..7077aaaee6 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -64,10 +64,6 @@ xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x] xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]" xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x" -xics_alloc(int irq) "irq %d" -xics_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" -xics_ics_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" -xics_ics_free_warn(int src, int irq) "Source#%d, irq %d is already free" # hw/intc/s390_flic_kvm.c flic_create_device(int err) "flic: create device failed %d" diff --git a/hw/intc/xics.c b/hw/intc/xics.c index a1cc0e420c..e73e623e3b 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -334,7 +334,6 @@ static void icp_realize(DeviceState *dev, Error **errp) } cpu = POWERPC_CPU(obj); - cpu->intc = OBJECT(icp); icp->cs = CPU(obj); env = &cpu->env; @@ -384,6 +383,27 @@ static const TypeInfo icp_info = { .class_size = sizeof(ICPStateClass), }; +Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp) +{ + Error *local_err = NULL; + Object *obj; + + obj = object_new(type); + object_property_add_child(cpu, type, obj, &error_abort); + object_unref(obj); + object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi), + &error_abort); + object_property_add_const_link(obj, ICP_PROP_CPU, cpu, &error_abort); + object_property_set_bool(obj, true, "realized", &local_err); + if (local_err) { + object_unparent(obj); + error_propagate(errp, local_err); + obj = NULL; + } + + return obj; +} + /* * ICS: Source layer */ @@ -693,18 +713,6 @@ static const TypeInfo xics_fabric_info = { /* * Exported functions */ -qemu_irq xics_get_qirq(XICSFabric *xi, int irq) -{ - XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); - ICSState *ics = xic->ics_get(xi, irq); - - if (ics) { - return ics->qirqs[irq - ics->offset]; - } - - return NULL; -} - ICPState *xics_icp_get(XICSFabric *xi, int server) { XICSFabricClass *xic = XICS_FABRIC_GET_CLASS(xi); diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index d98ea8b130..5a0967caf4 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -245,122 +245,6 @@ void xics_spapr_init(sPAPRMachineState *spapr) spapr_register_hypercall(H_IPOLL, h_ipoll); } -#define ICS_IRQ_FREE(ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - -static int ics_find_free_block(ICSState *ics, int num, int alignnum) -{ - int first, i; - - for (first = 0; first < ics->nr_irqs; first += alignnum) { - if (num > (ics->nr_irqs - first)) { - return -1; - } - for (i = first; i < first + num; ++i) { - if (!ICS_IRQ_FREE(ics, i)) { - break; - } - } - if (i == (first + num)) { - return first; - } - } - - return -1; -} - -int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp) -{ - int irq; - - if (!ics) { - return -1; - } - if (irq_hint) { - if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { - error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); - return -1; - } - irq = irq_hint; - } else { - irq = ics_find_free_block(ics, 1, 1); - if (irq < 0) { - error_setg(errp, "can't allocate IRQ: no IRQ left"); - return -1; - } - irq += ics->offset; - } - - ics_set_irq_type(ics, irq - ics->offset, lsi); - trace_xics_alloc(irq); - - return irq; -} - -/* - * Allocate block of consecutive IRQs, and return the number of the first IRQ in - * the block. If align==true, aligns the first IRQ number to num. - */ -int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi, - bool align, Error **errp) -{ - int i, first = -1; - - if (!ics) { - return -1; - } - - /* - * MSIMesage::data is used for storing VIRQ so - * it has to be aligned to num to support multiple - * MSI vectors. MSI-X is not affected by this. - * The hint is used for the first IRQ, the rest should - * be allocated continuously. - */ - if (align) { - assert((num == 1) || (num == 2) || (num == 4) || - (num == 8) || (num == 16) || (num == 32)); - first = ics_find_free_block(ics, num, num); - } else { - first = ics_find_free_block(ics, num, 1); - } - if (first < 0) { - error_setg(errp, "can't find a free %d-IRQ block", num); - return -1; - } - - if (first >= 0) { - for (i = first; i < first + num; ++i) { - ics_set_irq_type(ics, i, lsi); - } - } - first += ics->offset; - - trace_xics_alloc_block(first, num, lsi, align); - - return first; -} - -static void ics_free(ICSState *ics, int srcno, int num) -{ - int i; - - for (i = srcno; i < srcno + num; ++i) { - if (ICS_IRQ_FREE(ics, i)) { - trace_xics_ics_free_warn(0, i + ics->offset); - } - memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); - } -} - -void spapr_ics_free(ICSState *ics, int irq, int num) -{ - if (ics_valid_irq(ics, irq)) { - trace_xics_ics_free(0, irq, num); - ics_free(ics, irq - ics->offset, num); - } -} - void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle) { uint32_t interrupt_server_ranges_prop[] = { diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 66eace5a5c..6e74b61cb6 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -109,7 +109,6 @@ void pc_dimm_memory_plug(DeviceState *dev, MemoryHotplugState *hpms, memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr); vmstate_register_ram(vmstate_mr, dev); - numa_set_mem_node_id(addr, memory_region_size(mr), dimm->node); out: error_propagate(errp, local_err); @@ -122,7 +121,6 @@ void pc_dimm_memory_unplug(DeviceState *dev, MemoryHotplugState *hpms, PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm); MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm); - numa_unset_mem_node_id(dimm->addr, memory_region_size(mr), dimm->node); memory_region_del_subregion(&hpms->mr, mr); vmstate_unregister_ram(vmstate_mr, dev); } diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs index c018f6b2ff..0f4ee71dcb 100644 --- a/hw/nvram/Makefile.objs +++ b/hw/nvram/Makefile.objs @@ -1,5 +1,6 @@ common-obj-$(CONFIG_DS1225Y) += ds1225y.o common-obj-y += eeprom93xx.o +common-obj-y += eeprom_at24c.o common-obj-y += fw_cfg.o common-obj-y += chrp_nvram.o common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c new file mode 100644 index 0000000000..efa3621ac6 --- /dev/null +++ b/hw/nvram/eeprom_at24c.c @@ -0,0 +1,205 @@ +/* + * *AT24C* series I2C EEPROM + * + * Copyright (c) 2015 Michael Davidsaver + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the LICENSE file in the top-level directory. + */ + +#include <string.h> + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/i2c/i2c.h" +#include "sysemu/block-backend.h" + +/* #define DEBUG_AT24C */ + +#ifdef DEBUG_AT24C +#define DPRINTK(FMT, ...) printf(TYPE_AT24C_EE " : " FMT, ## __VA_ARGS__) +#else +#define DPRINTK(FMT, ...) do {} while (0) +#endif + +#define ERR(FMT, ...) fprintf(stderr, TYPE_AT24C_EE " : " FMT, \ + ## __VA_ARGS__) + +#define TYPE_AT24C_EE "at24c-eeprom" +#define AT24C_EE(obj) OBJECT_CHECK(EEPROMState, (obj), TYPE_AT24C_EE) + +typedef struct EEPROMState { + I2CSlave parent_obj; + + /* address counter */ + uint16_t cur; + /* total size in bytes */ + uint32_t rsize; + bool writable; + /* cells changed since last START? */ + bool changed; + /* during WRITE, # of address bytes transfered */ + uint8_t haveaddr; + + uint8_t *mem; + + BlockBackend *blk; +} EEPROMState; + +static +int at24c_eeprom_event(I2CSlave *s, enum i2c_event event) +{ + EEPROMState *ee = container_of(s, EEPROMState, parent_obj); + + switch (event) { + case I2C_START_SEND: + case I2C_START_RECV: + case I2C_FINISH: + ee->haveaddr = 0; + DPRINTK("clear\n"); + if (ee->blk && ee->changed) { + int len = blk_pwrite(ee->blk, 0, ee->mem, ee->rsize, 0); + if (len != ee->rsize) { + ERR(TYPE_AT24C_EE + " : failed to write backing file\n"); + } + DPRINTK("Wrote to backing file\n"); + } + ee->changed = false; + break; + case I2C_NACK: + break; + } + return 0; +} + +static +int at24c_eeprom_recv(I2CSlave *s) +{ + EEPROMState *ee = AT24C_EE(s); + int ret; + + ret = ee->mem[ee->cur]; + + ee->cur = (ee->cur + 1u) % ee->rsize; + DPRINTK("Recv %02x %c\n", ret, ret); + + return ret; +} + +static +int at24c_eeprom_send(I2CSlave *s, uint8_t data) +{ + EEPROMState *ee = AT24C_EE(s); + + if (ee->haveaddr < 2) { + ee->cur <<= 8; + ee->cur |= data; + ee->haveaddr++; + if (ee->haveaddr == 2) { + ee->cur %= ee->rsize; + DPRINTK("Set pointer %04x\n", ee->cur); + } + + } else { + if (ee->writable) { + DPRINTK("Send %02x\n", data); + ee->mem[ee->cur] = data; + ee->changed = true; + } else { + DPRINTK("Send error %02x read-only\n", data); + } + ee->cur = (ee->cur + 1u) % ee->rsize; + + } + + return 0; +} + +static +int at24c_eeprom_init(I2CSlave *i2c) +{ + EEPROMState *ee = AT24C_EE(i2c); + + ee->mem = g_malloc0(ee->rsize); + + if (ee->blk) { + int64_t len = blk_getlength(ee->blk); + + if (len != ee->rsize) { + ERR(TYPE_AT24C_EE " : Backing file size %lu != %u\n", + (unsigned long)len, (unsigned)ee->rsize); + exit(1); + } + + if (blk_set_perm(ee->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, + BLK_PERM_ALL, &error_fatal) < 0) + { + ERR(TYPE_AT24C_EE + " : Backing file incorrect permission\n"); + exit(1); + } + } + return 0; +} + +static +void at24c_eeprom_reset(DeviceState *state) +{ + EEPROMState *ee = AT24C_EE(state); + + ee->changed = false; + ee->cur = 0; + ee->haveaddr = 0; + + memset(ee->mem, 0, ee->rsize); + + if (ee->blk) { + int len = blk_pread(ee->blk, 0, ee->mem, ee->rsize); + + if (len != ee->rsize) { + ERR(TYPE_AT24C_EE + " : Failed initial sync with backing file\n"); + } + DPRINTK("Reset read backing file\n"); + } +} + +static Property at24c_eeprom_props[] = { + DEFINE_PROP_UINT32("rom-size", EEPROMState, rsize, 0), + DEFINE_PROP_BOOL("writable", EEPROMState, writable, true), + DEFINE_PROP_DRIVE("drive", EEPROMState, blk), + DEFINE_PROP_END_OF_LIST() +}; + +static +void at24c_eeprom_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->init = &at24c_eeprom_init; + k->event = &at24c_eeprom_event; + k->recv = &at24c_eeprom_recv; + k->send = &at24c_eeprom_send; + + dc->props = at24c_eeprom_props; + dc->reset = at24c_eeprom_reset; +} + +static +const TypeInfo at24c_eeprom_type = { + .name = TYPE_AT24C_EE, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(EEPROMState), + .class_size = sizeof(I2CSlaveClass), + .class_init = at24c_eeprom_class_init, +}; + +static void at24c_eeprom_register(void) +{ + type_register_static(&at24c_eeprom_type); +} + +type_init(at24c_eeprom_register) diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 39cd24464d..279badc894 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -423,11 +423,6 @@ static void e500_pcihost_bridge_realize(PCIDevice *d, Error **errp) PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(), "/e500-ccsr")); - pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI); - d->config[PCI_HEADER_TYPE] = - (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | - PCI_HEADER_TYPE_BRIDGE; - memory_region_init_alias(&b->bar0, OBJECT(ccsr), "e500-pci-bar0", &ccsr->ccsr_space, 0, int128_get64(ccsr->ccsr_space.size)); pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0); diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 5cf0dabef3..c4fe06ea2a 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -685,6 +685,8 @@ static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, int i, j, k; dev = qdev_create(NULL, TYPE_OPENPIC); + object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev), + &error_fatal); qdev_prop_set_uint32(dev, "model", params->mpic_version); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); @@ -884,6 +886,8 @@ void ppce500_init(MachineState *machine, PPCE500Params *params) /* PCI */ dev = qdev_create(NULL, "e500-pcihost"); + object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev), + &error_abort); qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); qdev_init_nofail(dev); diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 82ff440b33..03317db853 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -126,7 +126,6 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) Error *local_err = NULL; CPUState *cs = CPU(child); PowerPCCPU *cpu = POWERPC_CPU(cs); - Object *obj; object_property_set_bool(child, true, "realized", &local_err); if (local_err) { @@ -134,13 +133,7 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) return; } - obj = object_new(TYPE_PNV_ICP); - object_property_add_child(child, "icp", obj, NULL); - object_unref(obj); - object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(xi), - &error_abort); - object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + cpu->intc = icp_create(child, TYPE_PNV_ICP, xi, &local_err); if (local_err) { error_propagate(errp, local_err); return; @@ -148,7 +141,6 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) powernv_cpu_init(cpu, &local_err); if (local_err) { - object_unparent(obj); error_propagate(errp, local_err); return; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1ac7eb0f8c..6785a90c60 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -641,6 +641,26 @@ static void spapr_populate_cpus_dt_node(void *fdt, sPAPRMachineState *spapr) } +static uint32_t spapr_pc_dimm_node(MemoryDeviceInfoList *list, ram_addr_t addr) +{ + MemoryDeviceInfoList *info; + + for (info = list; info; info = info->next) { + MemoryDeviceInfo *value = info->value; + + if (value && value->type == MEMORY_DEVICE_INFO_KIND_DIMM) { + PCDIMMDeviceInfo *pcdimm_info = value->u.dimm.data; + + if (pcdimm_info->addr >= addr && + addr < (pcdimm_info->addr + pcdimm_info->size)) { + return pcdimm_info->node; + } + } + } + + return -1; +} + /* * Adds ibm,dynamic-reconfiguration-memory node. * Refer to docs/specs/ppc-spapr-hotplug.txt for the documentation @@ -658,6 +678,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) lmb_size; uint32_t *int_buf, *cur_index, buf_len; int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1; + MemoryDeviceInfoList *dimms = NULL; /* * Don't create the node if there is no hotpluggable memory @@ -692,6 +713,11 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) goto out; } + if (hotplug_lmb_start) { + MemoryDeviceInfoList **prev = &dimms; + qmp_pc_dimm_device_list(qdev_get_machine(), &prev); + } + /* ibm,dynamic-memory */ int_buf[0] = cpu_to_be32(nr_lmbs); cur_index++; @@ -709,7 +735,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff); dynamic_memory[2] = cpu_to_be32(spapr_drc_index(drc)); dynamic_memory[3] = cpu_to_be32(0); /* reserved */ - dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL)); + dynamic_memory[4] = cpu_to_be32(spapr_pc_dimm_node(dimms, addr)); if (memory_region_present(get_system_memory(), addr)) { dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED); } else { @@ -732,6 +758,7 @@ static int spapr_populate_drconf_memory(sPAPRMachineState *spapr, void *fdt) cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE; } + qapi_free_MemoryDeviceInfoList(dimms); ret = fdt_setprop(fdt, offset, "ibm,dynamic-memory", int_buf, buf_len); if (ret < 0) { goto out; @@ -916,9 +943,8 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) _FDT(fdt_setprop_cell(fdt, rtas, "rtas-event-scan-rate", RTAS_EVENT_SCAN_RATE)); - if (msi_nonbroken) { - _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0)); - } + g_assert(msi_nonbroken); + _FDT(fdt_setprop(fdt, rtas, "ibm,change-msix-capable", NULL, 0)); /* * According to PAPR, rtas ibm,os-term does not guarantee a return @@ -1427,7 +1453,7 @@ static int spapr_reset_drcs(Object *child, void *opaque) return 0; } -static void ppc_spapr_reset(void) +static void spapr_machine_reset(void) { MachineState *machine = MACHINE(qdev_get_machine()); sPAPRMachineState *spapr = SPAPR_MACHINE(machine); @@ -1440,7 +1466,10 @@ static void ppc_spapr_reset(void) /* Check for unknown sysbus devices */ foreach_dynamic_sysbus_device(find_unknown_sysbus_device, NULL); - if (kvm_enabled() && kvmppc_has_cap_mmu_radix()) { + first_ppc_cpu = POWERPC_CPU(first_cpu); + if (kvm_enabled() && kvmppc_has_cap_mmu_radix() && + ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, + spapr->max_compat_pvr)) { /* If using KVM with radix mode available, VCPUs can be started * without a HPT because KVM will start them in radix mode. * Set the GR bit in PATB so that we know there is no HPT. */ @@ -1499,7 +1528,6 @@ static void ppc_spapr_reset(void) g_free(fdt); /* Set up the entry state */ - first_ppc_cpu = POWERPC_CPU(first_cpu); first_ppc_cpu->env.gpr[3] = fdt_addr; first_ppc_cpu->env.gpr[5] = 0; first_cpu->halted = 0; @@ -2265,7 +2293,7 @@ out: } /* pSeries LPAR / sPAPR hardware init */ -static void ppc_spapr_init(MachineState *machine) +static void spapr_machine_init(MachineState *machine) { sPAPRMachineState *spapr = SPAPR_MACHINE(machine); sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine); @@ -2793,7 +2821,7 @@ static void spapr_set_vsmt(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, (uint32_t *)opaque, errp); } -static void spapr_machine_initfn(Object *obj) +static void spapr_instance_init(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -3180,12 +3208,10 @@ void spapr_core_release(DeviceState *dev) if (smc->pre_2_10_has_unused_icps) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc)); - size_t size = object_type_get_instance_size(scc->cpu_type); int i; for (i = 0; i < cc->nr_threads; i++) { - CPUState *cs = CPU(sc->threads + i * size); + CPUState *cs = CPU(sc->threads[i]); pre_2_10_vmstate_register_dummy_icp(cs->cpu_index); } @@ -3231,7 +3257,7 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc); sPAPRCPUCore *core = SPAPR_CPU_CORE(OBJECT(dev)); CPUCore *cc = CPU_CORE(dev); - CPUState *cs = CPU(core->threads); + CPUState *cs = CPU(core->threads[0]); sPAPRDRConnector *drc; Error *local_err = NULL; int smt = kvmppc_smt_threads(); @@ -3276,15 +3302,12 @@ static void spapr_core_plug(HotplugHandler *hotplug_dev, DeviceState *dev, core_slot->cpu = OBJECT(dev); if (smc->pre_2_10_has_unused_icps) { - sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(cc)); - size_t size = object_type_get_instance_size(scc->cpu_type); int i; for (i = 0; i < cc->nr_threads; i++) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(dev); - void *obj = sc->threads + i * size; - cs = CPU(obj); + cs = CPU(sc->threads[i]); pre_2_10_vmstate_unregister_dummy_icp(cs->cpu_index); } } @@ -3563,6 +3586,139 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id) return cpu ? ICP(cpu->intc) : NULL; } +#define ICS_IRQ_FREE(ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block(ICSState *ics, int num, int alignnum) +{ + int first, i; + + for (first = 0; first < ics->nr_irqs; first += alignnum) { + if (num > (ics->nr_irqs - first)) { + return -1; + } + for (i = first; i < first + num; ++i) { + if (!ICS_IRQ_FREE(ics, i)) { + break; + } + } + if (i == (first + num)) { + return first; + } + } + + return -1; +} + +/* + * Allocate the IRQ number and set the IRQ type, LSI or MSI + */ +static void spapr_irq_set_lsi(sPAPRMachineState *spapr, int irq, bool lsi) +{ + ics_set_irq_type(spapr->ics, irq - spapr->ics->offset, lsi); +} + +int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, + Error **errp) +{ + ICSState *ics = spapr->ics; + int irq; + + if (!ics) { + return -1; + } + if (irq_hint) { + if (!ICS_IRQ_FREE(ics, irq_hint - ics->offset)) { + error_setg(errp, "can't allocate IRQ %d: already in use", irq_hint); + return -1; + } + irq = irq_hint; + } else { + irq = ics_find_free_block(ics, 1, 1); + if (irq < 0) { + error_setg(errp, "can't allocate IRQ: no IRQ left"); + return -1; + } + irq += ics->offset; + } + + spapr_irq_set_lsi(spapr, irq, lsi); + trace_spapr_irq_alloc(irq); + + return irq; +} + +/* + * Allocate block of consecutive IRQs, and return the number of the first IRQ in + * the block. If align==true, aligns the first IRQ number to num. + */ +int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, + bool align, Error **errp) +{ + ICSState *ics = spapr->ics; + int i, first = -1; + + if (!ics) { + return -1; + } + + /* + * MSIMesage::data is used for storing VIRQ so + * it has to be aligned to num to support multiple + * MSI vectors. MSI-X is not affected by this. + * The hint is used for the first IRQ, the rest should + * be allocated continuously. + */ + if (align) { + assert((num == 1) || (num == 2) || (num == 4) || + (num == 8) || (num == 16) || (num == 32)); + first = ics_find_free_block(ics, num, num); + } else { + first = ics_find_free_block(ics, num, 1); + } + if (first < 0) { + error_setg(errp, "can't find a free %d-IRQ block", num); + return -1; + } + + first += ics->offset; + for (i = first; i < first + num; ++i) { + spapr_irq_set_lsi(spapr, i, lsi); + } + + trace_spapr_irq_alloc_block(first, num, lsi, align); + + return first; +} + +void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num) +{ + ICSState *ics = spapr->ics; + int srcno = irq - ics->offset; + int i; + + if (ics_valid_irq(ics, irq)) { + trace_spapr_irq_free(0, irq, num); + for (i = srcno; i < srcno + num; ++i) { + if (ICS_IRQ_FREE(ics, i)) { + trace_spapr_irq_free_warn(0, i + ics->offset); + } + memset(&ics->irqs[i], 0, sizeof(ICSIRQState)); + } + } +} + +qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq) +{ + ICSState *ics = spapr->ics; + + if (ics_valid_irq(ics, irq)) { + return ics->qirqs[irq - ics->offset]; + } + + return NULL; +} + static void spapr_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { @@ -3622,8 +3778,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) * functions for the specific versioned machine types can override * these details for backwards compatibility */ - mc->init = ppc_spapr_init; - mc->reset = ppc_spapr_reset; + mc->init = spapr_machine_init; + mc->reset = spapr_machine_reset; mc->block_default_type = IF_SCSI; mc->max_cpus = 1024; mc->no_parallel = 1; @@ -3670,7 +3826,7 @@ static const TypeInfo spapr_machine_info = { .parent = TYPE_MACHINE, .abstract = true, .instance_size = sizeof(sPAPRMachineState), - .instance_init = spapr_machine_initfn, + .instance_init = spapr_instance_init, .instance_finalize = spapr_machine_finalizefn, .class_size = sizeof(sPAPRMachineClass), .class_init = spapr_machine_class_init, @@ -3714,27 +3870,47 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* + * pseries-2.12 + */ +static void spapr_machine_2_12_instance_options(MachineState *machine) +{ +} + +static void spapr_machine_2_12_class_options(MachineClass *mc) +{ + /* Defaults for the latest behaviour inherited from the base class */ +} + +DEFINE_SPAPR_MACHINE(2_12, "2.12", true); + +/* * pseries-2.11 */ +#define SPAPR_COMPAT_2_11 \ + HW_COMPAT_2_11 + static void spapr_machine_2_11_instance_options(MachineState *machine) { + spapr_machine_2_12_instance_options(machine); } static void spapr_machine_2_11_class_options(MachineClass *mc) { - /* Defaults for the latest behaviour inherited from the base class */ + spapr_machine_2_12_class_options(mc); + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11); } -DEFINE_SPAPR_MACHINE(2_11, "2.11", true); +DEFINE_SPAPR_MACHINE(2_11, "2.11", false); /* * pseries-2.10 */ #define SPAPR_COMPAT_2_10 \ - HW_COMPAT_2_10 \ + HW_COMPAT_2_10 static void spapr_machine_2_10_instance_options(MachineState *machine) { + spapr_machine_2_11_instance_options(machine); } static void spapr_machine_2_10_class_options(MachineClass *mc) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 3a4c174012..032438b9ce 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -26,6 +26,7 @@ static void spapr_cpu_reset(void *opaque) PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); cpu_reset(cs); @@ -35,6 +36,13 @@ static void spapr_cpu_reset(void *opaque) cs->halted = 1; env->spr[SPR_HIOR] = 0; + + /* Disable Power-saving mode Exit Cause exceptions for the CPU. + * This can cause issues when rebooting the guest if a secondary + * is awaken */ + if (cs != first_cpu) { + env->spr[SPR_LPCR] &= ~pcc->lpcr_pm; + } } static void spapr_cpu_destroy(PowerPCCPU *cpu) @@ -79,13 +87,11 @@ const char *spapr_get_cpu_core_type(const char *cpu_type) static void spapr_cpu_core_unrealizefn(DeviceState *dev, Error **errp) { sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); - sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); - size_t size = object_type_get_instance_size(scc->cpu_type); CPUCore *cc = CPU_CORE(dev); int i; for (i = 0; i < cc->nr_threads; i++) { - void *obj = sc->threads + i * size; + Object *obj = OBJECT(sc->threads[i]); DeviceState *dev = DEVICE(obj); CPUState *cs = CPU(dev); PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -104,7 +110,6 @@ static void spapr_cpu_core_realize_child(Object *child, Error *local_err = NULL; CPUState *cs = CPU(child); PowerPCCPU *cpu = POWERPC_CPU(cs); - Object *obj; object_property_set_bool(child, true, "realized", &local_err); if (local_err) { @@ -116,21 +121,14 @@ static void spapr_cpu_core_realize_child(Object *child, goto error; } - obj = object_new(spapr->icp_type); - object_property_add_child(child, "icp", obj, &error_abort); - object_unref(obj); - object_property_add_const_link(obj, ICP_PROP_XICS, OBJECT(spapr), - &error_abort); - object_property_add_const_link(obj, ICP_PROP_CPU, child, &error_abort); - object_property_set_bool(obj, true, "realized", &local_err); + cpu->intc = icp_create(child, spapr->icp_type, XICS_FABRIC(spapr), + &local_err); if (local_err) { - goto free_icp; + goto error; } return; -free_icp: - object_unparent(obj); error: error_propagate(errp, local_err); } @@ -146,9 +144,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev)); sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(OBJECT(dev)); CPUCore *cc = CPU_CORE(OBJECT(dev)); - size_t size; Error *local_err = NULL; - void *obj; + Object *obj; int i, j; if (!spapr) { @@ -156,18 +153,16 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) return; } - size = object_type_get_instance_size(scc->cpu_type); - sc->threads = g_malloc0(size * cc->nr_threads); + sc->threads = g_new(PowerPCCPU *, cc->nr_threads); for (i = 0; i < cc->nr_threads; i++) { char id[32]; CPUState *cs; PowerPCCPU *cpu; - obj = sc->threads + i * size; + obj = object_new(scc->cpu_type); - object_initialize(obj, size, scc->cpu_type); cs = CPU(obj); - cpu = POWERPC_CPU(cs); + cpu = sc->threads[i] = POWERPC_CPU(obj); cs->cpu_index = cc->core_id + i; cpu->vcpu_id = (cc->core_id * spapr->vsmt / smp_threads) + i; if (kvm_enabled() && !kvm_vcpu_id_is_valid(cpu->vcpu_id)) { @@ -192,7 +187,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) } for (j = 0; j < cc->nr_threads; j++) { - obj = sc->threads + j * size; + obj = OBJECT(sc->threads[j]); spapr_cpu_core_realize_child(obj, spapr, &local_err); if (local_err) { @@ -203,7 +198,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp) err: while (--i >= 0) { - obj = sc->threads + i * size; + obj = OBJECT(sc->threads[i]); object_unparent(obj); } g_free(sc->threads); diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index e377fc7dde..86836f0626 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -282,8 +282,7 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt) continue; } - interrupts[0] = cpu_to_be32(source->irq); - interrupts[1] = 0; + spapr_dt_xics_irq(interrupts, source->irq, false); _FDT(node_offset = fdt_add_subnode(fdt, event_sources, source_name)); _FDT(fdt_setprop(fdt, node_offset, "interrupts", interrupts, @@ -293,9 +292,6 @@ void spapr_dt_events(sPAPRMachineState *spapr, void *fdt) irq_ranges[count++] = cpu_to_be32(1); } - irq_ranges[count] = cpu_to_be32(count); - count++; - _FDT((fdt_setprop(fdt, event_sources, "interrupt-controller", NULL, 0))); _FDT((fdt_setprop_cell(fdt, event_sources, "#interrupt-cells", 2))); _FDT((fdt_setprop(fdt, event_sources, "interrupt-ranges", @@ -472,9 +468,8 @@ static void spapr_powerdown_req(Notifier *n, void *opaque) rtas_event_log_queue(spapr, entry); - qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), - rtas_event_log_to_irq(spapr, - RTAS_LOG_TYPE_EPOW))); + qemu_irq_pulse(spapr_qirq(spapr, + rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_EPOW))); } static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, @@ -556,9 +551,8 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action, rtas_event_log_queue(spapr, entry); - qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), - rtas_event_log_to_irq(spapr, - RTAS_LOG_TYPE_HOTPLUG))); + qemu_irq_pulse(spapr_qirq(spapr, + rtas_event_log_to_irq(spapr, RTAS_LOG_TYPE_HOTPLUG))); } void spapr_hotplug_req_add_by_index(sPAPRDRConnector *drc) @@ -678,7 +672,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr, spapr_event_sources_get_source(spapr->event_sources, i); g_assert(source->enabled); - qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), source->irq)); + qemu_irq_pulse(spapr_qirq(spapr, source->irq)); } } @@ -718,7 +712,7 @@ void spapr_events_init(sPAPRMachineState *spapr) spapr->event_sources = spapr_event_sources_new(); spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_EPOW, - spapr_ics_alloc(spapr->ics, 0, false, + spapr_irq_alloc(spapr, 0, false, &error_fatal)); /* NOTE: if machine supports modern/dedicated hotplug event source, @@ -731,7 +725,7 @@ void spapr_events_init(sPAPRMachineState *spapr) */ if (spapr->use_hotplug_event_source) { spapr_event_sources_register(spapr->event_sources, EVENT_CLASS_HOT_PLUG, - spapr_ics_alloc(spapr->ics, 0, false, + spapr_irq_alloc(spapr, 0, false, &error_fatal)); } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 5a3122a9f9..88797b3d36 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -314,7 +314,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, return; } - spapr_ics_free(spapr->ics, msi->first_irq, msi->num); + spapr_irq_free(spapr, msi->first_irq, msi->num); if (msi_present(pdev)) { spapr_msi_setmsg(pdev, 0, false, 0, 0); } @@ -352,7 +352,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, } /* Allocate MSIs */ - irq = spapr_ics_alloc_block(spapr->ics, req_num, false, + irq = spapr_irq_alloc_block(spapr, req_num, false, ret_intr_type == RTAS_TYPE_MSI, &err); if (err) { error_reportf_err(err, "Can't allocate MSIs for device %x: ", @@ -363,7 +363,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, /* Release previous MSIs */ if (msi) { - spapr_ics_free(spapr->ics, msi->first_irq, msi->num); + spapr_irq_free(spapr, msi->first_irq, msi->num); g_hash_table_remove(phb->msi, &config_addr); } @@ -723,7 +723,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr, trace_spapr_pci_msi_write(addr, data, irq); - qemu_irq_pulse(xics_get_qirq(XICS_FABRIC(spapr), irq)); + qemu_irq_pulse(spapr_qirq(spapr, irq)); } static const MemoryRegionOps spapr_msi_ops = { @@ -1675,7 +1675,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) uint32_t irq; Error *local_err = NULL; - irq = spapr_ics_alloc_block(spapr->ics, 1, true, false, &local_err); + irq = spapr_irq_alloc_block(spapr, 1, true, false, &local_err); if (local_err) { error_propagate(errp, local_err); error_prepend(errp, "can't allocate LSIs: "); @@ -2121,8 +2121,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb, irqmap[2] = 0; irqmap[3] = cpu_to_be32(j+1); irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq); - irqmap[6] = cpu_to_be32(0x8); + spapr_dt_xics_irq(&irqmap[5], phb->lsi_table[lsi_num].irq, true); } } /* Write interrupt map */ diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index cdf0b607a0..4bb939d3d1 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -162,6 +162,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, if (cpu != NULL) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); if (!cs->halted) { rtas_st(rets, 0, RTAS_OUT_HW_ERROR); @@ -174,6 +175,10 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, kvm_cpu_synchronize_state(cs); env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + + /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ + env->spr[SPR_LPCR] |= pcc->lpcr_pm; + env->nip = start; env->gpr[3] = r3; cs->halted = 0; @@ -197,19 +202,15 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); cs->halted = 1; qemu_cpu_kick(cs); - /* - * While stopping a CPU, the guest calls H_CPPR which - * effectively disables interrupts on XICS level. - * However decrementer interrupts in TCG can still - * wake the CPU up so here we disable interrupts in MSR - * as well. - * As rtas_start_cpu() resets the whole MSR anyway, there is - * no need to bother with specific bits, we just clear it. - */ - env->msr = 0; + + /* Disable Power-saving mode Exit Cause exceptions for the CPU. + * This could deliver an interrupt on a dying CPU and crash the + * guest */ + env->spr[SPR_LPCR] &= ~pcc->lpcr_pm; } static inline int sysparm_st(target_ulong addr, target_ulong len, diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ea3bc8bd9e..472dd6f33a 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -126,8 +126,9 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, } if (dev->irq) { - uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0}; + uint32_t ints_prop[2]; + spapr_dt_xics_irq(ints_prop, dev->irq, false); ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, sizeof(ints_prop)); if (ret < 0) { @@ -454,7 +455,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq = spapr_ics_alloc(spapr->ics, dev->irq, false, &local_err); + dev->irq = spapr_irq_alloc(spapr, dev->irq, false, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 4a6a6490fa..b7c3e64b5e 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -12,6 +12,10 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) " # hw/ppc/spapr.c spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" +spapr_irq_alloc(int irq) "irq %d" +spapr_irq_alloc_block(int first, int num, bool lsi, int align) "first irq %d, %d irqs, lsi=%d, alignnum %d" +spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs" +spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free" # hw/ppc/spapr_hcall.c spapr_cas_pvr_try(uint32_t pvr) "0x%x" diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 081e3ef6f4..3af13ea027 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -104,7 +104,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) SubchDev *sch; Error *err = NULL; - sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp); + sch = css_create_sch(cdev->devno, cbus->squash_mcss, errp); if (!sch) { return; } diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index c4a9735d71..a02d708239 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -99,6 +99,8 @@ VirtualCssBus *virtual_css_bus_init(void) /* Create bridge device */ dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); + object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, + OBJECT(dev), NULL); qdev_init_nofail(dev); /* Create bus on bridge device */ @@ -123,6 +125,11 @@ static Property virtual_css_bridge_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static bool prop_get_true(Object *obj, Error **errp) +{ + return true; +} + static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) { HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); @@ -131,6 +138,12 @@ static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) hc->unplug = ccw_device_unplug; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = virtual_css_bridge_properties; + object_class_property_add_bool(klass, "cssid-unrestricted", + prop_get_true, NULL, NULL); + object_class_property_set_description(klass, "cssid-unrestricted", + "A css device can use any cssid, regardless whether virtual" + " or not (read only, always true)", + NULL); } static const TypeInfo virtual_css_bridge_info = { diff --git a/hw/s390x/css.c b/hw/s390x/css.c index f6b5c807cd..f071e1394b 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1723,12 +1723,6 @@ void css_undo_stcrw(CRW *crw) QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling); } -int css_do_tpi(IOIntCode *int_code, int lowcore) -{ - /* No pending interrupts for !KVM. */ - return 0; - } - int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, int rfmt, void *buf) { @@ -2370,22 +2364,12 @@ const PropertyInfo css_devid_ro_propinfo = { .get = get_css_devid, }; -SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, - Error **errp) +SubchDev *css_create_sch(CssDevId bus_id, bool squash_mcss, Error **errp) { uint16_t schid = 0; SubchDev *sch; if (bus_id.valid) { - if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) { - error_setg(errp, "cssid %hhx not valid for %s devices", - bus_id.cssid, - (is_virtual ? "virtual" : "non-virtual")); - return NULL; - } - } - - if (bus_id.valid) { if (squash_mcss) { bus_id.cssid = channel_subsys.default_cssid; } else if (!channel_subsys.css[bus_id.cssid]) { @@ -2396,19 +2380,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, bus_id.devid, &schid, errp)) { return NULL; } - } else if (squash_mcss || is_virtual) { - bus_id.cssid = channel_subsys.default_cssid; - - if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, - &bus_id.devid, &schid, errp)) { - return NULL; - } } else { - for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) { - if (bus_id.cssid == VIRTUAL_CSSID) { - continue; - } - + for (bus_id.cssid = channel_subsys.default_cssid;;) { if (!channel_subsys.css[bus_id.cssid]) { css_create_css_image(bus_id.cssid, false); } @@ -2418,7 +2391,8 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, NULL)) { break; } - if (bus_id.cssid == MAX_CSSID) { + bus_id.cssid = (bus_id.cssid + 1) % MAX_CSSID; + if (bus_id.cssid == channel_subsys.default_cssid) { error_setg(errp, "Virtual channel subsystem is full!"); return NULL; } diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 0ef232ec27..4a9d4d2534 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -77,7 +77,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) goto out_err_propagate; } - sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err); + sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, &err); if (!sch) { goto out_mdevid_free; } diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 560bd82a0f..2993f0ddef 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -284,6 +284,7 @@ struct S390PCIBusDevice { uint64_t fmb_addr; uint8_t isc; uint16_t noi; + uint16_t maxstbl; uint8_t sum; S390MsixInfo msix; AdapterRoutes routes; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8e088f3dc9..be449210d9 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -142,7 +142,7 @@ out: return rc; } -int clp_service_call(S390CPU *cpu, uint8_t r2) +int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) { ClpReqHdr *reqh; ClpRspHdr *resh; @@ -158,37 +158,40 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } reqh = (ClpReqHdr *)buffer; req_len = lduw_p(&reqh->len); if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, req_len + sizeof(*resh))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } resh = (ClpRspHdr *)(buffer + req_len); res_len = lduw_p(&resh->len); if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } if ((req_len + res_len) > 8192) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, req_len + res_len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } @@ -294,6 +297,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) stq_p(&resgrp->msia, ZPCI_MSI_ADDR); stw_p(&resgrp->mui, 0); stw_p(&resgrp->i, 128); + stw_p(&resgrp->maxstbl, 128); resgrp->version = 0; stw_p(&resgrp->hdr.rsp, CLP_RC_OK); @@ -308,19 +312,78 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) out: if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer, req_len + res_len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } setcc(cpu, cc); return 0; } -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +/** + * Swap data contained in s390x big endian registers to little endian + * PCI bars. + * + * @ptr: a pointer to a uint64_t data field + * @len: the length of the valid data, must be 1,2,4 or 8 + */ +static int zpci_endian_swap(uint64_t *ptr, uint8_t len) +{ + uint64_t data = *ptr; + + switch (len) { + case 1: + break; + case 2: + data = bswap16(data); + break; + case 4: + data = bswap32(data); + break; + case 8: + data = bswap64(data); + break; + default: + return -EINVAL; + } + *ptr = data; + return 0; +} + +static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset, + uint8_t len) +{ + MemoryRegion *subregion; + uint64_t subregion_size; + + QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { + subregion_size = int128_get64(subregion->size); + if ((offset >= subregion->addr) && + (offset + len) <= (subregion->addr + subregion_size)) { + mr = subregion; + break; + } + } + return mr; +} + +static MemTxResult zpci_read_bar(S390PCIBusDevice *pbdev, uint8_t pcias, + uint64_t offset, uint64_t *data, uint8_t len) +{ + MemoryRegion *mr; + + mr = pbdev->pdev->io_regions[pcias].memory; + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; + return memory_region_dispatch_read(mr, offset, data, len, + MEMTXATTRS_UNSPECIFIED); +} + +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; uint64_t offset; uint64_t data; - MemoryRegion *mr; MemTxResult result; uint8_t len; uint32_t fh; @@ -329,12 +392,12 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } @@ -343,6 +406,11 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) len = env->regs[r2] & 0xf; offset = env->regs[r2 + 1]; + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); + return 0; + } + pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh); if (!pbdev) { DPRINTF("pcilg no pci dev\n"); @@ -351,12 +419,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); @@ -365,44 +428,33 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) break; } - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + switch (pcias) { + case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX: + if (!len || (len > (8 - (offset & 0x7)))) { + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - mr = pbdev->pdev->io_regions[pcias].memory; - result = memory_region_dispatch_read(mr, offset, &data, len, - MEMTXATTRS_UNSPECIFIED); + result = zpci_read_bar(pbdev, pcias, offset, &data, len); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + break; + case ZPCI_CONFIG_BAR: + if (!len || (len > (4 - (offset & 0x3))) || len == 3) { + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } data = pci_host_config_read_common( pbdev->pdev, offset, pci_config_size(pbdev->pdev), len); - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: - program_interrupt(env, PGM_OPERAND, 4); + if (zpci_endian_swap(&data, len)) { + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else { - DPRINTF("invalid space\n"); + break; + default: + DPRINTF("pcilg invalid space\n"); setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); return 0; @@ -413,24 +465,23 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) return 0; } -static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) +static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, + uint64_t offset, uint64_t data, uint8_t len) { - if (pbdev->msix.available && pbdev->msix.table_bar == pcias && - offset >= pbdev->msix.table_offset && - offset < (pbdev->msix.table_offset + - pbdev->msix.entries * PCI_MSIX_ENTRY_SIZE)) { - return 1; - } else { - return 0; - } + MemoryRegion *mr; + + mr = pbdev->pdev->io_regions[pcias].memory; + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; + return memory_region_dispatch_write(mr, offset, data, len, + MEMTXATTRS_UNSPECIFIED); } -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint64_t offset, data; S390PCIBusDevice *pbdev; - MemoryRegion *mr; MemTxResult result; uint8_t len; uint32_t fh; @@ -439,12 +490,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); return 0; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } @@ -452,6 +503,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) pcias = (env->regs[r2] >> 16) & 0xf; len = env->regs[r2] & 0xf; offset = env->regs[r2 + 1]; + data = env->regs[r1]; + + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); + return 0; + } pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh); if (!pbdev) { @@ -461,12 +518,10 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: + /* ZPCI_FS_RESERVED, ZPCI_FS_STANDBY and ZPCI_FS_DISABLED + * are already covered by the FH_MASK_ENABLE check above + */ case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); @@ -475,52 +530,37 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) break; } - data = env->regs[r1]; - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + switch (pcias) { + /* A ZPCI PCI card may use any BAR from BAR 0 to BAR 5 */ + case ZPCI_IO_BAR_MIN...ZPCI_IO_BAR_MAX: + /* Check length: + * A length of 0 is invalid and length should not cross a double word + */ + if (!len || (len > (8 - (offset & 0x7)))) { + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - if (trap_msix(pbdev, offset, pcias)) { - offset = offset - pbdev->msix.table_offset; - mr = &pbdev->pdev->msix_table_mmio; - } else { - mr = pbdev->pdev->io_regions[pcias].memory; - } - - result = memory_region_dispatch_write(mr, offset, data, len, - MEMTXATTRS_UNSPECIFIED); + result = zpci_write_bar(pbdev, pcias, offset, data, len); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: - program_interrupt(env, PGM_OPERAND, 4); + break; + case ZPCI_CONFIG_BAR: + /* ZPCI uses the pseudo BAR number 15 as configuration space */ + /* possible access lengths are 1,2,4 and must not cross a word */ + if (!len || (len > (4 - (offset & 0x3))) || len == 3) { + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - + /* len = 1,2,4 so we do not need to test */ + zpci_endian_swap(&data, len); pci_host_config_write_common(pbdev->pdev, offset, pci_config_size(pbdev->pdev), data, len); - } else { + break; + default: DPRINTF("pcistg invalid space\n"); setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); @@ -531,7 +571,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) return 0; } -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; uint32_t fh; @@ -545,12 +585,12 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) cpu_synchronize_state(CPU(cpu)); if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); + s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra); goto out; } if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); goto out; } @@ -624,12 +664,13 @@ out: } int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar) + uint8_t ar, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; MemoryRegion *mr; MemTxResult result; + uint64_t offset; int i; uint32_t fh; uint8_t pcias; @@ -637,29 +678,17 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, uint8_t buffer[128]; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } fh = env->regs[r1] >> 32; pcias = (env->regs[r1] >> 16) & 0xf; len = env->regs[r1] & 0xff; + offset = env->regs[r3]; - if (pcias > 5) { - DPRINTF("pcistb invalid space\n"); - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS); - return 0; - } - - switch (len) { - case 16: - case 32: - case 64: - case 128: - break; - default: - program_interrupt(env, PGM_SPECIFICATION, 6); + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } @@ -671,12 +700,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } switch (pbdev->state) { - case ZPCI_FS_RESERVED: - case ZPCI_FS_STANDBY: - case ZPCI_FS_DISABLED: case ZPCI_FS_PERMANENT_ERROR: - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; case ZPCI_FS_ERROR: setcc(cpu, ZPCI_PCI_LS_ERR); s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED); @@ -685,28 +709,62 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, break; } + if (pcias > ZPCI_IO_BAR_MAX) { + DPRINTF("pcistb invalid space\n"); + setcc(cpu, ZPCI_PCI_LS_ERR); + s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS); + return 0; + } + + /* Verify the address, offset and length */ + /* offset must be a multiple of 8 */ + if (offset % 8) { + goto specification_error; + } + /* Length must be greater than 8, a multiple of 8 */ + /* and not greater than maxstbl */ + if ((len <= 8) || (len % 8) || (len > pbdev->maxstbl)) { + goto specification_error; + } + /* Do not cross a 4K-byte boundary */ + if (((offset & 0xfff) + len) > 0x1000) { + goto specification_error; + } + /* Guest address must be double word aligned */ + if (gaddr & 0x07UL) { + goto specification_error; + } + mr = pbdev->pdev->io_regions[pcias].memory; - if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { - program_interrupt(env, PGM_OPERAND, 6); + mr = s390_get_subregion(mr, offset, len); + offset -= mr->addr; + + if (!memory_region_access_valid(mr, offset, len, true)) { + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } for (i = 0; i < len / 8; i++) { - result = memory_region_dispatch_write(mr, env->regs[r3] + i * 8, - ldq_p(buffer + i * 8), 8, - MEMTXATTRS_UNSPECIFIED); + result = memory_region_dispatch_write(mr, offset + i * 8, + ldq_p(buffer + i * 8), 8, + MEMTXATTRS_UNSPECIFIED); if (result != MEMTX_OK) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } } setcc(cpu, ZPCI_PCI_LS_OK); return 0; + +specification_error: + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + return 0; } static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) @@ -767,7 +825,8 @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev) return 0; } -static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib) +static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib, + uintptr_t ra) { uint64_t pba = ldq_p(&fib.pba); uint64_t pal = ldq_p(&fib.pal); @@ -776,14 +835,14 @@ static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib) uint8_t t = (g_iota >> 11) & 0x1; if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return -EINVAL; } /* currently we only support designation type 1 with translation */ if (!(dt == ZPCI_IOTA_RTTO && t)) { error_report("unsupported ioat dt %d t %d", dt, t); - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return -EINVAL; } @@ -804,7 +863,8 @@ void pci_dereg_ioat(S390PCIIOMMU *iommu) iommu->g_iota = 0; } -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra) { CPUS390XState *env = &cpu->env; uint8_t oc, dmaas; @@ -814,7 +874,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) uint64_t cc = ZPCI_PCI_LS_OK; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } @@ -823,7 +883,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) fh = env->regs[r1] >> 32; if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } @@ -846,11 +906,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } if (fib.fmt != 0) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -879,7 +940,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } else if (pbdev->iommu->enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); - } else if (reg_ioat(env, pbdev->iommu, fib)) { + } else if (reg_ioat(env, pbdev->iommu, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); } @@ -904,7 +965,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { pci_dereg_ioat(pbdev->iommu); - if (reg_ioat(env, pbdev->iommu, fib)) { + if (reg_ioat(env, pbdev->iommu, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); } @@ -935,7 +996,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) pbdev->fmb_addr = ldq_p(&fib.fmb_addr); break; default: - program_interrupt(&cpu->env, PGM_OPERAND, 6); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 6, ra); cc = ZPCI_PCI_LS_ERR; } @@ -943,7 +1004,8 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) return 0; } -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra) { CPUS390XState *env = &cpu->env; uint8_t dmaas; @@ -954,7 +1016,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) uint64_t cc = ZPCI_PCI_LS_OK; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); return 0; } @@ -968,7 +1030,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } @@ -1026,6 +1088,7 @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) out: if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 94a959f91c..91c3d61f2a 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -162,7 +162,7 @@ typedef struct ClpRspQueryPciGrp { #define CLP_RSP_QPCIG_MASK_FRAME 0x2 #define CLP_RSP_QPCIG_MASK_REFRESH 0x1 uint8_t fr; - uint16_t reserved2; + uint16_t maxstbl; uint16_t mui; uint64_t reserved3; uint64_t dasm; /* dma address space mask */ @@ -293,13 +293,19 @@ typedef struct ZpciFib { int pci_dereg_irqs(S390PCIBusDevice *pbdev); void pci_dereg_ioat(S390PCIIOMMU *iommu); -int clp_service_call(S390CPU *cpu, uint8_t r2); -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); +int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra); +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); +int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); +int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar); -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); + uint8_t ar, uintptr_t ra); +int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra); +int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, + uintptr_t ra); + +#define ZPCI_IO_BAR_MIN 0 +#define ZPCI_IO_BAR_MAX 5 +#define ZPCI_CONFIG_BAR 15 #endif diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6a57f94197..35df7e19c5 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -152,14 +152,38 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } +/* + * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages + * as the dirty bitmap must be managed by bitops that take an int as + * position indicator. If we have a guest beyond that we will split off + * new subregions. The split must happen on a segment boundary (1MB). + */ +#define KVM_MEM_MAX_NR_PAGES ((1ULL << 31) - 1) +#define SEG_MSK (~0xfffffULL) +#define KVM_SLOT_MAX_BYTES ((KVM_MEM_MAX_NR_PAGES * TARGET_PAGE_SIZE) & SEG_MSK) static void s390_memory_init(ram_addr_t mem_size) { MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); + ram_addr_t chunk, offset = 0; + unsigned int number = 0; + gchar *name; /* allocate RAM for core */ - memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); - memory_region_add_subregion(sysmem, 0, ram); + name = g_strdup_printf("s390.ram"); + while (mem_size) { + MemoryRegion *ram = g_new(MemoryRegion, 1); + uint64_t size = mem_size; + + /* KVM does not allow memslots >= 8 TB */ + chunk = MIN(size, KVM_SLOT_MAX_BYTES); + memory_region_allocate_system_memory(ram, NULL, name, chunk); + memory_region_add_subregion(sysmem, offset, ram); + mem_size -= chunk; + offset += chunk; + g_free(name); + name = g_strdup_printf("s390.ram.%u", ++number); + } + g_free(name); /* Initialize storage key device */ s390_skeys_init(); @@ -302,13 +326,17 @@ static void ccw_init(MachineState *machine) /* * Non mcss-e enabled guests only see the devices from the default * css, which is determined by the value of the squash_mcss property. - * Note: we must not squash non virtual devices to css 0xFE. */ if (css_bus->squash_mcss) { ret = css_create_css_image(0, true); } else { ret = css_create_css_image(VIRTUAL_CSSID, true); } + if (qemu_opt_get(qemu_get_machine_opts(), "s390-squash-mcss")) { + warn_report("The machine property 's390-squash-mcss' is deprecated" + " (obsoleted by lifting the cssid restrictions)."); + } + assert(ret == 0); if (css_migration_enabled()) { css_register_vmstate(); @@ -583,7 +611,7 @@ static inline void s390_machine_initfn(Object *obj) object_property_add_bool(obj, "s390-squash-mcss", machine_get_squash_mcss, machine_set_squash_mcss, NULL); - object_property_set_description(obj, "s390-squash-mcss", + object_property_set_description(obj, "s390-squash-mcss", "(deprecated) " "enable/disable squashing subchannels into the default css", NULL); object_property_set_bool(obj, false, "s390-squash-mcss", NULL); @@ -639,6 +667,9 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +#define CCW_COMPAT_2_11 \ + HW_COMPAT_2_11 + #define CCW_COMPAT_2_10 \ HW_COMPAT_2_10 @@ -716,14 +747,30 @@ bool css_migration_enabled(void) .value = "0",\ }, +static void ccw_machine_2_12_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_2_12_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(2_12, "2.12", true); + static void ccw_machine_2_11_instance_options(MachineState *machine) { + static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V2_11 }; + ccw_machine_2_12_instance_options(machine); + + /* before 2.12 we emulated the very first z900 */ + s390_set_qemu_cpu_model(0x2064, 7, 1, qemu_cpu_feat); } static void ccw_machine_2_11_class_options(MachineClass *mc) { + ccw_machine_2_12_class_options(mc); + SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_11); } -DEFINE_CCW_MACHINE(2_11, "2.11", true); +DEFINE_CCW_MACHINE(2_11, "2.11", false); static void ccw_machine_2_10_instance_options(MachineState *machine) { diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 184515ce94..3dd902a664 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -701,7 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) SubchDev *sch; Error *err = NULL; - sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp); + sch = css_create_sch(ccw_dev->devno, cbus->squash_mcss, errp); if (!sch) { return; } diff --git a/hw/usb/bus.c b/hw/usb/bus.c index e56dc3348a..11f7720d71 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -559,28 +559,6 @@ int usb_device_detach(USBDevice *dev) return 0; } -int usb_device_delete_addr(int busnr, int addr) -{ - USBBus *bus; - USBPort *port; - USBDevice *dev; - - bus = usb_bus_find(busnr); - if (!bus) - return -1; - - QTAILQ_FOREACH(port, &bus->used, next) { - if (port->dev->addr == addr) - break; - } - if (!port) - return -1; - dev = port->dev; - - object_unparent(OBJECT(dev)); - return 0; -} - static const char *usb_speed(unsigned int speed) { static const char *txt[] = { diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 9bba717708..d57c6d3485 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -946,6 +946,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) k->exit = xen_pt_unregister_device; k->config_read = xen_pt_pci_read_config; k->config_write = xen_pt_pci_write_config; + k->is_express = 1; /* We might be */ set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "Assign an host PCI device with Xen"; dc->props = xen_pci_passthrough_properties; diff --git a/include/hw/compat.h b/include/hw/compat.h index cf389b4e85..263de973a7 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -1,6 +1,9 @@ #ifndef HW_COMPAT_H #define HW_COMPAT_H +#define HW_COMPAT_2_11 \ + /* empty */ + #define HW_COMPAT_2_10 \ {\ .driver = "virtio-mouse-device",\ diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 38470b2f0e..0fae4fc6a4 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -108,7 +108,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - return xics_get_qirq(XICS_FABRIC(spapr), phb->lsi_table[pin].irq); + return spapr_qirq(spapr, phb->lsi_table[pin].irq); } PCIHostState *spapr_create_phb(sPAPRMachineState *spapr, int index); diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 9d21ca9bde..14757b805e 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -590,6 +590,16 @@ void spapr_load_rtas(sPAPRMachineState *spapr, void *fdt, hwaddr addr); #define RTAS_EVENT_SCAN_RATE 1 +/* This helper should be used to encode interrupt specifiers when the related + * "interrupt-controller" node has its "#interrupt-cells" property set to 2 (ie, + * VIO devices, RTAS event sources and PHBs). + */ +static inline void spapr_dt_xics_irq(uint32_t *intspec, int irq, bool is_lsi) +{ + intspec[0] = cpu_to_be32(irq); + intspec[1] = is_lsi ? cpu_to_be32(1) : 0; +} + typedef struct sPAPRTCETable sPAPRTCETable; #define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" @@ -707,4 +717,11 @@ void spapr_do_system_reset_on_cpu(CPUState *cs, run_on_cpu_data arg); int spapr_vcpu_id(PowerPCCPU *cpu); PowerPCCPU *spapr_find_cpu(int vcpu_id); +int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, + Error **errp); +int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, + bool align, Error **errp); +void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num); +qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq); + #endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h index f2d48d6a67..1129f344aa 100644 --- a/include/hw/ppc/spapr_cpu_core.h +++ b/include/hw/ppc/spapr_cpu_core.h @@ -28,7 +28,7 @@ typedef struct sPAPRCPUCore { CPUCore parent_obj; /*< public >*/ - void *threads; + PowerPCCPU **threads; int node_id; } sPAPRCPUCore; diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 2e9685a5d9..e8b006d18f 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -87,7 +87,7 @@ static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); - return xics_get_qirq(XICS_FABRIC(spapr), dev->irq); + return spapr_qirq(spapr, dev->irq); } static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr, diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 2df99be111..6cebff47a7 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -181,13 +181,8 @@ typedef struct XICSFabricClass { #define XICS_IRQS_SPAPR 1024 -int spapr_ics_alloc(ICSState *ics, int irq_hint, bool lsi, Error **errp); -int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi, bool align, - Error **errp); -void spapr_ics_free(ICSState *ics, int irq, int num); void spapr_dt_xics(int nr_servers, void *fdt, uint32_t phandle); -qemu_irq xics_get_qirq(XICSFabric *xi, int irq); ICPState *xics_icp_get(XICSFabric *xi, int server); /* Internal XICS interfaces */ @@ -212,4 +207,7 @@ typedef struct sPAPRMachineState sPAPRMachineState; int xics_kvm_init(sPAPRMachineState *spapr, Error **errp); void xics_spapr_init(sPAPRMachineState *spapr); +Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, + Error **errp); + #endif /* XICS_H */ diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index ab6ebe66b5..35facb47d2 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -248,7 +248,6 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *irb, int *irb_len); void css_do_tsch_update_subch(SubchDev *sch); int css_do_stcrw(CRW *crw); void css_undo_stcrw(CRW *crw); -int css_do_tpi(IOIntCode *int_code, int lowcore); int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, int rfmt, void *buf); void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo); @@ -272,12 +271,9 @@ extern const PropertyInfo css_devid_ro_propinfo; * default css image for it. * If @p bus_id is valid, and @p squash_mcss is false, verify that it is * not already in use, and find a free devno for it. - * If @p bus_id is not valid, and if either @p squash_mcss or @p is_virtual - * is true, find a free subchannel id and device number across all - * subchannel sets from the default css image. - * If @p bus_id is not valid, and if both @p squash_mcss and @p is_virtual - * are false, find a non-full css image and find a free subchannel id and - * device number across all subchannel sets from it. + * If @p bus_id is not valid find a free subchannel id and device number + * across all subchannel sets and all css images starting from the default + * css image. * * If either of the former actions succeed, allocate a subchannel structure, * initialise it with the bus id, subchannel id and device number, register @@ -286,8 +282,7 @@ extern const PropertyInfo css_devid_ro_propinfo; * The caller becomes owner of the returned subchannel structure and * is responsible for unregistering and freeing it. */ -SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, - Error **errp); +SubchDev *css_create_sch(CssDevId bus_id, bool squash_mcss, Error **errp); /** Turn on css migration */ void css_register_vmstate(void); diff --git a/include/hw/usb.h b/include/hw/usb.h index eb28655270..9dd9c6f0d9 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -549,7 +549,6 @@ void usb_claim_port(USBDevice *dev, Error **errp); void usb_release_port(USBDevice *dev); void usb_device_attach(USBDevice *dev, Error **errp); int usb_device_detach(USBDevice *dev); -int usb_device_delete_addr(int busnr, int addr); void usb_check_attach(USBDevice *dev, Error **errp); static inline USBBus *usb_bus_from_device(USBDevice *d) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index e8568a0a54..adb3758275 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -365,6 +365,9 @@ void qemu_anon_ram_free(void *ptr, size_t size); #elif defined(__linux__) && defined(__s390x__) /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */ # define QEMU_VMALLOC_ALIGN (256 * 4096) +#elif defined(__linux__) && defined(__sparc__) +#include <sys/shm.h> +# define QEMU_VMALLOC_ALIGN MAX(getpagesize(), SHMLBA) #else # define QEMU_VMALLOC_ALIGN getpagesize() #endif diff --git a/include/sysemu/numa.h b/include/sysemu/numa.h index 5c6df2820b..b3545215f6 100644 --- a/include/sysemu/numa.h +++ b/include/sysemu/numa.h @@ -10,17 +10,10 @@ extern int nb_numa_nodes; /* Number of NUMA nodes */ extern bool have_numa_distance; -struct numa_addr_range { - ram_addr_t mem_start; - ram_addr_t mem_end; - QLIST_ENTRY(numa_addr_range) entry; -}; - struct node_info { uint64_t node_mem; struct HostMemoryBackend *node_memdev; bool present; - QLIST_HEAD(, numa_addr_range) addr; /* List to store address ranges */ uint8_t distance[MAX_NODES]; }; @@ -33,9 +26,6 @@ extern NodeInfo numa_info[MAX_NODES]; void parse_numa_opts(MachineState *ms); void query_numa_node_mem(NumaNodeMem node_mem[]); extern QemuOptsList qemu_numa_opts; -void numa_set_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node); -void numa_unset_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node); -uint32_t numa_get_node(ram_addr_t addr, Error **errp); void numa_legacy_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, int nb_nodes, ram_addr_t size); void numa_default_auto_assign_ram(MachineClass *mc, NodeInfo *nodes, diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index c083869fcf..31612caf10 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -166,8 +166,6 @@ extern Chardev *serial_hds[MAX_SERIAL_PORTS]; extern Chardev *parallel_hds[MAX_PARALLEL_PORTS]; -void hmp_usb_add(Monitor *mon, const QDict *qdict); -void hmp_usb_del(Monitor *mon, const QDict *qdict); void hmp_info_usb(Monitor *mon, const QDict *qdict); void add_boot_device_path(int32_t bootindex, DeviceState *dev, diff --git a/include/ui/input.h b/include/ui/input.h index f8cee43f65..5cc76d6e41 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -77,4 +77,7 @@ extern const guint16 qemu_input_map_qcode_to_qnum[]; extern const guint qemu_input_map_qnum_to_qcode_len; extern const guint16 qemu_input_map_qnum_to_qcode[]; +extern const guint qemu_input_map_qcode_to_linux_len; +extern const guint16 qemu_input_map_qcode_to_linux[]; + #endif /* INPUT_H */ @@ -55,92 +55,6 @@ int nb_numa_nodes; bool have_numa_distance; NodeInfo numa_info[MAX_NODES]; -void numa_set_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node) -{ - struct numa_addr_range *range; - - /* - * Memory-less nodes can come here with 0 size in which case, - * there is nothing to do. - */ - if (!size) { - return; - } - - range = g_malloc0(sizeof(*range)); - range->mem_start = addr; - range->mem_end = addr + size - 1; - QLIST_INSERT_HEAD(&numa_info[node].addr, range, entry); -} - -void numa_unset_mem_node_id(ram_addr_t addr, uint64_t size, uint32_t node) -{ - struct numa_addr_range *range, *next; - - QLIST_FOREACH_SAFE(range, &numa_info[node].addr, entry, next) { - if (addr == range->mem_start && (addr + size - 1) == range->mem_end) { - QLIST_REMOVE(range, entry); - g_free(range); - return; - } - } -} - -static void numa_set_mem_ranges(void) -{ - int i; - ram_addr_t mem_start = 0; - - /* - * Deduce start address of each node and use it to store - * the address range info in numa_info address range list - */ - for (i = 0; i < nb_numa_nodes; i++) { - numa_set_mem_node_id(mem_start, numa_info[i].node_mem, i); - mem_start += numa_info[i].node_mem; - } -} - -/* - * Check if @addr falls under NUMA @node. - */ -static bool numa_addr_belongs_to_node(ram_addr_t addr, uint32_t node) -{ - struct numa_addr_range *range; - - QLIST_FOREACH(range, &numa_info[node].addr, entry) { - if (addr >= range->mem_start && addr <= range->mem_end) { - return true; - } - } - return false; -} - -/* - * Given an address, return the index of the NUMA node to which the - * address belongs to. - */ -uint32_t numa_get_node(ram_addr_t addr, Error **errp) -{ - uint32_t i; - - /* For non NUMA configurations, check if the addr falls under node 0 */ - if (!nb_numa_nodes) { - if (numa_addr_belongs_to_node(addr, 0)) { - return 0; - } - } - - for (i = 0; i < nb_numa_nodes; i++) { - if (numa_addr_belongs_to_node(addr, i)) { - return i; - } - } - - error_setg(errp, "Address 0x" RAM_ADDR_FMT " doesn't belong to any " - "NUMA node", addr); - return -1; -} static void parse_numa_node(MachineState *ms, NumaNodeOptions *node, Error **errp) @@ -497,12 +411,6 @@ void parse_numa_opts(MachineState *ms) exit(1); } - for (i = 0; i < nb_numa_nodes; i++) { - QLIST_INIT(&numa_info[i].addr); - } - - numa_set_mem_ranges(); - /* QEMU needs at least all unique node pair distances to build * the whole NUMA distance table. QEMU treats the distance table * as symmetric by default, i.e. distance A->B == distance B->A. @@ -522,8 +430,6 @@ void parse_numa_opts(MachineState *ms) /* Validation succeeded, now fill in any missing distances. */ complete_init_numa_distance(); } - } else { - numa_set_mem_node_id(0, ram_size, 0); } } diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differindex 7415f1a3e7..97155d2638 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/start.S b/pc-bios/s390-ccw/start.S index 43f9bd243e..eb8d024dbb 100644 --- a/pc-bios/s390-ccw/start.S +++ b/pc-bios/s390-ccw/start.S @@ -3,7 +3,7 @@ * into the pc-bios directory of qemu. * * Copyright (c) 2013 Alexander Graf <agraf@suse.de> - * Copyright 2013 IBM Corp. + * Copyright IBM Corp. 2013, 2017 * * This work is licensed under the terms of the GNU GPL, version 2 or (at * your option) any later version. See the COPYING file in the top-level @@ -13,8 +13,32 @@ .globl _start _start: -larl %r15, stack + 0x8000 /* Set up stack */ -j main /* And call C */ + larl %r15, stack + 0x8000 /* Set up stack */ + + /* clear bss */ + larl %r2, __bss_start + larl %r3, _end + slgr %r3, %r2 /* get sizeof bss */ + ltgr %r3,%r3 /* bss emtpy? */ + jz done + aghi %r3,-1 + srlg %r4,%r3,8 /* how many 256 byte chunks? */ + ltgr %r4,%r4 + lgr %r1,%r2 + jz remainder +loop: + xc 0(256,%r1),0(%r1) + la %r1,256(%r1) + brctg %r4,loop +remainder: + larl %r2,memsetxc + ex %r3,0(%r2) +done: + j main /* And call C */ + +memsetxc: + xc 0(1,%r1),0(%r1) + /* * void disabled_wait(void) diff --git a/qemu-doc.texi b/qemu-doc.texi index db2351c746..f7317dfc66 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2501,6 +2501,14 @@ enabled via the ``-machine usb=on'' argument. The ``-nodefconfig`` argument is a synonym for ``-no-user-config``. +@subsection -machine s390-squash-mcss=on|off (since 2.12.0) + +The ``s390-squash-mcss=on`` property has been obsoleted by allowing the +cssid to be chosen freely. Instead of squashing subchannels into the +default channel subsystem image for guests that do not support multiple +channel subsystems, all devices can be put into the default channel +subsystem image. + @section qemu-img command line arguments @subsection convert -s (since 2.0.0) @@ -2518,14 +2526,6 @@ The ``host_net_add'' command is replaced by the ``netdev_add'' command. The ``host_net_remove'' command is replaced by the ``netdev_del'' command. -@subsection usb_add (since 2.10.0) - -The ``usb_add'' command is replaced by the ``device_add'' command. - -@subsection usb_del (since 2.10.0) - -The ``usb_del'' command is replaced by the ``device_del'' command. - @section System emulator devices @subsection ivshmem (since 2.6.0) diff --git a/qemu-options.hx b/qemu-options.hx index f11c4ac960..fe0c29271f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -43,7 +43,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ " suppress-vmdesc=on|off disables self-describing migration (default=off)\n" " nvdimm=on|off controls NVDIMM support (default=off)\n" " enforce-config-section=on|off enforce configuration section migration (default=off)\n" - " s390-squash-mcss=on|off controls support for squashing into default css (default=off)\n", + " s390-squash-mcss=on|off (deprecated) controls support for squashing into default css (default=off)\n", QEMU_ARCH_ALL) STEXI @item -machine [type=]@var{name}[,prop=@var{value}[,...]] @@ -98,6 +98,12 @@ Enables or disables NVDIMM support. The default is off. @item s390-squash-mcss=on|off Enables or disables squashing subchannels into the default css. The default is off. +NOTE: This property is deprecated and will be removed in future releases. +The ``s390-squash-mcss=on`` property has been obsoleted by allowing the +cssid to be chosen freely. Instead of squashing subchannels into the +default channel subsystem image for guests that do not support multiple +channel subsystems, all devices can be put into the default channel +subsystem image. @item enforce-config-section=on|off If @option{enforce-config-section} is set to @var{on}, force migration code to send configuration section even if the machine-type sets the diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h index 429b47f959..deaa46a14b 100644 --- a/target/ppc/cpu-qom.h +++ b/target/ppc/cpu-qom.h @@ -191,6 +191,7 @@ typedef struct PowerPCCPUClass { uint64_t insns_flags; uint64_t insns_flags2; uint64_t msr_mask; + uint64_t lpcr_pm; /* Power-saving mode Exit Cause Enable bits */ powerpc_mmu_t mmu_model; powerpc_excp_t excp_model; powerpc_input_t bus_model; diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 989761b795..370b05e76e 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -87,6 +87,13 @@ #define PPC_ELF_MACHINE EM_PPC #endif +#define PPC_BIT(bit) (0x8000000000000000UL >> (bit)) +#define PPC_BIT32(bit) (0x80000000UL >> (bit)) +#define PPC_BIT8(bit) (0x80UL >> (bit)) +#define PPC_BITMASK(bs, be) ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs)) +#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be)) | \ + PPC_BIT32(bs)) + /*****************************************************************************/ /* Exception vectors definitions */ enum { @@ -371,10 +378,10 @@ struct ppc_slb_t { #define MSR_LE 0 /* Little-endian mode 1 hflags */ /* LPCR bits */ -#define LPCR_VPM0 (1ull << (63 - 0)) -#define LPCR_VPM1 (1ull << (63 - 1)) -#define LPCR_ISL (1ull << (63 - 2)) -#define LPCR_KBV (1ull << (63 - 3)) +#define LPCR_VPM0 PPC_BIT(0) +#define LPCR_VPM1 PPC_BIT(1) +#define LPCR_ISL PPC_BIT(2) +#define LPCR_KBV PPC_BIT(3) #define LPCR_DPFD_SHIFT (63 - 11) #define LPCR_DPFD (0x7ull << LPCR_DPFD_SHIFT) #define LPCR_VRMASD_SHIFT (63 - 16) @@ -382,41 +389,41 @@ struct ppc_slb_t { /* P9: Power-saving mode Exit Cause Enable (Upper Section) Mask */ #define LPCR_PECE_U_SHIFT (63 - 19) #define LPCR_PECE_U_MASK (0x7ull << LPCR_PECE_U_SHIFT) -#define LPCR_HVEE (1ull << (63 - 17)) /* Hypervisor Virt Exit Enable */ +#define LPCR_HVEE PPC_BIT(17) /* Hypervisor Virt Exit Enable */ #define LPCR_RMLS_SHIFT (63 - 37) #define LPCR_RMLS (0xfull << LPCR_RMLS_SHIFT) -#define LPCR_ILE (1ull << (63 - 38)) +#define LPCR_ILE PPC_BIT(38) #define LPCR_AIL_SHIFT (63 - 40) /* Alternate interrupt location */ #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) -#define LPCR_UPRT (1ull << (63 - 41)) /* Use Process Table */ -#define LPCR_EVIRT (1ull << (63 - 42)) /* Enhanced Virtualisation */ -#define LPCR_ONL (1ull << (63 - 45)) -#define LPCR_LD (1ull << (63 - 46)) /* Large Decrementer */ -#define LPCR_P7_PECE0 (1ull << (63 - 49)) -#define LPCR_P7_PECE1 (1ull << (63 - 50)) -#define LPCR_P7_PECE2 (1ull << (63 - 51)) -#define LPCR_P8_PECE0 (1ull << (63 - 47)) -#define LPCR_P8_PECE1 (1ull << (63 - 48)) -#define LPCR_P8_PECE2 (1ull << (63 - 49)) -#define LPCR_P8_PECE3 (1ull << (63 - 50)) -#define LPCR_P8_PECE4 (1ull << (63 - 51)) +#define LPCR_UPRT PPC_BIT(41) /* Use Process Table */ +#define LPCR_EVIRT PPC_BIT(42) /* Enhanced Virtualisation */ +#define LPCR_ONL PPC_BIT(45) +#define LPCR_LD PPC_BIT(46) /* Large Decrementer */ +#define LPCR_P7_PECE0 PPC_BIT(49) +#define LPCR_P7_PECE1 PPC_BIT(50) +#define LPCR_P7_PECE2 PPC_BIT(51) +#define LPCR_P8_PECE0 PPC_BIT(47) +#define LPCR_P8_PECE1 PPC_BIT(48) +#define LPCR_P8_PECE2 PPC_BIT(49) +#define LPCR_P8_PECE3 PPC_BIT(50) +#define LPCR_P8_PECE4 PPC_BIT(51) /* P9: Power-saving mode Exit Cause Enable (Lower Section) Mask */ #define LPCR_PECE_L_SHIFT (63 - 51) #define LPCR_PECE_L_MASK (0x1full << LPCR_PECE_L_SHIFT) -#define LPCR_PDEE (1ull << (63 - 47)) /* Privileged Doorbell Exit EN */ -#define LPCR_HDEE (1ull << (63 - 48)) /* Hyperv Doorbell Exit Enable */ -#define LPCR_EEE (1ull << (63 - 49)) /* External Exit Enable */ -#define LPCR_DEE (1ull << (63 - 50)) /* Decrementer Exit Enable */ -#define LPCR_OEE (1ull << (63 - 51)) /* Other Exit Enable */ -#define LPCR_MER (1ull << (63 - 52)) -#define LPCR_GTSE (1ull << (63 - 53)) /* Guest Translation Shootdown */ -#define LPCR_TC (1ull << (63 - 54)) -#define LPCR_HEIC (1ull << (63 - 59)) /* HV Extern Interrupt Control */ -#define LPCR_LPES0 (1ull << (63 - 60)) -#define LPCR_LPES1 (1ull << (63 - 61)) -#define LPCR_RMI (1ull << (63 - 62)) -#define LPCR_HVICE (1ull << (63 - 62)) /* HV Virtualisation Int Enable */ -#define LPCR_HDICE (1ull << (63 - 63)) +#define LPCR_PDEE PPC_BIT(47) /* Privileged Doorbell Exit EN */ +#define LPCR_HDEE PPC_BIT(48) /* Hyperv Doorbell Exit Enable */ +#define LPCR_EEE PPC_BIT(49) /* External Exit Enable */ +#define LPCR_DEE PPC_BIT(50) /* Decrementer Exit Enable */ +#define LPCR_OEE PPC_BIT(51) /* Other Exit Enable */ +#define LPCR_MER PPC_BIT(52) +#define LPCR_GTSE PPC_BIT(53) /* Guest Translation Shootdown */ +#define LPCR_TC PPC_BIT(54) +#define LPCR_HEIC PPC_BIT(59) /* HV Extern Interrupt Control */ +#define LPCR_LPES0 PPC_BIT(60) +#define LPCR_LPES1 PPC_BIT(61) +#define LPCR_RMI PPC_BIT(62) +#define LPCR_HVICE PPC_BIT(62) /* HV Virtualisation Int Enable */ +#define LPCR_HDICE PPC_BIT(63) #define msr_sf ((env->msr >> MSR_SF) & 1) #define msr_isf ((env->msr >> MSR_ISF) & 1) @@ -507,22 +514,22 @@ struct ppc_slb_t { #define FSCR_IC_TAR 8 /* Exception state register bits definition */ -#define ESR_PIL (1 << (63 - 36)) /* Illegal Instruction */ -#define ESR_PPR (1 << (63 - 37)) /* Privileged Instruction */ -#define ESR_PTR (1 << (63 - 38)) /* Trap */ -#define ESR_FP (1 << (63 - 39)) /* Floating-Point Operation */ -#define ESR_ST (1 << (63 - 40)) /* Store Operation */ -#define ESR_AP (1 << (63 - 44)) /* Auxiliary Processor Operation */ -#define ESR_PUO (1 << (63 - 45)) /* Unimplemented Operation */ -#define ESR_BO (1 << (63 - 46)) /* Byte Ordering */ -#define ESR_PIE (1 << (63 - 47)) /* Imprecise exception */ -#define ESR_DATA (1 << (63 - 53)) /* Data Access (Embedded page table) */ -#define ESR_TLBI (1 << (63 - 54)) /* TLB Ineligible (Embedded page table) */ -#define ESR_PT (1 << (63 - 55)) /* Page Table (Embedded page table) */ -#define ESR_SPV (1 << (63 - 56)) /* SPE/VMX operation */ -#define ESR_EPID (1 << (63 - 57)) /* External Process ID operation */ -#define ESR_VLEMI (1 << (63 - 58)) /* VLE operation */ -#define ESR_MIF (1 << (63 - 62)) /* Misaligned instruction (VLE) */ +#define ESR_PIL PPC_BIT(36) /* Illegal Instruction */ +#define ESR_PPR PPC_BIT(37) /* Privileged Instruction */ +#define ESR_PTR PPC_BIT(38) /* Trap */ +#define ESR_FP PPC_BIT(39) /* Floating-Point Operation */ +#define ESR_ST PPC_BIT(40) /* Store Operation */ +#define ESR_AP PPC_BIT(44) /* Auxiliary Processor Operation */ +#define ESR_PUO PPC_BIT(45) /* Unimplemented Operation */ +#define ESR_BO PPC_BIT(46) /* Byte Ordering */ +#define ESR_PIE PPC_BIT(47) /* Imprecise exception */ +#define ESR_DATA PPC_BIT(53) /* Data Access (Embedded page table) */ +#define ESR_TLBI PPC_BIT(54) /* TLB Ineligible (Embedded page table) */ +#define ESR_PT PPC_BIT(55) /* Page Table (Embedded page table) */ +#define ESR_SPV PPC_BIT(56) /* SPE/VMX operation */ +#define ESR_EPID PPC_BIT(57) /* External Process ID operation */ +#define ESR_VLEMI PPC_BIT(58) /* VLE operation */ +#define ESR_MIF PPC_BIT(62) /* Misaligned instruction (VLE) */ /* Transaction EXception And Summary Register bits */ #define TEXASR_FAILURE_PERSISTENT (63 - 7) @@ -1991,7 +1998,7 @@ void ppc_compat_add_property(Object *obj, const char *name, #define HID0_DEEPNAP (1 << 24) /* pre-2.06 */ #define HID0_DOZE (1 << 23) /* pre-2.06 */ #define HID0_NAP (1 << 22) /* pre-2.06 */ -#define HID0_HILE (1ull << (63 - 19)) /* POWER8 */ +#define HID0_HILE PPC_BIT(19) /* POWER8 */ /*****************************************************************************/ /* PowerPC Instructions types definitions */ diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 998fbed848..4075fc8589 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -3419,7 +3419,7 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) } /*** Branch ***/ -static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { if (NARROW_MODE(ctx)) { dest = (uint32_t) dest; @@ -3441,7 +3441,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) gen_debug_exception(ctx); } } - tcg_gen_exit_tb(0); + tcg_gen_lookup_and_goto_ptr(); } } @@ -3479,7 +3479,7 @@ static void gen_b(DisasContext *ctx) #define BCOND_CTR 2 #define BCOND_TAR 3 -static inline void gen_bcond(DisasContext *ctx, int type) +static void gen_bcond(DisasContext *ctx, int type) { uint32_t bo = BO(ctx->opcode); TCGLabel *l1; @@ -3543,26 +3543,19 @@ static inline void gen_bcond(DisasContext *ctx, int type) } else { gen_goto_tb(ctx, 0, li); } - if ((bo & 0x14) != 0x14) { - gen_set_label(l1); - gen_goto_tb(ctx, 1, ctx->nip); - } } else { if (NARROW_MODE(ctx)) { tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3); } else { tcg_gen_andi_tl(cpu_nip, target, ~3); } - tcg_gen_exit_tb(0); - if ((bo & 0x14) != 0x14) { - gen_set_label(l1); - gen_update_nip(ctx, ctx->nip); - tcg_gen_exit_tb(0); - } - } - if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { + tcg_gen_lookup_and_goto_ptr(); tcg_temp_free(target); } + if ((bo & 0x14) != 0x14) { + gen_set_label(l1); + gen_goto_tb(ctx, 1, ctx->nip); + } } static void gen_bc(DisasContext *ctx) diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 4e11e6f489..70ff15a51a 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -8535,6 +8535,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->lpcr_pm = LPCR_P7_PECE0 | LPCR_P7_PECE1 | LPCR_P7_PECE2; } static void init_proc_POWER8(CPUPPCState *env) @@ -8704,6 +8705,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->lpcr_pm = LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 | + LPCR_P8_PECE3 | LPCR_P8_PECE4; } #ifdef CONFIG_SOFTMMU @@ -8898,14 +8901,17 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->lpcr_pm = LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | LPCR_OEE; } #if !defined(CONFIG_USER_ONLY) void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) { + PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); CPUPPCState *env = &cpu->env; ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR]; ppc_spr_t *amor = &env->spr_cb[SPR_AMOR]; + CPUState *cs = CPU(cpu); cpu->vhyp = vhyp; @@ -8932,8 +8938,7 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) lpcr->default_value &= ~LPCR_RMLS; lpcr->default_value |= 1ull << LPCR_RMLS_SHIFT; - switch (env->mmu_model) { - case POWERPC_MMU_3_00: + if (env->mmu_model == POWERPC_MMU_3_00) { /* By default we choose legacy mode and switch to new hash or radix * when a register process table hcall is made. So disable process * tables and guest translation shootdown by default @@ -8947,16 +8952,13 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) } else { lpcr->default_value &= ~(LPCR_UPRT | LPCR_GTSE); } - lpcr->default_value |= LPCR_PDEE | LPCR_HDEE | LPCR_EEE | LPCR_DEE | - LPCR_OEE; - break; - default: - /* P7 and P8 has slightly different PECE bits, mostly because P8 adds - * bit 47 and 48 which are reserved on P7. Here we set them all, which - * will work as expected for both implementations - */ - lpcr->default_value |= LPCR_P8_PECE0 | LPCR_P8_PECE1 | LPCR_P8_PECE2 | - LPCR_P8_PECE3 | LPCR_P8_PECE4; + } + + /* Only enable Power-saving mode Exit Cause exceptions on the boot + * CPU. The RTAS command start-cpu will enable them on secondaries. + */ + if (cs == first_cpu) { + lpcr->default_value |= pcc->lpcr_pm; } /* We should be followed by a CPU reset but update the active value diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c index f008897e84..5d91e458a8 100644 --- a/target/s390x/cc_helper.c +++ b/target/s390x/cc_helper.c @@ -564,7 +564,7 @@ void HELPER(sacf)(CPUS390XState *env, uint64_t a1) break; default: HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1); - program_interrupt(env, PGM_SPECIFICATION, 2); + s390_program_interrupt(env, PGM_SPECIFICATION, 2, GETPC()); break; } } diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 4db8b5409e..1a8b6b9ae9 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -351,6 +351,9 @@ extern const struct VMStateDescription vmstate_s390_cpu; #define CR0_CPU_TIMER_SC 0x0000000000000400ULL #define CR0_SERVICE_SC 0x0000000000000200ULL +/* Control register 14 bits */ +#define CR14_CHANNEL_REPORT_SC 0x0000000010000000ULL + /* MMU */ #define MMU_PRIMARY_IDX 0 #define MMU_SECONDARY_IDX 1 @@ -674,6 +677,26 @@ struct sysib_322 { #define MCIC_VB_CT 0x0000000000020000ULL #define MCIC_VB_CC 0x0000000000010000ULL +static inline uint64_t s390_build_validity_mcic(void) +{ + uint64_t mcic; + + /* + * Indicate all validity bits (no damage) only. Other bits have to be + * added by the caller. (storage errors, subclasses and subclass modifiers) + */ + mcic = MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP | + MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR | + MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC; + if (s390_has_feat(S390_FEAT_VECTOR)) { + mcic |= MCIC_VB_VR; + } + if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) { + mcic |= MCIC_VB_GS; + } + return mcic; +} + /* cpu.c */ int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low); @@ -699,6 +722,9 @@ static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) /* cpu_models.c */ void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); #define cpu_list s390_cpu_list +void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, + const S390FeatInit feat_init); + /* helper.c */ #define cpu_init(cpu_model) cpu_generic_init(TYPE_S390_CPU, cpu_model) @@ -719,7 +745,9 @@ void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word); /* automatically detect the instruction length */ #define ILEN_AUTO 0xff -void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +#define RA_IGNORED 0 +void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, + uintptr_t ra); /* service interrupts are floating therefore we must not pass an cpustate */ void s390_sclp_extint(uint32_t parm); @@ -733,6 +761,7 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, true) #define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \ s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true) +void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra); /* sigp.c */ diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index c4c37b3b15..212a5f0697 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -15,7 +15,6 @@ #include "internal.h" #include "kvm_s390x.h" #include "sysemu/kvm.h" -#include "gen-features.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/error-report.h" @@ -81,6 +80,12 @@ static S390CPUDef s390_cpu_defs[] = { CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"), }; +#define QEMU_MAX_CPU_TYPE 0x2827 +#define QEMU_MAX_CPU_GEN 12 +#define QEMU_MAX_CPU_EC_GA 2 +static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX }; +static S390FeatBitmap qemu_max_cpu_feat; + /* features part of a base model but not relevant for finding a base model */ S390FeatBitmap ignored_base_feat; @@ -812,48 +817,6 @@ static void check_compatibility(const S390CPUModel *max_model, "available in the configuration: "); } -/** - * The base TCG CPU model "qemu" is based on the z900. However, we already - * can also emulate some additional features of later CPU generations, so - * we add these additional feature bits here. - */ -static void add_qemu_cpu_model_features(S390FeatBitmap fbm) -{ - static const int feats[] = { - S390_FEAT_DAT_ENH, - S390_FEAT_IDTE_SEGMENT, - S390_FEAT_STFLE, - S390_FEAT_SENSE_RUNNING_STATUS, - S390_FEAT_EXTENDED_IMMEDIATE, - S390_FEAT_EXTENDED_TRANSLATION_2, - S390_FEAT_MSA, - S390_FEAT_EXTENDED_TRANSLATION_3, - S390_FEAT_LONG_DISPLACEMENT, - S390_FEAT_LONG_DISPLACEMENT_FAST, - S390_FEAT_ETF2_ENH, - S390_FEAT_STORE_CLOCK_FAST, - S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, - S390_FEAT_ETF3_ENH, - S390_FEAT_COMPARE_AND_SWAP_AND_STORE, - S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2, - S390_FEAT_GENERAL_INSTRUCTIONS_EXT, - S390_FEAT_EXECUTE_EXT, - S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, - S390_FEAT_STFLE_45, - S390_FEAT_STFLE_49, - S390_FEAT_LOCAL_TLB_CLEARING, - S390_FEAT_STFLE_53, - S390_FEAT_MSA_EXT_5, - S390_FEAT_MSA_EXT_3, - S390_FEAT_MSA_EXT_4, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(feats); i++) { - set_bit(feats[i], fbm); - } -} - static S390CPUModel *get_max_cpu_model(Error **errp) { static S390CPUModel max_model; @@ -866,12 +829,10 @@ static S390CPUModel *get_max_cpu_model(Error **errp) if (kvm_enabled()) { kvm_s390_get_host_cpu_model(&max_model, errp); } else { - /* TCG emulates a z900 (with some optional additional features) */ - max_model.def = &s390_cpu_defs[0]; - bitmap_copy(max_model.features, max_model.def->default_feat, - S390_FEAT_MAX); - add_qemu_cpu_model_features(max_model.features); - } + max_model.def = s390_find_cpu_def(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, + QEMU_MAX_CPU_EC_GA, NULL); + bitmap_copy(max_model.features, qemu_max_cpu_feat, S390_FEAT_MAX); + } if (!*errp) { cached = true; return &max_model; @@ -1127,18 +1088,42 @@ static void s390_host_cpu_model_initfn(Object *obj) } #endif +static S390CPUDef s390_qemu_cpu_def; +static S390CPUModel s390_qemu_cpu_model; + +/* Set the qemu CPU model (on machine initialization). Must not be called + * once CPUs have been created. + */ +void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, + const S390FeatInit feat_init) +{ + const S390CPUDef *def = s390_find_cpu_def(type, gen, ec_ga, NULL); + + g_assert(def); + g_assert(QTAILQ_EMPTY(&cpus)); + + /* TCG emulates some features that can usually not be enabled with + * the emulated machine generation. Make sure they can be enabled + * when using the QEMU model by adding them to full_feat. We have + * to copy the definition to do that. + */ + memcpy(&s390_qemu_cpu_def, def, sizeof(s390_qemu_cpu_def)); + bitmap_or(s390_qemu_cpu_def.full_feat, s390_qemu_cpu_def.full_feat, + qemu_max_cpu_feat, S390_FEAT_MAX); + + /* build the CPU model */ + s390_qemu_cpu_model.def = &s390_qemu_cpu_def; + bitmap_zero(s390_qemu_cpu_model.features, S390_FEAT_MAX); + s390_init_feat_bitmap(feat_init, s390_qemu_cpu_model.features); +} + static void s390_qemu_cpu_model_initfn(Object *obj) { - static S390CPUDef s390_qemu_cpu_defs; S390CPU *cpu = S390_CPU(obj); cpu->model = g_malloc0(sizeof(*cpu->model)); - /* TCG emulates a z900 (with some optional additional features) */ - memcpy(&s390_qemu_cpu_defs, &s390_cpu_defs[0], sizeof(s390_qemu_cpu_defs)); - add_qemu_cpu_model_features(s390_qemu_cpu_defs.full_feat); - cpu->model->def = &s390_qemu_cpu_defs; - bitmap_copy(cpu->model->features, cpu->model->def->default_feat, - S390_FEAT_MAX); + /* copy the CPU model so we can modify it */ + memcpy(cpu->model, &s390_qemu_cpu_model, sizeof(*cpu->model)); } static void s390_cpu_model_finalize(Object *obj) @@ -1279,11 +1264,13 @@ static void init_ignored_base_feat(void) static void register_types(void) { + static const S390FeatInit qemu_latest_init = { S390_FEAT_LIST_QEMU_LATEST }; int i; init_ignored_base_feat(); /* init all bitmaps from gnerated data initially */ + s390_init_feat_bitmap(qemu_max_cpu_feat_init, qemu_max_cpu_feat); for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { s390_init_feat_bitmap(s390_cpu_defs[i].base_init, s390_cpu_defs[i].base_feat); @@ -1293,6 +1280,10 @@ static void register_types(void) s390_cpu_defs[i].full_feat); } + /* initialize the qemu model with latest definition */ + s390_set_qemu_cpu_model(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN, + QEMU_MAX_CPU_EC_GA, qemu_latest_init); + for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) { char *base_name = s390_base_cpu_type_name(s390_cpu_defs[i].name); TypeInfo ti_base = { diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 4c6dee1871..11cf5386fb 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -14,6 +14,7 @@ #define TARGET_S390X_CPU_MODELS_H #include "cpu_features.h" +#include "gen-features.h" #include "qom/cpu.h" /* static CPU definition */ diff --git a/target/s390x/crypto_helper.c b/target/s390x/crypto_helper.c index fa360a2d6e..5c79790187 100644 --- a/target/s390x/crypto_helper.c +++ b/target/s390x/crypto_helper.c @@ -23,7 +23,6 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, const uintptr_t ra = GETPC(); const uint8_t mod = env->regs[0] & 0x80ULL; const uint8_t fc = env->regs[0] & 0x7fULL; - CPUState *cs = CPU(s390_env_get_cpu(env)); uint8_t subfunc[16] = { 0 }; uint64_t param_addr; int i; @@ -35,8 +34,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, case S390_FEAT_TYPE_PCKMO: case S390_FEAT_TYPE_PCC: if (mod) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } break; @@ -44,8 +42,7 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3, s390_get_feat_block(type, subfunc); if (!test_be_bit(fc, subfunc)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return 0; } diff --git a/target/s390x/diag.c b/target/s390x/diag.c index dbbb9e886f..a755837ad5 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -99,19 +99,19 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) #define DIAG_308_RC_NO_CONF 0x0102 #define DIAG_308_RC_INVALID 0x0402 -void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) +void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) { uint64_t addr = env->regs[r1]; uint64_t subcode = env->regs[r3]; IplParameterBlock *iplb; if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO); + s390_program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO, ra); return; } if ((subcode & ~0x0ffffULL) || (subcode > 6)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); return; } @@ -136,12 +136,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3) break; case 5: if ((r1 & 1) || (addr & 0x0fffULL)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); return; } if (!address_space_access_valid(&address_space_memory, addr, sizeof(IplParameterBlock), false)) { - program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO); + s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra); return; } iplb = g_new0(IplParameterBlock, 1); @@ -165,12 +165,12 @@ out: return; case 6: if ((r1 & 1) || (addr & 0x0fffULL)) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); return; } if (!address_space_access_valid(&address_space_memory, addr, sizeof(IplParameterBlock), true)) { - program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO); + s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra); return; } iplb = s390_ipl_get_iplb(); diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index e04b670663..f4697a884d 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -395,6 +395,9 @@ static void do_mchk_interrupt(CPUS390XState *env) lowcore = cpu_map_lowcore(env); + /* we are always in z/Architecture mode */ + lowcore->ar_access_id = 1; + for (i = 0; i < 16; i++) { lowcore->floating_pt_save_area[i] = cpu_to_be64(get_freg(env, i)->ll); lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]); @@ -404,13 +407,10 @@ static void do_mchk_interrupt(CPUS390XState *env) lowcore->prefixreg_save_area = cpu_to_be32(env->psa); lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc); lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr); - lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32); - lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm); - lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32); - lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc); + lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm); + lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8); - lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d); - lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000); + lowcore->mcic = cpu_to_be64(s390_build_validity_mcic() | MCIC_SC_CP); lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); mask = be64_to_cpu(lowcore->mcck_new_psw.mask); @@ -554,10 +554,7 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - if (retaddr) { - cpu_restore_state(cs, retaddr); - } - program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, retaddr); } #endif /* CONFIG_USER_ONLY */ diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index ffbeb3b2df..334159119f 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -44,7 +44,7 @@ static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr) /* Install the DXC code. */ env->fpc = (env->fpc & ~0xff00) | (dxc << 8); /* Trap. */ - runtime_exception(env, PGM_DATA, retaddr); + s390_program_interrupt(env, PGM_DATA, ILEN_AUTO, retaddr); } /* Should be called after any operation that may raise IEEE exceptions. */ diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c index 68e6c31b4b..b24f6ada5b 100644 --- a/target/s390x/gen-features.c +++ b/target/s390x/gen-features.c @@ -536,6 +536,52 @@ static uint16_t default_GEN14_GA1[] = { S390_FEAT_GROUP_MSA_EXT_8, }; +/* QEMU (CPU model) features */ + +static uint16_t qemu_V2_11[] = { + S390_FEAT_GROUP_PLO, + S390_FEAT_ESAN3, + S390_FEAT_ZARCH, +}; + +static uint16_t qemu_LATEST[] = { + S390_FEAT_DAT_ENH, + S390_FEAT_IDTE_SEGMENT, + S390_FEAT_STFLE, + S390_FEAT_SENSE_RUNNING_STATUS, + S390_FEAT_EXTENDED_TRANSLATION_2, + S390_FEAT_MSA, + S390_FEAT_LONG_DISPLACEMENT, + S390_FEAT_LONG_DISPLACEMENT_FAST, + S390_FEAT_EXTENDED_IMMEDIATE, + S390_FEAT_EXTENDED_TRANSLATION_3, + S390_FEAT_ETF2_ENH, + S390_FEAT_STORE_CLOCK_FAST, + S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, + S390_FEAT_ETF3_ENH, + S390_FEAT_EXTRACT_CPU_TIME, + S390_FEAT_COMPARE_AND_SWAP_AND_STORE, + S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2, + S390_FEAT_GENERAL_INSTRUCTIONS_EXT, + S390_FEAT_EXECUTE_EXT, + S390_FEAT_SET_PROGRAM_PARAMETERS, + S390_FEAT_FLOATING_POINT_SUPPPORT_ENH, + S390_FEAT_STFLE_45, + S390_FEAT_STFLE_49, + S390_FEAT_LOCAL_TLB_CLEARING, + S390_FEAT_INTERLOCKED_ACCESS_2, + S390_FEAT_MSA_EXT_4, + S390_FEAT_MSA_EXT_3, +}; + +/* add all new definitions before this point */ +static uint16_t qemu_MAX[] = { + /* z13+ features */ + S390_FEAT_STFLE_53, + /* generates a dependency warning, leave it out for now */ + S390_FEAT_MSA_EXT_5, +}; + /****** END FEATURE DEFS ******/ #define _YEARS "2016" @@ -627,6 +673,24 @@ static FeatGroupDefSpec FeatGroupDef[] = { FEAT_GROUP_INITIALIZER(MSA_EXT_8), }; +#define QEMU_FEAT_INITIALIZER(_name) \ + { \ + .name = "S390_FEAT_LIST_QEMU_" #_name, \ + .bits = \ + { .data = qemu_##_name, \ + .len = ARRAY_SIZE(qemu_##_name) }, \ + } + +/******************************* + * QEMU (CPU model) features + *******************************/ +static FeatGroupDefSpec QemuFeatDef[] = { + QEMU_FEAT_INITIALIZER(V2_11), + QEMU_FEAT_INITIALIZER(LATEST), + QEMU_FEAT_INITIALIZER(MAX), +}; + + static void set_bits(uint64_t list[], BitSpec bits) { uint32_t i; @@ -684,6 +748,29 @@ static void print_feature_defs(void) } } +static void print_qemu_feature_defs(void) +{ + uint64_t feat[S390_FEAT_MAX / 64 + 1] = {}; + int i, j; + + printf("\n/* QEMU (CPU model) feature list data */\n"); + + /* for now we assume that we only add new features */ + for (i = 0; i < ARRAY_SIZE(QemuFeatDef); i++) { + set_bits(feat, QemuFeatDef[i].bits); + + printf("#define %s\t", QemuFeatDef[i].name); + for (j = 0; j < ARRAY_SIZE(feat); j++) { + printf("0x%016"PRIx64"ULL", feat[j]); + if (j < ARRAY_SIZE(feat) - 1) { + printf(","); + } else { + printf("\n"); + } + } + } +} + static void print_feature_group_defs(void) { int i, j; @@ -721,6 +808,7 @@ int main(int argc, char *argv[]) "#ifndef %s\n#define %s\n", __FILE__, _YEARS, _NAME_H, _NAME_H); print_feature_defs(); print_feature_group_defs(); + print_qemu_feature_defs(); printf("\n#endif\n"); return 0; } diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 246ba20f0d..35d9741918 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -31,24 +31,6 @@ #include "sysemu/sysemu.h" #endif -//#define DEBUG_S390 -//#define DEBUG_S390_STDOUT - -#ifdef DEBUG_S390 -#ifdef DEBUG_S390_STDOUT -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); \ - if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { qemu_log(fmt, ## __VA_ARGS__); } while (0) -#endif -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - - #ifndef CONFIG_USER_ONLY void s390x_tod_timer(void *opaque) { diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 9459b73c73..2f17b62d3d 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -119,6 +119,7 @@ DEF_HELPER_4(cu24, i32, env, i32, i32, i32) DEF_HELPER_4(cu41, i32, env, i32, i32, i32) DEF_HELPER_4(cu42, i32, env, i32, i32, i32) DEF_HELPER_5(msa, i32, env, i32, i32, i32, i32) +DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) @@ -127,9 +128,9 @@ DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env) DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64) +DEF_HELPER_FLAGS_2(sckpf, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64) -DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env) DEF_HELPER_4(stsi, i32, env, i64, i64, i64) DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) @@ -164,7 +165,10 @@ DEF_HELPER_2(hsch, void, env, i64) DEF_HELPER_3(msch, void, env, i64, i64) DEF_HELPER_2(rchp, void, env, i64) DEF_HELPER_2(rsch, void, env, i64) +DEF_HELPER_2(sal, void, env, i64) +DEF_HELPER_4(schm, void, env, i64, i64, i64) DEF_HELPER_3(ssch, void, env, i64, i64) +DEF_HELPER_2(stcrw, void, env, i64) DEF_HELPER_3(stsch, void, env, i64, i64) DEF_HELPER_3(tsch, void, env, i64, i64) DEF_HELPER_2(chsc, void, env, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 16e27c8a35..11ee43dcbc 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -39,10 +39,10 @@ C(0xb9d8, AHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, adds32) /* ADD IMMEDIATE */ C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) - C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) + D(0xeb6a, ASI, SIY, GIE, la1, i2, new, 0, asi, adds32, MO_TESL) C(0xecd8, AHIK, RIE_d, DO, r3, i2, new, r1_32, add, adds32) C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) - C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) + D(0xeb7a, AGSI, SIY, GIE, la1, i2, new, 0, asi, adds64, MO_TEQ) C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) /* ADD IMMEDIATE HIGH */ C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32) @@ -70,9 +70,9 @@ C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) /* ADD LOGICAL WITH SIGNED IMMEDIATE */ - C(0xeb6e, ALSI, SIY, GIE, m1_32u, i2, new, m1_32, add, addu32) + D(0xeb6e, ALSI, SIY, GIE, la1, i2, new, 0, asi, addu32, MO_TEUL) C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) - C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) + D(0xeb7e, ALGSI, SIY, GIE, la1, i2, new, 0, asi, addu64, MO_TEQ) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) /* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */ C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, addu32) @@ -99,8 +99,8 @@ D(0xa505, NIHL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1020) D(0xa506, NILH, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1010) D(0xa507, NILL, RI_a, Z, r1_o, i2_16u, r1, 0, andi, 0, 0x1000) - C(0x9400, NI, SI, Z, m1_8u, i2_8u, new, m1_8, and, nz64) - C(0xeb54, NIY, SIY, LD, m1_8u, i2_8u, new, m1_8, and, nz64) + D(0x9400, NI, SI, Z, la1, i2_8u, new, 0, ni, nz64, MO_UB) + D(0xeb54, NIY, SIY, LD, la1, i2_8u, new, 0, ni, nz64, MO_UB) /* BRANCH AND SAVE */ C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0) @@ -357,8 +357,8 @@ /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) - C(0x9700, XI, SI, Z, m1_8u, i2_8u, new, m1_8, xor, nz64) - C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) + D(0x9700, XI, SI, Z, la1, i2_8u, new, 0, xi, nz64, MO_UB) + D(0xeb57, XIY, SIY, LD, la1, i2_8u, new, 0, xi, nz64, MO_UB) /* EXECUTE */ C(0x4400, EX, RX_a, Z, 0, a2, 0, 0, ex, 0) @@ -369,6 +369,8 @@ C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) /* EXTRACT CPU ATTRIBUTE */ C(0xeb4c, ECAG, RSY_a, GIE, 0, a2, r1, 0, ecag, 0) +/* EXTRACT CPU TIME */ + C(0xc801, ECTG, SSF, ECT, 0, 0, 0, 0, ectg, 0) /* EXTRACT FPC */ C(0xb38c, EFPC, RRE, Z, 0, 0, new, r1_32, efpc, 0) /* EXTRACT PSW */ @@ -698,8 +700,8 @@ D(0xa509, OIHL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1020) D(0xa50a, OILH, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1010) D(0xa50b, OILL, RI_a, Z, r1_o, i2_16u, r1, 0, ori, 0, 0x1000) - C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) - C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) + D(0x9600, OI, SI, Z, la1, i2_8u, new, 0, oi, nz64, MO_UB) + D(0xeb56, OIY, SIY, LD, la1, i2_8u, new, 0, oi, nz64, MO_UB) /* PACK */ /* Really format SS_b, but we pack both lengths into one argument @@ -999,6 +1001,8 @@ C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0) /* SET CLOCK COMPARATOR */ C(0xb206, SCKC, S, Z, 0, m2_64, 0, 0, sckc, 0) +/* SET CLOCK PROGRAMMABLE FIELD */ + C(0x0107, SCKPF, E, Z, 0, 0, 0, 0, sckpf, 0) /* SET CPU TIMER */ C(0xb208, SPT, S, Z, 0, m2_64, 0, 0, spt, 0) /* SET PREFIX */ @@ -1052,7 +1056,12 @@ C(0xb232, MSCH, S, Z, 0, insn, 0, 0, msch, 0) C(0xb23b, RCHP, S, Z, 0, 0, 0, 0, rchp, 0) C(0xb238, RSCH, S, Z, 0, 0, 0, 0, rsch, 0) + C(0xb237, SAL, S, Z, 0, 0, 0, 0, sal, 0) + C(0xb23c, SCHM, S, Z, 0, insn, 0, 0, schm, 0) + C(0xb274, SIGA, S, Z, 0, 0, 0, 0, siga, 0) + C(0xb23a, STCPS, S, Z, 0, 0, 0, 0, stcps, 0) C(0xb233, SSCH, S, Z, 0, insn, 0, 0, ssch, 0) + C(0xb239, STCRW, S, Z, 0, insn, 0, 0, stcrw, 0) C(0xb234, STSCH, S, Z, 0, insn, 0, 0, stsch, 0) C(0xb235, TSCH, S, Z, 0, insn, 0, 0, tsch, 0) /* ??? Not listed in PoO ninth edition, but there's a linux driver that diff --git a/target/s390x/int_helper.c b/target/s390x/int_helper.c index 0076bea047..abf77a94e6 100644 --- a/target/s390x/int_helper.c +++ b/target/s390x/int_helper.c @@ -39,7 +39,7 @@ int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) int64_t q; if (b == 0) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } ret = q = a / b; @@ -47,7 +47,7 @@ int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) /* Catch non-representable quotient. */ if (ret != q) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } return ret; @@ -60,7 +60,7 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) uint64_t q; if (b == 0) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } ret = q = a / b; @@ -68,7 +68,7 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) /* Catch non-representable quotient. */ if (ret != q) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } return ret; @@ -79,7 +79,7 @@ int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) { /* Catch divide by zero, and non-representable quotient (MIN / -1). */ if (b == 0 || (b == -1 && a == (1ll << 63))) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } env->retxl = a % b; return a / b; @@ -92,7 +92,7 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t ret; /* Signal divide by zero. */ if (b == 0) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } if (ah == 0) { /* 64 -> 64/64 case */ @@ -106,7 +106,7 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, env->retxl = a % b; ret = q; if (ret != q) { - runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); + s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC()); } #else S390CPU *cpu = s390_env_get_cpu(env); diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 3aff54ada4..1a88e4beb4 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -43,7 +43,7 @@ typedef struct LowCore { uint8_t pad3[0xc8 - 0xc4]; /* 0x0c4 */ uint32_t stfl_fac_list; /* 0x0c8 */ uint8_t pad4[0xe8 - 0xcc]; /* 0x0cc */ - uint32_t mcck_interruption_code[2]; /* 0x0e8 */ + uint64_t mcic; /* 0x0e8 */ uint8_t pad5[0xf4 - 0xf0]; /* 0x0f0 */ uint32_t external_damage_code; /* 0x0f4 */ uint64_t failing_storage_address; /* 0x0f8 */ @@ -118,8 +118,8 @@ typedef struct LowCore { uint32_t fpt_creg_save_area; /* 0x131c */ uint8_t pad16[0x1324 - 0x1320]; /* 0x1320 */ uint32_t tod_progreg_save_area; /* 0x1324 */ - uint32_t cpu_timer_save_area[2]; /* 0x1328 */ - uint32_t clock_comp_save_area[2]; /* 0x1330 */ + uint64_t cpu_timer_save_area; /* 0x1328 */ + uint64_t clock_comp_save_area; /* 0x1330 */ uint8_t pad17[0x1340 - 0x1338]; /* 0x1338 */ uint32_t access_regs_save_area[16]; /* 0x1340 */ uint64_t cregs_save_area[16]; /* 0x1380 */ @@ -379,21 +379,23 @@ void cpu_inject_stop(S390CPU *cpu); /* ioinst.c */ -void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb); -void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb); -int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb); +void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra); +void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra); +void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra); +void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, + uintptr_t ra); +void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, + uintptr_t ra); +void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra); +void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, + uintptr_t ra); +int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra); +void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra); void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, - uint32_t ipb); -void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1); + uint32_t ipb, uintptr_t ra); +void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra); +void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra); +void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra); /* mem_helper.c */ @@ -408,10 +410,9 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, /* misc_helper.c */ -void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, - uintptr_t retaddr); int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3); -void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); +void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, + uintptr_t ra); /* translate.c */ diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index ce6177c141..39c026b8b5 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -27,17 +27,18 @@ void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) } static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code, - int ilen) + int ilen, uintptr_t ra) { #ifdef CONFIG_TCG trigger_pgm_exception(env, code, ilen); - cpu_loop_exit(CPU(s390_env_get_cpu(env))); + cpu_loop_exit_restore(CPU(s390_env_get_cpu(env)), ra); #else g_assert_not_reached(); #endif } -void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) +void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, + uintptr_t ra) { S390CPU *cpu = s390_env_get_cpu(env); @@ -47,7 +48,7 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) if (kvm_enabled()) { kvm_s390_program_interrupt(cpu, code); } else if (tcg_enabled()) { - tcg_s390_program_interrupt(env, code, ilen); + tcg_s390_program_interrupt(env, code, ilen, ra); } else { g_assert_not_reached(); } diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 23962fbebc..83c164a168 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -38,13 +38,13 @@ int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid, return 0; } -void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(&cpu->env, PGM_OPERAND, 4); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("xsch", cssid, ssid, schid); @@ -56,13 +56,13 @@ void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1) setcc(cpu, css_do_xsch(sch)); } -void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(&cpu->env, PGM_OPERAND, 4); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("csch", cssid, ssid, schid); @@ -74,13 +74,13 @@ void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1) setcc(cpu, css_do_csch(sch)); } -void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(&cpu->env, PGM_OPERAND, 4); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("hsch", cssid, ssid, schid); @@ -105,7 +105,7 @@ static int ioinst_schib_valid(SCHIB *schib) return 1; } -void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) +void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; @@ -116,15 +116,16 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return; } if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_schib_valid(&schib)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("msch", cssid, ssid, schid); @@ -161,7 +162,7 @@ static int ioinst_orb_valid(ORB *orb) return 1; } -void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) +void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; @@ -172,16 +173,17 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return; } copy_orb_from_guest(&orb, &orig_orb); if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) || !ioinst_orb_valid(&orb)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("ssch", cssid, ssid, schid); @@ -193,7 +195,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) setcc(cpu, css_do_ssch(sch, &orb)); } -void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) +void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra) { CRW crw; uint64_t addr; @@ -203,7 +205,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } @@ -212,13 +214,17 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) { setcc(cpu, cc); - } else if (cc == 0) { - /* Write failed: requeue CRW since STCRW is a suppressing instruction */ - css_undo_stcrw(&crw); + } else { + if (cc == 0) { + /* Write failed: requeue CRW since STCRW is suppressing */ + css_undo_stcrw(&crw); + } + s390_cpu_virt_mem_handle_exc(cpu, ra); } } -void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) +void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, + uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; @@ -230,7 +236,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } @@ -241,7 +247,9 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) * access execption if it is not) first. */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); + } else { + s390_cpu_virt_mem_handle_exc(cpu, ra); } return; } @@ -267,18 +275,20 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) if (cc != 3) { if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib, sizeof(schib)) != 0) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return; } } else { /* Access exceptions have a higher priority than cc3 */ if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return; } } setcc(cpu, cc); } -int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) +int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) { CPUS390XState *env = &cpu->env; int cssid, ssid, schid, m; @@ -289,13 +299,13 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) uint8_t ar; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return -EIO; } trace_ioinst_sch_id("tsch", cssid, ssid, schid); addr = decode_basedisp_s(env, ipb, &ar); if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return -EIO; } @@ -308,6 +318,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) /* 0 - status pending, 1 - not status pending, 3 - not operational */ if (cc != 3) { if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } css_do_tsch_update_subch(sch); @@ -315,6 +326,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) irb_len = sizeof(irb) - sizeof(irb.emw); /* Access exceptions have a higher priority than cc3 */ if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return -EFAULT; } } @@ -585,7 +597,7 @@ static void ioinst_handle_chsc_unimplemented(ChscResp *res) res->param = 0; } -void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) +void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) { ChscReq *req; ChscResp *res; @@ -601,7 +613,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) addr = env->regs[reg]; /* Page boundary? */ if (addr & 0xfff) { - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); return; } /* @@ -610,13 +622,14 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) * care of req->len here first. */ if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return; } req = (ChscReq *)buf; len = be16_to_cpu(req->len); /* Length field valid? */ if ((len < 16) || (len > 4088) || (len & 7)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } memset((char *)req + len, 0, TARGET_PAGE_SIZE - len); @@ -644,42 +657,18 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res, be16_to_cpu(res->len))) { setcc(cpu, 0); /* Command execution complete */ + } else { + s390_cpu_virt_mem_handle_exc(cpu, ra); } } -int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb) -{ - CPUS390XState *env = &cpu->env; - uint64_t addr; - int lowcore; - IOIntCode int_code; - hwaddr len; - int ret; - uint8_t ar; - - trace_ioinst("tpi"); - addr = decode_basedisp_s(env, ipb, &ar); - if (addr & 3) { - program_interrupt(env, PGM_SPECIFICATION, 4); - return -EIO; - } - - lowcore = addr ? 0 : 1; - len = lowcore ? 8 /* two words */ : 12 /* three words */; - ret = css_do_tpi(&int_code, lowcore); - if (ret == 1) { - s390_cpu_virt_mem_write(cpu, lowcore ? 184 : addr, ar, &int_code, len); - } - return ret; -} - #define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc) #define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28) #define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1) #define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001) void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, - uint32_t ipb) + uint32_t ipb, uintptr_t ra) { uint8_t mbk; int update; @@ -689,7 +678,7 @@ void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, trace_ioinst("schm"); if (SCHM_REG1_RES(reg1)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } @@ -698,20 +687,20 @@ void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, dct = SCHM_REG1_DCT(reg1); if (update && (reg2 & 0x000000000000001f)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } css_do_schm(mbk, update, dct, update ? reg2 : 0); } -void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cssid, ssid, schid, m; SubchDev *sch; if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) { - program_interrupt(&cpu->env, PGM_OPERAND, 4); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); return; } trace_ioinst_sch_id("rsch", cssid, ssid, schid); @@ -726,7 +715,7 @@ void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1) #define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00) #define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16) #define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff) -void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { int cc; uint8_t cssid; @@ -735,7 +724,7 @@ void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1) CPUS390XState *env = &cpu->env; if (RCHP_REG1_RES(reg1)) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } @@ -758,17 +747,17 @@ void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1) break; default: /* Invalid channel subsystem. */ - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return; } setcc(cpu, cc); } #define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000) -void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1) +void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra) { /* We do not provide address limit checking, so let's suppress it. */ if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) { - program_interrupt(&cpu->env, PGM_OPERAND, 4); + s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra); } } diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index b03f583032..9b8b59f2a2 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1124,32 +1124,32 @@ static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) switch (ipa1) { case PRIV_B2_XSCH: - ioinst_handle_xsch(cpu, env->regs[1]); + ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_CSCH: - ioinst_handle_csch(cpu, env->regs[1]); + ioinst_handle_csch(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_HSCH: - ioinst_handle_hsch(cpu, env->regs[1]); + ioinst_handle_hsch(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_MSCH: - ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_SSCH: - ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_STCRW: - ioinst_handle_stcrw(cpu, run->s390_sieic.ipb); + ioinst_handle_stcrw(cpu, run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_STSCH: - ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb); + ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_TSCH: /* We should only get tsch via KVM_EXIT_S390_TSCH. */ fprintf(stderr, "Spurious tsch intercept\n"); break; case PRIV_B2_CHSC: - ioinst_handle_chsc(cpu, run->s390_sieic.ipb); + ioinst_handle_chsc(cpu, run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_TPI: /* This should have been handled by kvm already. */ @@ -1157,19 +1157,19 @@ static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) break; case PRIV_B2_SCHM: ioinst_handle_schm(cpu, env->regs[1], env->regs[2], - run->s390_sieic.ipb); + run->s390_sieic.ipb, RA_IGNORED); break; case PRIV_B2_RSCH: - ioinst_handle_rsch(cpu, env->regs[1]); + ioinst_handle_rsch(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_RCHP: - ioinst_handle_rchp(cpu, env->regs[1]); + ioinst_handle_rchp(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_STCPS: /* We do not provide this instruction, it is suppressed. */ break; case PRIV_B2_SAL: - ioinst_handle_sal(cpu, env->regs[1]); + ioinst_handle_sal(cpu, env->regs[1], RA_IGNORED); break; case PRIV_B2_SIGA: /* Not provided, set CC = 3 for subchannel not operational */ @@ -1230,7 +1230,7 @@ static int kvm_clp_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; if (s390_has_feat(S390_FEAT_ZPCI)) { - return clp_service_call(cpu, r2); + return clp_service_call(cpu, r2, RA_IGNORED); } else { return -1; } @@ -1242,7 +1242,7 @@ static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; if (s390_has_feat(S390_FEAT_ZPCI)) { - return pcilg_service_call(cpu, r1, r2); + return pcilg_service_call(cpu, r1, r2, RA_IGNORED); } else { return -1; } @@ -1254,7 +1254,7 @@ static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; if (s390_has_feat(S390_FEAT_ZPCI)) { - return pcistg_service_call(cpu, r1, r2); + return pcistg_service_call(cpu, r1, r2, RA_IGNORED); } else { return -1; } @@ -1270,7 +1270,7 @@ static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run) cpu_synchronize_state(CPU(cpu)); fiba = get_base_disp_rxy(cpu, run, &ar); - return stpcifc_service_call(cpu, r1, fiba, ar); + return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED); } else { return -1; } @@ -1302,7 +1302,7 @@ static int kvm_rpcit_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; if (s390_has_feat(S390_FEAT_ZPCI)) { - return rpcit_service_call(cpu, r1, r2); + return rpcit_service_call(cpu, r1, r2, RA_IGNORED); } else { return -1; } @@ -1319,7 +1319,7 @@ static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run) cpu_synchronize_state(CPU(cpu)); gaddr = get_base_disp_rsy(cpu, run, &ar); - return pcistb_service_call(cpu, r1, r3, gaddr, ar); + return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED); } else { return -1; } @@ -1335,7 +1335,7 @@ static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run) cpu_synchronize_state(CPU(cpu)); fiba = get_base_disp_rxy(cpu, run, &ar); - return mpcifc_service_call(cpu, r1, fiba, ar); + return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED); } else { return -1; } @@ -1451,7 +1451,7 @@ static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run) cpu_synchronize_state(CPU(cpu)); r1 = (run->s390_sieic.ipa & 0x00f0) >> 4; r3 = run->s390_sieic.ipa & 0x000f; - handle_diag_308(&cpu->env, r1, r3); + handle_diag_308(&cpu->env, r1, r3, RA_IGNORED); } static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run) @@ -1673,7 +1673,8 @@ static int handle_tsch(S390CPU *cpu) cpu_synchronize_state(cs); - ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb); + ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb, + RA_IGNORED); if (ret < 0) { /* * Failure. @@ -1851,33 +1852,12 @@ void kvm_s390_io_interrupt(uint16_t subchannel_id, kvm_s390_floating_interrupt(&irq); } -static uint64_t build_channel_report_mcic(void) -{ - uint64_t mcic; - - /* subclass: indicate channel report pending */ - mcic = MCIC_SC_CP | - /* subclass modifiers: none */ - /* storage errors: none */ - /* validity bits: no damage */ - MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP | - MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR | - MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC; - if (s390_has_feat(S390_FEAT_VECTOR)) { - mcic |= MCIC_VB_VR; - } - if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) { - mcic |= MCIC_VB_GS; - } - return mcic; -} - void kvm_s390_crw_mchk(void) { struct kvm_s390_irq irq = { .type = KVM_S390_MCHK, - .u.mchk.cr14 = 1 << 28, - .u.mchk.mcic = build_channel_report_mcic(), + .u.mchk.cr14 = CR14_CHANNEL_REPORT_SC, + .u.mchk.mcic = s390_build_validity_mcic() | MCIC_SC_CP, }; kvm_s390_floating_interrupt(&irq); } @@ -1979,7 +1959,10 @@ int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) { - struct kvm_s390_irq_state irq_state; + struct kvm_s390_irq_state irq_state = { + .buf = (uint64_t) cpu->irqstate, + .len = VCPU_IRQ_BUF_SIZE, + }; CPUState *cs = CPU(cpu); int32_t bytes; @@ -1987,9 +1970,6 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) return; } - irq_state.buf = (uint64_t) cpu->irqstate; - irq_state.len = VCPU_IRQ_BUF_SIZE; - bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state); if (bytes < 0) { cpu->irqstate_saved_size = 0; @@ -2003,7 +1983,10 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) { CPUState *cs = CPU(cpu); - struct kvm_s390_irq_state irq_state; + struct kvm_s390_irq_state irq_state = { + .buf = (uint64_t) cpu->irqstate, + .len = cpu->irqstate_saved_size, + }; int r; if (cpu->irqstate_saved_size == 0) { @@ -2014,9 +1997,6 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) return -ENOSYS; } - irq_state.buf = (uint64_t) cpu->irqstate; - irq_state.len = cpu->irqstate_saved_size; - r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state); if (r) { error_report("Setting interrupt state failed %d", r); diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index a1652d4849..2625d843b3 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -85,9 +85,7 @@ static inline void check_alignment(CPUS390XState *env, uint64_t v, int wordsize, uintptr_t ra) { if (v % wordsize) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); } } @@ -545,8 +543,7 @@ void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2) /* Bits 32-55 must contain all 0. */ if (env->regs[0] & 0xffffff00u) { - cpu_restore_state(ENV_GET_CPU(env), ra); - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); } str = get_address(env, r2); @@ -583,8 +580,7 @@ void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2) /* Bits 32-47 of R0 must be zero. */ if (env->regs[0] & 0xffff0000u) { - cpu_restore_state(ENV_GET_CPU(env), ra); - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); } str = get_address(env, r2); @@ -1600,8 +1596,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1, return cc; spec_exception: - cpu_restore_state(ENV_GET_CPU(env), ra); - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); g_assert_not_reached(); } @@ -1865,8 +1860,7 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4) uint16_t entries, i, index = 0; if (r2 & 0xff000) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); } if (!(r2 & 0x800)) { @@ -2014,8 +2008,7 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) /* XXX incomplete - has more corner cases */ if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { - cpu_restore_state(cs, GETPC()); - program_interrupt(env, PGM_SPECIAL_OP, 2); + s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC()); } old_exc = cs->exception_index; @@ -2185,7 +2178,6 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC; const uint64_t r0 = env->regs[0]; const uintptr_t ra = GETPC(); - CPUState *cs = CPU(s390_env_get_cpu(env)); uint8_t dest_key, dest_as, dest_k, dest_a; uint8_t src_key, src_as, src_k, src_a; uint64_t val; @@ -2195,8 +2187,7 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, __func__, dest, src, len); if (!(env->psw.mask & PSW_MASK_DAT)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIAL_OP, 6); + s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); } /* OAC (operand access control) for the first operand -> dest */ @@ -2227,17 +2218,14 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, } if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIAL_OP, 6); + s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); } if (!(env->cregs[0] & CR0_SECONDARY) && (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_SPECIAL_OP, 6); + s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra); } if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) { - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_PRIVILEGED, 6); + s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra); } len = wrap_length(env, len); @@ -2251,8 +2239,7 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, (env->psw.mask & PSW_MASK_PSTATE)) { qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n", __func__); - cpu_restore_state(cs, ra); - program_interrupt(env, PGM_ADDRESSING, 6); + s390_program_interrupt(env, PGM_ADDRESSING, 6, ra); } /* FIXME: a) LAP diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index d272851e1c..86da6aab7e 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -45,22 +45,6 @@ #define HELPER_LOG(x...) #endif -/* Raise an exception dynamically from a helper function. */ -void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, - uintptr_t retaddr) -{ - CPUState *cs = CPU(s390_env_get_cpu(env)); - - cs->exception_index = EXCP_PGM; - env->int_pgm_code = excp; - env->int_pgm_ilen = ILEN_AUTO; - - /* Use the (ultimate) callers address to find the insn that trapped. */ - cpu_restore_state(cs, retaddr); - - cpu_loop_exit(cs); -} - /* Raise an exception statically from a TB. */ void HELPER(exception)(CPUS390XState *env, uint32_t excp) { @@ -71,6 +55,21 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) cpu_loop_exit(cs); } +/* Store CPU Timer (also used for EXTRACT CPU TIME) */ +uint64_t HELPER(stpt)(CPUS390XState *env) +{ +#if defined(CONFIG_USER_ONLY) + /* + * Fake a descending CPU timer. We could get negative values here, + * but we don't care as it is up to the OS when to process that + * interrupt and reset to > 0. + */ + return UINT64_MAX - (uint64_t)cpu_get_host_ticks(); +#else + return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); +#endif +} + #ifndef CONFIG_USER_ONLY /* SCLP service call */ @@ -78,11 +77,10 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) { qemu_mutex_lock_iothread(); int r = sclp_service_call(env, r1, r2); + qemu_mutex_unlock_iothread(); if (r < 0) { - program_interrupt(env, -r, 4); - r = 0; + s390_program_interrupt(env, -r, 4, GETPC()); } - qemu_mutex_unlock_iothread(); return r; } @@ -104,7 +102,7 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) case 0x308: /* ipl */ qemu_mutex_lock_iothread(); - handle_diag_308(env, r1, r3); + handle_diag_308(env, r1, r3, GETPC()); qemu_mutex_unlock_iothread(); r = 0; break; @@ -118,7 +116,7 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) } if (r) { - program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); + s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC()); } } @@ -163,6 +161,17 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) timer_mod(env->tod_timer, env->tod_basetime + time); } +/* Set Tod Programmable Field */ +void HELPER(sckpf)(CPUS390XState *env, uint64_t r0) +{ + uint32_t val = r0; + + if (val & 0xffff0000) { + s390_program_interrupt(env, PGM_SPECIFICATION, 2, GETPC()); + } + env->todpr = val; +} + /* Store Clock Comparator */ uint64_t HELPER(stckc)(CPUS390XState *env) { @@ -184,12 +193,6 @@ void HELPER(spt)(CPUS390XState *env, uint64_t time) timer_mod(env->cpu_timer, env->cputm); } -/* Store CPU Timer */ -uint64_t HELPER(stpt)(CPUS390XState *env) -{ - return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); -} - /* Store System Information */ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1) @@ -201,7 +204,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { /* valid function code, invalid reserved bits */ - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, GETPC()); } sel1 = r0 & STSI_R0_SEL1_MASK; @@ -339,7 +342,7 @@ void HELPER(xsch)(CPUS390XState *env, uint64_t r1) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_xsch(cpu, r1); + ioinst_handle_xsch(cpu, r1, GETPC()); qemu_mutex_unlock_iothread(); } @@ -347,7 +350,7 @@ void HELPER(csch)(CPUS390XState *env, uint64_t r1) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_csch(cpu, r1); + ioinst_handle_csch(cpu, r1, GETPC()); qemu_mutex_unlock_iothread(); } @@ -355,7 +358,7 @@ void HELPER(hsch)(CPUS390XState *env, uint64_t r1) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_hsch(cpu, r1); + ioinst_handle_hsch(cpu, r1, GETPC()); qemu_mutex_unlock_iothread(); } @@ -363,7 +366,7 @@ void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_msch(cpu, r1, inst >> 16); + ioinst_handle_msch(cpu, r1, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } @@ -371,7 +374,7 @@ void HELPER(rchp)(CPUS390XState *env, uint64_t r1) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_rchp(cpu, r1); + ioinst_handle_rchp(cpu, r1, GETPC()); qemu_mutex_unlock_iothread(); } @@ -379,7 +382,25 @@ void HELPER(rsch)(CPUS390XState *env, uint64_t r1) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_rsch(cpu, r1); + ioinst_handle_rsch(cpu, r1, GETPC()); + qemu_mutex_unlock_iothread(); +} + +void HELPER(sal)(CPUS390XState *env, uint64_t r1) +{ + S390CPU *cpu = s390_env_get_cpu(env); + + qemu_mutex_lock_iothread(); + ioinst_handle_sal(cpu, r1, GETPC()); + qemu_mutex_unlock_iothread(); +} + +void HELPER(schm)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint64_t inst) +{ + S390CPU *cpu = s390_env_get_cpu(env); + + qemu_mutex_lock_iothread(); + ioinst_handle_schm(cpu, r1, r2, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } @@ -387,7 +408,16 @@ void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_ssch(cpu, r1, inst >> 16); + ioinst_handle_ssch(cpu, r1, inst >> 16, GETPC()); + qemu_mutex_unlock_iothread(); +} + +void HELPER(stcrw)(CPUS390XState *env, uint64_t inst) +{ + S390CPU *cpu = s390_env_get_cpu(env); + + qemu_mutex_lock_iothread(); + ioinst_handle_stcrw(cpu, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } @@ -395,7 +425,7 @@ void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_stsch(cpu, r1, inst >> 16); + ioinst_handle_stsch(cpu, r1, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } @@ -403,7 +433,7 @@ void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_tsch(cpu, r1, inst >> 16); + ioinst_handle_tsch(cpu, r1, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } @@ -411,7 +441,7 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); qemu_mutex_lock_iothread(); - ioinst_handle_chsc(cpu, inst >> 16); + ioinst_handle_chsc(cpu, inst >> 16, GETPC()); qemu_mutex_unlock_iothread(); } #endif @@ -429,7 +459,7 @@ void HELPER(per_check_exception)(CPUS390XState *env) * of EXECUTE, while per_address contains the target of EXECUTE. */ ilen = get_ilen(cpu_ldub_code(env, env->per_address)); - program_interrupt(env, PGM_PER, ilen); + s390_program_interrupt(env, PGM_PER, ilen, GETPC()); } } @@ -519,8 +549,7 @@ uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr) int i; if (addr & 0x7) { - cpu_restore_state(ENV_GET_CPU(env), ra); - program_interrupt(env, PGM_SPECIFICATION, 4); + s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra); } prepare_stfl(); diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 31e3f3f415..f477cc006a 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -22,6 +22,7 @@ #include "internal.h" #include "kvm_s390x.h" #include "sysemu/kvm.h" +#include "exec/exec-all.h" #include "trace.h" #include "hw/s390x/storage-keys.h" @@ -63,7 +64,9 @@ static void trigger_access_exception(CPUS390XState *env, uint32_t type, kvm_s390_access_exception(cpu, type, tec); } else { CPUState *cs = CPU(cpu); - stq_phys(cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec); + if (type != PGM_ADDRESSING) { + stq_phys(cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec); + } trigger_pgm_exception(env, type, ilen); } } @@ -442,7 +445,8 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, /** * translate_pages: Translate a set of consecutive logical page addresses - * to absolute addresses + * to absolute addresses. This function is used for TCG and old KVM without + * the MEMOP interface. */ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, target_ulong *pages, bool is_write) @@ -458,7 +462,7 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, } if (!address_space_access_valid(&address_space_memory, pages[i], TARGET_PAGE_SIZE, is_write)) { - program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO); + trigger_access_exception(env, PGM_ADDRESSING, ILEN_AUTO, 0); return -EFAULT; } addr += TARGET_PAGE_SIZE; @@ -478,6 +482,9 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages, * * Copy from/to guest memory using logical addresses. Note that we inject a * program interrupt in case there is an error while accessing the memory. + * + * This function will always return (also for TCG), make sure to call + * s390_cpu_virt_mem_handle_exc() to properly exit the CPU loop. */ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, int len, bool is_write) @@ -514,6 +521,16 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, return ret; } +void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra) +{ + /* KVM will handle the interrupt automatically, TCG has to exit the TB */ +#ifdef CONFIG_TCG + if (tcg_enabled()) { + cpu_loop_exit_restore(CPU(cpu), ra); + } +#endif +} + /** * Translate a real address into a physical (absolute) address. * @param raddr the real address diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 85d0a6c3af..eede2ed157 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -240,12 +240,6 @@ static void update_cc_op(DisasContext *s) } } -static void potential_page_fault(DisasContext *s) -{ - update_psw_addr(s); - update_cc_op(s); -} - static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) { return (uint64_t)cpu_lduw_code(env, pc); @@ -1370,6 +1364,27 @@ static ExitStatus op_addc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_asi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_STFLE_45)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic addition in memory. */ + tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_add_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_STFLE_45)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_aeb(DisasContext *s, DisasOps *o) { gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); @@ -1412,6 +1427,27 @@ static ExitStatus op_andi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ni(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_and_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_and_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_bas(DisasContext *s, DisasOps *o) { tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); @@ -2124,9 +2160,6 @@ static ExitStatus op_diag(DisasContext *s, DisasOps *o) TCGv_i32 func_code = tcg_const_i32(get_field(s->fields, i2)); check_privileged(s); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_diag(cpu_env, r1, r3, func_code); tcg_temp_free_i32(func_code); @@ -2942,7 +2975,8 @@ static ExitStatus op_lpd(DisasContext *s, DisasOps *o) /* In a parallel context, stop the world and single step. */ if (tb_cflags(s->tb) & CF_PARALLEL) { - potential_page_fault(s); + update_psw_addr(s); + update_cc_op(s); gen_exception(EXCP_ATOMIC); return EXIT_NORETURN; } @@ -3365,6 +3399,27 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_oi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_or_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_or_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_pack(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); @@ -3704,7 +3759,6 @@ static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) static ExitStatus op_servc(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); set_cc_static(s); return NO_EXIT; @@ -3863,6 +3917,36 @@ static ExitStatus op_spm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ectg(DisasContext *s, DisasOps *o) +{ + int b1 = get_field(s->fields, b1); + int d1 = get_field(s->fields, d1); + int b2 = get_field(s->fields, b2); + int d2 = get_field(s->fields, d2); + int r3 = get_field(s->fields, r3); + TCGv_i64 tmp = tcg_temp_new_i64(); + + /* fetch all operands first */ + o->in1 = tcg_temp_new_i64(); + tcg_gen_addi_i64(o->in1, regs[b1], d1); + o->in2 = tcg_temp_new_i64(); + tcg_gen_addi_i64(o->in2, regs[b2], d2); + o->addr1 = get_address(s, 0, r3, 0); + + /* load the third operand into r3 before modifying anything */ + tcg_gen_qemu_ld64(regs[r3], o->addr1, get_mem_index(s)); + + /* subtract CPU timer from first operand and store in GR0 */ + gen_helper_stpt(tmp, cpu_env); + tcg_gen_sub_i64(regs[0], o->in1, tmp); + + /* store second operand in GR1 */ + tcg_gen_mov_i64(regs[1], o->in2); + + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_spka(DisasContext *s, DisasOps *o) { @@ -3906,7 +3990,10 @@ static ExitStatus op_stcke(DisasContext *s, DisasOps *o) { TCGv_i64 c1 = tcg_temp_new_i64(); TCGv_i64 c2 = tcg_temp_new_i64(); + TCGv_i64 todpr = tcg_temp_new_i64(); gen_helper_stck(c1, cpu_env); + /* 16 bit value store in an uint32_t (only valid bits set) */ + tcg_gen_ld32u_i64(todpr, cpu_env, offsetof(CPUS390XState, todpr)); /* Shift the 64-bit value into its place as a zero-extended 104-bit value. Note that "bit positions 64-103 are always non-zero so that they compare differently to STCK"; we set @@ -3914,11 +4001,13 @@ static ExitStatus op_stcke(DisasContext *s, DisasOps *o) tcg_gen_shli_i64(c2, c1, 56); tcg_gen_shri_i64(c1, c1, 8); tcg_gen_ori_i64(c2, c2, 0x10000); + tcg_gen_or_i64(c2, c2, todpr); tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s)); tcg_gen_addi_i64(o->in2, o->in2, 8); tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s)); tcg_temp_free_i64(c1); tcg_temp_free_i64(c2); + tcg_temp_free_i64(todpr); /* ??? We don't implement clock states. */ gen_op_movi_cc(s, 0); return NO_EXIT; @@ -3931,6 +4020,13 @@ static ExitStatus op_sckc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sckpf(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sckpf(cpu_env, regs[0]); + return NO_EXIT; +} + static ExitStatus op_stckc(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3992,7 +4088,6 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) static ExitStatus op_stsi(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); set_cc_static(s); return NO_EXIT; @@ -4008,7 +4103,6 @@ static ExitStatus op_spx(DisasContext *s, DisasOps *o) static ExitStatus op_xsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_xsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4017,7 +4111,6 @@ static ExitStatus op_xsch(DisasContext *s, DisasOps *o) static ExitStatus op_csch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_csch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4026,7 +4119,6 @@ static ExitStatus op_csch(DisasContext *s, DisasOps *o) static ExitStatus op_hsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_hsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4035,7 +4127,6 @@ static ExitStatus op_hsch(DisasContext *s, DisasOps *o) static ExitStatus op_msch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_msch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4044,7 +4135,6 @@ static ExitStatus op_msch(DisasContext *s, DisasOps *o) static ExitStatus op_rchp(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_rchp(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4053,16 +4143,43 @@ static ExitStatus op_rchp(DisasContext *s, DisasOps *o) static ExitStatus op_rsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_rsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; } +static ExitStatus op_sal(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sal(cpu_env, regs[1]); + return NO_EXIT; +} + +static ExitStatus op_schm(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_schm(cpu_env, regs[1], regs[2], o->in2); + return NO_EXIT; +} + +static ExitStatus op_siga(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* From KVM code: Not provided, set CC = 3 for subchannel not operational */ + gen_op_movi_cc(s, 3); + return NO_EXIT; +} + +static ExitStatus op_stcps(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* The instruction is suppressed if not provided. */ + return NO_EXIT; +} + static ExitStatus op_ssch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_ssch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4071,16 +4188,22 @@ static ExitStatus op_ssch(DisasContext *s, DisasOps *o) static ExitStatus op_stsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_stsch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; } +static ExitStatus op_stcrw(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stcrw(cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_tsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_tsch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4089,7 +4212,6 @@ static ExitStatus op_tsch(DisasContext *s, DisasOps *o) static ExitStatus op_chsc(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_chsc(cpu_env, o->in2); set_cc_static(s); return NO_EXIT; @@ -4622,6 +4744,27 @@ static ExitStatus op_xori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_xi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_xor_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_xor_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_zero(DisasContext *s, DisasOps *o) { o->out = tcg_const_i64(0); @@ -5566,6 +5709,7 @@ enum DisasInsnEnum { #define FAC_MSA3 S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */ #define FAC_MSA4 S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */ #define FAC_MSA5 S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */ +#define FAC_ECT S390_FEAT_EXTRACT_CPU_TIME static const DisasInsn insn_info[] = { #include "insn-data.def" @@ -5851,9 +5995,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) tcg_gen_movi_i64(psw_addr, s->next_pc); } - /* Save off cc. */ - update_cc_op(s); - /* Call the helper to check for a possible PER exception. */ gen_helper_per_check_exception(cpu_env); } diff --git a/tests/test-hmp.c b/tests/test-hmp.c index 5677fbf775..5b7e447b6a 100644 --- a/tests/test-hmp.c +++ b/tests/test-hmp.c @@ -78,10 +78,13 @@ static void test_commands(void) int i; for (i = 0; hmp_cmds[i] != NULL; i++) { + response = hmp("%s", hmp_cmds[i]); if (verbose) { - fprintf(stderr, "\t%s\n", hmp_cmds[i]); + fprintf(stderr, + "\texecute HMP command: %s\n" + "\tresult : %s\n", + hmp_cmds[i], response); } - response = hmp("%s", hmp_cmds[i]); g_free(response); } diff --git a/ui/input-keymap.c b/ui/input-keymap.c index 3a19a169f5..663986a17b 100644 --- a/ui/input-keymap.c +++ b/ui/input-keymap.c @@ -8,6 +8,7 @@ #include "ui/input-keymap-linux-to-qcode.c" #include "ui/input-keymap-qcode-to-qnum.c" #include "ui/input-keymap-qnum-to-qcode.c" +#include "ui/input-keymap-qcode-to-linux.c" int qemu_input_linux_to_qcode(unsigned int lnx) { diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index 3ec029a9ea..2fd8cbcc6f 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -35,6 +35,10 @@ size_t qemu_fd_getpagesize(int fd) return fs.f_bsize; } } +#ifdef __sparc__ + /* SPARC Linux needs greater alignment than the pagesize */ + return QEMU_VMALLOC_ALIGN; +#endif #endif return getpagesize(); @@ -60,6 +64,10 @@ size_t qemu_mempath_getpagesize(const char *mem_path) /* It's hugepage, return the huge page size */ return fs.f_bsize; } +#ifdef __sparc__ + /* SPARC Linux needs greater alignment than the pagesize */ + return QEMU_VMALLOC_ALIGN; +#endif #endif return getpagesize(); @@ -1479,28 +1479,6 @@ done: return 0; } -static int usb_device_del(const char *devname) -{ - int bus_num, addr; - const char *p; - - if (strstart(devname, "host:", &p)) { - return -1; - } - - if (!machine_usb(current_machine)) { - return -1; - } - - p = strchr(devname, '.'); - if (!p) - return -1; - bus_num = strtoul(devname, NULL, 0); - addr = strtoul(p + 1, NULL, 0); - - return usb_device_delete_addr(bus_num, addr); -} - static int usb_parse(const char *cmdline) { int r; @@ -1511,28 +1489,6 @@ static int usb_parse(const char *cmdline) return r; } -void hmp_usb_add(Monitor *mon, const QDict *qdict) -{ - const char *devname = qdict_get_str(qdict, "devname"); - - error_report("usb_add is deprecated, please use device_add instead"); - - if (usb_device_add(devname) < 0) { - error_report("could not add USB device '%s'", devname); - } -} - -void hmp_usb_del(Monitor *mon, const QDict *qdict) -{ - const char *devname = qdict_get_str(qdict, "devname"); - - error_report("usb_del is deprecated, please use device_del instead"); - - if (usb_device_del(devname) < 0) { - error_report("could not delete USB device '%s'", devname); - } -} - /***********************************************************/ /* machine registration */ |