diff options
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | block/iscsi.c | 319 | ||||
-rwxr-xr-x | configure | 4 | ||||
-rw-r--r-- | hw/char/escc.c | 233 | ||||
-rw-r--r-- | hw/input/ps2.c | 166 | ||||
-rw-r--r-- | hw/scsi/megasas.c | 81 | ||||
-rw-r--r-- | hw/scsi/mfi.h | 9 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 16 | ||||
-rw-r--r-- | hw/scsi/scsi-generic.c | 8 | ||||
-rw-r--r-- | include/exec/exec-all.h | 9 | ||||
-rw-r--r-- | include/ui/input.h | 5 | ||||
-rw-r--r-- | tcg/s390/tcg-target.c | 752 | ||||
-rw-r--r-- | tcg/s390/tcg-target.h | 2 | ||||
-rw-r--r-- | trace-events | 10 | ||||
-rw-r--r-- | ui/Makefile.objs | 3 | ||||
-rw-r--r-- | ui/input-keymap.c | 191 | ||||
-rw-r--r-- | ui/input-legacy.c | 226 | ||||
-rw-r--r-- | ui/input.c | 7 |
18 files changed, 1321 insertions, 726 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 97c9fa1f7f..1de05f0525 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -659,6 +659,12 @@ S: Supported F: hw/block/nvme* F: tests/nvme-test.c +megasas +M: Hannes Reinecke <hare@suse.de> +S: Supported +F: hw/scsi/megasas.c +F: hw/scsi/mfi.h + Xilinx EDK M: Peter Crosthwaite <peter.crosthwaite@xilinx.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com> diff --git a/block/iscsi.c b/block/iscsi.c index 52355b8bce..d649424e5c 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -30,6 +30,8 @@ #include "qemu-common.h" #include "qemu/config-file.h" #include "qemu/error-report.h" +#include "qemu/bitops.h" +#include "qemu/bitmap.h" #include "block/block_int.h" #include "trace.h" #include "block/scsi.h" @@ -59,6 +61,8 @@ typedef struct IscsiLun { struct scsi_inquiry_logical_block_provisioning lbp; struct scsi_inquiry_block_limits bl; unsigned char *zeroblock; + unsigned long *allocationmap; + int cluster_sectors; } IscsiLun; typedef struct IscsiTask { @@ -92,6 +96,15 @@ typedef struct IscsiAIOCB { #define MAX_NOP_FAILURES 3 #define ISCSI_CMD_RETRIES 5 +/* this threshhold is a trade-off knob to choose between + * the potential additional overhead of an extra GET_LBA_STATUS request + * vs. unnecessarily reading a lot of zero sectors over the wire. + * If a read request is greater or equal than ISCSI_CHECKALLOC_THRES + * sectors we check the allocation status of the area covered by the + * request first if the allocationmap indicates that the area might be + * unallocated. */ +#define ISCSI_CHECKALLOC_THRES 64 + static void iscsi_bh_cb(void *p) { @@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors, return 1; } +static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num, + int nb_sectors) +{ + if (iscsilun->allocationmap == NULL) { + return; + } + bitmap_set(iscsilun->allocationmap, + sector_num / iscsilun->cluster_sectors, + DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors)); +} + +static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num, + int nb_sectors) +{ + int64_t cluster_num, nb_clusters; + if (iscsilun->allocationmap == NULL) { + return; + } + cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors); + nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors + - cluster_num; + if (nb_clusters > 0) { + bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters); + } +} + static int coroutine_fn iscsi_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov) @@ -336,9 +375,127 @@ retry: return -EIO; } + iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors); + return 0; } + +static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun, + int64_t sector_num, int nb_sectors) +{ + unsigned long size; + if (iscsilun->allocationmap == NULL) { + return true; + } + size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors); + return !(find_next_bit(iscsilun->allocationmap, size, + sector_num / iscsilun->cluster_sectors) == size); +} + + +#if defined(LIBISCSI_FEATURE_IOVECTOR) + +static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, int *pnum) +{ + IscsiLun *iscsilun = bs->opaque; + struct scsi_get_lba_status *lbas = NULL; + struct scsi_lba_status_descriptor *lbasd = NULL; + struct IscsiTask iTask; + int64_t ret; + + iscsi_co_init_iscsitask(iscsilun, &iTask); + + if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { + ret = -EINVAL; + goto out; + } + + /* default to all sectors allocated */ + ret = BDRV_BLOCK_DATA; + ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID; + *pnum = nb_sectors; + + /* LUN does not support logical block provisioning */ + if (iscsilun->lbpme == 0) { + goto out; + } + +retry: + if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun, + sector_qemu2lun(sector_num, iscsilun), + 8 + 16, iscsi_co_generic_cb, + &iTask) == NULL) { + ret = -ENOMEM; + goto out; + } + + while (!iTask.complete) { + iscsi_set_events(iscsilun); + qemu_coroutine_yield(); + } + + if (iTask.do_retry) { + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + iTask.task = NULL; + } + iTask.complete = 0; + goto retry; + } + + if (iTask.status != SCSI_STATUS_GOOD) { + /* in case the get_lba_status_callout fails (i.e. + * because the device is busy or the cmd is not + * supported) we pretend all blocks are allocated + * for backwards compatibility */ + goto out; + } + + lbas = scsi_datain_unmarshall(iTask.task); + if (lbas == NULL) { + ret = -EIO; + goto out; + } + + lbasd = &lbas->descriptors[0]; + + if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) { + ret = -EIO; + goto out; + } + + *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun); + + if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED || + lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) { + ret &= ~BDRV_BLOCK_DATA; + if (iscsilun->lbprz) { + ret |= BDRV_BLOCK_ZERO; + } + } + + if (ret & BDRV_BLOCK_ZERO) { + iscsi_allocationmap_clear(iscsilun, sector_num, *pnum); + } else { + iscsi_allocationmap_set(iscsilun, sector_num, *pnum); + } + + if (*pnum > nb_sectors) { + *pnum = nb_sectors; + } +out: + if (iTask.task != NULL) { + scsi_free_scsi_task(iTask.task); + } + return ret; +} + +#endif /* LIBISCSI_FEATURE_IOVECTOR */ + + static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *iov) @@ -355,6 +512,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, return -EINVAL; } +#if defined(LIBISCSI_FEATURE_IOVECTOR) + if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES && + !iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) { + int64_t ret; + int pnum; + ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum); + if (ret < 0) { + return ret; + } + if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) { + qemu_iovec_memset(iov, 0, 0x00, iov->size); + return 0; + } + } +#endif + lba = sector_qemu2lun(sector_num, iscsilun); num_sectors = sector_qemu2lun(nb_sectors, iscsilun); @@ -643,101 +816,6 @@ iscsi_getlength(BlockDriverState *bs) return len; } -#if defined(LIBISCSI_FEATURE_IOVECTOR) - -static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, - int64_t sector_num, - int nb_sectors, int *pnum) -{ - IscsiLun *iscsilun = bs->opaque; - struct scsi_get_lba_status *lbas = NULL; - struct scsi_lba_status_descriptor *lbasd = NULL; - struct IscsiTask iTask; - int64_t ret; - - iscsi_co_init_iscsitask(iscsilun, &iTask); - - if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { - ret = -EINVAL; - goto out; - } - - /* default to all sectors allocated */ - ret = BDRV_BLOCK_DATA; - ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID; - *pnum = nb_sectors; - - /* LUN does not support logical block provisioning */ - if (iscsilun->lbpme == 0) { - goto out; - } - -retry: - if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun, - sector_qemu2lun(sector_num, iscsilun), - 8 + 16, iscsi_co_generic_cb, - &iTask) == NULL) { - ret = -ENOMEM; - goto out; - } - - while (!iTask.complete) { - iscsi_set_events(iscsilun); - qemu_coroutine_yield(); - } - - if (iTask.do_retry) { - if (iTask.task != NULL) { - scsi_free_scsi_task(iTask.task); - iTask.task = NULL; - } - iTask.complete = 0; - goto retry; - } - - if (iTask.status != SCSI_STATUS_GOOD) { - /* in case the get_lba_status_callout fails (i.e. - * because the device is busy or the cmd is not - * supported) we pretend all blocks are allocated - * for backwards compatibility */ - goto out; - } - - lbas = scsi_datain_unmarshall(iTask.task); - if (lbas == NULL) { - ret = -EIO; - goto out; - } - - lbasd = &lbas->descriptors[0]; - - if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) { - ret = -EIO; - goto out; - } - - *pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun); - if (*pnum > nb_sectors) { - *pnum = nb_sectors; - } - - if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED || - lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) { - ret &= ~BDRV_BLOCK_DATA; - if (iscsilun->lbprz) { - ret |= BDRV_BLOCK_ZERO; - } - } - -out: - if (iTask.task != NULL) { - scsi_free_scsi_task(iTask.task); - } - return ret; -} - -#endif /* LIBISCSI_FEATURE_IOVECTOR */ - static int coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors) @@ -791,6 +869,8 @@ retry: return -EIO; } + iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors); + return 0; } @@ -809,13 +889,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num, return -EINVAL; } - if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { - /* WRITE SAME without UNMAP is not supported by the target */ - return -ENOTSUP; + if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) { + /* WRITE SAME with UNMAP is not supported by the target, + * fall back and try WRITE SAME without UNMAP */ + flags &= ~BDRV_REQ_MAY_UNMAP; } - if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) { - /* WRITE SAME with UNMAP is not supported by the target */ + if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) { + /* WRITE SAME without UNMAP is not supported by the target */ return -ENOTSUP; } @@ -864,6 +945,12 @@ retry: return -EIO; } + if (flags & BDRV_REQ_MAY_UNMAP) { + iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors); + } else { + iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors); + } + return 0; } @@ -1295,6 +1382,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags, timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL); #endif + /* Guess the internal cluster (page) size of the iscsi target by the means + * of opt_unmap_gran. Transfer the unmap granularity only if it has a + * reasonable size */ + if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 && + iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) { + iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran * + iscsilun->block_size) >> BDRV_SECTOR_BITS; +#if defined(LIBISCSI_FEATURE_IOVECTOR) + if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) { + iscsilun->allocationmap = + bitmap_new(DIV_ROUND_UP(bs->total_sectors, + iscsilun->cluster_sectors)); + } +#endif + } + out: qemu_opts_del(opts); if (initiator_name != NULL) { @@ -1328,6 +1431,7 @@ static void iscsi_close(BlockDriverState *bs) qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL); iscsi_destroy_context(iscsi); g_free(iscsilun->zeroblock); + g_free(iscsilun->allocationmap); memset(iscsilun, 0, sizeof(IscsiLun)); } @@ -1388,6 +1492,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset) return -EINVAL; } + if (iscsilun->allocationmap != NULL) { + g_free(iscsilun->allocationmap); + iscsilun->allocationmap = + bitmap_new(DIV_ROUND_UP(bs->total_sectors, + iscsilun->cluster_sectors)); + } + return 0; } @@ -1450,13 +1561,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) IscsiLun *iscsilun = bs->opaque; bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz; bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws; - /* Guess the internal cluster (page) size of the iscsi target by the means - * of opt_unmap_gran. Transfer the unmap granularity only if it has a - * reasonable size for bdi->cluster_size */ - if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 && - iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) { - bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size; - } + bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE; return 0; } @@ -1137,11 +1137,11 @@ case "$cpu" in CPU_CFLAGS="-m64 -mcpu=ultrasparc" ;; s390) - CPU_CFLAGS="-m31 -march=z990" + CPU_CFLAGS="-m31" LDFLAGS="-m31 $LDFLAGS" ;; s390x) - CPU_CFLAGS="-m64 -march=z990" + CPU_CFLAGS="-m64" LDFLAGS="-m64 $LDFLAGS" ;; i386) diff --git a/hw/char/escc.c b/hw/char/escc.c index 6397f6f282..d9a20aa931 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -27,6 +27,7 @@ #include "hw/char/escc.h" #include "sysemu/char.h" #include "ui/console.h" +#include "ui/input.h" #include "trace.h" /* @@ -94,6 +95,7 @@ typedef struct ChannelState { ChnID chn; // this channel, A (base+4) or B (base+0) ChnType type; uint8_t rx, tx; + QemuInputHandlerState *hs; } ChannelState; #define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC) @@ -714,71 +716,181 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB, return &d->mmio; } -static const uint8_t keycodes[128] = { - 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12, - 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112, - 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0, - 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66, - 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, +static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = { + [Q_KEY_CODE_SHIFT] = 99, + [Q_KEY_CODE_SHIFT_R] = 110, + [Q_KEY_CODE_ALT] = 19, + [Q_KEY_CODE_ALT_R] = 13, + [Q_KEY_CODE_ALTGR] = 13, + [Q_KEY_CODE_CTRL] = 76, + [Q_KEY_CODE_CTRL_R] = 76, + [Q_KEY_CODE_ESC] = 29, + [Q_KEY_CODE_1] = 30, + [Q_KEY_CODE_2] = 31, + [Q_KEY_CODE_3] = 32, + [Q_KEY_CODE_4] = 33, + [Q_KEY_CODE_5] = 34, + [Q_KEY_CODE_6] = 35, + [Q_KEY_CODE_7] = 36, + [Q_KEY_CODE_8] = 37, + [Q_KEY_CODE_9] = 38, + [Q_KEY_CODE_0] = 39, + [Q_KEY_CODE_MINUS] = 40, + [Q_KEY_CODE_EQUAL] = 41, + [Q_KEY_CODE_BACKSPACE] = 43, + [Q_KEY_CODE_TAB] = 53, + [Q_KEY_CODE_Q] = 54, + [Q_KEY_CODE_W] = 55, + [Q_KEY_CODE_E] = 56, + [Q_KEY_CODE_R] = 57, + [Q_KEY_CODE_T] = 58, + [Q_KEY_CODE_Y] = 59, + [Q_KEY_CODE_U] = 60, + [Q_KEY_CODE_I] = 61, + [Q_KEY_CODE_O] = 62, + [Q_KEY_CODE_P] = 63, + [Q_KEY_CODE_BRACKET_LEFT] = 64, + [Q_KEY_CODE_BRACKET_RIGHT] = 65, + [Q_KEY_CODE_RET] = 89, + [Q_KEY_CODE_A] = 77, + [Q_KEY_CODE_S] = 78, + [Q_KEY_CODE_D] = 79, + [Q_KEY_CODE_F] = 80, + [Q_KEY_CODE_G] = 81, + [Q_KEY_CODE_H] = 82, + [Q_KEY_CODE_J] = 83, + [Q_KEY_CODE_K] = 84, + [Q_KEY_CODE_L] = 85, + [Q_KEY_CODE_SEMICOLON] = 86, + [Q_KEY_CODE_APOSTROPHE] = 87, + [Q_KEY_CODE_GRAVE_ACCENT] = 42, + [Q_KEY_CODE_BACKSLASH] = 88, + [Q_KEY_CODE_Z] = 100, + [Q_KEY_CODE_X] = 101, + [Q_KEY_CODE_C] = 102, + [Q_KEY_CODE_V] = 103, + [Q_KEY_CODE_B] = 104, + [Q_KEY_CODE_N] = 105, + [Q_KEY_CODE_M] = 106, + [Q_KEY_CODE_COMMA] = 107, + [Q_KEY_CODE_DOT] = 108, + [Q_KEY_CODE_SLASH] = 109, + [Q_KEY_CODE_ASTERISK] = 47, + [Q_KEY_CODE_SPC] = 121, + [Q_KEY_CODE_CAPS_LOCK] = 119, + [Q_KEY_CODE_F1] = 5, + [Q_KEY_CODE_F2] = 6, + [Q_KEY_CODE_F3] = 8, + [Q_KEY_CODE_F4] = 10, + [Q_KEY_CODE_F5] = 12, + [Q_KEY_CODE_F6] = 14, + [Q_KEY_CODE_F7] = 16, + [Q_KEY_CODE_F8] = 17, + [Q_KEY_CODE_F9] = 18, + [Q_KEY_CODE_F10] = 7, + [Q_KEY_CODE_NUM_LOCK] = 98, + [Q_KEY_CODE_SCROLL_LOCK] = 23, + [Q_KEY_CODE_KP_DIVIDE] = 46, + [Q_KEY_CODE_KP_MULTIPLY] = 47, + [Q_KEY_CODE_KP_SUBTRACT] = 71, + [Q_KEY_CODE_KP_ADD] = 125, + [Q_KEY_CODE_KP_ENTER] = 90, + [Q_KEY_CODE_KP_DECIMAL] = 50, + [Q_KEY_CODE_KP_0] = 94, + [Q_KEY_CODE_KP_1] = 112, + [Q_KEY_CODE_KP_2] = 113, + [Q_KEY_CODE_KP_3] = 114, + [Q_KEY_CODE_KP_4] = 91, + [Q_KEY_CODE_KP_5] = 92, + [Q_KEY_CODE_KP_6] = 93, + [Q_KEY_CODE_KP_7] = 68, + [Q_KEY_CODE_KP_8] = 69, + [Q_KEY_CODE_KP_9] = 70, + [Q_KEY_CODE_LESS] = 124, + [Q_KEY_CODE_F11] = 9, + [Q_KEY_CODE_F12] = 11, + [Q_KEY_CODE_HOME] = 52, + [Q_KEY_CODE_PGUP] = 96, + [Q_KEY_CODE_PGDN] = 123, + [Q_KEY_CODE_END] = 74, + [Q_KEY_CODE_LEFT] = 24, + [Q_KEY_CODE_UP] = 20, + [Q_KEY_CODE_DOWN] = 27, + [Q_KEY_CODE_RIGHT] = 28, + [Q_KEY_CODE_INSERT] = 44, + [Q_KEY_CODE_DELETE] = 66, + [Q_KEY_CODE_STOP] = 1, + [Q_KEY_CODE_AGAIN] = 3, + [Q_KEY_CODE_PROPS] = 25, + [Q_KEY_CODE_UNDO] = 26, + [Q_KEY_CODE_FRONT] = 49, + [Q_KEY_CODE_COPY] = 51, + [Q_KEY_CODE_OPEN] = 72, + [Q_KEY_CODE_PASTE] = 73, + [Q_KEY_CODE_FIND] = 95, + [Q_KEY_CODE_CUT] = 97, + [Q_KEY_CODE_LF] = 111, + [Q_KEY_CODE_HELP] = 118, + [Q_KEY_CODE_META_L] = 120, + [Q_KEY_CODE_META_R] = 122, + [Q_KEY_CODE_COMPOSE] = 67, + [Q_KEY_CODE_PRINT] = 22, + [Q_KEY_CODE_SYSRQ] = 21, }; -static const uint8_t e0_keycodes[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112, - 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0, -}; - -static void sunkbd_event(void *opaque, int ch) +static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - ChannelState *s = opaque; - int release = ch & 0x80; - - trace_escc_sunkbd_event_in(ch); - switch (ch) { - case 58: // Caps lock press - s->caps_lock_mode ^= 1; - if (s->caps_lock_mode == 2) - return; // Drop second press - break; - case 69: // Num lock press - s->num_lock_mode ^= 1; - if (s->num_lock_mode == 2) - return; // Drop second press - break; - case 186: // Caps lock release - s->caps_lock_mode ^= 2; - if (s->caps_lock_mode == 3) - return; // Drop first release - break; - case 197: // Num lock release - s->num_lock_mode ^= 2; - if (s->num_lock_mode == 3) - return; // Drop first release - break; - case 0xe0: - s->e0_mode = 1; - return; - default: - break; + ChannelState *s = (ChannelState *)dev; + int qcode, keycode; + + assert(evt->kind == INPUT_EVENT_KIND_KEY); + qcode = qemu_input_key_value_to_qcode(evt->key->key); + trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode], + evt->key->down); + + if (qcode == Q_KEY_CODE_CAPS_LOCK) { + if (evt->key->down) { + s->caps_lock_mode ^= 1; + if (s->caps_lock_mode == 2) { + return; /* Drop second press */ + } + } else { + s->caps_lock_mode ^= 2; + if (s->caps_lock_mode == 3) { + return; /* Drop first release */ + } + } } - if (s->e0_mode) { - s->e0_mode = 0; - ch = e0_keycodes[ch & 0x7f]; - } else { - ch = keycodes[ch & 0x7f]; + + if (qcode == Q_KEY_CODE_NUM_LOCK) { + if (evt->key->down) { + s->num_lock_mode ^= 1; + if (s->num_lock_mode == 2) { + return; /* Drop second press */ + } + } else { + s->num_lock_mode ^= 2; + if (s->num_lock_mode == 3) { + return; /* Drop first release */ + } + } + } + + keycode = qcode_to_keycode[qcode]; + if (!evt->key->down) { + keycode |= 0x80; } - trace_escc_sunkbd_event_out(ch); - put_queue(s, ch | release); + trace_escc_sunkbd_event_out(keycode); + put_queue(s, keycode); } +static QemuInputHandler sunkbd_handler = { + .name = "sun keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = sunkbd_handle_event, +}; + static void handle_kbd_command(ChannelState *s, int val) { trace_escc_kbd_command(val); @@ -800,7 +912,7 @@ static void handle_kbd_command(ChannelState *s, int val) case 0xf: clear_queue(s); put_queue(s, 0xfe); - put_queue(s, 0); // XXX, layout? + put_queue(s, 0x21); /* en-us layout */ break; default: break; @@ -898,7 +1010,8 @@ static int escc_init1(SysBusDevice *dev) "QEMU Sun Mouse"); } if (s->chn[1].type == kbd) { - qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); + s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]), + &sunkbd_handler); } return 0; diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 34120796b1..22b77dfe5c 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -24,6 +24,7 @@ #include "hw/hw.h" #include "hw/input/ps2.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" /* debug PC keyboard */ @@ -71,10 +72,12 @@ #define MOUSE_STATUS_ENABLED 0x20 #define MOUSE_STATUS_SCALE21 0x10 -#define PS2_QUEUE_SIZE 256 +#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */ typedef struct { - uint8_t data[PS2_QUEUE_SIZE]; + /* Keep the data array 256 bytes long, which compatibility + with older qemu versions. */ + uint8_t data[256]; int rptr, wptr, count; } PS2Queue; @@ -137,7 +140,7 @@ void ps2_queue(void *opaque, int b) PS2State *s = (PS2State *)opaque; PS2Queue *q = &s->queue; - if (q->count >= PS2_QUEUE_SIZE) + if (q->count >= PS2_QUEUE_SIZE - 1) return; q->data[q->wptr] = b; if (++q->wptr == PS2_QUEUE_SIZE) @@ -170,6 +173,21 @@ static void ps2_put_keycode(void *opaque, int keycode) ps2_queue(&s->common, keycode); } +static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + PS2KbdState *s = (PS2KbdState *)dev; + int scancodes[3], i, count; + + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + count = qemu_input_key_value_to_scancode(evt->key->key, + evt->key->down, + scancodes); + for (i = 0; i < count; i++) { + ps2_put_keycode(s, scancodes[i]); + } +} + uint32_t ps2_read_data(void *opaque) { PS2State *s = (PS2State *)opaque; @@ -352,31 +370,57 @@ static void ps2_mouse_send_packet(PS2MouseState *s) s->mouse_dz -= dz1; } -static void ps2_mouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) +static void ps2_mouse_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - PS2MouseState *s = opaque; + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + }; + PS2MouseState *s = (PS2MouseState *)dev; /* check if deltas are recorded when disabled */ if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) return; - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && - s->mouse_buttons == buttons_state) - return; - s->mouse_buttons = buttons_state; + switch (evt->kind) { + case INPUT_EVENT_KIND_REL: + if (evt->rel->axis == INPUT_AXIS_X) { + s->mouse_dx += evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + s->mouse_dy -= evt->rel->value; + } + break; - if (buttons_state) { - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + s->mouse_buttons |= bmap[evt->btn->button]; + if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + s->mouse_dz--; + } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + s->mouse_dz++; + } + } else { + s->mouse_buttons &= ~bmap[evt->btn->button]; + } + break; + + default: + /* keep gcc happy */ + break; } +} - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { - for(;;) { +static void ps2_mouse_sync(DeviceState *dev) +{ + PS2MouseState *s = (PS2MouseState *)dev; + + if (s->mouse_buttons) { + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + } + if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) { + while (s->common.queue.count < PS2_QUEUE_SIZE - 4) { /* if not remote, send event. Multiple events are sent if too big deltas */ ps2_mouse_send_packet(s); @@ -388,7 +432,9 @@ static void ps2_mouse_event(void *opaque, void ps2_mouse_fake_event(void *opaque) { - ps2_mouse_event(opaque, 1, 0, 0, 0); + PS2MouseState *s = opaque; + s->mouse_dx++; + ps2_mouse_sync(opaque); } void ps2_write_mouse(void *opaque, int val) @@ -528,6 +574,34 @@ static void ps2_common_reset(PS2State *s) s->update_irq(s->update_arg, 0); } +static void ps2_common_post_load(PS2State *s) +{ + PS2Queue *q = &s->queue; + int size; + int i; + int tmp_data[PS2_QUEUE_SIZE]; + + /* set the useful data buffer queue size, < PS2_QUEUE_SIZE */ + size = q->count > PS2_QUEUE_SIZE ? 0 : q->count; + + /* move the queue elements to the start of data array */ + if (size > 0) { + for (i = 0; i < size; i++) { + /* move the queue elements to the temporary buffer */ + tmp_data[i] = q->data[q->rptr]; + if (++q->rptr == 256) { + q->rptr = 0; + } + } + memcpy(q->data, tmp_data, size); + } + /* reset rptr/wptr/count */ + q->rptr = 0; + q->wptr = size; + q->count = size; + s->update_irq(s->update_arg, q->count != 0); +} + static void ps2_kbd_reset(void *opaque) { PS2KbdState *s = (PS2KbdState *) opaque; @@ -600,18 +674,31 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = { static int ps2_kbd_post_load(void* opaque, int version_id) { PS2KbdState *s = (PS2KbdState*)opaque; + PS2State *ps2 = &s->common; if (version_id == 2) s->scancode_set=2; + + ps2_common_post_load(ps2); + return 0; } +static void ps2_kbd_pre_save(void *opaque) +{ + PS2KbdState *s = (PS2KbdState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); +} + static const VMStateDescription vmstate_ps2_keyboard = { .name = "ps2kbd", .version_id = 3, .minimum_version_id = 2, .minimum_version_id_old = 2, .post_load = ps2_kbd_post_load, + .pre_save = ps2_kbd_pre_save, .fields = (VMStateField []) { VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State), VMSTATE_INT32(scan_enabled, PS2KbdState), @@ -629,11 +716,31 @@ static const VMStateDescription vmstate_ps2_keyboard = { } }; +static int ps2_mouse_post_load(void *opaque, int version_id) +{ + PS2MouseState *s = (PS2MouseState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); + + return 0; +} + +static void ps2_mouse_pre_save(void *opaque) +{ + PS2MouseState *s = (PS2MouseState *)opaque; + PS2State *ps2 = &s->common; + + ps2_common_post_load(ps2); +} + static const VMStateDescription vmstate_ps2_mouse = { .name = "ps2mouse", .version_id = 2, .minimum_version_id = 2, .minimum_version_id_old = 2, + .post_load = ps2_mouse_post_load, + .pre_save = ps2_mouse_pre_save, .fields = (VMStateField []) { VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State), VMSTATE_UINT8(mouse_status, PS2MouseState), @@ -650,6 +757,12 @@ static const VMStateDescription vmstate_ps2_mouse = { } }; +static QemuInputHandler ps2_keyboard_handler = { + .name = "QEMU PS/2 Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = ps2_keyboard_event, +}; + void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) { PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState)); @@ -658,11 +771,19 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_arg = update_arg; s->scancode_set = 2; vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s); - qemu_add_kbd_event_handler(ps2_put_keycode, s); + qemu_input_handler_register((DeviceState *)s, + &ps2_keyboard_handler); qemu_register_reset(ps2_kbd_reset, s); return s; } +static QemuInputHandler ps2_mouse_handler = { + .name = "QEMU PS/2 Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = ps2_mouse_event, + .sync = ps2_mouse_sync, +}; + void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) { PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState)); @@ -670,7 +791,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) s->common.update_irq = update_irq; s->common.update_arg = update_arg; vmstate_register(NULL, 0, &vmstate_ps2_mouse, s); - qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse"); + qemu_input_handler_register((DeviceState *)s, + &ps2_mouse_handler); qemu_register_reset(ps2_mouse_reset, s); return s; } diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index e6e1ffd1bb..baee46f981 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -21,6 +21,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "sysemu/dma.h" +#include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "qemu/iov.h" #include "hw/scsi/scsi.h" @@ -43,9 +44,11 @@ #define MEGASAS_FLAG_USE_JBOD 0 #define MEGASAS_MASK_USE_JBOD (1 << MEGASAS_FLAG_USE_JBOD) -#define MEGASAS_FLAG_USE_MSIX 1 +#define MEGASAS_FLAG_USE_MSI 1 +#define MEGASAS_MASK_USE_MSI (1 << MEGASAS_FLAG_USE_MSI) +#define MEGASAS_FLAG_USE_MSIX 2 #define MEGASAS_MASK_USE_MSIX (1 << MEGASAS_FLAG_USE_MSIX) -#define MEGASAS_FLAG_USE_QUEUE64 2 +#define MEGASAS_FLAG_USE_QUEUE64 3 #define MEGASAS_MASK_USE_QUEUE64 (1 << MEGASAS_FLAG_USE_QUEUE64) static const char *mfi_frame_desc[] = { @@ -132,6 +135,11 @@ static bool megasas_use_queue64(MegasasState *s) return s->flags & MEGASAS_MASK_USE_QUEUE64; } +static bool megasas_use_msi(MegasasState *s) +{ + return s->flags & MEGASAS_MASK_USE_MSI; +} + static bool megasas_use_msix(MegasasState *s) { return s->flags & MEGASAS_MASK_USE_MSIX; @@ -538,6 +546,9 @@ static void megasas_complete_frame(MegasasState *s, uint64_t context) if (msix_enabled(pci_dev)) { trace_megasas_msix_raise(0); msix_notify(pci_dev, 0); + } else if (msi_enabled(pci_dev)) { + trace_megasas_msi_raise(0); + msi_notify(pci_dev, 0); } else { trace_megasas_irq_raise(); pci_irq_assert(pci_dev); @@ -1106,6 +1117,21 @@ static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd) return MFI_STAT_OK; } +static int megasas_dcmd_ld_list_query(MegasasState *s, MegasasCmd *cmd) +{ + uint16_t flags; + + /* mbox0 contains flags */ + flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]); + trace_megasas_dcmd_ld_list_query(cmd->index, flags); + if (flags == MR_LD_QUERY_TYPE_ALL || + flags == MR_LD_QUERY_TYPE_EXPOSED_TO_HOST) { + return megasas_dcmd_ld_get_list(s, cmd); + } + + return MFI_STAT_OK; +} + static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun, MegasasCmd *cmd) { @@ -1409,6 +1435,8 @@ static const struct dcmd_cmd_tbl_t { megasas_dcmd_dummy }, { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST", megasas_dcmd_ld_get_list}, + { MFI_DCMD_LD_LIST_QUERY, "LD_LIST_QUERY", + megasas_dcmd_ld_list_query }, { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO", megasas_dcmd_ld_get_info }, { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP", @@ -1939,12 +1967,20 @@ static void megasas_mmio_write(void *opaque, hwaddr addr, break; case MFI_OMSK: s->intr_mask = val; - if (!megasas_intr_enabled(s) && !msix_enabled(pci_dev)) { + if (!megasas_intr_enabled(s) && + !msi_enabled(pci_dev) && + !msix_enabled(pci_dev)) { trace_megasas_irq_lower(); pci_irq_deassert(pci_dev); } if (megasas_intr_enabled(s)) { - trace_megasas_intr_enabled(); + if (msix_enabled(pci_dev)) { + trace_megasas_msix_enabled(0); + } else if (msi_enabled(pci_dev)) { + trace_megasas_msi_enabled(0); + } else { + trace_megasas_intr_enabled(); + } } else { trace_megasas_intr_disabled(); } @@ -2068,6 +2104,7 @@ static const VMStateDescription vmstate_megasas = { .minimum_version_id_old = 0, .fields = (VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, MegasasState), + VMSTATE_MSIX(parent_obj, MegasasState), VMSTATE_INT32(fw_state, MegasasState), VMSTATE_INT32(intr_mask, MegasasState), @@ -2083,9 +2120,12 @@ static void megasas_scsi_uninit(PCIDevice *d) { MegasasState *s = MEGASAS(d); -#ifdef USE_MSIX - msix_uninit(d, &s->mmio_io); -#endif + if (megasas_use_msix(s)) { + msix_uninit(d, &s->mmio_io, &s->mmio_io); + } + if (megasas_use_msi(s)) { + msi_uninit(d); + } memory_region_destroy(&s->mmio_io); memory_region_destroy(&s->port_io); memory_region_destroy(&s->queue_io); @@ -2124,15 +2164,15 @@ static int megasas_scsi_init(PCIDevice *dev) memory_region_init_io(&s->queue_io, OBJECT(s), &megasas_queue_ops, s, "megasas-queue", 0x40000); -#ifdef USE_MSIX - /* MSI-X support is currently broken */ + if (megasas_use_msi(s) && + msi_init(dev, 0x50, 1, true, false)) { + s->flags &= ~MEGASAS_MASK_USE_MSI; + } if (megasas_use_msix(s) && - msix_init(dev, 15, &s->mmio_io, 0, 0x2000)) { + msix_init(dev, 15, &s->mmio_io, 0, 0x2000, + &s->mmio_io, 0, 0x3800, 0x68)) { s->flags &= ~MEGASAS_MASK_USE_MSIX; } -#else - s->flags &= ~MEGASAS_MASK_USE_MSIX; -#endif bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64; pci_register_bar(dev, 0, bar_type, &s->mmio_io); @@ -2151,7 +2191,7 @@ static int megasas_scsi_init(PCIDevice *dev) s->sas_addr |= PCI_FUNC(dev->devfn); } if (!s->hba_serial) { - s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); + s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL); } if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) { s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE; @@ -2164,7 +2204,6 @@ static int megasas_scsi_init(PCIDevice *dev) s->fw_cmds = MEGASAS_MAX_FRAMES; } trace_megasas_init(s->fw_sge, s->fw_cmds, - megasas_use_msix(s) ? "MSI-X" : "INTx", megasas_is_jbod(s) ? "jbod" : "raid"); s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ? MAX_SCSI_DEVS : MFI_MAX_LD; @@ -2189,6 +2228,13 @@ static int megasas_scsi_init(PCIDevice *dev) return 0; } +static void +megasas_write_config(PCIDevice *pci, uint32_t addr, uint32_t val, int len) +{ + pci_default_write_config(pci, addr, val, len); + msi_write_config(pci, addr, val, len); +} + static Property megasas_properties[] = { DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge, MEGASAS_DEFAULT_SGE), @@ -2196,10 +2242,10 @@ static Property megasas_properties[] = { MEGASAS_DEFAULT_FRAMES), DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial), DEFINE_PROP_UINT64("sas_address", MegasasState, sas_addr, 0), -#ifdef USE_MSIX + DEFINE_PROP_BIT("use_msi", MegasasState, flags, + MEGASAS_FLAG_USE_MSI, false), DEFINE_PROP_BIT("use_msix", MegasasState, flags, MEGASAS_FLAG_USE_MSIX, false), -#endif DEFINE_PROP_BIT("use_jbod", MegasasState, flags, MEGASAS_FLAG_USE_JBOD, false), DEFINE_PROP_END_OF_LIST(), @@ -2222,6 +2268,7 @@ static void megasas_class_init(ObjectClass *oc, void *data) dc->vmsd = &vmstate_megasas; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "LSI MegaRAID SAS 1078"; + pc->config_write = megasas_write_config; } static const TypeInfo megasas_info = { diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h index cd8355badf..a3034f6239 100644 --- a/hw/scsi/mfi.h +++ b/hw/scsi/mfi.h @@ -164,6 +164,7 @@ typedef enum { MFI_DCMD_PD_BLINK = 0x02070100, MFI_DCMD_PD_UNBLINK = 0x02070200, MFI_DCMD_LD_GET_LIST = 0x03010000, + MFI_DCMD_LD_LIST_QUERY = 0x03010100, MFI_DCMD_LD_GET_INFO = 0x03020000, MFI_DCMD_LD_GET_PROP = 0x03030000, MFI_DCMD_LD_SET_PROP = 0x03040000, @@ -411,6 +412,14 @@ typedef enum { MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, /*query for system drives */ } mfi_pd_query_type; +typedef enum { + MR_LD_QUERY_TYPE_ALL = 0, + MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1, + MR_LD_QUERY_TYPE_USED_TGT_IDS = 2, + MR_LD_QUERY_TYPE_CLUSTER_ACCESS = 3, + MR_LD_QUERY_TYPE_CLUSTER_LOCALE = 4, +} mfi_ld_query_type; + /* * Other propertities and definitions */ diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 48a28ae199..4bcef551a6 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2458,21 +2458,27 @@ static int scsi_block_initfn(SCSIDevice *dev) int rc; if (!s->qdev.conf.bs) { - error_report("scsi-block: drive property not set"); + error_report("drive property not set"); return -1; } /* check we are using a driver managing SG_IO (version 3 and after) */ - if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 || - sg_version < 30000) { - error_report("scsi-block: scsi generic interface too old"); + rc = bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version); + if (rc < 0) { + error_report("cannot get SG_IO version number: %s. " + "Is this a SCSI device?", + strerror(-rc)); + return -1; + } + if (sg_version < 30000) { + error_report("scsi generic interface too old"); return -1; } /* get device type from INQUIRY data */ rc = get_device_type(s); if (rc < 0) { - error_report("scsi-block: INQUIRY failed"); + error_report("INQUIRY failed"); return -1; } diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 8d92e0da15..3733d2c36c 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -394,6 +394,7 @@ static void scsi_destroy(SCSIDevice *s) static int scsi_generic_initfn(SCSIDevice *s) { + int rc; int sg_version; struct sg_scsi_id scsiid; @@ -412,8 +413,11 @@ static int scsi_generic_initfn(SCSIDevice *s) } /* check we are using a driver managing SG_IO (version 3 and after */ - if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) { - error_report("scsi generic interface not supported"); + rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version); + if (rc < 0) { + error_report("cannot get SG_IO version number: %s. " + "Is this a SCSI device?", + strerror(-rc)); return -1; } if (sg_version < 30000) { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 444b4d9a1d..8bc2eb663e 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -131,6 +131,7 @@ static inline void tlb_flush(CPUState *cpu, int flush_global) #if defined(__arm__) || defined(_ARCH_PPC) \ || defined(__x86_64__) || defined(__i386__) \ || defined(__sparc__) || defined(__aarch64__) \ + || defined(__s390x__) \ || defined(CONFIG_TCG_INTERPRETER) #define USE_DIRECT_JUMP #endif @@ -232,6 +233,14 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) stl_le_p((void*)jmp_addr, addr - (jmp_addr + 4)); /* no need to flush icache explicitly */ } +#elif defined(__s390x__) +static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) +{ + /* patch the branch destination */ + intptr_t disp = addr - (jmp_addr - 2); + stl_be_p((void*)jmp_addr, disp / 2); + /* no need to flush icache explicitly */ +} #elif defined(__aarch64__) void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr); #define tb_set_jmp_target1 aarch64_tb_set_jmp_target diff --git a/include/ui/input.h b/include/ui/input.h index 4976f3da2c..3d3d487f18 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -27,6 +27,7 @@ struct QemuInputHandler { QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, QemuInputHandler *handler); void qemu_input_handler_activate(QemuInputHandlerState *s); +void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s); void qemu_input_event_send(QemuConsole *src, InputEvent *evt); void qemu_input_event_sync(void); @@ -35,6 +36,10 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down); void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down); void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down); void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down); +int qemu_input_key_value_to_number(const KeyValue *value); +int qemu_input_key_value_to_qcode(const KeyValue *value); +int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, + int *codes); InputEvent *qemu_input_event_new_btn(InputButton btn, bool down); void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down); diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c index ebdd0743cf..07164e544d 100644 --- a/tcg/s390/tcg-target.c +++ b/tcg/s390/tcg-target.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "tcg-be-null.h" +#include "tcg-be-ldst.h" /* We only support generating code for 64-bit mode. */ #if TCG_TARGET_REG_BITS != 64 @@ -42,6 +42,7 @@ #define TCG_CT_CONST_ORI 0x200 #define TCG_CT_CONST_XORI 0x400 #define TCG_CT_CONST_CMPI 0x800 +#define TCG_CT_CONST_ADLI 0x1000 /* Several places within the instruction set 0 means "no register" rather than TCG_REG_R0. */ @@ -227,16 +228,6 @@ typedef enum S390Opcode { RX_STH = 0x40, } S390Opcode; -#define LD_SIGNED 0x04 -#define LD_UINT8 0x00 -#define LD_INT8 (LD_UINT8 | LD_SIGNED) -#define LD_UINT16 0x01 -#define LD_INT16 (LD_UINT16 | LD_SIGNED) -#define LD_UINT32 0x02 -#define LD_INT32 (LD_UINT32 | LD_SIGNED) -#define LD_UINT64 0x03 -#define LD_INT64 (LD_UINT64 | LD_SIGNED) - #ifndef NDEBUG static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", @@ -248,6 +239,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { call-saved registers. Likewise prefer the call-clobbered registers in reverse order to maximize the chance of avoiding the arguments. */ static const int tcg_target_reg_alloc_order[] = { + /* Call saved registers. */ TCG_REG_R13, TCG_REG_R12, TCG_REG_R11, @@ -256,9 +248,11 @@ static const int tcg_target_reg_alloc_order[] = { TCG_REG_R8, TCG_REG_R7, TCG_REG_R6, + /* Call clobbered registers. */ TCG_REG_R14, TCG_REG_R0, TCG_REG_R1, + /* Argument registers, in reverse order of allocation. */ TCG_REG_R5, TCG_REG_R4, TCG_REG_R3, @@ -318,22 +312,29 @@ static const uint8_t tcg_cond_to_ltr_cond[] = { }; #ifdef CONFIG_SOFTMMU -/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, - int mmu_idx) */ -static void * const qemu_ld_helpers[4] = { - helper_ldb_mmu, - helper_ldw_mmu, - helper_ldl_mmu, - helper_ldq_mmu, +static void * const qemu_ld_helpers[16] = { + [MO_UB] = helper_ret_ldub_mmu, + [MO_SB] = helper_ret_ldsb_mmu, + [MO_LEUW] = helper_le_lduw_mmu, + [MO_LESW] = helper_le_ldsw_mmu, + [MO_LEUL] = helper_le_ldul_mmu, + [MO_LESL] = helper_le_ldsl_mmu, + [MO_LEQ] = helper_le_ldq_mmu, + [MO_BEUW] = helper_be_lduw_mmu, + [MO_BESW] = helper_be_ldsw_mmu, + [MO_BEUL] = helper_be_ldul_mmu, + [MO_BESL] = helper_be_ldsl_mmu, + [MO_BEQ] = helper_be_ldq_mmu, }; -/* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, - uintxx_t val, int mmu_idx) */ -static void * const qemu_st_helpers[4] = { - helper_stb_mmu, - helper_stw_mmu, - helper_stl_mmu, - helper_stq_mmu, +static void * const qemu_st_helpers[16] = { + [MO_UB] = helper_ret_stb_mmu, + [MO_LEUW] = helper_le_stw_mmu, + [MO_LEUL] = helper_le_stl_mmu, + [MO_LEQ] = helper_le_stq_mmu, + [MO_BEUW] = helper_be_stw_mmu, + [MO_BEUL] = helper_be_stl_mmu, + [MO_BEQ] = helper_be_stq_mmu, }; #endif @@ -403,6 +404,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_clear(ct->u.regs); tcg_regset_set_reg(ct->u.regs, TCG_REG_R3); break; + case 'A': + ct->ct |= TCG_CT_CONST_ADLI; + break; case 'K': ct->ct |= TCG_CT_CONST_MULI; break; @@ -507,6 +511,20 @@ static int tcg_match_cmpi(TCGType type, tcg_target_long val) } } +/* Immediates to be used with add2/sub2. */ + +static int tcg_match_add2i(TCGType type, tcg_target_long val) +{ + if (facilities & FACILITY_EXT_IMM) { + if (type == TCG_TYPE_I32) { + return 1; + } else if (val >= -0xffffffffll && val <= 0xffffffffll) { + return 1; + } + } + return 0; +} + /* Test if a constant matches the constraint. */ static int tcg_target_const_match(tcg_target_long val, TCGType type, const TCGArgConstraint *arg_ct) @@ -532,6 +550,8 @@ static int tcg_target_const_match(tcg_target_long val, TCGType type, } else { return val == (int16_t)val; } + } else if (ct & TCG_CT_CONST_ADLI) { + return tcg_match_add2i(type, val); } else if (ct & TCG_CT_CONST_ORI) { return tcg_match_ori(type, val); } else if (ct & TCG_CT_CONST_XORI) { @@ -933,6 +953,20 @@ static inline bool risbg_mask(uint64_t c) return c == -lsb; } +static void tgen_andi_risbg(TCGContext *s, TCGReg out, TCGReg in, uint64_t val) +{ + int msb, lsb; + if ((val & 0x8000000000000001ull) == 0x8000000000000001ull) { + /* Achieve wraparound by swapping msb and lsb. */ + msb = 64 - ctz64(~val); + lsb = clz64(~val) - 1; + } else { + msb = clz64(val); + lsb = 63 - ctz64(val); + } + tcg_out_risbg(s, out, in, msb, lsb, 0, 1); +} + static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) { static const S390Opcode ni_insns[4] = { @@ -980,16 +1014,7 @@ static void tgen_andi(TCGContext *s, TCGType type, TCGReg dest, uint64_t val) } } if ((facilities & FACILITY_GEN_INST_EXT) && risbg_mask(val)) { - int msb, lsb; - if ((val & 0x8000000000000001ull) == 0x8000000000000001ull) { - /* Achieve wraparound by swapping msb and lsb. */ - msb = 63 - ctz64(~val); - lsb = clz64(~val) + 1; - } else { - msb = clz64(val); - lsb = 63 - ctz64(val); - } - tcg_out_risbg(s, dest, dest, msb, lsb, 0, 1); + tgen_andi_risbg(s, dest, dest, val); return; } @@ -1110,15 +1135,100 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, return tcg_cond_to_s390_cond[c]; } -static void tgen_setcond(TCGContext *s, TCGType type, TCGCond c, +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg c1, TCGArg c2, int c2const) { - int cc = tgen_cmp(s, type, c, c1, c2, c2const); + int cc; + + switch (cond) { + case TCG_COND_GTU: + case TCG_COND_GT: + do_greater: + /* The result of a compare has CC=2 for GT and CC=3 unused. + ADD LOGICAL WITH CARRY considers (CC & 2) the carry bit. */ + tgen_cmp(s, type, cond, c1, c2, c2const); + tcg_out_movi(s, type, dest, 0); + tcg_out_insn(s, RRE, ALCGR, dest, dest); + return; + + case TCG_COND_GEU: + do_geu: + /* We need "real" carry semantics, so use SUBTRACT LOGICAL + instead of COMPARE LOGICAL. This needs an extra move. */ + tcg_out_mov(s, type, TCG_TMP0, c1); + if (c2const) { + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, SLFI, TCG_TMP0, c2); + } else { + tcg_out_insn(s, RIL, SLGFI, TCG_TMP0, c2); + } + } else { + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, SLR, TCG_TMP0, c2); + } else { + tcg_out_insn(s, RRE, SLGR, TCG_TMP0, c2); + } + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + } + tcg_out_insn(s, RRE, ALCGR, dest, dest); + return; + + case TCG_COND_LEU: + case TCG_COND_LTU: + case TCG_COND_LT: + /* Swap operands so that we can use GEU/GTU/GT. */ + if (c2const) { + tcg_out_movi(s, type, TCG_TMP0, c2); + c2 = c1; + c2const = 0; + c1 = TCG_TMP0; + } else { + TCGReg t = c1; + c1 = c2; + c2 = t; + } + if (cond == TCG_COND_LEU) { + goto do_geu; + } + cond = tcg_swap_cond(cond); + goto do_greater; + + case TCG_COND_NE: + /* X != 0 is X > 0. */ + if (c2const && c2 == 0) { + cond = TCG_COND_GTU; + goto do_greater; + } + break; + + case TCG_COND_EQ: + /* X == 0 is X <= 0 is 0 >= X. */ + if (c2const && c2 == 0) { + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0); + c2 = c1; + c2const = 0; + c1 = TCG_TMP0; + goto do_geu; + } + break; + + default: + break; + } - /* Emit: r1 = 1; if (cc) goto over; r1 = 0; over: */ - tcg_out_movi(s, type, dest, 1); - tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); - tcg_out_movi(s, type, dest, 0); + cc = tgen_cmp(s, type, cond, c1, c2, c2const); + if (facilities & FACILITY_LOAD_ON_COND) { + /* Emit: d = 0, t = 1, d = (cc ? t : d). */ + tcg_out_movi(s, TCG_TYPE_I64, dest, 0); + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 1); + tcg_out_insn(s, RRF, LOCGR, dest, TCG_TMP0, cc); + } else { + /* Emit: d = 1; if (cc) goto over; d = 0; over: */ + tcg_out_movi(s, type, dest, 1); + tcg_out_insn(s, RI, BRC, cc, (4 + 4) >> 1); + tcg_out_movi(s, type, dest, 0); + } } static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, @@ -1280,230 +1390,231 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest) } } -static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data, +static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { -#ifdef TARGET_WORDS_BIGENDIAN - const int bswap = 0; -#else - const int bswap = 1; -#endif switch (opc) { - case LD_UINT8: + case MO_UB: tcg_out_insn(s, RXY, LLGC, data, base, index, disp); break; - case LD_INT8: + case MO_SB: tcg_out_insn(s, RXY, LGB, data, base, index, disp); break; - case LD_UINT16: - if (bswap) { - /* swapped unsigned halfword load with upper bits zeroed */ - tcg_out_insn(s, RXY, LRVH, data, base, index, disp); - tgen_ext16u(s, TCG_TYPE_I64, data, data); - } else { - tcg_out_insn(s, RXY, LLGH, data, base, index, disp); - } + + case MO_UW | MO_BSWAP: + /* swapped unsigned halfword load with upper bits zeroed */ + tcg_out_insn(s, RXY, LRVH, data, base, index, disp); + tgen_ext16u(s, TCG_TYPE_I64, data, data); break; - case LD_INT16: - if (bswap) { - /* swapped sign-extended halfword load */ - tcg_out_insn(s, RXY, LRVH, data, base, index, disp); - tgen_ext16s(s, TCG_TYPE_I64, data, data); - } else { - tcg_out_insn(s, RXY, LGH, data, base, index, disp); - } + case MO_UW: + tcg_out_insn(s, RXY, LLGH, data, base, index, disp); break; - case LD_UINT32: - if (bswap) { - /* swapped unsigned int load with upper bits zeroed */ - tcg_out_insn(s, RXY, LRV, data, base, index, disp); - tgen_ext32u(s, data, data); - } else { - tcg_out_insn(s, RXY, LLGF, data, base, index, disp); - } + + case MO_SW | MO_BSWAP: + /* swapped sign-extended halfword load */ + tcg_out_insn(s, RXY, LRVH, data, base, index, disp); + tgen_ext16s(s, TCG_TYPE_I64, data, data); break; - case LD_INT32: - if (bswap) { - /* swapped sign-extended int load */ - tcg_out_insn(s, RXY, LRV, data, base, index, disp); - tgen_ext32s(s, data, data); - } else { - tcg_out_insn(s, RXY, LGF, data, base, index, disp); - } + case MO_SW: + tcg_out_insn(s, RXY, LGH, data, base, index, disp); break; - case LD_UINT64: - if (bswap) { - tcg_out_insn(s, RXY, LRVG, data, base, index, disp); - } else { - tcg_out_insn(s, RXY, LG, data, base, index, disp); - } + + case MO_UL | MO_BSWAP: + /* swapped unsigned int load with upper bits zeroed */ + tcg_out_insn(s, RXY, LRV, data, base, index, disp); + tgen_ext32u(s, data, data); + break; + case MO_UL: + tcg_out_insn(s, RXY, LLGF, data, base, index, disp); break; + + case MO_SL | MO_BSWAP: + /* swapped sign-extended int load */ + tcg_out_insn(s, RXY, LRV, data, base, index, disp); + tgen_ext32s(s, data, data); + break; + case MO_SL: + tcg_out_insn(s, RXY, LGF, data, base, index, disp); + break; + + case MO_Q | MO_BSWAP: + tcg_out_insn(s, RXY, LRVG, data, base, index, disp); + break; + case MO_Q: + tcg_out_insn(s, RXY, LG, data, base, index, disp); + break; + default: tcg_abort(); } } -static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data, +static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data, TCGReg base, TCGReg index, int disp) { -#ifdef TARGET_WORDS_BIGENDIAN - const int bswap = 0; -#else - const int bswap = 1; -#endif switch (opc) { - case LD_UINT8: + case MO_UB: if (disp >= 0 && disp < 0x1000) { tcg_out_insn(s, RX, STC, data, base, index, disp); } else { tcg_out_insn(s, RXY, STCY, data, base, index, disp); } break; - case LD_UINT16: - if (bswap) { - tcg_out_insn(s, RXY, STRVH, data, base, index, disp); - } else if (disp >= 0 && disp < 0x1000) { + + case MO_UW | MO_BSWAP: + tcg_out_insn(s, RXY, STRVH, data, base, index, disp); + break; + case MO_UW: + if (disp >= 0 && disp < 0x1000) { tcg_out_insn(s, RX, STH, data, base, index, disp); } else { tcg_out_insn(s, RXY, STHY, data, base, index, disp); } break; - case LD_UINT32: - if (bswap) { - tcg_out_insn(s, RXY, STRV, data, base, index, disp); - } else if (disp >= 0 && disp < 0x1000) { + + case MO_UL | MO_BSWAP: + tcg_out_insn(s, RXY, STRV, data, base, index, disp); + break; + case MO_UL: + if (disp >= 0 && disp < 0x1000) { tcg_out_insn(s, RX, ST, data, base, index, disp); } else { tcg_out_insn(s, RXY, STY, data, base, index, disp); } break; - case LD_UINT64: - if (bswap) { - tcg_out_insn(s, RXY, STRVG, data, base, index, disp); - } else { - tcg_out_insn(s, RXY, STG, data, base, index, disp); - } + + case MO_Q | MO_BSWAP: + tcg_out_insn(s, RXY, STRVG, data, base, index, disp); + break; + case MO_Q: + tcg_out_insn(s, RXY, STG, data, base, index, disp); break; + default: tcg_abort(); } } #if defined(CONFIG_SOFTMMU) -static TCGReg tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, - TCGReg addr_reg, int mem_index, int opc, - tcg_insn_unit **label2_ptr_p, int is_store) +/* We're expecting to use a 20-bit signed offset on the tlb memory ops. + Using the offset of the second entry in the last tlb table ensures + that we can index all of the elements of the first entry. */ +QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1]) + > 0x7ffff); + +/* Load and compare a TLB entry, leaving the flags set. Loads the TLB + addend into R2. Returns a register with the santitized guest address. */ +static TCGReg tcg_out_tlb_read(TCGContext* s, TCGReg addr_reg, TCGMemOp opc, + int mem_index, bool is_ld) { - const TCGReg arg0 = tcg_target_call_iarg_regs[0]; - const TCGReg arg1 = tcg_target_call_iarg_regs[1]; - const TCGReg arg2 = tcg_target_call_iarg_regs[2]; - const TCGReg arg3 = tcg_target_call_iarg_regs[3]; - int s_bits = opc & 3; - tcg_insn_unit *label1_ptr; - tcg_target_long ofs; + TCGMemOp s_bits = opc & MO_SIZE; + uint64_t tlb_mask = TARGET_PAGE_MASK | ((1 << s_bits) - 1); + int ofs; - if (TARGET_LONG_BITS == 32) { - tgen_ext32u(s, arg1, addr_reg); + if (facilities & FACILITY_GEN_INST_EXT) { + tcg_out_risbg(s, TCG_REG_R2, addr_reg, + 64 - CPU_TLB_BITS - CPU_TLB_ENTRY_BITS, + 63 - CPU_TLB_ENTRY_BITS, + 64 + CPU_TLB_ENTRY_BITS - TARGET_PAGE_BITS, 1); + tgen_andi_risbg(s, TCG_REG_R3, addr_reg, tlb_mask); } else { - tcg_out_mov(s, TCG_TYPE_I64, arg1, addr_reg); + tcg_out_sh64(s, RSY_SRLG, TCG_REG_R2, addr_reg, TCG_REG_NONE, + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_movi(s, TCG_TYPE_TL, TCG_REG_R3, addr_reg); + tgen_andi(s, TCG_TYPE_I64, TCG_REG_R2, + (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); + tgen_andi(s, TCG_TYPE_TL, TCG_REG_R3, tlb_mask); } - tcg_out_sh64(s, RSY_SRLG, arg2, addr_reg, TCG_REG_NONE, - TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); - - tgen_andi(s, TCG_TYPE_I64, arg1, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); - tgen_andi(s, TCG_TYPE_I64, arg2, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); - - if (is_store) { - ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); - } else { + if (is_ld) { ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addr_read); + } else { + ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); } - assert(ofs < 0x80000); - if (TARGET_LONG_BITS == 32) { - tcg_out_mem(s, RX_C, RXY_CY, arg1, arg2, TCG_AREG0, ofs); + tcg_out_mem(s, RX_C, RXY_CY, TCG_REG_R3, TCG_REG_R2, TCG_AREG0, ofs); } else { - tcg_out_mem(s, 0, RXY_CG, arg1, arg2, TCG_AREG0, ofs); + tcg_out_mem(s, 0, RXY_CG, TCG_REG_R3, TCG_REG_R2, TCG_AREG0, ofs); } - if (TARGET_LONG_BITS == 32) { - tgen_ext32u(s, arg1, addr_reg); - } else { - tcg_out_mov(s, TCG_TYPE_I64, arg1, addr_reg); - } - - label1_ptr = s->code_ptr; - - /* je label1 (offset will be patched in later) */ - tcg_out_insn(s, RI, BRC, S390_CC_EQ, 0); - - /* call load/store helper */ - if (is_store) { - /* Make sure to zero-extend the value to the full register - for the calling convention. */ - switch (opc) { - case LD_UINT8: - tgen_ext8u(s, TCG_TYPE_I64, arg2, data_reg); - break; - case LD_UINT16: - tgen_ext16u(s, TCG_TYPE_I64, arg2, data_reg); - break; - case LD_UINT32: - tgen_ext32u(s, arg2, data_reg); - break; - case LD_UINT64: - tcg_out_mov(s, TCG_TYPE_I64, arg2, data_reg); - break; - default: - tcg_abort(); - } - tcg_out_movi(s, TCG_TYPE_I32, arg3, mem_index); - tcg_out_mov(s, TCG_TYPE_I64, arg0, TCG_AREG0); - tcg_out_call(s, qemu_st_helpers[s_bits]); - } else { - tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); - tcg_out_mov(s, TCG_TYPE_I64, arg0, TCG_AREG0); - tcg_out_call(s, qemu_ld_helpers[s_bits]); + ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addend); + tcg_out_mem(s, 0, RXY_LG, TCG_REG_R2, TCG_REG_R2, TCG_AREG0, ofs); - /* sign extension */ - switch (opc) { - case LD_INT8: - tgen_ext8s(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); - break; - case LD_INT16: - tgen_ext16s(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); - break; - case LD_INT32: - tgen_ext32s(s, data_reg, TCG_REG_R2); - break; - default: - /* unsigned -> just copy */ - tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); - break; - } + if (TARGET_LONG_BITS == 32) { + tgen_ext32u(s, TCG_REG_R3, addr_reg); + return TCG_REG_R3; } + return addr_reg; +} - /* jump to label2 (end) */ - *label2_ptr_p = s->code_ptr; - - tcg_out_insn(s, RI, BRC, S390_CC_ALWAYS, 0); +static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOp opc, + TCGReg data, TCGReg addr, int mem_index, + tcg_insn_unit *raddr, tcg_insn_unit *label_ptr) +{ + TCGLabelQemuLdst *label = new_ldst_label(s); + + label->is_ld = is_ld; + label->opc = opc; + label->datalo_reg = data; + label->addrlo_reg = addr; + label->mem_index = mem_index; + label->raddr = raddr; + label->label_ptr[0] = label_ptr; +} - /* this is label1, patch branch */ - label1_ptr[1] = s->code_ptr - label1_ptr; +static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) +{ + TCGReg addr_reg = lb->addrlo_reg; + TCGReg data_reg = lb->datalo_reg; + TCGMemOp opc = lb->opc; - ofs = offsetof(CPUArchState, tlb_table[mem_index][0].addend); - assert(ofs < 0x80000); + patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, -2); - tcg_out_mem(s, 0, RXY_AG, arg1, arg2, TCG_AREG0, ofs); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0); + if (TARGET_LONG_BITS == 64) { + tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, addr_reg); + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, lb->mem_index); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R5, (uintptr_t)lb->raddr); + tcg_out_call(s, qemu_ld_helpers[opc]); + tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_R2); - return arg1; + tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); } -static void tcg_finish_qemu_ldst(TCGContext* s, tcg_insn_unit *label2_ptr) +static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) { - /* patch branch */ - label2_ptr[1] = s->code_ptr - label2_ptr; + TCGReg addr_reg = lb->addrlo_reg; + TCGReg data_reg = lb->datalo_reg; + TCGMemOp opc = lb->opc; + + patch_reloc(lb->label_ptr[0], R_390_PC16DBL, (intptr_t)s->code_ptr, -2); + + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0); + if (TARGET_LONG_BITS == 64) { + tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R3, addr_reg); + } + switch (opc & MO_SIZE) { + case MO_UB: + tgen_ext8u(s, TCG_TYPE_I64, TCG_REG_R4, data_reg); + break; + case MO_UW: + tgen_ext16u(s, TCG_TYPE_I64, TCG_REG_R4, data_reg); + break; + case MO_UL: + tgen_ext32u(s, TCG_REG_R4, data_reg); + break; + case MO_Q: + tcg_out_mov(s, TCG_TYPE_I64, TCG_REG_R4, data_reg); + break; + default: + tcg_abort(); + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R5, lb->mem_index); + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R6, (uintptr_t)lb->raddr); + tcg_out_call(s, qemu_st_helpers[opc]); + + tgen_gotoi(s, S390_CC_ALWAYS, lb->raddr); } #else static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg, @@ -1523,61 +1634,51 @@ static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg, } #endif /* CONFIG_SOFTMMU */ -/* load data with address translation (if applicable) - and endianness conversion */ -static void tcg_out_qemu_ld(TCGContext* s, const TCGArg* args, int opc) +static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, + TCGMemOp opc, int mem_index) { - TCGReg addr_reg, data_reg; -#if defined(CONFIG_SOFTMMU) - int mem_index; - tcg_insn_unit *label2_ptr; -#else - TCGReg index_reg; - tcg_target_long disp; -#endif - - data_reg = *args++; - addr_reg = *args++; +#ifdef CONFIG_SOFTMMU + tcg_insn_unit *label_ptr; + TCGReg base_reg; -#if defined(CONFIG_SOFTMMU) - mem_index = *args; + base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 1); - addr_reg = tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index, - opc, &label2_ptr, 0); + label_ptr = s->code_ptr + 1; + tcg_out_insn(s, RI, BRC, S390_CC_NE, 0); - tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, TCG_REG_NONE, 0); + tcg_out_qemu_ld_direct(s, opc, data_reg, base_reg, TCG_REG_R2, 0); - tcg_finish_qemu_ldst(s, label2_ptr); + add_qemu_ldst_label(s, 1, opc, data_reg, addr_reg, mem_index, + s->code_ptr, label_ptr); #else + TCGReg index_reg; + tcg_target_long disp; + tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp); tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, index_reg, disp); #endif } -static void tcg_out_qemu_st(TCGContext* s, const TCGArg* args, int opc) +static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, + TCGMemOp opc, int mem_index) { - TCGReg addr_reg, data_reg; -#if defined(CONFIG_SOFTMMU) - int mem_index; - tcg_insn_unit *label2_ptr; -#else - TCGReg index_reg; - tcg_target_long disp; -#endif - - data_reg = *args++; - addr_reg = *args++; +#ifdef CONFIG_SOFTMMU + tcg_insn_unit *label_ptr; + TCGReg base_reg; -#if defined(CONFIG_SOFTMMU) - mem_index = *args; + base_reg = tcg_out_tlb_read(s, addr_reg, opc, mem_index, 0); - addr_reg = tcg_prepare_qemu_ldst(s, data_reg, addr_reg, mem_index, - opc, &label2_ptr, 1); + label_ptr = s->code_ptr + 1; + tcg_out_insn(s, RI, BRC, S390_CC_NE, 0); - tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, TCG_REG_NONE, 0); + tcg_out_qemu_st_direct(s, opc, data_reg, base_reg, TCG_REG_R2, 0); - tcg_finish_qemu_ldst(s, label2_ptr); + add_qemu_ldst_label(s, 0, opc, data_reg, addr_reg, mem_index, + s->code_ptr, label_ptr); #else + TCGReg index_reg; + tcg_target_long disp; + tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp); tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, index_reg, disp); #endif @@ -1602,7 +1703,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, case INDEX_op_goto_tb: if (s->tb_jmp_offset) { - tcg_abort(); + tcg_out16(s, RIL_BRCL | (S390_CC_ALWAYS << 4)); + s->tb_jmp_offset[args[0]] = tcg_current_code_size(s); + s->code_ptr += 2; } else { /* load address stored at s->tb_next + args[0] */ tcg_out_ld_abs(s, TCG_TYPE_PTR, TCG_TMP0, s->tb_next + args[0]); @@ -1784,13 +1887,19 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_add2_i32: - /* ??? Make use of ALFI. */ - tcg_out_insn(s, RR, ALR, args[0], args[4]); + if (const_args[4]) { + tcg_out_insn(s, RIL, ALFI, args[0], args[4]); + } else { + tcg_out_insn(s, RR, ALR, args[0], args[4]); + } tcg_out_insn(s, RRE, ALCR, args[1], args[5]); break; case INDEX_op_sub2_i32: - /* ??? Make use of SLFI. */ - tcg_out_insn(s, RR, SLR, args[0], args[4]); + if (const_args[4]) { + tcg_out_insn(s, RIL, SLFI, args[0], args[4]); + } else { + tcg_out_insn(s, RR, SLR, args[0], args[4]); + } tcg_out_insn(s, RRE, SLBR, args[1], args[5]); break; @@ -1811,37 +1920,14 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, args[2], const_args[2], args[3]); break; - case INDEX_op_qemu_ld8u: - tcg_out_qemu_ld(s, args, LD_UINT8); - break; - case INDEX_op_qemu_ld8s: - tcg_out_qemu_ld(s, args, LD_INT8); - break; - case INDEX_op_qemu_ld16u: - tcg_out_qemu_ld(s, args, LD_UINT16); - break; - case INDEX_op_qemu_ld16s: - tcg_out_qemu_ld(s, args, LD_INT16); - break; - case INDEX_op_qemu_ld32: + case INDEX_op_qemu_ld_i32: /* ??? Technically we can use a non-extending instruction. */ - tcg_out_qemu_ld(s, args, LD_UINT32); - break; - case INDEX_op_qemu_ld64: - tcg_out_qemu_ld(s, args, LD_UINT64); - break; - - case INDEX_op_qemu_st8: - tcg_out_qemu_st(s, args, LD_UINT8); - break; - case INDEX_op_qemu_st16: - tcg_out_qemu_st(s, args, LD_UINT16); - break; - case INDEX_op_qemu_st32: - tcg_out_qemu_st(s, args, LD_UINT32); + case INDEX_op_qemu_ld_i64: + tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3]); break; - case INDEX_op_qemu_st64: - tcg_out_qemu_st(s, args, LD_UINT64); + case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st_i64: + tcg_out_qemu_st(s, args[0], args[1], args[2], args[3]); break; case INDEX_op_ld16s_i64: @@ -2014,13 +2100,27 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; case INDEX_op_add2_i64: - /* ??? Make use of ALGFI and SLGFI. */ - tcg_out_insn(s, RRE, ALGR, args[0], args[4]); + if (const_args[4]) { + if ((int64_t)args[4] >= 0) { + tcg_out_insn(s, RIL, ALGFI, args[0], args[4]); + } else { + tcg_out_insn(s, RIL, SLGFI, args[0], -args[4]); + } + } else { + tcg_out_insn(s, RRE, ALGR, args[0], args[4]); + } tcg_out_insn(s, RRE, ALCGR, args[1], args[5]); break; case INDEX_op_sub2_i64: - /* ??? Make use of ALGFI and SLGFI. */ - tcg_out_insn(s, RRE, SLGR, args[0], args[4]); + if (const_args[4]) { + if ((int64_t)args[4] >= 0) { + tcg_out_insn(s, RIL, SLGFI, args[0], args[4]); + } else { + tcg_out_insn(s, RIL, ALGFI, args[0], -args[4]); + } + } else { + tcg_out_insn(s, RRE, SLGR, args[0], args[4]); + } tcg_out_insn(s, RRE, SLBGR, args[1], args[5]); break; @@ -2037,13 +2137,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, args[2], const_args[2], args[3]); break; - case INDEX_op_qemu_ld32u: - tcg_out_qemu_ld(s, args, LD_UINT32); - break; - case INDEX_op_qemu_ld32s: - tcg_out_qemu_ld(s, args, LD_INT32); - break; - OP_32_64(deposit): tgen_deposit(s, args[0], args[2], args[3], args[4]); break; @@ -2100,25 +2193,18 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_bswap16_i32, { "r", "r" } }, { INDEX_op_bswap32_i32, { "r", "r" } }, - { INDEX_op_add2_i32, { "r", "r", "0", "1", "r", "r" } }, - { INDEX_op_sub2_i32, { "r", "r", "0", "1", "r", "r" } }, + { INDEX_op_add2_i32, { "r", "r", "0", "1", "rA", "r" } }, + { INDEX_op_sub2_i32, { "r", "r", "0", "1", "rA", "r" } }, { INDEX_op_brcond_i32, { "r", "rC" } }, { INDEX_op_setcond_i32, { "r", "r", "rC" } }, { INDEX_op_movcond_i32, { "r", "r", "rC", "r", "0" } }, { INDEX_op_deposit_i32, { "r", "0", "r" } }, - { INDEX_op_qemu_ld8u, { "r", "L" } }, - { INDEX_op_qemu_ld8s, { "r", "L" } }, - { INDEX_op_qemu_ld16u, { "r", "L" } }, - { INDEX_op_qemu_ld16s, { "r", "L" } }, - { INDEX_op_qemu_ld32, { "r", "L" } }, - { INDEX_op_qemu_ld64, { "r", "L" } }, - - { INDEX_op_qemu_st8, { "L", "L" } }, - { INDEX_op_qemu_st16, { "L", "L" } }, - { INDEX_op_qemu_st32, { "L", "L" } }, - { INDEX_op_qemu_st64, { "L", "L" } }, + { INDEX_op_qemu_ld_i32, { "r", "L" } }, + { INDEX_op_qemu_ld_i64, { "r", "L" } }, + { INDEX_op_qemu_st_i32, { "L", "L" } }, + { INDEX_op_qemu_st_i64, { "L", "L" } }, { INDEX_op_ld8u_i64, { "r", "r" } }, { INDEX_op_ld8s_i64, { "r", "r" } }, @@ -2165,17 +2251,14 @@ static const TCGTargetOpDef s390_op_defs[] = { { INDEX_op_bswap32_i64, { "r", "r" } }, { INDEX_op_bswap64_i64, { "r", "r" } }, - { INDEX_op_add2_i64, { "r", "r", "0", "1", "r", "r" } }, - { INDEX_op_sub2_i64, { "r", "r", "0", "1", "r", "r" } }, + { INDEX_op_add2_i64, { "r", "r", "0", "1", "rA", "r" } }, + { INDEX_op_sub2_i64, { "r", "r", "0", "1", "rA", "r" } }, { INDEX_op_brcond_i64, { "r", "rC" } }, { INDEX_op_setcond_i64, { "r", "r", "rC" } }, { INDEX_op_movcond_i64, { "r", "r", "rC", "r", "0" } }, { INDEX_op_deposit_i64, { "r", "0", "r" } }, - { INDEX_op_qemu_ld32u, { "r", "L" } }, - { INDEX_op_qemu_ld32s, { "r", "L" } }, - { -1 }, }; @@ -2210,6 +2293,9 @@ static void tcg_target_init(TCGContext *s) tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3); tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R4); tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R5); + /* The r6 register is technically call-saved, but it's also a parameter + register, so it can get killed by setup for the qemu_st helper. */ + tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R6); /* The return register can be considered call-clobbered. */ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14); @@ -2222,18 +2308,17 @@ static void tcg_target_init(TCGContext *s) tcg_add_target_add_op_defs(s390_op_defs); } +#define FRAME_SIZE ((int)(TCG_TARGET_CALL_STACK_OFFSET \ + + TCG_STATIC_CALL_ARGS_SIZE \ + + CPU_TEMP_BUF_NLONGS * sizeof(long))) + static void tcg_target_qemu_prologue(TCGContext *s) { - tcg_target_long frame_size; - /* stmg %r6,%r15,48(%r15) (save registers) */ tcg_out_insn(s, RXY, STMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, 48); /* aghi %r15,-frame_size */ - frame_size = TCG_TARGET_CALL_STACK_OFFSET; - frame_size += TCG_STATIC_CALL_ARGS_SIZE; - frame_size += CPU_TEMP_BUF_NLONGS * sizeof(long); - tcg_out_insn(s, RI, AGHI, TCG_REG_R15, -frame_size); + tcg_out_insn(s, RI, AGHI, TCG_REG_R15, -FRAME_SIZE); tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE + TCG_TARGET_CALL_STACK_OFFSET, @@ -2252,8 +2337,57 @@ static void tcg_target_qemu_prologue(TCGContext *s) /* lmg %r6,%r15,fs+48(%r15) (restore registers) */ tcg_out_insn(s, RXY, LMG, TCG_REG_R6, TCG_REG_R15, TCG_REG_R15, - frame_size + 48); + FRAME_SIZE + 48); /* br %r14 (return) */ tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, TCG_REG_R14); } + +typedef struct { + DebugFrameCIE cie; + DebugFrameFDEHeader fde; + uint8_t fde_def_cfa[4]; + uint8_t fde_reg_ofs[18]; +} DebugFrame; + +/* We're expecting a 2 byte uleb128 encoded value. */ +QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14)); + +#define ELF_HOST_MACHINE EM_S390 + +static DebugFrame debug_frame = { + .cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */ + .cie.id = -1, + .cie.version = 1, + .cie.code_align = 1, + .cie.data_align = 8, /* sleb128 8 */ + .cie.return_column = TCG_REG_R14, + + /* Total FDE size does not include the "len" member. */ + .fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, fde.cie_offset), + + .fde_def_cfa = { + 12, TCG_REG_CALL_STACK, /* DW_CFA_def_cfa %r15, ... */ + (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */ + (FRAME_SIZE >> 7) + }, + .fde_reg_ofs = { + 0x86, 6, /* DW_CFA_offset, %r6, 48 */ + 0x87, 7, /* DW_CFA_offset, %r7, 56 */ + 0x88, 8, /* DW_CFA_offset, %r8, 64 */ + 0x89, 9, /* DW_CFA_offset, %r92, 72 */ + 0x8a, 10, /* DW_CFA_offset, %r10, 80 */ + 0x8b, 11, /* DW_CFA_offset, %r11, 88 */ + 0x8c, 12, /* DW_CFA_offset, %r12, 96 */ + 0x8d, 13, /* DW_CFA_offset, %r13, 104 */ + 0x8e, 14, /* DW_CFA_offset, %r14, 112 */ + } +}; + +void tcg_register_jit(void *buf, size_t buf_size) +{ + debug_frame.fde.func_start = (uintptr_t)buf; + debug_frame.fde.func_len = buf_size; + + tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); +} diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h index 5bf733eb3d..ad2c6ddaf4 100644 --- a/tcg/s390/tcg-target.h +++ b/tcg/s390/tcg-target.h @@ -100,7 +100,7 @@ typedef enum TCGReg { #define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 -#define TCG_TARGET_HAS_new_ldst 0 +#define TCG_TARGET_HAS_new_ldst 1 extern bool tcg_target_deposit_valid(int ofs, int len); #define TCG_TARGET_deposit_i32_valid tcg_target_deposit_valid diff --git a/trace-events b/trace-events index 2c5b30763e..b6d289d720 100644 --- a/trace-events +++ b/trace-events @@ -688,17 +688,21 @@ megasas_dcmd_ld_get_list(int cmd, int num, int max) "scmd %d: DCMD LD get list: megasas_dcmd_ld_get_info(int cmd, int ld_id) "scmd %d: DCMD LD get info for dev %d" megasas_dcmd_pd_get_info(int cmd, int pd_id) "scmd %d: DCMD PD get info for dev %d" megasas_dcmd_pd_list_query(int cmd, int flags) "scmd %d: DCMD PD list query flags %x" +megasas_dcmd_ld_list_query(int cmd, int flags) "scmd %d: DCMD LD list query flags %x" megasas_dcmd_unsupported(int cmd, unsigned long size) "scmd %d: set properties len %ld" megasas_abort_frame(int cmd, int abort_cmd) "scmd %d: aborting frame %x" megasas_abort_no_cmd(int cmd, uint64_t context) "scmd %d: no active command for frame context %" PRIx64 "" megasas_abort_invalid_context(int cmd, uint64_t context, int abort_cmd) "scmd %d: invalid frame context %" PRIx64 " for abort frame %x" megasas_reset(void) "Reset" -megasas_init(int sges, int cmds, const char *intr, const char *mode) "Using %d sges, %d cmds, %s, %s mode" +megasas_init(int sges, int cmds, const char *mode) "Using %d sges, %d cmds, %s mode" megasas_msix_raise(int vector) "vector %d" +megasas_msi_raise(int vector) "vector %d" megasas_irq_lower(void) "INTx" megasas_irq_raise(void) "INTx" megasas_intr_enabled(void) "Interrupts enabled" megasas_intr_disabled(void) "Interrupts disabled" +megasas_msix_enabled(int vector) "vector %d" +megasas_msi_enabled(int vector) "vector %d" megasas_mmio_readl(unsigned long addr, uint32_t val) "addr 0x%lx: 0x%x" megasas_mmio_invalid_readl(unsigned long addr) "addr 0x%lx" megasas_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%x: 0x%x" @@ -862,8 +866,8 @@ escc_mem_writeb_data(char channel, uint32_t val) "Write channel %c, ch %d" escc_mem_readb_ctrl(char channel, uint32_t reg, uint8_t val) "Read channel %c, reg[%d] = %2.2x" escc_mem_readb_data(char channel, uint32_t ret) "Read channel %c, ch %d" escc_serial_receive_byte(char channel, int ch) "channel %c put ch %d" -escc_sunkbd_event_in(int ch) "Untranslated keycode %2.2x" -escc_sunkbd_event_out(int ch) "Translated keycode %2.2x" +escc_sunkbd_event_in(int ch, const char *name, int down) "QKeyCode 0x%2.2x [%s], down %d" +escc_sunkbd_event_out(int ch) "Translated keycode 0x%2.2x" escc_kbd_command(int val) "Command %d" escc_sunmouse_event(int dx, int dy, int buttons_state) "dx=%d dy=%d buttons=%01x" diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 4af420bfa8..6afb52a93c 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -7,7 +7,8 @@ vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o vnc-obj-y += vnc-jobs.o -common-obj-y += keymaps.o console.o cursor.o input.o input-legacy.o qemu-pixman.o +common-obj-y += keymaps.o console.o cursor.o qemu-pixman.o +common-obj-y += input.o input-keymap.o input-legacy.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o common-obj-$(CONFIG_COCOA) += cocoa.o diff --git a/ui/input-keymap.c b/ui/input-keymap.c new file mode 100644 index 0000000000..6da4495103 --- /dev/null +++ b/ui/input-keymap.c @@ -0,0 +1,191 @@ +#include "sysemu/sysemu.h" +#include "ui/keymaps.h" +#include "ui/input.h" + +static const int qcode_to_number[] = { + [Q_KEY_CODE_SHIFT] = 0x2a, + [Q_KEY_CODE_SHIFT_R] = 0x36, + + [Q_KEY_CODE_ALT] = 0x38, + [Q_KEY_CODE_ALT_R] = 0xb8, + [Q_KEY_CODE_ALTGR] = 0x64, + [Q_KEY_CODE_ALTGR_R] = 0xe4, + [Q_KEY_CODE_CTRL] = 0x1d, + [Q_KEY_CODE_CTRL_R] = 0x9d, + + [Q_KEY_CODE_MENU] = 0xdd, + + [Q_KEY_CODE_ESC] = 0x01, + + [Q_KEY_CODE_1] = 0x02, + [Q_KEY_CODE_2] = 0x03, + [Q_KEY_CODE_3] = 0x04, + [Q_KEY_CODE_4] = 0x05, + [Q_KEY_CODE_5] = 0x06, + [Q_KEY_CODE_6] = 0x07, + [Q_KEY_CODE_7] = 0x08, + [Q_KEY_CODE_8] = 0x09, + [Q_KEY_CODE_9] = 0x0a, + [Q_KEY_CODE_0] = 0x0b, + [Q_KEY_CODE_MINUS] = 0x0c, + [Q_KEY_CODE_EQUAL] = 0x0d, + [Q_KEY_CODE_BACKSPACE] = 0x0e, + + [Q_KEY_CODE_TAB] = 0x0f, + [Q_KEY_CODE_Q] = 0x10, + [Q_KEY_CODE_W] = 0x11, + [Q_KEY_CODE_E] = 0x12, + [Q_KEY_CODE_R] = 0x13, + [Q_KEY_CODE_T] = 0x14, + [Q_KEY_CODE_Y] = 0x15, + [Q_KEY_CODE_U] = 0x16, + [Q_KEY_CODE_I] = 0x17, + [Q_KEY_CODE_O] = 0x18, + [Q_KEY_CODE_P] = 0x19, + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, + [Q_KEY_CODE_RET] = 0x1c, + + [Q_KEY_CODE_A] = 0x1e, + [Q_KEY_CODE_S] = 0x1f, + [Q_KEY_CODE_D] = 0x20, + [Q_KEY_CODE_F] = 0x21, + [Q_KEY_CODE_G] = 0x22, + [Q_KEY_CODE_H] = 0x23, + [Q_KEY_CODE_J] = 0x24, + [Q_KEY_CODE_K] = 0x25, + [Q_KEY_CODE_L] = 0x26, + [Q_KEY_CODE_SEMICOLON] = 0x27, + [Q_KEY_CODE_APOSTROPHE] = 0x28, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, + + [Q_KEY_CODE_BACKSLASH] = 0x2b, + [Q_KEY_CODE_Z] = 0x2c, + [Q_KEY_CODE_X] = 0x2d, + [Q_KEY_CODE_C] = 0x2e, + [Q_KEY_CODE_V] = 0x2f, + [Q_KEY_CODE_B] = 0x30, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_M] = 0x32, + [Q_KEY_CODE_COMMA] = 0x33, + [Q_KEY_CODE_DOT] = 0x34, + [Q_KEY_CODE_SLASH] = 0x35, + + [Q_KEY_CODE_ASTERISK] = 0x37, + + [Q_KEY_CODE_SPC] = 0x39, + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, + [Q_KEY_CODE_F1] = 0x3b, + [Q_KEY_CODE_F2] = 0x3c, + [Q_KEY_CODE_F3] = 0x3d, + [Q_KEY_CODE_F4] = 0x3e, + [Q_KEY_CODE_F5] = 0x3f, + [Q_KEY_CODE_F6] = 0x40, + [Q_KEY_CODE_F7] = 0x41, + [Q_KEY_CODE_F8] = 0x42, + [Q_KEY_CODE_F9] = 0x43, + [Q_KEY_CODE_F10] = 0x44, + [Q_KEY_CODE_NUM_LOCK] = 0x45, + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, + + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, + [Q_KEY_CODE_KP_ADD] = 0x4e, + [Q_KEY_CODE_KP_ENTER] = 0x9c, + [Q_KEY_CODE_KP_DECIMAL] = 0x53, + [Q_KEY_CODE_SYSRQ] = 0x54, + + [Q_KEY_CODE_KP_0] = 0x52, + [Q_KEY_CODE_KP_1] = 0x4f, + [Q_KEY_CODE_KP_2] = 0x50, + [Q_KEY_CODE_KP_3] = 0x51, + [Q_KEY_CODE_KP_4] = 0x4b, + [Q_KEY_CODE_KP_5] = 0x4c, + [Q_KEY_CODE_KP_6] = 0x4d, + [Q_KEY_CODE_KP_7] = 0x47, + [Q_KEY_CODE_KP_8] = 0x48, + [Q_KEY_CODE_KP_9] = 0x49, + + [Q_KEY_CODE_LESS] = 0x56, + + [Q_KEY_CODE_F11] = 0x57, + [Q_KEY_CODE_F12] = 0x58, + + [Q_KEY_CODE_PRINT] = 0xb7, + + [Q_KEY_CODE_HOME] = 0xc7, + [Q_KEY_CODE_PGUP] = 0xc9, + [Q_KEY_CODE_PGDN] = 0xd1, + [Q_KEY_CODE_END] = 0xcf, + + [Q_KEY_CODE_LEFT] = 0xcb, + [Q_KEY_CODE_UP] = 0xc8, + [Q_KEY_CODE_DOWN] = 0xd0, + [Q_KEY_CODE_RIGHT] = 0xcd, + + [Q_KEY_CODE_INSERT] = 0xd2, + [Q_KEY_CODE_DELETE] = 0xd3, + [Q_KEY_CODE_MAX] = 0, +}; + +static int number_to_qcode[0xff]; + +int qemu_input_key_value_to_number(const KeyValue *value) +{ + if (value->kind == KEY_VALUE_KIND_QCODE) { + return qcode_to_number[value->qcode]; + } else { + assert(value->kind == KEY_VALUE_KIND_NUMBER); + return value->number; + } +} + +int qemu_input_key_value_to_qcode(const KeyValue *value) +{ + static int first = true; + + if (first) { + int qcode, number; + first = false; + for (qcode = 0; qcode < Q_KEY_CODE_MAX; qcode++) { + number = qcode_to_number[qcode]; + assert(number < ARRAY_SIZE(number_to_qcode)); + number_to_qcode[number] = qcode; + } + } + + if (value->kind == KEY_VALUE_KIND_QCODE) { + return value->qcode; + } else { + assert(value->kind == KEY_VALUE_KIND_NUMBER); + return number_to_qcode[value->number]; + } +} + +int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, + int *codes) +{ + int keycode = qemu_input_key_value_to_number(value); + int count = 0; + + if (value->kind == KEY_VALUE_KIND_QCODE && + value->qcode == Q_KEY_CODE_PAUSE) { + /* specific case */ + int v = down ? 0 : 0x80; + codes[count++] = 0xe1; + codes[count++] = 0x1d | v; + codes[count++] = 0x45 | v; + return count; + } + if (keycode & SCANCODE_GREY) { + codes[count++] = SCANCODE_EMUL0; + keycode &= ~SCANCODE_GREY; + } + if (!down) { + keycode |= SCANCODE_UP; + } + codes[count++] = keycode; + + return count; +} diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 1aa2605b75..2a538607a2 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -60,152 +60,6 @@ static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = QTAILQ_HEAD_INITIALIZER(mouse_handlers); -static const int key_defs[] = { - [Q_KEY_CODE_SHIFT] = 0x2a, - [Q_KEY_CODE_SHIFT_R] = 0x36, - - [Q_KEY_CODE_ALT] = 0x38, - [Q_KEY_CODE_ALT_R] = 0xb8, - [Q_KEY_CODE_ALTGR] = 0x64, - [Q_KEY_CODE_ALTGR_R] = 0xe4, - [Q_KEY_CODE_CTRL] = 0x1d, - [Q_KEY_CODE_CTRL_R] = 0x9d, - - [Q_KEY_CODE_MENU] = 0xdd, - - [Q_KEY_CODE_ESC] = 0x01, - - [Q_KEY_CODE_1] = 0x02, - [Q_KEY_CODE_2] = 0x03, - [Q_KEY_CODE_3] = 0x04, - [Q_KEY_CODE_4] = 0x05, - [Q_KEY_CODE_5] = 0x06, - [Q_KEY_CODE_6] = 0x07, - [Q_KEY_CODE_7] = 0x08, - [Q_KEY_CODE_8] = 0x09, - [Q_KEY_CODE_9] = 0x0a, - [Q_KEY_CODE_0] = 0x0b, - [Q_KEY_CODE_MINUS] = 0x0c, - [Q_KEY_CODE_EQUAL] = 0x0d, - [Q_KEY_CODE_BACKSPACE] = 0x0e, - - [Q_KEY_CODE_TAB] = 0x0f, - [Q_KEY_CODE_Q] = 0x10, - [Q_KEY_CODE_W] = 0x11, - [Q_KEY_CODE_E] = 0x12, - [Q_KEY_CODE_R] = 0x13, - [Q_KEY_CODE_T] = 0x14, - [Q_KEY_CODE_Y] = 0x15, - [Q_KEY_CODE_U] = 0x16, - [Q_KEY_CODE_I] = 0x17, - [Q_KEY_CODE_O] = 0x18, - [Q_KEY_CODE_P] = 0x19, - [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, - [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, - [Q_KEY_CODE_RET] = 0x1c, - - [Q_KEY_CODE_A] = 0x1e, - [Q_KEY_CODE_S] = 0x1f, - [Q_KEY_CODE_D] = 0x20, - [Q_KEY_CODE_F] = 0x21, - [Q_KEY_CODE_G] = 0x22, - [Q_KEY_CODE_H] = 0x23, - [Q_KEY_CODE_J] = 0x24, - [Q_KEY_CODE_K] = 0x25, - [Q_KEY_CODE_L] = 0x26, - [Q_KEY_CODE_SEMICOLON] = 0x27, - [Q_KEY_CODE_APOSTROPHE] = 0x28, - [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, - - [Q_KEY_CODE_BACKSLASH] = 0x2b, - [Q_KEY_CODE_Z] = 0x2c, - [Q_KEY_CODE_X] = 0x2d, - [Q_KEY_CODE_C] = 0x2e, - [Q_KEY_CODE_V] = 0x2f, - [Q_KEY_CODE_B] = 0x30, - [Q_KEY_CODE_N] = 0x31, - [Q_KEY_CODE_M] = 0x32, - [Q_KEY_CODE_COMMA] = 0x33, - [Q_KEY_CODE_DOT] = 0x34, - [Q_KEY_CODE_SLASH] = 0x35, - - [Q_KEY_CODE_ASTERISK] = 0x37, - - [Q_KEY_CODE_SPC] = 0x39, - [Q_KEY_CODE_CAPS_LOCK] = 0x3a, - [Q_KEY_CODE_F1] = 0x3b, - [Q_KEY_CODE_F2] = 0x3c, - [Q_KEY_CODE_F3] = 0x3d, - [Q_KEY_CODE_F4] = 0x3e, - [Q_KEY_CODE_F5] = 0x3f, - [Q_KEY_CODE_F6] = 0x40, - [Q_KEY_CODE_F7] = 0x41, - [Q_KEY_CODE_F8] = 0x42, - [Q_KEY_CODE_F9] = 0x43, - [Q_KEY_CODE_F10] = 0x44, - [Q_KEY_CODE_NUM_LOCK] = 0x45, - [Q_KEY_CODE_SCROLL_LOCK] = 0x46, - - [Q_KEY_CODE_KP_DIVIDE] = 0xb5, - [Q_KEY_CODE_KP_MULTIPLY] = 0x37, - [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, - [Q_KEY_CODE_KP_ADD] = 0x4e, - [Q_KEY_CODE_KP_ENTER] = 0x9c, - [Q_KEY_CODE_KP_DECIMAL] = 0x53, - [Q_KEY_CODE_SYSRQ] = 0x54, - - [Q_KEY_CODE_KP_0] = 0x52, - [Q_KEY_CODE_KP_1] = 0x4f, - [Q_KEY_CODE_KP_2] = 0x50, - [Q_KEY_CODE_KP_3] = 0x51, - [Q_KEY_CODE_KP_4] = 0x4b, - [Q_KEY_CODE_KP_5] = 0x4c, - [Q_KEY_CODE_KP_6] = 0x4d, - [Q_KEY_CODE_KP_7] = 0x47, - [Q_KEY_CODE_KP_8] = 0x48, - [Q_KEY_CODE_KP_9] = 0x49, - - [Q_KEY_CODE_LESS] = 0x56, - - [Q_KEY_CODE_F11] = 0x57, - [Q_KEY_CODE_F12] = 0x58, - - [Q_KEY_CODE_PRINT] = 0xb7, - - [Q_KEY_CODE_HOME] = 0xc7, - [Q_KEY_CODE_PGUP] = 0xc9, - [Q_KEY_CODE_PGDN] = 0xd1, - [Q_KEY_CODE_END] = 0xcf, - - [Q_KEY_CODE_LEFT] = 0xcb, - [Q_KEY_CODE_UP] = 0xc8, - [Q_KEY_CODE_DOWN] = 0xd0, - [Q_KEY_CODE_RIGHT] = 0xcd, - - [Q_KEY_CODE_INSERT] = 0xd2, - [Q_KEY_CODE_DELETE] = 0xd3, -#ifdef NEED_CPU_H -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) - [Q_KEY_CODE_STOP] = 0xf0, - [Q_KEY_CODE_AGAIN] = 0xf1, - [Q_KEY_CODE_PROPS] = 0xf2, - [Q_KEY_CODE_UNDO] = 0xf3, - [Q_KEY_CODE_FRONT] = 0xf4, - [Q_KEY_CODE_COPY] = 0xf5, - [Q_KEY_CODE_OPEN] = 0xf6, - [Q_KEY_CODE_PASTE] = 0xf7, - [Q_KEY_CODE_FIND] = 0xf8, - [Q_KEY_CODE_CUT] = 0xf9, - [Q_KEY_CODE_LF] = 0xfa, - [Q_KEY_CODE_HELP] = 0xfb, - [Q_KEY_CODE_META_L] = 0xfc, - [Q_KEY_CODE_META_R] = 0xfd, - [Q_KEY_CODE_COMPOSE] = 0xfe, -#endif -#endif - [Q_KEY_CODE_MAX] = 0, -}; - int index_from_key(const char *key) { int i; @@ -220,48 +74,44 @@ int index_from_key(const char *key) return i; } -static int *keycodes; -static int keycodes_size; +static KeyValue **keyvalues; +static int keyvalues_size; static QEMUTimer *key_timer; -static int keycode_from_keyvalue(const KeyValue *value) +static void free_keyvalues(void) { - if (value->kind == KEY_VALUE_KIND_QCODE) { - return key_defs[value->qcode]; - } else { - assert(value->kind == KEY_VALUE_KIND_NUMBER); - return value->number; - } -} - -static void free_keycodes(void) -{ - g_free(keycodes); - keycodes = NULL; - keycodes_size = 0; + g_free(keyvalues); + keyvalues = NULL; + keyvalues_size = 0; } static void release_keys(void *opaque) { - while (keycodes_size > 0) { - qemu_input_event_send_key_number(NULL, keycodes[--keycodes_size], - false); + while (keyvalues_size > 0) { + qemu_input_event_send_key(NULL, keyvalues[--keyvalues_size], + false); } - free_keycodes(); + free_keyvalues(); +} + +static KeyValue *copy_key_value(KeyValue *src) +{ + KeyValue *dst = g_new(KeyValue, 1); + memcpy(dst, src, sizeof(*src)); + return dst; } void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, Error **errp) { - int keycode; KeyValueList *p; if (!key_timer) { key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL); } - if (keycodes != NULL) { + if (keyvalues != NULL) { timer_del(key_timer); release_keys(NULL); } @@ -271,51 +121,33 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, } for (p = keys; p != NULL; p = p->next) { - /* key down events */ - keycode = keycode_from_keyvalue(p->value); - if (keycode < 0x01 || keycode > 0xff) { - error_setg(errp, "invalid hex keycode 0x%x", keycode); - free_keycodes(); - return; - } - - qemu_input_event_send_key_number(NULL, keycode, true); + qemu_input_event_send_key(NULL, copy_key_value(p->value), true); - keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1)); - keycodes[keycodes_size++] = keycode; + keyvalues = g_realloc(keyvalues, sizeof(KeyValue *) * + (keyvalues_size + 1)); + keyvalues[keyvalues_size++] = copy_key_value(p->value); } /* delayed key up events */ timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + - muldiv64(get_ticks_per_sec(), hold_time, 1000)); + muldiv64(get_ticks_per_sec(), hold_time, 1000)); } static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) { QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; - int keycode = keycode_from_keyvalue(evt->key->key); + int scancodes[3], i, count; if (!entry || !entry->put_kbd) { return; } - if (evt->key->key->kind == KEY_VALUE_KIND_QCODE && - evt->key->key->qcode == Q_KEY_CODE_PAUSE) { - /* specific case */ - int v = evt->key->down ? 0 : 0x80; - entry->put_kbd(entry->opaque, 0xe1); - entry->put_kbd(entry->opaque, 0x1d | v); - entry->put_kbd(entry->opaque, 0x45 | v); - return; - } - if (keycode & SCANCODE_GREY) { - entry->put_kbd(entry->opaque, SCANCODE_EMUL0); - keycode &= ~SCANCODE_GREY; - } - if (!evt->key->down) { - keycode |= SCANCODE_UP; + count = qemu_input_key_value_to_scancode(evt->key->key, + evt->key->down, + scancodes); + for (i = 0; i < count; i++) { + entry->put_kbd(entry->opaque, scancodes[i]); } - entry->put_kbd(entry->opaque, keycode); } static QemuInputHandler legacy_kbd_handler = { diff --git a/ui/input.c b/ui/input.c index 1ed0e783b1..fc91fba83c 100644 --- a/ui/input.c +++ b/ui/input.c @@ -39,6 +39,13 @@ void qemu_input_handler_activate(QemuInputHandlerState *s) qemu_input_check_mode_change(); } +void qemu_input_handler_deactivate(QemuInputHandlerState *s) +{ + QTAILQ_REMOVE(&handlers, s, node); + QTAILQ_INSERT_TAIL(&handlers, s, node); + qemu_input_check_mode_change(); +} + void qemu_input_handler_unregister(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); |