From 7472e2efb049ea65a6a5e7261b78ebf5c561bc2f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Dec 2017 15:42:44 +0000 Subject: [PATCH 001/546] target/arm: Generate UNDEF for 32-bit Thumb2 insns The refactoring of commit 296e5a0a6c3935 has a nasty bug: it accidentally dropped the generation of code to raise the UNDEF exception when disas_thumb2_insn() returns nonzero. This means that 32-bit Thumb2 instruction patterns that ought to UNDEF just act like nops instead. This is likely to break any number of things, including the kernel's "disable the FPU and use the UNDEF exception to identify when to turn it back on again" trick. Signed-off-by: Peter Maydell Message-id: 1513006964-3371-1-git-send-email-peter.maydell@linaro.org Reviewed-by: Richard Henderson --- target/arm/translate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index 4afb0c86ec..f120932f44 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -12245,7 +12245,10 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) if (is_16bit) { disas_thumb_insn(dc, insn); } else { - disas_thumb2_insn(dc, insn); + if (disas_thumb2_insn(dc, insn)) { + gen_exception_insn(dc, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(dc)); + } } /* Advance the Thumb condexec condition. */ From 6afd0c1998fed739d7e62c491ba449365b0e9c28 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 11 Dec 2017 17:49:53 +0000 Subject: [PATCH 002/546] Update version for v2.11.0-rc5 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9735ddce29..1b45fb2c83 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.10.94 +2.10.95 From 0a0dc59d27527b78a195c2d838d28b7b49e5a639 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 14:31:09 +0000 Subject: [PATCH 003/546] Update version for v2.11.0 release Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1b45fb2c83..46b81d815a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.10.95 +2.11.0 From cba4d6d3181f2322d1a06aa0add8bca3d0e6faf3 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:05:59 +0000 Subject: [PATCH 004/546] Open 2.12 development tree Signed-off-by: Peter Maydell --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 46b81d815a..789af8370b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.11.0 +2.11.50 From 2016986aedb6ea2839662eb5f60630f3e231bd1a Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 13 Dec 2017 10:19:32 -0700 Subject: [PATCH 005/546] vfio: Fix vfio-kvm group registration Commit 8c37faa475f3 ("vfio-pci, ppc64/spapr: Reorder group-to-container attaching") moved registration of groups with the vfio-kvm device from vfio_get_group() to vfio_connect_container(), but it missed the case where a group is attached to an existing container and takes an early exit. Perhaps this is a less common case on ppc64/spapr, but on x86 (without viommu) all groups are connected to the same container and thus only the first group gets registered with the vfio-kvm device. This becomes a problem if we then hot-unplug the devices associated with that first group and we end up with KVM being misinformed about any vfio connections that might remain. Fix by including the call to vfio_kvm_device_add_group() in this early exit path. Fixes: 8c37faa475f3 ("vfio-pci, ppc64/spapr: Reorder group-to-container attaching") Cc: qemu-stable@nongnu.org # qemu-2.10+ Reviewed-by: Alexey Kardashevskiy Reviewed-by: Peter Xu Tested-by: Peter Xu Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Alex Williamson --- hw/vfio/common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 7b2924c0ef..7007878e34 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -968,6 +968,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) { group->container = container; QLIST_INSERT_HEAD(&container->group_list, group, container_next); + vfio_kvm_device_add_group(group); return 0; } } From f7f9c7b23243fef21296d04d03df1477d12c5c19 Mon Sep 17 00:00:00 2001 From: "Liu, Yi L" Date: Wed, 13 Dec 2017 10:19:33 -0700 Subject: [PATCH 006/546] vfio/common: init giommu_list and hostwin_list of vfio container The init of giommu_list and hostwin_list is missed during container initialization. Signed-off-by: Liu, Yi L Signed-off-by: Alex Williamson --- hw/vfio/common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 7007878e34..216eec68ef 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -991,6 +991,8 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, container = g_malloc0(sizeof(*container)); container->space = space; container->fd = fd; + QLIST_INIT(&container->giommu_list); + QLIST_INIT(&container->hostwin_list); if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) || ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) { bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU); From c6e7958eb76ed267f7254b97f89773874df50e48 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 13 Dec 2017 10:19:33 -0700 Subject: [PATCH 007/546] vfio/spapr: Allow fallback to SPAPR TCE IOMMU v1 The vfio_iommu_spapr_tce driver advertises kernel's support for v1 and v2 IOMMU support, however it is not always possible to use the requested IOMMU type. For example, a pseries host platform does not support dynamic DMA windows so v2 cannot initialize and QEMU fails to start. This adds a fallback to the v1 IOMMU if v2 cannot be used. Fixes: 318f67ce1371 ("vfio: spapr: Add DMA memory preregistering (SPAPR IOMMU v2)") Signed-off-by: Alexey Kardashevskiy Signed-off-by: Alex Williamson --- hw/vfio/common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 216eec68ef..b77be3a8b3 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1042,6 +1042,11 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, container->iommu_type = v2 ? VFIO_SPAPR_TCE_v2_IOMMU : VFIO_SPAPR_TCE_IOMMU; ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); + if (ret) { + container->iommu_type = VFIO_SPAPR_TCE_IOMMU; + v2 = false; + ret = ioctl(fd, VFIO_SET_IOMMU, container->iommu_type); + } if (ret) { error_setg_errno(errp, errno, "failed to set iommu for container"); ret = -errno; From 2fb9636ebf24e695617bf407bf0a345aa223d1ac Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 13 Dec 2017 10:19:34 -0700 Subject: [PATCH 008/546] vfio-pci: Remove unused fields from VFIOMSIXInfo When support for multiple mappings per a region were added, this was left behind, let's finish and remove unused bits. Fixes: db0da029a185 ("vfio: Generalize region support") Signed-off-by: Alexey Kardashevskiy Signed-off-by: Alex Williamson --- hw/vfio/pci.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 502a5755b9..a8fb3b3422 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -93,8 +93,6 @@ typedef struct VFIOMSIXInfo { uint16_t entries; uint32_t table_offset; uint32_t pba_offset; - MemoryRegion mmap_mem; - void *mmap; unsigned long *pending; } VFIOMSIXInfo; From 0add925f7c3188a5e020e223dbb45fb24e093a24 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:20 +0000 Subject: [PATCH 009/546] m25p80: Add support for continuous read out of RDSR and READ_FSR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for continuous read out of the RDSR and READ_FSR status registers until the chip select is deasserted. This feature is supported by amongst others 1 or more flashtypes manufactured by Numonyx (Micron), Windbond, SST, Gigadevice, Eon and Macronix. Signed-off-by: Francisco Iglesias Acked-by: Marcin Krzemiński Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-2-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/block/m25p80.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index a2438b9ed2..d50acc1d3a 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -423,6 +423,7 @@ typedef struct Flash { uint8_t data[M25P80_INTERNAL_DATA_BUFFER_SZ]; uint32_t len; uint32_t pos; + bool data_read_loop; uint8_t needed_bytes; uint8_t cmd_in_progress; uint32_t cur_addr; @@ -983,6 +984,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) } s->pos = 0; s->len = 1; + s->data_read_loop = true; s->state = STATE_READING_DATA; break; @@ -993,6 +995,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) } s->pos = 0; s->len = 1; + s->data_read_loop = true; s->state = STATE_READING_DATA; break; @@ -1133,6 +1136,7 @@ static int m25p80_cs(SSISlave *ss, bool select) s->pos = 0; s->state = STATE_IDLE; flash_sync_dirty(s, -1); + s->data_read_loop = false; } DB_PRINT_L(0, "%sselect\n", select ? "de" : ""); @@ -1198,7 +1202,9 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) s->pos++; if (s->pos == s->len) { s->pos = 0; - s->state = STATE_IDLE; + if (!s->data_read_loop) { + s->state = STATE_IDLE; + } } break; @@ -1269,11 +1275,38 @@ static Property m25p80_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static int m25p80_pre_load(void *opaque) +{ + Flash *s = (Flash *)opaque; + + s->data_read_loop = false; + return 0; +} + +static bool m25p80_data_read_loop_needed(void *opaque) +{ + Flash *s = (Flash *)opaque; + + return s->data_read_loop; +} + +static const VMStateDescription vmstate_m25p80_data_read_loop = { + .name = "m25p80/data_read_loop", + .version_id = 1, + .minimum_version_id = 1, + .needed = m25p80_data_read_loop_needed, + .fields = (VMStateField[]) { + VMSTATE_BOOL(data_read_loop, Flash), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_m25p80 = { .name = "m25p80", .version_id = 0, .minimum_version_id = 0, .pre_save = m25p80_pre_save, + .pre_load = m25p80_pre_load, .fields = (VMStateField[]) { VMSTATE_UINT8(state, Flash), VMSTATE_UINT8_ARRAY(data, Flash, M25P80_INTERNAL_DATA_BUFFER_SZ), @@ -1295,6 +1328,10 @@ static const VMStateDescription vmstate_m25p80 = { VMSTATE_UINT8(spansion_cr3nv, Flash), VMSTATE_UINT8(spansion_cr4nv, Flash), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription * []) { + &vmstate_m25p80_data_read_loop, + NULL } }; From a87fc364f937f1d054fa3457662eb5ffe0491303 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 010/546] m25p80: Add support for SST READ ID 0x90/0xAB commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for SST READ ID 0x90/0xAB commands for reading out the flash manufacturer ID and device ID. Signed-off-by: Francisco Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-id: 20171126231634.9531-3-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/block/m25p80.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index d50acc1d3a..092c0c67e9 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -355,6 +355,8 @@ typedef enum { DPP = 0xa2, QPP = 0x32, QPP_4 = 0x34, + RDID_90 = 0x90, + RDID_AB = 0xab, ERASE_4K = 0x20, ERASE4_4K = 0x21, @@ -405,6 +407,7 @@ typedef enum { MAN_MACRONIX, MAN_NUMONYX, MAN_WINBOND, + MAN_SST, MAN_GENERIC, } Manufacturer; @@ -476,6 +479,8 @@ static inline Manufacturer get_man(Flash *s) return MAN_SPANSION; case 0xC2: return MAN_MACRONIX; + case 0xBF: + return MAN_SST; default: return MAN_GENERIC; } @@ -711,6 +716,31 @@ static void complete_collecting_data(Flash *s) case WEVCR: s->enh_volatile_cfg = s->data[0]; break; + case RDID_90: + case RDID_AB: + if (get_man(s) == MAN_SST) { + if (s->cur_addr <= 1) { + if (s->cur_addr) { + s->data[0] = s->pi->id[2]; + s->data[1] = s->pi->id[0]; + } else { + s->data[0] = s->pi->id[0]; + s->data[1] = s->pi->id[2]; + } + s->pos = 0; + s->len = 2; + s->data_read_loop = true; + s->state = STATE_READING_DATA; + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: Invalid read id address\n"); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "M25P80: Read id (command 0x90/0xAB) is not supported" + " by device\n"); + } + break; default: break; } @@ -926,6 +956,8 @@ static void decode_new_cmd(Flash *s, uint32_t value) case PP4: case PP4_4: case DIE_ERASE: + case RDID_90: + case RDID_AB: s->needed_bytes = get_addr_length(s); s->pos = 0; s->len = 0; From 0f5897821d3cf8ec6f198dc415d58591c47ce334 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 011/546] m25p80: Add support for BRRD/BRWR and BULK_ERASE (0x60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the bank address register access commands (BRRD/BRWR) and the BULK_ERASE (0x60) command. Signed-off-by: Francisco Iglesias Acked-by: Marcin Krzemiński Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-4-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/block/m25p80.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 092c0c67e9..35efdf0600 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -331,7 +331,10 @@ typedef enum { WRDI = 0x4, RDSR = 0x5, WREN = 0x6, + BRRD = 0x16, + BRWR = 0x17, JEDEC_READ = 0x9f, + BULK_ERASE_60 = 0x60, BULK_ERASE = 0xc7, READ_FSR = 0x70, RDCR = 0x15, @@ -704,6 +707,7 @@ static void complete_collecting_data(Flash *s) s->write_enable = false; } break; + case BRWR: case EXTEND_ADDR_WRITE: s->ear = s->data[0]; break; @@ -1050,6 +1054,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) s->state = STATE_READING_DATA; break; + case BULK_ERASE_60: case BULK_ERASE: if (s->write_enable) { DB_PRINT_L(0, "chip erase\n"); @@ -1067,12 +1072,14 @@ static void decode_new_cmd(Flash *s, uint32_t value) case EX_4BYTE_ADDR: s->four_bytes_address_mode = false; break; + case BRRD: case EXTEND_ADDR_READ: s->data[0] = s->ear; s->pos = 0; s->len = 1; s->state = STATE_READING_DATA; break; + case BRWR: case EXTEND_ADDR_WRITE: if (s->write_enable) { s->needed_bytes = 1; From 53dc9c79d93ca8bd246870735becd117054a12ef Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 012/546] m25p80: Add support for n25q512a11 and n25q512a13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Micron (Numonyx) n25q512a11 and n25q512a13 flashes. Signed-off-by: Francisco Iglesias Acked-by: Marcin Krzemiński Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-5-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/block/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 35efdf0600..ea142160b3 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -240,6 +240,8 @@ static const FlashPartInfo known_devices[] = { { INFO("n25q128a13", 0x20ba18, 0, 64 << 10, 256, ER_4K) }, { INFO("n25q256a11", 0x20bb19, 0, 64 << 10, 512, ER_4K) }, { INFO("n25q256a13", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, + { INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) }, + { INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, { INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) }, { INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) }, { INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) }, From 5394dbcca8839bfb87bc65594170ba80f45054ec Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 013/546] xilinx_spips: Move FlashCMD, XilinxQSPIPS and XilinxSPIPSClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the FlashCMD enum, XilinxQSPIPS and XilinxSPIPSClass structures to the header for consistency (struct XilinxSPIPS is found there). Also move out a define and remove two double included headers (while touching the code). Finally, add 4 byte address commands to the FlashCMD enum. Signed-off-by: Francisco Iglesias Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-6-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 35 ----------------------------------- include/hw/ssi/xilinx_spips.h | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index ef56d35f2c..559fa79e88 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -27,8 +27,6 @@ #include "sysemu/sysemu.h" #include "hw/ptimer.h" #include "qemu/log.h" -#include "qemu/fifo8.h" -#include "hw/ssi/ssi.h" #include "qemu/bitops.h" #include "hw/ssi/xilinx_spips.h" #include "qapi/error.h" @@ -116,44 +114,11 @@ /* 16MB per linear region */ #define LQSPI_ADDRESS_BITS 24 -/* Bite off 4k chunks at a time */ -#define LQSPI_CACHE_SIZE 1024 #define SNOOP_CHECKING 0xFF #define SNOOP_NONE 0xFE #define SNOOP_STRIPING 0 -typedef enum { - READ = 0x3, - FAST_READ = 0xb, - DOR = 0x3b, - QOR = 0x6b, - DIOR = 0xbb, - QIOR = 0xeb, - - PP = 0x2, - DPP = 0xa2, - QPP = 0x32, -} FlashCMD; - -typedef struct { - XilinxSPIPS parent_obj; - - uint8_t lqspi_buf[LQSPI_CACHE_SIZE]; - hwaddr lqspi_cached_addr; - Error *migration_blocker; - bool mmio_execution_enabled; -} XilinxQSPIPS; - -typedef struct XilinxSPIPSClass { - SysBusDeviceClass parent_class; - - const MemoryRegionOps *reg_ops; - - uint32_t rx_fifo_size; - uint32_t tx_fifo_size; -} XilinxSPIPSClass; - static inline int num_effective_busses(XilinxSPIPS *s) { return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS && diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index 06aa09629d..7f9e2fc687 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -32,6 +32,22 @@ typedef struct XilinxSPIPS XilinxSPIPS; #define XLNX_SPIPS_R_MAX (0x100 / 4) +/* Bite off 4k chunks at a time */ +#define LQSPI_CACHE_SIZE 1024 + +typedef enum { + READ = 0x3, READ_4 = 0x13, + FAST_READ = 0xb, FAST_READ_4 = 0x0c, + DOR = 0x3b, DOR_4 = 0x3c, + QOR = 0x6b, QOR_4 = 0x6c, + DIOR = 0xbb, DIOR_4 = 0xbc, + QIOR = 0xeb, QIOR_4 = 0xec, + + PP = 0x2, PP_4 = 0x12, + DPP = 0xa2, + QPP = 0x32, QPP_4 = 0x34, +} FlashCMD; + struct XilinxSPIPS { SysBusDevice parent_obj; @@ -56,6 +72,24 @@ struct XilinxSPIPS { uint32_t regs[XLNX_SPIPS_R_MAX]; }; +typedef struct { + XilinxSPIPS parent_obj; + + uint8_t lqspi_buf[LQSPI_CACHE_SIZE]; + hwaddr lqspi_cached_addr; + Error *migration_blocker; + bool mmio_execution_enabled; +} XilinxQSPIPS; + +typedef struct XilinxSPIPSClass { + SysBusDeviceClass parent_class; + + const MemoryRegionOps *reg_ops; + + uint32_t rx_fifo_size; + uint32_t tx_fifo_size; +} XilinxSPIPSClass; + #define TYPE_XILINX_SPIPS "xlnx.ps7-spi" #define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi" From c3725b8549dba4b47d17672654ca5a19a8281dfb Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 014/546] xilinx_spips: Update striping to be big-endian bit order Update striping functionality to be big-endian bit order (as according to the Zynq-7000 Technical Reference Manual). Output thereafter the even bits into the flash memory connected to the lower QSPI bus and the odd bits into the flash memory connected to the upper QSPI bus. Signed-off-by: Francisco Iglesias Acked-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-7-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 559fa79e88..231aa5b6fb 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -208,14 +208,14 @@ static void xilinx_spips_reset(DeviceState *d) xilinx_spips_update_cs_lines(s); } -/* N way (num) in place bit striper. Lay out row wise bits (LSB to MSB) +/* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB) * column wise (from element 0 to N-1). num is the length of x, and dir * reverses the direction of the transform. Best illustrated by example: * Each digit in the below array is a single bit (num == 3): * - * {{ 76543210, } ----- stripe (dir == false) -----> {{ FCheb630, } - * { hgfedcba, } { GDAfc741, } - * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { HEBgda52, }} + * {{ 76543210, } ----- stripe (dir == false) -----> {{ 741gdaFC, } + * { hgfedcba, } { 630fcHEB, } + * { HGFEDCBA, }} <---- upstripe (dir == true) ----- { 52hebGDA, }} */ static inline void stripe8(uint8_t *x, int num, bool dir) @@ -223,15 +223,15 @@ static inline void stripe8(uint8_t *x, int num, bool dir) uint8_t r[num]; memset(r, 0, sizeof(uint8_t) * num); int idx[2] = {0, 0}; - int bit[2] = {0, 0}; + int bit[2] = {0, 7}; int d = dir; for (idx[0] = 0; idx[0] < num; ++idx[0]) { - for (bit[0] = 0; bit[0] < 8; ++bit[0]) { - r[idx[d]] |= x[idx[!d]] & 1 << bit[!d] ? 1 << bit[d] : 0; + for (bit[0] = 7; bit[0] >= 0; bit[0]--) { + r[idx[!d]] |= x[idx[d]] & 1 << bit[d] ? 1 << bit[!d] : 0; idx[1] = (idx[1] + 1) % num; if (!idx[1]) { - bit[1]++; + bit[1]--; } } } @@ -266,8 +266,9 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) } for (i = 0; i < num_effective_busses(s); ++i) { + int bus = num_effective_busses(s) - 1 - i; DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]); - tx_rx[i] = ssi_transfer(s->spi[i], (uint32_t)tx_rx[i]); + tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]); DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]); } From ef06ca3946e284cb86fa712ba00f1c961e9456db Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 015/546] xilinx_spips: Add support for RX discard and RX drain Add support for the RX discard and RX drain functionality. Also transmit one byte per dummy cycle (to the flash memories) with commands that require these. Signed-off-by: Francisco Iglesias Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-8-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 177 +++++++++++++++++++++++++++++----- include/hw/ssi/xilinx_spips.h | 6 ++ 2 files changed, 160 insertions(+), 23 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 231aa5b6fb..691d48d36f 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -30,6 +30,7 @@ #include "qemu/bitops.h" #include "hw/ssi/xilinx_spips.h" #include "qapi/error.h" +#include "hw/register.h" #include "migration/blocker.h" #ifndef XILINX_SPIPS_ERR_DEBUG @@ -100,6 +101,14 @@ #define LQSPI_CFG_DUMMY_SHIFT 8 #define LQSPI_CFG_INST_CODE 0xFF +#define R_CMND (0xc0 / 4) + #define R_CMND_RXFIFO_DRAIN (1 << 19) + FIELD(CMND, PARTIAL_BYTE_LEN, 16, 3) +#define R_CMND_EXT_ADD (1 << 15) + FIELD(CMND, RX_DISCARD, 8, 7) + FIELD(CMND, DUMMY_CYCLES, 2, 6) +#define R_CMND_DMA_EN (1 << 1) +#define R_CMND_PUSH_WAIT (1 << 0) #define R_LQSPI_STS (0xA4 / 4) #define LQSPI_STS_WR_RECVD (1 << 1) @@ -116,7 +125,8 @@ #define LQSPI_ADDRESS_BITS 24 #define SNOOP_CHECKING 0xFF -#define SNOOP_NONE 0xFE +#define SNOOP_ADDR 0xF0 +#define SNOOP_NONE 0xEE #define SNOOP_STRIPING 0 static inline int num_effective_busses(XilinxSPIPS *s) @@ -146,9 +156,14 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) if (xilinx_spips_cs_is_set(s, i, field) && !found) { DB_PRINT_L(0, "selecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 0); + if (s->cs_lines_state[cs_to_set]) { + s->cs_lines_state[cs_to_set] = false; + s->rx_discard = ARRAY_FIELD_EX32(s->regs, CMND, RX_DISCARD); + } } else { DB_PRINT_L(0, "deselecting slave %d\n", i); qemu_set_irq(s->cs_lines[cs_to_set], 1); + s->cs_lines_state[cs_to_set] = true; } } if (xilinx_spips_cs_is_set(s, i, field)) { @@ -157,6 +172,10 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) } if (!found) { s->snoop_state = SNOOP_CHECKING; + s->cmd_dummies = 0; + s->link_state = 1; + s->link_state_next = 1; + s->link_state_next_when = 0; DB_PRINT_L(1, "moving to snoop check state\n"); } } @@ -203,7 +222,11 @@ static void xilinx_spips_reset(DeviceState *d) /* FIXME: move magic number definition somewhere sensible */ s->regs[R_MOD_ID] = 0x01090106; s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET; + s->link_state = 1; + s->link_state_next = 1; + s->link_state_next_when = 0; s->snoop_state = SNOOP_CHECKING; + s->cmd_dummies = 0; xilinx_spips_update_ixr(s); xilinx_spips_update_cs_lines(s); } @@ -238,14 +261,69 @@ static inline void stripe8(uint8_t *x, int num, bool dir) memcpy(x, r, sizeof(uint8_t) * num); } +static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command) +{ + if (!qs) { + /* The SPI device is not a QSPI device */ + return -1; + } + + switch (command) { /* check for dummies */ + case READ: /* no dummy bytes/cycles */ + case PP: + case DPP: + case QPP: + case READ_4: + case PP_4: + case QPP_4: + return 0; + case FAST_READ: + case DOR: + case QOR: + case DOR_4: + case QOR_4: + return 1; + case DIOR: + case FAST_READ_4: + case DIOR_4: + return 2; + case QIOR: + case QIOR_4: + return 5; + default: + return -1; + } +} + +static inline uint8_t get_addr_length(XilinxSPIPS *s, uint8_t cmd) +{ + switch (cmd) { + case PP_4: + case QPP_4: + case READ_4: + case QIOR_4: + case FAST_READ_4: + case DOR_4: + case QOR_4: + case DIOR_4: + return 4; + default: + return (s->regs[R_CMND] & R_CMND_EXT_ADD) ? 4 : 3; + } +} + static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) { int debug_level = 0; + XilinxQSPIPS *q = (XilinxQSPIPS *) object_dynamic_cast(OBJECT(s), + TYPE_XILINX_QSPIPS); for (;;) { int i; uint8_t tx = 0; uint8_t tx_rx[num_effective_busses(s)]; + uint8_t dummy_cycles = 0; + uint8_t addr_length; if (fifo8_is_empty(&s->tx_fifo)) { if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) { @@ -258,54 +336,102 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) tx_rx[i] = fifo8_pop(&s->tx_fifo); } stripe8(tx_rx, num_effective_busses(s), false); - } else { + } else if (s->snoop_state >= SNOOP_ADDR) { tx = fifo8_pop(&s->tx_fifo); for (i = 0; i < num_effective_busses(s); ++i) { tx_rx[i] = tx; } + } else { + /* Extract a dummy byte and generate dummy cycles according to the + * link state */ + tx = fifo8_pop(&s->tx_fifo); + dummy_cycles = 8 / s->link_state; } for (i = 0; i < num_effective_busses(s); ++i) { int bus = num_effective_busses(s) - 1 - i; - DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]); - tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]); - DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]); + if (dummy_cycles) { + int d; + for (d = 0; d < dummy_cycles; ++d) { + tx_rx[0] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[0]); + } + } else { + DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]); + tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]); + DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]); + } } - if (fifo8_is_full(&s->rx_fifo)) { + if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) { + DB_PRINT_L(debug_level, "dircarding drained rx byte\n"); + /* Do nothing */ + } else if (s->rx_discard) { + DB_PRINT_L(debug_level, "dircarding discarded rx byte\n"); + s->rx_discard -= 8 / s->link_state; + } else if (fifo8_is_full(&s->rx_fifo)) { s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW; DB_PRINT_L(0, "rx FIFO overflow"); } else if (s->snoop_state == SNOOP_STRIPING) { stripe8(tx_rx, num_effective_busses(s), true); for (i = 0; i < num_effective_busses(s); ++i) { fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]); + DB_PRINT_L(debug_level, "pushing striped rx byte\n"); } } else { + DB_PRINT_L(debug_level, "pushing unstriped rx byte\n"); fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]); } + if (s->link_state_next_when) { + s->link_state_next_when--; + if (!s->link_state_next_when) { + s->link_state = s->link_state_next; + } + } + DB_PRINT_L(debug_level, "initial snoop state: %x\n", (unsigned)s->snoop_state); switch (s->snoop_state) { case (SNOOP_CHECKING): - switch (tx) { /* new instruction code */ - case READ: /* 3 address bytes, no dummy bytes/cycles */ - case PP: - case DPP: - case QPP: - s->snoop_state = 3; - break; - case FAST_READ: /* 3 address bytes, 1 dummy byte */ - case DOR: - case QOR: - case DIOR: /* FIXME: these vary between vendor - set to spansion */ - s->snoop_state = 4; - break; - case QIOR: /* 3 address bytes, 2 dummy bytes */ - s->snoop_state = 6; - break; - default: + /* Store the count of dummy bytes in the txfifo */ + s->cmd_dummies = xilinx_spips_num_dummies(q, tx); + addr_length = get_addr_length(s, tx); + if (s->cmd_dummies < 0) { s->snoop_state = SNOOP_NONE; + } else { + s->snoop_state = SNOOP_ADDR + addr_length - 1; + } + switch (tx) { + case DPP: + case DOR: + case DOR_4: + s->link_state_next = 2; + s->link_state_next_when = addr_length + s->cmd_dummies; + break; + case QPP: + case QPP_4: + case QOR: + case QOR_4: + s->link_state_next = 4; + s->link_state_next_when = addr_length + s->cmd_dummies; + break; + case DIOR: + case DIOR_4: + s->link_state = 2; + break; + case QIOR: + case QIOR_4: + s->link_state = 4; + break; + } + break; + case (SNOOP_ADDR): + /* Address has been transmitted, transmit dummy cycles now if + * needed */ + if (s->cmd_dummies < 0) { + s->snoop_state = SNOOP_NONE; + } else { + s->snoop_state = s->cmd_dummies; } break; case (SNOOP_STRIPING): @@ -483,6 +609,7 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { XilinxQSPIPS *q = XILINX_QSPIPS(opaque); + XilinxSPIPS *s = XILINX_SPIPS(opaque); xilinx_spips_write(opaque, addr, value, size); addr >>= 2; @@ -490,6 +617,9 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr, if (addr == R_LQSPI_CFG) { xilinx_qspips_invalidate_mmio_ptr(q); } + if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) { + fifo8_reset(&s->rx_fifo); + } } static const MemoryRegionOps qspips_ops = { @@ -632,6 +762,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) } s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses); + s->cs_lines_state = g_new0(bool, s->num_cs * s->num_busses); for (i = 0, cs = s->cs_lines; i < s->num_busses; ++i, cs += s->num_cs) { ssi_auto_connect_slaves(DEVICE(s), cs, s->spi[i]); } diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index 7f9e2fc687..bac90a53ce 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -61,13 +61,19 @@ struct XilinxSPIPS { uint8_t num_busses; uint8_t snoop_state; + int cmd_dummies; + uint8_t link_state; + uint8_t link_state_next; + uint8_t link_state_next_when; qemu_irq *cs_lines; + bool *cs_lines_state; SSIBus **spi; Fifo8 rx_fifo; Fifo8 tx_fifo; uint8_t num_txrx_bytes; + uint32_t rx_discard; uint32_t regs[XLNX_SPIPS_R_MAX]; }; From 2fdd171edf5661b10ade16f33c2c0b0ed13afdf5 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:21 +0000 Subject: [PATCH 016/546] xilinx_spips: Make tx/rx_data_bytes more generic and reusable Make tx/rx_data_bytes more generic so they can be reused (when adding support for the Zynqmp Generic QSPI). Signed-off-by: Francisco Iglesias Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-9-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 64 +++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 691d48d36f..4621dbbaad 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -47,7 +47,7 @@ /* config register */ #define R_CONFIG (0x00 / 4) #define IFMODE (1U << 31) -#define ENDIAN (1 << 26) +#define R_CONFIG_ENDIAN (1 << 26) #define MODEFAIL_GEN_EN (1 << 17) #define MAN_START_COM (1 << 16) #define MAN_START_EN (1 << 15) @@ -450,13 +450,28 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) } } -static inline void rx_data_bytes(XilinxSPIPS *s, uint8_t *value, int max) +static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be) +{ + int i; + for (i = 0; i < num && !fifo8_is_full(fifo); ++i) { + if (be) { + fifo8_push(fifo, (uint8_t)(value >> 24)); + value <<= 8; + } else { + fifo8_push(fifo, (uint8_t)value); + value >>= 8; + } + } +} + +static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max) { int i; - for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) { - value[i] = fifo8_pop(&s->rx_fifo); + for (i = 0; i < max && !fifo8_is_empty(fifo); ++i) { + value[i] = fifo8_pop(fifo); } + return max - i; } static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, @@ -466,6 +481,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, uint32_t mask = ~0; uint32_t ret; uint8_t rx_buf[4]; + int shortfall; addr >>= 2; switch (addr) { @@ -496,9 +512,13 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, break; case R_RX_DATA: memset(rx_buf, 0, sizeof(rx_buf)); - rx_data_bytes(s, rx_buf, s->num_txrx_bytes); - ret = s->regs[R_CONFIG] & ENDIAN ? cpu_to_be32(*(uint32_t *)rx_buf) - : cpu_to_le32(*(uint32_t *)rx_buf); + shortfall = rx_data_bytes(&s->rx_fifo, rx_buf, s->num_txrx_bytes); + ret = s->regs[R_CONFIG] & R_CONFIG_ENDIAN ? + cpu_to_be32(*(uint32_t *)rx_buf) : + cpu_to_le32(*(uint32_t *)rx_buf); + if (!(s->regs[R_CONFIG] & R_CONFIG_ENDIAN)) { + ret <<= 8 * shortfall; + } DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); xilinx_spips_update_ixr(s); return ret; @@ -509,20 +529,6 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, } -static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num) -{ - int i; - for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) { - if (s->regs[R_CONFIG] & ENDIAN) { - fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24)); - value <<= 8; - } else { - fifo8_push(&s->tx_fifo, (uint8_t)value); - value >>= 8; - } - } -} - static void xilinx_spips_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { @@ -563,16 +569,20 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, mask = 0; break; case R_TX_DATA: - tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes); + tx_data_bytes(&s->tx_fifo, (uint32_t)value, s->num_txrx_bytes, + s->regs[R_CONFIG] & R_CONFIG_ENDIAN); goto no_reg_update; case R_TXD1: - tx_data_bytes(s, (uint32_t)value, 1); + tx_data_bytes(&s->tx_fifo, (uint32_t)value, 1, + s->regs[R_CONFIG] & R_CONFIG_ENDIAN); goto no_reg_update; case R_TXD2: - tx_data_bytes(s, (uint32_t)value, 2); + tx_data_bytes(&s->tx_fifo, (uint32_t)value, 2, + s->regs[R_CONFIG] & R_CONFIG_ENDIAN); goto no_reg_update; case R_TXD3: - tx_data_bytes(s, (uint32_t)value, 3); + tx_data_bytes(&s->tx_fifo, (uint32_t)value, 3, + s->regs[R_CONFIG] & R_CONFIG_ENDIAN); goto no_reg_update; } s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); @@ -682,11 +692,11 @@ static void lqspi_load_cache(void *opaque, hwaddr addr) while (cache_entry < LQSPI_CACHE_SIZE) { for (i = 0; i < 64; ++i) { - tx_data_bytes(s, 0, 1); + tx_data_bytes(&s->tx_fifo, 0, 1, false); } xilinx_spips_flush_txfifo(s); for (i = 0; i < 64; ++i) { - rx_data_bytes(s, &q->lqspi_buf[cache_entry++], 1); + rx_data_bytes(&s->rx_fifo, &q->lqspi_buf[cache_entry++], 1); } } From 275e28cccc1a915cc1ac6bdf367aa71555593bb4 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 017/546] xilinx_spips: Add support for zero pumping Add support for zero pumping according to the transfer size register. Signed-off-by: Francisco Iglesias Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-10-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 47 +++++++++++++++++++++++++++++------ include/hw/ssi/xilinx_spips.h | 2 ++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 4621dbbaad..878b17ea6b 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -109,6 +109,7 @@ FIELD(CMND, DUMMY_CYCLES, 2, 6) #define R_CMND_DMA_EN (1 << 1) #define R_CMND_PUSH_WAIT (1 << 0) +#define R_TRANSFER_SIZE (0xc4 / 4) #define R_LQSPI_STS (0xA4 / 4) #define LQSPI_STS_WR_RECVD (1 << 1) @@ -227,6 +228,7 @@ static void xilinx_spips_reset(DeviceState *d) s->link_state_next_when = 0; s->snoop_state = SNOOP_CHECKING; s->cmd_dummies = 0; + s->man_start_com = false; xilinx_spips_update_ixr(s); xilinx_spips_update_cs_lines(s); } @@ -464,6 +466,41 @@ static inline void tx_data_bytes(Fifo8 *fifo, uint32_t value, int num, bool be) } } +static void xilinx_spips_check_zero_pump(XilinxSPIPS *s) +{ + if (!s->regs[R_TRANSFER_SIZE]) { + return; + } + if (!fifo8_is_empty(&s->tx_fifo) && s->regs[R_CMND] & R_CMND_PUSH_WAIT) { + return; + } + /* + * The zero pump must never fill tx fifo such that rx overflow is + * possible + */ + while (s->regs[R_TRANSFER_SIZE] && + s->rx_fifo.num + s->tx_fifo.num < RXFF_A_Q - 3) { + /* endianess just doesn't matter when zero pumping */ + tx_data_bytes(&s->tx_fifo, 0, 4, false); + s->regs[R_TRANSFER_SIZE] &= ~0x03ull; + s->regs[R_TRANSFER_SIZE] -= 4; + } +} + +static void xilinx_spips_check_flush(XilinxSPIPS *s) +{ + if (s->man_start_com || + (!fifo8_is_empty(&s->tx_fifo) && + !(s->regs[R_CONFIG] & MAN_START_EN))) { + xilinx_spips_check_zero_pump(s); + xilinx_spips_flush_txfifo(s); + } + if (fifo8_is_empty(&s->tx_fifo) && !s->regs[R_TRANSFER_SIZE]) { + s->man_start_com = false; + } + xilinx_spips_update_ixr(s); +} + static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max) { int i; @@ -533,7 +570,6 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { int mask = ~0; - int man_start_com = 0; XilinxSPIPS *s = opaque; DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value); @@ -541,8 +577,8 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, switch (addr) { case R_CONFIG: mask = ~(R_CONFIG_RSVD | MAN_START_COM); - if (value & MAN_START_COM) { - man_start_com = 1; + if ((value & MAN_START_COM) && (s->regs[R_CONFIG] & MAN_START_EN)) { + s->man_start_com = true; } break; case R_INTR_STATUS: @@ -588,10 +624,7 @@ static void xilinx_spips_write(void *opaque, hwaddr addr, s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask); no_reg_update: xilinx_spips_update_cs_lines(s); - if ((man_start_com && s->regs[R_CONFIG] & MAN_START_EN) || - (fifo8_is_empty(&s->tx_fifo) && s->regs[R_CONFIG] & MAN_START_EN)) { - xilinx_spips_flush_txfifo(s); - } + xilinx_spips_check_flush(s); xilinx_spips_update_cs_lines(s); xilinx_spips_update_ixr(s); } diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index bac90a53ce..ad2175ac5c 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -76,6 +76,8 @@ struct XilinxSPIPS { uint32_t rx_discard; uint32_t regs[XLNX_SPIPS_R_MAX]; + + bool man_start_com; }; typedef struct { From fbfaa5074c455c5d61c9242128e7789595d2327d Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 018/546] xilinx_spips: Add support for 4 byte addresses in the LQSPI Add support for 4 byte addresses in the LQSPI and correct LQSPI_CFG_SEP_BUS. Signed-off-by: Francisco Iglesias Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-11-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 878b17ea6b..ab54da8aa3 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -92,8 +92,9 @@ #define R_LQSPI_CFG_RESET 0x03A002EB #define LQSPI_CFG_LQ_MODE (1U << 31) #define LQSPI_CFG_TWO_MEM (1 << 30) -#define LQSPI_CFG_SEP_BUS (1 << 30) +#define LQSPI_CFG_SEP_BUS (1 << 29) #define LQSPI_CFG_U_PAGE (1 << 28) +#define LQSPI_CFG_ADDR4 (1 << 27) #define LQSPI_CFG_MODE_EN (1 << 25) #define LQSPI_CFG_MODE_WIDTH 8 #define LQSPI_CFG_MODE_SHIFT 16 @@ -702,6 +703,9 @@ static void lqspi_load_cache(void *opaque, hwaddr addr) fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE); /* read address */ DB_PRINT_L(0, "pushing read address %06x\n", flash_addr); + if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_ADDR4) { + fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 24)); + } fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16)); fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8)); fifo8_push(&s->tx_fifo, (uint8_t)flash_addr); From 2e1cf2c9685978193ef429cdb711bf50debea9d8 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 019/546] xilinx_spips: Don't set TX FIFO UNDERFLOW at cmd done Don't set TX FIFO UNDERFLOW interrupt after transmitting the commands. Also update interrupts after reading out the interrupt status. Signed-off-by: Francisco Iglesias Acked-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-12-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index ab54da8aa3..3805d8b46d 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -329,9 +329,6 @@ static void xilinx_spips_flush_txfifo(XilinxSPIPS *s) uint8_t addr_length; if (fifo8_is_empty(&s->tx_fifo)) { - if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) { - s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW; - } xilinx_spips_update_ixr(s); return; } else if (s->snoop_state == SNOOP_STRIPING) { @@ -530,6 +527,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, ret = s->regs[addr] & IXR_ALL; s->regs[addr] = 0; DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + xilinx_spips_update_ixr(s); return ret; case R_INTR_MASK: mask = IXR_ALL; From c95997a39de679a1ae29c2f0637ec07f0291fedc Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 020/546] xilinx_spips: Add support for the ZynqMP Generic QSPI Add support for the Zynq Ultrascale MPSoc Generic QSPI. Signed-off-by: Francisco Iglesias Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Message-id: 20171126231634.9531-13-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 2 +- hw/ssi/xilinx_spips.c | 577 +++++++++++++++++++++++++++++--- include/hw/ssi/xilinx_spips.h | 32 +- 3 files changed, 563 insertions(+), 48 deletions(-) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index d37edc4312..b0d6e65038 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -130,5 +130,5 @@ CONFIG_SMBIOS=y CONFIG_ASPEED_SOC=y CONFIG_GPIO_KEY=y CONFIG_MSF2=y - CONFIG_FW_CFG_DMA=y +CONFIG_XILINX_AXI=y diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 3805d8b46d..ad1b2ba79f 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -31,6 +31,7 @@ #include "hw/ssi/xilinx_spips.h" #include "qapi/error.h" #include "hw/register.h" +#include "sysemu/dma.h" #include "migration/blocker.h" #ifndef XILINX_SPIPS_ERR_DEBUG @@ -69,13 +70,30 @@ #define R_INTR_DIS (0x0C / 4) #define R_INTR_MASK (0x10 / 4) #define IXR_TX_FIFO_UNDERFLOW (1 << 6) +/* Poll timeout not implemented */ +#define IXR_RX_FIFO_EMPTY (1 << 11) +#define IXR_GENERIC_FIFO_FULL (1 << 10) +#define IXR_GENERIC_FIFO_NOT_FULL (1 << 9) +#define IXR_TX_FIFO_EMPTY (1 << 8) +#define IXR_GENERIC_FIFO_EMPTY (1 << 7) #define IXR_RX_FIFO_FULL (1 << 5) #define IXR_RX_FIFO_NOT_EMPTY (1 << 4) #define IXR_TX_FIFO_FULL (1 << 3) #define IXR_TX_FIFO_NOT_FULL (1 << 2) #define IXR_TX_FIFO_MODE_FAIL (1 << 1) #define IXR_RX_FIFO_OVERFLOW (1 << 0) -#define IXR_ALL ((IXR_TX_FIFO_UNDERFLOW<<1)-1) +#define IXR_ALL ((1 << 13) - 1) +#define GQSPI_IXR_MASK 0xFBE +#define IXR_SELF_CLEAR \ +(IXR_GENERIC_FIFO_EMPTY \ +| IXR_GENERIC_FIFO_FULL \ +| IXR_GENERIC_FIFO_NOT_FULL \ +| IXR_TX_FIFO_EMPTY \ +| IXR_TX_FIFO_FULL \ +| IXR_TX_FIFO_NOT_FULL \ +| IXR_RX_FIFO_EMPTY \ +| IXR_RX_FIFO_FULL \ +| IXR_RX_FIFO_NOT_EMPTY) #define R_EN (0x14 / 4) #define R_DELAY (0x18 / 4) @@ -116,9 +134,54 @@ #define R_MOD_ID (0xFC / 4) +#define R_GQSPI_SELECT (0x144 / 4) + FIELD(GQSPI_SELECT, GENERIC_QSPI_EN, 0, 1) +#define R_GQSPI_ISR (0x104 / 4) +#define R_GQSPI_IER (0x108 / 4) +#define R_GQSPI_IDR (0x10c / 4) +#define R_GQSPI_IMR (0x110 / 4) +#define R_GQSPI_TX_THRESH (0x128 / 4) +#define R_GQSPI_RX_THRESH (0x12c / 4) +#define R_GQSPI_CNFG (0x100 / 4) + FIELD(GQSPI_CNFG, MODE_EN, 30, 2) + FIELD(GQSPI_CNFG, GEN_FIFO_START_MODE, 29, 1) + FIELD(GQSPI_CNFG, GEN_FIFO_START, 28, 1) + FIELD(GQSPI_CNFG, ENDIAN, 26, 1) + /* Poll timeout not implemented */ + FIELD(GQSPI_CNFG, EN_POLL_TIMEOUT, 20, 1) + /* QEMU doesnt care about any of these last three */ + FIELD(GQSPI_CNFG, BR, 3, 3) + FIELD(GQSPI_CNFG, CPH, 2, 1) + FIELD(GQSPI_CNFG, CPL, 1, 1) +#define R_GQSPI_GEN_FIFO (0x140 / 4) +#define R_GQSPI_TXD (0x11c / 4) +#define R_GQSPI_RXD (0x120 / 4) +#define R_GQSPI_FIFO_CTRL (0x14c / 4) + FIELD(GQSPI_FIFO_CTRL, RX_FIFO_RESET, 2, 1) + FIELD(GQSPI_FIFO_CTRL, TX_FIFO_RESET, 1, 1) + FIELD(GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET, 0, 1) +#define R_GQSPI_GFIFO_THRESH (0x150 / 4) +#define R_GQSPI_DATA_STS (0x15c / 4) +/* We use the snapshot register to hold the core state for the currently + * or most recently executed command. So the generic fifo format is defined + * for the snapshot register + */ +#define R_GQSPI_GF_SNAPSHOT (0x160 / 4) + FIELD(GQSPI_GF_SNAPSHOT, POLL, 19, 1) + FIELD(GQSPI_GF_SNAPSHOT, STRIPE, 18, 1) + FIELD(GQSPI_GF_SNAPSHOT, RECIEVE, 17, 1) + FIELD(GQSPI_GF_SNAPSHOT, TRANSMIT, 16, 1) + FIELD(GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT, 14, 2) + FIELD(GQSPI_GF_SNAPSHOT, CHIP_SELECT, 12, 2) + FIELD(GQSPI_GF_SNAPSHOT, SPI_MODE, 10, 2) + FIELD(GQSPI_GF_SNAPSHOT, EXPONENT, 9, 1) + FIELD(GQSPI_GF_SNAPSHOT, DATA_XFER, 8, 1) + FIELD(GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA, 0, 8) +#define R_GQSPI_MOD_ID (0x168 / 4) +#define R_GQSPI_MOD_ID_VALUE 0x010A0000 /* size of TXRX FIFOs */ -#define RXFF_A 32 -#define TXFF_A 32 +#define RXFF_A (128) +#define TXFF_A (128) #define RXFF_A_Q (64 * 4) #define TXFF_A_Q (64 * 4) @@ -137,42 +200,22 @@ static inline int num_effective_busses(XilinxSPIPS *s) s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1; } -static inline bool xilinx_spips_cs_is_set(XilinxSPIPS *s, int i, int field) +static void xilinx_spips_update_cs(XilinxSPIPS *s, int field) { - return ~field & (1 << i) && (s->regs[R_CONFIG] & MANUAL_CS - || !fifo8_is_empty(&s->tx_fifo)); -} - -static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) -{ - int i, j; - bool found = false; - int field = s->regs[R_CONFIG] >> CS_SHIFT; + int i; for (i = 0; i < s->num_cs; i++) { - for (j = 0; j < num_effective_busses(s); j++) { - int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE); - int cs_to_set = (j * s->num_cs + i + upage) % - (s->num_cs * s->num_busses); + bool old_state = s->cs_lines_state[i]; + bool new_state = field & (1 << i); - if (xilinx_spips_cs_is_set(s, i, field) && !found) { - DB_PRINT_L(0, "selecting slave %d\n", i); - qemu_set_irq(s->cs_lines[cs_to_set], 0); - if (s->cs_lines_state[cs_to_set]) { - s->cs_lines_state[cs_to_set] = false; - s->rx_discard = ARRAY_FIELD_EX32(s->regs, CMND, RX_DISCARD); - } - } else { - DB_PRINT_L(0, "deselecting slave %d\n", i); - qemu_set_irq(s->cs_lines[cs_to_set], 1); - s->cs_lines_state[cs_to_set] = true; - } - } - if (xilinx_spips_cs_is_set(s, i, field)) { - found = true; + if (old_state != new_state) { + s->cs_lines_state[i] = new_state; + s->rx_discard = ARRAY_FIELD_EX32(s->regs, CMND, RX_DISCARD); + DB_PRINT_L(1, "%sselecting slave %d\n", new_state ? "" : "de", i); } + qemu_set_irq(s->cs_lines[i], !new_state); } - if (!found) { + if (!(field & ((1 << s->num_cs) - 1))) { s->snoop_state = SNOOP_CHECKING; s->cmd_dummies = 0; s->link_state = 1; @@ -182,21 +225,51 @@ static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) } } +static void xlnx_zynqmp_qspips_update_cs_lines(XlnxZynqMPQSPIPS *s) +{ + if (s->regs[R_GQSPI_GF_SNAPSHOT]) { + int field = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, CHIP_SELECT); + xilinx_spips_update_cs(XILINX_SPIPS(s), field); + } +} + +static void xilinx_spips_update_cs_lines(XilinxSPIPS *s) +{ + int field = ~((s->regs[R_CONFIG] & CS) >> CS_SHIFT); + + /* In dual parallel, mirror low CS to both */ + if (num_effective_busses(s) == 2) { + /* Single bit chip-select for qspi */ + field &= 0x1; + field |= field << 1; + /* Dual stack U-Page */ + } else if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM && + s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE) { + /* Single bit chip-select for qspi */ + field &= 0x1; + /* change from CS0 to CS1 */ + field <<= 1; + } + /* Auto CS */ + if (!(s->regs[R_CONFIG] & MANUAL_CS) && + fifo8_is_empty(&s->tx_fifo)) { + field = 0; + } + xilinx_spips_update_cs(s, field); +} + static void xilinx_spips_update_ixr(XilinxSPIPS *s) { - if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE) { - return; + if (!(s->regs[R_LQSPI_CFG] & LQSPI_CFG_LQ_MODE)) { + s->regs[R_INTR_STATUS] &= ~IXR_SELF_CLEAR; + s->regs[R_INTR_STATUS] |= + (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) | + (s->rx_fifo.num >= s->regs[R_RX_THRES] ? + IXR_RX_FIFO_NOT_EMPTY : 0) | + (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) | + (fifo8_is_empty(&s->tx_fifo) ? IXR_TX_FIFO_EMPTY : 0) | + (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0); } - /* These are set/cleared as they occur */ - s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW | - IXR_TX_FIFO_MODE_FAIL); - /* these are pure functions of fifo state, set them here */ - s->regs[R_INTR_STATUS] |= - (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) | - (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) | - (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) | - (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0); - /* drive external interrupt pin */ int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] & IXR_ALL); if (new_irqline != s->irqline) { @@ -205,6 +278,37 @@ static void xilinx_spips_update_ixr(XilinxSPIPS *s) } } +static void xlnx_zynqmp_qspips_update_ixr(XlnxZynqMPQSPIPS *s) +{ + uint32_t gqspi_int; + int new_irqline; + + s->regs[R_GQSPI_ISR] &= ~IXR_SELF_CLEAR; + s->regs[R_GQSPI_ISR] |= + (fifo32_is_empty(&s->fifo_g) ? IXR_GENERIC_FIFO_EMPTY : 0) | + (fifo32_is_full(&s->fifo_g) ? IXR_GENERIC_FIFO_FULL : 0) | + (s->fifo_g.fifo.num < s->regs[R_GQSPI_GFIFO_THRESH] ? + IXR_GENERIC_FIFO_NOT_FULL : 0) | + (fifo8_is_empty(&s->rx_fifo_g) ? IXR_RX_FIFO_EMPTY : 0) | + (fifo8_is_full(&s->rx_fifo_g) ? IXR_RX_FIFO_FULL : 0) | + (s->rx_fifo_g.num >= s->regs[R_GQSPI_RX_THRESH] ? + IXR_RX_FIFO_NOT_EMPTY : 0) | + (fifo8_is_empty(&s->tx_fifo_g) ? IXR_TX_FIFO_EMPTY : 0) | + (fifo8_is_full(&s->tx_fifo_g) ? IXR_TX_FIFO_FULL : 0) | + (s->tx_fifo_g.num < s->regs[R_GQSPI_TX_THRESH] ? + IXR_TX_FIFO_NOT_FULL : 0); + + /* GQSPI Interrupt Trigger Status */ + gqspi_int = (~s->regs[R_GQSPI_IMR]) & s->regs[R_GQSPI_ISR] & GQSPI_IXR_MASK; + new_irqline = !!(gqspi_int & IXR_ALL); + + /* drive external interrupt pin */ + if (new_irqline != s->gqspi_irqline) { + s->gqspi_irqline = new_irqline; + qemu_set_irq(XILINX_SPIPS(s)->irq, s->gqspi_irqline); + } +} + static void xilinx_spips_reset(DeviceState *d) { XilinxSPIPS *s = XILINX_SPIPS(d); @@ -234,6 +338,28 @@ static void xilinx_spips_reset(DeviceState *d) xilinx_spips_update_cs_lines(s); } +static void xlnx_zynqmp_qspips_reset(DeviceState *d) +{ + XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(d); + int i; + + xilinx_spips_reset(d); + + for (i = 0; i < XLNX_ZYNQMP_SPIPS_R_MAX; i++) { + s->regs[i] = 0; + } + fifo8_reset(&s->rx_fifo_g); + fifo8_reset(&s->rx_fifo_g); + fifo32_reset(&s->fifo_g); + s->regs[R_GQSPI_TX_THRESH] = 1; + s->regs[R_GQSPI_RX_THRESH] = 1; + s->regs[R_GQSPI_GFIFO_THRESH] = 1; + s->regs[R_GQSPI_IMR] = GQSPI_IXR_MASK; + s->man_start_com_g = false; + s->gqspi_irqline = 0; + xlnx_zynqmp_qspips_update_ixr(s); +} + /* N way (num) in place bit striper. Lay out row wise bits (MSB to LSB) * column wise (from element 0 to N-1). num is the length of x, and dir * reverses the direction of the transform. Best illustrated by example: @@ -264,6 +390,108 @@ static inline void stripe8(uint8_t *x, int num, bool dir) memcpy(x, r, sizeof(uint8_t) * num); } +static void xlnx_zynqmp_qspips_flush_fifo_g(XlnxZynqMPQSPIPS *s) +{ + while (s->regs[R_GQSPI_DATA_STS] || !fifo32_is_empty(&s->fifo_g)) { + uint8_t tx_rx[2] = { 0 }; + int num_stripes = 1; + uint8_t busses; + int i; + + if (!s->regs[R_GQSPI_DATA_STS]) { + uint8_t imm; + + s->regs[R_GQSPI_GF_SNAPSHOT] = fifo32_pop(&s->fifo_g); + DB_PRINT_L(0, "GQSPI command: %x\n", s->regs[R_GQSPI_GF_SNAPSHOT]); + if (!s->regs[R_GQSPI_GF_SNAPSHOT]) { + DB_PRINT_L(0, "Dummy GQSPI Delay Command Entry, Do nothing"); + continue; + } + xlnx_zynqmp_qspips_update_cs_lines(s); + + imm = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA); + if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) { + /* immedate transfer */ + if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) || + ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) { + s->regs[R_GQSPI_DATA_STS] = 1; + /* CS setup/hold - do nothing */ + } else { + s->regs[R_GQSPI_DATA_STS] = 0; + } + } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, EXPONENT)) { + if (imm > 31) { + qemu_log_mask(LOG_UNIMP, "QSPI exponential transfer too" + " long - 2 ^ %" PRId8 " requested\n", imm); + } + s->regs[R_GQSPI_DATA_STS] = 1ul << imm; + } else { + s->regs[R_GQSPI_DATA_STS] = imm; + } + } + /* Zero length transfer check */ + if (!s->regs[R_GQSPI_DATA_STS]) { + continue; + } + if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE) && + fifo8_is_full(&s->rx_fifo_g)) { + /* No space in RX fifo for transfer - try again later */ + return; + } + if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, STRIPE) && + (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT) || + ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE))) { + num_stripes = 2; + } + if (!ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_XFER)) { + tx_rx[0] = ARRAY_FIELD_EX32(s->regs, + GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA); + } else if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, TRANSMIT)) { + for (i = 0; i < num_stripes; ++i) { + if (!fifo8_is_empty(&s->tx_fifo_g)) { + tx_rx[i] = fifo8_pop(&s->tx_fifo_g); + s->tx_fifo_g_align++; + } else { + return; + } + } + } + if (num_stripes == 1) { + /* mirror */ + tx_rx[1] = tx_rx[0]; + } + busses = ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, DATA_BUS_SELECT); + for (i = 0; i < 2; ++i) { + DB_PRINT_L(1, "bus %d tx = %02x\n", i, tx_rx[i]); + tx_rx[i] = ssi_transfer(XILINX_SPIPS(s)->spi[i], tx_rx[i]); + DB_PRINT_L(1, "bus %d rx = %02x\n", i, tx_rx[i]); + } + if (s->regs[R_GQSPI_DATA_STS] > 1 && + busses == 0x3 && num_stripes == 2) { + s->regs[R_GQSPI_DATA_STS] -= 2; + } else if (s->regs[R_GQSPI_DATA_STS] > 0) { + s->regs[R_GQSPI_DATA_STS]--; + } + if (ARRAY_FIELD_EX32(s->regs, GQSPI_GF_SNAPSHOT, RECIEVE)) { + for (i = 0; i < 2; ++i) { + if (busses & (1 << i)) { + DB_PRINT_L(1, "bus %d push_byte = %02x\n", i, tx_rx[i]); + fifo8_push(&s->rx_fifo_g, tx_rx[i]); + s->rx_fifo_g_align++; + } + } + } + if (!s->regs[R_GQSPI_DATA_STS]) { + for (; s->tx_fifo_g_align % 4; s->tx_fifo_g_align++) { + fifo8_pop(&s->tx_fifo_g); + } + for (; s->rx_fifo_g_align % 4; s->rx_fifo_g_align++) { + fifo8_push(&s->rx_fifo_g, 0); + } + } + } +} + static int xilinx_spips_num_dummies(XilinxQSPIPS *qs, uint8_t command) { if (!qs) { @@ -499,6 +727,25 @@ static void xilinx_spips_check_flush(XilinxSPIPS *s) xilinx_spips_update_ixr(s); } +static void xlnx_zynqmp_qspips_check_flush(XlnxZynqMPQSPIPS *s) +{ + bool gqspi_has_work = s->regs[R_GQSPI_DATA_STS] || + !fifo32_is_empty(&s->fifo_g); + + if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) { + if (s->man_start_com_g || (gqspi_has_work && + !ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE))) { + xlnx_zynqmp_qspips_flush_fifo_g(s); + } + } else { + xilinx_spips_check_flush(XILINX_SPIPS(s)); + } + if (!gqspi_has_work) { + s->man_start_com_g = false; + } + xlnx_zynqmp_qspips_update_ixr(s); +} + static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max) { int i; @@ -509,6 +756,53 @@ static inline int rx_data_bytes(Fifo8 *fifo, uint8_t *value, int max) return max - i; } +static const void *pop_buf(Fifo8 *fifo, uint32_t max, uint32_t *num) +{ + void *ret; + + if (max == 0 || max > fifo->num) { + abort(); + } + *num = MIN(fifo->capacity - fifo->head, max); + ret = &fifo->data[fifo->head]; + fifo->head += *num; + fifo->head %= fifo->capacity; + fifo->num -= *num; + return ret; +} + +static void xlnx_zynqmp_qspips_notify(void *opaque) +{ + XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(opaque); + XilinxSPIPS *s = XILINX_SPIPS(rq); + Fifo8 *recv_fifo; + + if (ARRAY_FIELD_EX32(rq->regs, GQSPI_SELECT, GENERIC_QSPI_EN)) { + if (!(ARRAY_FIELD_EX32(rq->regs, GQSPI_CNFG, MODE_EN) == 2)) { + return; + } + recv_fifo = &rq->rx_fifo_g; + } else { + if (!(s->regs[R_CMND] & R_CMND_DMA_EN)) { + return; + } + recv_fifo = &s->rx_fifo; + } + while (recv_fifo->num >= 4 + && stream_can_push(rq->dma, xlnx_zynqmp_qspips_notify, rq)) + { + size_t ret; + uint32_t num; + const void *rxd = pop_buf(recv_fifo, 4, &num); + + memcpy(rq->dma_buf, rxd, num); + + ret = stream_push(rq->dma, rq->dma_buf, 4); + assert(ret == 4); + xlnx_zynqmp_qspips_check_flush(rq); + } +} + static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, unsigned size) { @@ -556,6 +850,7 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, ret <<= 8 * shortfall; } DB_PRINT_L(0, "addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret); + xilinx_spips_check_flush(s); xilinx_spips_update_ixr(s); return ret; } @@ -565,6 +860,43 @@ static uint64_t xilinx_spips_read(void *opaque, hwaddr addr, } +static uint64_t xlnx_zynqmp_qspips_read(void *opaque, + hwaddr addr, unsigned size) +{ + XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque); + uint32_t reg = addr / 4; + uint32_t ret; + uint8_t rx_buf[4]; + int shortfall; + + if (reg <= R_MOD_ID) { + return xilinx_spips_read(opaque, addr, size); + } else { + switch (reg) { + case R_GQSPI_RXD: + if (fifo8_is_empty(&s->rx_fifo_g)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Read from empty GQSPI RX FIFO\n"); + return 0; + } + memset(rx_buf, 0, sizeof(rx_buf)); + shortfall = rx_data_bytes(&s->rx_fifo_g, rx_buf, + XILINX_SPIPS(s)->num_txrx_bytes); + ret = ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN) ? + cpu_to_be32(*(uint32_t *)rx_buf) : + cpu_to_le32(*(uint32_t *)rx_buf); + if (!ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN)) { + ret <<= 8 * shortfall; + } + xlnx_zynqmp_qspips_check_flush(s); + xlnx_zynqmp_qspips_update_ixr(s); + return ret; + default: + return s->regs[reg]; + } + } +} + static void xilinx_spips_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { @@ -664,12 +996,81 @@ static void xilinx_qspips_write(void *opaque, hwaddr addr, } } +static void xlnx_zynqmp_qspips_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size) +{ + XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(opaque); + uint32_t reg = addr / 4; + + if (reg <= R_MOD_ID) { + xilinx_qspips_write(opaque, addr, value, size); + } else { + switch (reg) { + case R_GQSPI_CNFG: + if (FIELD_EX32(value, GQSPI_CNFG, GEN_FIFO_START) && + ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, GEN_FIFO_START_MODE)) { + s->man_start_com_g = true; + } + s->regs[reg] = value & ~(R_GQSPI_CNFG_GEN_FIFO_START_MASK); + break; + case R_GQSPI_GEN_FIFO: + if (!fifo32_is_full(&s->fifo_g)) { + fifo32_push(&s->fifo_g, value); + } + break; + case R_GQSPI_TXD: + tx_data_bytes(&s->tx_fifo_g, (uint32_t)value, 4, + ARRAY_FIELD_EX32(s->regs, GQSPI_CNFG, ENDIAN)); + break; + case R_GQSPI_FIFO_CTRL: + if (FIELD_EX32(value, GQSPI_FIFO_CTRL, GENERIC_FIFO_RESET)) { + fifo32_reset(&s->fifo_g); + } + if (FIELD_EX32(value, GQSPI_FIFO_CTRL, TX_FIFO_RESET)) { + fifo8_reset(&s->tx_fifo_g); + } + if (FIELD_EX32(value, GQSPI_FIFO_CTRL, RX_FIFO_RESET)) { + fifo8_reset(&s->rx_fifo_g); + } + break; + case R_GQSPI_IDR: + s->regs[R_GQSPI_IMR] |= value; + break; + case R_GQSPI_IER: + s->regs[R_GQSPI_IMR] &= ~value; + break; + case R_GQSPI_ISR: + s->regs[R_GQSPI_ISR] &= ~value; + break; + case R_GQSPI_IMR: + case R_GQSPI_RXD: + case R_GQSPI_GF_SNAPSHOT: + case R_GQSPI_MOD_ID: + break; + default: + s->regs[reg] = value; + break; + } + xlnx_zynqmp_qspips_update_cs_lines(s); + xlnx_zynqmp_qspips_check_flush(s); + xlnx_zynqmp_qspips_update_cs_lines(s); + xlnx_zynqmp_qspips_update_ixr(s); + } + xlnx_zynqmp_qspips_notify(s); +} + static const MemoryRegionOps qspips_ops = { .read = xilinx_spips_read, .write = xilinx_qspips_write, .endianness = DEVICE_LITTLE_ENDIAN, }; +static const MemoryRegionOps xlnx_zynqmp_qspips_ops = { + .read = xlnx_zynqmp_qspips_read, + .write = xlnx_zynqmp_qspips_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + #define LQSPI_CACHE_SIZE 1024 static void lqspi_load_cache(void *opaque, hwaddr addr) @@ -818,7 +1219,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp) } memory_region_init_io(&s->iomem, OBJECT(s), xsc->reg_ops, s, - "spi", XLNX_SPIPS_R_MAX * 4); + "spi", XLNX_ZYNQMP_SPIPS_R_MAX * 4); sysbus_init_mmio(sbd, &s->iomem); s->irqline = -1; @@ -856,6 +1257,28 @@ static void xilinx_qspips_realize(DeviceState *dev, Error **errp) } } +static void xlnx_zynqmp_qspips_realize(DeviceState *dev, Error **errp) +{ + XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(dev); + XilinxSPIPSClass *xsc = XILINX_SPIPS_GET_CLASS(s); + + xilinx_qspips_realize(dev, errp); + fifo8_create(&s->rx_fifo_g, xsc->rx_fifo_size); + fifo8_create(&s->tx_fifo_g, xsc->tx_fifo_size); + fifo32_create(&s->fifo_g, 32); +} + +static void xlnx_zynqmp_qspips_init(Object *obj) +{ + XlnxZynqMPQSPIPS *rq = XLNX_ZYNQMP_QSPIPS(obj); + + object_property_add_link(obj, "stream-connected-dma", TYPE_STREAM_SLAVE, + (Object **)&rq->dma, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, + NULL); +} + static int xilinx_spips_post_load(void *opaque, int version_id) { xilinx_spips_update_ixr((XilinxSPIPS *)opaque); @@ -877,6 +1300,46 @@ static const VMStateDescription vmstate_xilinx_spips = { } }; +static int xlnx_zynqmp_qspips_post_load(void *opaque, int version_id) +{ + XlnxZynqMPQSPIPS *s = (XlnxZynqMPQSPIPS *)opaque; + XilinxSPIPS *qs = XILINX_SPIPS(s); + + if (ARRAY_FIELD_EX32(s->regs, GQSPI_SELECT, GENERIC_QSPI_EN) && + fifo8_is_empty(&qs->rx_fifo) && fifo8_is_empty(&qs->tx_fifo)) { + xlnx_zynqmp_qspips_update_ixr(s); + xlnx_zynqmp_qspips_update_cs_lines(s); + } + return 0; +} + +static const VMStateDescription vmstate_xilinx_qspips = { + .name = "xilinx_qspips", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(parent_obj, XilinxQSPIPS, 0, + vmstate_xilinx_spips, XilinxSPIPS), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_xlnx_zynqmp_qspips = { + .name = "xlnx_zynqmp_qspips", + .version_id = 1, + .minimum_version_id = 1, + .post_load = xlnx_zynqmp_qspips_post_load, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(parent_obj, XlnxZynqMPQSPIPS, 0, + vmstate_xilinx_qspips, XilinxQSPIPS), + VMSTATE_FIFO8(tx_fifo_g, XlnxZynqMPQSPIPS), + VMSTATE_FIFO8(rx_fifo_g, XlnxZynqMPQSPIPS), + VMSTATE_FIFO32(fifo_g, XlnxZynqMPQSPIPS), + VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPQSPIPS, XLNX_ZYNQMP_SPIPS_R_MAX), + VMSTATE_END_OF_LIST() + } +}; + static Property xilinx_qspips_properties[] = { /* We had to turn this off for 2.10 as it is not compatible with migration. * It can be enabled but will prevent the device to be migrated. @@ -921,6 +1384,19 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data) xsc->tx_fifo_size = TXFF_A; } +static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, void * data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); + + dc->realize = xlnx_zynqmp_qspips_realize; + dc->reset = xlnx_zynqmp_qspips_reset; + dc->vmsd = &vmstate_xlnx_zynqmp_qspips; + xsc->reg_ops = &xlnx_zynqmp_qspips_ops; + xsc->rx_fifo_size = RXFF_A_Q; + xsc->tx_fifo_size = TXFF_A_Q; +} + static const TypeInfo xilinx_spips_info = { .name = TYPE_XILINX_SPIPS, .parent = TYPE_SYS_BUS_DEVICE, @@ -936,10 +1412,19 @@ static const TypeInfo xilinx_qspips_info = { .class_init = xilinx_qspips_class_init, }; +static const TypeInfo xlnx_zynqmp_qspips_info = { + .name = TYPE_XLNX_ZYNQMP_QSPIPS, + .parent = TYPE_XILINX_QSPIPS, + .instance_size = sizeof(XlnxZynqMPQSPIPS), + .instance_init = xlnx_zynqmp_qspips_init, + .class_init = xlnx_zynqmp_qspips_class_init, +}; + static void xilinx_spips_register_types(void) { type_register_static(&xilinx_spips_info); type_register_static(&xilinx_qspips_info); + type_register_static(&xlnx_zynqmp_qspips_info); } type_init(xilinx_spips_register_types) diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index ad2175ac5c..75fc94ce5d 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -26,11 +26,13 @@ #define XILINX_SPIPS_H #include "hw/ssi/ssi.h" -#include "qemu/fifo8.h" +#include "qemu/fifo32.h" +#include "hw/stream.h" typedef struct XilinxSPIPS XilinxSPIPS; #define XLNX_SPIPS_R_MAX (0x100 / 4) +#define XLNX_ZYNQMP_SPIPS_R_MAX (0x200 / 4) /* Bite off 4k chunks at a time */ #define LQSPI_CACHE_SIZE 1024 @@ -89,6 +91,30 @@ typedef struct { bool mmio_execution_enabled; } XilinxQSPIPS; +typedef struct { + XilinxQSPIPS parent_obj; + + StreamSlave *dma; + uint8_t dma_buf[4]; + int gqspi_irqline; + + uint32_t regs[XLNX_ZYNQMP_SPIPS_R_MAX]; + + /* GQSPI has seperate tx/rx fifos */ + Fifo8 rx_fifo_g; + Fifo8 tx_fifo_g; + Fifo32 fifo_g; + /* + * At the end of each generic command, misaligned extra bytes are discard + * or padded to tx and rx respectively to round it out (and avoid need for + * individual byte access. Since we use byte fifos, keep track of the + * alignment WRT to word access. + */ + uint8_t rx_fifo_g_align; + uint8_t tx_fifo_g_align; + bool man_start_com_g; +} XlnxZynqMPQSPIPS; + typedef struct XilinxSPIPSClass { SysBusDeviceClass parent_class; @@ -100,6 +126,7 @@ typedef struct XilinxSPIPSClass { #define TYPE_XILINX_SPIPS "xlnx.ps7-spi" #define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi" +#define TYPE_XLNX_ZYNQMP_QSPIPS "xlnx.usmp-gqspi" #define XILINX_SPIPS(obj) \ OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS) @@ -111,4 +138,7 @@ typedef struct XilinxSPIPSClass { #define XILINX_QSPIPS(obj) \ OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS) +#define XLNX_ZYNQMP_QSPIPS(obj) \ + OBJECT_CHECK(XlnxZynqMPQSPIPS, (obj), TYPE_XLNX_ZYNQMP_QSPIPS) + #endif /* XILINX_SPIPS_H */ From babc1f30090b8541c9669d4ba74eedf0ee2894d8 Mon Sep 17 00:00:00 2001 From: Francisco Iglesias Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 021/546] xlnx-zcu102: Add support for the ZynqMP QSPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the ZynqMP QSPI (consisting of the Generic QSPI and Legacy QSPI) and connect Numonyx n25q512a11 flashes to it. Signed-off-by: Francisco Iglesias Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Tested-by: Edgar E. Iglesias Reviewed-by: Philippe Mathieu-Daudé Message-id: 20171126231634.9531-14-frasse.iglesias@gmail.com Signed-off-by: Peter Maydell --- hw/arm/xlnx-zcu102.c | 23 +++++++++++++++++++++++ hw/arm/xlnx-zynqmp.c | 26 ++++++++++++++++++++++++++ include/hw/arm/xlnx-zynqmp.h | 5 +++++ 3 files changed, 54 insertions(+) diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index bbe7d046e4..b126cf148b 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -151,6 +151,29 @@ static void xlnx_zynqmp_init(XlnxZCU102 *s, MachineState *machine) sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line); } + for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_FLASH; i++) { + SSIBus *spi_bus; + DeviceState *flash_dev; + qemu_irq cs_line; + DriveInfo *dinfo = drive_get_next(IF_MTD); + int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS; + gchar *bus_name = g_strdup_printf("qspi%d", bus); + + spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); + g_free(bus_name); + + flash_dev = ssi_create_slave_no_init(spi_bus, "n25q512a11"); + if (dinfo) { + qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), + &error_fatal); + } + qdev_init_nofail(flash_dev); + + cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); + + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.qspi), i + 1, cs_line); + } + /* TODO create and connect IDE devices for ide_drive_get() */ xlnx_zcu102_binfo.ram_size = ram_size; diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index c707c66322..325642058b 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -40,6 +40,10 @@ #define SATA_ADDR 0xFD0C0000 #define SATA_NUM_PORTS 2 +#define QSPI_ADDR 0xff0f0000 +#define LQSPI_ADDR 0xc0000000 +#define QSPI_IRQ 15 + #define DP_ADDR 0xfd4a0000 #define DP_IRQ 113 @@ -171,6 +175,9 @@ static void xlnx_zynqmp_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default()); } + object_initialize(&s->qspi, sizeof(s->qspi), TYPE_XLNX_ZYNQMP_QSPIPS); + qdev_set_parent_bus(DEVICE(&s->qspi), sysbus_get_default()); + object_initialize(&s->dp, sizeof(s->dp), TYPE_XLNX_DP); qdev_set_parent_bus(DEVICE(&s->dp), sysbus_get_default()); @@ -411,6 +418,25 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) g_free(bus_name); } + object_property_set_bool(OBJECT(&s->qspi), true, "realized", &err); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 0, QSPI_ADDR); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->qspi), 1, LQSPI_ADDR); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->qspi), 0, gic_spi[QSPI_IRQ]); + + for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_BUS; i++) { + gchar *bus_name; + gchar *target_bus; + + /* Alias controller SPI bus to the SoC itself */ + bus_name = g_strdup_printf("qspi%d", i); + target_bus = g_strdup_printf("spi%d", i); + object_property_add_alias(OBJECT(s), bus_name, + OBJECT(&s->qspi), target_bus, + &error_abort); + g_free(bus_name); + g_free(target_bus); + } + object_property_set_bool(OBJECT(&s->dp), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 6eff81a995..3e6fb9b7bd 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -40,6 +40,10 @@ #define XLNX_ZYNQMP_NUM_SDHCI 2 #define XLNX_ZYNQMP_NUM_SPIS 2 +#define XLNX_ZYNQMP_NUM_QSPI_BUS 2 +#define XLNX_ZYNQMP_NUM_QSPI_BUS_CS 2 +#define XLNX_ZYNQMP_NUM_QSPI_FLASH 4 + #define XLNX_ZYNQMP_NUM_OCM_BANKS 4 #define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000 #define XLNX_ZYNQMP_OCM_RAM_SIZE 0x10000 @@ -83,6 +87,7 @@ typedef struct XlnxZynqMPState { SysbusAHCIState sata; SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI]; XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS]; + XlnxZynqMPQSPIPS qspi; XlnxDPState dp; XlnxDPDMAState dpdma; From 7e7244796bc8d69a277669bb4137980fd2527b13 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 022/546] hw/intc/arm_gicv3_its: Don't call post_load on reset From the very beginning, post_load() was called from common reset. This is not standard and obliged to discriminate the reset case from the restore case using the iidr value. Let's get rid of that call. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1511883692-11511-2-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_its_common.c | 2 -- hw/intc/arm_gicv3_its_kvm.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index f2cce597a9..2bd2f0f3c9 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -131,8 +131,6 @@ static void gicv3_its_common_reset(DeviceState *dev) s->creadr = 0; s->iidr = 0; memset(&s->baser, 0, sizeof(s->baser)); - - gicv3_its_post_load(s, 0); } static void gicv3_its_common_class_init(ObjectClass *klass, void *data) diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 6fb45dffd7..b1b322bc72 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -155,10 +155,6 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) { int i; - if (!s->iidr) { - return; - } - kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_IIDR, &s->iidr, true, &error_abort); From c9aedf8ca4b4c16641812c018770f5da3ebf640c Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 13 Dec 2017 17:59:22 +0000 Subject: [PATCH 023/546] hw/intc/arm_gicv3_its: Implement a minimalist reset At the moment the ITS is not properly reset and this causes various bugs on save/restore. We implement a minimalist reset through individual register writes but for kernel versions before v4.15 this fails voiding the vITS cache. We cannot claim we have a comprehensive reset (hence the error message) but that's better than nothing. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1511883692-11511-3-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_its_kvm.c | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index b1b322bc72..1c663ac28e 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -28,6 +28,16 @@ #define TYPE_KVM_ARM_ITS "arm-its-kvm" #define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS) +#define KVM_ARM_ITS_CLASS(klass) \ + OBJECT_CLASS_CHECK(KVMARMITSClass, (klass), TYPE_KVM_ARM_ITS) +#define KVM_ARM_ITS_GET_CLASS(obj) \ + OBJECT_GET_CLASS(KVMARMITSClass, (obj), TYPE_KVM_ARM_ITS) + +typedef struct KVMARMITSClass { + GICv3ITSCommonClass parent_class; + void (*parent_reset)(DeviceState *dev); +} KVMARMITSClass; + static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid) { @@ -186,6 +196,34 @@ static void kvm_arm_its_post_load(GICv3ITSState *s) GITS_CTLR, &s->ctlr, true, &error_abort); } +static void kvm_arm_its_reset(DeviceState *dev) +{ + GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); + KVMARMITSClass *c = KVM_ARM_ITS_GET_CLASS(s); + int i; + + c->parent_reset(dev); + + error_report("ITS KVM: full reset is not supported by QEMU"); + + if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR)) { + return; + } + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CTLR, &s->ctlr, true, &error_abort); + + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_CBASER, &s->cbaser, true, &error_abort); + + for (i = 0; i < 8; i++) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, + GITS_BASER + i * 8, &s->baser[i], true, + &error_abort); + } +} + static Property kvm_arm_its_props[] = { DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "kvm-arm-gicv3", GICv3State *), @@ -196,12 +234,15 @@ static void kvm_arm_its_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); + KVMARMITSClass *ic = KVM_ARM_ITS_CLASS(klass); dc->realize = kvm_arm_its_realize; dc->props = kvm_arm_its_props; + ic->parent_reset = dc->reset; icc->send_msi = kvm_its_send_msi; icc->pre_save = kvm_arm_its_pre_save; icc->post_load = kvm_arm_its_post_load; + dc->reset = kvm_arm_its_reset; } static const TypeInfo kvm_arm_its_info = { @@ -209,6 +250,7 @@ static const TypeInfo kvm_arm_its_info = { .parent = TYPE_ARM_GICV3_ITS_COMMON, .instance_size = sizeof(GICv3ITSState), .class_init = kvm_arm_its_class_init, + .class_size = sizeof(KVMARMITSClass), }; static void kvm_arm_its_register_types(void) From dd8739669f95b30653a3a05cb2e21da3f52894fa Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 024/546] linux-headers: update to 4.15-rc1 Update headers against v4.15-rc1. Signed-off-by: Eric Auger Message-id: 1511883692-11511-4-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- .../standard-headers/asm-s390/virtio-ccw.h | 1 + include/standard-headers/asm-x86/hyperv.h | 394 +----------------- .../linux/input-event-codes.h | 2 + include/standard-headers/linux/input.h | 1 + include/standard-headers/linux/pci_regs.h | 45 +- linux-headers/asm-arm/kvm.h | 8 + linux-headers/asm-arm/kvm_para.h | 1 + linux-headers/asm-arm/unistd.h | 2 + linux-headers/asm-arm64/kvm.h | 8 + linux-headers/asm-arm64/unistd.h | 1 + linux-headers/asm-powerpc/epapr_hcalls.h | 1 + linux-headers/asm-powerpc/kvm.h | 1 + linux-headers/asm-powerpc/kvm_para.h | 1 + linux-headers/asm-powerpc/unistd.h | 1 + linux-headers/asm-s390/kvm.h | 1 + linux-headers/asm-s390/kvm_para.h | 1 + linux-headers/asm-s390/unistd.h | 4 +- linux-headers/asm-x86/kvm.h | 1 + linux-headers/asm-x86/kvm_para.h | 2 +- linux-headers/asm-x86/unistd.h | 1 + linux-headers/linux/kvm.h | 2 + linux-headers/linux/kvm_para.h | 1 + linux-headers/linux/psci.h | 1 + linux-headers/linux/userfaultfd.h | 1 + linux-headers/linux/vfio.h | 1 + linux-headers/linux/vfio_ccw.h | 1 + linux-headers/linux/vhost.h | 1 + 27 files changed, 74 insertions(+), 411 deletions(-) diff --git a/include/standard-headers/asm-s390/virtio-ccw.h b/include/standard-headers/asm-s390/virtio-ccw.h index a9a4ebf79f..967aad3901 100644 --- a/include/standard-headers/asm-s390/virtio-ccw.h +++ b/include/standard-headers/asm-s390/virtio-ccw.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Definitions for virtio-ccw devices. * diff --git a/include/standard-headers/asm-x86/hyperv.h b/include/standard-headers/asm-x86/hyperv.h index 5f95d5ed02..ce87d0c344 100644 --- a/include/standard-headers/asm-x86/hyperv.h +++ b/include/standard-headers/asm-x86/hyperv.h @@ -1,393 +1 @@ -#ifndef _ASM_X86_HYPERV_H -#define _ASM_X86_HYPERV_H - -#include "standard-headers/linux/types.h" - -/* - * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent - * is set by CPUID(HvCpuIdFunctionVersionAndFeatures). - */ -#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS 0x40000000 -#define HYPERV_CPUID_INTERFACE 0x40000001 -#define HYPERV_CPUID_VERSION 0x40000002 -#define HYPERV_CPUID_FEATURES 0x40000003 -#define HYPERV_CPUID_ENLIGHTMENT_INFO 0x40000004 -#define HYPERV_CPUID_IMPLEMENT_LIMITS 0x40000005 - -#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000 -#define HYPERV_CPUID_MIN 0x40000005 -#define HYPERV_CPUID_MAX 0x4000ffff - -/* - * Feature identification. EAX indicates which features are available - * to the partition based upon the current partition privileges. - */ - -/* VP Runtime (HV_X64_MSR_VP_RUNTIME) available */ -#define HV_X64_MSR_VP_RUNTIME_AVAILABLE (1 << 0) -/* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/ -#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1) -/* Partition reference TSC MSR is available */ -#define HV_X64_MSR_REFERENCE_TSC_AVAILABLE (1 << 9) - -/* A partition's reference time stamp counter (TSC) page */ -#define HV_X64_MSR_REFERENCE_TSC 0x40000021 - -/* - * There is a single feature flag that signifies if the partition has access - * to MSRs with local APIC and TSC frequencies. - */ -#define HV_X64_ACCESS_FREQUENCY_MSRS (1 << 11) - -/* - * Basic SynIC MSRs (HV_X64_MSR_SCONTROL through HV_X64_MSR_EOM - * and HV_X64_MSR_SINT0 through HV_X64_MSR_SINT15) available - */ -#define HV_X64_MSR_SYNIC_AVAILABLE (1 << 2) -/* - * Synthetic Timer MSRs (HV_X64_MSR_STIMER0_CONFIG through - * HV_X64_MSR_STIMER3_COUNT) available - */ -#define HV_X64_MSR_SYNTIMER_AVAILABLE (1 << 3) -/* - * APIC access MSRs (HV_X64_MSR_EOI, HV_X64_MSR_ICR and HV_X64_MSR_TPR) - * are available - */ -#define HV_X64_MSR_APIC_ACCESS_AVAILABLE (1 << 4) -/* Hypercall MSRs (HV_X64_MSR_GUEST_OS_ID and HV_X64_MSR_HYPERCALL) available*/ -#define HV_X64_MSR_HYPERCALL_AVAILABLE (1 << 5) -/* Access virtual processor index MSR (HV_X64_MSR_VP_INDEX) available*/ -#define HV_X64_MSR_VP_INDEX_AVAILABLE (1 << 6) -/* Virtual system reset MSR (HV_X64_MSR_RESET) is available*/ -#define HV_X64_MSR_RESET_AVAILABLE (1 << 7) - /* - * Access statistics pages MSRs (HV_X64_MSR_STATS_PARTITION_RETAIL_PAGE, - * HV_X64_MSR_STATS_PARTITION_INTERNAL_PAGE, HV_X64_MSR_STATS_VP_RETAIL_PAGE, - * HV_X64_MSR_STATS_VP_INTERNAL_PAGE) available - */ -#define HV_X64_MSR_STAT_PAGES_AVAILABLE (1 << 8) - -/* Frequency MSRs available */ -#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE (1 << 8) - -/* Crash MSR available */ -#define HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE (1 << 10) - -/* - * Feature identification: EBX indicates which flags were specified at - * partition creation. The format is the same as the partition creation - * flag structure defined in section Partition Creation Flags. - */ -#define HV_X64_CREATE_PARTITIONS (1 << 0) -#define HV_X64_ACCESS_PARTITION_ID (1 << 1) -#define HV_X64_ACCESS_MEMORY_POOL (1 << 2) -#define HV_X64_ADJUST_MESSAGE_BUFFERS (1 << 3) -#define HV_X64_POST_MESSAGES (1 << 4) -#define HV_X64_SIGNAL_EVENTS (1 << 5) -#define HV_X64_CREATE_PORT (1 << 6) -#define HV_X64_CONNECT_PORT (1 << 7) -#define HV_X64_ACCESS_STATS (1 << 8) -#define HV_X64_DEBUGGING (1 << 11) -#define HV_X64_CPU_POWER_MANAGEMENT (1 << 12) -#define HV_X64_CONFIGURE_PROFILER (1 << 13) - -/* - * Feature identification. EDX indicates which miscellaneous features - * are available to the partition. - */ -/* The MWAIT instruction is available (per section MONITOR / MWAIT) */ -#define HV_X64_MWAIT_AVAILABLE (1 << 0) -/* Guest debugging support is available */ -#define HV_X64_GUEST_DEBUGGING_AVAILABLE (1 << 1) -/* Performance Monitor support is available*/ -#define HV_X64_PERF_MONITOR_AVAILABLE (1 << 2) -/* Support for physical CPU dynamic partitioning events is available*/ -#define HV_X64_CPU_DYNAMIC_PARTITIONING_AVAILABLE (1 << 3) -/* - * Support for passing hypercall input parameter block via XMM - * registers is available - */ -#define HV_X64_HYPERCALL_PARAMS_XMM_AVAILABLE (1 << 4) -/* Support for a virtual guest idle state is available */ -#define HV_X64_GUEST_IDLE_STATE_AVAILABLE (1 << 5) -/* Guest crash data handler available */ -#define HV_X64_GUEST_CRASH_MSR_AVAILABLE (1 << 10) - -/* - * Implementation recommendations. Indicates which behaviors the hypervisor - * recommends the OS implement for optimal performance. - */ - /* - * Recommend using hypercall for address space switches rather - * than MOV to CR3 instruction - */ -#define HV_X64_AS_SWITCH_RECOMMENDED (1 << 0) -/* Recommend using hypercall for local TLB flushes rather - * than INVLPG or MOV to CR3 instructions */ -#define HV_X64_LOCAL_TLB_FLUSH_RECOMMENDED (1 << 1) -/* - * Recommend using hypercall for remote TLB flushes rather - * than inter-processor interrupts - */ -#define HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED (1 << 2) -/* - * Recommend using MSRs for accessing APIC registers - * EOI, ICR and TPR rather than their memory-mapped counterparts - */ -#define HV_X64_APIC_ACCESS_RECOMMENDED (1 << 3) -/* Recommend using the hypervisor-provided MSR to initiate a system RESET */ -#define HV_X64_SYSTEM_RESET_RECOMMENDED (1 << 4) -/* - * Recommend using relaxed timing for this partition. If used, - * the VM should disable any watchdog timeouts that rely on the - * timely delivery of external interrupts - */ -#define HV_X64_RELAXED_TIMING_RECOMMENDED (1 << 5) - -/* - * Virtual APIC support - */ -#define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9) - -/* Recommend using the newer ExProcessorMasks interface */ -#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11) - -/* - * Crash notification flag. - */ -#define HV_CRASH_CTL_CRASH_NOTIFY (1ULL << 63) - -/* MSR used to identify the guest OS. */ -#define HV_X64_MSR_GUEST_OS_ID 0x40000000 - -/* MSR used to setup pages used to communicate with the hypervisor. */ -#define HV_X64_MSR_HYPERCALL 0x40000001 - -/* MSR used to provide vcpu index */ -#define HV_X64_MSR_VP_INDEX 0x40000002 - -/* MSR used to reset the guest OS. */ -#define HV_X64_MSR_RESET 0x40000003 - -/* MSR used to provide vcpu runtime in 100ns units */ -#define HV_X64_MSR_VP_RUNTIME 0x40000010 - -/* MSR used to read the per-partition time reference counter */ -#define HV_X64_MSR_TIME_REF_COUNT 0x40000020 - -/* MSR used to retrieve the TSC frequency */ -#define HV_X64_MSR_TSC_FREQUENCY 0x40000022 - -/* MSR used to retrieve the local APIC timer frequency */ -#define HV_X64_MSR_APIC_FREQUENCY 0x40000023 - -/* Define the virtual APIC registers */ -#define HV_X64_MSR_EOI 0x40000070 -#define HV_X64_MSR_ICR 0x40000071 -#define HV_X64_MSR_TPR 0x40000072 -#define HV_X64_MSR_APIC_ASSIST_PAGE 0x40000073 - -/* Define synthetic interrupt controller model specific registers. */ -#define HV_X64_MSR_SCONTROL 0x40000080 -#define HV_X64_MSR_SVERSION 0x40000081 -#define HV_X64_MSR_SIEFP 0x40000082 -#define HV_X64_MSR_SIMP 0x40000083 -#define HV_X64_MSR_EOM 0x40000084 -#define HV_X64_MSR_SINT0 0x40000090 -#define HV_X64_MSR_SINT1 0x40000091 -#define HV_X64_MSR_SINT2 0x40000092 -#define HV_X64_MSR_SINT3 0x40000093 -#define HV_X64_MSR_SINT4 0x40000094 -#define HV_X64_MSR_SINT5 0x40000095 -#define HV_X64_MSR_SINT6 0x40000096 -#define HV_X64_MSR_SINT7 0x40000097 -#define HV_X64_MSR_SINT8 0x40000098 -#define HV_X64_MSR_SINT9 0x40000099 -#define HV_X64_MSR_SINT10 0x4000009A -#define HV_X64_MSR_SINT11 0x4000009B -#define HV_X64_MSR_SINT12 0x4000009C -#define HV_X64_MSR_SINT13 0x4000009D -#define HV_X64_MSR_SINT14 0x4000009E -#define HV_X64_MSR_SINT15 0x4000009F - -/* - * Synthetic Timer MSRs. Four timers per vcpu. - */ -#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0 -#define HV_X64_MSR_STIMER0_COUNT 0x400000B1 -#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2 -#define HV_X64_MSR_STIMER1_COUNT 0x400000B3 -#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4 -#define HV_X64_MSR_STIMER2_COUNT 0x400000B5 -#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6 -#define HV_X64_MSR_STIMER3_COUNT 0x400000B7 - -/* Hyper-V guest crash notification MSR's */ -#define HV_X64_MSR_CRASH_P0 0x40000100 -#define HV_X64_MSR_CRASH_P1 0x40000101 -#define HV_X64_MSR_CRASH_P2 0x40000102 -#define HV_X64_MSR_CRASH_P3 0x40000103 -#define HV_X64_MSR_CRASH_P4 0x40000104 -#define HV_X64_MSR_CRASH_CTL 0x40000105 -#define HV_X64_MSR_CRASH_CTL_NOTIFY (1ULL << 63) -#define HV_X64_MSR_CRASH_PARAMS \ - (1 + (HV_X64_MSR_CRASH_P4 - HV_X64_MSR_CRASH_P0)) - -#define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001 -#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12 -#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_MASK \ - (~((1ull << HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT) - 1)) - -/* Declare the various hypercall operations. */ -#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002 -#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003 -#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 -#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013 -#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014 -#define HVCALL_POST_MESSAGE 0x005c -#define HVCALL_SIGNAL_EVENT 0x005d - -#define HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE 0x00000001 -#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT 12 -#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \ - (~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1)) - -#define HV_X64_MSR_TSC_REFERENCE_ENABLE 0x00000001 -#define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12 - -#define HV_PROCESSOR_POWER_STATE_C0 0 -#define HV_PROCESSOR_POWER_STATE_C1 1 -#define HV_PROCESSOR_POWER_STATE_C2 2 -#define HV_PROCESSOR_POWER_STATE_C3 3 - -#define HV_FLUSH_ALL_PROCESSORS BIT(0) -#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1) -#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2) -#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3) - -enum HV_GENERIC_SET_FORMAT { - HV_GENERIC_SET_SPARCE_4K, - HV_GENERIC_SET_ALL, -}; - -/* hypercall status code */ -#define HV_STATUS_SUCCESS 0 -#define HV_STATUS_INVALID_HYPERCALL_CODE 2 -#define HV_STATUS_INVALID_HYPERCALL_INPUT 3 -#define HV_STATUS_INVALID_ALIGNMENT 4 -#define HV_STATUS_INSUFFICIENT_MEMORY 11 -#define HV_STATUS_INVALID_CONNECTION_ID 18 -#define HV_STATUS_INSUFFICIENT_BUFFERS 19 - -typedef struct _HV_REFERENCE_TSC_PAGE { - uint32_t tsc_sequence; - uint32_t res1; - uint64_t tsc_scale; - int64_t tsc_offset; -} HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE; - -/* Define the number of synthetic interrupt sources. */ -#define HV_SYNIC_SINT_COUNT (16) -/* Define the expected SynIC version. */ -#define HV_SYNIC_VERSION_1 (0x1) - -#define HV_SYNIC_CONTROL_ENABLE (1ULL << 0) -#define HV_SYNIC_SIMP_ENABLE (1ULL << 0) -#define HV_SYNIC_SIEFP_ENABLE (1ULL << 0) -#define HV_SYNIC_SINT_MASKED (1ULL << 16) -#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17) -#define HV_SYNIC_SINT_VECTOR_MASK (0xFF) - -#define HV_SYNIC_STIMER_COUNT (4) - -/* Define synthetic interrupt controller message constants. */ -#define HV_MESSAGE_SIZE (256) -#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240) -#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30) - -/* Define hypervisor message types. */ -enum hv_message_type { - HVMSG_NONE = 0x00000000, - - /* Memory access messages. */ - HVMSG_UNMAPPED_GPA = 0x80000000, - HVMSG_GPA_INTERCEPT = 0x80000001, - - /* Timer notification messages. */ - HVMSG_TIMER_EXPIRED = 0x80000010, - - /* Error messages. */ - HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020, - HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021, - HVMSG_UNSUPPORTED_FEATURE = 0x80000022, - - /* Trace buffer complete messages. */ - HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040, - - /* Platform-specific processor intercept messages. */ - HVMSG_X64_IOPORT_INTERCEPT = 0x80010000, - HVMSG_X64_MSR_INTERCEPT = 0x80010001, - HVMSG_X64_CPUID_INTERCEPT = 0x80010002, - HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003, - HVMSG_X64_APIC_EOI = 0x80010004, - HVMSG_X64_LEGACY_FP_ERROR = 0x80010005 -}; - -/* Define synthetic interrupt controller message flags. */ -union hv_message_flags { - uint8_t asu8; - struct { - uint8_t msg_pending:1; - uint8_t reserved:7; - }; -}; - -/* Define port identifier type. */ -union hv_port_id { - uint32_t asu32; - struct { - uint32_t id:24; - uint32_t reserved:8; - } u; -}; - -/* Define synthetic interrupt controller message header. */ -struct hv_message_header { - uint32_t message_type; - uint8_t payload_size; - union hv_message_flags message_flags; - uint8_t reserved[2]; - union { - uint64_t sender; - union hv_port_id port; - }; -}; - -/* Define synthetic interrupt controller message format. */ -struct hv_message { - struct hv_message_header header; - union { - uint64_t payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT]; - } u; -}; - -/* Define the synthetic interrupt message page layout. */ -struct hv_message_page { - struct hv_message sint_message[HV_SYNIC_SINT_COUNT]; -}; - -/* Define timer message payload structure. */ -struct hv_timer_message_payload { - uint32_t timer_index; - uint32_t reserved; - uint64_t expiration_time; /* When the timer expired */ - uint64_t delivery_time; /* When the message was delivered */ -}; - -#define HV_STIMER_ENABLE (1ULL << 0) -#define HV_STIMER_PERIODIC (1ULL << 1) -#define HV_STIMER_LAZY (1ULL << 2) -#define HV_STIMER_AUTOENABLE (1ULL << 3) -#define HV_STIMER_SINT(config) (uint8_t)(((config) >> 16) & 0x0F) - -#endif + /* this is a temporary placeholder until kvm_para.h stops including it */ diff --git a/include/standard-headers/linux/input-event-codes.h b/include/standard-headers/linux/input-event-codes.h index 2fa0f4ea6b..79841b543f 100644 --- a/include/standard-headers/linux/input-event-codes.h +++ b/include/standard-headers/linux/input-event-codes.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Input event codes * @@ -406,6 +407,7 @@ #define BTN_TOOL_MOUSE 0x146 #define BTN_TOOL_LENS 0x147 #define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ +#define BTN_STYLUS3 0x149 #define BTN_TOUCH 0x14a #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c diff --git a/include/standard-headers/linux/input.h b/include/standard-headers/linux/input.h index 666e201ddb..bc3e6d3d5b 100644 --- a/include/standard-headers/linux/input.h +++ b/include/standard-headers/linux/input.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (c) 1999-2002 Vojtech Pavlik * diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h index f8d5804592..70c2b2ade0 100644 --- a/include/standard-headers/linux/pci_regs.h +++ b/include/standard-headers/linux/pci_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * pci_regs.h * @@ -746,6 +747,7 @@ #define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First UNC is Fatal */ #define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ #define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ +#define PCI_ERR_ROOT_AER_IRQ 0xf8000000 /* Advanced Error Interrupt Message Number */ #define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ /* Virtual Channel */ @@ -939,9 +941,13 @@ #define PCI_SATA_SIZEOF_LONG 16 /* Resizable BARs */ +#define PCI_REBAR_CAP 4 /* capability register */ +#define PCI_REBAR_CAP_SIZES 0x00FFFFF0 /* supported BAR sizes */ #define PCI_REBAR_CTRL 8 /* control register */ -#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */ -#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */ +#define PCI_REBAR_CTRL_BAR_IDX 0x00000007 /* BAR index */ +#define PCI_REBAR_CTRL_NBAR_MASK 0x000000E0 /* # of resizable BARs */ +#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # of BARs */ +#define PCI_REBAR_CTRL_BAR_SIZE 0x00001F00 /* BAR size */ /* Dynamic Power Allocation */ #define PCI_DPA_CAP 4 /* capability register */ @@ -960,6 +966,7 @@ /* Downstream Port Containment */ #define PCI_EXP_DPC_CAP 4 /* DPC Capability */ +#define PCI_EXP_DPC_IRQ 0x1f /* DPC Interrupt Message Number */ #define PCI_EXP_DPC_CAP_RP_EXT 0x20 /* Root Port Extensions for DPC */ #define PCI_EXP_DPC_CAP_POISONED_TLP 0x40 /* Poisoned TLP Egress Blocking Supported */ #define PCI_EXP_DPC_CAP_SW_TRIGGER 0x80 /* Software Triggering Supported */ @@ -995,19 +1002,25 @@ #define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */ #define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */ -/* L1 PM Substates */ -#define PCI_L1SS_CAP 4 /* capability register */ -#define PCI_L1SS_CAP_PCIPM_L1_2 1 /* PCI PM L1.2 Support */ -#define PCI_L1SS_CAP_PCIPM_L1_1 2 /* PCI PM L1.1 Support */ -#define PCI_L1SS_CAP_ASPM_L1_2 4 /* ASPM L1.2 Support */ -#define PCI_L1SS_CAP_ASPM_L1_1 8 /* ASPM L1.1 Support */ -#define PCI_L1SS_CAP_L1_PM_SS 16 /* L1 PM Substates Support */ -#define PCI_L1SS_CTL1 8 /* Control Register 1 */ -#define PCI_L1SS_CTL1_PCIPM_L1_2 1 /* PCI PM L1.2 Enable */ -#define PCI_L1SS_CTL1_PCIPM_L1_1 2 /* PCI PM L1.1 Support */ -#define PCI_L1SS_CTL1_ASPM_L1_2 4 /* ASPM L1.2 Support */ -#define PCI_L1SS_CTL1_ASPM_L1_1 8 /* ASPM L1.1 Support */ -#define PCI_L1SS_CTL1_L1SS_MASK 0x0000000F -#define PCI_L1SS_CTL2 0xC /* Control Register 2 */ +/* ASPM L1 PM Substates */ +#define PCI_L1SS_CAP 0x04 /* Capabilities Register */ +#define PCI_L1SS_CAP_PCIPM_L1_2 0x00000001 /* PCI-PM L1.2 Supported */ +#define PCI_L1SS_CAP_PCIPM_L1_1 0x00000002 /* PCI-PM L1.1 Supported */ +#define PCI_L1SS_CAP_ASPM_L1_2 0x00000004 /* ASPM L1.2 Supported */ +#define PCI_L1SS_CAP_ASPM_L1_1 0x00000008 /* ASPM L1.1 Supported */ +#define PCI_L1SS_CAP_L1_PM_SS 0x00000010 /* L1 PM Substates Supported */ +#define PCI_L1SS_CAP_CM_RESTORE_TIME 0x0000ff00 /* Port Common_Mode_Restore_Time */ +#define PCI_L1SS_CAP_P_PWR_ON_SCALE 0x00030000 /* Port T_POWER_ON scale */ +#define PCI_L1SS_CAP_P_PWR_ON_VALUE 0x00f80000 /* Port T_POWER_ON value */ +#define PCI_L1SS_CTL1 0x08 /* Control 1 Register */ +#define PCI_L1SS_CTL1_PCIPM_L1_2 0x00000001 /* PCI-PM L1.2 Enable */ +#define PCI_L1SS_CTL1_PCIPM_L1_1 0x00000002 /* PCI-PM L1.1 Enable */ +#define PCI_L1SS_CTL1_ASPM_L1_2 0x00000004 /* ASPM L1.2 Enable */ +#define PCI_L1SS_CTL1_ASPM_L1_1 0x00000008 /* ASPM L1.1 Enable */ +#define PCI_L1SS_CTL1_L1SS_MASK 0x0000000f +#define PCI_L1SS_CTL1_CM_RESTORE_TIME 0x0000ff00 /* Common_Mode_Restore_Time */ +#define PCI_L1SS_CTL1_LTR_L12_TH_VALUE 0x03ff0000 /* LTR_L1.2_THRESHOLD_Value */ +#define PCI_L1SS_CTL1_LTR_L12_TH_SCALE 0xe0000000 /* LTR_L1.2_THRESHOLD_Scale */ +#define PCI_L1SS_CTL2 0x0c /* Control 2 Register */ #endif /* LINUX_PCI_REGS_H */ diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h index fa9fae8dc2..4392955081 100644 --- a/linux-headers/asm-arm/kvm.h +++ b/linux-headers/asm-arm/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (C) 2012 - Virtual Open Systems and Columbia University * Author: Christoffer Dall @@ -151,6 +152,12 @@ struct kvm_arch_memory_slot { (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) #define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) +/* PL1 Physical Timer Registers */ +#define KVM_REG_ARM_PTIMER_CTL ARM_CP15_REG32(0, 14, 2, 1) +#define KVM_REG_ARM_PTIMER_CNT ARM_CP15_REG64(0, 14) +#define KVM_REG_ARM_PTIMER_CVAL ARM_CP15_REG64(2, 14) + +/* Virtual Timer Registers */ #define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) #define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) #define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) @@ -215,6 +222,7 @@ struct kvm_arch_memory_slot { #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 +#define KVM_DEV_ARM_ITS_CTRL_RESET 4 /* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/linux-headers/asm-arm/kvm_para.h b/linux-headers/asm-arm/kvm_para.h index 14fab8f0b9..baacc4996d 100644 --- a/linux-headers/asm-arm/kvm_para.h +++ b/linux-headers/asm-arm/kvm_para.h @@ -1 +1,2 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #include diff --git a/linux-headers/asm-arm/unistd.h b/linux-headers/asm-arm/unistd.h index 155571b874..18b0825885 100644 --- a/linux-headers/asm-arm/unistd.h +++ b/linux-headers/asm-arm/unistd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * arch/arm/include/asm/unistd.h * @@ -35,5 +36,6 @@ #define __ARM_NR_usr26 (__ARM_NR_BASE+3) #define __ARM_NR_usr32 (__ARM_NR_BASE+4) #define __ARM_NR_set_tls (__ARM_NR_BASE+5) +#define __ARM_NR_get_tls (__ARM_NR_BASE+6) #endif /* __ASM_ARM_UNISTD_H */ diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h index d254700b08..4e80651efe 100644 --- a/linux-headers/asm-arm64/kvm.h +++ b/linux-headers/asm-arm64/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (C) 2012,2013 - ARM Ltd * Author: Marc Zyngier @@ -195,6 +196,12 @@ struct kvm_arch_memory_slot { #define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64) +/* Physical Timer EL0 Registers */ +#define KVM_REG_ARM_PTIMER_CTL ARM64_SYS_REG(3, 3, 14, 2, 1) +#define KVM_REG_ARM_PTIMER_CVAL ARM64_SYS_REG(3, 3, 14, 2, 2) +#define KVM_REG_ARM_PTIMER_CNT ARM64_SYS_REG(3, 3, 14, 0, 1) + +/* EL0 Virtual Timer Registers */ #define KVM_REG_ARM_TIMER_CTL ARM64_SYS_REG(3, 3, 14, 3, 1) #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) @@ -227,6 +234,7 @@ struct kvm_arch_memory_slot { #define KVM_DEV_ARM_ITS_SAVE_TABLES 1 #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 +#define KVM_DEV_ARM_ITS_CTRL_RESET 4 /* Device Control API on vcpu fd */ #define KVM_ARM_VCPU_PMU_V3_CTRL 0 diff --git a/linux-headers/asm-arm64/unistd.h b/linux-headers/asm-arm64/unistd.h index 043d17a213..5072cbd15c 100644 --- a/linux-headers/asm-arm64/unistd.h +++ b/linux-headers/asm-arm64/unistd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (C) 2012 ARM Ltd. * diff --git a/linux-headers/asm-powerpc/epapr_hcalls.h b/linux-headers/asm-powerpc/epapr_hcalls.h index 33b3f89f55..6cca559993 100644 --- a/linux-headers/asm-powerpc/epapr_hcalls.h +++ b/linux-headers/asm-powerpc/epapr_hcalls.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: ((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) */ /* * ePAPR hcall interface * diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index 8cf8f0c969..61d6049f4c 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h index 2abcc46382..9beb49cc10 100644 --- a/linux-headers/asm-powerpc/kvm_para.h +++ b/linux-headers/asm-powerpc/kvm_para.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as diff --git a/linux-headers/asm-powerpc/unistd.h b/linux-headers/asm-powerpc/unistd.h index a1786340e9..36abf58582 100644 --- a/linux-headers/asm-powerpc/unistd.h +++ b/linux-headers/asm-powerpc/unistd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ /* * This file contains the system call numbers. * diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h index 7b750ef7ee..32d372e977 100644 --- a/linux-headers/asm-s390/kvm.h +++ b/linux-headers/asm-s390/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_KVM_S390_H #define __LINUX_KVM_S390_H /* diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h index ff1f4e7b30..0dc86b3a7c 100644 --- a/linux-headers/asm-s390/kvm_para.h +++ b/linux-headers/asm-s390/kvm_para.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * User API definitions for paravirtual devices on s390 * diff --git a/linux-headers/asm-s390/unistd.h b/linux-headers/asm-s390/unistd.h index 65e7e59dbb..99223b874a 100644 --- a/linux-headers/asm-s390/unistd.h +++ b/linux-headers/asm-s390/unistd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * S390 version * @@ -315,7 +316,8 @@ #define __NR_pwritev2 377 #define __NR_s390_guarded_storage 378 #define __NR_statx 379 -#define NR_syscalls 380 +#define __NR_s390_sthyi 380 +#define NR_syscalls 381 /* * There are some system calls that are not present on 64 bit, some diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h index c2824d02ba..f3a960488e 100644 --- a/linux-headers/asm-x86/kvm.h +++ b/linux-headers/asm-x86/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _ASM_X86_KVM_H #define _ASM_X86_KVM_H diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h index cefa127d84..4c300f6aaa 100644 --- a/linux-headers/asm-x86/kvm_para.h +++ b/linux-headers/asm-x86/kvm_para.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _ASM_X86_KVM_PARA_H #define _ASM_X86_KVM_PARA_H @@ -109,5 +110,4 @@ struct kvm_vcpu_pv_apf_data { #define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK #define KVM_PV_EOI_DISABLED 0x0 - #endif /* _ASM_X86_KVM_PARA_H */ diff --git a/linux-headers/asm-x86/unistd.h b/linux-headers/asm-x86/unistd.h index 1f99b12843..c04f638154 100644 --- a/linux-headers/asm-x86/unistd.h +++ b/linux-headers/asm-x86/unistd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _ASM_X86_UNISTD_H #define _ASM_X86_UNISTD_H diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index dd8a91801e..ce6c2f11f4 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_KVM_H #define __LINUX_KVM_H @@ -930,6 +931,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_PPC_SMT_POSSIBLE 147 #define KVM_CAP_HYPERV_SYNIC2 148 #define KVM_CAP_HYPERV_VP_INDEX 149 +#define KVM_CAP_S390_AIS_MIGRATION 150 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h index 15b24ff6cf..8bcd0aa853 100644 --- a/linux-headers/linux/kvm_para.h +++ b/linux-headers/linux/kvm_para.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef __LINUX_KVM_PARA_H #define __LINUX_KVM_PARA_H diff --git a/linux-headers/linux/psci.h b/linux-headers/linux/psci.h index 08d443f7cf..ccd17731c6 100644 --- a/linux-headers/linux/psci.h +++ b/linux-headers/linux/psci.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * ARM Power State and Coordination Interface (PSCI) header * diff --git a/linux-headers/linux/userfaultfd.h b/linux-headers/linux/userfaultfd.h index b43cf0d415..ce78878d12 100644 --- a/linux-headers/linux/userfaultfd.h +++ b/linux-headers/linux/userfaultfd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * include/linux/userfaultfd.h * diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index 4e7ab4c52a..4312e961ff 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * VFIO API definition * diff --git a/linux-headers/linux/vfio_ccw.h b/linux-headers/linux/vfio_ccw.h index 3a565511ab..5bf96c3812 100644 --- a/linux-headers/linux/vfio_ccw.h +++ b/linux-headers/linux/vfio_ccw.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Interfaces for vfio-ccw * diff --git a/linux-headers/linux/vhost.h b/linux-headers/linux/vhost.h index 1e86a3dd0d..e336395d67 100644 --- a/linux-headers/linux/vhost.h +++ b/linux-headers/linux/vhost.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ #ifndef _LINUX_VHOST_H #define _LINUX_VHOST_H /* Userspace interface for in-kernel virtio accelerators. */ From ba2aecabefc5c06a91c12dd421564afd63f083ff Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 025/546] hw/intc/arm_gicv3_its: Implement full reset Voiding the ITS caches is not supposed to happen via individual register writes. So we introduced a dedicated ITS KVM device ioctl to perform a cold reset of the ITS: KVM_DEV_ARM_VGIC_GRP_CTRL/KVM_DEV_ARM_ITS_CTRL_RESET. Let's use this latter if the kernel supports it. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 1511883692-11511-5-git-send-email-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/intc/arm_gicv3_its_kvm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index 1c663ac28e..bf290b8bff 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -204,7 +204,14 @@ static void kvm_arm_its_reset(DeviceState *dev) c->parent_reset(dev); - error_report("ITS KVM: full reset is not supported by QEMU"); + if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_CTRL_RESET)) { + kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_ITS_CTRL_RESET, NULL, true, &error_abort); + return; + } + + error_report("ITS KVM: full reset is not supported by the host kernel"); if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS, GITS_CTLR)) { From 1169d3aa5b19adca9384d954d80e1f48da388284 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 026/546] target/arm: Handle SPSEL and current stack being out of sync in MSP/PSP reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For v8M it is possible for the CONTROL.SPSEL bit value and the current stack to be out of sync. This means we need to update the checks used in reads and writes of the PSP and MSP special registers to use v7m_using_psp() rather than directly checking the SPSEL bit in the control register. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-2-git-send-email-peter.maydell@linaro.org Reviewed-by: Philippe Mathieu-Daudé --- target/arm/helper.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 91a9300f11..88394d497b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9953,11 +9953,9 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) switch (reg) { case 8: /* MSP */ - return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ? - env->v7m.other_sp : env->regs[13]; + return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13]; case 9: /* PSP */ - return (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) ? - env->regs[13] : env->v7m.other_sp; + return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp; case 16: /* PRIMASK */ return env->v7m.primask[env->v7m.secure]; case 17: /* BASEPRI */ @@ -10059,14 +10057,14 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) } break; case 8: /* MSP */ - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) { + if (v7m_using_psp(env)) { env->v7m.other_sp = val; } else { env->regs[13] = val; } break; case 9: /* PSP */ - if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK) { + if (v7m_using_psp(env)) { env->regs[13] = val; } else { env->v7m.other_sp = val; From 83d7f86d3d27473c0aac79c1baaa5c2ab01b02d9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 027/546] target/arm: Allow explicit writes to CONTROL.SPSEL in Handler mode In ARMv7M the CPU ignores explicit writes to CONTROL.SPSEL in Handler mode. In v8M the behaviour is slightly different: writes to the bit are permitted but will have no effect. We've already done the hard work to handle the value in CONTROL.SPSEL being out of sync with what stack pointer is actually in use, so all we need to do to fix this last loose end is to update the condition we use to guard whether we call write_v7m_control_spsel() on the register write. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-3-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 88394d497b..f21c142602 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10091,8 +10091,11 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) * thread mode; other bits can be updated by any privileged code. * write_v7m_control_spsel() deals with updating the SPSEL bit in * env->v7m.control, so we only need update the others. + * For v7M, we must just ignore explicit writes to SPSEL in handler + * mode; for v8M the write is permitted but will have no effect. */ - if (!arm_v7m_is_handler_mode(env)) { + if (arm_feature(env, ARM_FEATURE_V8) || + !arm_v7m_is_handler_mode(env)) { write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0); } env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK; From 871bec7c44a453d9cab972ce1b5d12e1af0545ab Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 028/546] target/arm: Add missing M profile case to regime_is_user() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we added the ARMMMUIdx_MSUser MMU index we forgot to add it to the case statement in regime_is_user(), so we weren't treating it as unprivileged when doing MPU lookups. Correct the omission. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-4-git-send-email-peter.maydell@linaro.org Reviewed-by: Philippe Mathieu-Daudé --- target/arm/helper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index f21c142602..c4c8d5a7d2 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8016,6 +8016,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_MUser: + case ARMMMUIdx_MSUser: return true; default: return false; From 62593718d77c06ad2b5e942727cead40775d2395 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 029/546] target/arm: Split M profile MNegPri mmu index into user and priv For M profile, we currently have an mmu index MNegPri for "requested execution priority negative". This fails to distinguish "requested execution priority negative, privileged" from "requested execution priority negative, usermode", but the two can return different results for MPU lookups. Fix this by splitting MNegPri into MNegPriPriv and MNegPriUser, and similarly for the Secure equivalent MSNegPri. This takes us from 6 M profile MMU modes to 8, which means we need to bump NB_MMU_MODES; this is OK since the point where we are forced to reduce TLB sizes is 9 MMU modes. (It would in theory be possible to stick with 6 MMU indexes: {mpu-disabled,user,privileged} x {secure,nonsecure} since in the MPU-disabled case the result of an MPU lookup is always the same for both user and privileged code. However we would then need to rework the TB flags handling to put user/priv into the TB flags separately from the mmuidx. Adding an extra couple of mmu indexes is simpler.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-5-git-send-email-peter.maydell@linaro.org --- target/arm/cpu.h | 54 ++++++++++++++++++++++++++---------------- target/arm/helper.c | 11 +++++---- target/arm/internals.h | 6 +++-- target/arm/translate.c | 8 +++++-- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 89d49cdcb2..c42d62d479 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -112,7 +112,7 @@ enum { #define ARM_CPU_VIRQ 2 #define ARM_CPU_VFIQ 3 -#define NB_MMU_MODES 7 +#define NB_MMU_MODES 8 /* ARM-specific extra insn start words: * 1: Conditional execution bits * 2: Partial exception syndrome for data aborts @@ -2226,13 +2226,13 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * They have the following different MMU indexes: * User * Privileged - * Execution priority negative (this is like privileged, but the - * MPU HFNMIENA bit means that it may have different access permission - * check results to normal privileged code, so can't share a TLB). + * User, execution priority negative (ie the MPU HFNMIENA bit may apply) + * Privileged, execution priority negative (ditto) * If the CPU supports the v8M Security Extension then there are also: * Secure User * Secure Privileged - * Secure, execution priority negative + * Secure User, execution priority negative + * Secure Privileged, execution priority negative * * The ARMMMUIdx and the mmu index value used by the core QEMU TLB code * are not quite the same -- different CPU types (most notably M profile @@ -2251,11 +2251,18 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx, * The constant names here are patterned after the general style of the names * of the AT/ATS operations. * The values used are carefully arranged to make mmu_idx => EL lookup easy. + * For M profile we arrange them to have a bit for priv, a bit for negpri + * and a bit for secure. */ #define ARM_MMU_IDX_A 0x10 /* A profile */ #define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */ #define ARM_MMU_IDX_M 0x40 /* M profile */ +/* meanings of the bits for M profile mmu idx values */ +#define ARM_MMU_IDX_M_PRIV 0x1 +#define ARM_MMU_IDX_M_NEGPRI 0x2 +#define ARM_MMU_IDX_M_S 0x4 + #define ARM_MMU_IDX_TYPE_MASK (~0x7) #define ARM_MMU_IDX_COREIDX_MASK 0x7 @@ -2269,10 +2276,12 @@ typedef enum ARMMMUIdx { ARMMMUIdx_S2NS = 6 | ARM_MMU_IDX_A, ARMMMUIdx_MUser = 0 | ARM_MMU_IDX_M, ARMMMUIdx_MPriv = 1 | ARM_MMU_IDX_M, - ARMMMUIdx_MNegPri = 2 | ARM_MMU_IDX_M, - ARMMMUIdx_MSUser = 3 | ARM_MMU_IDX_M, - ARMMMUIdx_MSPriv = 4 | ARM_MMU_IDX_M, - ARMMMUIdx_MSNegPri = 5 | ARM_MMU_IDX_M, + ARMMMUIdx_MUserNegPri = 2 | ARM_MMU_IDX_M, + ARMMMUIdx_MPrivNegPri = 3 | ARM_MMU_IDX_M, + ARMMMUIdx_MSUser = 4 | ARM_MMU_IDX_M, + ARMMMUIdx_MSPriv = 5 | ARM_MMU_IDX_M, + ARMMMUIdx_MSUserNegPri = 6 | ARM_MMU_IDX_M, + ARMMMUIdx_MSPrivNegPri = 7 | ARM_MMU_IDX_M, /* Indexes below here don't have TLBs and are used only for AT system * instructions or for the first stage of an S12 page table walk. */ @@ -2293,10 +2302,12 @@ typedef enum ARMMMUIdxBit { ARMMMUIdxBit_S2NS = 1 << 6, ARMMMUIdxBit_MUser = 1 << 0, ARMMMUIdxBit_MPriv = 1 << 1, - ARMMMUIdxBit_MNegPri = 1 << 2, - ARMMMUIdxBit_MSUser = 1 << 3, - ARMMMUIdxBit_MSPriv = 1 << 4, - ARMMMUIdxBit_MSNegPri = 1 << 5, + ARMMMUIdxBit_MUserNegPri = 1 << 2, + ARMMMUIdxBit_MPrivNegPri = 1 << 3, + ARMMMUIdxBit_MSUser = 1 << 4, + ARMMMUIdxBit_MSPriv = 1 << 5, + ARMMMUIdxBit_MSUserNegPri = 1 << 6, + ARMMMUIdxBit_MSPrivNegPri = 1 << 7, } ARMMMUIdxBit; #define MMU_USER_IDX 0 @@ -2322,8 +2333,7 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) case ARM_MMU_IDX_A: return mmu_idx & 3; case ARM_MMU_IDX_M: - return (mmu_idx == ARMMMUIdx_MUser || mmu_idx == ARMMMUIdx_MSUser) - ? 0 : 1; + return mmu_idx & ARM_MMU_IDX_M_PRIV; default: g_assert_not_reached(); } @@ -2334,16 +2344,18 @@ static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate) { int el = arm_current_el(env); - ARMMMUIdx mmu_idx; + ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; - if (el == 0) { - mmu_idx = secstate ? ARMMMUIdx_MSUser : ARMMMUIdx_MUser; - } else { - mmu_idx = secstate ? ARMMMUIdx_MSPriv : ARMMMUIdx_MPriv; + if (el != 0) { + mmu_idx |= ARM_MMU_IDX_M_PRIV; } if (armv7m_nvic_neg_prio_requested(env->nvic, secstate)) { - mmu_idx = secstate ? ARMMMUIdx_MSNegPri : ARMMMUIdx_MNegPri; + mmu_idx |= ARM_MMU_IDX_M_NEGPRI; + } + + if (secstate) { + mmu_idx |= ARM_MMU_IDX_M_S; } return mmu_idx; diff --git a/target/arm/helper.c b/target/arm/helper.c index c4c8d5a7d2..70cf313260 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7856,11 +7856,13 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1SE1: case ARMMMUIdx_S1NSE0: case ARMMMUIdx_S1NSE1: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: case ARMMMUIdx_MUser: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: case ARMMMUIdx_MSUser: return 1; default: @@ -7883,8 +7885,7 @@ static inline bool regime_translation_disabled(CPUARMState *env, (R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) { case R_V7M_MPU_CTRL_ENABLE_MASK: /* Enabled, but not for HardFault and NMI */ - return mmu_idx == ARMMMUIdx_MNegPri || - mmu_idx == ARMMMUIdx_MSNegPri; + return mmu_idx & ARM_MMU_IDX_M_NEGPRI; case R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK: /* Enabled for all cases */ return false; @@ -8017,6 +8018,8 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1NSE0: case ARMMMUIdx_MUser: case ARMMMUIdx_MSUser: + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MSUserNegPri: return true; default: return false; diff --git a/target/arm/internals.h b/target/arm/internals.h index d9cc75e4c5..aa9c91b99f 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -544,15 +544,17 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx) case ARMMMUIdx_S1NSE1: case ARMMMUIdx_S1E2: case ARMMMUIdx_S2NS: + case ARMMMUIdx_MPrivNegPri: + case ARMMMUIdx_MUserNegPri: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: case ARMMMUIdx_MUser: return false; case ARMMMUIdx_S1E3: case ARMMMUIdx_S1SE0: case ARMMMUIdx_S1SE1: + case ARMMMUIdx_MSPrivNegPri: + case ARMMMUIdx_MSUserNegPri: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: case ARMMMUIdx_MSUser: return true; default: diff --git a/target/arm/translate.c b/target/arm/translate.c index f120932f44..50339e7bdd 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -159,12 +159,16 @@ static inline int get_a32_user_mem_index(DisasContext *s) return arm_to_core_mmu_idx(ARMMMUIdx_S1SE0); case ARMMMUIdx_MUser: case ARMMMUIdx_MPriv: - case ARMMMUIdx_MNegPri: return arm_to_core_mmu_idx(ARMMMUIdx_MUser); + case ARMMMUIdx_MUserNegPri: + case ARMMMUIdx_MPrivNegPri: + return arm_to_core_mmu_idx(ARMMMUIdx_MUserNegPri); case ARMMMUIdx_MSUser: case ARMMMUIdx_MSPriv: - case ARMMMUIdx_MSNegPri: return arm_to_core_mmu_idx(ARMMMUIdx_MSUser); + case ARMMMUIdx_MSUserNegPri: + case ARMMMUIdx_MSPrivNegPri: + return arm_to_core_mmu_idx(ARMMMUIdx_MSUserNegPri); case ARMMMUIdx_S2NS: default: g_assert_not_reached(); From ec8e3340286a87d3924c223d60ba5c994549f796 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:23 +0000 Subject: [PATCH 030/546] target/arm: Create new arm_v7m_mmu_idx_for_secstate_and_priv() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TT instruction is going to need to look up the MMU index for a specified security and privilege state. Refactor the existing arm_v7m_mmu_idx_for_secstate() into a version that lets you specify the privilege state and one that uses the current state of the CPU. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-6-git-send-email-peter.maydell@linaro.org Reviewed-by: Philippe Mathieu-Daudé --- target/arm/cpu.h | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c42d62d479..96316700dd 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2339,14 +2339,16 @@ static inline int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx) } } -/* Return the MMU index for a v7M CPU in the specified security state */ -static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, - bool secstate) +/* Return the MMU index for a v7M CPU in the specified security and + * privilege state + */ +static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate_and_priv(CPUARMState *env, + bool secstate, + bool priv) { - int el = arm_current_el(env); ARMMMUIdx mmu_idx = ARM_MMU_IDX_M; - if (el != 0) { + if (priv) { mmu_idx |= ARM_MMU_IDX_M_PRIV; } @@ -2361,6 +2363,15 @@ static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, return mmu_idx; } +/* Return the MMU index for a v7M CPU in the specified security state */ +static inline ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, + bool secstate) +{ + bool priv = arm_current_el(env) != 0; + + return arm_v7m_mmu_idx_for_secstate_and_priv(env, secstate, priv); +} + /* Determine the current mmu_idx to use for normal loads/stores */ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) { From 54317c0ff3a3c0f6b2c3a1d3c8b5d93686a86d24 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 031/546] target/arm: Factor MPU lookup code out of get_phys_addr_pmsav8() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the TT instruction we're going to need to do an MPU lookup that also tells us which MPU region the access hit. This requires us to do the MPU lookup without first doing the SAU security access check, so pull the MPU lookup parts of get_phys_addr_pmsav8() out into their own function. The TT instruction also needs to know the MPU region number which the lookup hit, so provide this information to the caller of the MPU lookup code, even though get_phys_addr_pmsav8() doesn't need to know it. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-7-git-send-email-peter.maydell@linaro.org Reviewed-by: Philippe Mathieu-Daudé --- target/arm/helper.c | 130 +++++++++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 51 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 70cf313260..9e7eaa1080 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9348,67 +9348,28 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, } } -static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, - MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, uint32_t *fsr) +static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, uint32_t *fsr, uint32_t *mregion) { + /* Perform a PMSAv8 MPU lookup (without also doing the SAU check + * that a full phys-to-virt translation does). + * mregion is (if not NULL) set to the region number which matched, + * or -1 if no region number is returned (MPU off, address did not + * hit a region, address hit in multiple regions). + */ ARMCPU *cpu = arm_env_get_cpu(env); bool is_user = regime_is_user(env, mmu_idx); uint32_t secure = regime_is_secure(env, mmu_idx); int n; int matchregion = -1; bool hit = false; - V8M_SAttributes sattrs = {}; *phys_ptr = address; *prot = 0; - - if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { - v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); - if (access_type == MMU_INST_FETCH) { - /* Instruction fetches always use the MMU bank and the - * transaction attribute determined by the fetch address, - * regardless of CPU state. This is painful for QEMU - * to handle, because it would mean we need to encode - * into the mmu_idx not just the (user, negpri) information - * for the current security state but also that for the - * other security state, which would balloon the number - * of mmu_idx values needed alarmingly. - * Fortunately we can avoid this because it's not actually - * possible to arbitrarily execute code from memory with - * the wrong security attribute: it will always generate - * an exception of some kind or another, apart from the - * special case of an NS CPU executing an SG instruction - * in S&NSC memory. So we always just fail the translation - * here and sort things out in the exception handler - * (including possibly emulating an SG instruction). - */ - if (sattrs.ns != !secure) { - *fsr = sattrs.nsc ? M_FAKE_FSR_NSC_EXEC : M_FAKE_FSR_SFAULT; - return true; - } - } else { - /* For data accesses we always use the MMU bank indicated - * by the current CPU state, but the security attributes - * might downgrade a secure access to nonsecure. - */ - if (sattrs.ns) { - txattrs->secure = false; - } else if (!secure) { - /* NS access to S memory must fault. - * Architecturally we should first check whether the - * MPU information for this address indicates that we - * are doing an unaligned access to Device memory, which - * should generate a UsageFault instead. QEMU does not - * currently check for that kind of unaligned access though. - * If we added it we would need to do so as a special case - * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). - */ - *fsr = M_FAKE_FSR_SFAULT; - return true; - } - } + if (mregion) { + *mregion = -1; } /* Unlike the ARM ARM pseudocode, we don't need to check whether this @@ -9497,12 +9458,79 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, /* We don't need to look the attribute up in the MAIR0/MAIR1 * registers because that only tells us about cacheability. */ + if (mregion) { + *mregion = matchregion; + } } *fsr = 0x00d; /* Permission fault */ return !(*prot & (1 << access_type)); } + +static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, + MMUAccessType access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, + int *prot, uint32_t *fsr) +{ + uint32_t secure = regime_is_secure(env, mmu_idx); + V8M_SAttributes sattrs = {}; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + v8m_security_lookup(env, address, access_type, mmu_idx, &sattrs); + if (access_type == MMU_INST_FETCH) { + /* Instruction fetches always use the MMU bank and the + * transaction attribute determined by the fetch address, + * regardless of CPU state. This is painful for QEMU + * to handle, because it would mean we need to encode + * into the mmu_idx not just the (user, negpri) information + * for the current security state but also that for the + * other security state, which would balloon the number + * of mmu_idx values needed alarmingly. + * Fortunately we can avoid this because it's not actually + * possible to arbitrarily execute code from memory with + * the wrong security attribute: it will always generate + * an exception of some kind or another, apart from the + * special case of an NS CPU executing an SG instruction + * in S&NSC memory. So we always just fail the translation + * here and sort things out in the exception handler + * (including possibly emulating an SG instruction). + */ + if (sattrs.ns != !secure) { + *fsr = sattrs.nsc ? M_FAKE_FSR_NSC_EXEC : M_FAKE_FSR_SFAULT; + *phys_ptr = address; + *prot = 0; + return true; + } + } else { + /* For data accesses we always use the MMU bank indicated + * by the current CPU state, but the security attributes + * might downgrade a secure access to nonsecure. + */ + if (sattrs.ns) { + txattrs->secure = false; + } else if (!secure) { + /* NS access to S memory must fault. + * Architecturally we should first check whether the + * MPU information for this address indicates that we + * are doing an unaligned access to Device memory, which + * should generate a UsageFault instead. QEMU does not + * currently check for that kind of unaligned access though. + * If we added it we would need to do so as a special case + * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). + */ + *fsr = M_FAKE_FSR_SFAULT; + *phys_ptr = address; + *prot = 0; + return true; + } + } + } + + return pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, + txattrs, prot, fsr, NULL); +} + static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, uint32_t *fsr) From 5158de241b0fb344a6c948dfcbc4e611ab5fafbe Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 032/546] target/arm: Implement TT instruction Implement the TT instruction which queries the security state and access permissions of a memory location. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512153879-5291-8-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 108 +++++++++++++++++++++++++++++++++++++++++ target/arm/helper.h | 2 + target/arm/translate.c | 29 ++++++++++- 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 9e7eaa1080..6140e84d8f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -5947,6 +5947,28 @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) g_assert_not_reached(); } +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* The TT instructions can be used by unprivileged code, but in + * user-only emulation we don't have the MPU. + * Luckily since we know we are NonSecure unprivileged (and that in + * turn means that the A flag wasn't specified), all the bits in the + * register must be zero: + * IREGION: 0 because IRVALID is 0 + * IRVALID: 0 because NS + * S: 0 because NS + * NSRW: 0 because NS + * NSR: 0 because NS + * RW: 0 because unpriv and A flag not set + * R: 0 because unpriv and A flag not set + * SRVALID: 0 because NS + * MRVALID: 0 because unpriv and A flag not set + * SREGION: 0 becaus SRVALID is 0 + * MREGION: 0 because MRVALID is 0 + */ + return 0; +} + void switch_mode(CPUARMState *env, int mode) { ARMCPU *cpu = arm_env_get_cpu(env); @@ -10140,6 +10162,92 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) } } +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) +{ + /* Implement the TT instruction. op is bits [7:6] of the insn. */ + bool forceunpriv = op & 1; + bool alt = op & 2; + V8M_SAttributes sattrs = {}; + uint32_t tt_resp; + bool r, rw, nsr, nsrw, mrvalid; + int prot; + MemTxAttrs attrs = {}; + hwaddr phys_addr; + uint32_t fsr; + ARMMMUIdx mmu_idx; + uint32_t mregion; + bool targetpriv; + bool targetsec = env->v7m.secure; + + /* Work out what the security state and privilege level we're + * interested in is... + */ + if (alt) { + targetsec = !targetsec; + } + + if (forceunpriv) { + targetpriv = false; + } else { + targetpriv = arm_v7m_is_handler_mode(env) || + !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK); + } + + /* ...and then figure out which MMU index this is */ + mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv); + + /* We know that the MPU and SAU don't care about the access type + * for our purposes beyond that we don't want to claim to be + * an insn fetch, so we arbitrarily call this a read. + */ + + /* MPU region info only available for privileged or if + * inspecting the other MPU state. + */ + if (arm_current_el(env) != 0 || alt) { + /* We can ignore the return value as prot is always set */ + pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, + &phys_addr, &attrs, &prot, &fsr, &mregion); + if (mregion == -1) { + mrvalid = false; + mregion = 0; + } else { + mrvalid = true; + } + r = prot & PAGE_READ; + rw = prot & PAGE_WRITE; + } else { + r = false; + rw = false; + mrvalid = false; + mregion = 0; + } + + if (env->v7m.secure) { + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + nsr = sattrs.ns && r; + nsrw = sattrs.ns && rw; + } else { + sattrs.ns = true; + nsr = false; + nsrw = false; + } + + tt_resp = (sattrs.iregion << 24) | + (sattrs.irvalid << 23) | + ((!sattrs.ns) << 22) | + (nsrw << 21) | + (nsr << 20) | + (rw << 19) | + (r << 18) | + (sattrs.srvalid << 17) | + (mrvalid << 16) | + (sattrs.sregion << 8) | + mregion; + + return tt_resp; +} + #endif void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) diff --git a/target/arm/helper.h b/target/arm/helper.h index 439d228420..066729e8ad 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -66,6 +66,8 @@ DEF_HELPER_2(v7m_mrs, i32, env, i32) DEF_HELPER_2(v7m_bxns, void, env, i32) DEF_HELPER_2(v7m_blxns, void, env, i32) +DEF_HELPER_3(v7m_tt, i32, env, i32, i32) + DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32) DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_2(get_cp_reg, i32, env, ptr) diff --git a/target/arm/translate.c b/target/arm/translate.c index 50339e7bdd..e15192d5d6 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9810,7 +9810,7 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) if (insn & (1 << 22)) { /* 0b1110_100x_x1xx_xxxx_xxxx_xxxx_xxxx_xxxx * - load/store doubleword, load/store exclusive, ldacq/strel, - * table branch. + * table branch, TT. */ if (insn == 0xe97fe97f && arm_dc_feature(s, ARM_FEATURE_M) && arm_dc_feature(s, ARM_FEATURE_V8)) { @@ -9887,8 +9887,35 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) } else if ((insn & (1 << 23)) == 0) { /* 0b1110_1000_010x_xxxx_xxxx_xxxx_xxxx_xxxx * - load/store exclusive word + * - TT (v8M only) */ if (rs == 15) { + if (!(insn & (1 << 20)) && + arm_dc_feature(s, ARM_FEATURE_M) && + arm_dc_feature(s, ARM_FEATURE_V8)) { + /* 0b1110_1000_0100_xxxx_1111_xxxx_xxxx_xxxx + * - TT (v8M only) + */ + bool alt = insn & (1 << 7); + TCGv_i32 addr, op, ttresp; + + if ((insn & 0x3f) || rd == 13 || rd == 15 || rn == 15) { + /* we UNDEF for these UNPREDICTABLE cases */ + goto illegal_op; + } + + if (alt && !s->v8m_secure) { + goto illegal_op; + } + + addr = load_reg(s, rn); + op = tcg_const_i32(extract32(insn, 6, 2)); + ttresp = tcg_temp_new_i32(); + gen_helper_v7m_tt(ttresp, cpu_env, addr, op); + tcg_temp_free_i32(addr); + tcg_temp_free_i32(op); + store_reg(s, rd, ttresp); + } goto illegal_op; } addr = tcg_temp_local_new_i32(); From 1fa498fe0de979030bd1f481046e9f1c5574a584 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 033/546] target/arm: Provide fault type enum and FSR conversion functions Currently get_phys_addr() and its various subfunctions return a hard-coded fault status register value for translation failures. This is awkward because FSR values these days may be either long-descriptor format or short-descriptor format. Worse, the right FSR type to use doesn't depend only on the translation table being walked -- some cases, like fault info reported to AArch32 EL2 for some kinds of ATS operation, must be in long-descriptor format even if the translation table being walked was short format. We can't get those cases right with our current approach. Provide fields in the ARMMMUFaultInfo struct which allow get_phys_addr() to provide sufficient information for a caller to construct an FSR value themselves, and utility functions which do this for both long and short format FSR values, as a first step in switching get_phys_addr() and its children to only returning the failure cause in the ARMMMUFaultInfo struct. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-2-git-send-email-peter.maydell@linaro.org --- target/arm/internals.h | 185 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/target/arm/internals.h b/target/arm/internals.h index aa9c91b99f..67b9a52943 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -487,8 +487,40 @@ static inline void arm_clear_exclusive(CPUARMState *env) env->exclusive_addr = -1; } +/** + * ARMFaultType: type of an ARM MMU fault + * This corresponds to the v8A pseudocode's Fault enumeration, + * with extensions for QEMU internal conditions. + */ +typedef enum ARMFaultType { + ARMFault_None, + ARMFault_AccessFlag, + ARMFault_Alignment, + ARMFault_Background, + ARMFault_Domain, + ARMFault_Permission, + ARMFault_Translation, + ARMFault_AddressSize, + ARMFault_SyncExternal, + ARMFault_SyncExternalOnWalk, + ARMFault_SyncParity, + ARMFault_SyncParityOnWalk, + ARMFault_AsyncParity, + ARMFault_AsyncExternal, + ARMFault_Debug, + ARMFault_TLBConflict, + ARMFault_Lockdown, + ARMFault_Exclusive, + ARMFault_ICacheMaint, + ARMFault_QEMU_NSCExec, /* v8M: NS executing in S&NSC memory */ + ARMFault_QEMU_SFault, /* v8M: SecureFault INVTRAN, INVEP or AUVIOL */ +} ARMFaultType; + /** * ARMMMUFaultInfo: Information describing an ARM MMU Fault + * @type: Type of fault + * @level: Table walk level (for translation, access flag and permission faults) + * @domain: Domain of the fault address (for non-LPAE CPUs only) * @s2addr: Address that caused a fault at stage 2 * @stage2: True if we faulted at stage 2 * @s1ptw: True if we faulted at stage 2 while doing a stage 1 page-table walk @@ -496,12 +528,165 @@ static inline void arm_clear_exclusive(CPUARMState *env) */ typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; struct ARMMMUFaultInfo { + ARMFaultType type; target_ulong s2addr; + int level; + int domain; bool stage2; bool s1ptw; bool ea; }; +/** + * arm_fi_to_sfsc: Convert fault info struct to short-format FSC + * Compare pseudocode EncodeSDFSC(), though unlike that function + * we set up a whole FSR-format code including domain field and + * putting the high bit of the FSC into bit 10. + */ +static inline uint32_t arm_fi_to_sfsc(ARMMMUFaultInfo *fi) +{ + uint32_t fsc; + + switch (fi->type) { + case ARMFault_None: + return 0; + case ARMFault_AccessFlag: + fsc = fi->level == 1 ? 0x3 : 0x6; + break; + case ARMFault_Alignment: + fsc = 0x1; + break; + case ARMFault_Permission: + fsc = fi->level == 1 ? 0xd : 0xf; + break; + case ARMFault_Domain: + fsc = fi->level == 1 ? 0x9 : 0xb; + break; + case ARMFault_Translation: + fsc = fi->level == 1 ? 0x5 : 0x7; + break; + case ARMFault_SyncExternal: + fsc = 0x8 | (fi->ea << 12); + break; + case ARMFault_SyncExternalOnWalk: + fsc = fi->level == 1 ? 0xc : 0xe; + fsc |= (fi->ea << 12); + break; + case ARMFault_SyncParity: + fsc = 0x409; + break; + case ARMFault_SyncParityOnWalk: + fsc = fi->level == 1 ? 0x40c : 0x40e; + break; + case ARMFault_AsyncParity: + fsc = 0x408; + break; + case ARMFault_AsyncExternal: + fsc = 0x406 | (fi->ea << 12); + break; + case ARMFault_Debug: + fsc = 0x2; + break; + case ARMFault_TLBConflict: + fsc = 0x400; + break; + case ARMFault_Lockdown: + fsc = 0x404; + break; + case ARMFault_Exclusive: + fsc = 0x405; + break; + case ARMFault_ICacheMaint: + fsc = 0x4; + break; + case ARMFault_Background: + fsc = 0x0; + break; + case ARMFault_QEMU_NSCExec: + fsc = M_FAKE_FSR_NSC_EXEC; + break; + case ARMFault_QEMU_SFault: + fsc = M_FAKE_FSR_SFAULT; + break; + default: + /* Other faults can't occur in a context that requires a + * short-format status code. + */ + g_assert_not_reached(); + } + + fsc |= (fi->domain << 4); + return fsc; +} + +/** + * arm_fi_to_lfsc: Convert fault info struct to long-format FSC + * Compare pseudocode EncodeLDFSC(), though unlike that function + * we fill in also the LPAE bit 9 of a DFSR format. + */ +static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) +{ + uint32_t fsc; + + switch (fi->type) { + case ARMFault_None: + return 0; + case ARMFault_AddressSize: + fsc = fi->level & 3; + break; + case ARMFault_AccessFlag: + fsc = (fi->level & 3) | (0x2 << 2); + break; + case ARMFault_Permission: + fsc = (fi->level & 3) | (0x3 << 2); + break; + case ARMFault_Translation: + fsc = (fi->level & 3) | (0x1 << 2); + break; + case ARMFault_SyncExternal: + fsc = 0x10 | (fi->ea << 12); + break; + case ARMFault_SyncExternalOnWalk: + fsc = (fi->level & 3) | (0x5 << 2) | (fi->ea << 12); + break; + case ARMFault_SyncParity: + fsc = 0x18; + break; + case ARMFault_SyncParityOnWalk: + fsc = (fi->level & 3) | (0x7 << 2); + break; + case ARMFault_AsyncParity: + fsc = 0x19; + break; + case ARMFault_AsyncExternal: + fsc = 0x11 | (fi->ea << 12); + break; + case ARMFault_Alignment: + fsc = 0x21; + break; + case ARMFault_Debug: + fsc = 0x22; + break; + case ARMFault_TLBConflict: + fsc = 0x30; + break; + case ARMFault_Lockdown: + fsc = 0x34; + break; + case ARMFault_Exclusive: + fsc = 0x35; + break; + default: + /* Other faults can't occur in a context that requires a + * long-format status code. + */ + g_assert_not_reached(); + } + + fsc |= 1 << 9; + return fsc; +} + /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, MMUAccessType access_type, int mmu_idx, From 3795a6de9f7ec4a7e3dcb8bf02a88a014147b0b0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 034/546] target/arm: Remove fsr argument from arm_ld*_ptw() All the callers of arm_ldq_ptw() and arm_ldl_ptw() ignore the value that those functions store in the fsr argument on failure: if they return failure to their callers they will always overwrite the fsr value with something else. Remove the argument from these functions and S1_ptw_translate(). This will simplify removing fsr from the calling functions. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-3-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6140e84d8f..c43159ea87 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8266,7 +8266,6 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx, /* Translate a S1 pagetable walk through S2 if needed. */ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr addr, MemTxAttrs txattrs, - uint32_t *fsr, ARMMMUFaultInfo *fi) { if ((mmu_idx == ARMMMUIdx_S1NSE0 || mmu_idx == ARMMMUIdx_S1NSE1) && @@ -8275,9 +8274,10 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr s2pa; int s2prot; int ret; + uint32_t fsr; ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, - &txattrs, &s2prot, &s2size, fsr, fi, NULL); + &txattrs, &s2prot, &s2size, &fsr, fi, NULL); if (ret) { fi->s2addr = addr; fi->stage2 = true; @@ -8297,8 +8297,7 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, * (but not if it was for a debug access). */ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, uint32_t *fsr, - ARMMMUFaultInfo *fi) + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -8307,7 +8306,7 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, attrs.secure = is_secure; as = arm_addressspace(cs, attrs); - addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi); if (fi->s1ptw) { return 0; } @@ -8319,8 +8318,7 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure, } static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, - ARMMMUIdx mmu_idx, uint32_t *fsr, - ARMMMUFaultInfo *fi) + ARMMMUIdx mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -8329,7 +8327,7 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, attrs.secure = is_secure; as = arm_addressspace(cs, attrs); - addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); + addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi); if (fi->s1ptw) { return 0; } @@ -8365,7 +8363,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); type = (desc & 3); domain = (desc >> 5) & 0x0f; if (regime_el(env, mmu_idx) == 1) { @@ -8402,7 +8400,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, table = (desc & 0xfffff000) | ((address >> 8) & 0xffc); } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); switch (desc & 3) { case 0: /* Page translation fault. */ code = 7; @@ -8484,7 +8482,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); type = (desc & 3); if (type == 0 || (type == 3 && !arm_feature(env, ARM_FEATURE_PXN))) { /* Section translation fault, or attempt to use the encoding @@ -8536,7 +8534,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Lookup l2 entry. */ table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc); desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), - mmu_idx, fsr, fi); + mmu_idx, fi); ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ @@ -8947,7 +8945,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, descaddr |= (address >> (stride * (4 - level))) & indexmask; descaddr &= ~7ULL; nstable = extract32(tableattrs, 4, 1); - descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fsr, fi); + descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi); if (fi->s1ptw) { goto do_fault; } From f989983e8dc9be6bc3468c6dbe46fcb1501a740c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 035/546] target/arm: Convert get_phys_addr_v5() to not return FSC values Make get_phys_addr_v5() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-4-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c43159ea87..5f2f00445a 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8341,11 +8341,11 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); - int code; + int level = 1; uint32_t table; uint32_t desc; int type; @@ -8359,7 +8359,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Lookup l1 descriptor. */ if (!get_level1_table_address(env, mmu_idx, &table, address)) { /* Section translation fault if page walk is disabled by PD0 or PD1 */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), @@ -8374,21 +8374,20 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, domain_prot = (dacr >> (domain * 2)) & 3; if (type == 0) { /* Section translation fault. */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } + if (type != 2) { + level = 2; + } if (domain_prot == 0 || domain_prot == 2) { - if (type == 2) - code = 9; /* Section domain fault. */ - else - code = 11; /* Page domain fault. */ + fi->type = ARMFault_Domain; goto do_fault; } if (type == 2) { /* 1Mb section. */ phys_addr = (desc & 0xfff00000) | (address & 0x000fffff); ap = (desc >> 10) & 3; - code = 13; *page_size = 1024 * 1024; } else { /* Lookup l2 entry. */ @@ -8403,7 +8402,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, mmu_idx, fi); switch (desc & 3) { case 0: /* Page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); @@ -8426,7 +8425,7 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* UNPREDICTABLE in ARMv5; we choose to take a * page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; } } else { @@ -8439,18 +8438,19 @@ static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, /* Never happens, but compiler isn't smart enough to tell. */ abort(); } - code = 15; } *prot = ap_to_rw_prot(env, mmu_idx, ap, domain_prot); *prot |= *prot ? PAGE_EXEC : 0; if (!(*prot & (1 << access_type))) { /* Access permission fault. */ + fi->type = ARMFault_Permission; goto do_fault; } *phys_ptr = phys_addr; return false; do_fault: - *fsr = code | (domain << 4); + fi->domain = domain; + fi->level = level; return true; } @@ -9860,8 +9860,11 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, attrs, prot, page_size, fsr, fi); } else { - return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, - prot, page_size, fsr, fi); + bool ret = get_phys_addr_v5(env, address, access_type, mmu_idx, + phys_ptr, prot, page_size, fi); + + *fsr = arm_fi_to_sfsc(fi); + return ret; } } From f06cf243945ccb24cb9578304306ae7fcb4cf3fd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 036/546] target/arm: Convert get_phys_addr_v6() to not return FSC values Make get_phys_addr_v6() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-5-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 5f2f00445a..37357d281b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8457,11 +8457,10 @@ do_fault: static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, - ARMMMUFaultInfo *fi) + target_ulong *page_size, ARMMMUFaultInfo *fi) { CPUState *cs = CPU(arm_env_get_cpu(env)); - int code; + int level = 1; uint32_t table; uint32_t desc; uint32_t xn; @@ -8478,7 +8477,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Lookup l1 descriptor. */ if (!get_level1_table_address(env, mmu_idx, &table, address)) { /* Section translation fault if page walk is disabled by PD0 or PD1 */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } desc = arm_ldl_ptw(cs, table, regime_is_secure(env, mmu_idx), @@ -8488,7 +8487,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Section translation fault, or attempt to use the encoding * which is Reserved on implementations without PXN. */ - code = 5; + fi->type = ARMFault_Translation; goto do_fault; } if ((type == 1) || !(desc & (1 << 18))) { @@ -8500,13 +8499,13 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } else { dacr = env->cp15.dacr_s; } + if (type == 1) { + level = 2; + } domain_prot = (dacr >> (domain * 2)) & 3; if (domain_prot == 0 || domain_prot == 2) { - if (type != 1) { - code = 9; /* Section domain fault. */ - } else { - code = 11; /* Page domain fault. */ - } + /* Section or Page domain fault */ + fi->type = ARMFault_Domain; goto do_fault; } if (type != 1) { @@ -8524,7 +8523,6 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ap = ((desc >> 10) & 3) | ((desc >> 13) & 4); xn = desc & (1 << 4); pxn = desc & 1; - code = 13; ns = extract32(desc, 19, 1); } else { if (arm_feature(env, ARM_FEATURE_PXN)) { @@ -8538,7 +8536,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, ap = ((desc >> 4) & 3) | ((desc >> 7) & 4); switch (desc & 3) { case 0: /* Page translation fault. */ - code = 7; + fi->type = ARMFault_Translation; goto do_fault; case 1: /* 64k page. */ phys_addr = (desc & 0xffff0000) | (address & 0xffff); @@ -8554,7 +8552,6 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, /* Never happens, but compiler isn't smart enough to tell. */ abort(); } - code = 15; } if (domain_prot == 3) { *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; @@ -8562,15 +8559,17 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, if (pxn && !regime_is_user(env, mmu_idx)) { xn = 1; } - if (xn && access_type == MMU_INST_FETCH) + if (xn && access_type == MMU_INST_FETCH) { + fi->type = ARMFault_Permission; goto do_fault; + } if (arm_feature(env, ARM_FEATURE_V6K) && (regime_sctlr(env, mmu_idx) & SCTLR_AFE)) { /* The simplified model uses AP[0] as an access control bit. */ if ((ap & 1) == 0) { /* Access flag fault. */ - code = (code == 15) ? 6 : 3; + fi->type = ARMFault_AccessFlag; goto do_fault; } *prot = simple_ap_to_rw_prot(env, mmu_idx, ap >> 1); @@ -8582,6 +8581,7 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, } if (!(*prot & (1 << access_type))) { /* Access permission fault. */ + fi->type = ARMFault_Permission; goto do_fault; } } @@ -8595,7 +8595,8 @@ static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, *phys_ptr = phys_addr; return false; do_fault: - *fsr = code | (domain << 4); + fi->domain = domain; + fi->level = level; return true; } @@ -9857,8 +9858,11 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr, attrs, prot, page_size, fsr, fi, cacheattrs); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { - return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr, fi); + bool ret = get_phys_addr_v6(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, fi); + + *fsr = arm_fi_to_sfsc(fi); + return ret; } else { bool ret = get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, prot, page_size, fi); From da909b2c23a68e57bbcb6be98229e40df606f0c8 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:24 +0000 Subject: [PATCH 037/546] target/arm: Convert get_phys_addr_lpae() to not return FSC values Make get_phys_addr_v6() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-6-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 37357d281b..ce9cb6f4ba 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -34,7 +34,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, uint32_t *fsr, + target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); /* Security attributes for an address, as returned by v8m_security_lookup. */ @@ -8274,10 +8274,9 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx, hwaddr s2pa; int s2prot; int ret; - uint32_t fsr; ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa, - &txattrs, &s2prot, &s2size, &fsr, fi, NULL); + &txattrs, &s2prot, &s2size, fi, NULL); if (ret) { fi->s2addr = addr; fi->stage2 = true; @@ -8600,15 +8599,6 @@ do_fault: return true; } -/* Fault type for long-descriptor MMU fault reporting; this corresponds - * to bits [5..2] in the STATUS field in long-format DFSR/IFSR. - */ -typedef enum { - translation_fault = 1, - access_fault = 2, - permission_fault = 3, -} MMUFaultType; - /* * check_s2_mmu_setup * @cpu: ARMCPU @@ -8710,13 +8700,13 @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs) static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr, uint32_t *fsr, + target_ulong *page_size_ptr, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { ARMCPU *cpu = arm_env_get_cpu(env); CPUState *cs = CPU(cpu); /* Read an LPAE long-descriptor translation table. */ - MMUFaultType fault_type = translation_fault; + ARMFaultType fault_type = ARMFault_Translation; uint32_t level; uint32_t epd = 0; int32_t t0sz, t1sz; @@ -8826,7 +8816,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ttbr_select = 1; } else { /* in the gap between the two regions, this is a Translation fault */ - fault_type = translation_fault; + fault_type = ARMFault_Translation; goto do_fault; } @@ -8912,7 +8902,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, ok = check_s2_mmu_setup(cpu, aarch64, startlevel, inputsize, stride); if (!ok) { - fault_type = translation_fault; + fault_type = ARMFault_Translation; goto do_fault; } level = startlevel; @@ -8998,7 +8988,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, /* Here descaddr is the final physical address, and attributes * are all in attrs. */ - fault_type = access_fault; + fault_type = ARMFault_AccessFlag; if ((attrs & (1 << 8)) == 0) { /* Access flag */ goto do_fault; @@ -9016,7 +9006,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, *prot = get_S1prot(env, mmu_idx, aarch64, ap, ns, xn, pxn); } - fault_type = permission_fault; + fault_type = ARMFault_Permission; if (!(*prot & (1 << access_type))) { goto do_fault; } @@ -9048,8 +9038,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, return false; do_fault: - /* Long-descriptor format IFSR/DFSR value */ - *fsr = (1 << 9) | (fault_type << 2) | level; + fi->type = fault_type; + fi->level = level; /* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */ fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_S2NS); return true; @@ -9775,8 +9765,9 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, /* S1 is done. Now do S2 translation. */ ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_S2NS, phys_ptr, attrs, &s2_prot, - page_size, fsr, fi, + page_size, fi, cacheattrs != NULL ? &cacheattrs2 : NULL); + *fsr = arm_fi_to_lfsc(fi); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ *prot &= s2_prot; @@ -9855,8 +9846,12 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, } if (regime_using_lpae_format(env, mmu_idx)) { - return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size, fsr, fi, cacheattrs); + bool ret = get_phys_addr_lpae(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, + fi, cacheattrs); + + *fsr = arm_fi_to_lfsc(fi); + return ret; } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { bool ret = get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, attrs, prot, page_size, fi); From 53a4e5c5b07b2f50c538511b74b0d3d4964695ea Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 038/546] target/arm: Convert get_phys_addr_pmsav5() to not return FSC values Make get_phys_addr_pmsav5() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Note that PMSAv5 does not define any guest-visible fault status register, so the different "fsr" values we were previously returning are entirely arbitrary. So we can just switch to using the most appropriae fi->type values without worrying that we need to special-case FaultInfo->FSC conversion for PMSAv5. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-7-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index ce9cb6f4ba..b08910b385 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9544,7 +9544,8 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, uint32_t *fsr) + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) { int n; uint32_t mask; @@ -9573,7 +9574,7 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, } } if (n < 0) { - *fsr = 2; + fi->type = ARMFault_Background; return true; } @@ -9585,11 +9586,13 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, mask = (mask >> (n * 4)) & 0xf; switch (mask) { case 0: - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; case 1: if (is_user) { - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot = PAGE_READ | PAGE_WRITE; @@ -9605,7 +9608,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, break; case 5: if (is_user) { - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot = PAGE_READ; @@ -9615,7 +9619,8 @@ static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, break; default: /* Bad permission. */ - *fsr = 1; + fi->type = ARMFault_Permission; + fi->level = 1; return true; } *prot |= PAGE_EXEC; @@ -9820,7 +9825,8 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, } else { /* Pre-v7 MPU */ ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, - phys_ptr, prot, fsr); + phys_ptr, prot, fi); + *fsr = arm_fi_to_sfsc(fi); } qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 " mmu_idx %u -> %s (prot %c%c%c)\n", From 9375ad15338b24e06109071ac3a85df48a2cc2e6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 039/546] target/arm: Convert get_phys_addr_pmsav7() to not return FSC values Make get_phys_addr_pmsav7() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-8-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index b08910b385..2752d9e605 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9123,7 +9123,8 @@ static inline bool m_is_system_region(CPUARMState *env, uint32_t address) static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, uint32_t *fsr) + hwaddr *phys_ptr, int *prot, + ARMMMUFaultInfo *fi) { ARMCPU *cpu = arm_env_get_cpu(env); int n; @@ -9218,7 +9219,7 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, if (n == -1) { /* no hits */ if (!pmsav7_use_background_region(cpu, mmu_idx, is_user)) { /* background fault */ - *fsr = 0; + fi->type = ARMFault_Background; return true; } get_phys_addr_pmsav7_default(env, mmu_idx, address, prot); @@ -9276,7 +9277,8 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, } } - *fsr = 0x00d; /* Permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return !(*prot & (1 << access_type)); } @@ -9821,7 +9823,8 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, - phys_ptr, prot, fsr); + phys_ptr, prot, fi); + *fsr = arm_fi_to_sfsc(fi); } else { /* Pre-v7 MPU */ ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, From 3f551b5b7380ff131fe22944aa6f5b166aa13caf Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 040/546] target/arm: Convert get_phys_addr_pmsav8() to not return FSC values Make get_phys_addr_pmsav8() return a fault type in the ARMMMUFaultInfo structure, which we convert to the FSC at the callsite. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-9-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 2752d9e605..e611b0f2ea 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -9364,7 +9364,7 @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address, static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, uint32_t *fsr, uint32_t *mregion) + int *prot, ARMMMUFaultInfo *fi, uint32_t *mregion) { /* Perform a PMSAv8 MPU lookup (without also doing the SAU check * that a full phys-to-virt translation does). @@ -9420,7 +9420,8 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, /* Multiple regions match -- always a failure (unlike * PMSAv7 where highest-numbered-region wins) */ - *fsr = 0x00d; /* permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return true; } @@ -9448,7 +9449,7 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, if (!hit) { /* background fault */ - *fsr = 0; + fi->type = ARMFault_Background; return true; } @@ -9476,7 +9477,8 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, } } - *fsr = 0x00d; /* Permission fault */ + fi->type = ARMFault_Permission; + fi->level = 1; return !(*prot & (1 << access_type)); } @@ -9484,7 +9486,7 @@ static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *txattrs, - int *prot, uint32_t *fsr) + int *prot, ARMMMUFaultInfo *fi) { uint32_t secure = regime_is_secure(env, mmu_idx); V8M_SAttributes sattrs = {}; @@ -9510,7 +9512,11 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, * (including possibly emulating an SG instruction). */ if (sattrs.ns != !secure) { - *fsr = sattrs.nsc ? M_FAKE_FSR_NSC_EXEC : M_FAKE_FSR_SFAULT; + if (sattrs.nsc) { + fi->type = ARMFault_QEMU_NSCExec; + } else { + fi->type = ARMFault_QEMU_SFault; + } *phys_ptr = address; *prot = 0; return true; @@ -9532,7 +9538,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, * If we added it we would need to do so as a special case * for M_FAKE_FSR_SFAULT in arm_v7m_cpu_do_interrupt(). */ - *fsr = M_FAKE_FSR_SFAULT; + fi->type = ARMFault_QEMU_SFault; *phys_ptr = address; *prot = 0; return true; @@ -9541,7 +9547,7 @@ static bool get_phys_addr_pmsav8(CPUARMState *env, uint32_t address, } return pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr, - txattrs, prot, fsr, NULL); + txattrs, prot, fi, NULL); } static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, @@ -9819,7 +9825,8 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, if (arm_feature(env, ARM_FEATURE_V8)) { /* PMSAv8 */ ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, fsr); + phys_ptr, attrs, prot, fi); + *fsr = arm_fi_to_sfsc(fi); } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, @@ -10180,9 +10187,9 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) uint32_t tt_resp; bool r, rw, nsr, nsrw, mrvalid; int prot; + ARMMMUFaultInfo fi = {}; MemTxAttrs attrs = {}; hwaddr phys_addr; - uint32_t fsr; ARMMMUIdx mmu_idx; uint32_t mregion; bool targetpriv; @@ -10216,7 +10223,7 @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op) if (arm_current_el(env) != 0 || alt) { /* We can ignore the return value as prot is always set */ pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, - &phys_addr, &attrs, &prot, &fsr, &mregion); + &phys_addr, &attrs, &prot, &fi, &mregion); if (mregion == -1) { mrvalid = false; mregion = 0; From 681f9a89d201d7891e2c60dff5e5415d8f618518 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 041/546] target/arm: Use ARMMMUFaultInfo in deliver_fault() Now that ARMMMUFaultInfo is guaranteed to have enough information to construct a fault status code, we can pass it in to the deliver_fault() function and let it generate the correct type of FSR for the destination, rather than relying on the value provided by get_phys_addr(). I don't think there are any cases the old code was getting wrong, but this is more obviously correct. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-10-git-send-email-peter.maydell@linaro.org --- target/arm/op_helper.c | 79 ++++++++++++------------------------------ 1 file changed, 22 insertions(+), 57 deletions(-) diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index a40a84ac24..38e6993584 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -116,12 +116,13 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, } static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, - uint32_t fsr, uint32_t fsc, ARMMMUFaultInfo *fi) + int mmu_idx, ARMMMUFaultInfo *fi) { CPUARMState *env = &cpu->env; int target_el; bool same_el; - uint32_t syn, exc; + uint32_t syn, exc, fsr, fsc; + ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); target_el = exception_target_el(env); if (fi->stage2) { @@ -130,14 +131,21 @@ static void deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, } same_el = (arm_current_el(env) == target_el); - if (fsc == 0x3f) { - /* Caller doesn't have a long-format fault status code. This - * should only happen if this fault will never actually be reported - * to an EL that uses a syndrome register. Check that here. - * 0x3f is a (currently) reserved FSC code, in case the constructed - * syndrome does leak into the guest somehow. + if (target_el == 2 || arm_el_is_aa64(env, target_el) || + arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { + /* LPAE format fault status register : bottom 6 bits are + * status code in the same form as needed for syndrome */ - assert(target_el != 2 && !arm_el_is_aa64(env, target_el)); + fsr = arm_fi_to_lfsc(fi); + fsc = extract32(fsr, 0, 6); + } else { + fsr = arm_fi_to_sfsc(fi); + /* Short format FSR : this fault will never actually be reported + * to an EL that uses a syndrome register. Use a (currently) + * reserved FSR code in case the constructed syndrome does leak + * into the guest somehow. + */ + fsc = 0x3f; } if (access_type == MMU_INST_FETCH) { @@ -174,29 +182,13 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fsr, &fi); if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); - uint32_t fsc; if (retaddr) { /* now we have a real cpu fault */ cpu_restore_state(cs, retaddr); } - if (fsr & (1 << 9)) { - /* LPAE format fault status register : bottom 6 bits are - * status code in the same form as needed for syndrome - */ - fsc = extract32(fsr, 0, 6); - } else { - /* Short format FSR : this fault will never actually be reported - * to an EL that uses a syndrome register. Use a (currently) - * reserved FSR code in case the constructed syndrome does leak - * into the guest somehow. deliver_fault will assert that - * we don't target an EL using the syndrome. - */ - fsc = 0x3f; - } - - deliver_fault(cpu, addr, access_type, fsr, fsc, &fi); + deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } } @@ -206,27 +198,15 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int mmu_idx, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - uint32_t fsr, fsc; ARMMMUFaultInfo fi = {}; - ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); if (retaddr) { /* now we have a real cpu fault */ cpu_restore_state(cs, retaddr); } - /* the DFSR for an alignment fault depends on whether we're using - * the LPAE long descriptor format, or the short descriptor format - */ - if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { - fsr = (1 << 9) | 0x21; - } else { - fsr = 0x1; - } - fsc = 0x21; - - deliver_fault(cpu, vaddr, access_type, fsr, fsc, &fi); + fi.type = ARMFault_Alignment; + deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); } /* arm_cpu_do_transaction_failed: handle a memory system error response @@ -240,10 +220,7 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MemTxResult response, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); - CPUARMState *env = &cpu->env; - uint32_t fsr, fsc; ARMMMUFaultInfo fi = {}; - ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx); if (retaddr) { /* now we have a real cpu fault */ @@ -256,20 +233,8 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, * Slave error (1); in QEMU we follow that. */ fi.ea = (response != MEMTX_DECODE_ERROR); - - /* The fault status register format depends on whether we're using - * the LPAE long descriptor format, or the short descriptor format. - */ - if (arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) { - /* long descriptor form, STATUS 0b010000: synchronous ext abort */ - fsr = (fi.ea << 12) | (1 << 9) | 0x10; - } else { - /* short descriptor form, FSR 0b01000 : synchronous ext abort */ - fsr = (fi.ea << 12) | 0x8; - } - fsc = 0x10; - - deliver_fault(cpu, addr, access_type, fsr, fsc, &fi); + fi.type = ARMFault_SyncExternal; + deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } #endif /* !defined(CONFIG_USER_ONLY) */ From 5efe9ed45dec775ebe91ce72bd805ee780d16064 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 042/546] target/arm: Ignore fsr from get_phys_addr() in do_ats_write() In do_ats_write(), rather than using the FSR value from get_phys_addr(), construct the PAR values using the information in the ARMMMUFaultInfo struct. This allows us to create a PAR of the correct format regardless of what the translation table format is. For the moment we leave the condition for "when should this be a 64 bit PAR" as it was previously; this will need to be fixed to properly support AArch32 Hyp mode. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-11-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index e611b0f2ea..79ab277623 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2160,7 +2160,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, hwaddr phys_addr; target_ulong page_size; int prot; - uint32_t fsr; + uint32_t fsr_unused; bool ret; uint64_t par64; MemTxAttrs attrs = {}; @@ -2168,12 +2168,12 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ARMCacheAttrs cacheattrs = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, - &prot, &page_size, &fsr, &fi, &cacheattrs); + &prot, &page_size, &fsr_unused, &fi, &cacheattrs); + /* TODO: this is not the correct condition to use to decide whether + * to report a PAR in 64-bit or 32-bit format. + */ if (arm_s1_regime_using_lpae_format(env, mmu_idx)) { - /* fsr is a DFSR/IFSR value for the long descriptor - * translation table format, but with WnR always clear. - * Convert it to a 64-bit PAR. - */ + /* Create a 64-bit PAR */ par64 = (1 << 11); /* LPAE bit always set */ if (!ret) { par64 |= phys_addr & ~0xfffULL; @@ -2183,6 +2183,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, par64 |= (uint64_t)cacheattrs.attrs << 56; /* ATTR */ par64 |= cacheattrs.shareability << 7; /* SH */ } else { + uint32_t fsr = arm_fi_to_lfsc(&fi); + par64 |= 1; /* F */ par64 |= (fsr & 0x3f) << 1; /* FS */ /* Note that S2WLK and FSTAGE are always zero, because we don't @@ -2207,6 +2209,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, par64 |= (1 << 9); /* NS */ } } else { + uint32_t fsr = arm_fi_to_sfsc(&fi); + par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) | ((fsr & 0xf) << 1) | 1; } From bc52bfeb3be2052942b7dac8ba284f342ac9605b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 043/546] target/arm: Remove fsr argument from get_phys_addr() and arm_tlb_fill() All of the callers of get_phys_addr() and arm_tlb_fill() now ignore the FSR values they return, so we can just remove the argument entirely. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Message-id: 1512503192-2239-12-git-send-email-peter.maydell@linaro.org --- target/arm/helper.c | 45 +++++++++++++----------------------------- target/arm/internals.h | 2 +- target/arm/op_helper.c | 3 +-- 3 files changed, 16 insertions(+), 34 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 79ab277623..c469e6a56c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -28,7 +28,7 @@ typedef struct ARMCacheAttrs { static bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs); static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, @@ -2160,7 +2160,6 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, hwaddr phys_addr; target_ulong page_size; int prot; - uint32_t fsr_unused; bool ret; uint64_t par64; MemTxAttrs attrs = {}; @@ -2168,7 +2167,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, ARMCacheAttrs cacheattrs = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, - &prot, &page_size, &fsr_unused, &fi, &cacheattrs); + &prot, &page_size, &fi, &cacheattrs); /* TODO: this is not the correct condition to use to decide whether * to report a PAR in 64-bit or 32-bit format. */ @@ -6981,7 +6980,6 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, target_ulong page_size; hwaddr physaddr; int prot; - uint32_t fsr; v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs); if (!sattrs.nsc || sattrs.ns) { @@ -6995,7 +6993,7 @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx, return false; } if (get_phys_addr(env, addr, MMU_INST_FETCH, mmu_idx, - &physaddr, &attrs, &prot, &page_size, &fsr, &fi, NULL)) { + &physaddr, &attrs, &prot, &page_size, &fi, NULL)) { /* the MPU lookup failed */ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_IACCVIOL_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM, env->v7m.secure); @@ -9749,14 +9747,13 @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2) * @attrs: set to the memory transaction attributes to use * @prot: set to the permissions for the page containing phys_ptr * @page_size: set to the size of the page containing phys_ptr - * @fsr: set to the DFSR/IFSR value on failure * @fi: set to fault info if the translation fails * @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes */ static bool get_phys_addr(CPUARMState *env, target_ulong address, MMUAccessType access_type, ARMMMUIdx mmu_idx, hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size, uint32_t *fsr, + target_ulong *page_size, ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { @@ -9771,7 +9768,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, ret = get_phys_addr(env, address, access_type, stage_1_mmu_idx(mmu_idx), &ipa, attrs, - prot, page_size, fsr, fi, cacheattrs); + prot, page_size, fi, cacheattrs); /* If S1 fails or S2 is disabled, return early. */ if (ret || regime_translation_disabled(env, ARMMMUIdx_S2NS)) { @@ -9784,7 +9781,6 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, phys_ptr, attrs, &s2_prot, page_size, fi, cacheattrs != NULL ? &cacheattrs2 : NULL); - *fsr = arm_fi_to_lfsc(fi); fi->s2addr = ipa; /* Combine the S1 and S2 perms. */ *prot &= s2_prot; @@ -9830,17 +9826,14 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, /* PMSAv8 */ ret = get_phys_addr_pmsav8(env, address, access_type, mmu_idx, phys_ptr, attrs, prot, fi); - *fsr = arm_fi_to_sfsc(fi); } else if (arm_feature(env, ARM_FEATURE_V7)) { /* PMSAv7 */ ret = get_phys_addr_pmsav7(env, address, access_type, mmu_idx, phys_ptr, prot, fi); - *fsr = arm_fi_to_sfsc(fi); } else { /* Pre-v7 MPU */ ret = get_phys_addr_pmsav5(env, address, access_type, mmu_idx, phys_ptr, prot, fi); - *fsr = arm_fi_to_sfsc(fi); } qemu_log_mask(CPU_LOG_MMU, "PMSA MPU lookup for %s at 0x%08" PRIx32 " mmu_idx %u -> %s (prot %c%c%c)\n", @@ -9866,24 +9859,15 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, } if (regime_using_lpae_format(env, mmu_idx)) { - bool ret = get_phys_addr_lpae(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, - fi, cacheattrs); - - *fsr = arm_fi_to_lfsc(fi); - return ret; + return get_phys_addr_lpae(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, + fi, cacheattrs); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { - bool ret = get_phys_addr_v6(env, address, access_type, mmu_idx, - phys_ptr, attrs, prot, page_size, fi); - - *fsr = arm_fi_to_sfsc(fi); - return ret; + return get_phys_addr_v6(env, address, access_type, mmu_idx, + phys_ptr, attrs, prot, page_size, fi); } else { - bool ret = get_phys_addr_v5(env, address, access_type, mmu_idx, + return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, prot, page_size, fi); - - *fsr = arm_fi_to_sfsc(fi); - return ret; } } @@ -9892,7 +9876,7 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address, * fsr with ARM DFSR/IFSR fault register format value on failure. */ bool arm_tlb_fill(CPUState *cs, vaddr address, - MMUAccessType access_type, int mmu_idx, uint32_t *fsr, + MMUAccessType access_type, int mmu_idx, ARMMMUFaultInfo *fi) { ARMCPU *cpu = ARM_CPU(cs); @@ -9905,7 +9889,7 @@ bool arm_tlb_fill(CPUState *cs, vaddr address, ret = get_phys_addr(env, address, access_type, core_to_arm_mmu_idx(env, mmu_idx), &phys_addr, - &attrs, &prot, &page_size, fsr, fi, NULL); + &attrs, &prot, &page_size, fi, NULL); if (!ret) { /* Map a single [sub]page. */ phys_addr &= TARGET_PAGE_MASK; @@ -9927,14 +9911,13 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr, target_ulong page_size; int prot; bool ret; - uint32_t fsr; ARMMMUFaultInfo fi = {}; ARMMMUIdx mmu_idx = core_to_arm_mmu_idx(env, cpu_mmu_index(env, false)); *attrs = (MemTxAttrs) {}; ret = get_phys_addr(env, addr, 0, mmu_idx, &phys_addr, - attrs, &prot, &page_size, &fsr, &fi, NULL); + attrs, &prot, &page_size, &fi, NULL); if (ret) { return -1; diff --git a/target/arm/internals.h b/target/arm/internals.h index 67b9a52943..876854d876 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -690,7 +690,7 @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi) /* Do a page table walk and add page to TLB if possible */ bool arm_tlb_fill(CPUState *cpu, vaddr address, MMUAccessType access_type, int mmu_idx, - uint32_t *fsr, ARMMMUFaultInfo *fi); + ARMMMUFaultInfo *fi); /* Return true if the stage 1 translation regime is using LPAE format page * tables */ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index 38e6993584..c2bb4f3a43 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -176,10 +176,9 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { bool ret; - uint32_t fsr = 0; ARMMMUFaultInfo fi = {}; - ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fsr, &fi); + ret = arm_tlb_fill(cs, addr, access_type, mmu_idx, &fi); if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); From 1313e2d7e2cd8b21741e0cf542eb09dfc4188f79 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Wed, 13 Dec 2017 17:59:25 +0000 Subject: [PATCH 044/546] target/arm: Extend PAR format determination Now that do_ats_write() is entirely in control of whether to generate a 32-bit PAR or a 64-bit PAR, we can make it use the correct (complicated) condition for doing so. Signed-off-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Reviewed-by: Edgar E. Iglesias Tested-by: Stefano Stabellini Signed-off-by: Peter Maydell Message-id: 1512503192-2239-13-git-send-email-peter.maydell@linaro.org [PMM: Rebased Edgar's patch on top of get_phys_addr() refactoring; use arm_s1_regime_using_lpae_format() rather than regime_using_lpae_format() because the latter will assert if passed ARMMMUIdx_S12NSE0 or ARMMMUIdx_S12NSE1; updated commit message appropriately] Signed-off-by: Peter Maydell --- target/arm/helper.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c469e6a56c..d1395f9b73 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -2162,16 +2162,41 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, int prot; bool ret; uint64_t par64; + bool format64 = false; MemTxAttrs attrs = {}; ARMMMUFaultInfo fi = {}; ARMCacheAttrs cacheattrs = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, &phys_addr, &attrs, &prot, &page_size, &fi, &cacheattrs); - /* TODO: this is not the correct condition to use to decide whether - * to report a PAR in 64-bit or 32-bit format. - */ - if (arm_s1_regime_using_lpae_format(env, mmu_idx)) { + + if (is_a64(env)) { + format64 = true; + } else if (arm_feature(env, ARM_FEATURE_LPAE)) { + /* + * ATS1Cxx: + * * TTBCR.EAE determines whether the result is returned using the + * 32-bit or the 64-bit PAR format + * * Instructions executed in Hyp mode always use the 64bit format + * + * ATS1S2NSOxx uses the 64bit format if any of the following is true: + * * The Non-secure TTBCR.EAE bit is set to 1 + * * The implementation includes EL2, and the value of HCR.VM is 1 + * + * ATS1Hx always uses the 64bit format (not supported yet). + */ + format64 = arm_s1_regime_using_lpae_format(env, mmu_idx); + + if (arm_feature(env, ARM_FEATURE_EL2)) { + if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { + format64 |= env->cp15.hcr_el2 & HCR_VM; + } else { + format64 |= arm_current_el(env) == 2; + } + } + } + + if (format64) { /* Create a 64-bit PAR */ par64 = (1 << 11); /* LPAE bit always set */ if (!ret) { From 62f018482c18c2f1a70f000a0bb361dd6d89aef4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 045/546] nvic: Make nvic_sysreg_ns_ops work with any MemoryRegion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generalize nvic_sysreg_ns_ops so that we can pass it an arbitrary MemoryRegion which it will use as the underlying register implementation to apply the NS-alias behaviour to. We'll want this so we can do the same with systick. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 1512154296-5652-2-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 5d9c8834ad..63f2743576 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1786,10 +1786,12 @@ static MemTxResult nvic_sysreg_ns_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { + MemoryRegion *mr = opaque; + if (attrs.secure) { /* S accesses to the alias act like NS accesses to the real region */ attrs.secure = 0; - return nvic_sysreg_write(opaque, addr, value, size, attrs); + return memory_region_dispatch_write(mr, addr, value, size, attrs); } else { /* NS attrs are RAZ/WI for privileged, and BusFault for user */ if (attrs.user) { @@ -1803,10 +1805,12 @@ static MemTxResult nvic_sysreg_ns_read(void *opaque, hwaddr addr, uint64_t *data, unsigned size, MemTxAttrs attrs) { + MemoryRegion *mr = opaque; + if (attrs.secure) { /* S accesses to the alias act like NS accesses to the real region */ attrs.secure = 0; - return nvic_sysreg_read(opaque, addr, data, size, attrs); + return memory_region_dispatch_read(mr, addr, data, size, attrs); } else { /* NS attrs are RAZ/WI for privileged, and BusFault for user */ if (attrs.user) { @@ -2075,7 +2079,7 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) { memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s), - &nvic_sysreg_ns_ops, s, + &nvic_sysreg_ns_ops, &s->sysregmem, "nvic_sysregs_ns", 0x1000); memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem); } From 27f26bfed923e4c68a1acb61fdafcd0bc63abf71 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 046/546] nvic: Make systick banked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the v8M security extension, there should be two systick devices, which use separate banked systick exceptions. The register interface is banked in the same way as for other banked registers, including the existence of an NS alias region for secure code to access the nonsecure timer. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-id: 1512154296-5652-3-git-send-email-peter.maydell@linaro.org --- hw/intc/armv7m_nvic.c | 90 ++++++++++++++++++++++++++++++----- include/hw/intc/armv7m_nvic.h | 4 +- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 63f2743576..dd49b6c335 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -1827,6 +1827,36 @@ static const MemoryRegionOps nvic_sysreg_ns_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static MemTxResult nvic_systick_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + NVICState *s = opaque; + MemoryRegion *mr; + + /* Direct the access to the correct systick */ + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0); + return memory_region_dispatch_write(mr, addr, value, size, attrs); +} + +static MemTxResult nvic_systick_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + NVICState *s = opaque; + MemoryRegion *mr; + + /* Direct the access to the correct systick */ + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0); + return memory_region_dispatch_read(mr, addr, data, size, attrs); +} + +static const MemoryRegionOps nvic_systick_ops = { + .read_with_attrs = nvic_systick_read, + .write_with_attrs = nvic_systick_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static int nvic_post_load(void *opaque, int version_id) { NVICState *s = opaque; @@ -2005,17 +2035,16 @@ static void nvic_systick_trigger(void *opaque, int n, int level) /* SysTick just asked us to pend its exception. * (This is different from an external interrupt line's * behaviour.) - * TODO: when we implement the banked systicks we must make - * this pend the correct banked exception. + * n == 0 : NonSecure systick + * n == 1 : Secure systick */ - armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK, false); + armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK, n); } } static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { NVICState *s = NVIC(dev); - SysBusDevice *systick_sbd; Error *err = NULL; int regionlen; @@ -2032,14 +2061,35 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) /* include space for internal exception vectors */ s->num_irq += NVIC_FIRST_IRQ; - object_property_set_bool(OBJECT(&s->systick), true, "realized", &err); + object_property_set_bool(OBJECT(&s->systick[M_REG_NS]), true, + "realized", &err); if (err != NULL) { error_propagate(errp, err); return; } - systick_sbd = SYS_BUS_DEVICE(&s->systick); - sysbus_connect_irq(systick_sbd, 0, - qdev_get_gpio_in_named(dev, "systick-trigger", 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), 0, + qdev_get_gpio_in_named(dev, "systick-trigger", + M_REG_NS)); + + if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) { + /* We couldn't init the secure systick device in instance_init + * as we didn't know then if the CPU had the security extensions; + * so we have to do it here. + */ + object_initialize(&s->systick[M_REG_S], sizeof(s->systick[M_REG_S]), + TYPE_SYSTICK); + qdev_set_parent_bus(DEVICE(&s->systick[M_REG_S]), sysbus_get_default()); + + object_property_set_bool(OBJECT(&s->systick[M_REG_S]), true, + "realized", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_S]), 0, + qdev_get_gpio_in_named(dev, "systick-trigger", + M_REG_S)); + } /* The NVIC and System Control Space (SCS) starts at 0xe000e000 * and looks like this: @@ -2073,15 +2123,24 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s, "nvic_sysregs", 0x1000); memory_region_add_subregion(&s->container, 0, &s->sysregmem); + + memory_region_init_io(&s->systickmem, OBJECT(s), + &nvic_systick_ops, s, + "nvic_systick", 0xe0); + memory_region_add_subregion_overlap(&s->container, 0x10, - sysbus_mmio_get_region(systick_sbd, 0), - 1); + &s->systickmem, 1); if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) { memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s), &nvic_sysreg_ns_ops, &s->sysregmem, "nvic_sysregs_ns", 0x1000); memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem); + memory_region_init_io(&s->systick_ns_mem, OBJECT(s), + &nvic_sysreg_ns_ops, &s->systickmem, + "nvic_systick_ns", 0xe0); + memory_region_add_subregion_overlap(&s->container, 0x20010, + &s->systick_ns_mem, 1); } sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container); @@ -2099,12 +2158,17 @@ static void armv7m_nvic_instance_init(Object *obj) NVICState *nvic = NVIC(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - object_initialize(&nvic->systick, sizeof(nvic->systick), TYPE_SYSTICK); - qdev_set_parent_bus(DEVICE(&nvic->systick), sysbus_get_default()); + object_initialize(&nvic->systick[M_REG_NS], + sizeof(nvic->systick[M_REG_NS]), TYPE_SYSTICK); + qdev_set_parent_bus(DEVICE(&nvic->systick[M_REG_NS]), sysbus_get_default()); + /* We can't initialize the secure systick here, as we don't know + * yet if we need it. + */ sysbus_init_irq(sbd, &nvic->excpout); qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1); - qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger", 1); + qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger", + M_REG_NUM_BANKS); } static void armv7m_nvic_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h index ac7997ca8c..8bc29112e3 100644 --- a/include/hw/intc/armv7m_nvic.h +++ b/include/hw/intc/armv7m_nvic.h @@ -78,13 +78,15 @@ typedef struct NVICState { MemoryRegion sysregmem; MemoryRegion sysreg_ns_mem; + MemoryRegion systickmem; + MemoryRegion systick_ns_mem; MemoryRegion container; uint32_t num_irq; qemu_irq excpout; qemu_irq sysresetreq; - SysTickState systick; + SysTickState systick[M_REG_NUM_BANKS]; } NVICState; #endif From d6c3768b32277559cf6424bdf1edfee1fbf9a970 Mon Sep 17 00:00:00 2001 From: Prasad J Pandit Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 047/546] hw/display/tc6393xb: limit irq handler index to TC6393XB_GPIOS The ctz32() routine could return a value greater than TC6393XB_GPIOS=16, because the device has 24 GPIO level bits but we only implement 16 outgoing lines. This could lead to an OOB array access. Mask 'level' to avoid it. Reported-by: Moguofang Signed-off-by: Prasad J Pandit Message-id: 20171212041539.25700-1-ppandit@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/display/tc6393xb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c index 74d10af3d4..0ae63605f0 100644 --- a/hw/display/tc6393xb.c +++ b/hw/display/tc6393xb.c @@ -172,6 +172,7 @@ static void tc6393xb_gpio_handler_update(TC6393xbState *s) int bit; level = s->gpio_level & s->gpio_dir; + level &= MAKE_64BIT_MASK(0, TC6393XB_GPIOS); for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { bit = ctz32(diff); From e59f13d76bb0bb7498e49ba83f95a7445bed2b1d Mon Sep 17 00:00:00 2001 From: Zhaoshenglong Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 048/546] MAINTAINERS: replace the unavailable email address Since I'm not working as an assignee in Linaro, replace the Linaro email address with my personal one. Signed-off-by: Zhaoshenglong Message-id: 1513058845-9768-1-git-send-email-zhaoshenglong@huawei.com Signed-off-by: Peter Maydell --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 0255113470..45e2e2009b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -543,7 +543,7 @@ F: include/hw/*/xlnx*.h ARM ACPI Subsystem M: Shannon Zhao -M: Shannon Zhao +M: Shannon Zhao L: qemu-arm@nongnu.org S: Maintained F: hw/arm/virt-acpi-build.c From cbf8b991f8a3ea293a6b43c6f4738cc0e19c722c Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 049/546] xilinx_spips: Update the QSPI Mod ID reset value Update the reset value to match the latest ZynqMP register spec. Signed-off-by: Alistair Francis Reviewed-by: KONRAD Frederic Reviewed-by: Francisco Iglesias Message-id: c03e51d041db7f055596084891aeb1e856e32b9f.1513104804.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index ad1b2ba79f..899db814ee 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -355,6 +355,7 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d) s->regs[R_GQSPI_RX_THRESH] = 1; s->regs[R_GQSPI_GFIFO_THRESH] = 1; s->regs[R_GQSPI_IMR] = GQSPI_IXR_MASK; + s->regs[R_MOD_ID] = 0x01090101; s->man_start_com_g = false; s->gqspi_irqline = 0; xlnx_zynqmp_qspips_update_ixr(s); From 4f0da466ca209c670c010e7aad0ed041e0bf2461 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 050/546] xilinx_spips: Set all of the reset values Following the ZynqMP register spec let's ensure that all reset values are set. Signed-off-by: Alistair Francis Reviewed-by: Francisco Iglesias Message-id: 19836f3e0a298b13343c5a59c87425355e7fd8bd.1513104804.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 35 ++++++++++++++++++++++++++++++----- include/hw/ssi/xilinx_spips.h | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 899db814ee..42d9b04bd3 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -66,6 +66,7 @@ /* interrupt mechanism */ #define R_INTR_STATUS (0x04 / 4) +#define R_INTR_STATUS_RESET (0x104) #define R_INTR_EN (0x08 / 4) #define R_INTR_DIS (0x0C / 4) #define R_INTR_MASK (0x10 / 4) @@ -102,6 +103,9 @@ #define R_SLAVE_IDLE_COUNT (0x24 / 4) #define R_TX_THRES (0x28 / 4) #define R_RX_THRES (0x2C / 4) +#define R_GPIO (0x30 / 4) +#define R_LPBK_DLY_ADJ (0x38 / 4) +#define R_LPBK_DLY_ADJ_RESET (0x33) #define R_TXD1 (0x80 / 4) #define R_TXD2 (0x84 / 4) #define R_TXD3 (0x88 / 4) @@ -140,8 +144,12 @@ #define R_GQSPI_IER (0x108 / 4) #define R_GQSPI_IDR (0x10c / 4) #define R_GQSPI_IMR (0x110 / 4) +#define R_GQSPI_IMR_RESET (0xfbe) #define R_GQSPI_TX_THRESH (0x128 / 4) #define R_GQSPI_RX_THRESH (0x12c / 4) +#define R_GQSPI_GPIO (0x130 / 4) +#define R_GQSPI_LPBK_DLY_ADJ (0x138 / 4) +#define R_GQSPI_LPBK_DLY_ADJ_RESET (0x33) #define R_GQSPI_CNFG (0x100 / 4) FIELD(GQSPI_CNFG, MODE_EN, 30, 2) FIELD(GQSPI_CNFG, GEN_FIFO_START_MODE, 29, 1) @@ -177,8 +185,16 @@ FIELD(GQSPI_GF_SNAPSHOT, EXPONENT, 9, 1) FIELD(GQSPI_GF_SNAPSHOT, DATA_XFER, 8, 1) FIELD(GQSPI_GF_SNAPSHOT, IMMEDIATE_DATA, 0, 8) -#define R_GQSPI_MOD_ID (0x168 / 4) -#define R_GQSPI_MOD_ID_VALUE 0x010A0000 +#define R_GQSPI_MOD_ID (0x1fc / 4) +#define R_GQSPI_MOD_ID_RESET (0x10a0000) + +#define R_QSPIDMA_DST_CTRL (0x80c / 4) +#define R_QSPIDMA_DST_CTRL_RESET (0x803ffa00) +#define R_QSPIDMA_DST_I_MASK (0x820 / 4) +#define R_QSPIDMA_DST_I_MASK_RESET (0xfe) +#define R_QSPIDMA_DST_CTRL2 (0x824 / 4) +#define R_QSPIDMA_DST_CTRL2_RESET (0x081bfff8) + /* size of TXRX FIFOs */ #define RXFF_A (128) #define TXFF_A (128) @@ -351,11 +367,20 @@ static void xlnx_zynqmp_qspips_reset(DeviceState *d) fifo8_reset(&s->rx_fifo_g); fifo8_reset(&s->rx_fifo_g); fifo32_reset(&s->fifo_g); + s->regs[R_INTR_STATUS] = R_INTR_STATUS_RESET; + s->regs[R_GPIO] = 1; + s->regs[R_LPBK_DLY_ADJ] = R_LPBK_DLY_ADJ_RESET; + s->regs[R_GQSPI_GFIFO_THRESH] = 0x10; + s->regs[R_MOD_ID] = 0x01090101; + s->regs[R_GQSPI_IMR] = R_GQSPI_IMR_RESET; s->regs[R_GQSPI_TX_THRESH] = 1; s->regs[R_GQSPI_RX_THRESH] = 1; - s->regs[R_GQSPI_GFIFO_THRESH] = 1; - s->regs[R_GQSPI_IMR] = GQSPI_IXR_MASK; - s->regs[R_MOD_ID] = 0x01090101; + s->regs[R_GQSPI_GPIO] = 1; + s->regs[R_GQSPI_LPBK_DLY_ADJ] = R_GQSPI_LPBK_DLY_ADJ_RESET; + s->regs[R_GQSPI_MOD_ID] = R_GQSPI_MOD_ID_RESET; + s->regs[R_QSPIDMA_DST_CTRL] = R_QSPIDMA_DST_CTRL_RESET; + s->regs[R_QSPIDMA_DST_I_MASK] = R_QSPIDMA_DST_I_MASK_RESET; + s->regs[R_QSPIDMA_DST_CTRL2] = R_QSPIDMA_DST_CTRL2_RESET; s->man_start_com_g = false; s->gqspi_irqline = 0; xlnx_zynqmp_qspips_update_ixr(s); diff --git a/include/hw/ssi/xilinx_spips.h b/include/hw/ssi/xilinx_spips.h index 75fc94ce5d..d398a4e81c 100644 --- a/include/hw/ssi/xilinx_spips.h +++ b/include/hw/ssi/xilinx_spips.h @@ -32,7 +32,7 @@ typedef struct XilinxSPIPS XilinxSPIPS; #define XLNX_SPIPS_R_MAX (0x100 / 4) -#define XLNX_ZYNQMP_SPIPS_R_MAX (0x200 / 4) +#define XLNX_ZYNQMP_SPIPS_R_MAX (0x830 / 4) /* Bite off 4k chunks at a time */ #define LQSPI_CACHE_SIZE 1024 From d3c348b6e3af3598bfcb755d59f8f4de80a2228a Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Wed, 13 Dec 2017 17:59:26 +0000 Subject: [PATCH 051/546] xilinx_spips: Use memset instead of a for loop to zero registers Use memset() instead of a for loop to zero all of the registers. Signed-off-by: Alistair Francis Reviewed-by: KONRAD Frederic Reviewed-by: Francisco Iglesias Message-id: c076e907f355923864cb1afde31b938ffb677778.1513104804.git.alistair.francis@xilinx.com Signed-off-by: Peter Maydell --- hw/ssi/xilinx_spips.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 42d9b04bd3..d8187fadd1 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -329,10 +329,7 @@ static void xilinx_spips_reset(DeviceState *d) { XilinxSPIPS *s = XILINX_SPIPS(d); - int i; - for (i = 0; i < XLNX_SPIPS_R_MAX; i++) { - s->regs[i] = 0; - } + memset(s->regs, 0, sizeof(s->regs)); fifo8_reset(&s->rx_fifo); fifo8_reset(&s->rx_fifo); @@ -357,13 +354,11 @@ static void xilinx_spips_reset(DeviceState *d) static void xlnx_zynqmp_qspips_reset(DeviceState *d) { XlnxZynqMPQSPIPS *s = XLNX_ZYNQMP_QSPIPS(d); - int i; xilinx_spips_reset(d); - for (i = 0; i < XLNX_ZYNQMP_SPIPS_R_MAX; i++) { - s->regs[i] = 0; - } + memset(s->regs, 0, sizeof(s->regs)); + fifo8_reset(&s->rx_fifo_g); fifo8_reset(&s->rx_fifo_g); fifo32_reset(&s->fifo_g); From 81950da6819bbe77f38835724cc4643f19677554 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Nov 2017 21:19:00 +0100 Subject: [PATCH 052/546] hmp-commands: Remove the deprecated usb_add and usb_del It's easy to use device_add and device_del as replacement instead. The usb_add and usb_del commands are deprecated since QEMU 2.10, and nobody complained that they are still needed, so let's get rid of them now to make the HMP interface a little bit less overloaded. Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Thomas Huth Message-Id: <1512073140-17672-1-git-send-email-thuth@redhat.com> Signed-off-by: Dr. David Alan Gilbert --- hmp-commands.hx | 33 ------------------------------- hw/usb/bus.c | 22 --------------------- include/hw/usb.h | 1 - include/sysemu/sysemu.h | 2 -- qemu-doc.texi | 8 -------- vl.c | 44 ----------------------------------------- 6 files changed, 110 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 4afd57cf5f..6d5ebdf6ab 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -663,39 +663,6 @@ STEXI @item sum @var{addr} @var{size} @findex sum 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 { 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/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/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/qemu-doc.texi b/qemu-doc.texi index db2351c746..ee206b8cba 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2518,14 +2518,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/vl.c b/vl.c index 1ad1c04637..fc8bd9372f 100644 --- a/vl.c +++ b/vl.c @@ -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 */ From 0eaf3b824745cacebfc321aef6787528d33d58fe Mon Sep 17 00:00:00 2001 From: Vadim Galitsyn Date: Mon, 23 Oct 2017 17:13:10 +0200 Subject: [PATCH 053/546] tests: test-hmp: print command execution result Provide HMP monitor command execution result as it would be seen by user who established an HMP monitor session. Currently many commands may silently fail without any sign of that. This patch let this info to be printed once test is running in verbose mode. For the future it might be useful to fail the test if command has failed, however it would require a bit of rework inside test engine itself. A simple example of silent failure without reporting it would to add some non-existent HMP command into 'hmp_cmds' list. In this case test will report it successfully passed without error. Signed-off-by: Vadim Galitsyn Cc: Dr. David Alan Gilbert Cc: qemu-devel@nongnu.org Message-Id: <20171023151310.6462-5-vadim.galitsyn@profitbricks.com> Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- tests/test-hmp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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++) { - if (verbose) { - fprintf(stderr, "\t%s\n", hmp_cmds[i]); - } response = hmp("%s", hmp_cmds[i]); + if (verbose) { + fprintf(stderr, + "\texecute HMP command: %s\n" + "\tresult : %s\n", + hmp_cmds[i], response); + } g_free(response); } From 39b28b26cf5b7d397bbc5cd1750971efad331b4b Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 22 Nov 2017 15:26:26 +0100 Subject: [PATCH 054/546] s390x/migration: use zero flag parameter valgrind pointed out that we call KVM_S390_GET_IRQ_STATE with an undefined value for flags. Kernels prior to 4.15 did not use that field, and later kernels ignore it for compatibility reasons, but we better play safe. The same is true for SET_IRQ_STATE. We should make sure to not use the flag field, either. Signed-off-by: Christian Borntraeger Message-Id: <20171122142627.73170-2-borntraeger@de.ibm.com> Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/kvm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index b03f583032..f205e0a2ca 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1979,7 +1979,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 +1990,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 +2003,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 +2017,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); From 339686a358b11a231aa5b6d1424e7a1460d7f277 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 22 Nov 2017 15:26:27 +0100 Subject: [PATCH 055/546] pc-bios/s390-ccw: zero out bss section The QEMU ELF loader does not zero the bss segment. This resulted in several bugs, e.g. see commit 5d739a4787a5 (s390-ccw.img: Fix sporadic errors with ccw boot image - initialize css) commit 6a40fa2669d3 (s390-ccw.img: Initialize next_idx) commit 8775d91a0f42 (pc-bios/s390-ccw: Fix problem with invalid virtio-scsi LUN when rebooting) Let's fix this once and forever by letting the BIOS zero the bss itself. Suggested-by: Alexander Graf Signed-off-by: Christian Borntraeger Message-Id: <20171122142627.73170-3-borntraeger@de.ibm.com> Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: Cornelia Huck --- pc-bios/s390-ccw/start.S | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) 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 - * 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) From 039efad77b5923d7b3421d4e60b0d178e500fa34 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 22 Nov 2017 16:39:45 +0100 Subject: [PATCH 056/546] pc-bios/s390-ccw.img: update image Contains the following commit: - pc-bios/s390-ccw: zero out bss section Signed-off-by: Cornelia Huck --- pc-bios/s390-ccw.img | Bin 26416 -> 26416 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index 7415f1a3e797a17ce4ede0ee39034288b4ecae86..97155d2638eebc1220a63287fcada21df65b3a77 100644 GIT binary patch delta 1426 zcmYLJT}%{L6h3EISr;e_umTG#4$C6lg0Qj{s)*giwU!p@@?*uHs7*v4G`d>q4@s-7 z)J99qb`Nb6YjwrwSo^YYX>@&Pr)n)}6KY6Qd}vCtnwr?3p&?qeWqa??)cY{=-S3|J zoipD#ndk^cM=*5L5&~nb3w=2Lb>`6Yrse-PMe(e4_sPjmZjJ4GHTXeN^_h}64V`-} ze%dN+!66!xmhq>O^q%VvO$Jbojaqe82JH?&#^IO=`USGuH3eXCk->WCT2h6S0W_7= zjPt0;R5E)?9Hd_nL9-tj_$z@+Y6Qj}I%0aG@p_g+?MVz8r*X9sQ0;-74kcuyDl!!8 z4@3<3MNHaKL+x8bq1?bHjk~L;X~v3u2i3{MfWbBk7XCEwY9m51@D2m#3+xCRG2>>l zrUQOv6F9JQjDs zZ1uYpP$#D@-sDHzE$$q+=jQ+>u4Gzk14|IUizJK&&167%)%zTkMc?o_= zUCA-*ph|OD?lN_f>l!Pr>wCb-%Y#LwwAH*4U3A6lLM#1l{=xQ^>H=AOPJS~ts|!x& z^=l!3H9Ki^CgIbx$+C9lx`$enQ_1wbr4uicJ7otRrv8+A+)m>hS5s?heWphX0yM}0 zc>@T6h60MDG8|y-X-SAxtm7#gVn5rNUWS-VM>D+XD}Rg2dStq=mA}y4j5Qb|zg&)| zSWu254p4hm37()mS=(_l-OYL#TWEf^3)j-RY@2<#sCibOs2Q8I2%n}GxWUh8`#EZ) zzU-?~{ZF*kYR3`QZGC|DeqnU`3DxF>@Hy^vIUktZ#NWb|_C7k2a~j`d^K+{ZKc|g( zZJF<@Hh_45-!W-kfVRCfoOcSjeYO(JrjYIJVpGfl7qvTy!~+XY91fq0fcga&JwGkl zdWov@ci299qT`F|5uw$3fLoqSuQ+npX#N_+D^yunf`imrScON~JB0;^X>{DKNP)*p zv(G@>LsyGDxQRU~dKd9i+OMp@Ub>+yFL;p;?d9nnYXR;?ulgJmirLv-N8aKExRAPw zyQOX8bf0g2Cbz?em*^#j$1-G|5@B3izFc7A%osR*vVNbV zae*d)Cr9rMwr$>e#9cH}-Ds}m?Z@Y*sK{gIqrJ#;tL}m?H~~Io!p#j41q|~76g|qt zWx)DxME&VG@u;qGJ}8p%4#o_XP8OKogVLhE=*F`@;zc@BQ_Lq~xW>o3kWyRB2eG2I z96i)gYey&BRr{TU+i3B^0{ob*UYM6F4cum3ExRS$zK*3XK8F> eWs0A>D3;$#a%ZjO$$vG#cfskiwjc|2M(|(tW7}&0 delta 1349 zcmYLJZ%kEX7=ND2h06tn!@mm`xNzmoQwoLJ#%83G&4XwDI% z`GxSt!?c;&4W+}h+LgDZl-Ws~7;Z{z8B{hB{SaC^7-=60df&sA?}u}K@AE$A_dM_K z_v{3(WAHlqe=vJMUpqbT&VC)!yt1kN|4l(0j(_iDbXH5tQ{Q&aZ#?*?rSRpA-yHv) zUNh{$W|}r^=1)1~VD`8w0mvOw@tPumdKV!2#Ze;+3KaL3Dg#uc>Cs4<49PV_P190H z4VtOi=uE#U4x)~Ur1U8r9~RgdB{1%wKI7|EpTs(pp5+n!^h+fVQ0W0ngY4H!rRfZ| z8zKibikww8o$a{J5TfHw{oA!v9lCY%PGxcVtRBq}QJB#2lLD{)TgO#8eju>pRXyjt z$)sw4$K#d7rCZ{%kVS=I8BW)f34{E~B4QaCk>DO^02u@SYGFFcH!V?DSS8+~%VDF~ zMF&h-iB-xXfJt9-n)U{`R5w6b4P7v8!&-_D&&D#U2)}0iNXZ6CR8Owqck6(mq(RjW z(0G&_W3$L%y2Ssv4?x-2QQ131;KQi;e{r#r{pq$~P=T=C!%u{!A zyY;KbJl>!d5L{c%aLL2ygu}udDUFEt=|HLzf26_Ge7wY_Qd1BM=?|N1sC6cAlO#5>wZG6VYRy=!|rFifceLS7_PHEIhd5utTw_k&+~Bz0(x6$);*Tu<&kM{c_r;3N3#Mg z056W7C3bOb6XFR_}=ps)uGJfcVT;xoe$#vq8x0b z;UXJWvnxg820ToC>r?O|JH0+B(J)fTF4yieV33v7UyY!^P9HNiaYvh(yz8718)&*Y eFQQTdeN}2C?JhDu{uTQ8j`t>3oy`2Z1Na|Pug>TI From 67ee0cefb09672247f502c0f208f2a0e3c566173 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 24 Nov 2017 16:26:51 +0100 Subject: [PATCH 057/546] s390x: introduce 2.12 compat machine Acked-by: Christian Borntraeger Reviewed-by: David Hildenbrand Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 17 ++++++++++++++++- include/hw/compat.h | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 6a57f94197..a23b8aec9f 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -639,6 +639,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 +719,26 @@ 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) { + ccw_machine_2_12_instance_options(machine); } 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/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",\ From 9879003bb82c1351fa84feb81aa1bbcf7442ca84 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 30 Nov 2017 14:57:36 +0100 Subject: [PATCH 058/546] target/s390x: nuke DPRINTF in helper.c It is not used anywhere. Reviewed-by: Eric Blake Reviewed-by: David Hildenbrand Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- target/s390x/helper.c | 18 ------------------ 1 file changed, 18 deletions(-) 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) { From 8d2f850a5ab7579a852f23b28273940a47dfd7ff Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:29 +0100 Subject: [PATCH 059/546] s390x/tcg: introduce and use s390_program_interrupt() Allows to easily convert more callers of program_interrupt() and to easily introduce new exceptions without forgetting about the cpu state reset. Use s390_program_interrupt() in places where we already had the same pattern. We will later get rid of program_interrupt(). RA != 0 checks are already done behind the scenes. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-2-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 2 ++ target/s390x/crypto_helper.c | 7 ++----- target/s390x/excp_helper.c | 5 +---- target/s390x/interrupt.c | 13 +++++++++++++ target/s390x/mem_helper.c | 35 +++++++++++------------------------ target/s390x/misc_helper.c | 3 +-- 6 files changed, 30 insertions(+), 35 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 4db8b5409e..3340fdf4b5 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -720,6 +720,8 @@ void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, /* automatically detect the instruction length */ #define ILEN_AUTO 0xff void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +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); 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/excp_helper.c b/target/s390x/excp_helper.c index e04b670663..d831537544 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -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/interrupt.c b/target/s390x/interrupt.c index ce6177c141..b07e75daed 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -53,6 +53,19 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) } } +void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, + uintptr_t ra) +{ +#ifdef CONFIG_TCG + S390CPU *cpu = s390_env_get_cpu(env); + + if (tcg_enabled()) { + cpu_restore_state(CPU(cpu), ra); + } +#endif + program_interrupt(env, code, ilen); +} + #if !defined(CONFIG_USER_ONLY) static void cpu_inject_service(S390CPU *cpu, uint32_t param) { 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..1ccbafbb7d 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -519,8 +519,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(); From 7693f77a7f038393b14e54a578cf4b9aeec7a2da Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:30 +0100 Subject: [PATCH 060/546] s390x/tcg: get rid of runtime_exception() Let's use s390_program_interrupt() instead. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-3-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/fpu_helper.c | 2 +- target/s390x/int_helper.c | 14 +++++++------- target/s390x/internal.h | 2 -- target/s390x/misc_helper.c | 16 ---------------- 4 files changed, 8 insertions(+), 26 deletions(-) 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/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..db39d5bfac 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -408,8 +408,6 @@ 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); diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 1ccbafbb7d..67628e690d 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) { From fc21eb6bd9f340e8d2083064e86cf09868e69872 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:31 +0100 Subject: [PATCH 061/546] s390x/tcg: rip out dead tpi code It is broken and not even wired up. We'll add a new handler soon, but that will live somewhere else. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-4-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 6 ------ include/hw/s390x/css.h | 1 - target/s390x/internal.h | 1 - target/s390x/ioinst.c | 26 -------------------------- 4 files changed, 34 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index f6b5c807cd..6bd0fedc78 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) { diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index ab6ebe66b5..0a14f76fea 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); diff --git a/target/s390x/internal.h b/target/s390x/internal.h index db39d5bfac..603b0d7a7c 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -388,7 +388,6 @@ 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_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, uint32_t ipb); void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1); diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 23962fbebc..1d6857c14d 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -647,32 +647,6 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) } } -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) From 1b98fb99d39732231a247acb04823b1ddb5570a1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:32 +0100 Subject: [PATCH 062/546] s390x/ioinst: pass the retaddr to all IO instructions TCG needs the retaddr when injecting an interrupt. Let's just pass it along and use RA_IGNORED for KVM. The value will be completely ignored for KVM. Convert program_interrupt() to s390_program_interrupt() directly, making use of the passed address. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-5-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 1 + target/s390x/internal.h | 29 +++++++++-------- target/s390x/ioinst.c | 67 +++++++++++++++++++------------------- target/s390x/kvm.c | 27 +++++++-------- target/s390x/misc_helper.c | 20 ++++++------ 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 3340fdf4b5..96abb2976b 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -720,6 +720,7 @@ void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, /* 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 */ diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 603b0d7a7c..9db5f2d49d 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -379,20 +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); +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 */ diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 1d6857c14d..25e0ad6f77 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,7 +116,7 @@ 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))) { @@ -124,7 +124,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) } 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 +161,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,7 +172,7 @@ 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))) { @@ -181,7 +181,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) 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 +193,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 +203,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; } @@ -218,7 +218,8 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb) } } -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 +231,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 +242,7 @@ 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); } return; } @@ -278,7 +279,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb) 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 +290,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; } @@ -585,7 +586,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 +602,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; } /* @@ -616,7 +617,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) 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); @@ -653,7 +654,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb) #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; @@ -663,7 +664,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; } @@ -672,20 +673,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); @@ -700,7 +701,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; @@ -709,7 +710,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; } @@ -732,17 +733,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 f205e0a2ca..5e448e4136 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 */ @@ -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. diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 67628e690d..9b53abbfa7 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -323,7 +323,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(); } @@ -331,7 +331,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(); } @@ -339,7 +339,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(); } @@ -347,7 +347,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(); } @@ -355,7 +355,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(); } @@ -363,7 +363,7 @@ 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(); } @@ -371,7 +371,7 @@ 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(); } @@ -379,7 +379,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(); } @@ -387,7 +387,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(); } @@ -395,7 +395,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 From 468a93898a97639d8ba412d6a3cf9252f1927276 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:33 +0100 Subject: [PATCH 063/546] s390x/pci: pass the retaddr to all PCI instructions Once we wire up TCG, we will need the retaddr to correctly inject program interrupts. As we want to get rid of the function program_interrupt(), convert PCI code too. For KVM, we can simply use RA_IGNORED. Convert program_interrupt() to s390_program_interrupt() directly, making use of the passed address. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-6-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 83 +++++++++++++++++++++------------------- hw/s390x/s390-pci-inst.h | 16 ++++---- target/s390x/kvm.c | 14 +++---- 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8e088f3dc9..8123705dfd 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,7 +158,7 @@ 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; } @@ -168,7 +168,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) 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; } @@ -179,11 +179,11 @@ int clp_service_call(S390CPU *cpu, uint8_t r2) 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; } @@ -314,7 +314,7 @@ out: return 0; } -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; S390PCIBusDevice *pbdev; @@ -329,12 +329,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; } @@ -367,19 +367,19 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) if (pcias < 6) { if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + 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); 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); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } data = pci_host_config_read_common( @@ -398,7 +398,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = bswap64(data); break; default: - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } } else { @@ -425,7 +425,7 @@ static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) } } -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; @@ -439,12 +439,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; } @@ -478,7 +478,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = env->regs[r1]; if (pcias < 6) { if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -492,12 +492,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) result = memory_region_dispatch_write(mr, offset, data, len, MEMTXATTRS_UNSPECIFIED); 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); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } switch (len) { @@ -513,7 +513,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) data = bswap64(data); break; default: - program_interrupt(env, PGM_OPERAND, 4); + s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -531,7 +531,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 +545,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,7 +624,7 @@ 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; @@ -637,7 +637,7 @@ 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; } @@ -659,7 +659,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, case 128: break; default: - program_interrupt(env, PGM_SPECIFICATION, 6); + s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); return 0; } @@ -687,7 +687,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, mr = pbdev->pdev->io_regions[pcias].memory; if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -700,7 +700,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, 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; } } @@ -767,7 +767,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 +777,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 +805,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 +816,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 +825,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; } @@ -850,7 +852,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) } if (fib.fmt != 0) { - program_interrupt(env, PGM_OPERAND, 6); + s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -879,7 +881,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 +906,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 +937,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 +945,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 +957,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 +971,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; } diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 94a959f91c..93ef290101 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -293,13 +293,15 @@ 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); #endif diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 5e448e4136..5de6937b47 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -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; } From 968db419de26d3011670ca7eeab57424f93cd888 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:34 +0100 Subject: [PATCH 064/546] s390x/diag: pass the retaddr into handle_diag_308() Needed to later drop potential_page_fault() from the diag TCG translate function. Convert program_interrupt() to s390_program_interrupt() directly, making use of the passed address. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-7-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/diag.c | 14 +++++++------- target/s390x/internal.h | 3 ++- target/s390x/kvm.c | 2 +- target/s390x/misc_helper.c | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) 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/internal.h b/target/s390x/internal.h index 9db5f2d49d..6817b2c432 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -411,7 +411,8 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, /* misc_helper.c */ 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/kvm.c b/target/s390x/kvm.c index 5de6937b47..97c45d5537 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -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) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 9b53abbfa7..556340756c 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -88,7 +88,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; From 98ee9bedc734e18287902f39e3a3a8adb399386a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:35 +0100 Subject: [PATCH 065/546] s390x: handle exceptions during s390_cpu_virt_mem_rw() correctly (TCG) s390_cpu_virt_mem_rw() must always return, so callers can react on an exception (e.g. see ioinst_handle_stcrw()). However, for TCG we always have to exit the cpu loop (and restore the cpu state before that) if we injected a program interrupt. So let's introduce and use s390_cpu_virt_mem_handle_exc() in code that is not purely KVM. Directly pass the retaddr we already have available in these functions. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-8-david@redhat.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 7 +++++++ target/s390x/cpu.h | 1 + target/s390x/ioinst.c | 20 +++++++++++++++++--- target/s390x/mmu_helper.c | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8123705dfd..6f41083244 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -163,6 +163,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) } 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; @@ -174,6 +175,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) 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); @@ -189,6 +191,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) 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; } @@ -308,6 +311,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) 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); @@ -692,6 +696,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) { + s390_cpu_virt_mem_handle_exc(cpu, ra); return 0; } @@ -848,6 +853,7 @@ 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; } @@ -1029,6 +1035,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/target/s390x/cpu.h b/target/s390x/cpu.h index 96abb2976b..ae61d18c0a 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -736,6 +736,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/ioinst.c b/target/s390x/ioinst.c index 25e0ad6f77..83c164a168 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -120,6 +120,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t 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) || @@ -176,6 +177,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t 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); @@ -212,9 +214,12 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra) 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); } } @@ -243,6 +248,8 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, */ if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); + } else { + s390_cpu_virt_mem_handle_exc(cpu, ra); } return; } @@ -268,11 +275,13 @@ 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; } } @@ -309,6 +318,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) /* 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); @@ -316,6 +326,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra) 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; } } @@ -611,6 +622,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) * 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; @@ -645,6 +657,8 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra) 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); } } diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 31e3f3f415..dbe2f511f8 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" @@ -478,6 +479,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 +518,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 From 820613b1c1c76cb77a15313eb333a710972614ec Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:36 +0100 Subject: [PATCH 066/546] s390x/tcg: don't exit the cpu loop in s390_cpu_virt_mem_rw() s390_cpu_virt_mem_rw() must always return, so callers can react on an exception (e.g. see ioinst_handle_stcrw()). Therefore, using program_interrupt() is wrong. Fix that up. Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-9-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/mmu_helper.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index dbe2f511f8..f477cc006a 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -64,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); } } @@ -443,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) @@ -459,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; From 0ef28497768d9ff354aaa93087643f7046c89679 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:37 +0100 Subject: [PATCH 067/546] s390x/tcg: io instructions don't need potential_page_fault() As we handle the retaddr in all cases properly now, we can drop it. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-10-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/translate.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 85d0a6c3af..d0859c4bc7 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4008,7 +4008,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 +4016,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 +4024,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 +4032,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 +4040,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,7 +4048,6 @@ 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; @@ -4062,7 +4056,6 @@ static ExitStatus op_rsch(DisasContext *s, DisasOps *o) 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,7 +4064,6 @@ 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; @@ -4080,7 +4072,6 @@ static ExitStatus op_stsch(DisasContext *s, DisasOps *o) 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 +4080,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; From 1a38921a61d1394089186c03491321b6e682793c Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:38 +0100 Subject: [PATCH 068/546] s390x/tcg: use s390_program_interrupt() in SCLP Service Call Now we can drop potential_page_fault(). While at it, move the unlock further up, looks cleaner. Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-11-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/misc_helper.c | 7 +++---- target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 556340756c..02654617b3 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -62,11 +62,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); - if (r < 0) { - program_interrupt(env, -r, 4); - r = 0; - } qemu_mutex_unlock_iothread(); + if (r < 0) { + s390_program_interrupt(env, -r, 4, GETPC()); + } return r; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d0859c4bc7..76b222b0ce 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3704,7 +3704,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; From 277b156d8dd4d54fa00997ef384d4503dd057479 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:39 +0100 Subject: [PATCH 069/546] s390x/tcg: use s390_program_interrupt() in DIAG Now we can drop the two save statements in the translate function. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-12-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/misc_helper.c | 2 +- target/s390x/translate.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 02654617b3..ee6179ef89 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -101,7 +101,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()); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 76b222b0ce..cf8ffa217e 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2124,9 +2124,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); From 8808338200fe3bb2b475fa7b6492b34c1d32fdd2 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:40 +0100 Subject: [PATCH 070/546] s390x/tcg: use s390_program_interrupt() in per_check_exception() We can now drop updating the cc. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-13-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/misc_helper.c | 2 +- target/s390x/translate.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index ee6179ef89..a911bff706 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -412,7 +412,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()); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index cf8ffa217e..f26fa64a78 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -5837,9 +5837,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); } From 005a0491846db216ef9d3b31f8567fd5527aa0c5 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:41 +0100 Subject: [PATCH 071/546] s390x/tcg: use s390_program_interrupt() in SACF Convert this user, too. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-14-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } } From 5e8f154e88c0722377a36ee2d21873cb23c5ef42 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:42 +0100 Subject: [PATCH 072/546] s390x/tcg: use s390_program_interrupt() in STSI STSI needs some more love, but let's do one step at a time. We can now drop potential_page_fault(). Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-15-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/misc_helper.c | 2 +- target/s390x/translate.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index a911bff706..6d766ce1e7 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -184,7 +184,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; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index f26fa64a78..1ce1390699 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3988,7 +3988,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; From 51dcdbd319f8d46834d8155defc8d384a9958a73 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:43 +0100 Subject: [PATCH 073/546] s390x/tcg: drop program_interrupt() All users are gone, we can finally drop it and make sure that all new program interrupt injections are reminded of the retaddr - as they have to use s390_program_interrupt() now. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-16-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 1 - target/s390x/interrupt.c | 22 +++++----------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index ae61d18c0a..9cfbbbac04 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -719,7 +719,6 @@ 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); diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index b07e75daed..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,25 +48,12 @@ 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(); } } -void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen, - uintptr_t ra) -{ -#ifdef CONFIG_TCG - S390CPU *cpu = s390_env_get_cpu(env); - - if (tcg_enabled()) { - cpu_restore_state(CPU(cpu), ra); - } -#endif - program_interrupt(env, code, ilen); -} - #if !defined(CONFIG_USER_ONLY) static void cpu_inject_service(S390CPU *cpu, uint32_t param) { From cb3129c3762ceadabcef7e9d319bae9243fc238e Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Thu, 30 Nov 2017 17:27:44 +0100 Subject: [PATCH 074/546] s390x/tcg: drop potential_page_fault() Only one user left, get rid of it so we don't get any new users. Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171130162744.25442-17-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/translate.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 1ce1390699..26cf993405 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); @@ -2939,7 +2933,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; } From c748814b20f1f1b43eed1fd32c84579c60f4cc58 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:24 +0100 Subject: [PATCH 075/546] s390x/pci: factor out endianess conversion There are two places where the same endianness conversion is done. Let's factor this out into a static function. Note that the conversion must always be done for data in a register: The S390 BE guest converted date to le before issuing the instruction. After interception in a BE host: ZPCI VFIO using pwrite must make the conversion back for the BE kernel. Kernel will do BE to le translation when loading the register for the real instruction. After interception in a le host: TCG stores a BE register in le, swapping bytes. But since the data in the register was already le it is now BE ZPCI VFIO must convert it to le before writing to the PCI memory. In both cases ZPCI VFIO must swap the bytes from the register. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-2-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 58 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 6f41083244..cb84d209e0 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -318,6 +318,36 @@ out: return 0; } +/** + * 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; +} + int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) { CPUS390XState *env = &cpu->env; @@ -389,19 +419,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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: + if (zpci_endian_swap(&data, len)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -504,19 +522,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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: + if (zpci_endian_swap(&data, len)) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } From 7645b9a794741be6d007d8074c73c4510d269ad4 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:25 +0100 Subject: [PATCH 076/546] s390x/pci: rework PCI STORE Enhance the fault detection, correction of the fault reporting. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-3-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 41 ++++++++++++++++++++++++---------------- hw/s390x/s390-pci-inst.h | 4 ++++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index cb84d209e0..66d191f57f 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -474,6 +474,12 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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) { @@ -483,12 +489,10 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } 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); @@ -497,9 +501,13 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - data = env->regs[r1]; - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { + 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; } @@ -517,20 +525,21 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { + 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; } - if (zpci_endian_swap(&data, len)) { - 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); diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index 93ef290101..a396364635 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -304,4 +304,8 @@ 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, uintptr_t ra); +#define ZPCI_IO_BAR_MIN 0 +#define ZPCI_IO_BAR_MAX 5 +#define ZPCI_CONFIG_BAR 15 + #endif From 8cbd6aab9579a1ce0601049ea4bce5ea37a668ce Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:26 +0100 Subject: [PATCH 077/546] s390x/pci: rework PCI LOAD Enhance the fault detection, correction of the fault reporting. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-4-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 66d191f57f..48ccf2289e 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -377,6 +377,11 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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"); @@ -385,12 +390,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } 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); @@ -399,8 +399,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { + 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; } @@ -411,8 +412,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { + break; + case ZPCI_CONFIG_BAR: + if (!len || (len > (4 - (offset & 0x3))) || len == 3) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; } @@ -423,8 +425,9 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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; From 0e7c259adff7e97f829a08a5f146e7ee03b5ae47 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:27 +0100 Subject: [PATCH 078/546] s390x/pci: rework PCI STORE BLOCK Enhance the fault detection. Fixup the precedence to check the destination path existance before checking for the source accessibility. Add the maxstbl entry to both the Query PCI Function Group response and the PCIBusDevice structure. Initialize the maxstbl to 128 per default until we get the actual data from the hardware. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-5-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-bus.h | 1 + hw/s390x/s390-pci-inst.c | 63 +++++++++++++++++++++++++--------------- hw/s390x/s390-pci-inst.h | 2 +- 3 files changed, 41 insertions(+), 25 deletions(-) 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 48ccf2289e..e70cd04eb4 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -297,6 +297,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra) 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); @@ -652,6 +653,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, S390PCIBusDevice *pbdev; MemoryRegion *mr; MemTxResult result; + uint64_t offset; int i; uint32_t fh; uint8_t pcias; @@ -666,22 +668,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, 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: - s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra); + if (!(fh & FH_MASK_ENABLE)) { + setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); return 0; } @@ -693,12 +683,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); @@ -707,8 +692,34 @@ 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)) { + if (!memory_region_access_valid(mr, offset, len, true)) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; } @@ -719,9 +730,9 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } 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) { s390_program_interrupt(env, PGM_OPERAND, 6, ra); return 0; @@ -730,6 +741,10 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, 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) diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h index a396364635..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 */ From ab0380cab330c986ac6db91df1679c035d19ae77 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:28 +0100 Subject: [PATCH 079/546] s390x/pci: move the memory region read from pcilg Let's move the memory region read from pcilg into a dedicated function. This allows us to prepare a later patch. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Reviewed-by: Thomas Huth Message-Id: <1512046530-17773-6-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index e70cd04eb4..f0247e0ba7 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -349,13 +349,22 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len) return 0; } +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; + 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; @@ -406,9 +415,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) 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) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; From 8af27a9eab16f92990ce9b562719bdb485ffaf1b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:29 +0100 Subject: [PATCH 080/546] s390x/pci: move the memory region write from pcistg Let's move the memory region write from pcistg into a dedicated function. This allows us to prepare a later patch searching for subregions inside of the memory region. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Reviewed-by: Thomas Huth Message-Id: <1512046530-17773-7-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index f0247e0ba7..4b3be7af83 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -458,12 +458,27 @@ 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) +{ + MemoryRegion *mr; + + 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; + } + + return memory_region_dispatch_write(mr, offset, data, len, + MEMTXATTRS_UNSPECIFIED); +} + 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; @@ -523,15 +538,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t 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) { s390_program_interrupt(env, PGM_OPERAND, 4, ra); return 0; From 4f6482bfe3da1e6b51ad4722a0c22f22f0d54a3b Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 30 Nov 2017 13:55:30 +0100 Subject: [PATCH 081/546] s390x/pci: search for subregion inside the BARs When dispatching memory access to PCI BAR region, we must look for possible subregions, used by the PCI device to map different memory areas inside the same PCI BAR. Since the data offset we received is calculated starting at the region start address we need to adjust the offset for the subregion. The data offset inside the subregion is calculated by substracting the subregion's starting address from the data offset in the region. The access to the MSIX region is now handled in a generic way, we do not need the specific trap_msix() function anymore. Signed-off-by: Pierre Morel Reviewed-by: Yi Min Zhao Message-Id: <1512046530-17773-8-git-send-email-pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 44 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 4b3be7af83..be449210d9 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -349,12 +349,31 @@ static int zpci_endian_swap(uint64_t *ptr, uint8_t len) 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); } @@ -446,30 +465,14 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) -{ - 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; - } -} - static MemTxResult zpci_write_bar(S390PCIBusDevice *pbdev, uint8_t pcias, uint64_t offset, uint64_t data, uint8_t len) { MemoryRegion *mr; - 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; - } - + 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); } @@ -733,6 +736,9 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, } mr = pbdev->pdev->io_regions[pcias].memory; + 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; From 99577c492fb2916165ed9bc215f058877f0a4106 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 6 Dec 2017 15:44:37 +0100 Subject: [PATCH 082/546] s390x/css: unrestrict cssids The default css 0xfe is currently restricted to virtual subchannel devices. The hope when the decision was made was, that non-virtual subchannel devices will come around when guest can exploit multiple channel subsystems. Since the guests generally don't do, the pain of the partitioned (cssid) namespace outweighs the gain. Let us remove the corresponding restrictions (virtual devices can be put only in 0xfe and non-virtual devices in any css except the 0xfe -- while s390-squash-mcss then remaps everything to cssid 0). At the same time, change our schema for generating css bus ids to put both virtual and non-virtual devices into the default css (spilling over into other css images, if needed). The intention is to deprecate s390-squash-mcss. With this change devices without a specified devno won't end up hidden to guests not supporting multiple channel subsystems, unless this can not be avoided (default css full). Let us also advertise the changes to the management software (so it can tell are cssids unrestricted or restricted). The adverse effect of getting rid of the restriction on migration should not be too severe. Vfio-ccw devices are not live-migratable yet, and for virtual devices using the extra freedom would only make sense with the aforementioned guest support in place. The auto-generated bus ids are affected by both changes. We hope to not encounter any auto-generated bus ids in production as Libvirt is always explicit about the bus id. Since 8ed179c937 ("s390x/css: catch section mismatch on load", 2017-05-18) the worst that can happen because the same device ended up having a different bus id is a cleanly failed migration. I find it hard to reason about the impact of changed auto-generated bus ids on migration for command line users as I don't know which rules is such an user supposed to follow. Another pain-point is down- or upgrade of QEMU for command line users. The old way and the new way of doing vfio-ccw are mutually incompatible. Libvirt is only going to support the new way, so for libvirt users, the possible problems at QEMU downgrade are the following. If a domain contains virtual devices placed into a css different than 0xfe the domain will refuse to start with a QEMU not having this patch. Putting devices into a css different that 0xfe however won't make much sense in the near future (guest support). Libvirt will refuse to do vfio-ccw with a QEMU not having this patch. This is business as usual. Signed-off-by: Halil Pasic Acked-by: Christian Borntraeger Reviewed-by: Dong Jia Shi Message-Id: <20171206144438.28908-2-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/3270-ccw.c | 2 +- hw/s390x/css-bridge.c | 11 +++++++++++ hw/s390x/css.c | 28 ++++------------------------ hw/s390x/s390-ccw.c | 2 +- hw/s390x/s390-virtio-ccw.c | 1 - hw/s390x/virtio-ccw.c | 2 +- include/hw/s390x/css.h | 12 ++++-------- 7 files changed, 22 insertions(+), 36 deletions(-) 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..a91a237f37 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -123,6 +123,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 +136,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 6bd0fedc78..f071e1394b 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -2364,21 +2364,11 @@ 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; @@ -2390,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); } @@ -2412,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-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index a23b8aec9f..5d4aaaf158 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -302,7 +302,6 @@ 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); 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/include/hw/s390x/css.h b/include/hw/s390x/css.h index 0a14f76fea..35facb47d2 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -271,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 @@ -285,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); From d69969e55f2187188c3d2a0ea9c6be29631358fb Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Wed, 6 Dec 2017 15:44:38 +0100 Subject: [PATCH 083/546] s390x: deprecate s390-squash-mcss machine prop With the cssids unrestricted (commit "s390x/css: unrestrict cssids") the s390-squash-mcss machine property should not be used. Actually Libvirt never supported this, so the expectation is that removing it should be pretty painless. But let's play nice and deprecate it first. Signed-off-by: Halil Pasic Message-Id: <20171206144438.28908-3-pasic@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 7 ++++++- qemu-doc.texi | 8 ++++++++ qemu-options.hx | 8 +++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 5d4aaaf158..fe3f3b2ad6 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -308,6 +308,11 @@ static void ccw_init(MachineState *machine) } 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(); @@ -582,7 +587,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); diff --git a/qemu-doc.texi b/qemu-doc.texi index ee206b8cba..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) 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 From 864c2512576ab4e0d84bda0481b15dd1820d43de Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 28 Nov 2017 14:08:14 +0100 Subject: [PATCH 084/546] s390x/css: attach css bridge Logically, the css bridge should be attached to the machine. Reviewed-by: Christian Borntraeger Reviewed-by: David Hildenbrand Tested-by: Bjoern Walk Signed-off-by: Cornelia Huck --- hw/s390x/css-bridge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index a91a237f37..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 */ From b700d75eda81c371c575b759de8e260d9f147494 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:54 +0100 Subject: [PATCH 085/546] s390x/kvm: factor out build_channel_report_mcic() into cpu.h We'll need it later on in two places. Refactor it to just indicate the validity bits. While at it, introduce a define for the used CR14 bit (we'll also need later on). Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-2-david@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Cornelia Huck --- target/s390x/cpu.h | 23 +++++++++++++++++++++++ target/s390x/kvm.c | 25 ++----------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 9cfbbbac04..f9d4d62c48 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); diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index 97c45d5537..9b8b59f2a2 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -1852,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); } From b8d55db07089493da8cc264ab5991253e1102822 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:55 +0100 Subject: [PATCH 086/546] s390x/tcg: fix and cleanup mcck injection The architecture mode indication wasn't stored. The split of certain 64bit fields was unnecessary. Also, the complete clock comparator, not just bit 0-55 (starting at byte 1) was stored. We now generate a proper MCIC via the same helper we use for KVM. There is more to clean up, but we will change the other parts later on either way. Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-3-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/excp_helper.c | 12 ++++++------ target/s390x/internal.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index d831537544..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); diff --git a/target/s390x/internal.h b/target/s390x/internal.h index 6817b2c432..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 */ From 257a119ee3464a0558d47f692fb007b2713e24ec Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:56 +0100 Subject: [PATCH 087/546] s390x/tcg: implement SET CLOCK PROGRAMMABLE FIELD Needed for machine check handling inside Linux (when restoring registers). Except for SIGP and machine checks, we don't make use of the register yet. Sufficient for now. Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-4-david@redhat.com> Reviewed-by: Richard Henderson Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/misc_helper.c | 11 +++++++++++ target/s390x/translate.c | 7 +++++++ 4 files changed, 21 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 9459b73c73..3eb7715e5b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -127,6 +127,7 @@ 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 16e27c8a35..8c2541f545 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -999,6 +999,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 */ diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 6d766ce1e7..769ec52e1d 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -146,6 +146,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) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 26cf993405..d13f531c5b 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3922,6 +3922,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); From a63b7cbf884b98d4de1cf6519143fa8202f76fe1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:57 +0100 Subject: [PATCH 088/546] s390x/tcg: indicate value of TODPR in STCKE We were not yet using the value of the TOD Programmable Register. Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-5-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d13f531c5b..38e1770e5e 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3897,7 +3897,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 @@ -3905,11 +3908,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; From 5a59bc1de21921996545574822e92004629dbd37 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:58 +0100 Subject: [PATCH 089/546] s390x/tcg: wire up STORE CHANNEL REPORT WORD CRW machine check handling requires STCRW. So let's wire it up. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-6-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 1 + target/s390x/misc_helper.c | 9 +++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 19 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 3eb7715e5b..ba11cfdc30 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -166,6 +166,7 @@ DEF_HELPER_3(msch, void, env, i64, i64) DEF_HELPER_2(rchp, void, env, i64) DEF_HELPER_2(rsch, void, env, 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 8c2541f545..43ab1963c8 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1055,6 +1055,7 @@ C(0xb23b, RCHP, S, Z, 0, 0, 0, 0, rchp, 0) C(0xb238, RSCH, S, Z, 0, 0, 0, 0, rsch, 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/misc_helper.c b/target/s390x/misc_helper.c index 769ec52e1d..04fb53d8a3 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -385,6 +385,15 @@ void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) 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(); +} + void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 38e1770e5e..08c1ace0d8 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4071,6 +4071,14 @@ static ExitStatus op_stsch(DisasContext *s, DisasOps *o) 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); From 0e9383bca8b92c4b457a46af0e351b7712984622 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:01:59 +0100 Subject: [PATCH 090/546] s390x/tcg: ASI/ASGI/ALSI/ALSGI are atomic with Interlocked-acccess facility 1 The semantics of ASI/ASGI/ALSI/ALSGI changed. Let's implement them just like LOAD AND ADD, so they are atomic. Emulate old behavior. This fixes random crashes when booting a Linux kernel compiled for z196+ with SMP + MTTCG. Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-7-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 8 ++++---- target/s390x/translate.c | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 43ab1963c8..166ee7c80b 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) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 08c1ace0d8..7ab8e853ab 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1364,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); From f400be1813ee581f15bb2e93b463e2d9857e12f4 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:00 +0100 Subject: [PATCH 091/546] s390x/tcg: implement Interlocked-Access Facility 2 With this facility, OI/OIY, NI/NIY and XI/XIY are atomic. All operate on one byte (MO_UB). Emulate old behavior. Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-8-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu_models.c | 1 + target/s390x/insn-data.def | 12 ++++---- target/s390x/translate.c | 63 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index c4c37b3b15..94d24e423d 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -842,6 +842,7 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) S390_FEAT_STFLE_45, S390_FEAT_STFLE_49, S390_FEAT_LOCAL_TLB_CLEARING, + S390_FEAT_INTERLOCKED_ACCESS_2, S390_FEAT_STFLE_53, S390_FEAT_MSA_EXT_5, S390_FEAT_MSA_EXT_3, diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 166ee7c80b..6cbd604814 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -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) @@ -698,8 +698,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 diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 7ab8e853ab..de00b9471a 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1427,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)); @@ -3378,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)); @@ -4643,6 +4685,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); From 86c34633c5a822e5eebed96ae163426e2615abc1 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:01 +0100 Subject: [PATCH 092/546] s390x/tcg: wire up SET ADDRESS LIMIT Let's handle it just like KVM: Depending on the model, this instruction may not be provided. When this instruction is not provided, it is checked for operand exception and privileged-opera- tion exception, and then is suppressed. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-9-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 1 + target/s390x/misc_helper.c | 9 +++++++++ target/s390x/translate.c | 7 +++++++ 4 files changed, 18 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index ba11cfdc30..f1acc34f36 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -165,6 +165,7 @@ 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_3(ssch, void, env, i64, i64) DEF_HELPER_2(stcrw, void, env, i64) DEF_HELPER_3(stsch, void, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 6cbd604814..11746f5298 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1054,6 +1054,7 @@ 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(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) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 04fb53d8a3..1941c9c3de 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -377,6 +377,15 @@ void HELPER(rsch)(CPUS390XState *env, uint64_t r1) 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(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index de00b9471a..30d3d767ea 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4118,6 +4118,13 @@ static ExitStatus op_rsch(DisasContext *s, DisasOps *o) 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_ssch(DisasContext *s, DisasOps *o) { check_privileged(s); From a9de75a0b8b5acb26f26bd0048f0a33b416e5f66 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:02 +0100 Subject: [PATCH 093/546] s390x/tcg: wire up SET CHANNEL MONITOR Let's just wire it up like KVM. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-10-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 1 + target/s390x/misc_helper.c | 9 +++++++++ target/s390x/translate.c | 7 +++++++ 4 files changed, 18 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index f1acc34f36..102fbdd7b9 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -166,6 +166,7 @@ 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 11746f5298..0c225d5e78 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1055,6 +1055,7 @@ 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(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) diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 1941c9c3de..7ddade2f0e 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -386,6 +386,15 @@ void HELPER(sal)(CPUS390XState *env, uint64_t r1) 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(); +} + void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst) { S390CPU *cpu = s390_env_get_cpu(env); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 30d3d767ea..8cf35a7b49 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4125,6 +4125,13 @@ static ExitStatus op_sal(DisasContext *s, DisasOps *o) 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_ssch(DisasContext *s, DisasOps *o) { check_privileged(s); From b9b0a4dc13cc6180c79056a7d15e828e93a24a41 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:03 +0100 Subject: [PATCH 094/546] s390x/tcg: Implement STORE CHANNEL PATH STATUS Just like KVM does, we should suppress this instruction: When this instruction is not provided, it is checked for privileged operation exception and the instruction is suppressed by the machine Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-11-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 1 + target/s390x/translate.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 0c225d5e78..2e47a6b5bc 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1056,6 +1056,7 @@ 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(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) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 8cf35a7b49..16febf4274 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4132,6 +4132,13 @@ static ExitStatus op_schm(DisasContext *s, DisasOps *o) 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); From ad0ccf1e6a45c22d6c0564f8365bf1df39c64c15 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:04 +0100 Subject: [PATCH 095/546] s390x/tcg: Implement SIGNAL ADAPTER instruction KVM suppresses SIGA, setting cc=3. Let's do the same for TCG, so we're at least equal. Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-12-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/insn-data.def | 1 + target/s390x/translate.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 2e47a6b5bc..250741330d 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -1056,6 +1056,7 @@ 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) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 16febf4274..83e1df0f48 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4132,6 +4132,14 @@ static ExitStatus op_schm(DisasContext *s, DisasOps *o) 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); From 4bac52f5c4b3dd5d0bd7568377ad7e957d5e3c6a Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:05 +0100 Subject: [PATCH 096/546] s390x/tcg: implement extract-CPU-time facility It only provides the EXTRACT CPU TIME instruction. We can reuse the stpt helper, which calculates the CPU timer value. As the instruction is not privileged, but we don't have a CPU timer value in case of linux user, we simply reuse cpu_get_host_ticks() to produce some descending value. Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-13-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu_models.c | 1 + target/s390x/helper.h | 2 +- target/s390x/insn-data.def | 2 ++ target/s390x/misc_helper.c | 21 +++++++++++++++------ target/s390x/translate.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 94d24e423d..0be037eac1 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -834,6 +834,7 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) 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, diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 102fbdd7b9..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) @@ -130,7 +131,6 @@ 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 250741330d..11ee43dcbc 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -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 */ diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 7ddade2f0e..86da6aab7e 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -55,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 */ @@ -178,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) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 83e1df0f48..eede2ed157 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3917,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) { @@ -5679,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" From 33ae8a424245bb9ebb66875ca5b16c26f9e88da6 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:02:06 +0100 Subject: [PATCH 097/546] s390x/tcg: we already implement the Set-Program-Parameter facility The Set-Program-Parameter facility (also known as Load-Program-Parameter facility) provides the LPP instruction used to load the program parameter. We already implement that instruction in TCG, so add it to our list. Note: Not documented in the PoP but in "The Load-Program-Parameter and CPU-Measurement Facilities) - SA23-2260-05 document. While at it, make the whole list ordered (according to cpu_features_def.h). Reviewed-by: Richard Henderson Signed-off-by: David Hildenbrand Message-Id: <20171208160207.26494-14-david@redhat.com> Signed-off-by: Cornelia Huck --- target/s390x/cpu_models.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 0be037eac1..edac7fdecf 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -824,12 +824,12 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) 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_EXTENDED_IMMEDIATE, + S390_FEAT_EXTENDED_TRANSLATION_3, S390_FEAT_ETF2_ENH, S390_FEAT_STORE_CLOCK_FAST, S390_FEAT_MOVE_WITH_OPTIONAL_SPEC, @@ -839,6 +839,7 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) 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, From 35b4df6417fc3cd9d0150590f770fdd404dfbee7 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Fri, 8 Dec 2017 17:55:29 +0100 Subject: [PATCH 098/546] s390x: change the QEMU cpu model to a stripped down z12 We are good enough to boot upstream Linux kernels / Fedora 26/27. That should be sufficient for now. As the QEMU CPU model is migration safe, let's add compatibility code. Generate the feature list to reduce the chance of messing things up in the future. Signed-off-by: David Hildenbrand Message-Id: <20171208165529.14124-1-david@redhat.com> [CH: squashed 's390x/cpumodel: make qemu cpu model play with "none" machine' (20171213132407.5227-1-david@redhat.com) and 's390x/tcg: don't include z13 features in the qemu model' (20171213171512.17601-1-david@redhat.com) into patch] Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 4 ++ target/s390x/cpu.h | 3 + target/s390x/cpu_models.c | 106 ++++++++++++++++-------------------- target/s390x/cpu_models.h | 1 + target/s390x/gen-features.c | 88 ++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 59 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fe3f3b2ad6..466e45343c 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -734,7 +734,11 @@ 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) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index f9d4d62c48..1a8b6b9ae9 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -722,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) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index edac7fdecf..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,51 +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_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_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; @@ -869,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; @@ -1130,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) @@ -1282,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); @@ -1296,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/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; } From c4a2e3a9709aa7c84def7bc4bfbdcaf37ccf7527 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 Oct 2017 18:58:14 +0200 Subject: [PATCH 099/546] target/ppc: Use tcg_gen_lookup_and_goto_ptr Signed-off-by: Richard Henderson Reviewed-by: Daniel Henrique Barboza Signed-off-by: David Gibson --- target/ppc/translate.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) 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) From e0f7110acaaa222591e5f025953934c70c5ae15f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 10 Nov 2017 15:20:08 +0000 Subject: [PATCH 100/546] ppc/xics: remove useless if condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous code section uses a 'first < 0' test and returns. Therefore, there is no need to test the 'first' variable against '>= 0' afterwards. Signed-off-by: Cédric Le Goater Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/intc/xics_spapr.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index d98ea8b130..e8c0a1b3e9 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -329,10 +329,8 @@ int spapr_ics_alloc_block(ICSState *ics, int num, bool lsi, return -1; } - if (first >= 0) { - for (i = first; i < first + num; ++i) { - ics_set_irq_type(ics, i, lsi); - } + for (i = first; i < first + num; ++i) { + ics_set_irq_type(ics, i, lsi); } first += ics->offset; From 2b6154120cbd7f5514cefd3c6084d39922d26d88 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Mon, 13 Nov 2017 16:50:40 +1100 Subject: [PATCH 101/546] spapr: Add pseries-2.12 machine type While we're at it fix a couple of small errors in the 2.11 and 2.10 models (they didn't have any real effect, but don't quite match the template). Signed-off-by: David Gibson --- hw/ppc/spapr.c | 30 +++++++++++++++++++++++++----- include/hw/compat.h | 2 ++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 1ac7eb0f8c..8881f2f1e8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3714,27 +3714,47 @@ static const TypeInfo spapr_machine_info = { type_init(spapr_machine_register_##suffix) /* - * pseries-2.11 + * pseries-2.12 */ -static void spapr_machine_2_11_instance_options(MachineState *machine) +static void spapr_machine_2_12_instance_options(MachineState *machine) { } -static void spapr_machine_2_11_class_options(MachineClass *mc) +static void spapr_machine_2_12_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE(2_11, "2.11", true); +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) +{ + spapr_machine_2_12_class_options(mc); + SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_2_11); +} + +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/include/hw/compat.h b/include/hw/compat.h index cf389b4e85..0d2a6ac468 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -1,6 +1,8 @@ #ifndef HW_COMPAT_H #define HW_COMPAT_H +#define HW_COMPAT_2_11 + #define HW_COMPAT_2_10 \ {\ .driver = "virtio-mouse-device",\ From 94ad93bd976841c26af75322301f5aad925114d6 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 20 Nov 2017 10:19:54 +0100 Subject: [PATCH 102/546] spapr_cpu_core: instantiate CPUs separately The current code assumes that only the CPU core object holds a reference on each individual CPU object, and happily frees their allocated memory when the core is unrealized. This is dangerous as some other code can legitimely keep a pointer to a CPU if it calls object_ref(), but it would end up with a dangling pointer. Let's allocate all CPUs with object_new() and let QOM free them when their reference count reaches zero. This greatly simplify the code as we don't have to fiddle with the instance size anymore. Signed-off-by: Greg Kurz Acked-by: Igor Mammedov Signed-off-by: David Gibson --- hw/ppc/spapr.c | 11 +++-------- hw/ppc/spapr_cpu_core.c | 19 +++++++------------ include/hw/ppc/spapr_cpu_core.h | 2 +- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8881f2f1e8..f1b96a4e92 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3180,12 +3180,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 +3229,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 +3274,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); } } diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 3a4c174012..588f9b4571 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -79,13 +79,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); @@ -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/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; From e75ce32a75ba2fe78579882cfa06590edec2cd4a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 19 Nov 2017 21:24:13 -0600 Subject: [PATCH 103/546] e500: name openpic and pci host bridge Signed-off-by: Michael Davidsaver Signed-off-by: David Gibson --- hw/ppc/e500.c | 4 ++++ 1 file changed, 4 insertions(+) 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); From 5d8424dbd3e8335ea3d57f64eaa603c8fc80706f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 19 Nov 2017 21:24:17 -0600 Subject: [PATCH 104/546] nvram: add AT24Cx i2c eeprom Signed-off-by: Michael Davidsaver Signed-off-by: David Gibson --- hw/nvram/Makefile.objs | 1 + hw/nvram/eeprom_at24c.c | 205 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 hw/nvram/eeprom_at24c.c 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 + +#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) From 403aacdb44219fcdb198e0293288a818b6cccc5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Thu, 23 Nov 2017 18:05:24 +0100 Subject: [PATCH 105/546] pcc: define the Power-saving mode Exit Cause Enable bits in PowerPCCPUClass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and use the value to define precisely the default value of the LPCR in the helper routine cpu_ppc_set_papr() Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/cpu-qom.h | 1 + target/ppc/translate_init.c | 23 +++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) 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/translate_init.c b/target/ppc/translate_init.c index 4e11e6f489..074c3a1d45 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,11 +8901,13 @@ 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]; @@ -8932,8 +8937,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,18 +8951,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; } + /* Also set the power-saving mode bits which depend on the CPU + * family + */ + lpcr->default_value |= pcc->lpcr_pm; + /* We should be followed by a CPU reset but update the active value * just in case... */ From df592270447317d70c7f6ab204bbab27db1dee21 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 26 Nov 2017 15:58:59 -0600 Subject: [PATCH 106/546] openpic: debug w/ info_report() Replace *printf() with *_report(). Remove trailing new lines. Signed-off-by: Michael Davidsaver Signed-off-by: David Gibson --- hw/intc/openpic.c | 102 +++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 51 deletions(-) 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; } From 67113c03423a23e60915574275aed7d60e9f85e1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 26 Nov 2017 15:59:05 -0600 Subject: [PATCH 107/546] e500: fix pci host bridge class/type Correct some confusion wrt. the PCI facing side of the PCI host bridge (not PCIe root complex). The ref. manual for the mpc8533 (as well as mpc8540 and mpc8540) give the class code as PCI_CLASS_PROCESSOR_POWERPC. While the PCI_HEADER_TYPE field is oddly omitted, the tables in the "PCI Configuration Header" section shows a type 0 layout using all 6 BAR registers (as 2x 32, and 2x 64 bit regions) So 997505065dc92e533debf5cb23012ba4e673d387 seems to be in error. Although there was perhaps some confusion as the mpc8533 has a separate PCIe root complex. With PCIe, a root complex has PCI_HEADER_TYPE=1. Neither the PCI host bridge, nor the PCIe root complex advertise class PCI_CLASS_BRIDGE_PCI. This was confusing Linux guests, which try to interpret the host bridge as a pci-pci bridge, but get confused and re-enumerate the bus when the primary/secondary/subordinate bus registers don't have valid values. Signed-off-by: Michael Davidsaver Signed-off-by: David Gibson --- hw/pci-host/ppce500.c | 5 ----- 1 file changed, 5 deletions(-) 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); From 9a94ee5bb15793ef69692998ef57794a33074134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 24 Nov 2017 08:05:48 +0100 Subject: [PATCH 108/546] spapr/rtas: disable the decrementer interrupt when a CPU is unplugged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a CPU is stopped with the 'stop-self' RTAS call, its state 'halted' is switched to 1 and, in this case, the MSR is not taken into account anymore in the cpu_has_work() routine. Only the pending hardware interrupts are checked with their LPCR:PECE* enablement bit. If the DECR timer fires after 'stop-self' is called and before the CPU 'stop' state is reached, the nearly-dead CPU will have some work to do and the guest will crash. This case happens very frequently with the not yet upstream P9 XIVE exploitation mode. In XICS mode, the DECR is occasionally fired but after 'stop' state, so no work is to be done and the guest survives. I suspect there is a race between the QEMU mainloop triggering the timers and the TCG CPU thread but I could not quite identify the root cause. To be safe, let's disable in the LPCR all the exceptions which can cause an exit while the CPU is in power-saving mode and reenable them when the CPU is started. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 11 +++++++++++ target/ppc/translate_init.c | 9 ++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index cdf0b607a0..858adb1bf3 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,6 +202,7 @@ 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); @@ -210,6 +216,11 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, * 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/target/ppc/translate_init.c b/target/ppc/translate_init.c index 074c3a1d45..70ff15a51a 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -8911,6 +8911,7 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) 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; @@ -8953,10 +8954,12 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp) } } - /* Also set the power-saving mode bits which depend on the CPU - * family + /* Only enable Power-saving mode Exit Cause exceptions on the boot + * CPU. The RTAS command start-cpu will enable them on secondaries. */ - lpcr->default_value |= pcc->lpcr_pm; + if (cs == first_cpu) { + lpcr->default_value |= pcc->lpcr_pm; + } /* We should be followed by a CPU reset but update the active value * just in case... From d6322252b3210b663e303746f151abbae7d0b6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 24 Nov 2017 08:05:49 +0100 Subject: [PATCH 109/546] spapr/rtas: fix reboot of a a SMP TCG guest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like for hot unplug CPUs, when a guest is rebooted, the secondary CPUs can be awaken by the decrementer and start entering SLOF at the same time the boot CPU is. To be safe, let's disable on the secondaries all the exceptions which can cause an exit while the CPU is in power-saving mode. Based on previous work from Nikunj A Dadhania Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr_cpu_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 588f9b4571..1ea0e295dd 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) From 3fe4f0fc8530e9411819f02accf2d17c128061b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 24 Nov 2017 08:05:50 +0100 Subject: [PATCH 110/546] spapr/rtas: do not reset the MSR in stop-self command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a CPU is stopped with the 'stop-self' RTAS call, its state 'halted' is switched to 1 and, in this case, the MSR is not taken into account anymore in the cpu_has_work() routine. Only the pending hardware interrupts are checked with their LPCR:PECE* enablement bit. The CPU is now also protected from the decrementer interrupt by the LPCR:PECE* bits which are disabled in the 'stop-self' RTAS call. Reseting the MSR is pointless. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr_rtas.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 858adb1bf3..4bb939d3d1 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -206,16 +206,6 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, 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 From 4f7a47beebd6d37861d08c81941be1b33a0ae627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 1 Dec 2017 17:06:00 +0100 Subject: [PATCH 111/546] ppc/xics: introduce an icp_create() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sPAPR and the PowerNV core objects create the interrupt presenter object of the CPUs in a very similar way. Let's provide a common routine in which we use the presenter 'type' as a child identifier. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/intc/xics.c | 21 +++++++++++++++++++++ hw/ppc/pnv_core.c | 10 +--------- hw/ppc/spapr_cpu_core.c | 13 ++----------- include/hw/ppc/xics.h | 3 +++ 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index a1cc0e420c..bfc6b5bb23 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -384,6 +384,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 */ diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 82ff440b33..8d966e0802 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); + 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_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 1ea0e295dd..70e757f808 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -110,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) { @@ -122,21 +121,13 @@ 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); + 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); } diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 2df99be111..2ba8b12208 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -212,4 +212,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 */ From ed0c37eedfdb953d61d1e0a41439cd404e914d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 1 Dec 2017 17:06:01 +0100 Subject: [PATCH 112/546] ppc/xics: assign of the CPU 'intc' pointer under the core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'intc' pointer of the CPU references the interrupt presenter in the XICS interrupt mode. When the XIVE interrupt mode is available and activated, the machine will need to reassign this pointer to reflect the change. Moving this assignment under the realize routine of the CPU will ease the process when the interrupt mode is toggled. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/intc/xics.c | 1 - hw/ppc/pnv_core.c | 2 +- hw/ppc/spapr_cpu_core.c | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index bfc6b5bb23..700f6baa13 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; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 8d966e0802..03317db853 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -133,7 +133,7 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) return; } - icp_create(child, TYPE_PNV_ICP, xi, &local_err); + cpu->intc = icp_create(child, TYPE_PNV_ICP, xi, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 70e757f808..032438b9ce 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -121,7 +121,8 @@ static void spapr_cpu_core_realize_child(Object *child, goto error; } - icp_create(child, spapr->icp_type, XICS_FABRIC(spapr), &local_err); + cpu->intc = icp_create(child, spapr->icp_type, XICS_FABRIC(spapr), + &local_err); if (local_err) { goto error; } From 60c6823b9bce6789f1ad95bca233fc490161b279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 1 Dec 2017 17:06:02 +0100 Subject: [PATCH 113/546] spapr: move the IRQ allocation routines under the machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also change the prototype to use a sPAPRMachineState and prefix them with spapr_irq_. It will let us synchronise the IRQ allocation with the XIVE interrupt mode when available. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Reviewed-by: Greg Kurz Signed-off-by: David Gibson --- hw/intc/trace-events | 4 -- hw/intc/xics_spapr.c | 114 ----------------------------------------- hw/ppc/spapr.c | 114 +++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_events.c | 4 +- hw/ppc/spapr_pci.c | 8 +-- hw/ppc/spapr_vio.c | 2 +- hw/ppc/trace-events | 4 ++ include/hw/ppc/spapr.h | 6 +++ include/hw/ppc/xics.h | 4 -- 9 files changed, 131 insertions(+), 129 deletions(-) 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_spapr.c b/hw/intc/xics_spapr.c index e8c0a1b3e9..5a0967caf4 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -245,120 +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; - } - - 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/ppc/spapr.c b/hw/ppc/spapr.c index f1b96a4e92..53c2c58a25 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3558,6 +3558,120 @@ 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; +} + +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; + } + + ics_set_irq_type(ics, irq - ics->offset, 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; + } + + for (i = first; i < first + num; ++i) { + ics_set_irq_type(ics, i, lsi); + } + first += ics->offset; + + 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)); + } + } +} + static void spapr_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index e377fc7dde..cead596f3e 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -718,7 +718,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 +731,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..e0ef77a480 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); } @@ -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: "); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index ea3bc8bd9e..bb7ed2c537 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -454,7 +454,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/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 9d21ca9bde..895f48471e 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -707,4 +707,10 @@ 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); + #endif /* HW_SPAPR_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 2ba8b12208..0b67abbbb9 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -181,10 +181,6 @@ 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); From 9e7dc5fc2e9d87a5492099de72800347e944e4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 1 Dec 2017 17:06:03 +0100 Subject: [PATCH 114/546] spapr: introduce a spapr_irq_set_lsi() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will make synchronisation easier with the XIVE interrupt mode when available. The 'irq' parameter refers to the global IRQ number space. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/ppc/spapr.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 53c2c58a25..02cc7ffd4d 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3582,6 +3582,14 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum) 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) { @@ -3606,7 +3614,7 @@ int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, irq += ics->offset; } - ics_set_irq_type(ics, irq - ics->offset, lsi); + spapr_irq_set_lsi(spapr, irq, lsi); trace_spapr_irq_alloc(irq); return irq; @@ -3645,10 +3653,10 @@ int spapr_irq_alloc_block(sPAPRMachineState *spapr, int num, bool lsi, return -1; } - for (i = first; i < first + num; ++i) { - ics_set_irq_type(ics, i, lsi); - } 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); From 7718375584a0214c951668a6e92896aaed88b289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 1 Dec 2017 17:06:04 +0100 Subject: [PATCH 115/546] spapr: introduce a spapr_qirq() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xics_get_qirq() is only used by the sPAPR machine. Let's move it there and change its name to reflect its scope. It will be useful for XIVE support which will use its own set of qirqs. Signed-off-by: Cédric Le Goater Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/intc/xics.c | 12 ------------ hw/ppc/spapr.c | 11 +++++++++++ hw/ppc/spapr_events.c | 12 +++++------- hw/ppc/spapr_pci.c | 2 +- include/hw/pci-host/spapr.h | 2 +- include/hw/ppc/spapr.h | 1 + include/hw/ppc/spapr_vio.h | 2 +- include/hw/ppc/xics.h | 1 - 8 files changed, 20 insertions(+), 23 deletions(-) diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 700f6baa13..e73e623e3b 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -713,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/ppc/spapr.c b/hw/ppc/spapr.c index 02cc7ffd4d..8a6a59f098 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -3680,6 +3680,17 @@ void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num) } } +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) { diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index cead596f3e..7dc87fc7bd 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -472,9 +472,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 +555,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 +676,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)); } } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index e0ef77a480..39134f0ef0 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -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 = { 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 895f48471e..6b8e04c787 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -712,5 +712,6 @@ int spapr_irq_alloc(sPAPRMachineState *spapr, int irq_hint, bool lsi, 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_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 0b67abbbb9..6cebff47a7 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -183,7 +183,6 @@ typedef struct XICSFabricClass { 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 */ From f47bd1c839d57c12207a28421a9df718fbf476ba Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Tue, 5 Dec 2017 16:41:17 +0100 Subject: [PATCH 116/546] spapr: replace numa_get_node() with lookup in pc-dimm list SPAPR is the last user of numa_get_node() and a bunch of supporting code to maintain numa_info[x].addr list. Get LMB node id from pc-dimm list, which allows to remove ~80LOC maintaining dynamic address range lookup list. It also removes pc-dimm dependency on numa_[un]set_mem_node_id() and makes pc-dimms a sole source of information about which node it belongs to and removes duplicate data from global numa_info. Signed-off-by: Igor Mammedov Signed-off-by: David Gibson --- hw/mem/pc-dimm.c | 2 - hw/ppc/spapr.c | 29 ++++++++++++- include/sysemu/numa.h | 10 ----- numa.c | 94 ------------------------------------------- 4 files changed, 28 insertions(+), 107 deletions(-) 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/ppc/spapr.c b/hw/ppc/spapr.c index 8a6a59f098..306875e123 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; 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/numa.c b/numa.c index 7151b24d1c..98fa9a4bcf 100644 --- a/numa.c +++ b/numa.c @@ -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); } } From bb2d8ab6369abc8e90a9f7e2e8f154fea752bdaf Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 6 Dec 2017 09:13:16 +0100 Subject: [PATCH 117/546] spapr: fix LSI interrupt specifiers in the device tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LoPAPR 1.1 B.6.9.1.2 describes the "#interrupt-cells" property of the PowerPC External Interrupt Source Controller node as follows: “#interrupt-cells” Standard property name to define the number of cells in an interrupt- specifier within an interrupt domain. prop-encoded-array: An integer, encoded as with encode-int, that denotes the number of cells required to represent an interrupt specifier in its child nodes. The value of this property for the PowerPC External Interrupt option shall be 2. Thus all interrupt specifiers (as used in the standard “interrupts” property) shall consist of two cells, each containing an integer encoded as with encode-int. The first integer represents the interrupt number the second integer is the trigger code: 0 for edge triggered, 1 for level triggered. This patch fixes the interrupt specifiers in the "interrupt-map" property of the PHB node, that were setting the second cell to 8 (confusion with IRQ_TYPE_LEVEL_LOW ?) instead of 1. VIO devices and RTAS event sources use the same format for interrupt specifiers: while here, we introduce a common helper to handle the encoding details. Signed-off-by: Greg Kurz Reviewed-by: Cédric Le Goater Tested-by: Cédric Le Goater -- v3: - reference public LoPAPR instead of internal PAPR+ in changelog - change helper name to spapr_dt_xics_irq() v2: - drop the erroneous changes to the "interrupts" prop in PCI device nodes - introduce a common helper to encode interrupt specifiers Signed-off-by: David Gibson --- hw/ppc/spapr_events.c | 3 +-- hw/ppc/spapr_pci.c | 3 +-- hw/ppc/spapr_vio.c | 3 ++- include/hw/ppc/spapr.h | 10 ++++++++++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index 7dc87fc7bd..c7a64e6b8d 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, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 39134f0ef0..88797b3d36 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -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_vio.c b/hw/ppc/spapr_vio.c index bb7ed2c537..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) { diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 6b8e04c787..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" From 638f2caa01eb1ec2c4acf4f43798bea465a7eeb5 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 6 Dec 2017 09:16:52 +0100 Subject: [PATCH 118/546] spapr_events: drop bogus cell from "interrupt-ranges" property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to LoPAPR 1.1 B.6.12, the "/event-sources" node has an "interrupt- ranges" property, the format of which is described in B.6.9.1.2 as follows: “interrupt-ranges” Standard property name that defines the interrupt number(s) and range(s) handled by this unit. prop-encoded-array: List of (int-number, range) specifications. Int-number is encoded as with encode-int. Range is encoded as with encode-int. The first entry in this list shall contain the int-number associated with the first “reg” property entry. The int-num-ber is the value representing the interrupt source as would appear in the PowerPC External Interrupt Architecture XISR. The range shall be the number of sequential interrupt numbers which this unit can generate. There's no such thing as a cell count at the end of the array, like the one introduced by commit ffbb1705a33d in QEMU 2.8. It doesn't seem it had any impact on existing guests and I couldn't find any related workaround in linux. So, let's just drop the bogus lines. Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_events.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index c7a64e6b8d..86836f0626 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -292,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", From 2a83f9976efa9a85e8ceb9d1035a68f25c321334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 6 Dec 2017 10:41:50 +0100 Subject: [PATCH 119/546] target/ppc: introduce the PPC_BIT() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and use them in a couple of obvious places. Other macros will be used in the model of the XIVE interrupt controller. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- target/ppc/cpu.h | 105 +++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 49 deletions(-) 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 */ From bcb5ce08cf3ddf69af87cc0fe750c3b564f1e6af Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 8 Dec 2017 12:47:34 +1100 Subject: [PATCH 120/546] spapr: Rename machine init functions for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Machine objects have two init functions - the generic QOM level instance_init which should only do static object initialization, and the Machine specific MachineClass::init which does the actual construction of the machine. In spapr the functions implementing these two have names - ppc_machine_initfn() and ppc_spapr_init() - which don't correspond closely to either of those. To prevent people (read, me) from confusing which is which, rename them spapr_instance_init() and spapr_machine_init() to make it clearer which is which. While we're there rename ppc_spapr_reset() to spapr_machine_reset() to match. Signed-off-by: David Gibson Reviewed-by: Cédric Le Goater Reviewed-by: Greg Kurz Reviewed-by: Suraj Jitindar Singh --- hw/ppc/spapr.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 306875e123..42d6a2302a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1454,7 +1454,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); @@ -2292,7 +2292,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); @@ -2820,7 +2820,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); @@ -3777,8 +3777,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; @@ -3825,7 +3825,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, From 4f441474c61f317de7927edfdb1d042b0b6f3882 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 8 Dec 2017 14:11:49 +1100 Subject: [PATCH 121/546] spapr: Assume msi_nonbroken We conditionally adjust part of the guest device tree based on the global msi_nonbroken flag. However, the main machine type code initializes msi_nonbroken to true and there's nothing that would set it to false again. So replace the test with an assert(). Signed-off-by: David Gibson Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 42d6a2302a..4f354a8760 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -943,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 From 1481fe5fcfeb7fcf3c1ebb9d8c0432e3e0188ccf Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 14 Dec 2017 19:09:48 +0100 Subject: [PATCH 122/546] spapr: don't initialize PATB entry if max-cpu-compat < power9 if KVM is enabled and KVM capabilities MMU radix is available, the partition table entry (patb_entry) for the radix mode is initialized by default in ppc_spapr_reset(). It's a problem if we want to migrate the guest to a POWER8 host while the kernel is not started to set the value to the one expected for a POWER8 CPU. The "-machine max-cpu-compat=power8" should allow to migrate a POWER9 KVM host to a POWER8 KVM host, but because patb_entry is set, the destination QEMU tries to enable radix mode on the POWER8 host. This fails and cancels the migration: Process table config unsupported by the host error while loading state for instance 0x0 of device 'spapr' load of migration failed: Invalid argument This patch doesn't set the PATB entry if the user provides a CPU compatibility mode that doesn't support radix mode. Signed-off-by: Laurent Vivier Signed-off-by: David Gibson --- hw/ppc/spapr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 4f354a8760..6785a90c60 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1466,7 +1466,10 @@ static void spapr_machine_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. */ @@ -1525,7 +1528,6 @@ static void spapr_machine_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; From 1491ede74dd441d77e7d8df5c65892ddfa140879 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Tue, 7 Nov 2017 05:46:53 -0500 Subject: [PATCH 123/546] xen-disk: use an IOThread per instance This patch allocates an IOThread object for each xen_disk instance and sets the AIO context appropriately on connect. This allows processing of I/O to proceed in parallel. The patch also adds tracepoints into xen_disk to make it possible to follow the state transtions of an instance in the log. Signed-off-by: Paul Durrant Acked-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/block/trace-events | 7 ++++++ hw/block/xen_disk.c | 53 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 7 deletions(-) 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; } From de80d78594b4c3767a12d8d42debcf12cbf85a5b Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Fri, 3 Nov 2017 11:56:28 +0000 Subject: [PATCH 124/546] ui: generate qcode to linux mappings Use keycodedb to generate a qcode to linux mapping Signed-off-by: Owen Smith Reviewed-by: Gerd Hoffmann Signed-off-by: Stefano Stabellini --- Makefile | 1 + include/ui/input.h | 3 +++ ui/input-keymap.c | 1 + 3 files changed, 5 insertions(+) diff --git a/Makefile b/Makefile index ab0354c153..0331c182ed 100644 --- a/Makefile +++ b/Makefile @@ -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/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 */ 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) { From a1ccbafdedb1a66ad4100d713d55d4eaea54df82 Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Fri, 3 Nov 2017 11:56:29 +0000 Subject: [PATCH 125/546] xenfb: Use Input Handlers directly Avoid the unneccessary calls through the input-legacy.c file by using the qemu_input_handler_*() calls directly. This did require reworking the event and sync handlers to use the reverse mapping from qcode to linux using qemu_input_qcode_to_linux(). Removes the scancode2linux mapping, and supporting documention. Signed-off-by: Owen Smith Reviewed-by: Gerd Hoffmann Reviewed-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/display/xenfb.c | 282 ++++++++++++++++++++++----------------------- 1 file changed, 141 insertions(+), 141 deletions(-) diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 8e2547ac05..ed06efa21c 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,10 @@ 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; + QemuInputHandlerState *qkbd; + QemuInputHandlerState *qmou; + int axis[INPUT_AXIS__MAX]; + int wheel; }; #define UP_QUEUE 8 @@ -119,79 +121,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 +191,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 (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); + } } - if (xenfb->extended) { - scancode |= 0x80; - xenfb->extended = 0; - } - trace_xenfb_key_event(opaque, scancode2linux[scancode], down); - xenfb_send_key(xenfb, down, scancode2linux[scancode]); } /* @@ -303,45 +224,118 @@ 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; - if (!con) { - xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available"); - return; + 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; + 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; + + 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); - - trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state, - 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; } +static void xenfb_mouse_sync(DeviceState *dev) +{ + struct XenInput *xenfb = (struct XenInput *)dev; + + 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, 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); @@ -357,7 +351,6 @@ static int input_initialise(struct XenDevice *xendev) if (rc != 0) return rc; - qemu_add_kbd_event_handler(xenfb_key_event, in); return 0; } @@ -370,24 +363,31 @@ static void input_connected(struct XenDevice *xendev) in->abs_pointer_wanted = 0; } - 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); } 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); } From 34975e536f3531ad852d724a46280b882ec1bc9d Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Fri, 3 Nov 2017 11:56:30 +0000 Subject: [PATCH 126/546] xenfb: Add [feature|request]-raw-pointer Writes "feature-raw-pointer" during init to indicate the backend can pass raw unscaled values for absolute axes to the frontend. Frontends set "request-raw-pointer" to indicate the backend should not attempt to scale absolute values to console size. "request-raw-pointer" is only valid if "request-abs-pointer" is also set. Raw unscaled pointer values are in the range [0, 0x7fff] "feature-raw-pointer" and "request-raw-pointer" added to Xen header in commit 7868654ff7fe5e4a2eeae2b277644fa884a5031e Signed-off-by: Owen Smith Reviewed-by: Gerd Hoffmann Reviewed-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/display/xenfb.c | 47 +++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index ed06efa21c..776a2ce559 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -52,6 +52,7 @@ struct common { struct XenInput { struct common c; int abs_pointer_wanted; /* Whether guest supports absolute pointer */ + int raw_pointer_wanted; /* Whether guest supports raw (unscaled) pointer */ QemuInputHandlerState *qkbd; QemuInputHandlerState *qmou; int axis[INPUT_AXIS__MAX]; @@ -264,24 +265,28 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src, case INPUT_EVENT_KIND_ABS: move = evt->u.abs.data; - con = qemu_console_lookup_by_index(0); - if (!con) { - xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available"); - return; + 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; } - 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; case INPUT_EVENT_KIND_REL: @@ -339,6 +344,7 @@ static QemuInputHandler xenfb_rel_mouse = { 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; } @@ -362,6 +368,13 @@ 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->qkbd) { qemu_input_handler_unregister(in->qkbd); From d12c5b7ddf2cee57f3e72fe6f450203a9ab455ed Mon Sep 17 00:00:00 2001 From: Owen Smith Date: Fri, 3 Nov 2017 11:56:31 +0000 Subject: [PATCH 127/546] xenfb: activate input handlers for raw pointer devices If the frontend requests raw pointers, the input handlers must be activated to have the input events delivered to the xenfb backend. Without activation, the input events are delivered to handlers registered earlier, which would be the emulated USB tablet or emulated PS/2 mouse. HVM xen_kbdfront can incorrectly scale absolute coordinates when the display resolution is not 800x600. Signed-off-by: Owen Smith Reviewed-by: Gerd Hoffmann Reviewed-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/display/xenfb.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 776a2ce559..d4fc0fa5f2 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -387,6 +387,11 @@ static void input_connected(struct XenDevice *xendev) 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) From 2e63eb2becc228232f12a1ea30a91b2aa8c5cecd Mon Sep 17 00:00:00 2001 From: Simon Gaiser Date: Sat, 28 Oct 2017 04:53:15 +0200 Subject: [PATCH 128/546] xen/pt: Set is_express to avoid out-of-bounds write The passed-through device might be an express device. In this case the old code allocated a too small emulated config space in pci_config_alloc() since pci_config_size() returned the size for a non-express device. This leads to an out-of-bound write in xen_pt_config_reg_init(), which sometimes results in crashes. So set is_express as already done for KVM in vfio-pci. Shortened ASan report: ==17512==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000041648 at pc 0x55e0fdac51ff bp 0x7ffe4af07410 sp 0x7ffe4af07408 WRITE of size 2 at 0x611000041648 thread T0 #0 0x55e0fdac51fe in memcpy /usr/include/x86_64-linux-gnu/bits/string3.h:53 #1 0x55e0fdac51fe in stw_he_p include/qemu/bswap.h:330 #2 0x55e0fdac51fe in stw_le_p include/qemu/bswap.h:379 #3 0x55e0fdac51fe in pci_set_word include/hw/pci/pci.h:490 #4 0x55e0fdac51fe in xen_pt_config_reg_init hw/xen/xen_pt_config_init.c:1991 #5 0x55e0fdac51fe in xen_pt_config_init hw/xen/xen_pt_config_init.c:2067 #6 0x55e0fdabcf4d in xen_pt_realize hw/xen/xen_pt.c:830 #7 0x55e0fdf59666 in pci_qdev_realize hw/pci/pci.c:2034 #8 0x55e0fdda7d3d in device_set_realized hw/core/qdev.c:914 [...] 0x611000041648 is located 8 bytes to the right of 256-byte region [0x611000041540,0x611000041640) allocated by thread T0 here: #0 0x7ff596a94bb8 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xd9bb8) #1 0x7ff57da66580 in g_malloc0 (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x50580) #2 0x55e0fdda7d3d in device_set_realized hw/core/qdev.c:914 [...] Signed-off-by: Simon Gaiser Acked-by: Stefano Stabellini Signed-off-by: Stefano Stabellini --- hw/xen/xen_pt.c | 1 + 1 file changed, 1 insertion(+) 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; From 8a37fc44c6618ca0ede761809d0ecaf605f832fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:38:58 +0100 Subject: [PATCH 129/546] tpm-tis: remove unused locty_number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This field slipped in commit 5086bf9784. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 42d647d363..880ca1a572 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -89,7 +89,6 @@ struct TPMState { qemu_irq irq; uint32_t irq_num; - uint8_t locty_number; TPMBackendCmd cmd; char *backend; From 67af320cd653a107c0bbdf0d2e6c51b24403c64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:38:59 +0100 Subject: [PATCH 130/546] tpm: move TpmIf in include/sysemu/tpm.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a better location than hw/tpm, since we are going to use the interface from outside hw/tpm. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 1 - hw/tpm/tpm_int.h | 22 +--------------------- include/sysemu/tpm.h | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 5763f6f369..1e416d7f90 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -17,7 +17,6 @@ #include "qapi/error.h" #include "qapi/qmp/qerror.h" #include "sysemu/tpm.h" -#include "hw/tpm/tpm_int.h" #include "qemu/thread.h" static void tpm_backend_worker_thread(gpointer data, gpointer user_data) diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index 9c045b6691..1df5883f3c 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -13,28 +13,8 @@ #define TPM_TPM_INT_H #include "qemu/osdep.h" -#include "qom/object.h" -#define TYPE_TPM_IF "tpm-if" -#define TPM_IF_CLASS(klass) \ - OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF) -#define TPM_IF_GET_CLASS(obj) \ - OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF) -#define TPM_IF(obj) \ - INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF) - -typedef struct TPMIf { - Object parent_obj; -} TPMIf; - -typedef struct TPMIfClass { - InterfaceClass parent_class; - - /* run in thread pool by backend */ - void (*request_completed)(TPMIf *obj); -} TPMIfClass; - -#define TPM_STANDARD_CMDLINE_OPTS \ +#define TPM_STANDARD_CMDLINE_OPTS \ { \ .name = "type", \ .type = QEMU_OPT_STRING, \ diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index d7a2bd8556..452cdb9cb7 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -27,6 +27,25 @@ typedef enum TPMVersion { TPM_VERSION_2_0 = 2, } TPMVersion; +#define TYPE_TPM_IF "tpm-if" +#define TPM_IF_CLASS(klass) \ + OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF) +#define TPM_IF_GET_CLASS(obj) \ + OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF) +#define TPM_IF(obj) \ + INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF) + +typedef struct TPMIf { + Object parent_obj; +} TPMIf; + +typedef struct TPMIfClass { + InterfaceClass parent_class; + + /* run in thread pool by backend */ + void (*request_completed)(TPMIf *obj); +} TPMIfClass; + TPMVersion tpm_tis_get_tpm_version(Object *obj); #define TYPE_TPM_TIS "tpm-tis" From 8a89c9ac15981c2d15ce4ee6d6ad67da58824a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:00 +0100 Subject: [PATCH 131/546] tpm-backend: store TPMIf interface, improve backend_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store the TPM interface, the actual object may be different from TPMState. Keep a reference on the interface, and check the backend wasn't already initialized. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 11 +++++++++-- hw/tpm/tpm_emulator.c | 4 ++-- hw/tpm/tpm_passthrough.c | 4 ++-- hw/tpm/tpm_tis.c | 2 +- include/sysemu/tpm.h | 2 +- include/sysemu/tpm_backend.h | 6 +++--- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 1e416d7f90..86f0e7e915 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -43,9 +43,15 @@ enum TpmType tpm_backend_get_type(TPMBackend *s) return k->type; } -int tpm_backend_init(TPMBackend *s, TPMState *state) +int tpm_backend_init(TPMBackend *s, TPMIf *tpmif) { - s->tpm_state = state; + if (s->tpmif) { + return -1; + } + + s->tpmif = tpmif; + object_ref(OBJECT(tpmif)); + s->had_startup_error = false; return 0; @@ -193,6 +199,7 @@ static void tpm_backend_instance_finalize(Object *obj) { TPMBackend *s = TPM_BACKEND(obj); + object_unref(OBJECT(s->tpmif)); g_free(s->id); tpm_backend_thread_end(s); } diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index e1a68104d6..5f88975c25 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -186,7 +186,7 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number, static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) { TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state); + TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpmif); Error *err = NULL; DPRINTF("processing TPM command"); @@ -201,7 +201,7 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) goto error; } - tic->request_completed(TPM_IF(tb->tpm_state)); + tic->request_completed(tb->tpmif); return; error: diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index c440aff4b2..2ad74badca 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -139,14 +139,14 @@ err_exit: static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) { TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state); + TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpmif); DPRINTF("tpm_passthrough: processing command %p\n", cmd); tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len, cmd->out, cmd->out_len, &cmd->selftest_done); - tic->request_completed(TPM_IF(tb->tpm_state)); + tic->request_completed(tb->tpmif); } static void tpm_passthrough_reset(TPMBackend *tb) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 880ca1a572..9a2360e250 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1082,7 +1082,7 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) s->be_driver->fe_model = TPM_MODEL_TPM_TIS; - if (tpm_backend_init(s->be_driver, s)) { + if (tpm_backend_init(s->be_driver, TPM_IF(s))) { error_setg(errp, "tpm_tis: backend driver with id %s could not be " "initialized", s->backend); return; diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 452cdb9cb7..fb1719e5e4 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -12,8 +12,8 @@ #ifndef QEMU_TPM_H #define QEMU_TPM_H -#include "qemu/option.h" #include "qom/object.h" +#include "qapi-types.h" typedef struct TPMState TPMState; diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 03ea5a3400..b5f21ed8f1 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -43,8 +43,8 @@ struct TPMBackend { Object parent; /*< protected >*/ + TPMIf *tpmif; bool opened; - TPMState *tpm_state; GThreadPool *thread_pool; bool had_startup_error; @@ -96,14 +96,14 @@ enum TpmType tpm_backend_get_type(TPMBackend *s); /** * tpm_backend_init: * @s: the backend to initialized - * @state: TPMState + * @tpmif: TPM interface * @datacb: callback for sending data to frontend * * Initialize the backend with the given variables. * * Returns 0 on success. */ -int tpm_backend_init(TPMBackend *s, TPMState *state); +int tpm_backend_init(TPMBackend *s, TPMIf *tpmif); /** * tpm_backend_startup_tpm: From 36e8658924cec6427ca00f87ce86f65cfa705d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:01 +0100 Subject: [PATCH 132/546] tpm-tis: no longer expose TPMState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that there is an interface instead. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 4 ++-- include/sysemu/tpm.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 9a2360e250..4670287f82 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -72,7 +72,7 @@ typedef struct TPMLocality { TPMSizedBuffer r_buffer; } TPMLocality; -struct TPMState { +typedef struct TPMState { ISADevice busdev; MemoryRegion mmio; @@ -94,7 +94,7 @@ struct TPMState { char *backend; TPMBackend *be_driver; TPMVersion be_tpm_version; -}; +} TPMState; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index fb1719e5e4..7a1713a81e 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -15,8 +15,6 @@ #include "qom/object.h" #include "qapi-types.h" -typedef struct TPMState TPMState; - int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); int tpm_init(void); void tpm_cleanup(void); From 689990598a710519eba37e4eb4d8bdebac1aa562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:02 +0100 Subject: [PATCH 133/546] tpm-be: call request_completed() out of thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lift from the backend implementation the responsability to call the request_completed() callback outside of thread context. This also simplify frontend/interface work, as they no longer need to care whether the callback is called from a different thread. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 15 ++++++++++++++- hw/tpm/tpm_emulator.c | 2 -- hw/tpm/tpm_passthrough.c | 3 --- hw/tpm/tpm_tis.c | 34 ++++++++++++---------------------- include/sysemu/tpm.h | 1 - include/sysemu/tpm_backend.h | 1 + 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 86f0e7e915..58f823d54c 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -18,14 +18,25 @@ #include "qapi/qmp/qerror.h" #include "sysemu/tpm.h" #include "qemu/thread.h" +#include "qemu/main-loop.h" + +static void tpm_backend_request_completed_bh(void *opaque) +{ + TPMBackend *s = TPM_BACKEND(opaque); + TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); + + tic->request_completed(s->tpmif); +} static void tpm_backend_worker_thread(gpointer data, gpointer user_data) { TPMBackend *s = TPM_BACKEND(user_data); - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); assert(k->handle_request != NULL); k->handle_request(s, (TPMBackendCmd *)data); + + qemu_bh_schedule(s->bh); } static void tpm_backend_thread_end(TPMBackend *s) @@ -193,6 +204,7 @@ static void tpm_backend_instance_init(Object *obj) tpm_backend_prop_set_opened, NULL); s->fe_model = -1; + s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s); } static void tpm_backend_instance_finalize(Object *obj) @@ -202,6 +214,7 @@ static void tpm_backend_instance_finalize(Object *obj) object_unref(OBJECT(s->tpmif)); g_free(s->id); tpm_backend_thread_end(s); + qemu_bh_delete(s->bh); } static const TypeInfo tpm_backend_info = { diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 5f88975c25..47f37d6cac 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -186,7 +186,6 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number, static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) { TPMEmulator *tpm_emu = TPM_EMULATOR(tb); - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpmif); Error *err = NULL; DPRINTF("processing TPM command"); @@ -201,7 +200,6 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) goto error; } - tic->request_completed(tb->tpmif); return; error: diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 2ad74badca..8c002e4da6 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -139,14 +139,11 @@ err_exit: static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) { TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpmif); DPRINTF("tpm_passthrough: processing command %p\n", cmd); tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len, cmd->out, cmd->out_len, &cmd->selftest_done); - - tic->request_completed(tb->tpmif); } static void tpm_passthrough_reset(TPMBackend *tb) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 4670287f82..95d3afca1d 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -76,7 +76,6 @@ typedef struct TPMState { ISADevice busdev; MemoryRegion mmio; - QEMUBH *bh; uint32_t offset; uint8_t buf[TPM_TIS_BUFFER_MAX]; @@ -410,10 +409,20 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) tpm_tis_abort(s, locty); } -static void tpm_tis_receive_bh(void *opaque) +/* + * Callback from the TPM to indicate that the response was received. + */ +static void tpm_tis_request_completed(TPMIf *ti) { - TPMState *s = opaque; + TPMState *s = TPM(ti); uint8_t locty = s->cmd.locty; + uint8_t l; + + if (s->cmd.selftest_done) { + for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { + s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE; + } + } tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); @@ -431,23 +440,6 @@ static void tpm_tis_receive_bh(void *opaque) TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); } -static void tpm_tis_request_completed(TPMIf *ti) -{ - TPMState *s = TPM(ti); - - bool is_selftest_done = s->cmd.selftest_done; - uint8_t locty = s->cmd.locty; - uint8_t l; - - if (is_selftest_done) { - for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { - s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE; - } - } - - qemu_bh_schedule(s->bh); -} - /* * Read a byte of response data */ @@ -1094,8 +1086,6 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) return; } - s->bh = qemu_bh_new(tpm_tis_receive_bh, s); - isa_init_irq(&s->busdev, &s->irq, s->irq_num); memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 7a1713a81e..e0879620e7 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -40,7 +40,6 @@ typedef struct TPMIf { typedef struct TPMIfClass { InterfaceClass parent_class; - /* run in thread pool by backend */ void (*request_completed)(TPMIf *obj); } TPMIfClass; diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index b5f21ed8f1..c5d1a6818a 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -47,6 +47,7 @@ struct TPMBackend { bool opened; GThreadPool *thread_pool; bool had_startup_error; + QEMUBH *bh; /* */ char *id; From 0bd6c8a9cfa4fd5c25a32ed39f3b8cb786b75b58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:03 +0100 Subject: [PATCH 134/546] tpm-be: report error instead of front-end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend can give more accurate error description, and lift out the job from the frontend. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 3 ++- hw/tpm/tpm_tis.c | 4 +--- include/sysemu/tpm_backend.h | 3 ++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 58f823d54c..7b108bd5d8 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -54,9 +54,10 @@ enum TpmType tpm_backend_get_type(TPMBackend *s) return k->type; } -int tpm_backend_init(TPMBackend *s, TPMIf *tpmif) +int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp) { if (s->tpmif) { + error_setg(errp, "TPM backend '%s' is already initialized", s->id); return -1; } diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 95d3afca1d..bf291e6eff 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1074,9 +1074,7 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) s->be_driver->fe_model = TPM_MODEL_TPM_TIS; - if (tpm_backend_init(s->be_driver, TPM_IF(s))) { - error_setg(errp, "tpm_tis: backend driver with id %s could not be " - "initialized", s->backend); + if (tpm_backend_init(s->be_driver, TPM_IF(s), errp)) { return; } diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index c5d1a6818a..df9ebd0e81 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -99,12 +99,13 @@ enum TpmType tpm_backend_get_type(TPMBackend *s); * @s: the backend to initialized * @tpmif: TPM interface * @datacb: callback for sending data to frontend + * @errp: a pointer to return the #Error object if an error occurs. * * Initialize the backend with the given variables. * * Returns 0 on success. */ -int tpm_backend_init(TPMBackend *s, TPMIf *tpmif); +int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp); /** * tpm_backend_startup_tpm: From 191adc9476371ad94771609d8b9a968d9332a962 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:04 +0100 Subject: [PATCH 135/546] tpm-be: ask model to the TPM interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to store the mode in the backend, or to let the frontend set it itself. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 4 ++-- hw/tpm/tpm_tis.c | 3 +-- include/sysemu/tpm.h | 1 + include/sysemu/tpm_backend.h | 1 - tpm.c | 3 ++- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 7b108bd5d8..0c48d18775 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -148,9 +148,10 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s) { TPMInfo *info = g_new0(TPMInfo, 1); TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); info->id = g_strdup(s->id); - info->model = s->fe_model; + info->model = tic->model; if (k->get_tpm_options) { info->options = k->get_tpm_options(s); } @@ -204,7 +205,6 @@ static void tpm_backend_instance_init(Object *obj) tpm_backend_prop_get_opened, tpm_backend_prop_set_opened, NULL); - s->fe_model = -1; s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s); } diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index bf291e6eff..a780167feb 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1072,8 +1072,6 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) return; } - s->be_driver->fe_model = TPM_MODEL_TPM_TIS; - if (tpm_backend_init(s->be_driver, TPM_IF(s), errp)) { return; } @@ -1108,6 +1106,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) dc->props = tpm_tis_properties; dc->reset = tpm_tis_reset; dc->vmsd = &vmstate_tpm_tis; + tc->model = TPM_MODEL_TPM_TIS; tc->request_completed = tpm_tis_request_completed; } diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index e0879620e7..7b407caf25 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -40,6 +40,7 @@ typedef struct TPMIf { typedef struct TPMIfClass { InterfaceClass parent_class; + enum TpmModel model; void (*request_completed)(TPMIf *obj); } TPMIfClass; diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index df9ebd0e81..665e807a73 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -51,7 +51,6 @@ struct TPMBackend { /* */ char *id; - enum TpmModel fe_model; QLIST_ENTRY(TPMBackend) list; }; diff --git a/tpm.c b/tpm.c index ab5d29e91e..4320f44c9f 100644 --- a/tpm.c +++ b/tpm.c @@ -200,9 +200,10 @@ TPMInfoList *qmp_query_tpm(Error **errp) TPMInfoList *info, *head = NULL, *cur_item = NULL; QLIST_FOREACH(drv, &tpm_backends, list) { - if (!tpm_models[drv->fe_model]) { + if (!drv->tpmif) { continue; } + info = g_new0(TPMInfoList, 1); info->value = tpm_backend_query_tpm(drv); From 3c3ef630621e4cdc5171dcfd19a22b2dc300bcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:05 +0100 Subject: [PATCH 136/546] tpm: remove unused opened code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 42 ------------------------------------ include/sysemu/tpm_backend.h | 12 ----------- tpm.c | 6 ------ 3 files changed, 60 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 0c48d18775..7e636fbc7a 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -159,52 +159,10 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s) return info; } -static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) -{ - TPMBackend *s = TPM_BACKEND(obj); - - return s->opened; -} - -void tpm_backend_open(TPMBackend *s, Error **errp) -{ - object_property_set_bool(OBJECT(s), true, "opened", errp); -} - -static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) -{ - TPMBackend *s = TPM_BACKEND(obj); - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - Error *local_err = NULL; - - if (value == s->opened) { - return; - } - - if (!value && s->opened) { - error_setg(errp, QERR_PERMISSION_DENIED); - return; - } - - if (k->opened) { - k->opened(s, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - - s->opened = true; -} - static void tpm_backend_instance_init(Object *obj) { TPMBackend *s = TPM_BACKEND(obj); - object_property_add_bool(obj, "opened", - tpm_backend_prop_get_opened, - tpm_backend_prop_set_opened, - NULL); s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s); } diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 665e807a73..904e5b1026 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -80,8 +80,6 @@ struct TPMBackendClass { TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); - void (*opened)(TPMBackend *s, Error **errp); - void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd); }; @@ -171,16 +169,6 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s); */ int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty); -/** - * tpm_backend_open: - * @s: the backend to open - * @errp: a pointer to return the #Error object if an error occurs. - * - * This function will open the backend if it is not already open. Calling this - * function on an already opened backend will not result in an error. - */ -void tpm_backend_open(TPMBackend *s, Error **errp); - /** * tpm_backend_get_tpm_version: * @s: the backend to call into diff --git a/tpm.c b/tpm.c index 4320f44c9f..32d398aadf 100644 --- a/tpm.c +++ b/tpm.c @@ -132,12 +132,6 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) return 1; } - tpm_backend_open(drv, &local_err); - if (local_err) { - error_report_err(local_err); - return 1; - } - QLIST_INSERT_HEAD(&tpm_backends, drv, list); return 0; From 69c07db04625cb243db6e8a0ac0a8e3973dd961a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:06 +0100 Subject: [PATCH 137/546] tpm-passthrough: don't save guessed cancel_path in options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The value is later unneeded, and may leak if the free visitor doesn't consider it since has_cancel_path is false. And for consistency with "path" it shouldn't be returned in get_tpm_options(). Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_passthrough.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 8c002e4da6..048edb1a1a 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -226,9 +226,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel", dev) < sizeof(path)) { fd = qemu_open(path, O_WRONLY); - if (fd >= 0) { - tpm_pt->options->cancel_path = g_strdup(path); - } else { + if (fd < 0) { error_report("tpm_passthrough: Could not open TPM cancel " "path %s : %s", path, strerror(errno)); } From ebca2df783a5a742bb93784524336d8cbb9e662b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:07 +0100 Subject: [PATCH 138/546] tpm-be: update optional function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QEMU code doesn't generally have assert() for mandatory callbacks/function pointers, probably because the crash is pretty obvious. Document the methods instead of going into the code. Make get_tpm_options() mandatory to implement (since all backend implementation have it). Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- backends/tpm.c | 9 +-------- include/sysemu/tpm_backend.h | 5 ++++- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 7e636fbc7a..7777467c44 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -33,7 +33,6 @@ static void tpm_backend_worker_thread(gpointer data, gpointer user_data) TPMBackend *s = TPM_BACKEND(user_data); TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - assert(k->handle_request != NULL); k->handle_request(s, (TPMBackendCmd *)data); qemu_bh_schedule(s->bh); @@ -114,8 +113,6 @@ void tpm_backend_cancel_cmd(TPMBackend *s) { TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - assert(k->cancel_cmd); - k->cancel_cmd(s); } @@ -139,8 +136,6 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) { TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); - assert(k->get_tpm_version); - return k->get_tpm_version(s); } @@ -152,9 +147,7 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s) info->id = g_strdup(s->id); info->model = tic->model; - if (k->get_tpm_options) { - info->options = k->get_tpm_options(s); - } + info->options = k->get_tpm_options(s); return info; } diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 904e5b1026..ce8dee58cf 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -65,15 +65,18 @@ struct TPMBackendClass { TPMBackend *(*create)(QemuOpts *opts, const char *id); - /* start up the TPM on the backend */ + /* start up the TPM on the backend - optional */ int (*startup_tpm)(TPMBackend *t); + /* optional */ void (*reset)(TPMBackend *t); void (*cancel_cmd)(TPMBackend *t); + /* optional */ bool (*get_tpm_established_flag)(TPMBackend *t); + /* optional */ int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty); TPMVersion (*get_tpm_version)(TPMBackend *t); From 803de211aa1447585b91354aa2ae8dddd4ff68e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:08 +0100 Subject: [PATCH 139/546] tpm-passthrough: pass TPMPassthruState to handle_device_opts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It doesn't need TPMBackend. Also reorder arguments for consistency. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_passthrough.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 048edb1a1a..9326cbfdc9 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -239,9 +239,9 @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) return fd; } -static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) +static int +tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) { - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); const char *value; value = qemu_opt_get(opts, "cancel-path"); @@ -292,7 +292,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) tb->id = g_strdup(id); - if (tpm_passthrough_handle_device_opts(opts, tb)) { + if (tpm_passthrough_handle_device_opts(tpm_pt, opts)) { goto err_exit; } From 9f7c0ef2ffa02b3bf6bc630496b8df67c750edd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:09 +0100 Subject: [PATCH 140/546] tpm-backend: move set 'id' to common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_emulator.c | 12 +++--------- hw/tpm/tpm_passthrough.c | 9 +++------ include/sysemu/tpm_backend.h | 2 +- tpm.c | 3 ++- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 47f37d6cac..94e6660a5a 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -463,22 +463,16 @@ err: return -1; } -static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id) +static TPMBackend *tpm_emulator_create(QemuOpts *opts) { TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); - tb->id = g_strdup(id); - if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { - goto err_exit; + object_unref(OBJECT(tb)); + return NULL; } return tb; - -err_exit: - object_unref(OBJECT(tb)); - - return NULL; } static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 9326cbfdc9..7371d50739 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -284,13 +284,10 @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) return 1; } -static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) +static TPMBackend *tpm_passthrough_create(QemuOpts *opts) { Object *obj = object_new(TYPE_TPM_PASSTHROUGH); - TPMBackend *tb = TPM_BACKEND(obj); - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - - tb->id = g_strdup(id); + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); if (tpm_passthrough_handle_device_opts(tpm_pt, opts)) { goto err_exit; @@ -301,7 +298,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) goto err_exit; } - return tb; + return TPM_BACKEND(obj); err_exit: object_unref(obj); diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index ce8dee58cf..1ad27ec374 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -63,7 +63,7 @@ struct TPMBackendClass { /* get a descriptive text of the backend to display to the user */ const char *desc; - TPMBackend *(*create)(QemuOpts *opts, const char *id); + TPMBackend *(*create)(QemuOpts *opts); /* start up the TPM on the backend - optional */ int (*startup_tpm)(TPMBackend *t); diff --git a/tpm.c b/tpm.c index 32d398aadf..520f449234 100644 --- a/tpm.c +++ b/tpm.c @@ -127,11 +127,12 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) return 1; } - drv = be->create(opts, id); + drv = be->create(opts); if (!drv) { return 1; } + drv->id = g_strdup(id); QLIST_INSERT_HEAD(&tpm_backends, drv, list); return 0; From 8df4d8484f607d4973e66e93f2eba0b3f80c4238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:10 +0100 Subject: [PATCH 141/546] tpm-passthrough: make it safer to destroy after creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check fds values before closing, to avoid close(-1). Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_passthrough.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 7371d50739..aa9167e3c6 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -347,8 +347,12 @@ static void tpm_passthrough_inst_finalize(Object *obj) tpm_passthrough_cancel_cmd(TPM_BACKEND(obj)); - qemu_close(tpm_pt->tpm_fd); - qemu_close(tpm_pt->cancel_fd); + if (tpm_pt->tpm_fd >= 0) { + qemu_close(tpm_pt->tpm_fd); + } + if (tpm_pt->cancel_fd >= 0) { + qemu_close(tpm_pt->cancel_fd); + } qapi_free_TPMPassthroughOptions(tpm_pt->options); } From bef2ed3fd2454586a7c1132ad574b891741d12c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:11 +0100 Subject: [PATCH 142/546] tpm-passthrough: simplify create() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a similar code as tpm_emulator_create(), call handle_opts() and handle failure cleanup with object_unref() in create(). Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_passthrough.c | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index aa9167e3c6..788be3847d 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -261,49 +261,33 @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) if (tpm_pt->tpm_fd < 0) { error_report("Cannot access TPM device using '%s': %s", tpm_pt->tpm_dev, strerror(errno)); - goto err_free_parameters; + return -1; } if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) { error_report("'%s' is not a TPM device.", tpm_pt->tpm_dev); - goto err_close_tpmdev; + return -1; + } + + tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); + if (tpm_pt->cancel_fd < 0) { + return -1; } return 0; - - err_close_tpmdev: - qemu_close(tpm_pt->tpm_fd); - tpm_pt->tpm_fd = -1; - - err_free_parameters: - qapi_free_TPMPassthroughOptions(tpm_pt->options); - tpm_pt->options = NULL; - tpm_pt->tpm_dev = NULL; - - return 1; } static TPMBackend *tpm_passthrough_create(QemuOpts *opts) { Object *obj = object_new(TYPE_TPM_PASSTHROUGH); - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); - if (tpm_passthrough_handle_device_opts(tpm_pt, opts)) { - goto err_exit; - } - - tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); - if (tpm_pt->cancel_fd < 0) { - goto err_exit; + if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) { + object_unref(obj); + return NULL; } return TPM_BACKEND(obj); - -err_exit: - object_unref(obj); - - return NULL; } static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) From 21cb1e63a594e36ff350fba41600190fb0a1f42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:12 +0100 Subject: [PATCH 143/546] tpm-passthrough: workaround a possible race MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TPM backend processing thread has common shared variable race issues. (they should not be so easy to reach since guest interaction with the device is slow compared to host emulation) An obvious one is setting op_cancelled from device thread after calling write(cancel_fd). The backend thread may return before the device thread has set the variable. Instead set it before cancellation. Even if the write() failed, the end result is command get possibly cancelled (even if cancellation came from external sources it doesn't matter much). It's worth to consider removing the backend processing thread for now. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_passthrough.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 788be3847d..73554aa792 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -89,6 +89,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt, bool is_selftest; const struct tpm_resp_hdr *hdr; + /* FIXME: protect shared variables or use other sync mechanism */ tpm_pt->tpm_op_canceled = false; tpm_pt->tpm_executing = true; *selftest_done = false; @@ -178,12 +179,11 @@ static void tpm_passthrough_cancel_cmd(TPMBackend *tb) */ if (tpm_pt->tpm_executing) { if (tpm_pt->cancel_fd >= 0) { + tpm_pt->tpm_op_canceled = true; n = write(tpm_pt->cancel_fd, "-", 1); if (n != 1) { error_report("Canceling TPM command failed: %s", strerror(errno)); - } else { - tpm_pt->tpm_op_canceled = true; } } else { error_report("Cannot cancel TPM command due to missing " From 023299d87f7b6cccaede8210755afd0c2eaec41a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:13 +0100 Subject: [PATCH 144/546] tpm-tis: simplify header inclusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index a780167feb..81b23b78bb 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -24,17 +24,12 @@ #include "qemu/osdep.h" #include "hw/isa/isa.h" +#include "qapi/error.h" + +#include "hw/acpi/tpm.h" +#include "hw/pci/pci_ids.h" #include "sysemu/tpm_backend.h" #include "tpm_int.h" -#include "sysemu/block-backend.h" -#include "exec/address-spaces.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci_ids.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/main-loop.h" -#include "hw/acpi/tpm.h" #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ #define TPM_TIS_LOCALITY_SHIFT 12 From d36e7db1fbf1a5cff4aa359dfe5c2e5dd97d3e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:14 +0100 Subject: [PATCH 145/546] tpm: rename qemu_find_tpm() -> qemu_find_tpm_be() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit find_tpm() will be introduced to lookup the TPM device. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 2 +- include/sysemu/tpm_backend.h | 2 +- tpm.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 81b23b78bb..fd1511b8eb 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1060,7 +1060,7 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) { TPMState *s = TPM(dev); - s->be_driver = qemu_find_tpm(s->backend); + s->be_driver = qemu_find_tpm_be(s->backend); if (!s->be_driver) { error_setg(errp, "tpm_tis: backend driver with id %s could not be " "found", s->backend); diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 1ad27ec374..c42d83aaef 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -192,7 +192,7 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); */ TPMInfo *tpm_backend_query_tpm(TPMBackend *s); -TPMBackend *qemu_find_tpm(const char *id); +TPMBackend *qemu_find_tpm_be(const char *id); void tpm_register_model(enum TpmModel model); diff --git a/tpm.c b/tpm.c index 520f449234..4661dfc46e 100644 --- a/tpm.c +++ b/tpm.c @@ -69,7 +69,7 @@ static void tpm_display_backend_drivers(void) /* * Find the TPM with the given Id */ -TPMBackend *qemu_find_tpm(const char *id) +TPMBackend *qemu_find_tpm_be(const char *id) { TPMBackend *drv; From 3dfd5a2a50fc4907728eb83569c84b0d98b56582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:15 +0100 Subject: [PATCH 146/546] tpm: lookup the the TPM interface instead of TIS device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow to introduce new devices implementing TPM. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/i386/acpi-build.c | 2 +- include/sysemu/tpm.h | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 73519ab3ac..cdb4aa9835 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -208,7 +208,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info) } info->has_hpet = hpet_find(); - info->tpm_version = tpm_get_version(); + info->tpm_version = tpm_get_version(tpm_find()); info->pvpanic_port = pvpanic_port(); info->applesmc_io_base = applesmc_port(); } diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 7b407caf25..2fe0f1e120 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -19,7 +19,7 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); int tpm_init(void); void tpm_cleanup(void); -typedef enum TPMVersion { +typedef enum TPMVersion { TPM_VERSION_UNSPEC = 0, TPM_VERSION_1_2 = 1, TPM_VERSION_2_0 = 2, @@ -44,20 +44,25 @@ typedef struct TPMIfClass { void (*request_completed)(TPMIf *obj); } TPMIfClass; -TPMVersion tpm_tis_get_tpm_version(Object *obj); - #define TYPE_TPM_TIS "tpm-tis" -static inline TPMVersion tpm_get_version(void) +/* returns NULL unless there is exactly one TPM device */ +static inline TPMIf *tpm_find(void) { -#ifdef CONFIG_TPM - Object *obj = object_resolve_path_type("", TYPE_TPM_TIS, NULL); + Object *obj = object_resolve_path_type("", TYPE_TPM_IF, NULL); - if (obj) { - return tpm_tis_get_tpm_version(obj); + return TPM_IF(obj); +} + +TPMVersion tpm_tis_get_tpm_version(Object *obj); + +static inline TPMVersion tpm_get_version(TPMIf *ti) +{ + if (!ti) { + return TPM_VERSION_UNSPEC; } -#endif - return TPM_VERSION_UNSPEC; + + return tpm_tis_get_tpm_version(OBJECT(ti)); } #endif /* QEMU_TPM_H */ From 9af7a721662de8cdfa7b02b7e9cc2c2c30e7bacb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:16 +0100 Subject: [PATCH 147/546] tpm: add TPM interface to lookup TPM version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not hardcode TPM device model to lookup version, use an interface instead. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 5 +++-- include/sysemu/tpm.h | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index fd1511b8eb..4d13335d23 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -990,9 +990,9 @@ static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb) /* * Get the TPMVersion of the backend device being used */ -TPMVersion tpm_tis_get_tpm_version(Object *obj) +static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) { - TPMState *s = TPM(obj); + TPMState *s = TPM(ti); if (tpm_backend_had_startup_error(s->be_driver)) { return TPM_VERSION_UNSPEC; @@ -1102,6 +1102,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) dc->reset = tpm_tis_reset; dc->vmsd = &vmstate_tpm_tis; tc->model = TPM_MODEL_TPM_TIS; + tc->get_version = tpm_tis_get_tpm_version; tc->request_completed = tpm_tis_request_completed; } diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 2fe0f1e120..650b4b8565 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -42,6 +42,7 @@ typedef struct TPMIfClass { enum TpmModel model; void (*request_completed)(TPMIf *obj); + enum TPMVersion (*get_version)(TPMIf *obj); } TPMIfClass; #define TYPE_TPM_TIS "tpm-tis" @@ -54,15 +55,13 @@ static inline TPMIf *tpm_find(void) return TPM_IF(obj); } -TPMVersion tpm_tis_get_tpm_version(Object *obj); - static inline TPMVersion tpm_get_version(TPMIf *ti) { if (!ti) { return TPM_VERSION_UNSPEC; } - return tpm_tis_get_tpm_version(OBJECT(ti)); + return TPM_IF_GET_CLASS(ti)->get_version(ti); } #endif /* QEMU_TPM_H */ From 5cf954d02161a974c16b33189192b43da9ac4413 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:17 +0100 Subject: [PATCH 148/546] tpm: add tpm_cmd_get_size() to tpm_util MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function is generally useful and used in the following patches. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 3 ++- hw/tpm/tpm_util.h | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 4d13335d23..06b30c4783 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -30,6 +30,7 @@ #include "hw/pci/pci_ids.h" #include "sysemu/tpm_backend.h" #include "tpm_int.h" +#include "tpm_util.h" #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ #define TPM_TIS_LOCALITY_SHIFT 12 @@ -215,7 +216,7 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb) { - return be32_to_cpu(*(uint32_t *)&sb->buffer[2]); + return tpm_cmd_get_size(sb->buffer); } static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index 2f7c96146d..aca10c97bf 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -22,7 +22,8 @@ #ifndef TPM_TPM_UTIL_H #define TPM_TPM_UTIL_H -#include "sysemu/tpm_backend.h" +#include "sysemu/tpm.h" +#include "qemu/bswap.h" void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len); @@ -30,4 +31,9 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len); int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version); +static inline uint32_t tpm_cmd_get_size(const void *b) +{ + return be32_to_cpu(*(const uint32_t *)(b + 2)); +} + #endif /* TPM_TPM_UTIL_H */ From ff5ce21e1b959206f257967d6de2efa6f4e3d188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:18 +0100 Subject: [PATCH 149/546] acpi: change TPM TIS data conditions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device should be exposed if present. It shouldn't have an undefined version (or else backend init failed, and device should fail too). Finally, make the fields specific to TIS device model. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/i386/acpi-build.c | 12 ++++++++---- include/sysemu/tpm.h | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index cdb4aa9835..dd1420b410 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2038,7 +2038,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, } } - if (misc->tpm_version != TPM_VERSION_UNSPEC) { + if (TPM_IS_TIS(tpm_find())) { aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); } @@ -2204,7 +2204,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, /* Scan all PCI buses. Generate tables to support hotplug. */ build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); - if (misc->tpm_version != TPM_VERSION_UNSPEC) { + if (TPM_IS_TIS(tpm_find())) { dev = aml_device("ISA.TPM"); aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); @@ -2281,8 +2281,12 @@ build_tpm2(GArray *table_data, BIOSLinker *linker) tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); - tpm2_ptr->control_area_address = cpu_to_le64(0); - tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + if (TPM_IS_TIS(tpm_find())) { + tpm2_ptr->control_area_address = cpu_to_le64(0); + tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + } else { + g_warn_if_reached(); + } build_header(linker, table_data, (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL); diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 650b4b8565..852e02687c 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -47,6 +47,9 @@ typedef struct TPMIfClass { #define TYPE_TPM_TIS "tpm-tis" +#define TPM_IS_TIS(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) + /* returns NULL unless there is exactly one TPM device */ static inline TPMIf *tpm_find(void) { From 3d01141144583bd12b5d7c76326328e509a677ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:19 +0100 Subject: [PATCH 150/546] tpm-emulator: add a FIXME comment about blocking cancel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_emulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 94e6660a5a..24cb61162f 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -338,6 +338,7 @@ static void tpm_emulator_cancel_cmd(TPMBackend *tb) return; } + /* FIXME: make the function non-blocking, or it may block a VCPU */ if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0, sizeof(res)) < 0) { error_report("tpm-emulator: Could not cancel command: %s", From c87b35fa71833ec4c34fb4a85f03c47028c44d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:20 +0100 Subject: [PATCH 151/546] tpm-tis: remove redundant 'tpm_tis:' in error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reported error message is already prefixed with the -device name & arguments. Before: qemu-system-x86_64: -device tpm-tis,id=foo,tpmdev=foo,irq=21: tpm_tis: IRQ 21 is outside valid range of 0 to 15 After: qemu-system-x86_64: -device tpm-tis,id=foo,tpmdev=foo,irq=21: IRQ 21 is outside valid range of 0 to 15 Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 06b30c4783..0a23203e75 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1063,8 +1063,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) s->be_driver = qemu_find_tpm_be(s->backend); if (!s->be_driver) { - error_setg(errp, "tpm_tis: backend driver with id %s could not be " - "found", s->backend); + error_setg(errp, "backend driver with id %s could not be found", + s->backend); return; } @@ -1073,8 +1073,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) } if (s->irq_num > 15) { - error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range " - "of 0 to 15", s->irq_num); + error_setg(errp, "IRQ %d is outside valid range of 0 to 15", + s->irq_num); return; } From 51a837e908d6f4bbe94469a4a0edcb76348fe964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:21 +0100 Subject: [PATCH 152/546] tpm-tis: check that at most one TPM device exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 0a23203e75..db101b61d4 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1061,6 +1061,11 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) { TPMState *s = TPM(dev); + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); + return; + } + s->be_driver = qemu_find_tpm_be(s->backend); if (!s->be_driver) { error_setg(errp, "backend driver with id %s could not be found", From 493b78303532146c8161b33e878db8af7dca3b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:23 +0100 Subject: [PATCH 153/546] qdev: add DEFINE_PROP_TPMBE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A property to lookup a tpm backend. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/core/qdev-properties-system.c | 64 ++++++++++++++++++++++++++++++++ include/hw/qdev-properties.h | 3 ++ 2 files changed, 67 insertions(+) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index ec10da7424..c17364655c 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -21,6 +21,7 @@ #include "net/hub.h" #include "qapi/visitor.h" #include "chardev/char-fe.h" +#include "sysemu/tpm_backend.h" #include "sysemu/iothread.h" static void get_pointer(Object *obj, Visitor *v, Property *prop, @@ -236,6 +237,69 @@ const PropertyInfo qdev_prop_chr = { .release = release_chr, }; +/* --- character device --- */ + +static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + TPMBackend **be = qdev_get_prop_ptr(dev, opaque); + char *p; + + p = g_strdup(*be ? (*be)->id : ""); + visit_type_str(v, name, &p, errp); + g_free(p); +} + +static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + Property *prop = opaque; + TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); + char *str; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_str(v, name, &str, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + s = qemu_find_tpm_be(str); + if (s == NULL) { + error_setg(errp, "Property '%s.%s' can't find value '%s'", + object_get_typename(obj), prop->name, str); + } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) { + *be = s; /* weak reference, avoid cyclic ref */ + } + g_free(str); +} + +static void release_tpm(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + TPMBackend **be = qdev_get_prop_ptr(dev, prop); + + if (*be) { + tpm_backend_reset(*be); + } +} + +const PropertyInfo qdev_prop_tpm = { + .name = "str", + .description = "ID of a tpm to use as a backend", + .get = get_tpm, + .set = set_tpm, + .release = release_tpm, +}; + /* --- netdev device --- */ static void get_netdev(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index e2321f1cc1..4d24cdf8d6 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -17,6 +17,7 @@ extern const PropertyInfo qdev_prop_int64; extern const PropertyInfo qdev_prop_size; extern const PropertyInfo qdev_prop_string; extern const PropertyInfo qdev_prop_chr; +extern const PropertyInfo qdev_prop_tpm; extern const PropertyInfo qdev_prop_ptr; extern const PropertyInfo qdev_prop_macaddr; extern const PropertyInfo qdev_prop_on_off_auto; @@ -186,6 +187,8 @@ extern const PropertyInfo qdev_prop_link; #define DEFINE_PROP_CHR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend) +#define DEFINE_PROP_TPMBE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) #define DEFINE_PROP_STRING(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) #define DEFINE_PROP_NETDEV(_n, _s, _f) \ From c03785440d1d949cad6fa515e456479c2ec9b212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:24 +0100 Subject: [PATCH 154/546] tpm-tis: use DEFINE_PROP_TPMBE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index db101b61d4..97cd7f5026 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -86,7 +86,6 @@ typedef struct TPMState { TPMBackendCmd cmd; - char *backend; TPMBackend *be_driver; TPMVersion be_tpm_version; } TPMState; @@ -1053,7 +1052,7 @@ static const VMStateDescription vmstate_tpm_tis = { static Property tpm_tis_properties[] = { DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), - DEFINE_PROP_STRING("tpmdev", TPMState, backend), + DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), DEFINE_PROP_END_OF_LIST(), }; @@ -1066,17 +1065,10 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) return; } - s->be_driver = qemu_find_tpm_be(s->backend); if (!s->be_driver) { - error_setg(errp, "backend driver with id %s could not be found", - s->backend); + error_setg(errp, "'tpmdev' property is required"); return; } - - if (tpm_backend_init(s->be_driver, TPM_IF(s), errp)) { - return; - } - if (s->irq_num > 15) { error_setg(errp, "IRQ %d is outside valid range of 0 to 15", s->irq_num); From d3fd953f06700ebe2d15825d4399f7cd3e31af34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:39:25 +0100 Subject: [PATCH 155/546] tpm: remove tpm_register_model() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Query object classes that implements TPMIf instead. Signed-off-by: Marc-André Lureau Reviewed-by: Stefan Berger Signed-off-by: Stefan Berger --- hw/tpm/tpm_tis.c | 1 - include/sysemu/tpm_backend.h | 2 -- tpm.c | 20 ++++++-------------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 97cd7f5026..98c11a4da1 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1119,7 +1119,6 @@ static const TypeInfo tpm_tis_info = { static void tpm_tis_register(void) { type_register_static(&tpm_tis_info); - tpm_register_model(TPM_MODEL_TPM_TIS); } type_init(tpm_tis_register) diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index c42d83aaef..590e8b42de 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -194,6 +194,4 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s); TPMBackend *qemu_find_tpm_be(const char *id); -void tpm_register_model(enum TpmModel model); - #endif diff --git a/tpm.c b/tpm.c index 4661dfc46e..61a434185a 100644 --- a/tpm.c +++ b/tpm.c @@ -23,13 +23,6 @@ static QLIST_HEAD(, TPMBackend) tpm_backends = QLIST_HEAD_INITIALIZER(tpm_backends); -static bool tpm_models[TPM_MODEL__MAX]; - -void tpm_register_model(enum TpmModel model) -{ - tpm_models[model] = true; -} - static const TPMBackendClass * tpm_be_find_by_type(enum TpmType type) { @@ -236,18 +229,16 @@ TpmTypeList *qmp_query_tpm_types(Error **errp) return head; } - TpmModelList *qmp_query_tpm_models(Error **errp) { - unsigned int i = 0; TpmModelList *head = NULL, *prev = NULL, *cur_item; + GSList *e, *l = object_class_get_list(TYPE_TPM_IF, false); + + for (e = l; e; e = e->next) { + TPMIfClass *c = TPM_IF_CLASS(e->data); - for (i = 0; i < TPM_MODEL__MAX; i++) { - if (!tpm_models[i]) { - continue; - } cur_item = g_new0(TpmModelList, 1); - cur_item->value = i; + cur_item->value = c->model; if (prev) { prev->next = cur_item; @@ -257,6 +248,7 @@ TpmModelList *qmp_query_tpm_models(Error **errp) } prev = cur_item; } + g_slist_free(l); return head; } From b21e6aaf4a1e25c22a603e22ef96b3a31d3013aa Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 3 Nov 2017 18:10:01 -0400 Subject: [PATCH 156/546] tpm: Move getting TPM buffer size to backends MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than setting the size of the TPM buffer in the front-end, query the backend for the size of the buffer. In this patch we just move the hard-coded buffer size of 4096 to the backends. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- backends/tpm.c | 7 +++++++ hw/tpm/tpm_emulator.c | 6 ++++++ hw/tpm/tpm_passthrough.c | 6 ++++++ hw/tpm/tpm_tis.c | 12 +++++++----- include/sysemu/tpm_backend.h | 12 ++++++++++++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index 7777467c44..cb49185d4b 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -139,6 +139,13 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) return k->get_tpm_version(s); } +size_t tpm_backend_get_buffer_size(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->get_buffer_size(s); +} + TPMInfo *tpm_backend_query_tpm(TPMBackend *s) { TPMInfo *info = g_new0(TPMInfo, 1); diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 24cb61162f..44a769d86b 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -356,6 +356,11 @@ static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) return tpm_emu->tpm_version; } +static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) +{ + return 4096; +} + static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) { Error *err = NULL; @@ -556,6 +561,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data) tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag; tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag; tbc->get_tpm_version = tpm_emulator_get_tpm_version; + tbc->get_buffer_size = tpm_emulator_get_buffer_size; tbc->get_tpm_options = tpm_emulator_get_tpm_options; tbc->handle_request = tpm_emulator_handle_request; diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 73554aa792..daac67d44a 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -199,6 +199,11 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) return tpm_pt->tpm_version; } +static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb) +{ + return 4096; +} + /* * Unless path or file descriptor set has been provided by user, * determine the sysfs cancel file following kernel documentation @@ -354,6 +359,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data) tbc->reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag; tbc->get_tpm_version = tpm_passthrough_get_tpm_version; + tbc->get_buffer_size = tpm_passthrough_get_buffer_size; tbc->get_tpm_options = tpm_passthrough_get_tpm_options; tbc->handle_request = tpm_passthrough_handle_request; } diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 98c11a4da1..bd22e699bb 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -88,6 +88,8 @@ typedef struct TPMState { TPMBackend *be_driver; TPMVersion be_tpm_version; + + size_t be_buffer_size; } TPMState; #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) @@ -977,10 +979,9 @@ static int tpm_tis_do_startup_tpm(TPMState *s) return tpm_backend_startup_tpm(s->be_driver); } -static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb) +static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb, + size_t wanted_size) { - size_t wanted_size = 4096; /* Linux tpm.c buffer size */ - if (sb->size != wanted_size) { sb->buffer = g_realloc(sb->buffer, wanted_size); sb->size = wanted_size; @@ -1011,6 +1012,7 @@ static void tpm_tis_reset(DeviceState *dev) int c; s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); + s->be_buffer_size = tpm_backend_get_buffer_size(s->be_driver); tpm_backend_reset(s->be_driver); @@ -1037,9 +1039,9 @@ static void tpm_tis_reset(DeviceState *dev) s->loc[c].state = TPM_TIS_STATE_IDLE; s->loc[c].w_offset = 0; - tpm_tis_realloc_buffer(&s->loc[c].w_buffer); + tpm_tis_realloc_buffer(&s->loc[c].w_buffer, s->be_buffer_size); s->loc[c].r_offset = 0; - tpm_tis_realloc_buffer(&s->loc[c].r_buffer); + tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size); } tpm_tis_do_startup_tpm(s); diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 590e8b42de..7c98b6100d 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -81,6 +81,8 @@ struct TPMBackendClass { TPMVersion (*get_tpm_version)(TPMBackend *t); + size_t (*get_buffer_size)(TPMBackend *t); + TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd); @@ -182,6 +184,16 @@ int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty); */ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); +/** + * tpm_backend_get_buffer_size: + * @s: the backend to call into + * + * Get the TPM's buffer size. + * + * Returns buffer size. + */ +size_t tpm_backend_get_buffer_size(TPMBackend *s); + /** * tpm_backend_query_tpm: * @s: the backend From 56388eee01144d59d5c94a34431a29c75073ba53 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 3 Nov 2017 23:00:36 -0400 Subject: [PATCH 157/546] tpm: pull tpm_util_request() out of tpm_util_test() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_util.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index daf1faa63d..b852f53b8d 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -50,13 +50,13 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len) } /* - * A basic test of a TPM device. We expect a well formatted response header - * (error response is fine) within one second. + * Send request to a TPM device. We expect a response within one second. */ -static int tpm_util_test(int fd, - unsigned char *request, - size_t requestlen, - uint16_t *return_tag) +static int tpm_util_request(int fd, + unsigned char *request, + size_t requestlen, + unsigned char *response, + size_t responselen) { struct tpm_resp_hdr *resp; fd_set readfds; @@ -65,7 +65,6 @@ static int tpm_util_test(int fd, .tv_sec = 1, .tv_usec = 0, }; - unsigned char buf[1024]; n = write(fd, request, requestlen); if (n < 0) { @@ -84,17 +83,40 @@ static int tpm_util_test(int fd, return -errno; } - n = read(fd, &buf, sizeof(buf)); + n = read(fd, response, responselen); if (n < sizeof(struct tpm_resp_hdr)) { return -EFAULT; } - resp = (struct tpm_resp_hdr *)buf; + resp = (struct tpm_resp_hdr *)response; /* check the header */ if (be32_to_cpu(resp->len) != n) { return -EMSGSIZE; } + return 0; +} + +/* + * A basic test of a TPM device. We expect a well formatted response header + * (error response is fine). + */ +static int tpm_util_test(int fd, + unsigned char *request, + size_t requestlen, + uint16_t *return_tag) +{ + struct tpm_resp_hdr *resp; + unsigned char buf[1024]; + ssize_t ret; + + ret = tpm_util_request(fd, request, requestlen, + buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + + resp = (struct tpm_resp_hdr *)buf; *return_tag = be16_to_cpu(resp->tag); return 0; From abc5cda097f46bdb86833a38ee0961a0e6a47ae1 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 3 Nov 2017 22:49:23 -0400 Subject: [PATCH 158/546] tpm: tpm_passthrough: Read the buffer size from the host device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than hard coding the buffer size in the tpm_passthrough backend read the TPM I/O buffer size from the host device. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_int.h | 9 +++ hw/tpm/tpm_passthrough.c | 11 +++- hw/tpm/tpm_util.c | 115 +++++++++++++++++++++++++++++++++++++++ hw/tpm/tpm_util.h | 3 + 4 files changed, 137 insertions(+), 1 deletion(-) diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h index 1df5883f3c..abbca5191a 100644 --- a/hw/tpm/tpm_int.h +++ b/hw/tpm/tpm_int.h @@ -45,11 +45,20 @@ struct tpm_resp_hdr { #define TPM_ORD_ContinueSelfTest 0x53 #define TPM_ORD_GetTicks 0xf1 +#define TPM_ORD_GetCapability 0x65 +#define TPM_CAP_PROPERTY 0x05 + +#define TPM_CAP_PROP_INPUT_BUFFER 0x124 /* TPM2 defines */ #define TPM2_ST_NO_SESSIONS 0x8001 #define TPM2_CC_ReadClock 0x00000181 +#define TPM2_CC_GetCapability 0x0000017a + +#define TPM2_CAP_TPM_PROPERTIES 0x6 + +#define TPM2_PT_MAX_COMMAND_SIZE 0x11e #endif /* TPM_TPM_INT_H */ diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index daac67d44a..886af9e702 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -57,6 +57,7 @@ struct TPMPassthruState { int cancel_fd; TPMVersion tpm_version; + size_t tpm_buffersize; }; typedef struct TPMPassthruState TPMPassthruState; @@ -201,7 +202,15 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb) static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb) { - return 4096; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); + int ret; + + ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version, + &tpm_pt->tpm_buffersize); + if (ret < 0) { + tpm_pt->tpm_buffersize = 4096; + } + return tpm_pt->tpm_buffersize; } /* diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index b852f53b8d..a317243a7e 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -20,10 +20,19 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "tpm_util.h" #include "tpm_int.h" #include "exec/memory.h" +#define DEBUG_TPM 0 + +#define DPRINTF(fmt, ...) do { \ + if (DEBUG_TPM) { \ + fprintf(stderr, "tpm-util:"fmt"\n", ## __VA_ARGS__); \ + } \ +} while (0) + /* * Write an error message in the given output buffer. */ @@ -173,3 +182,109 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version) return 1; } + +int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, + size_t *buffersize) +{ + unsigned char buf[1024]; + int ret; + + switch (tpm_version) { + case TPM_VERSION_1_2: { + const struct tpm_req_get_buffer_size { + struct tpm_req_hdr hdr; + uint32_t capability; + uint32_t len; + uint32_t subcap; + } QEMU_PACKED tpm_get_buffer_size = { + .hdr = { + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), + .len = cpu_to_be32(sizeof(tpm_get_buffer_size)), + .ordinal = cpu_to_be32(TPM_ORD_GetCapability), + }, + .capability = cpu_to_be32(TPM_CAP_PROPERTY), + .len = cpu_to_be32(sizeof(uint32_t)), + .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER), + }; + struct tpm_resp_get_buffer_size { + struct tpm_resp_hdr hdr; + uint32_t len; + uint32_t buffersize; + } QEMU_PACKED *tpm_resp = (struct tpm_resp_get_buffer_size *)buf; + + ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_size, + sizeof(tpm_get_buffer_size), buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + + if (be32_to_cpu(tpm_resp->hdr.len) != sizeof(*tpm_resp) || + be32_to_cpu(tpm_resp->len) != sizeof(uint32_t)) { + DPRINTF("tpm_resp->hdr.len = %u, expected = %zu\n", + be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp)); + DPRINTF("tpm_resp->len = %u, expected = %zu\n", + be32_to_cpu(tpm_resp->len), sizeof(uint32_t)); + error_report("tpm_util: Got unexpected response to " + "TPM_GetCapability; errcode: 0x%x", + be32_to_cpu(tpm_resp->hdr.errcode)); + return -EFAULT; + } + *buffersize = be32_to_cpu(tpm_resp->buffersize); + break; + } + case TPM_VERSION_2_0: { + const struct tpm2_req_get_buffer_size { + struct tpm_req_hdr hdr; + uint32_t capability; + uint32_t property; + uint32_t count; + } QEMU_PACKED tpm2_get_buffer_size = { + .hdr = { + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), + .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)), + .ordinal = cpu_to_be32(TPM2_CC_GetCapability), + }, + .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES), + .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE), + .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */ + }; + struct tpm2_resp_get_buffer_size { + struct tpm_resp_hdr hdr; + uint8_t more; + uint32_t capability; + uint32_t count; + uint32_t property1; + uint32_t value1; + uint32_t property2; + uint32_t value2; + } QEMU_PACKED *tpm2_resp = (struct tpm2_resp_get_buffer_size *)buf; + + ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer_size, + sizeof(tpm2_get_buffer_size), buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + + if (be32_to_cpu(tpm2_resp->hdr.len) != sizeof(*tpm2_resp) || + be32_to_cpu(tpm2_resp->count) != 2) { + DPRINTF("tpm2_resp->hdr.len = %u, expected = %zu\n", + be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp)); + DPRINTF("tpm2_resp->len = %u, expected = %u\n", + be32_to_cpu(tpm2_resp->count), 2); + error_report("tpm_util: Got unexpected response to " + "TPM2_GetCapability; errcode: 0x%x", + be32_to_cpu(tpm2_resp->hdr.errcode)); + return -EFAULT; + } + *buffersize = MAX(be32_to_cpu(tpm2_resp->value1), + be32_to_cpu(tpm2_resp->value2)); + break; + } + case TPM_VERSION_UNSPEC: + return -EFAULT; + } + + DPRINTF("buffersize of device: %zu\n", *buffersize); + + return 0; +} diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index aca10c97bf..1c17e3913b 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -36,4 +36,7 @@ static inline uint32_t tpm_cmd_get_size(const void *b) return be32_to_cpu(*(const uint32_t *)(b + 2)); } +int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, + size_t *buffersize); + #endif /* TPM_TPM_UTIL_H */ From 9375c44fdfc07c0fef3052a3f25a13197a528902 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Sat, 4 Nov 2017 19:57:15 -0400 Subject: [PATCH 159/546] tpm: tpm_emulator: get and set buffer size of device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the tpm_emulator backend to get the current buffer size of the external device and set it to the buffer size that the frontend (TIS) requests. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- backends/tpm.c | 4 +- hw/tpm/tpm_emulator.c | 79 ++++++++++++++++++++++++++++++++++-- hw/tpm/tpm_ioctl.h | 28 ++++++++++++- hw/tpm/tpm_tis.c | 6 +-- include/sysemu/tpm_backend.h | 6 ++- 5 files changed, 111 insertions(+), 12 deletions(-) diff --git a/backends/tpm.c b/backends/tpm.c index cb49185d4b..91222c5164 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -68,7 +68,7 @@ int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp) return 0; } -int tpm_backend_startup_tpm(TPMBackend *s) +int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize) { int res = 0; TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); @@ -79,7 +79,7 @@ int tpm_backend_startup_tpm(TPMBackend *s) s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE, NULL); - res = k->startup_tpm ? k->startup_tpm(s) : 0; + res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; s->had_startup_error = (res != 0); diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 44a769d86b..3ae8bf6c5a 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -232,13 +232,14 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) switch (tpm_emu->tpm_version) { case TPM_VERSION_1_2: caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | - PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD; + PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | + PTM_CAP_SET_BUFFERSIZE; tpm = "1.2"; break; case TPM_VERSION_2_0: caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | - PTM_CAP_SET_DATAFD; + PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE; tpm = "2"; break; case TPM_VERSION_UNSPEC: @@ -255,12 +256,76 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu) return 0; } -static int tpm_emulator_startup_tpm(TPMBackend *tb) +static int tpm_emulator_stop_tpm(TPMBackend *tb) +{ + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + ptm_res res; + + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) { + error_report("tpm-emulator: Could not stop TPM: %s", + strerror(errno)); + return -1; + } + + res = be32_to_cpu(res); + if (res) { + error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res); + return -1; + } + + return 0; +} + +static int tpm_emulator_set_buffer_size(TPMBackend *tb, + size_t wanted_size, + size_t *actual_size) +{ + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + ptm_setbuffersize psbs; + + if (tpm_emulator_stop_tpm(tb) < 0) { + return -1; + } + + psbs.u.req.buffersize = cpu_to_be32(wanted_size); + + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs, + sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) { + error_report("tpm-emulator: Could not set buffer size: %s", + strerror(errno)); + return -1; + } + + psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result); + if (psbs.u.resp.tpm_result != 0) { + error_report("tpm-emulator: TPM result for set buffer size : 0x%x", + psbs.u.resp.tpm_result); + return -1; + } + + if (actual_size) { + *actual_size = be32_to_cpu(psbs.u.resp.buffersize); + } + + DPRINTF("buffer size: %u, min: %u, max: %u\n", + be32_to_cpu(psbs.u.resp.buffersize), + be32_to_cpu(psbs.u.resp.minsize), + be32_to_cpu(psbs.u.resp.maxsize)); + + return 0; +} + +static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) { TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ptm_init init; ptm_res res; + if (buffersize != 0 && + tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) { + goto err_exit; + } + DPRINTF("%s", __func__); if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init), sizeof(init)) < 0) { @@ -358,7 +423,13 @@ static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb) static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) { - return 4096; + size_t actual_size; + + if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) { + return 4096; + } + + return actual_size; } static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h index 33564b11de..54c8d345ad 100644 --- a/hw/tpm/tpm_ioctl.h +++ b/hw/tpm/tpm_ioctl.h @@ -169,6 +169,28 @@ struct ptm_getconfig { #define PTM_CONFIG_FLAG_FILE_KEY 0x1 #define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2 +/* + * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM. + * A 0 on input queries for the current buffer size. Any other + * number will try to set the buffer size. The returned number is + * the buffer size that will be used, which can be larger than the + * requested one, if it was below the minimum, or smaller than the + * requested one, if it was above the maximum. + */ +struct ptm_setbuffersize { + union { + struct { + uint32_t buffersize; /* 0 to query for current buffer size */ + } req; /* request */ + struct { + ptm_res tpm_result; + uint32_t buffersize; /* buffer size in use */ + uint32_t minsize; /* min. supported buffer size */ + uint32_t maxsize; /* max. supported buffer size */ + } resp; /* response */ + } u; +}; + typedef uint64_t ptm_cap; typedef struct ptm_est ptm_est; @@ -179,6 +201,7 @@ typedef struct ptm_init ptm_init; typedef struct ptm_getstate ptm_getstate; typedef struct ptm_setstate ptm_setstate; typedef struct ptm_getconfig ptm_getconfig; +typedef struct ptm_setbuffersize ptm_setbuffersize; /* capability flags returned by PTM_GET_CAPABILITY */ #define PTM_CAP_INIT (1) @@ -194,6 +217,7 @@ typedef struct ptm_getconfig ptm_getconfig; #define PTM_CAP_STOP (1 << 10) #define PTM_CAP_GET_CONFIG (1 << 11) #define PTM_CAP_SET_DATAFD (1 << 12) +#define PTM_CAP_SET_BUFFERSIZE (1 << 13) enum { PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), @@ -212,6 +236,7 @@ enum { PTM_STOP = _IOR('P', 13, ptm_res), PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), PTM_SET_DATAFD = _IOR('P', 15, ptm_res), + PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize), }; /* @@ -240,7 +265,8 @@ enum { CMD_SET_STATEBLOB, CMD_STOP, CMD_GET_CONFIG, - CMD_SET_DATAFD + CMD_SET_DATAFD, + CMD_SET_BUFFERSIZE, }; #endif /* _TPM_IOCTL_H */ diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index bd22e699bb..b8e811b086 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -974,9 +974,9 @@ static const MemoryRegionOps tpm_tis_memory_ops = { }, }; -static int tpm_tis_do_startup_tpm(TPMState *s) +static int tpm_tis_do_startup_tpm(TPMState *s, uint32_t buffersize) { - return tpm_backend_startup_tpm(s->be_driver); + return tpm_backend_startup_tpm(s->be_driver, buffersize); } static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb, @@ -1044,7 +1044,7 @@ static void tpm_tis_reset(DeviceState *dev) tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size); } - tpm_tis_do_startup_tpm(s); + tpm_tis_do_startup_tpm(s, 0); } static const VMStateDescription vmstate_tpm_tis = { diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 7c98b6100d..0d6c994a62 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -66,7 +66,7 @@ struct TPMBackendClass { TPMBackend *(*create)(QemuOpts *opts); /* start up the TPM on the backend - optional */ - int (*startup_tpm)(TPMBackend *t); + int (*startup_tpm)(TPMBackend *t, size_t buffersize); /* optional */ void (*reset)(TPMBackend *t); @@ -112,10 +112,12 @@ int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp); /** * tpm_backend_startup_tpm: * @s: the backend whose TPM support is to be started + * @buffersize: the buffer size the TPM is supposed to use, + * 0 to leave it as-is * * Returns 0 on success. */ -int tpm_backend_startup_tpm(TPMBackend *s); +int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize); /** * tpm_backend_had_startup_error: From 683c4b775355cc7acd301e8efe7d4c1c9acdafd8 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Sun, 5 Nov 2017 19:31:43 -0500 Subject: [PATCH 160/546] tpm: tpm_passthrough: Fail startup if FE buffer size < BE buffer size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the requested buffer size of the frontend is smaller than the fixed buffer size of the host's TPM, fail the startup_tpm() interface function, which will make the device unusable. We fail it because the backend TPM could produce larger packets than what the frontend could pass to the OS. The current combination of TIS frontend and either passthrough or emulator backend will not lead to this case since the TIS can support any size of buffer. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_passthrough.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 886af9e702..487aae2043 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -304,6 +304,20 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts) return TPM_BACKEND(obj); } +static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize) +{ + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); + + if (buffersize && buffersize < tpm_pt->tpm_buffersize) { + error_report("Requested buffer size of %zu is smaller than host TPM's " + "fixed buffer size of %zu", + buffersize, tpm_pt->tpm_buffersize); + return -1; + } + + return 0; +} + static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) { TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); @@ -362,6 +376,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data) tbc->opts = tpm_passthrough_cmdline_opts; tbc->desc = "Passthrough TPM backend driver"; tbc->create = tpm_passthrough_create; + tbc->startup_tpm = tpm_passthrough_startup_tpm; tbc->reset = tpm_passthrough_reset; tbc->cancel_cmd = tpm_passthrough_cancel_cmd; tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag; From bb223055b9b327ec66e1f6d2fbaebaee0b8f3dbe Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 11 Dec 2017 13:21:46 +0100 Subject: [PATCH 161/546] s390-ccw-virtio: allow for systems larger that 7.999TB KVM does not allow memory regions > KVM_MEM_MAX_NR_PAGES, basically limiting the memory per slot to 8TB-4k. As memory slots on s390/kvm must be a multiple of 1MB we need start a new memory region if we cross 8TB-1M. With that (and optimistic overcommitment in the kernel) I was able to start a 24TB guest on a 1TB system. Signed-off-by: Christian Borntraeger Message-Id: <20171211122146.162430-1-borntraeger@de.ibm.com> Reviewed-by: David Hildenbrand [CH: 1UL -> 1ULL in KVM_MEM_MAX_NR_PAGES; build fix on 32 bit hosts] Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-ccw.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 466e45343c..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(); From 530473924d57fd26ba9779c8702574db4df829d3 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 19 Jul 2016 13:37:51 +0100 Subject: [PATCH 162/546] io: introduce a network socket listener API The existing QIOChannelSocket class provides the ability to listen on a single socket at a time. This patch introduces a QIONetListener class that provides a higher level API concept around listening for network services, allowing for listening on multiple sockets. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- include/io/net-listener.h | 174 +++++++++++++++++++++ io/Makefile.objs | 1 + io/net-listener.c | 307 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 482 insertions(+) create mode 100644 include/io/net-listener.h create mode 100644 io/net-listener.c diff --git a/include/io/net-listener.h b/include/io/net-listener.h new file mode 100644 index 0000000000..56d6da7a76 --- /dev/null +++ b/include/io/net-listener.h @@ -0,0 +1,174 @@ +/* + * QEMU network listener + * + * Copyright (c) 2016-2017 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#ifndef QIO_NET_LISTENER_H +#define QIO_NET_LISTENER_H + +#include "io/channel-socket.h" + +#define TYPE_QIO_NET_LISTENER "qio-net-listener" +#define QIO_NET_LISTENER(obj) \ + OBJECT_CHECK(QIONetListener, (obj), TYPE_QIO_NET_LISTENER) +#define QIO_NET_LISTENER_CLASS(klass) \ + OBJECT_CLASS_CHECK(QIONetListenerClass, klass, TYPE_QIO_NET_LISTENER) +#define QIO_NET_LISTENER_GET_CLASS(obj) \ + OBJECT_GET_CLASS(QIONetListenerClass, obj, TYPE_QIO_NET_LISTENER) + +typedef struct QIONetListener QIONetListener; +typedef struct QIONetListenerClass QIONetListenerClass; + +typedef void (*QIONetListenerClientFunc)(QIONetListener *listener, + QIOChannelSocket *sioc, + gpointer data); + +/** + * QIONetListener: + * + * The QIONetListener object encapsulates the management of a + * listening socket. It is able to listen on multiple sockets + * concurrently, to deal with the scenario where IPv4 / IPv6 + * needs separate sockets, or there is a need to listen on a + * subset of interface IP addresses, instead of the wildcard + * address. + */ +struct QIONetListener { + Object parent; + + char *name; + QIOChannelSocket **sioc; + gulong *io_tag; + size_t nsioc; + + bool connected; + + QIONetListenerClientFunc io_func; + gpointer io_data; + GDestroyNotify io_notify; +}; + +struct QIONetListenerClass { + ObjectClass parent; +}; + + +/** + * qio_net_listener_new: + * + * Create a new network listener service, which is not + * listening on any sockets initially. + * + * Returns: the new listener + */ +QIONetListener *qio_net_listener_new(void); + + +/** + * qio_net_listener_set_name: + * @listener: the network listener object + * @name: the listener name + * + * Set the name of the listener. This is used as a debugging + * aid, to set names on any GSource instances associated + * with the listener + */ +void qio_net_listener_set_name(QIONetListener *listener, + const char *name); + +/** + * qio_net_listener_open_sync: + * @listener: the network listener object + * @addr: the address to listen on + * @errp: pointer to a NULL initialized error object + * + * Synchronously open a listening connection on all + * addresses associated with @addr. This method may + * also be invoked multiple times, in order to have a + * single listener on multiple distinct addresses. + */ +int qio_net_listener_open_sync(QIONetListener *listener, + SocketAddress *addr, + Error **errp); + +/** + * qio_net_listener_add: + * @listener: the network listener object + * @sioc: the socket I/O channel + * + * Associate a listening socket I/O channel with the + * listener. The listener will acquire a new reference + * on @sioc, so the caller should release its own reference + * if it no longer requires the object. + */ +void qio_net_listener_add(QIONetListener *listener, + QIOChannelSocket *sioc); + +/** + * qio_net_listener_set_client_func: + * @listener: the network listener object + * @func: the callback function + * @data: opaque data to pass to @func + * @notify: callback to free @data + * + * Register @func to be invoked whenever a new client + * connects to the listener. @func will be invoked + * passing in the QIOChannelSocket instance for the + * client. + */ +void qio_net_listener_set_client_func(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify); + +/** + * qio_net_listener_wait_client: + * @listener: the network listener object + * + * Block execution of the caller until a new client arrives + * on one of the listening sockets. If there was previously + * a callback registered with qio_net_listener_set_client_func + * it will be temporarily disabled, and re-enabled afterwards. + * + * Returns: the new client socket + */ +QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener); + + +/** + * qio_net_listener_disconnect: + * @listener: the network listener object + * + * Disconnect the listener, removing all I/O callback + * watches and closing the socket channels. + */ +void qio_net_listener_disconnect(QIONetListener *listener); + + +/** + * qio_net_listener_is_connected: + * @listener: the network listener object + * + * Determine if the listener is connected to any socket + * channels + * + * Returns: true if connected, false otherwise + */ +bool qio_net_listener_is_connected(QIONetListener *listener); + +#endif /* QIO_NET_LISTENER_H */ diff --git a/io/Makefile.objs b/io/Makefile.objs index 12983cca79..9a20fce4ed 100644 --- a/io/Makefile.objs +++ b/io/Makefile.objs @@ -8,4 +8,5 @@ io-obj-y += channel-watch.o io-obj-y += channel-websock.o io-obj-y += channel-util.o io-obj-y += dns-resolver.o +io-obj-y += net-listener.o io-obj-y += task.o diff --git a/io/net-listener.c b/io/net-listener.c new file mode 100644 index 0000000000..77a4e2831c --- /dev/null +++ b/io/net-listener.c @@ -0,0 +1,307 @@ +/* + * QEMU network listener + * + * Copyright (c) 2016-2017 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "io/net-listener.h" +#include "io/dns-resolver.h" +#include "qapi/error.h" + +QIONetListener *qio_net_listener_new(void) +{ + QIONetListener *ret; + + ret = QIO_NET_LISTENER(object_new(TYPE_QIO_NET_LISTENER)); + + return ret; +} + +void qio_net_listener_set_name(QIONetListener *listener, + const char *name) +{ + g_free(listener->name); + listener->name = g_strdup(name); +} + + +static gboolean qio_net_listener_channel_func(QIOChannel *ioc, + GIOCondition condition, + gpointer opaque) +{ + QIONetListener *listener = QIO_NET_LISTENER(opaque); + QIOChannelSocket *sioc; + + sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), + NULL); + if (!sioc) { + return TRUE; + } + + if (listener->io_func) { + listener->io_func(listener, sioc, listener->io_data); + } + + object_unref(OBJECT(sioc)); + + return TRUE; +} + + +int qio_net_listener_open_sync(QIONetListener *listener, + SocketAddress *addr, + Error **errp) +{ + QIODNSResolver *resolver = qio_dns_resolver_get_instance(); + SocketAddress **resaddrs; + size_t nresaddrs; + size_t i; + Error *err = NULL; + bool success = false; + + if (qio_dns_resolver_lookup_sync(resolver, + addr, + &nresaddrs, + &resaddrs, + errp) < 0) { + return -1; + } + + for (i = 0; i < nresaddrs; i++) { + QIOChannelSocket *sioc = qio_channel_socket_new(); + + if (qio_channel_socket_listen_sync(sioc, resaddrs[i], + err ? NULL : &err) == 0) { + success = true; + + qio_net_listener_add(listener, sioc); + } + + qapi_free_SocketAddress(resaddrs[i]); + object_unref(OBJECT(sioc)); + } + g_free(resaddrs); + + if (success) { + error_free(err); + return 0; + } else { + error_propagate(errp, err); + return -1; + } +} + + +void qio_net_listener_add(QIONetListener *listener, + QIOChannelSocket *sioc) +{ + if (listener->name) { + char *name = g_strdup_printf("%s-listen", listener->name); + qio_channel_set_name(QIO_CHANNEL(sioc), name); + g_free(name); + } + + listener->sioc = g_renew(QIOChannelSocket *, listener->sioc, + listener->nsioc + 1); + listener->io_tag = g_renew(gulong, listener->io_tag, listener->nsioc + 1); + listener->sioc[listener->nsioc] = sioc; + listener->io_tag[listener->nsioc] = 0; + + object_ref(OBJECT(sioc)); + listener->connected = true; + + if (listener->io_func != NULL) { + object_ref(OBJECT(listener)); + listener->io_tag[listener->nsioc] = qio_channel_add_watch( + QIO_CHANNEL(listener->sioc[listener->nsioc]), G_IO_IN, + qio_net_listener_channel_func, + listener, (GDestroyNotify)object_unref); + } + + listener->nsioc++; +} + + +void qio_net_listener_set_client_func(QIONetListener *listener, + QIONetListenerClientFunc func, + gpointer data, + GDestroyNotify notify) +{ + size_t i; + + if (listener->io_notify) { + listener->io_notify(listener->io_data); + } + listener->io_func = func; + listener->io_data = data; + listener->io_notify = notify; + + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_tag[i]) { + g_source_remove(listener->io_tag[i]); + listener->io_tag[i] = 0; + } + } + + if (listener->io_func != NULL) { + for (i = 0; i < listener->nsioc; i++) { + object_ref(OBJECT(listener)); + listener->io_tag[i] = qio_channel_add_watch( + QIO_CHANNEL(listener->sioc[i]), G_IO_IN, + qio_net_listener_channel_func, + listener, (GDestroyNotify)object_unref); + } + } +} + + +struct QIONetListenerClientWaitData { + QIOChannelSocket *sioc; + GMainLoop *loop; +}; + + +static gboolean qio_net_listener_wait_client_func(QIOChannel *ioc, + GIOCondition condition, + gpointer opaque) +{ + struct QIONetListenerClientWaitData *data = opaque; + QIOChannelSocket *sioc; + + sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), + NULL); + if (!sioc) { + return TRUE; + } + + if (data->sioc) { + object_unref(OBJECT(sioc)); + } else { + data->sioc = sioc; + g_main_loop_quit(data->loop); + } + + return TRUE; +} + +QIOChannelSocket *qio_net_listener_wait_client(QIONetListener *listener) +{ + GMainContext *ctxt = g_main_context_new(); + GMainLoop *loop = g_main_loop_new(ctxt, TRUE); + GSource **sources; + struct QIONetListenerClientWaitData data = { + .sioc = NULL, + .loop = loop + }; + size_t i; + + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_tag[i]) { + g_source_remove(listener->io_tag[i]); + listener->io_tag[i] = 0; + } + } + + sources = g_new0(GSource *, listener->nsioc); + for (i = 0; i < listener->nsioc; i++) { + sources[i] = qio_channel_create_watch(QIO_CHANNEL(listener->sioc[i]), + G_IO_IN); + + g_source_set_callback(sources[i], + (GSourceFunc)qio_net_listener_wait_client_func, + &data, + NULL); + g_source_attach(sources[i], ctxt); + } + + g_main_loop_run(loop); + + for (i = 0; i < listener->nsioc; i++) { + g_source_unref(sources[i]); + } + g_main_loop_unref(loop); + g_main_context_unref(ctxt); + + if (listener->io_func != NULL) { + for (i = 0; i < listener->nsioc; i++) { + object_ref(OBJECT(listener)); + listener->io_tag[i] = qio_channel_add_watch( + QIO_CHANNEL(listener->sioc[i]), G_IO_IN, + qio_net_listener_channel_func, + listener, (GDestroyNotify)object_unref); + } + } + + return data.sioc; +} + +void qio_net_listener_disconnect(QIONetListener *listener) +{ + size_t i; + + if (!listener->connected) { + return; + } + + for (i = 0; i < listener->nsioc; i++) { + if (listener->io_tag[i]) { + g_source_remove(listener->io_tag[i]); + listener->io_tag[i] = 0; + } + qio_channel_close(QIO_CHANNEL(listener->sioc[i]), NULL); + } + listener->connected = false; +} + + +bool qio_net_listener_is_connected(QIONetListener *listener) +{ + return listener->connected; +} + +static void qio_net_listener_finalize(Object *obj) +{ + QIONetListener *listener = QIO_NET_LISTENER(obj); + size_t i; + + qio_net_listener_disconnect(listener); + + for (i = 0; i < listener->nsioc; i++) { + object_unref(OBJECT(listener->sioc[i])); + } + g_free(listener->io_tag); + g_free(listener->sioc); + g_free(listener->name); +} + +static const TypeInfo qio_net_listener_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QIO_NET_LISTENER, + .instance_size = sizeof(QIONetListener), + .instance_finalize = qio_net_listener_finalize, + .class_size = sizeof(QIONetListenerClass), +}; + + +static void qio_net_listener_register_types(void) +{ + type_register_static(&qio_net_listener_info); +} + + +type_init(qio_net_listener_register_types); From 57d1f6d7ce23e79a8ebe4a57bd2363b269b4664b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 8 Dec 2017 16:57:28 +0000 Subject: [PATCH 163/546] sparc: Make sure we mmap at SHMLBA alignment SPARC Linux has an oddity that it insists that mmap() of MAP_FIXED memory must be at an alignment defined by SHMLBA, which is more aligned than the page size (typically, SHMLBA alignment is to 16K, and pages are 8K). This is a relic of ancient hardware that had cache aliasing constraints, but even on modern hardware the kernel still insists on the alignment. To ensure that we get mmap() alignment sufficient to make the kernel happy, change QEMU_VMALLOC_ALIGN, qemu_fd_getpagesize() and qemu_mempath_getpagesize() to use the maximum of getpagesize() and SHMLBA. In particular, this allows 'make check' to pass on Sparc: we were previously failing the ivshmem tests. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1512752248-17857-1-git-send-email-peter.maydell@linaro.org --- include/qemu/osdep.h | 3 +++ util/mmap-alloc.c | 8 ++++++++ 2 files changed, 11 insertions(+) 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 +# define QEMU_VMALLOC_ALIGN MAX(getpagesize(), SHMLBA) #else # define QEMU_VMALLOC_ALIGN getpagesize() #endif 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(); From 3c254ab8d76e49d2bda818ec5885d110f2e1e67e Mon Sep 17 00:00:00 2001 From: Ladi Prosek Date: Tue, 17 Oct 2017 16:40:51 +0200 Subject: [PATCH 164/546] Remove empty statements Thanks to Laszlo Ersek for spotting the double semicolon in target/i386/kvm.c I have trivially grepped the tree for ';;' in C files. Suggested-by: Laszlo Ersek Signed-off-by: Ladi Prosek Reviewed-by: Laszlo Ersek Reviewed-by: Cornelia Huck Reviewed-by: Laurent Vivier Signed-off-by: Michael Tokarev --- hw/misc/imx6_ccm.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- linux-user/signal.c | 2 +- migration/block.c | 2 +- target/i386/cpu.c | 2 +- target/i386/kvm.c | 2 +- target/sh4/translate.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index 1b421013a3..4fa94835fe 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -335,7 +335,7 @@ static uint64_t imx6_ccm_get_ipg_clk(IMX6CCMState *dev) uint64_t freq = 0; freq = imx6_ccm_get_ahb_clk(dev) - / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF));; + / (1 + EXTRACT(dev->ccm[CCM_CBCDR], IPG_PODF)); DPRINTF("freq = %d\n", (uint32_t)freq); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 3dd902a664..38f6a8afc9 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -486,7 +486,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } else { address_space_stb(&address_space_memory, ccw.cda, vdev->status, MEMTXATTRS_UNSPECIFIED, NULL); - sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status);; + sch->curr_status.scsw.count = ccw.count - sizeof(vdev->status); ret = 0; } break; diff --git a/linux-user/signal.c b/linux-user/signal.c index cf35473671..dae14d4a89 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -6530,7 +6530,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka, haddr = dest; } env->iaoq_f = haddr; - env->iaoq_b = haddr + 4;; + env->iaoq_b = haddr + 4; return; give_sigsegv: diff --git a/migration/block.c b/migration/block.c index 7147171bb7..e68e090c6f 100644 --- a/migration/block.c +++ b/migration/block.c @@ -897,7 +897,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id) int len, flags; char device_name[256]; int64_t addr; - BlockBackend *blk, *blk_prev = NULL;; + BlockBackend *blk, *blk_prev = NULL; Error *local_err = NULL; uint8_t *buf; int64_t total_sectors = 0; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 045d66191f..82603e3130 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2220,7 +2220,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, if (xcc->kvm_required && !kvm_enabled()) { strList *new = g_new0(strList, 1); - new->value = g_strdup("kvm");; + new->value = g_strdup("kvm"); *missing_feats = new; return; } diff --git a/target/i386/kvm.c b/target/i386/kvm.c index b1e32e95d3..d4b2ce2e94 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1122,7 +1122,7 @@ static int kvm_get_supported_msrs(KVMState *s) break; case MSR_IA32_XSS: has_msr_xss = true; - break;; + break; case HV_X64_MSR_CRASH_CTL: has_msr_hv_crash = true; break; diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 703020fe87..8569179883 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -668,7 +668,7 @@ static void _decode_opc(DisasContext * ctx) return; case 0x6008: /* swap.b Rm,Rn */ { - TCGv low = tcg_temp_new();; + TCGv low = tcg_temp_new(); tcg_gen_ext16u_i32(low, REG(B7_4)); tcg_gen_bswap16_i32(low, low); tcg_gen_deposit_i32(REG(B11_8), REG(B7_4), low, 0, 16); From 5f2d910c0068838061862978f27d6ca9a47ba194 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 18 Oct 2017 18:01:40 -0400 Subject: [PATCH 165/546] disas/arm: fix 'instuction' typo in comment Signed-off-by: Emilio G. Cota Signed-off-by: Michael Tokarev --- disas/arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/disas/arm.c b/disas/arm.c index 9967c45990..dda7b2a943 100644 --- a/disas/arm.c +++ b/disas/arm.c @@ -1662,7 +1662,7 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given, } else { - /* Only match unconditional instuctions against unconditional + /* Only match unconditional instructions against unconditional patterns. */ if ((given & 0xf0000000) == 0xf0000000) { From 55bbc8610c310c689eb7bd889f1924a6c128e1cf Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 18 Oct 2017 18:01:42 -0400 Subject: [PATCH 166/546] translate-all: fix 'consisits' typo in comment Signed-off-by: Emilio G. Cota Signed-off-by: Michael Tokarev --- accel/tcg/translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index e7f0329a52..02dfa361bb 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -257,7 +257,7 @@ static target_long decode_sleb128(uint8_t **pp) /* Encode the data collected about the instructions while compiling TB. Place the data at BLOCK, and return the number of bytes consumed. - The logical table consisits of TARGET_INSN_START_WORDS target_ulong's, + The logical table consists of TARGET_INSN_START_WORDS target_ulong's, which come from the target's insn_start data, followed by a uintptr_t which comes from the host pc of the end of the code implementing the insn. From 6b1a756112c35d1243831b81609e321f0ffdaa21 Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Wed, 18 Oct 2017 18:01:43 -0400 Subject: [PATCH 167/546] qht: fix kernel-doc markup in qht.h While at it, s/stuct/struct/. Signed-off-by: Emilio G. Cota Signed-off-by: Michael Tokarev --- include/qemu/qht.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/qemu/qht.h b/include/qemu/qht.h index 56c2c7784c..531aa95325 100644 --- a/include/qemu/qht.h +++ b/include/qemu/qht.h @@ -166,7 +166,7 @@ void qht_iter(struct qht *ht, qht_iter_func_t func, void *userp); /** * qht_statistics_init - Gather statistics from a QHT * @ht: QHT to gather statistics from - * @stats: pointer to a struct qht_stats to be filled in + * @stats: pointer to a &struct qht_stats to be filled in * * Does NOT need to be called under an RCU read-critical section, * since it does not dereference any pointers stored in the hash table. @@ -177,8 +177,8 @@ void qht_iter(struct qht *ht, qht_iter_func_t func, void *userp); void qht_statistics_init(struct qht *ht, struct qht_stats *stats); /** - * qht_statistics_destroy - Destroy a struct qht_stats - * @stats: stuct qht_stats to be destroyed + * qht_statistics_destroy - Destroy a &struct qht_stats + * @stats: &struct qht_stats to be destroyed * * See also: qht_statistics_init(). */ From 9aae6e549d9a05f00315429097705a7beadd2aa4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 2 Nov 2017 07:09:06 -0200 Subject: [PATCH 168/546] configure: check $CC available before verifying host CPU When executing 'configure' in a fresh QEMU clone, in a fresh OS install running in a ppc64le host, this is the error shown: ----- ../configure --enable-trace-backend=simple --enable-debug --target-list=ppc64-softmmu ERROR: Unsupported CPU = ppc64le, try --enable-tcg-interpreter ----- This isn't true, ppc64le host CPU is supported. This happens because, in a fresh install, we don't have a C compiler to autodetect the $cpu variable to "ppc64". This patch moves the CC available check up a bit, just before verifying the host CPU. This ensures that we bail out with a $CC not available error instead of unsupported CPU (the host CPU detection without the compiler wouldn't work properly anyway). It also allows --help to keep working without a C compiler. With this patch, in the same ppc64le host without gcc: $ ../configure --enable-trace-backend=simple --enable-debug --target-list=ppc64-softmmu ERROR: "cc" either does not exist or does not work $ ../configure --help Usage: configure [options] Options: [defaults in brackets after descriptions] Standard options: --help print this message --prefix=PREFIX install in PREFIX [/usr/local] --interp-prefix=PREFIX where to find shared libraries, etc. (...) Signed-off-by: Daniel Henrique Barboza Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- configure | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/configure b/configure index 0c6e7572db..9c8aa5a98b 100755 --- a/configure +++ b/configure @@ -1582,6 +1582,20 @@ fi # Suppress writing compiled files python="$python -B" +# Check that the C compiler works. Doing this here before testing +# the host CPU ensures that we had a valid CC to autodetect the +# $cpu var (and we should bail right here if that's not the case). +# It also allows the help message to be printed without a CC. +write_c_skeleton; +if compile_object ; then + : C compiler works ok +else + error_exit "\"$cc\" either does not exist or does not work" +fi +if ! compile_prog ; then + error_exit "\"$cc\" cannot build an executable (is your linker broken?)" +fi + # Now we have handled --enable-tcg-interpreter and know we're not just # printing the help message, bail out if the host CPU isn't supported. if test "$ARCH" = "unknown"; then @@ -1603,17 +1617,6 @@ if test -z "$werror" ; then fi fi -# check that the C compiler works. -write_c_skeleton; -if compile_object ; then - : C compiler works ok -else - error_exit "\"$cc\" either does not exist or does not work" -fi -if ! compile_prog ; then - error_exit "\"$cc\" cannot build an executable (is your linker broken?)" -fi - if test "$bogus_os" = "yes"; then # Now that we know that we're not printing the help and that # the compiler works (so the results of the check_defines we used From ab1ce9bd4897b9909836e2d50bca86f2f3f2dddc Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Fri, 1 Dec 2017 11:31:57 -0700 Subject: [PATCH 169/546] mmap(2) returns MAP_FAILED, not NULL, on failure Signed-off-by: Michael McConville Reviewed-by: John Snow Signed-off-by: Michael Tokarev --- hw/i386/xen/xen-mapcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/i386/xen/xen-mapcache.c b/hw/i386/xen/xen-mapcache.c index baab93b614..efa35dc6e0 100644 --- a/hw/i386/xen/xen-mapcache.c +++ b/hw/i386/xen/xen-mapcache.c @@ -199,7 +199,7 @@ static void xen_remap_bucket(MapCacheEntry *entry, */ vaddr_base = mmap(vaddr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); - if (vaddr_base == NULL) { + if (vaddr_base == MAP_FAILED) { perror("mmap"); exit(-1); } From 67eb7f4884f7fbb513ae02ced6e4ac7157b9d33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:54:10 +0100 Subject: [PATCH 170/546] .gitignore: remove vscclient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was removed with libcacard, since: commit 7b02f5447c64d1854468f758398c9f6fe9e5721f Author: Marc-André Lureau Date: Sun Aug 30 11:48:40 2015 +0200 libcacard: use the standalone project Signed-off-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 588769b250..433f64f429 100644 --- a/.gitignore +++ b/.gitignore @@ -53,7 +53,6 @@ /qemu-version.h.tmp /module_block.h /scsi/qemu-pr-helper -/vscclient /vhost-user-scsi /fsdev/virtfs-proxy-helper *.tmp From e2fbe20851ceec5ccd7b539a89db0420393fb85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 6 Nov 2017 19:55:06 +0100 Subject: [PATCH 171/546] memory: remove unused memory_region_set_global_locking() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was never used since its introduction in commit 196ea13104f8 ("memory: Add global-locking property to memory regions"). Signed-off-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- include/exec/memory.h | 12 ------------ memory.c | 5 ----- 2 files changed, 17 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 5ed4042f87..a4cabdf44c 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -1240,18 +1240,6 @@ void memory_region_set_flush_coalesced(MemoryRegion *mr); */ void memory_region_clear_flush_coalesced(MemoryRegion *mr); -/** - * memory_region_set_global_locking: Declares the access processing requires - * QEMU's global lock. - * - * When this is invoked, accesses to the memory region will be processed while - * holding the global lock of QEMU. This is the default behavior of memory - * regions. - * - * @mr: the memory region to be updated. - */ -void memory_region_set_global_locking(MemoryRegion *mr); - /** * memory_region_clear_global_locking: Declares that access processing does * not depend on the QEMU global lock. diff --git a/memory.c b/memory.c index e26e5a3b1d..4b41fb837b 100644 --- a/memory.c +++ b/memory.c @@ -2189,11 +2189,6 @@ void memory_region_clear_flush_coalesced(MemoryRegion *mr) } } -void memory_region_set_global_locking(MemoryRegion *mr) -{ - mr->global_locking = true; -} - void memory_region_clear_global_locking(MemoryRegion *mr) { mr->global_locking = false; From ef670726a593b9225479ef4e6a0ec079d934ea08 Mon Sep 17 00:00:00 2001 From: Vicente Jimenez Aguilar Date: Tue, 14 Nov 2017 09:11:27 +0100 Subject: [PATCH 172/546] Document pretty parameter for mon option Documentation: document pretty parameter for mon option that turns on JSON pretty printing Signed-off-by: Vicente Jimenez Aguilar Signed-off-by: Michael Tokarev --- qemu-options.hx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index fe0c29271f..32d9378172 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3487,11 +3487,12 @@ Like -qmp but uses pretty JSON formatting. ETEXI DEF("mon", HAS_ARG, QEMU_OPTION_mon, \ - "-mon [chardev=]name[,mode=readline|control]\n", QEMU_ARCH_ALL) + "-mon [chardev=]name[,mode=readline|control][,pretty[=on|off]]\n", QEMU_ARCH_ALL) STEXI -@item -mon [chardev=]name[,mode=readline|control] +@item -mon [chardev=]name[,mode=readline|control][,pretty[=on|off]] @findex -mon -Setup monitor on chardev @var{name}. +Setup monitor on chardev @var{name}. @code{pretty} turns on JSON pretty printing +easing human reading and debugging. ETEXI DEF("debugcon", HAS_ARG, QEMU_OPTION_debugcon, \ From b98a3bae2596fd9bf60f140d042c8e993daba930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 21 Nov 2017 06:55:10 -0300 Subject: [PATCH 173/546] Makefile: use $(MAKE) variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some systems (i.e. FreeBSD) the default 'make' is not compatible with the GNU extensions used by QEMU makefiles. Calling the GNU make (gmake) works, however the help displayed refers to the host 'make' and copy/paste leads to lot of unobvious errors: $ gmake check-help [...] make check Run all tests $ make check make: "Makefile" line 28: Missing dependency operator make: "Makefile" line 37: Need an operator make: "Makefile" line 41: warning: duplicate script for target "git-submodule-update" ignored make: "rules.mak" line 70: warning: duplicate script for target "%.o" ignored make: Unknown modifier ' ' make: Unclosed substitution for eval modules (= missing) make: "tests/Makefile.include" line 24: Variable/Value missing from "export" make: "tests/" line 1: warning: Zero byte read from file, skipping rest of line. make: "tests/" line 1: Need an operator make: "Makefile" line 660: warning: duplicate script for target "ifneq" ignored make: "Makefile" line 78: warning: using previous script for "ifneq" defined here make: Fatal errors encountered -- cannot continue Using the $(MAKE) variable, the help displayed is consistent with the 'make' program used. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- Makefile | 6 +++--- tests/Makefile.include | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 0331c182ed..1f93515677 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ ifneq ($(realpath $(SRC_PATH)),$(realpath .)) ifneq ($(wildcard $(SRC_PATH)/config-host.mak),) $(error This is an out of tree build but your source tree ($(SRC_PATH)) \ seems to have been used for an in-tree build. You can fix this by running \ -"make distclean && rm -rf *-linux-user *-softmmu" in your source tree) +"$(MAKE) distclean && rm -rf *-linux-user *-softmmu" in your source tree) endif endif @@ -304,7 +304,7 @@ endif else \ echo "WARNING: $@ out of date.";\ fi; \ - echo "Run \"make defconfig\" to regenerate."; \ + echo "Run \"$(MAKE) defconfig\" to regenerate."; \ rm $@.tmp; \ fi; \ else \ @@ -934,4 +934,4 @@ ifdef QEMU_GA_MSI_ENABLED endif @echo '' endif - @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' + @echo ' $(MAKE) V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' diff --git a/tests/Makefile.include b/tests/Makefile.include index c002352134..b4bcc872f2 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -3,21 +3,21 @@ check-help: @echo "Regression testing targets:" @echo - @echo " make check Run all tests" - @echo " make check-qtest-TARGET Run qtest tests for given target" - @echo " make check-qtest Run qtest tests" - @echo " make check-unit Run qobject tests" - @echo " make check-speed Run qobject speed tests" - @echo " make check-qapi-schema Run QAPI schema tests" - @echo " make check-block Run block tests" - @echo " make check-report.html Generates an HTML test report" - @echo " make check-clean Clean the tests" + @echo " $(MAKE) check Run all tests" + @echo " $(MAKE) check-qtest-TARGET Run qtest tests for given target" + @echo " $(MAKE) check-qtest Run qtest tests" + @echo " $(MAKE) check-unit Run qobject tests" + @echo " $(MAKE) check-speed Run qobject speed tests" + @echo " $(MAKE) check-qapi-schema Run QAPI schema tests" + @echo " $(MAKE) check-block Run block tests" + @echo " $(MAKE) check-report.html Generates an HTML test report" + @echo " $(MAKE) check-clean Clean the tests" @echo @echo "Please note that HTML reports do not regenerate if the unit tests" @echo "has not changed." @echo @echo "The variable SPEED can be set to control the gtester speed setting." - @echo "Default options are -k and (for make V=1) --verbose; they can be" + @echo "Default options are -k and (for $(MAKE) V=1) --verbose; they can be" @echo "changed with variable GTESTER_OPTIONS." ifneq ($(wildcard config-host.mak),) From 4e81129645af51efab76aaae2502994c596c3411 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 27 Nov 2017 12:49:44 -0500 Subject: [PATCH 174/546] build: fix typo in error message Signed-off-by: Mike Frysinger Reviewed-by: John Snow Reviewed-by: Eric Blake Signed-off-by: Michael Tokarev --- scripts/git-submodule.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/git-submodule.sh b/scripts/git-submodule.sh index 030617b4ac..bc7224a27f 100755 --- a/scripts/git-submodule.sh +++ b/scripts/git-submodule.sh @@ -24,7 +24,7 @@ error() { echo "Alternatively you may disable automatic GIT submodule checkout" echo "with:" echo - echo " $ ./configure --disable-git-update'" + echo " $ ./configure --disable-git-update" echo echo "and then manually update submodules prior to running make, with:" echo From 4d60b25b371c62bd1a0fad8981d034cd2d3e5385 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 21 Nov 2017 15:07:31 +0000 Subject: [PATCH 175/546] accel/tcg/cpu-exec-common.c: Remove unnecessary include of memory-internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cpu-exec-common.c file includes memory-internal.h, but it doesn't actually use anything from that header. Remove the unnecessary include. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Michael Tokarev --- accel/tcg/cpu-exec-common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/accel/tcg/cpu-exec-common.c b/accel/tcg/cpu-exec-common.c index 5b4ae54a4d..dac5aac477 100644 --- a/accel/tcg/cpu-exec-common.c +++ b/accel/tcg/cpu-exec-common.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "sysemu/cpus.h" #include "exec/exec-all.h" -#include "exec/memory-internal.h" bool tcg_allowed; From 28fa29272f660b3407c6499ea6313e84c89e1784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 21 Nov 2017 00:22:47 -0300 Subject: [PATCH 176/546] Makefile: add more targets to the UNCHECKED_GOALS rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These targets don't need a full build of git submodules. (See b8e535ae8af and eaa2ddbb767). Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1f93515677..d86ecd2dd4 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,10 @@ BUILD_DIR=$(CURDIR) # Before including a proper config-host.mak, assume we are in the source tree SRC_PATH=. -UNCHECKED_GOALS := %clean TAGS cscope ctags docker docker-% help +UNCHECKED_GOALS := %clean TAGS cscope ctags dist \ + html info pdf txt \ + help check-help \ + docker docker-% vm-test vm-build-% # All following code might depend on configuration variables ifneq ($(wildcard config-host.mak),) From 06a7b24350083a7d40d4c5bfce6f8957777a167e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 Dec 2017 02:17:33 -0300 Subject: [PATCH 177/546] MAINTAINERS: add "hw/registerfields.h" in Register API entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orphan since afb3141c660 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Darren Kenny Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 45e2e2009b..55e403833f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1538,6 +1538,7 @@ M: Alistair Francis S: Maintained F: hw/core/register.c F: include/hw/register.h +F: include/hw/registerfields.h SLIRP M: Samuel Thibault From 9102fe6c7f63306670b7d45635ddfeab72409199 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 Dec 2017 02:17:34 -0300 Subject: [PATCH 178/546] hw/registerfields: fix a typo in the FIELD() documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Darren Kenny Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Signed-off-by: Michael Tokarev --- include/hw/registerfields.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h index af101d5ae6..ad9d7a82a3 100644 --- a/include/hw/registerfields.h +++ b/include/hw/registerfields.h @@ -22,7 +22,7 @@ /* Define SHIFT, LENGTH and MASK constants for a field within a register */ -/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH +/* This macro will define R_FOO_BAR_MASK, R_FOO_BAR_SHIFT and R_FOO_BAR_LENGTH * constants for field BAR in register FOO. */ #define FIELD(reg, field, shift, length) \ From cdb70a5c18aec03ef3b8b1bc68d5ca8a3cd80155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 Dec 2017 02:17:35 -0300 Subject: [PATCH 179/546] hw/registerfields: add 64-bit extract/deposit macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Darren Kenny Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Signed-off-by: Michael Tokarev --- include/hw/registerfields.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h index ad9d7a82a3..f59e7f47bd 100644 --- a/include/hw/registerfields.h +++ b/include/hw/registerfields.h @@ -35,6 +35,9 @@ #define FIELD_EX32(storage, reg, field) \ extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ R_ ## reg ## _ ## field ## _LENGTH) +#define FIELD_EX64(storage, reg, field) \ + extract64((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH) /* Extract a field from an array of registers */ #define ARRAY_FIELD_EX32(regs, reg, field) \ @@ -52,6 +55,14 @@ d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \ R_ ## reg ## _ ## field ## _LENGTH, v.v); \ d; }) +#define FIELD_DP64(storage, reg, field, val) ({ \ + struct { \ + unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \ + } v = { .v = val }; \ + uint64_t d; \ + d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \ + R_ ## reg ## _ ## field ## _LENGTH, v.v); \ + d; }) /* Deposit a field to array of registers. */ #define ARRAY_FIELD_DP32(regs, reg, field, val) \ From 27de8f2dcf9c7daa3f5691cefab3563dea3535d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 13 Dec 2017 02:17:36 -0300 Subject: [PATCH 180/546] hw/registerfields: add missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to use this header in qtests. This fixes: CC tests/test.o include/hw/registerfields.h:32:41: error: implicit declaration of function ‘MAKE_64BIT_MASK’ [-Werror=implicit-function-declaration] MAKE_64BIT_MASK(shift, length)}; ^ include/hw/registerfields.h:39:5: error: implicit declaration of function ‘extract64’; [-Werror=implicit-function-declaration] extract64((storage), R_ ## reg ## _ ## field ## _SHIFT, ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Darren Kenny Reviewed-by: Alistair Francis Reviewed-by: Edgar E. Iglesias Signed-off-by: Michael Tokarev --- include/hw/registerfields.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h index f59e7f47bd..44e0b94edf 100644 --- a/include/hw/registerfields.h +++ b/include/hw/registerfields.h @@ -11,6 +11,8 @@ #ifndef REGISTERFIELDS_H #define REGISTERFIELDS_H +#include + /* Define constants for a 32 bit register */ /* This macro will define A_FOO, for the byte address of a register From 160997fa6dbffbb85b8d064592fbed8d2ae8141a Mon Sep 17 00:00:00 2001 From: Tao Wu Date: Wed, 6 Dec 2017 22:56:39 -0800 Subject: [PATCH 181/546] hw/input/hid: Add support for several keys. Add support for these keys: audiomute volumedown volumeup power. Tested with "sendkey" command in monitor and verify the behavior in guest OS. Signed-off-by: Tao Wu Signed-off-by: Michael Tokarev --- hw/input/hid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/input/hid.c b/hw/input/hid.c index 0d049ff61c..aa4fb826fd 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -57,14 +57,14 @@ static const uint8_t hid_usage_keys[0x100] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x48, 0x4a, 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From aa3a41f96e937688d6e49047b092368471eb290f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:45 -0300 Subject: [PATCH 182/546] MAINTAINERS: add entries for i2c/ppc4xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Corey Minyard Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 55e403833f..331c2efeaf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -976,7 +976,9 @@ M: Alexander Graf L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/ppc4*.c +F: hw/i2c/ppc4xx_i2c.c F: include/hw/ppc/ppc4xx.h +F: include/hw/i2c/ppc4xx_i2c.h ppce500 M: Alexander Graf From 1cd6dccb60fa52a83b806cd20051ca19f88f6e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:46 -0300 Subject: [PATCH 183/546] MAINTAINERS: add an entry for the i82374 (southbridge) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Hervé Poussineau Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 331c2efeaf..10079f4a21 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -733,6 +733,7 @@ F: hw/ppc/prep_systemio.c F: hw/ppc/rs6000_mc.c F: hw/pci-host/prep.[hc] F: hw/isa/pc87312.[hc] +F: hw/dma/i82374.c F: pc-bios/ppc_rom.bin sPAPR From ea638a458fb2e34f7bd5e09670d9eab45776197a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:47 -0300 Subject: [PATCH 184/546] MAINTAINERS: add an entry for the i8257 (DMA controller) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 10079f4a21..b48065aad6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -877,6 +877,7 @@ F: hw/timer/hpet* F: hw/timer/i8254* F: hw/timer/mc146818rtc* F: include/hw/i2c/pm_smbus.h +F: include/hw/isa/i8257.h F: include/hw/timer/hpet.h F: include/hw/timer/i8254* F: include/hw/timer/mc146818rtc* From 0a9464b572b35b3bbbd4544b73ccf9cfd954c08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:48 -0300 Subject: [PATCH 185/546] MAINTAINERS: add an entry for the i82378 (superio) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index b48065aad6..1a379edc80 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -732,6 +732,7 @@ F: hw/ppc/prep.c F: hw/ppc/prep_systemio.c F: hw/ppc/rs6000_mc.c F: hw/pci-host/prep.[hc] +F: hw/isa/i82378.c F: hw/isa/pc87312.[hc] F: hw/dma/i82374.c F: pc-bios/ppc_rom.bin From edc46aff4e7cff85d4f583bb30401ae531bd52ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:49 -0300 Subject: [PATCH 186/546] MAINTAINERS: add an entry for watchdog/wdt_ib700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1a379edc80..2122a2a024 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -877,6 +877,7 @@ F: hw/misc/pc-testdev.c F: hw/timer/hpet* F: hw/timer/i8254* F: hw/timer/mc146818rtc* +F: hw/watchdog/wdt_ib700.c F: include/hw/i2c/pm_smbus.h F: include/hw/isa/i8257.h F: include/hw/timer/hpet.h From 1732be86575a3904003032521aee28a822284bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:50 -0300 Subject: [PATCH 187/546] MAINTAINERS: add an entry for input/pckbd.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and fix a typo in the "PC Chipset" section Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Signed-off-by: Michael Tokarev --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 2122a2a024..baeec72802 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -863,12 +863,13 @@ F: hw/misc/sga.c PC Chipset M: Michael S. Tsirkin M: Paolo Bonzini -S: Support +S: Supported F: hw/char/debugcon.c F: hw/char/parallel.c F: hw/char/serial* F: hw/dma/i8257* F: hw/i2c/pm_smbus.c +F: hw/input/pckbd.c F: hw/intc/apic* F: hw/intc/ioapic* F: hw/intc/i8259* From cec16f0d826e6440de8d716900740248d175ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:51 -0300 Subject: [PATCH 188/546] MAINTAINERS: add entries for timer/m48t59 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Signed-off-by: Michael Tokarev --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index baeec72802..33cd4f6bed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -735,6 +735,8 @@ F: hw/pci-host/prep.[hc] F: hw/isa/i82378.c F: hw/isa/pc87312.[hc] F: hw/dma/i82374.c +F: hw/timer/m48t59-isa.c +F: include/hw/timer/m48t59.h F: pc-bios/ppc_rom.bin sPAPR From 6061b5c63e1229da3e1e55b7b0a57bbaf2f9a603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:52 -0300 Subject: [PATCH 189/546] MAINTAINERS: add missing entry for include/hw/net/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 33cd4f6bed..acbff2f1bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1004,6 +1004,7 @@ Network devices M: Jason Wang S: Odd Fixes F: hw/net/ +F: include/hw/net/ F: tests/virtio-net-test.c T: git git://github.com/jasowang/qemu.git net From e9808d09697b5b0ac82ab9291f61571f65f4bff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:53 -0300 Subject: [PATCH 190/546] hw: use "qemu/osdep.h" as first #include in source files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Acked-by: David Gibson Acked-by: Cornelia Huck Signed-off-by: Michael Tokarev --- hw/acpi/ipmi-stub.c | 1 + hw/audio/fmopl.c | 1 - hw/cpu/core.c | 1 + hw/ppc/spapr_cpu_core.c | 1 + hw/smbios/smbios_type_38-stub.c | 1 + hw/vfio/ccw.c | 2 +- hw/virtio/vhost-vsock.c | 2 +- 7 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/acpi/ipmi-stub.c b/hw/acpi/ipmi-stub.c index 98b6dcee0d..f525f71c2d 100644 --- a/hw/acpi/ipmi-stub.c +++ b/hw/acpi/ipmi-stub.c @@ -7,6 +7,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "hw/acpi/ipmi.h" void build_acpi_ipmi_devices(Aml *table, BusState *bus) diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c index 5cfb6a96dd..9f50a89b4a 100644 --- a/hw/audio/fmopl.c +++ b/hw/audio/fmopl.c @@ -34,7 +34,6 @@ #include //#include "driver.h" /* use M.A.M.E. */ #include "fmopl.h" -#include "qemu/osdep.h" #ifndef PI #define PI 3.14159265358979323846 #endif diff --git a/hw/cpu/core.c b/hw/cpu/core.c index bd578ab80c..7e42e2c87a 100644 --- a/hw/cpu/core.c +++ b/hw/cpu/core.c @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "hw/cpu/core.h" #include "qapi/visitor.h" #include "qapi/error.h" diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index 032438b9ce..ac19b2e0b7 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "hw/cpu/core.h" #include "hw/ppc/spapr_cpu_core.h" #include "target/ppc/cpu.h" diff --git a/hw/smbios/smbios_type_38-stub.c b/hw/smbios/smbios_type_38-stub.c index 9528c2c28e..5b83c9b1f1 100644 --- a/hw/smbios/smbios_type_38-stub.c +++ b/hw/smbios/smbios_type_38-stub.c @@ -7,6 +7,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "hw/smbios/ipmi.h" void smbios_build_type_38_table(void) diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 636729c03d..16713f2c52 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -11,11 +11,11 @@ * directory. */ +#include "qemu/osdep.h" #include #include #include -#include "qemu/osdep.h" #include "qapi/error.h" #include "hw/sysbus.h" #include "hw/vfio/vfio.h" diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 5ec1c6a2a2..aa5af927e1 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -11,8 +11,8 @@ * top-level directory. */ -#include #include "qemu/osdep.h" +#include #include "standard-headers/linux/virtio_vsock.h" #include "qapi/error.h" #include "hw/virtio/virtio-bus.h" From b86caf7ad8ba779747975fe838b26aba366eb731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:54 -0300 Subject: [PATCH 191/546] hw: remove "qemu/osdep.h" from header files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Corey Minyard Tested-by: Corey Minyard Signed-off-by: Michael Tokarev --- include/hw/acpi/ipmi.h | 1 - include/hw/cpu/core.h | 1 - include/hw/i2c/ppc4xx_i2c.h | 1 - 3 files changed, 3 deletions(-) diff --git a/include/hw/acpi/ipmi.h b/include/hw/acpi/ipmi.h index ab2bb29048..c38483565c 100644 --- a/include/hw/acpi/ipmi.h +++ b/include/hw/acpi/ipmi.h @@ -9,7 +9,6 @@ #ifndef HW_ACPI_IPMI_H #define HW_ACPI_IPMI_H -#include "qemu/osdep.h" #include "hw/acpi/aml-build.h" /* diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h index 79ac79c29c..b7470644d8 100644 --- a/include/hw/cpu/core.h +++ b/include/hw/cpu/core.h @@ -9,7 +9,6 @@ #ifndef HW_CPU_CORE_H #define HW_CPU_CORE_H -#include "qemu/osdep.h" #include "hw/qdev.h" #define TYPE_CPU_CORE "cpu-core" diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h index e53042f6d4..3450bda577 100644 --- a/include/hw/i2c/ppc4xx_i2c.h +++ b/include/hw/i2c/ppc4xx_i2c.h @@ -25,7 +25,6 @@ #ifndef PPC4XX_I2C_H #define PPC4XX_I2C_H -#include "qemu/osdep.h" #include "qemu-common.h" #include "hw/sysbus.h" #include "hw/i2c/i2c.h" From 7d98febd6759c0164a9f1fef94b9bf3ecbb51ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:55 -0300 Subject: [PATCH 192/546] block: remove "qemu/osdep.h" from header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- block/dmg.h | 1 - 1 file changed, 1 deletion(-) diff --git a/block/dmg.h b/block/dmg.h index b592d6fa8b..2ecf239ba5 100644 --- a/block/dmg.h +++ b/block/dmg.h @@ -26,7 +26,6 @@ #ifndef BLOCK_DMG_H #define BLOCK_DMG_H -#include "qemu/osdep.h" #include "qemu-common.h" #include "block/block_int.h" #include From 47181f5d4541dafc80b0237966316931ec424c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:56 -0300 Subject: [PATCH 193/546] misc: remove headers implicitly included MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Reviewed-by: Stefan Hajnoczi Reviewed-by: Ben Warren Signed-off-by: Michael Tokarev --- bsd-user/main.c | 1 - chardev/wctablet.c | 4 ---- hw/audio/fmopl.h | 1 - hw/scsi/vhost-user-scsi.c | 1 - linux-user/main.c | 1 - net/colo-compare.c | 1 - tests/test-aio-multithread.c | 1 - tests/test-clone-visitor.c | 1 - tests/vmgenid-test.c | 3 --- 9 files changed, 14 deletions(-) diff --git a/bsd-user/main.c b/bsd-user/main.c index f1b244b59b..efef5ff8c5 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -32,7 +32,6 @@ #include "qemu/envlist.h" #include "exec/log.h" #include "trace/control.h" -#include "glib-compat.h" int singlestep; unsigned long mmap_min_addr; diff --git a/chardev/wctablet.c b/chardev/wctablet.c index 6c13c2c58a..969d014574 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -25,10 +25,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include #include "qemu/osdep.h" #include "qemu-common.h" diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h index f4065f425c..e7e578a48e 100644 --- a/hw/audio/fmopl.h +++ b/hw/audio/fmopl.h @@ -1,7 +1,6 @@ #ifndef FMOPL_H #define FMOPL_H -#include typedef void (*OPL_TIMERHANDLER)(void *param, int channel, double interval_Sec); diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index f7561e23fa..9389ed48e0 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qemu/typedefs.h" #include "qom/object.h" #include "hw/fw-path-provider.h" #include "hw/qdev-core.h" diff --git a/linux-user/main.c b/linux-user/main.c index 6286661bd3..2fd2a143ed 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -35,7 +35,6 @@ #include "elf.h" #include "exec/log.h" #include "trace/control.h" -#include "glib-compat.h" char *exec_path; diff --git a/net/colo-compare.c b/net/colo-compare.c index 1ce195f877..0ebdec936c 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -23,7 +23,6 @@ #include "qom/object_interfaces.h" #include "qemu/iov.h" #include "qom/object.h" -#include "qemu/typedefs.h" #include "net/queue.h" #include "chardev/char-fe.h" #include "qemu/sockets.h" diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c index d396185972..c8bec81520 100644 --- a/tests/test-aio-multithread.c +++ b/tests/test-aio-multithread.c @@ -11,7 +11,6 @@ */ #include "qemu/osdep.h" -#include #include "block/aio.h" #include "qapi/error.h" #include "qemu/coroutine.h" diff --git a/tests/test-clone-visitor.c b/tests/test-clone-visitor.c index 96982163e4..ac6afc562e 100644 --- a/tests/test-clone-visitor.c +++ b/tests/test-clone-visitor.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include #include "qemu-common.h" #include "qapi/clone-visitor.h" diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c index 5a86b40775..68ff954578 100644 --- a/tests/vmgenid-test.c +++ b/tests/vmgenid-test.c @@ -8,9 +8,6 @@ * See the COPYING file in the top-level directory. */ -#include -#include -#include #include "qemu/osdep.h" #include "qemu/bitmap.h" #include "qemu/uuid.h" From ff676046fb7018a1e62961cc306e466b0a167540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:57 -0300 Subject: [PATCH 194/546] misc: remove duplicated includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit exec: housekeeping (funny since 02d0e095031) applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Acked-by: Cornelia Huck Reviewed-by: Anthony PERARD Signed-off-by: Michael Tokarev --- accel/tcg/translate-all.c | 1 - exec.c | 3 --- hw/arm/spitz.c | 1 - hw/char/xen_console.c | 1 - hw/core/machine.c | 1 - hw/s390x/css.c | 1 - target/openrisc/exception_helper.c | 1 - tests/vhost-user-test.c | 1 - util/qemu-sockets.c | 1 - vl.c | 1 - 10 files changed, 12 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 02dfa361bb..7736257085 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -31,7 +31,6 @@ #include "tcg.h" #if defined(CONFIG_USER_ONLY) #include "qemu.h" -#include "exec/exec-all.h" #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include #if __FreeBSD_version >= 700104 diff --git a/exec.c b/exec.c index 03238a3449..3e7c57e914 100644 --- a/exec.c +++ b/exec.c @@ -18,8 +18,6 @@ */ #include "qemu/osdep.h" #include "qapi/error.h" -#ifndef _WIN32 -#endif #include "qemu/cutils.h" #include "cpu.h" @@ -51,7 +49,6 @@ #include "trace-root.h" #ifdef CONFIG_FALLOCATE_PUNCH_HOLE -#include #include #endif diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index feccdb00d3..ac1e15cbbc 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -29,7 +29,6 @@ #include "sysemu/block-backend.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" -#include "sysemu/sysemu.h" #include "cpu.h" #undef REG_FMT diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index 3643dfe067..5e68326c19 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -27,7 +27,6 @@ #include "hw/hw.h" #include "chardev/char-fe.h" #include "hw/xen/xen_backend.h" -#include "qapi/error.h" #include diff --git a/hw/core/machine.c b/hw/core/machine.c index 36c2fb069c..c857f3f934 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -20,7 +20,6 @@ #include "sysemu/numa.h" #include "qemu/error-report.h" #include "qemu/cutils.h" -#include "sysemu/numa.h" #include "sysemu/qtest.h" static char *machine_get_accel(Object *obj, Error **errp) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index f071e1394b..1c526fd7e2 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -13,7 +13,6 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/qdev.h" -#include "qemu/error-report.h" #include "qemu/bitops.h" #include "qemu/error-report.h" #include "exec/address-spaces.h" diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index a8a5f69b05..6073a5b21c 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exception.h" void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp) diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c index 4b98018478..e2c89ed376 100644 --- a/tests/vhost-user-test.c +++ b/tests/vhost-user-test.c @@ -21,7 +21,6 @@ #include "libqos/libqos.h" #include "libqos/pci-pc.h" #include "libqos/virtio-pci.h" -#include "qapi/error.h" #include "libqos/malloc-pc.h" #include "hw/virtio/virtio-net.h" diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index a1cf47e625..af4f01211a 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -26,7 +26,6 @@ #include "qapi/error.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" -#include "qapi/clone-visitor.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" #include "qapi-visit.h" diff --git a/vl.c b/vl.c index fc8bd9372f..c1ba52306a 100644 --- a/vl.c +++ b/vl.c @@ -95,7 +95,6 @@ int main(int argc, char **argv) #include "sysemu/kvm.h" #include "sysemu/hax.h" #include "qapi/qobject-input-visitor.h" -#include "qapi/qobject-input-visitor.h" #include "qapi-visit.h" #include "qapi/qmp/qjson.h" #include "qemu/option.h" From 1945e6ab47faad4778883fa5cf839ece006ea3d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:58 -0300 Subject: [PATCH 195/546] ppc: remove duplicated includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes not needed since 7ebaf795560 Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Acked-by: David Gibson Signed-off-by: Michael Tokarev --- hw/ppc/spapr_hcall.c | 1 - target/ppc/kvm.c | 3 --- 2 files changed, 4 deletions(-) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index be22a6b289..51eba52e86 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -13,7 +13,6 @@ #include "trace.h" #include "kvm_ppc.h" #include "hw/ppc/spapr_ovec.h" -#include "qemu/error-report.h" #include "mmu-book3s-v3.h" struct SPRSyncState { diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 9d57debf0e..4664a3ce9d 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -47,9 +47,6 @@ #include "sysemu/hostmem.h" #include "qemu/cutils.h" #include "qemu/mmap-alloc.h" -#if defined(TARGET_PPC64) -#include "hw/ppc/spapr_cpu_core.h" -#endif #include "elf.h" #include "sysemu/kvm_int.h" From 744fc0540dd306a90680277667914ce8d38a26ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:43:59 -0300 Subject: [PATCH 196/546] i386/hax: remove duplicated includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- include/sysemu/hax.h | 1 - target/i386/hax-darwin.c | 6 +----- target/i386/hax-darwin.h | 3 --- target/i386/hax-windows.h | 2 -- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/include/sysemu/hax.h b/include/sysemu/hax.h index 232a68ab1b..f252399623 100644 --- a/include/sysemu/hax.h +++ b/include/sysemu/hax.h @@ -22,7 +22,6 @@ #ifndef QEMU_HAX_H #define QEMU_HAX_H -#include "config-host.h" #include "qemu-common.h" int hax_sync_vcpus(void); diff --git a/target/i386/hax-darwin.c b/target/i386/hax-darwin.c index 1c5bbd0a2d..ee9417454c 100644 --- a/target/i386/hax-darwin.c +++ b/target/i386/hax-darwin.c @@ -11,13 +11,9 @@ */ /* HAX module interface - darwin version */ -#include -#include -#include -#include +#include "qemu/osdep.h" #include -#include "qemu/osdep.h" #include "target/i386/hax-i386.h" hax_fd hax_mod_open(void) diff --git a/target/i386/hax-darwin.h b/target/i386/hax-darwin.h index 0c0968b77d..fb8e25a096 100644 --- a/target/i386/hax-darwin.h +++ b/target/i386/hax-darwin.h @@ -15,10 +15,7 @@ #ifndef TARGET_I386_HAX_DARWIN_H #define TARGET_I386_HAX_DARWIN_H -#include #include -#include -#include #define HAX_INVALID_FD (-1) static inline int hax_invalid_fd(hax_fd fd) diff --git a/target/i386/hax-windows.h b/target/i386/hax-windows.h index 1d8f68de91..f7c3e99246 100644 --- a/target/i386/hax-windows.h +++ b/target/i386/hax-windows.h @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #define HAX_INVALID_FD INVALID_HANDLE_VALUE From 6f144ff081d87308b45e44f746e98589c8246686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:00 -0300 Subject: [PATCH 197/546] i386/hax: remove duplicated include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this file in include in "target/i386/hax-i386.h": #ifdef CONFIG_WIN32 #include "target/i386/hax-windows.h" #endif which guaranties that sysemu/os-win32.h is previously included (CONFIG_WIN32) Suggested-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- target/i386/hax-windows.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target/i386/hax-windows.h b/target/i386/hax-windows.h index f7c3e99246..004f867694 100644 --- a/target/i386/hax-windows.h +++ b/target/i386/hax-windows.h @@ -20,7 +20,6 @@ #ifndef TARGET_I386_HAX_WINDOWS_H #define TARGET_I386_HAX_WINDOWS_H -#include #include #include #include From 9d808657249dcb1fab6a3f16bd3a8149c5c9b88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:01 -0300 Subject: [PATCH 198/546] nios2: remove duplicated includes (in code commented out) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit applied using ./scripts/clean-includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- disas/nios2.c | 3 --- hw/nios2/boot.c | 1 - target/nios2/cpu.h | 1 - target/nios2/helper.c | 5 +---- target/nios2/op_helper.c | 1 + target/nios2/translate.c | 1 + 6 files changed, 3 insertions(+), 9 deletions(-) diff --git a/disas/nios2.c b/disas/nios2.c index b342936d21..de11f04cc4 100644 --- a/disas/nios2.c +++ b/disas/nios2.c @@ -1756,7 +1756,6 @@ extern const int nios2_num_r2_reg_range_mappings; #endif /* _NIOS2_H */ /*#include "sysdep.h" -#include #include "opcode/nios2.h" */ /* Register string table */ @@ -2521,8 +2520,6 @@ const int nios2_num_r2_reg_range_mappings = 8; #include "dis-asm.h" #include "opcode/nios2.h" #include "libiberty.h" -#include -#include */ /* No symbol table is available when this code runs out in an embedded system as when it is used for disassembler support in a monitor. */ diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index 2b31f5b844..94f436e7fb 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -34,7 +34,6 @@ #include "qemu/option.h" #include "qemu/config-file.h" #include "qemu/error-report.h" -#include "qemu-common.h" #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" #include "hw/loader.h" diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h index 9119eee587..88823a6d4d 100644 --- a/target/nios2/cpu.h +++ b/target/nios2/cpu.h @@ -20,7 +20,6 @@ #ifndef CPU_NIOS2_H #define CPU_NIOS2_H -#include "qemu/osdep.h" #include "qemu-common.h" #define TARGET_LONG_BITS 32 diff --git a/target/nios2/helper.c b/target/nios2/helper.c index ef9ee05798..9f741a8f19 100644 --- a/target/nios2/helper.c +++ b/target/nios2/helper.c @@ -18,12 +18,9 @@ * */ -#include -#include -#include +#include "qemu/osdep.h" #include "cpu.h" -#include "qemu/osdep.h" #include "qemu/host-utils.h" #include "qapi/error.h" #include "exec/exec-all.h" diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c index efb1c489c9..c853aeae02 100644 --- a/target/nios2/op_helper.c +++ b/target/nios2/op_helper.c @@ -18,6 +18,7 @@ * */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 72329002ac..51a54ff760 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -21,6 +21,7 @@ * */ +#include "qemu/osdep.h" #include "cpu.h" #include "tcg-op.h" #include "exec/exec-all.h" From d6e3f50a471ab870c5c99df499cd38ce61d3efb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:02 -0300 Subject: [PATCH 199/546] misc: avoid "include/" in include path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- hw/input/adb.c | 2 +- hw/ssi/aspeed_smc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/input/adb.c b/hw/input/adb.c index fcca3a8eb9..924a3f9fd5 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -24,8 +24,8 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/input/adb.h" +#include "hw/input/adb-keys.h" #include "ui/console.h" -#include "include/hw/input/adb-keys.h" #include "ui/input.h" #include "sysemu/sysemu.h" diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index cb515730c5..992617fd3a 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -26,7 +26,7 @@ #include "hw/sysbus.h" #include "sysemu/sysemu.h" #include "qemu/log.h" -#include "include/qemu/error-report.h" +#include "qemu/error-report.h" #include "exec/address-spaces.h" #include "hw/ssi/aspeed_smc.h" From 1330f1e2b76af4094ce3596a8c80874d7e1048a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:03 -0300 Subject: [PATCH 200/546] numa: remove unused #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- numa.c | 1 - 1 file changed, 1 deletion(-) diff --git a/numa.c b/numa.c index 98fa9a4bcf..7b9c33ad12 100644 --- a/numa.c +++ b/numa.c @@ -29,7 +29,6 @@ #include "qemu/bitmap.h" #include "qom/cpu.h" #include "qemu/error-report.h" -#include "include/exec/cpu-common.h" /* for RAM_ADDR_FMT */ #include "qapi-visit.h" #include "qapi/opts-visitor.h" #include "hw/boards.h" From 44ae27d65c84be9746186f52e69d477838c8de12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:04 -0300 Subject: [PATCH 201/546] hw/input/vmmouse: remove unused #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- hw/input/vmmouse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/input/vmmouse.c b/hw/input/vmmouse.c index b6d22086f4..65ef55329e 100644 --- a/hw/input/vmmouse.c +++ b/hw/input/vmmouse.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "ui/console.h" -#include "hw/input/ps2.h" #include "hw/i386/pc.h" #include "hw/qdev.h" From c8b15f913da0d740c56b01375f96681aaca60b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:05 -0300 Subject: [PATCH 202/546] hw/misc/pvpanic: remove unused #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- hw/misc/pvpanic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 2b1e9a6450..3a0e4ba828 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -13,14 +13,11 @@ */ #include "qemu/osdep.h" -#include "qapi/qmp/qobject.h" -#include "qapi/qmp/qjson.h" #include "sysemu/sysemu.h" #include "qemu/log.h" #include "hw/nvram/fw_cfg.h" #include "hw/i386/pc.h" -#include "qapi-event.h" /* The bit of supported pv event */ #define PVPANIC_F_PANICKED 0 From f7ee2cf9d1aab216f3736baa0e90112ffbc649b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:06 -0300 Subject: [PATCH 203/546] hw/ssi/aspeed_smc: remove unused #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Michael Tokarev --- hw/ssi/aspeed_smc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 992617fd3a..5059396bc6 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -27,7 +27,6 @@ #include "sysemu/sysemu.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" #include "hw/ssi/aspeed_smc.h" From 433545d56930ad8867ff6950bd47e2b438173ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:07 -0300 Subject: [PATCH 204/546] amd_iommu: avoid needless includes in header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit instead move them to the source file Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/i386/amd_iommu.c | 5 ++++- hw/i386/amd_iommu.h | 5 ----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index ad8155ca4c..eeaf0e0aa8 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -20,7 +20,10 @@ * Cache implementation inspired by hw/i386/intel_iommu.c */ #include "qemu/osdep.h" -#include "hw/i386/amd_iommu.h" +#include "hw/i386/pc.h" +#include "hw/pci/msi.h" +#include "hw/pci/pci_bus.h" +#include "amd_iommu.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "trace.h" diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index d370ae3549..aeef802364 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -23,11 +23,6 @@ #include "hw/hw.h" #include "hw/pci/pci.h" -#include "hw/pci/msi.h" -#include "hw/sysbus.h" -#include "sysemu/dma.h" -#include "hw/i386/pc.h" -#include "hw/pci/pci_bus.h" #include "hw/i386/x86-iommu.h" /* Capability registers */ From 09db4d37d204c03924912924a39f22891b125148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:08 -0300 Subject: [PATCH 205/546] misc: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Anthony PERARD Signed-off-by: Michael Tokarev --- hw/audio/pcspk.c | 1 - hw/i386/xen/xen_platform.c | 1 - hw/isa/vt82c686.c | 1 - hw/misc/ivshmem.c | 1 - hw/misc/sga.c | 1 - hw/pci-bridge/pci_expander_bridge.c | 1 - monitor.c | 1 - 7 files changed, 7 deletions(-) diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 0206f7399b..908696d483 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "hw/audio/soundhw.h" #include "audio/audio.h" diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 056b87de0b..fc8623c90b 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -26,7 +26,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/ide.h" #include "hw/pci/pci.h" #include "hw/irq.h" diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index c129985e2a..4084b32be9 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/vt82c686.h" #include "hw/i2c/i2c.h" #include "hw/i2c/smbus.h" diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index a5a46827fe..4919011f38 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -20,7 +20,6 @@ #include "qapi/error.h" #include "qemu/cutils.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" diff --git a/hw/misc/sga.c b/hw/misc/sga.c index 03b006d6f0..97fd63f176 100644 --- a/hw/misc/sga.c +++ b/hw/misc/sga.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" #include "hw/pci/pci.h" -#include "hw/i386/pc.h" #include "hw/loader.h" #include "sysemu/sysemu.h" diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 8c8ac737ad..9e799dc10f 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -16,7 +16,6 @@ #include "hw/pci/pci_bus.h" #include "hw/pci/pci_host.h" #include "hw/pci/pci_bridge.h" -#include "hw/i386/pc.h" #include "qemu/range.h" #include "qemu/error-report.h" #include "sysemu/numa.h" diff --git a/monitor.c b/monitor.c index e36fb5308d..d682eee2d8 100644 --- a/monitor.c +++ b/monitor.c @@ -28,7 +28,6 @@ #include "hw/hw.h" #include "monitor/qdev.h" #include "hw/usb.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "sysemu/watchdog.h" #include "hw/loader.h" From 786316113a2ed693cdada9cd7abe9e0aefa93670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:09 -0300 Subject: [PATCH 206/546] hw/ide: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and remove a duplicated include Signed-off-by: Philippe Mathieu-Daudé Acked-by: John Snow Signed-off-by: Michael Tokarev --- hw/ide/ahci.c | 1 - hw/ide/cmd646.c | 1 - hw/ide/core.c | 3 +-- hw/ide/ich.c | 1 - hw/ide/isa.c | 1 - hw/ide/microdrive.c | 1 - hw/ide/pci.c | 1 - hw/ide/piix.c | 2 +- hw/ide/via.c | 1 - 9 files changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 373311f91a..451b18b419 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/msi.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "qemu/error-report.h" diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 86b2a8f504..65aff518ec 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" diff --git a/hw/ide/core.c b/hw/ide/core.c index 471d0c928b..1ea5812b7e 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -24,17 +24,16 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" +#include "sysemu/blockdev.h" #include "sysemu/dma.h" #include "hw/block/block.h" #include "sysemu/block-backend.h" #include "qemu/cutils.h" -#include "qemu/error-report.h" #include "hw/ide/internal.h" #include "trace.h" diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 8dd0ced6b3..c01b24ecbe 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -63,7 +63,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/msi.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 40213d662c..9fb24fc92b 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" #include "sysemu/dma.h" diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 17917c0b30..fde4d4645e 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pcmcia.h" #include "sysemu/block-backend.h" #include "sysemu/dma.h" diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 25f1d36f3a..1ab0a892d0 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" diff --git a/hw/ide/piix.c b/hw/ide/piix.c index dfb21f65fa..a3afe1fd29 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -25,11 +25,11 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" +#include "sysemu/blockdev.h" #include "sysemu/dma.h" #include "hw/ide/pci.h" diff --git a/hw/ide/via.c b/hw/ide/via.c index 35c3059325..117ac4d95e 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "sysemu/block-backend.h" From 34d06688b2ebb32440f91c7f46313c3add2b76f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:10 -0300 Subject: [PATCH 207/546] hw/ipmi: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Corey Minyard Tested-by: Corey Minyard Signed-off-by: Michael Tokarev --- hw/ipmi/isa_ipmi_bt.c | 1 - hw/ipmi/isa_ipmi_kcs.c | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index 2fcc3d2e7c..e098fd5206 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -26,7 +26,6 @@ #include "hw/hw.h" #include "hw/ipmi/ipmi.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" /* Control register */ #define IPMI_BT_CLR_WR_BIT 0 diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 80444977a0..689587b65d 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -26,7 +26,6 @@ #include "hw/hw.h" #include "hw/ipmi/ipmi.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" #define IPMI_KCS_OBF_BIT 0 #define IPMI_KCS_IBF_BIT 1 From b0392e8f78aa677f8bb5c7b11052a6af41ba69de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:11 -0300 Subject: [PATCH 208/546] hw/i2c: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/i2c/pm_smbus.c | 1 - hw/i2c/smbus_ich9.c | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 6fc3923f56..a044dd1b27 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -19,7 +19,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/i2c/pm_smbus.h" #include "hw/i2c/smbus.h" diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index e47556c9d8..007cb6701d 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/i2c/pm_smbus.h" #include "hw/pci/pci.h" #include "sysemu/sysemu.h" From 4c22db44859af80dfca946070d155f5dd43e5492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 17 Dec 2017 22:59:47 -0300 Subject: [PATCH 209/546] hw/tpm: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Berger Reviewed-by: Marc-André Lureau Signed-off-by: Michael Tokarev --- hw/tpm/tpm_emulator.c | 1 - hw/tpm/tpm_passthrough.c | 1 - 2 files changed, 2 deletions(-) diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 3ae8bf6c5a..38b6f175a1 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -33,7 +33,6 @@ #include "sysemu/tpm_backend.h" #include "tpm_int.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "tpm_util.h" #include "tpm_ioctl.h" #include "migration/blocker.h" diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index 487aae2043..149fae63e6 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -29,7 +29,6 @@ #include "sysemu/tpm_backend.h" #include "tpm_int.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "qapi/clone-visitor.h" #include "tpm_util.h" From 2070aaebd2a91b8924db302b7b360c43d7968bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:13 -0300 Subject: [PATCH 210/546] hw/virtio-balloon: remove old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/virtio/virtio-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 37cde38982..14e08d20d0 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -18,7 +18,7 @@ #include "qemu/timer.h" #include "qemu-common.h" #include "hw/virtio/virtio.h" -#include "hw/i386/pc.h" +#include "hw/mem/pc-dimm.h" #include "sysemu/balloon.h" #include "hw/virtio/virtio-balloon.h" #include "sysemu/kvm.h" From 40a3bbc93e5a75bbfc1d220b8bf9bfc33bb1b4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:14 -0300 Subject: [PATCH 211/546] hw/unicore32: restrict hw addr defines to source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and drop unused #includes Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/unicore32/puv3.c | 15 ++++++++++----- include/hw/unicore32/puv3.h | 10 ---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index 1b39cc035b..db26959a1d 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -11,16 +11,11 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qemu-common.h" #include "cpu.h" #include "ui/console.h" -#include "elf.h" -#include "exec/address-spaces.h" -#include "hw/sysbus.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/i386/pc.h" -#include "qemu/error-report.h" #include "sysemu/qtest.h" #undef DEBUG_PUV3 @@ -29,6 +24,16 @@ #define KERNEL_LOAD_ADDR 0x03000000 #define KERNEL_MAX_SIZE 0x00800000 /* Just a guess */ +/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */ +#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */ + +/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */ +#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */ +#define PUV3_INTC_BASE (0xee600000) /* APB-6 */ +#define PUV3_OST_BASE (0xee800000) /* APB-8 */ +#define PUV3_PM_BASE (0xeea00000) /* APB-10 */ +#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */ + static void puv3_intc_cpu_handler(void *opaque, int irq, int level) { UniCore32CPU *cpu = opaque; diff --git a/include/hw/unicore32/puv3.h b/include/hw/unicore32/puv3.h index 5a4839f8df..f587a1f622 100644 --- a/include/hw/unicore32/puv3.h +++ b/include/hw/unicore32/puv3.h @@ -14,16 +14,6 @@ #define PUV3_REGS_OFFSET (0x1000) /* 4K is reasonable */ -/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */ -#define PUV3_DMA_BASE (0xc0200000) /* AHB-4 */ - -/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */ -#define PUV3_GPIO_BASE (0xee500000) /* APB-5 */ -#define PUV3_INTC_BASE (0xee600000) /* APB-6 */ -#define PUV3_OST_BASE (0xee800000) /* APB-8 */ -#define PUV3_PM_BASE (0xeea00000) /* APB-10 */ -#define PUV3_PS2_BASE (0xeeb00000) /* APB-11 */ - /* Hardware interrupts */ #define PUV3_IRQS_NR (32) From acf695eca605ed18fd485af3414e78d1edf93082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:15 -0300 Subject: [PATCH 212/546] hw/timer/i8254: rename pit_init() -> i8254_pit_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and remove the old i386/pc dependency Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Signed-off-by: Michael Tokarev --- hw/alpha/dp264.c | 2 +- hw/i386/pc.c | 2 +- hw/isa/i82378.c | 2 +- hw/mips/mips_fulong2e.c | 2 +- hw/mips/mips_jazz.c | 2 +- hw/mips/mips_malta.c | 2 +- hw/mips/mips_r4k.c | 2 +- hw/timer/i8254.c | 1 - hw/timer/i8254_common.c | 1 - include/hw/timer/i8254.h | 5 +++-- include/hw/timer/i8254_internal.h | 2 +- 11 files changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index babd6ea514..887a7401f1 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -80,7 +80,7 @@ static void clipper_init(MachineState *machine) /* Since we have an SRM-compatible PALcode, use the SRM epoch. */ rtc_init(isa_bus, 1900, rtc_irq); - pit_init(isa_bus, 0x40, 0, NULL); + i8254_pit_init(isa_bus, 0x40, 0, NULL); isa_create_simple(isa_bus, "i8042"); /* VGA setup. Don't bother loading the bios. */ diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 186545d2a4..6a6041573f 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1573,7 +1573,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, if (kvm_pit_in_kernel()) { pit = kvm_pit_init(isa_bus, 0x40); } else { - pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); + pit = i8254_pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq); } if (hpet) { /* connect PIT to output control line of the HPET */ diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index d20ea4c2ee..a9c15f858d 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -97,7 +97,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp) isa_bus_irqs(isabus, s->i8259); /* 1 82C54 (pit) */ - isa = pit_init(isabus, 0x40, 0, NULL); + isa = i8254_pit_init(isabus, 0x40, 0, NULL); /* speaker */ pcspk_init(isabus, isa); diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 146cf0fccd..2a2a09c9de 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -359,7 +359,7 @@ static void mips_fulong2e_init(MachineState *machine) smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); /* init other devices */ - pit = pit_init(isa_bus, 0x40, 0, NULL); + pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); DMA_init(isa_bus, 0); /* Super I/O */ diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index fe4f17389f..995419344d 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -218,7 +218,7 @@ static void mips_jazz_init(MachineState *machine, i8259 = i8259_init(isa_bus, env->irq[4]); isa_bus_irqs(isa_bus, i8259); DMA_init(isa_bus, 0); - pit = pit_init(isa_bus, 0x40, 0, NULL); + pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); pcspk_init(isa_bus, pit); /* Video card */ diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index ec6af4a277..88b4733743 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1208,7 +1208,7 @@ void mips_malta_init(MachineState *machine) isa_get_irq(NULL, 9), NULL, 0, NULL); smbus_eeprom_init(smbus, 8, smbus_eeprom_buf, smbus_eeprom_size); g_free(smbus_eeprom_buf); - pit = pit_init(isa_bus, 0x40, 0, NULL); + pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); DMA_init(isa_bus, 0); /* Super I/O */ diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 3bbb1827e1..58d7bac18b 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -272,7 +272,7 @@ void mips_r4k_init(MachineState *machine) rtc_init(isa_bus, 2000, NULL); - pit = pit_init(isa_bus, 0x40, 0, NULL); + pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index 5e61ad50a8..dbc4a0baec 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "qemu/timer.h" #include "hw/timer/i8254.h" diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c index b623c96198..6190b6fc5d 100644 --- a/hw/timer/i8254_common.c +++ b/hw/timer/i8254_common.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "qemu/timer.h" #include "hw/timer/i8254.h" diff --git a/include/hw/timer/i8254.h b/include/hw/timer/i8254.h index 5adae9fa44..5b12eb918e 100644 --- a/include/hw/timer/i8254.h +++ b/include/hw/timer/i8254.h @@ -26,6 +26,7 @@ #define HW_I8254_H #include "hw/hw.h" +#include "hw/qdev.h" #include "hw/isa/isa.h" #define PIT_FREQ 1193182 @@ -48,8 +49,8 @@ typedef struct PITChannelInfo { #define TYPE_I8254 "isa-pit" #define TYPE_KVM_I8254 "kvm-pit" -static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq, - qemu_irq alt_irq) +static inline ISADevice *i8254_pit_init(ISABus *bus, int base, int isa_irq, + qemu_irq alt_irq) { DeviceState *dev; ISADevice *d; diff --git a/include/hw/timer/i8254_internal.h b/include/hw/timer/i8254_internal.h index dc09cc0467..c37a438f82 100644 --- a/include/hw/timer/i8254_internal.h +++ b/include/hw/timer/i8254_internal.h @@ -26,8 +26,8 @@ #define QEMU_I8254_INTERNAL_H #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" +#include "qemu/timer.h" typedef struct PITChannelState { int count; /* can be 65536 */ From 6c646a11bf5ef87424fa07d3c42d04e709cd7c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:16 -0300 Subject: [PATCH 213/546] hw/timer/mc146818: rename rtc_init() -> mc146818_rtc_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Reviewed-by: David Gibson Signed-off-by: Michael Tokarev --- hw/alpha/dp264.c | 2 +- hw/i386/pc.c | 2 +- hw/isa/i82378.c | 3 ++- hw/mips/mips_fulong2e.c | 2 +- hw/mips/mips_jazz.c | 2 +- hw/mips/mips_malta.c | 2 +- hw/mips/mips_r4k.c | 2 +- hw/ppc/pnv.c | 2 +- hw/timer/mc146818rtc.c | 2 +- include/hw/timer/mc146818rtc.h | 3 ++- 10 files changed, 12 insertions(+), 10 deletions(-) diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 887a7401f1..766373eec7 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -78,7 +78,7 @@ static void clipper_init(MachineState *machine) clipper_pci_map_irq); /* Since we have an SRM-compatible PALcode, use the SRM epoch. */ - rtc_init(isa_bus, 1900, rtc_irq); + mc146818_rtc_init(isa_bus, 1900, rtc_irq); i8254_pit_init(isa_bus, 0x40, 0, NULL); isa_create_simple(isa_bus, "i8042"); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 6a6041573f..fe5e8b53bb 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1565,7 +1565,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT); } } - *rtc_state = rtc_init(isa_bus, 2000, rtc_irq); + *rtc_state = mc146818_rtc_init(isa_bus, 2000, rtc_irq); qemu_register_boot_set(pc_boot_set, *rtc_state); diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index a9c15f858d..a5d67bc6d7 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -21,6 +21,7 @@ #include "hw/pci/pci.h" #include "hw/i386/pc.h" #include "hw/timer/i8254.h" +#include "hw/timer/mc146818rtc.h" #include "hw/audio/pcspk.h" #define TYPE_I82378 "i82378" @@ -106,7 +107,7 @@ static void i82378_realize(PCIDevice *pci, Error **errp) isa = isa_create_simple(isabus, "i82374"); /* timer */ - isa_create_simple(isabus, "mc146818rtc"); + isa_create_simple(isabus, TYPE_MC146818_RTC); } static void i82378_init(Object *obj) diff --git a/hw/mips/mips_fulong2e.c b/hw/mips/mips_fulong2e.c index 2a2a09c9de..725e25a134 100644 --- a/hw/mips/mips_fulong2e.c +++ b/hw/mips/mips_fulong2e.c @@ -365,7 +365,7 @@ static void mips_fulong2e_init(MachineState *machine) /* Super I/O */ isa_create_simple(isa_bus, "i8042"); - rtc_init(isa_bus, 2000, NULL); + mc146818_rtc_init(isa_bus, 2000, NULL); serial_hds_isa_init(isa_bus, 0, MAX_SERIAL_PORTS); parallel_hds_isa_init(isa_bus, 1); diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 995419344d..22a3d5169c 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -288,7 +288,7 @@ static void mips_jazz_init(MachineState *machine, fdctrl_init_sysbus(qdev_get_gpio_in(rc4030, 1), -1, 0x80003000, fds); /* Real time clock */ - rtc_init(isa_bus, 1980, NULL); + mc146818_rtc_init(isa_bus, 1980, NULL); memory_region_init_io(rtc, NULL, &rtc_ops, NULL, "rtc", 0x1000); memory_region_add_subregion(address_space, 0x80004000, rtc); diff --git a/hw/mips/mips_malta.c b/hw/mips/mips_malta.c index 88b4733743..37f19428d6 100644 --- a/hw/mips/mips_malta.c +++ b/hw/mips/mips_malta.c @@ -1214,7 +1214,7 @@ void mips_malta_init(MachineState *machine) /* Super I/O */ isa_create_simple(isa_bus, "i8042"); - rtc_init(isa_bus, 2000, NULL); + mc146818_rtc_init(isa_bus, 2000, NULL); serial_hds_isa_init(isa_bus, 0, 2); parallel_hds_isa_init(isa_bus, 1); diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 58d7bac18b..9884ee7e9f 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -270,7 +270,7 @@ void mips_r4k_init(MachineState *machine) i8259 = i8259_init(isa_bus, env->irq[2]); isa_bus_irqs(isa_bus, i8259); - rtc_init(isa_bus, 2000, NULL); + mc146818_rtc_init(isa_bus, 2000, NULL); pit = i8254_pit_init(isa_bus, 0x40, 0, NULL); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index c35c439d81..94ffc8e137 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -655,7 +655,7 @@ static void ppc_powernv_init(MachineState *machine) serial_hds_isa_init(pnv->isa_bus, 0, MAX_SERIAL_PORTS); /* Create an RTC ISA device too */ - rtc_init(pnv->isa_bus, 2000, NULL); + mc146818_rtc_init(pnv->isa_bus, 2000, NULL); /* OpenPOWER systems use a IPMI SEL Event message to notify the * host to powerdown */ diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 7764be25ec..35a05a64cc 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -999,7 +999,7 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) qdev_init_gpio_out(dev, &s->irq, 1); } -ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) +ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) { DeviceState *dev; ISADevice *isadev; diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h index 7c8e64b203..fe6ed63f71 100644 --- a/include/hw/timer/mc146818rtc.h +++ b/include/hw/timer/mc146818rtc.h @@ -6,7 +6,8 @@ #define TYPE_MC146818_RTC "mc146818rtc" -ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); +ISADevice *mc146818_rtc_init(ISABus *bus, int base_year, + qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); int rtc_get_memory(ISADevice *dev, int addr); From 9dc047ce8f9e787bb9a9c5892c38c2424a0ee65f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:17 -0300 Subject: [PATCH 214/546] hw/acpi: ACPI_PM_* defines are not restricted to i386 arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this allows to remove the old i386/pc dependency on acpi/core. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Signed-off-by: Michael Tokarev --- hw/acpi/core.c | 1 - include/hw/acpi/acpi.h | 11 +++++++++++ include/hw/i386/pc.h | 11 ----------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/hw/acpi/core.c b/hw/acpi/core.c index cd0a1d357b..eb9b76f70b 100644 --- a/hw/acpi/core.c +++ b/hw/acpi/core.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "sysemu/sysemu.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/acpi/acpi.h" #include "hw/nvram/fw_cfg.h" #include "qemu/config-file.h" diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index 7b3d93cf0d..39ff512129 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -39,6 +39,17 @@ #define ACPI_PM2_REGISTER_WIDTH 8 #define ACPI_PM_TIMER_WIDTH 32 +/* PC-style peripherals (also used by other machines). */ +#define ACPI_PM_PROP_S3_DISABLED "disable_s3" +#define ACPI_PM_PROP_S4_DISABLED "disable_s4" +#define ACPI_PM_PROP_S4_VAL "s4_val" +#define ACPI_PM_PROP_SCI_INT "sci_int" +#define ACPI_PM_PROP_ACPI_ENABLE_CMD "acpi_enable_cmd" +#define ACPI_PM_PROP_ACPI_DISABLE_CMD "acpi_disable_cmd" +#define ACPI_PM_PROP_PM_IO_BASE "pm_io_base" +#define ACPI_PM_PROP_GPE0_BLK "gpe0_blk" +#define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len" + /* PM Timer ticks per second (HZ) */ #define PM_TIMER_FREQUENCY 3579545 diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index ef438bd765..252526e600 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -151,17 +151,6 @@ struct PCMachineClass { #define PC_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE) -/* PC-style peripherals (also used by other machines). */ - -#define ACPI_PM_PROP_S3_DISABLED "disable_s3" -#define ACPI_PM_PROP_S4_DISABLED "disable_s4" -#define ACPI_PM_PROP_S4_VAL "s4_val" -#define ACPI_PM_PROP_SCI_INT "sci_int" -#define ACPI_PM_PROP_ACPI_ENABLE_CMD "acpi_enable_cmd" -#define ACPI_PM_PROP_ACPI_DISABLE_CMD "acpi_disable_cmd" -#define ACPI_PM_PROP_PM_IO_BASE "pm_io_base" -#define ACPI_PM_PROP_GPE0_BLK "gpe0_blk" -#define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len" #define ACPI_PM_PROP_TCO_ENABLED "enable_tco" /* parallel.c */ From b1c439d1794a86536bf5f47d9823ff156a7d7433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:18 -0300 Subject: [PATCH 215/546] hw/acpi/ich9: extract ACPI_PM_PROP_TCO_ENABLED from i386/pc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit enable_tco is specific to i386/pc. Suggested-by: Paolo Bonzini Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Igor Mammedov Signed-off-by: Michael Tokarev --- include/hw/acpi/ich9.h | 2 ++ include/hw/i386/pc.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h index a352c94fde..59aeb06393 100644 --- a/include/hw/acpi/ich9.h +++ b/include/hw/acpi/ich9.h @@ -63,6 +63,8 @@ typedef struct ICH9LPCPMRegs { TCOIORegs tco_regs; } ICH9LPCPMRegs; +#define ACPI_PM_PROP_TCO_ENABLED "enable_tco" + void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool smm_enabled, qemu_irq sci_irq); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 252526e600..3794473108 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -151,8 +151,6 @@ struct PCMachineClass { #define PC_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(PCMachineClass, (klass), TYPE_PC_MACHINE) -#define ACPI_PM_PROP_TCO_ENABLED "enable_tco" - /* parallel.c */ void parallel_hds_isa_init(ISABus *bus, int n); From d10d69e39d921a7ca23458421195116ab4577c87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:19 -0300 Subject: [PATCH 216/546] hw/display/vga: "vga.h" only contains registers defs, rename it "vga_regs.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/display/vga.c | 2 +- hw/display/{vga.h => vga_regs.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename hw/display/{vga.h => vga_regs.h} (100%) diff --git a/hw/display/vga.c b/hw/display/vga.c index a64a0942da..ce95b40e5c 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -24,11 +24,11 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "vga.h" #include "ui/console.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "vga_int.h" +#include "vga_regs.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" #include "hw/xen/xen.h" diff --git a/hw/display/vga.h b/hw/display/vga_regs.h similarity index 100% rename from hw/display/vga.h rename to hw/display/vga_regs.h From e07b15891ecafb9c198245410013b30a68de7bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:20 -0300 Subject: [PATCH 217/546] hw/display/vga: "vga_int.h" requires "ui/console.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit since The VGACommonState struct has a GraphicHwOps *hw_ops member, then remove the now unnecessary includes. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/display/cirrus_vga.c | 1 - hw/display/qxl.h | 1 - hw/display/vga-isa-mm.c | 1 - hw/display/vga-isa.c | 1 - hw/display/vga-pci.c | 1 - hw/display/vga.c | 1 - hw/display/vga_int.h | 3 ++- hw/display/virtio-vga.c | 1 - hw/display/vmware_vga.c | 1 - 9 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index bc32bf1e39..138ae961b9 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -31,7 +31,6 @@ #include "trace.h" #include "hw/hw.h" #include "hw/pci/pci.h" -#include "ui/console.h" #include "ui/pixel_ops.h" #include "vga_int.h" #include "hw/loader.h" diff --git a/hw/display/qxl.h b/hw/display/qxl.h index f6556adb73..8668a8e05a 100644 --- a/hw/display/qxl.h +++ b/hw/display/qxl.h @@ -3,7 +3,6 @@ #include "qemu-common.h" -#include "ui/console.h" #include "hw/hw.h" #include "hw/pci/pci.h" #include "vga_int.h" diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c index 51ccbccc41..68c4d6e23e 100644 --- a/hw/display/vga-isa-mm.c +++ b/hw/display/vga-isa-mm.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "ui/console.h" #include "hw/i386/pc.h" #include "vga_int.h" #include "ui/pixel_ops.h" diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 1af95562f2..26f69fd40a 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "ui/console.h" #include "hw/i386/pc.h" #include "vga_int.h" #include "ui/pixel_ops.h" diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 7adb89fcb4..1674bd3581 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -25,7 +25,6 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "ui/console.h" #include "hw/pci/pci.h" #include "vga_int.h" #include "ui/pixel_ops.h" diff --git a/hw/display/vga.c b/hw/display/vga.c index ce95b40e5c..4163b532e0 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -24,7 +24,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "ui/console.h" #include "hw/i386/pc.h" #include "hw/pci/pci.h" #include "vga_int.h" diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index ad34a1f048..fe23b81442 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -25,8 +25,9 @@ #ifndef HW_VGA_INT_H #define HW_VGA_INT_H -#include "hw/hw.h" +#include "exec/ioport.h" #include "exec/memory.h" +#include "ui/console.h" #define ST01_V_RETRACE 0x08 #define ST01_DISP_ENABLE 0x01 diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index f9b017d86b..baa74ba82c 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -1,7 +1,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/pci/pci.h" -#include "ui/console.h" #include "vga_int.h" #include "hw/virtio/virtio-pci.h" #include "qapi/error.h" diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 0e6673a911..bd3e8b3586 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -26,7 +26,6 @@ #include "hw/hw.h" #include "hw/loader.h" #include "trace.h" -#include "ui/console.h" #include "ui/vnc.h" #include "hw/pci/pci.h" From 866e2b3727b6f9f55d5921365f2c97ecf763de65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:21 -0300 Subject: [PATCH 218/546] hw/display/vga: extract public API from i386/pc to "hw/display/vga.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and remove the old i386/pc dependency. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- MAINTAINERS | 1 + hw/display/vga-isa-mm.c | 3 +-- hw/display/vga-isa.c | 2 +- hw/display/vga.c | 2 +- hw/mips/mips_jazz.c | 1 + include/hw/display/vga.h | 25 +++++++++++++++++++++++++ include/hw/i386/pc.h | 12 ------------ vl.c | 2 +- 8 files changed, 31 insertions(+), 17 deletions(-) create mode 100644 include/hw/display/vga.h diff --git a/MAINTAINERS b/MAINTAINERS index acbff2f1bb..8859a50c36 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -881,6 +881,7 @@ F: hw/timer/hpet* F: hw/timer/i8254* F: hw/timer/mc146818rtc* F: hw/watchdog/wdt_ib700.c +F: include/hw/display/vga.h F: include/hw/i2c/pm_smbus.h F: include/hw/isa/i8257.h F: include/hw/timer/hpet.h diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c index 68c4d6e23e..e887b45651 100644 --- a/hw/display/vga-isa-mm.c +++ b/hw/display/vga-isa-mm.c @@ -23,10 +23,9 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" +#include "hw/display/vga.h" #include "vga_int.h" #include "ui/pixel_ops.h" -#include "qemu/timer.h" #define VGA_RAM_SIZE (8192 * 1024) diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 26f69fd40a..469834add5 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -25,7 +25,7 @@ */ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" +#include "hw/isa/isa.h" #include "vga_int.h" #include "ui/pixel_ops.h" #include "qemu/timer.h" diff --git a/hw/display/vga.c b/hw/display/vga.c index 4163b532e0..a0412000a5 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/hw.h" -#include "hw/i386/pc.h" +#include "hw/display/vga.h" #include "hw/pci/pci.h" #include "vga_int.h" #include "vga_regs.h" diff --git a/hw/mips/mips_jazz.c b/hw/mips/mips_jazz.c index 22a3d5169c..0d2c0683ba 100644 --- a/hw/mips/mips_jazz.c +++ b/hw/mips/mips_jazz.c @@ -39,6 +39,7 @@ #include "hw/loader.h" #include "hw/timer/mc146818rtc.h" #include "hw/timer/i8254.h" +#include "hw/display/vga.h" #include "hw/audio/pcspk.h" #include "sysemu/block-backend.h" #include "hw/sysbus.h" diff --git a/include/hw/display/vga.h b/include/hw/display/vga.h new file mode 100644 index 0000000000..0401a3a292 --- /dev/null +++ b/include/hw/display/vga.h @@ -0,0 +1,25 @@ +/* + * QEMU VGA Emulator. + * + * Copyright (c) 2003 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#ifndef QEMU_HW_DISPLAY_VGA_H +#define QEMU_HW_DISPLAY_VGA_H + +#include "exec/memory.h" + +enum vga_retrace_method { + VGA_RETRACE_DUMB, + VGA_RETRACE_PRECISE +}; + +extern enum vga_retrace_method vga_retrace_method; + +int isa_vga_mm_init(hwaddr vram_base, + hwaddr ctrl_base, int it_shift, + MemoryRegion *address_space); + +#endif diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 3794473108..1d55ba3322 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -302,18 +302,6 @@ PCIBus *find_i440fx(void); extern PCIDevice *piix4_dev; int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); -/* vga.c */ -enum vga_retrace_method { - VGA_RETRACE_DUMB, - VGA_RETRACE_PRECISE -}; - -extern enum vga_retrace_method vga_retrace_method; - -int isa_vga_mm_init(hwaddr vram_base, - hwaddr ctrl_base, int it_shift, - MemoryRegion *address_space); - /* ne2000.c */ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) { diff --git a/vl.c b/vl.c index c1ba52306a..e9012bb009 100644 --- a/vl.c +++ b/vl.c @@ -57,9 +57,9 @@ int main(int argc, char **argv) #include "hw/boards.h" #include "sysemu/accel.h" #include "hw/usb.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "hw/scsi/scsi.h" +#include "hw/display/vga.h" #include "hw/bt.h" #include "sysemu/watchdog.h" #include "hw/smbios/smbios.h" From 489983d6b4cb501a86dfd08648fb370aec0f9b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:22 -0300 Subject: [PATCH 219/546] hw/net/ne2000: extract ne2k-isa code from i386/pc to ne2000-isa.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add "hw/net/ne2000-isa.h" - remove the old i386 dependency Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Hervé Poussineau Acked-by: David Gibson [PPC] Signed-off-by: Michael Tokarev --- hw/i386/pc.c | 1 + hw/mips/mips_r4k.c | 1 + hw/net/ne2000-isa.c | 6 ++---- hw/net/ne2000.c | 2 -- hw/net/ne2000.h | 3 +++ hw/ppc/prep.c | 1 + include/hw/i386/pc.h | 20 -------------------- include/hw/net/ne2000-isa.h | 33 +++++++++++++++++++++++++++++++++ 8 files changed, 41 insertions(+), 26 deletions(-) create mode 100644 include/hw/net/ne2000-isa.h diff --git a/hw/i386/pc.c b/hw/i386/pc.c index fe5e8b53bb..3fcf318a95 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -69,6 +69,7 @@ #include "qom/cpu.h" #include "hw/nmi.h" #include "hw/i386/intel_iommu.h" +#include "hw/net/ne2000-isa.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ diff --git a/hw/mips/mips_r4k.c b/hw/mips/mips_r4k.c index 9884ee7e9f..244bd41813 100644 --- a/hw/mips/mips_r4k.c +++ b/hw/mips/mips_r4k.c @@ -18,6 +18,7 @@ #include "hw/char/serial.h" #include "hw/isa/isa.h" #include "net/net.h" +#include "hw/net/ne2000-isa.h" #include "sysemu/sysemu.h" #include "hw/boards.h" #include "hw/block/flash.h" diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index f3455339ee..70e5c1d3d4 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -22,17 +22,15 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" +#include "hw/net/ne2000-isa.h" #include "hw/qdev.h" -#include "net/net.h" #include "ne2000.h" +#include "sysemu/sysemu.h" #include "exec/address-spaces.h" #include "qapi/error.h" #include "qapi/visitor.h" -#define TYPE_ISA_NE2000 "ne2k_isa" #define ISA_NE2000(obj) OBJECT_CHECK(ISANE2000State, (obj), TYPE_ISA_NE2000) typedef struct ISANE2000State { diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 3938e6ddd8..6874c8c6b9 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -22,9 +22,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" #include "hw/pci/pci.h" -#include "net/net.h" #include "ne2000.h" #include "hw/loader.h" #include "sysemu/sysemu.h" diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h index d213dccae3..adb8021bd1 100644 --- a/hw/net/ne2000.h +++ b/hw/net/ne2000.h @@ -1,6 +1,9 @@ #ifndef HW_NE2000_H #define HW_NE2000_H +#include "hw/hw.h" +#include "net/net.h" + #define NE2000_PMEM_SIZE (32*1024) #define NE2000_PMEM_START (16*1024) #define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 6f8accc397..af08ac319a 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -42,6 +42,7 @@ #include "hw/loader.h" #include "hw/timer/mc146818rtc.h" #include "hw/isa/pc87312.h" +#include "hw/net/ne2000-isa.h" #include "sysemu/block-backend.h" #include "sysemu/arch_init.h" #include "sysemu/kvm.h" diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 1d55ba3322..ab84e31cce 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -302,26 +302,6 @@ PCIBus *find_i440fx(void); extern PCIDevice *piix4_dev; int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); -/* ne2000.c */ -static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) -{ - DeviceState *dev; - ISADevice *isadev; - - qemu_check_nic_model(nd, "ne2k_isa"); - - isadev = isa_try_create(bus, "ne2k_isa"); - if (!isadev) { - return false; - } - dev = DEVICE(isadev); - qdev_prop_set_uint32(dev, "iobase", base); - qdev_prop_set_uint32(dev, "irq", irq); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - return true; -} - /* pc_sysfw.c */ void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw); diff --git a/include/hw/net/ne2000-isa.h b/include/hw/net/ne2000-isa.h new file mode 100644 index 0000000000..ff2bed9c95 --- /dev/null +++ b/include/hw/net/ne2000-isa.h @@ -0,0 +1,33 @@ +/* + * QEMU NE2000 emulation -- isa bus windup + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "hw/hw.h" +#include "hw/qdev.h" +#include "hw/isa/isa.h" +#include "net/net.h" + +#define TYPE_ISA_NE2000 "ne2k_isa" + +static inline ISADevice *isa_ne2000_init(ISABus *bus, int base, int irq, + NICInfo *nd) +{ + ISADevice *d; + + qemu_check_nic_model(nd, "ne2k_isa"); + + d = isa_try_create(bus, TYPE_ISA_NE2000); + if (d) { + DeviceState *dev = DEVICE(d); + + qdev_prop_set_uint32(dev, "iobase", base); + qdev_prop_set_uint32(dev, "irq", irq); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + } + return d; +} From 0d5d8a3a906f782eab8a85079eede78879dc8155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:23 -0300 Subject: [PATCH 220/546] hw/misc/pvpanic: extract public API from i386/pc to "hw/misc/pvpanic.h" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and remove the old i386/pc dependency. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Michael Tokarev --- hw/i386/acpi-build.c | 2 +- hw/misc/pvpanic.c | 9 ++++----- include/hw/i386/pc.h | 3 --- include/hw/misc/pvpanic.h | 21 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 include/hw/misc/pvpanic.h diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index dd1420b410..5a6dee081c 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -28,8 +28,8 @@ #include "qemu/error-report.h" #include "hw/pci/pci.h" #include "qom/cpu.h" -#include "hw/i386/pc.h" #include "target/i386/cpu.h" +#include "hw/misc/pvpanic.h" #include "hw/timer/hpet.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 3a0e4ba828..b26250dec9 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -17,7 +17,7 @@ #include "qemu/log.h" #include "hw/nvram/fw_cfg.h" -#include "hw/i386/pc.h" +#include "hw/misc/pvpanic.h" /* The bit of supported pv event */ #define PVPANIC_F_PANICKED 0 @@ -25,9 +25,8 @@ /* The pv event value */ #define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED) -#define TYPE_ISA_PVPANIC_DEVICE "pvpanic" #define ISA_PVPANIC_DEVICE(obj) \ - OBJECT_CHECK(PVPanicState, (obj), TYPE_ISA_PVPANIC_DEVICE) + OBJECT_CHECK(PVPanicState, (obj), TYPE_PVPANIC) static void handle_event(int event) { @@ -104,7 +103,7 @@ static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp) uint16_t pvpanic_port(void) { - Object *o = object_resolve_path_type("", TYPE_ISA_PVPANIC_DEVICE, NULL); + Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL); if (!o) { return 0; } @@ -126,7 +125,7 @@ static void pvpanic_isa_class_init(ObjectClass *klass, void *data) } static TypeInfo pvpanic_isa_info = { - .name = TYPE_ISA_PVPANIC_DEVICE, + .name = TYPE_PVPANIC, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(PVPanicState), .instance_init = pvpanic_isa_initfn, diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index ab84e31cce..6f77eb0665 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -306,9 +306,6 @@ int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); void pc_system_firmware_init(MemoryRegion *rom_memory, bool isapc_ram_fw); -/* pvpanic.c */ -uint16_t pvpanic_port(void); - /* acpi-build.c */ void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry); diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h new file mode 100644 index 0000000000..36a54e270c --- /dev/null +++ b/include/hw/misc/pvpanic.h @@ -0,0 +1,21 @@ +/* + * QEMU simulated pvpanic device. + * + * Copyright Fujitsu, Corp. 2013 + * + * Authors: + * Wen Congyang + * Hu Tao + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#ifndef HW_MISC_PVPANIC_H +#define HW_MISC_PVPANIC_H + +#define TYPE_PVPANIC "pvpanic" + +uint16_t pvpanic_port(void); + +#endif From 323d7d1d999d8be31e4d5a50ee18f7e2ca5d096a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:24 -0300 Subject: [PATCH 221/546] i386/pc: move vmport.c to hw/i386/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a x86-only device, so it does not make sense to keep it in the shared misc folder. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/i386/Makefile.objs | 1 + hw/{misc => i386}/vmport.c | 17 +++++++++-------- hw/misc/Makefile.objs | 2 -- 3 files changed, 10 insertions(+), 10 deletions(-) rename hw/{misc => i386}/vmport.c (95%) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 2e5e1299ad..1548ad1ad0 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -5,6 +5,7 @@ obj-y += pc_sysfw.o obj-y += x86-iommu.o intel_iommu.o obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ +obj-$(CONFIG_VMPORT) += vmport.o obj-y += kvmvapic.o obj-y += acpi-build.o diff --git a/hw/misc/vmport.c b/hw/i386/vmport.c similarity index 95% rename from hw/misc/vmport.c rename to hw/i386/vmport.c index 165500223f..eb880c6def 100644 --- a/hw/misc/vmport.c +++ b/hw/i386/vmport.c @@ -28,7 +28,7 @@ #include "sysemu/hw_accel.h" #include "hw/qdev.h" -//#define VMPORT_DEBUG +/* #define VMPORT_DEBUG */ #define VMPORT_CMD_GETVERSION 0x0a #define VMPORT_CMD_GETRAMSIZE 0x14 @@ -38,8 +38,7 @@ #define VMPORT(obj) OBJECT_CHECK(VMPortState, (obj), TYPE_VMPORT) -typedef struct VMPortState -{ +typedef struct VMPortState { ISADevice parent_obj; MemoryRegion io; @@ -51,8 +50,9 @@ static VMPortState *port_state; void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque) { - if (command >= VMPORT_ENTRIES) + if (command >= VMPORT_ENTRIES) { return; + } port_state->func[command] = func; port_state->opaque[command] = opaque; @@ -71,14 +71,15 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, cpu_synchronize_state(cs); eax = env->regs[R_EAX]; - if (eax != VMPORT_MAGIC) + if (eax != VMPORT_MAGIC) { return eax; + } command = env->regs[R_ECX]; - if (command >= VMPORT_ENTRIES) + if (command >= VMPORT_ENTRIES) { return eax; - if (!s->func[command]) - { + } + if (!s->func[command]) { #ifdef VMPORT_DEBUG fprintf(stderr, "vmport: unknown command %x\n", command); #endif diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index 10c88a84b4..d517f83e81 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -11,8 +11,6 @@ common-obj-$(CONFIG_EDU) += edu.o common-obj-y += unimp.o common-obj-$(CONFIG_FW_CFG_DMA) += vmcoreinfo.o -obj-$(CONFIG_VMPORT) += vmport.o - # ARM devices common-obj-$(CONFIG_PL310) += arm_l2x0.o common-obj-$(CONFIG_INTEGRATOR_DEBUG) += arm_integrator_debug.o From 664b4be5e8bcb538ae8e68fe54ff27fedc5ea5b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:25 -0300 Subject: [PATCH 222/546] i386/pc: move vmmouse.c to hw/i386/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's a x86-only device, so it does not make sense to keep it in the shared misc folder. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/i386/Makefile.objs | 1 + hw/{input => i386}/vmmouse.c | 0 hw/input/Makefile.objs | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename hw/{input => i386}/vmmouse.c (100%) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 1548ad1ad0..fd279e7584 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -6,6 +6,7 @@ obj-y += x86-iommu.o intel_iommu.o obj-y += amd_iommu.o obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-$(CONFIG_VMPORT) += vmport.o +obj-$(CONFIG_VMMOUSE) += vmmouse.o obj-y += kvmvapic.o obj-y += acpi-build.o diff --git a/hw/input/vmmouse.c b/hw/i386/vmmouse.c similarity index 100% rename from hw/input/vmmouse.c rename to hw/i386/vmmouse.c diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs index 7715d7230d..636f794b6b 100644 --- a/hw/input/Makefile.objs +++ b/hw/input/Makefile.objs @@ -6,7 +6,6 @@ common-obj-$(CONFIG_PL050) += pl050.o common-obj-y += ps2.o common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o common-obj-$(CONFIG_TSC2005) += tsc2005.o -common-obj-$(CONFIG_VMMOUSE) += vmmouse.o common-obj-$(CONFIG_VIRTIO) += virtio-input.o common-obj-$(CONFIG_VIRTIO) += virtio-input-hid.o From c0578de60fcc3a07a881e9c4b7b8262faf6abbc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 17 Oct 2017 13:44:26 -0300 Subject: [PATCH 223/546] misc: drop old i386 dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Signed-off-by: Michael Tokarev --- hw/char/debugcon.c | 1 - hw/intc/lm32_pic.c | 1 - hw/moxie/moxiesim.c | 1 - hw/sparc/sun4m.c | 1 - hw/watchdog/wdt_ib700.c | 1 - 5 files changed, 5 deletions(-) diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index 95ccec6f8b..e2abc61b04 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -29,7 +29,6 @@ #include "hw/hw.h" #include "chardev/char-fe.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" #define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" #define ISA_DEBUGCON_DEVICE(obj) \ diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c index 09e15115fb..db6c7afc2f 100644 --- a/hw/intc/lm32_pic.c +++ b/hw/intc/lm32_pic.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "monitor/monitor.h" #include "hw/sysbus.h" #include "trace.h" diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index 3ba58481d0..3c3ba9d8c5 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -30,7 +30,6 @@ #include "cpu.h" #include "hw/sysbus.h" #include "hw/hw.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "net/net.h" #include "sysemu/sysemu.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 24c2b8a555..e71648404c 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -36,7 +36,6 @@ #include "net/net.h" #include "hw/boards.h" #include "hw/scsi/esp.h" -#include "hw/i386/pc.h" #include "hw/isa/isa.h" #include "hw/nvram/sun_nvram.h" #include "hw/nvram/chrp_nvram.h" diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index 532afe89e7..d045032bf4 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -25,7 +25,6 @@ #include "sysemu/watchdog.h" #include "hw/hw.h" #include "hw/isa/isa.h" -#include "hw/i386/pc.h" /*#define IB700_DEBUG 1*/ From 5070570c9089b905dd9efae30ee4318033c6ccd6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Nov 2017 00:31:34 +0900 Subject: [PATCH 224/546] trace: Simplify find_debugfs() The return vale of find_debugfs() is 1 if it could find a mount point of debugfs. It can be saved in the while loop instead of checking it again. Signed-off-by: Namhyung Kim Signed-off-by: Stefan Hajnoczi --- trace/ftrace.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/trace/ftrace.c b/trace/ftrace.c index 7de104deba..bfa38e71f0 100644 --- a/trace/ftrace.c +++ b/trace/ftrace.c @@ -19,6 +19,7 @@ static int find_debugfs(char *debugfs) { char type[100]; FILE *fp; + int ret = 0; fp = fopen("/proc/mounts", "r"); if (fp == NULL) { @@ -28,15 +29,13 @@ static int find_debugfs(char *debugfs) while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", debugfs, type) == 2) { if (strcmp(type, "debugfs") == 0) { + ret = 1; break; } } fclose(fp); - if (strcmp(type, "debugfs") != 0) { - return 0; - } - return 1; + return ret; } bool ftrace_init(void) From babfff8e11589a2d1ab9ca777ebb16495f708616 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Nov 2017 00:31:35 +0900 Subject: [PATCH 225/546] trace: Generalize searching for debugfs The find_debugfs() can be shared to find a different filesystem like tracefs. So make it more general and rename to find_mount(). Signed-off-by: Namhyung Kim Signed-off-by: Stefan Hajnoczi --- trace/ftrace.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/trace/ftrace.c b/trace/ftrace.c index bfa38e71f0..213cb2205f 100644 --- a/trace/ftrace.c +++ b/trace/ftrace.c @@ -15,7 +15,7 @@ int trace_marker_fd; -static int find_debugfs(char *debugfs) +static int find_mount(char *mount_point, const char *fstype) { char type[100]; FILE *fp; @@ -27,8 +27,8 @@ static int find_debugfs(char *debugfs) } while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", - debugfs, type) == 2) { - if (strcmp(type, "debugfs") == 0) { + mount_point, type) == 2) { + if (strcmp(type, fstype) == 0) { ret = 1; break; } @@ -40,14 +40,14 @@ static int find_debugfs(char *debugfs) bool ftrace_init(void) { - char debugfs[PATH_MAX]; + char mount_point[PATH_MAX]; char path[PATH_MAX]; int debugfs_found; int trace_fd = -1; - debugfs_found = find_debugfs(debugfs); + debugfs_found = find_mount(mount_point, "debugfs"); if (debugfs_found) { - snprintf(path, PATH_MAX, "%s/tracing/tracing_on", debugfs); + snprintf(path, PATH_MAX, "%s/tracing/tracing_on", mount_point); trace_fd = open(path, O_WRONLY); if (trace_fd < 0) { if (errno == EACCES) { @@ -66,7 +66,7 @@ bool ftrace_init(void) } close(trace_fd); } - snprintf(path, PATH_MAX, "%s/tracing/trace_marker", debugfs); + snprintf(path, PATH_MAX, "%s/tracing/trace_marker", mount_point); trace_marker_fd = open(path, O_WRONLY); if (trace_marker_fd < 0) { perror("Could not open ftrace 'trace_marker' file"); From c9add6219514b20223f024584f0464b8842b1ec0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 8 Nov 2017 00:31:36 +0900 Subject: [PATCH 226/546] trace: Try using tracefs first Recent Linux kernel provides separate tracefs which doesn't need to be mounted on the debugfs. Although most systems mount it at the traditional place on the debugfs, it'd be safer to check tracefs first. Signed-off-by: Namhyung Kim Signed-off-by: Stefan Hajnoczi --- trace/ftrace.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/trace/ftrace.c b/trace/ftrace.c index 213cb2205f..61692a8682 100644 --- a/trace/ftrace.c +++ b/trace/ftrace.c @@ -42,12 +42,18 @@ bool ftrace_init(void) { char mount_point[PATH_MAX]; char path[PATH_MAX]; - int debugfs_found; + int tracefs_found; int trace_fd = -1; + const char *subdir = ""; - debugfs_found = find_mount(mount_point, "debugfs"); - if (debugfs_found) { - snprintf(path, PATH_MAX, "%s/tracing/tracing_on", mount_point); + tracefs_found = find_mount(mount_point, "tracefs"); + if (!tracefs_found) { + tracefs_found = find_mount(mount_point, "debugfs"); + subdir = "/tracing"; + } + + if (tracefs_found) { + snprintf(path, PATH_MAX, "%s%s/tracing_on", mount_point, subdir); trace_fd = open(path, O_WRONLY); if (trace_fd < 0) { if (errno == EACCES) { @@ -66,14 +72,14 @@ bool ftrace_init(void) } close(trace_fd); } - snprintf(path, PATH_MAX, "%s/tracing/trace_marker", mount_point); + snprintf(path, PATH_MAX, "%s%s/trace_marker", mount_point, subdir); trace_marker_fd = open(path, O_WRONLY); if (trace_marker_fd < 0) { perror("Could not open ftrace 'trace_marker' file"); return false; } } else { - fprintf(stderr, "debugfs is not mounted\n"); + fprintf(stderr, "tracefs is not mounted\n"); return false; } From 5c9522b358faf9688fd83cd0a881e1990bb84516 Mon Sep 17 00:00:00 2001 From: Doug Gale Date: Sat, 2 Dec 2017 20:30:37 -0500 Subject: [PATCH 227/546] gdbstub: add tracing Signed-off-by: Doug Gale Message-id: 20171203013037.31978-1-doug16k@gmail.com Signed-off-by: Stefan Hajnoczi --- gdbstub.c | 113 +++++++++++++++++++++++++++++++++++---------------- trace-events | 28 +++++++++++++ 2 files changed, 106 insertions(+), 35 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 2a94030d3b..f1d51480f7 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -21,6 +21,7 @@ #include "qemu/error-report.h" #include "qemu/cutils.h" #include "cpu.h" +#include "trace-root.h" #ifdef CONFIG_USER_ONLY #include "qemu.h" #else @@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig) return -1; } -/* #define DEBUG_GDB */ - -#ifdef DEBUG_GDB -# define DEBUG_GDB_GATE 1 -#else -# define DEBUG_GDB_GATE 0 -#endif - -#define gdb_debug(fmt, ...) do { \ - if (DEBUG_GDB_GATE) { \ - fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ - } \ -} while (0) - - typedef struct GDBRegisterState { int base_reg; int num_regs; @@ -410,10 +396,13 @@ int use_gdb_syscalls(void) /* Resume execution. */ static inline void gdb_continue(GDBState *s) { + #ifdef CONFIG_USER_ONLY s->running_state = 1; + trace_gdbstub_op_continue(); #else if (!runstate_needs_reset()) { + trace_gdbstub_op_continue(); vm_start(); } #endif @@ -434,6 +423,7 @@ static int gdb_continue_partial(GDBState *s, char *newstates) */ CPU_FOREACH(cpu) { if (newstates[cpu->cpu_index] == 's') { + trace_gdbstub_op_stepping(cpu->cpu_index); cpu_single_step(cpu, sstep_flags); } } @@ -452,11 +442,13 @@ static int gdb_continue_partial(GDBState *s, char *newstates) case 1: break; /* nothing to do here */ case 's': + trace_gdbstub_op_stepping(cpu->cpu_index); cpu_single_step(cpu, sstep_flags); cpu_resume(cpu); flag = 1; break; case 'c': + trace_gdbstub_op_continue_cpu(cpu->cpu_index); cpu_resume(cpu); flag = 1; break; @@ -538,12 +530,49 @@ static void hextomem(uint8_t *mem, const char *buf, int len) } } +static void hexdump(const char *buf, int len, + void (*trace_fn)(size_t ofs, char const *text)) +{ + char line_buffer[3 * 16 + 4 + 16 + 1]; + + size_t i; + for (i = 0; i < len || (i & 0xF); ++i) { + size_t byte_ofs = i & 15; + + if (byte_ofs == 0) { + memset(line_buffer, ' ', 3 * 16 + 4 + 16); + line_buffer[3 * 16 + 4 + 16] = 0; + } + + size_t col_group = (i >> 2) & 3; + size_t hex_col = byte_ofs * 3 + col_group; + size_t txt_col = 3 * 16 + 4 + byte_ofs; + + if (i < len) { + char value = buf[i]; + + line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF); + line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF); + line_buffer[txt_col + 0] = (value >= ' ' && value < 127) + ? value + : '.'; + } + + if (byte_ofs == 0xF) + trace_fn(i & -16, line_buffer); + } +} + /* return -1 if error, 0 if OK */ -static int put_packet_binary(GDBState *s, const char *buf, int len) +static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump) { int csum, i; uint8_t *p; + if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) { + hexdump(buf, len, trace_gdbstub_io_binaryreply); + } + for(;;) { p = s->last_packet; *(p++) = '$'; @@ -576,9 +605,9 @@ static int put_packet_binary(GDBState *s, const char *buf, int len) /* return -1 if error, 0 if OK */ static int put_packet(GDBState *s, const char *buf) { - gdb_debug("reply='%s'\n", buf); + trace_gdbstub_io_reply(buf); - return put_packet_binary(s, buf, strlen(buf)); + return put_packet_binary(s, buf, strlen(buf), false); } /* Encode data using the encoding for 'x' packets. */ @@ -975,8 +1004,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) uint8_t *registers; target_ulong addr, len; - - gdb_debug("command='%s'\n", line_buf); + trace_gdbstub_io_command(line_buf); p = line_buf; ch = *p++; @@ -999,7 +1027,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } s->signal = 0; gdb_continue(s); - return RS_IDLE; + return RS_IDLE; case 'C': s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16)); if (s->signal == -1) @@ -1045,7 +1073,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) } cpu_single_step(s->c_cpu, sstep_flags); gdb_continue(s); - return RS_IDLE; + return RS_IDLE; case 'F': { target_ulong ret; @@ -1267,6 +1295,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) len = snprintf((char *)mem_buf, sizeof(buf) / 2, "CPU#%d [%s]", cpu->cpu_index, cpu->halted ? "halted " : "running"); + trace_gdbstub_op_extra_info((char *)mem_buf); memtohex(buf, mem_buf, len); put_packet(s, buf); } @@ -1350,7 +1379,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) buf[0] = 'l'; len = memtox(buf + 1, xml + addr, total_len - addr); } - put_packet_binary(s, buf, len + 1); + put_packet_binary(s, buf, len + 1, true); break; } if (is_query_packet(p, "Attached", ':')) { @@ -1407,29 +1436,38 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) type = ""; break; } + trace_gdbstub_hit_watchpoint(type, cpu_gdb_index(cpu), + (target_ulong)cpu->watchpoint_hit->vaddr); snprintf(buf, sizeof(buf), "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", GDB_SIGNAL_TRAP, cpu_gdb_index(cpu), type, (target_ulong)cpu->watchpoint_hit->vaddr); cpu->watchpoint_hit = NULL; goto send_packet; + } else { + trace_gdbstub_hit_break(); } tb_flush(cpu); ret = GDB_SIGNAL_TRAP; break; case RUN_STATE_PAUSED: + trace_gdbstub_hit_paused(); ret = GDB_SIGNAL_INT; break; case RUN_STATE_SHUTDOWN: + trace_gdbstub_hit_shutdown(); ret = GDB_SIGNAL_QUIT; break; case RUN_STATE_IO_ERROR: + trace_gdbstub_hit_io_error(); ret = GDB_SIGNAL_IO; break; case RUN_STATE_WATCHDOG: + trace_gdbstub_hit_watchdog(); ret = GDB_SIGNAL_ALRM; break; case RUN_STATE_INTERNAL_ERROR: + trace_gdbstub_hit_internal_error(); ret = GDB_SIGNAL_ABRT; break; case RUN_STATE_SAVE_VM: @@ -1439,6 +1477,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state) ret = GDB_SIGNAL_XCPU; break; default: + trace_gdbstub_hit_unknown(state); ret = GDB_SIGNAL_UNKNOWN; break; } @@ -1538,12 +1577,12 @@ static void gdb_read_byte(GDBState *s, int ch) /* Waiting for a response to the last packet. If we see the start of a new command then abandon the previous response. */ if (ch == '-') { - gdb_debug("Got NACK, retransmitting\n"); + trace_gdbstub_err_got_nack(); put_buffer(s, (uint8_t *)s->last_packet, s->last_packet_len); } else if (ch == '+') { - gdb_debug("Got ACK\n"); + trace_gdbstub_io_got_ack(); } else { - gdb_debug("Got '%c' when expecting ACK/NACK\n", ch); + trace_gdbstub_io_got_unexpected((uint8_t)ch); } if (ch == '+' || ch == '$') @@ -1566,7 +1605,7 @@ static void gdb_read_byte(GDBState *s, int ch) s->line_sum = 0; s->state = RS_GETLINE; } else { - gdb_debug("received garbage between packets: 0x%x\n", ch); + trace_gdbstub_err_garbage((uint8_t)ch); } break; case RS_GETLINE: @@ -1582,7 +1621,7 @@ static void gdb_read_byte(GDBState *s, int ch) /* end of command, start of checksum*/ s->state = RS_CHKSUM1; } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { - gdb_debug("command buffer overrun, dropping command\n"); + trace_gdbstub_err_overrun(); s->state = RS_IDLE; } else { /* unescaped command character */ @@ -1596,7 +1635,7 @@ static void gdb_read_byte(GDBState *s, int ch) s->state = RS_CHKSUM1; } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) { /* command buffer overrun */ - gdb_debug("command buffer overrun, dropping command\n"); + trace_gdbstub_err_overrun(); s->state = RS_IDLE; } else { /* parse escaped character and leave escape state */ @@ -1608,18 +1647,18 @@ static void gdb_read_byte(GDBState *s, int ch) case RS_GETLINE_RLE: if (ch < ' ') { /* invalid RLE count encoding */ - gdb_debug("got invalid RLE count: 0x%x\n", ch); + trace_gdbstub_err_invalid_repeat((uint8_t)ch); s->state = RS_GETLINE; } else { /* decode repeat length */ int repeat = (unsigned char)ch - ' ' + 3; if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) { /* that many repeats would overrun the command buffer */ - gdb_debug("command buffer overrun, dropping command\n"); + trace_gdbstub_err_overrun(); s->state = RS_IDLE; } else if (s->line_buf_index < 1) { /* got a repeat but we have nothing to repeat */ - gdb_debug("got invalid RLE sequence\n"); + trace_gdbstub_err_invalid_rle(); s->state = RS_GETLINE; } else { /* repeat the last character */ @@ -1634,7 +1673,7 @@ static void gdb_read_byte(GDBState *s, int ch) case RS_CHKSUM1: /* get high hex digit of checksum */ if (!isxdigit(ch)) { - gdb_debug("got invalid command checksum digit\n"); + trace_gdbstub_err_checksum_invalid((uint8_t)ch); s->state = RS_GETLINE; break; } @@ -1645,14 +1684,14 @@ static void gdb_read_byte(GDBState *s, int ch) case RS_CHKSUM2: /* get low hex digit of checksum */ if (!isxdigit(ch)) { - gdb_debug("got invalid command checksum digit\n"); + trace_gdbstub_err_checksum_invalid((uint8_t)ch); s->state = RS_GETLINE; break; } s->line_csum |= fromhex(ch); if (s->line_csum != (s->line_sum & 0xff)) { - gdb_debug("got command packet with incorrect checksum\n"); + trace_gdbstub_err_checksum_incorrect(s->line_sum, s->line_csum); /* send NAK reply */ reply = '-'; put_buffer(s, &reply, 1); @@ -1686,6 +1725,8 @@ void gdb_exit(CPUArchState *env, int code) } #endif + trace_gdbstub_op_exiting((uint8_t)code); + snprintf(buf, sizeof(buf), "W%02x", (uint8_t)code); put_packet(s, buf); @@ -1944,6 +1985,8 @@ static const TypeInfo char_gdb_type_info = { int gdbserver_start(const char *device) { + trace_gdbstub_op_start(device); + GDBState *s; char gdbstub_device_name[128]; Chardev *chr = NULL; diff --git a/trace-events b/trace-events index 1d2eb5d3e4..3695959d0a 100644 --- a/trace-events +++ b/trace-events @@ -68,6 +68,34 @@ flatview_new(FlatView *view, MemoryRegion *root) "%p (root %p)" flatview_destroy(FlatView *view, MemoryRegion *root) "%p (root %p)" flatview_destroy_rcu(FlatView *view, MemoryRegion *root) "%p (root %p)" +# gdbstub.c +gdbstub_op_start(char const *device) "Starting gdbstub using device %s" +gdbstub_op_exiting(uint8_t code) "notifying exit with code=0x%02x" +gdbstub_op_continue(void) "Continuing all CPUs" +gdbstub_op_continue_cpu(int cpu_index) "Continuing CPU %d" +gdbstub_op_stepping(int cpu_index) "Stepping CPU %d" +gdbstub_op_extra_info(char const *info) "Thread extra info: %s" +gdbstub_hit_watchpoint(char const *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 "" +gdbstub_hit_internal_error(void) "RUN_STATE_INTERNAL_ERROR" +gdbstub_hit_break(void) "RUN_STATE_DEBUG" +gdbstub_hit_paused(void) "RUN_STATE_PAUSED" +gdbstub_hit_shutdown(void) "RUN_STATE_SHUTDOWN" +gdbstub_hit_io_error(void) "RUN_STATE_IO_ERROR" +gdbstub_hit_watchdog(void) "RUN_STATE_WATCHDOG" +gdbstub_hit_unknown(int state) "Unknown run state=0x%x" +gdbstub_io_reply(char const *message) "Sent: %s" +gdbstub_io_binaryreply(size_t ofs, char const *line) "0x%04zx: %s" +gdbstub_io_command(char const *command) "Received: %s" +gdbstub_io_got_ack(void) "Got ACK" +gdbstub_io_got_unexpected(uint8_t ch) "Got 0x%02x when expecting ACK/NACK" +gdbstub_err_got_nack(void) "Got NACK, retransmitting" +gdbstub_err_garbage(uint8_t ch) "received garbage between packets: 0x%02x" +gdbstub_err_overrun(void) "command buffer overrun, dropping command" +gdbstub_err_invalid_repeat(uint8_t ch) "got invalid RLE count: 0x%02x" +gdbstub_err_invalid_rle(void) "got invalid RLE sequence" +gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x" +gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x" + ### Guest events, keep at bottom From 56207df55ea546f3e72578a5920e68a346440b1a Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 12 Oct 2017 16:53:09 +0300 Subject: [PATCH 228/546] hbitmap: add next_zero function The function searches for next zero bit. Also add interface for BdrvDirtyBitmap and unit test. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Message-id: 20171012135313.227864-2-vsementsov@virtuozzo.com Signed-off-by: Jeff Cody --- block/dirty-bitmap.c | 5 +++ include/block/dirty-bitmap.h | 1 + include/qemu/hbitmap.h | 8 +++++ tests/test-hbitmap.c | 61 ++++++++++++++++++++++++++++++++++++ util/hbitmap.c | 39 +++++++++++++++++++++++ 5 files changed, 114 insertions(+) diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c index bd04e991b1..7879d13ddb 100644 --- a/block/dirty-bitmap.c +++ b/block/dirty-bitmap.c @@ -715,3 +715,8 @@ char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp) { return hbitmap_sha256(bitmap->bitmap, errp); } + +int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t offset) +{ + return hbitmap_next_zero(bitmap->bitmap, offset); +} diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h index 3579a7597c..a591c27213 100644 --- a/include/block/dirty-bitmap.h +++ b/include/block/dirty-bitmap.h @@ -91,5 +91,6 @@ bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs); BdrvDirtyBitmap *bdrv_dirty_bitmap_next(BlockDriverState *bs, BdrvDirtyBitmap *bitmap); char *bdrv_dirty_bitmap_sha256(const BdrvDirtyBitmap *bitmap, Error **errp); +int64_t bdrv_dirty_bitmap_next_zero(BdrvDirtyBitmap *bitmap, uint64_t start); #endif diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index 81e78043d1..6b6490ecad 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -292,6 +292,14 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first); */ unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi); +/* hbitmap_next_zero: + * @hb: The HBitmap to operate on + * @start: The bit to start from. + * + * Find next not dirty bit. + */ +int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start); + /* hbitmap_create_meta: * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap. * The caller owns the created bitmap and must call hbitmap_free_meta(hb) to diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c index af41642346..9091c639b3 100644 --- a/tests/test-hbitmap.c +++ b/tests/test-hbitmap.c @@ -925,6 +925,61 @@ static void test_hbitmap_iter_and_reset(TestHBitmapData *data, hbitmap_iter_next(&hbi); } +static void test_hbitmap_next_zero_check(TestHBitmapData *data, int64_t start) +{ + int64_t ret1 = hbitmap_next_zero(data->hb, start); + int64_t ret2 = start; + for ( ; ret2 < data->size && hbitmap_get(data->hb, ret2); ret2++) { + ; + } + if (ret2 == data->size) { + ret2 = -1; + } + + g_assert_cmpint(ret1, ==, ret2); +} + +static void test_hbitmap_next_zero_do(TestHBitmapData *data, int granularity) +{ + hbitmap_test_init(data, L3, granularity); + test_hbitmap_next_zero_check(data, 0); + test_hbitmap_next_zero_check(data, L3 - 1); + + hbitmap_set(data->hb, L2, 1); + test_hbitmap_next_zero_check(data, 0); + test_hbitmap_next_zero_check(data, L2 - 1); + test_hbitmap_next_zero_check(data, L2); + test_hbitmap_next_zero_check(data, L2 + 1); + + hbitmap_set(data->hb, L2 + 5, L1); + test_hbitmap_next_zero_check(data, 0); + test_hbitmap_next_zero_check(data, L2 + 1); + test_hbitmap_next_zero_check(data, L2 + 2); + test_hbitmap_next_zero_check(data, L2 + 5); + test_hbitmap_next_zero_check(data, L2 + L1 - 1); + test_hbitmap_next_zero_check(data, L2 + L1); + + hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2); + test_hbitmap_next_zero_check(data, L2 * 2 - L1); + test_hbitmap_next_zero_check(data, L2 * 2 - 2); + test_hbitmap_next_zero_check(data, L2 * 2 - 1); + test_hbitmap_next_zero_check(data, L2 * 2); + test_hbitmap_next_zero_check(data, L3 - 1); + + hbitmap_set(data->hb, 0, L3); + test_hbitmap_next_zero_check(data, 0); +} + +static void test_hbitmap_next_zero_0(TestHBitmapData *data, const void *unused) +{ + test_hbitmap_next_zero_do(data, 0); +} + +static void test_hbitmap_next_zero_4(TestHBitmapData *data, const void *unused) +{ + test_hbitmap_next_zero_do(data, 4); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -985,6 +1040,12 @@ int main(int argc, char **argv) hbitmap_test_add("/hbitmap/iter/iter_and_reset", test_hbitmap_iter_and_reset); + + hbitmap_test_add("/hbitmap/next_zero/next_zero_0", + test_hbitmap_next_zero_0); + hbitmap_test_add("/hbitmap/next_zero/next_zero_4", + test_hbitmap_next_zero_4); + g_test_run(); return 0; diff --git a/util/hbitmap.c b/util/hbitmap.c index 2f9d0fdbd0..289778a55c 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -188,6 +188,45 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first) } } +int64_t hbitmap_next_zero(const HBitmap *hb, uint64_t start) +{ + size_t pos = (start >> hb->granularity) >> BITS_PER_LEVEL; + unsigned long *last_lev = hb->levels[HBITMAP_LEVELS - 1]; + uint64_t sz = hb->sizes[HBITMAP_LEVELS - 1]; + unsigned long cur = last_lev[pos]; + unsigned start_bit_offset = + (start >> hb->granularity) & (BITS_PER_LONG - 1); + int64_t res; + + cur |= (1UL << start_bit_offset) - 1; + assert((start >> hb->granularity) < hb->size); + + if (cur == (unsigned long)-1) { + do { + pos++; + } while (pos < sz && last_lev[pos] == (unsigned long)-1); + + if (pos >= sz) { + return -1; + } + + cur = last_lev[pos]; + } + + res = (pos << BITS_PER_LEVEL) + ctol(cur); + if (res >= hb->size) { + return -1; + } + + res = res << hb->granularity; + if (res < start) { + assert(((start - res) >> hb->granularity) == 0); + return start; + } + + return res; +} + bool hbitmap_empty(const HBitmap *hb) { return hb->count == 0; From a193b0f0a8d7735f4eb2ff863fd0902a5fa5eec6 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 12 Oct 2017 16:53:10 +0300 Subject: [PATCH 229/546] backup: move from done_bitmap to copy_bitmap Use HBitmap copy_bitmap instead of done_bitmap. This is needed to improve incremental backup in following patches and to unify backup loop for full/incremental modes in future patches. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Jeff Cody Reviewed-by: Stefan Hajnoczi Reviewed-by: John Snow Message-id: 20171012135313.227864-3-vsementsov@virtuozzo.com Signed-off-by: Jeff Cody --- block/backup.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/block/backup.c b/block/backup.c index 99e6bcc748..5175808093 100644 --- a/block/backup.c +++ b/block/backup.c @@ -40,11 +40,12 @@ typedef struct BackupBlockJob { BlockdevOnError on_target_error; CoRwlock flush_rwlock; uint64_t bytes_read; - unsigned long *done_bitmap; int64_t cluster_size; bool compress; NotifierWithReturn before_write; QLIST_HEAD(, CowRequest) inflight_reqs; + + HBitmap *copy_bitmap; } BackupBlockJob; /* See if in-flight requests overlap and wait for them to complete */ @@ -109,10 +110,11 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, cow_request_begin(&cow_request, job, start, end); for (; start < end; start += job->cluster_size) { - if (test_bit(start / job->cluster_size, job->done_bitmap)) { + if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) { trace_backup_do_cow_skip(job, start); continue; /* already copied */ } + hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1); trace_backup_do_cow_process(job, start); @@ -132,6 +134,7 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, if (error_is_read) { *error_is_read = true; } + hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1); goto out; } @@ -148,11 +151,10 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job, if (error_is_read) { *error_is_read = false; } + hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1); goto out; } - set_bit(start / job->cluster_size, job->done_bitmap); - /* Publish progress, guest I/O counts as progress too. Note that the * offset field is an opaque progress value, it is not a disk offset. */ @@ -260,7 +262,7 @@ void backup_do_checkpoint(BlockJob *job, Error **errp) } len = DIV_ROUND_UP(backup_job->common.len, backup_job->cluster_size); - bitmap_zero(backup_job->done_bitmap, len); + hbitmap_set(backup_job->copy_bitmap, 0, len); } void backup_wait_for_overlapping_requests(BlockJob *job, int64_t offset, @@ -425,19 +427,22 @@ static void coroutine_fn backup_run(void *opaque) BackupBlockJob *job = opaque; BackupCompleteData *data; BlockDriverState *bs = blk_bs(job->common.blk); - int64_t offset; + int64_t offset, nb_clusters; int ret = 0; QLIST_INIT(&job->inflight_reqs); qemu_co_rwlock_init(&job->flush_rwlock); - job->done_bitmap = bitmap_new(DIV_ROUND_UP(job->common.len, - job->cluster_size)); + nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size); + job->copy_bitmap = hbitmap_alloc(nb_clusters, 0); + hbitmap_set(job->copy_bitmap, 0, nb_clusters); job->before_write.notify = backup_before_write_notify; bdrv_add_before_write_notifier(bs, &job->before_write); if (job->sync_mode == MIRROR_SYNC_MODE_NONE) { + /* All bits are set in copy_bitmap to allow any cluster to be copied. + * This does not actually require them to be copied. */ while (!block_job_is_cancelled(&job->common)) { /* Yield until the job is cancelled. We just let our before_write * notify callback service CoW requests. */ @@ -512,7 +517,7 @@ static void coroutine_fn backup_run(void *opaque) /* wait until pending backup_do_cow() calls have completed */ qemu_co_rwlock_wrlock(&job->flush_rwlock); qemu_co_rwlock_unlock(&job->flush_rwlock); - g_free(job->done_bitmap); + hbitmap_free(job->copy_bitmap); data = g_malloc(sizeof(*data)); data->ret = ret; From 8cc6dc6215fa2a278fd853a2caca172e43c6263e Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 12 Oct 2017 16:53:11 +0300 Subject: [PATCH 230/546] backup: init copy_bitmap from sync_bitmap for incremental We should not copy non-dirty clusters in write notifiers. So, initialize copy_bitmap from sync_bitmap. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Jeff Cody Reviewed-by: Stefan Hajnoczi Message-id: 20171012135313.227864-4-vsementsov@virtuozzo.com Signed-off-by: Jeff Cody --- block/backup.c | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/block/backup.c b/block/backup.c index 5175808093..b8901ea662 100644 --- a/block/backup.c +++ b/block/backup.c @@ -422,6 +422,43 @@ out: return ret; } +/* init copy_bitmap from sync_bitmap */ +static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) +{ + BdrvDirtyBitmapIter *dbi; + int64_t offset; + int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap), + job->cluster_size); + + dbi = bdrv_dirty_iter_new(job->sync_bitmap); + while ((offset = bdrv_dirty_iter_next(dbi)) != -1) { + int64_t cluster = offset / job->cluster_size; + int64_t next_cluster; + + offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap); + if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) { + hbitmap_set(job->copy_bitmap, cluster, end - cluster); + break; + } + + offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset); + if (offset == -1) { + hbitmap_set(job->copy_bitmap, cluster, end - cluster); + break; + } + + next_cluster = DIV_ROUND_UP(offset, job->cluster_size); + hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster); + if (next_cluster >= end) { + break; + } + + bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size); + } + + bdrv_dirty_iter_free(dbi); +} + static void coroutine_fn backup_run(void *opaque) { BackupBlockJob *job = opaque; @@ -435,7 +472,12 @@ static void coroutine_fn backup_run(void *opaque) nb_clusters = DIV_ROUND_UP(job->common.len, job->cluster_size); job->copy_bitmap = hbitmap_alloc(nb_clusters, 0); - hbitmap_set(job->copy_bitmap, 0, nb_clusters); + if (job->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) { + backup_incremental_init_copy_bitmap(job); + } else { + hbitmap_set(job->copy_bitmap, 0, nb_clusters); + } + job->before_write.notify = backup_before_write_notify; bdrv_add_before_write_notifier(bs, &job->before_write); From 085bd08e6f32f0d96885ff8e0fa2896c2fabed50 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 12 Oct 2017 16:53:12 +0300 Subject: [PATCH 231/546] backup: simplify non-dirty bits progress processing Set fake progress for non-dirty clusters in copy_bitmap initialization, to. It simplifies code and allows further refactoring. This patch changes user's view of backup progress, but formally it doesn't changed: progress hops are just moved to the beginning. Actually it's just a point of view: when do we actually skip clusters? We can say in the very beginning, that we skip these clusters and do not think about them later. Of course, if go through disk sequentially, it's logical to say, that we skip clusters between copied portions to the left and to the right of them. But even now copying progress is not sequential because of write notifiers. Future patches will introduce new backup architecture which will do copying in several coroutines in parallel, so it will make no sense to publish fake progress by parts in parallel with other copying requests. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: John Snow Reviewed-by: Stefan Hajnoczi Reviewed-by: Jeff Cody Message-id: 20171012135313.227864-5-vsementsov@virtuozzo.com Signed-off-by: Jeff Cody --- block/backup.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/block/backup.c b/block/backup.c index b8901ea662..8ee220076b 100644 --- a/block/backup.c +++ b/block/backup.c @@ -369,7 +369,6 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) int64_t offset; int64_t cluster; int64_t end; - int64_t last_cluster = -1; BdrvDirtyBitmapIter *dbi; granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap); @@ -380,12 +379,6 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) { cluster = offset / job->cluster_size; - /* Fake progress updates for any clusters we skipped */ - if (cluster != last_cluster + 1) { - job->common.offset += ((cluster - last_cluster - 1) * - job->cluster_size); - } - for (end = cluster + clusters_per_iter; cluster < end; cluster++) { do { if (yield_and_check(job)) { @@ -407,14 +400,6 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job) if (granularity < job->cluster_size) { bdrv_set_dirty_iter(dbi, cluster * job->cluster_size); } - - last_cluster = cluster - 1; - } - - /* Play some final catchup with the progress meter */ - end = DIV_ROUND_UP(job->common.len, job->cluster_size); - if (last_cluster + 1 < end) { - job->common.offset += ((end - last_cluster - 1) * job->cluster_size); } out: @@ -456,6 +441,9 @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job) bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size); } + job->common.offset = job->common.len - + hbitmap_count(job->copy_bitmap) * job->cluster_size; + bdrv_dirty_iter_free(dbi); } From 53f1c8794f2c1aea4d2888a3ac4e1b3b8b8b9777 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 12 Oct 2017 16:53:13 +0300 Subject: [PATCH 232/546] backup: use copy_bitmap in incremental backup We can use copy_bitmap instead of sync_bitmap. copy_bitmap is initialized from sync_bitmap and it is more informative: we will not try to process data, that is already in progress (by write notifier). Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Stefan Hajnoczi Reviewed-by: John Snow Reviewed-by: Jeff Cody Message-id: 20171012135313.227864-6-vsementsov@virtuozzo.com Signed-off-by: Jeff Cody --- block/backup.c | 55 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/block/backup.c b/block/backup.c index 8ee220076b..4a16a37229 100644 --- a/block/backup.c +++ b/block/backup.c @@ -362,49 +362,28 @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job) static int coroutine_fn backup_run_incremental(BackupBlockJob *job) { + int ret; bool error_is_read; - int ret = 0; - int clusters_per_iter; - uint32_t granularity; - int64_t offset; int64_t cluster; - int64_t end; - BdrvDirtyBitmapIter *dbi; + HBitmapIter hbi; - granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap); - clusters_per_iter = MAX((granularity / job->cluster_size), 1); - dbi = bdrv_dirty_iter_new(job->sync_bitmap); - - /* Find the next dirty sector(s) */ - while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) { - cluster = offset / job->cluster_size; - - for (end = cluster + clusters_per_iter; cluster < end; cluster++) { - do { - if (yield_and_check(job)) { - goto out; - } - ret = backup_do_cow(job, cluster * job->cluster_size, - job->cluster_size, &error_is_read, - false); - if ((ret < 0) && - backup_error_action(job, error_is_read, -ret) == - BLOCK_ERROR_ACTION_REPORT) { - goto out; - } - } while (ret < 0); - } - - /* If the bitmap granularity is smaller than the backup granularity, - * we need to advance the iterator pointer to the next cluster. */ - if (granularity < job->cluster_size) { - bdrv_set_dirty_iter(dbi, cluster * job->cluster_size); - } + hbitmap_iter_init(&hbi, job->copy_bitmap, 0); + while ((cluster = hbitmap_iter_next(&hbi)) != -1) { + do { + if (yield_and_check(job)) { + return 0; + } + ret = backup_do_cow(job, cluster * job->cluster_size, + job->cluster_size, &error_is_read, false); + if (ret < 0 && backup_error_action(job, error_is_read, -ret) == + BLOCK_ERROR_ACTION_REPORT) + { + return ret; + } + } while (ret < 0); } -out: - bdrv_dirty_iter_free(dbi); - return ret; + return 0; } /* init copy_bitmap from sync_bitmap */ From aa9ef2e65bed6a8f1709e0523fc856ec08beb657 Mon Sep 17 00:00:00 2001 From: John Snow Date: Wed, 13 Dec 2017 15:46:11 -0500 Subject: [PATCH 233/546] blockjob: kick jobs on set-speed If users set an unreasonably low speed (like one byte per second), the calculated delay may exceed many hours. While we like to punish users for asking for stupid things, we do also like to allow users to correct their wicked ways. When a user provides a new speed, kick the job to allow it to recalculate its delay. Signed-off-by: John Snow Reviewed-by: Stefan Hajnoczi Message-id: 20171213204611.26276-1-jsnow@redhat.com Signed-off-by: Jeff Cody --- blockjob.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/blockjob.c b/blockjob.c index 715c2c2680..6173e4728c 100644 --- a/blockjob.c +++ b/blockjob.c @@ -59,6 +59,7 @@ static void __attribute__((__constructor__)) block_job_init(void) static void block_job_event_cancelled(BlockJob *job); static void block_job_event_completed(BlockJob *job, const char *msg); +static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)); /* Transactional group of block jobs */ struct BlockJobTxn { @@ -480,9 +481,16 @@ static void block_job_completed_txn_success(BlockJob *job) } } +/* Assumes the block_job_mutex is held */ +static bool block_job_timer_pending(BlockJob *job) +{ + return timer_pending(&job->sleep_timer); +} + void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) { Error *local_err = NULL; + int64_t old_speed = job->speed; if (!job->driver->set_speed) { error_setg(errp, QERR_UNSUPPORTED); @@ -495,6 +503,12 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp) } job->speed = speed; + if (speed <= old_speed) { + return; + } + + /* kick only if a timer is pending */ + block_job_enter_cond(job, block_job_timer_pending); } void block_job_complete(BlockJob *job, Error **errp) @@ -821,7 +835,11 @@ void block_job_resume_all(void) } } -void block_job_enter(BlockJob *job) +/* + * Conditionally enter a block_job pending a call to fn() while + * under the block_job_lock critical section. + */ +static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job)) { if (!block_job_started(job)) { return; @@ -836,6 +854,11 @@ void block_job_enter(BlockJob *job) return; } + if (fn && !fn(job)) { + block_job_unlock(); + return; + } + assert(!job->deferred_to_main_loop); timer_del(&job->sleep_timer); job->busy = true; @@ -843,6 +866,11 @@ void block_job_enter(BlockJob *job) aio_co_wake(job->co); } +void block_job_enter(BlockJob *job) +{ + block_job_enter_cond(job, NULL); +} + bool block_job_is_cancelled(BlockJob *job) { return job->cancelled; From ac90dad94b5b1eda18a9a86c739c249d851cd35c Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 7 Nov 2017 17:27:20 -0500 Subject: [PATCH 234/546] block/sheepdog: remove spurious NULL check 'tag' is already checked in the lines immediately preceding this check, and set to non-NULL if NULL. No need to check again, it hasn't changed. Signed-off-by: Jeff Cody Reviewed-by: Eric Blake Reviewed-by: Darren Kenny Signed-off-by: Jeff Cody --- block/sheepdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 696a71442a..459d93a35f 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1632,7 +1632,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags, if (!tag) { tag = ""; } - if (tag && strlen(tag) >= SD_MAX_VDI_TAG_LEN) { + if (strlen(tag) >= SD_MAX_VDI_TAG_LEN) { error_setg(errp, "value of parameter 'tag' is too long"); ret = -EINVAL; goto err_no_fd; From d507c5f682d23a60a356a081557ceb34ea0d2669 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 7 Nov 2017 17:27:21 -0500 Subject: [PATCH 235/546] block/sheepdog: code beautification No functional changes, just whitespace manipulation. Signed-off-by: Jeff Cody Reviewed-by: Eric Blake Reviewed-by: Darren Kenny Signed-off-by: Jeff Cody --- block/sheepdog.c | 164 +++++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 459d93a35f..488bad333b 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -400,7 +400,7 @@ typedef struct BDRVSheepdogReopenState { int cache_flags; } BDRVSheepdogReopenState; -static const char * sd_strerror(int err) +static const char *sd_strerror(int err) { int i; @@ -3078,111 +3078,111 @@ static QemuOptsList sd_create_opts = { }; static BlockDriver bdrv_sheepdog = { - .format_name = "sheepdog", - .protocol_name = "sheepdog", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_create = sd_create, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, + .format_name = "sheepdog", + .protocol_name = "sheepdog", + .instance_size = sizeof(BDRVSheepdogState), + .bdrv_parse_filename = sd_parse_filename, + .bdrv_file_open = sd_open, + .bdrv_reopen_prepare = sd_reopen_prepare, + .bdrv_reopen_commit = sd_reopen_commit, + .bdrv_reopen_abort = sd_reopen_abort, + .bdrv_close = sd_close, + .bdrv_create = sd_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_truncate = sd_truncate, + .bdrv_truncate = sd_truncate, - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_get_block_status = sd_co_get_block_status, + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, + .bdrv_co_flush_to_disk = sd_co_flush_to_disk, + .bdrv_co_pdiscard = sd_co_pdiscard, + .bdrv_co_get_block_status = sd_co_get_block_status, - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, + .bdrv_snapshot_create = sd_snapshot_create, + .bdrv_snapshot_goto = sd_snapshot_goto, + .bdrv_snapshot_delete = sd_snapshot_delete, + .bdrv_snapshot_list = sd_snapshot_list, - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, + .bdrv_save_vmstate = sd_save_vmstate, + .bdrv_load_vmstate = sd_load_vmstate, - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, + .bdrv_detach_aio_context = sd_detach_aio_context, + .bdrv_attach_aio_context = sd_attach_aio_context, - .create_opts = &sd_create_opts, + .create_opts = &sd_create_opts, }; static BlockDriver bdrv_sheepdog_tcp = { - .format_name = "sheepdog", - .protocol_name = "sheepdog+tcp", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_create = sd_create, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, + .format_name = "sheepdog", + .protocol_name = "sheepdog+tcp", + .instance_size = sizeof(BDRVSheepdogState), + .bdrv_parse_filename = sd_parse_filename, + .bdrv_file_open = sd_open, + .bdrv_reopen_prepare = sd_reopen_prepare, + .bdrv_reopen_commit = sd_reopen_commit, + .bdrv_reopen_abort = sd_reopen_abort, + .bdrv_close = sd_close, + .bdrv_create = sd_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_truncate = sd_truncate, + .bdrv_truncate = sd_truncate, - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_get_block_status = sd_co_get_block_status, + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, + .bdrv_co_flush_to_disk = sd_co_flush_to_disk, + .bdrv_co_pdiscard = sd_co_pdiscard, + .bdrv_co_get_block_status = sd_co_get_block_status, - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, + .bdrv_snapshot_create = sd_snapshot_create, + .bdrv_snapshot_goto = sd_snapshot_goto, + .bdrv_snapshot_delete = sd_snapshot_delete, + .bdrv_snapshot_list = sd_snapshot_list, - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, + .bdrv_save_vmstate = sd_save_vmstate, + .bdrv_load_vmstate = sd_load_vmstate, - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, + .bdrv_detach_aio_context = sd_detach_aio_context, + .bdrv_attach_aio_context = sd_attach_aio_context, - .create_opts = &sd_create_opts, + .create_opts = &sd_create_opts, }; static BlockDriver bdrv_sheepdog_unix = { - .format_name = "sheepdog", - .protocol_name = "sheepdog+unix", - .instance_size = sizeof(BDRVSheepdogState), - .bdrv_parse_filename = sd_parse_filename, - .bdrv_file_open = sd_open, - .bdrv_reopen_prepare = sd_reopen_prepare, - .bdrv_reopen_commit = sd_reopen_commit, - .bdrv_reopen_abort = sd_reopen_abort, - .bdrv_close = sd_close, - .bdrv_create = sd_create, - .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_getlength = sd_getlength, + .format_name = "sheepdog", + .protocol_name = "sheepdog+unix", + .instance_size = sizeof(BDRVSheepdogState), + .bdrv_parse_filename = sd_parse_filename, + .bdrv_file_open = sd_open, + .bdrv_reopen_prepare = sd_reopen_prepare, + .bdrv_reopen_commit = sd_reopen_commit, + .bdrv_reopen_abort = sd_reopen_abort, + .bdrv_close = sd_close, + .bdrv_create = sd_create, + .bdrv_has_zero_init = bdrv_has_zero_init_1, + .bdrv_getlength = sd_getlength, .bdrv_get_allocated_file_size = sd_get_allocated_file_size, - .bdrv_truncate = sd_truncate, + .bdrv_truncate = sd_truncate, - .bdrv_co_readv = sd_co_readv, - .bdrv_co_writev = sd_co_writev, - .bdrv_co_flush_to_disk = sd_co_flush_to_disk, - .bdrv_co_pdiscard = sd_co_pdiscard, - .bdrv_co_get_block_status = sd_co_get_block_status, + .bdrv_co_readv = sd_co_readv, + .bdrv_co_writev = sd_co_writev, + .bdrv_co_flush_to_disk = sd_co_flush_to_disk, + .bdrv_co_pdiscard = sd_co_pdiscard, + .bdrv_co_get_block_status = sd_co_get_block_status, - .bdrv_snapshot_create = sd_snapshot_create, - .bdrv_snapshot_goto = sd_snapshot_goto, - .bdrv_snapshot_delete = sd_snapshot_delete, - .bdrv_snapshot_list = sd_snapshot_list, + .bdrv_snapshot_create = sd_snapshot_create, + .bdrv_snapshot_goto = sd_snapshot_goto, + .bdrv_snapshot_delete = sd_snapshot_delete, + .bdrv_snapshot_list = sd_snapshot_list, - .bdrv_save_vmstate = sd_save_vmstate, - .bdrv_load_vmstate = sd_load_vmstate, + .bdrv_save_vmstate = sd_save_vmstate, + .bdrv_load_vmstate = sd_load_vmstate, - .bdrv_detach_aio_context = sd_detach_aio_context, - .bdrv_attach_aio_context = sd_attach_aio_context, + .bdrv_detach_aio_context = sd_detach_aio_context, + .bdrv_attach_aio_context = sd_attach_aio_context, - .create_opts = &sd_create_opts, + .create_opts = &sd_create_opts, }; static void bdrv_sheepdog_init(void) From 2d25964d1831c99d54981e8b615eba5dd6a63e36 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 7 Nov 2017 17:27:22 -0500 Subject: [PATCH 236/546] block/curl: check error return of curl_global_init() If curl_global_init() fails, per the documentation no other curl functions may be called, so make sure to check the return value. Also, some minor changes to the initialization latch variable 'inited': - Make it static in the file, for clarity - Change the name for clarity - Make it a bool Signed-off-by: Jeff Cody Reviewed-by: Eric Blake Reviewed-by: Richard W.M. Jones Reviewed-by: Darren Kenny Signed-off-by: Jeff Cody --- block/curl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/block/curl.c b/block/curl.c index 2a244e2439..00a98799b6 100644 --- a/block/curl.c +++ b/block/curl.c @@ -89,6 +89,8 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, struct BDRVCURLState; +static bool libcurl_initialized; + typedef struct CURLAIOCB { Coroutine *co; QEMUIOVector *qiov; @@ -686,14 +688,23 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, double d; const char *secretid; const char *protocol_delimiter; + int ret; - static int inited = 0; if (flags & BDRV_O_RDWR) { error_setg(errp, "curl block device does not support writes"); return -EROFS; } + if (!libcurl_initialized) { + ret = curl_global_init(CURL_GLOBAL_ALL); + if (ret) { + error_setg(errp, "libcurl initialization failed with %d", ret); + return -EIO; + } + libcurl_initialized = true; + } + qemu_mutex_init(&s->mutex); opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort); qemu_opts_absorb_qdict(opts, options, &local_err); @@ -772,11 +783,6 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } } - if (!inited) { - curl_global_init(CURL_GLOBAL_ALL); - inited = 1; - } - DPRINTF("CURL: Opening %s\n", file); QSIMPLEQ_INIT(&s->free_state_waitq); s->aio_context = bdrv_get_aio_context(bs); From 996922de45299878cdc4c15b72b19edf2bc618a4 Mon Sep 17 00:00:00 2001 From: Jeff Cody Date: Tue, 7 Nov 2017 17:27:23 -0500 Subject: [PATCH 237/546] block/curl: fix minor memory leaks Signed-off-by: Jeff Cody Reviewed-by: Richard W.M. Jones Signed-off-by: Jeff Cody --- block/curl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block/curl.c b/block/curl.c index 00a98799b6..35cf417f59 100644 --- a/block/curl.c +++ b/block/curl.c @@ -857,6 +857,9 @@ out_noclean: qemu_mutex_destroy(&s->mutex); g_free(s->cookie); g_free(s->url); + g_free(s->username); + g_free(s->proxyusername); + g_free(s->proxypassword); qemu_opts_del(opts); return -EINVAL; } @@ -955,6 +958,9 @@ static void curl_close(BlockDriverState *bs) g_free(s->cookie); g_free(s->url); + g_free(s->username); + g_free(s->proxyusername); + g_free(s->proxypassword); } static int64_t curl_getlength(BlockDriverState *bs) From e691e0ed135ac989221683ca9560c34d357edc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 5 Dec 2017 14:00:13 -0300 Subject: [PATCH 238/546] target/sh4: add missing tcg_temp_free() in _decode_opc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit missed in c55497ecb8c and 852d481faf7. Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20171205170013.22337-3-f4bug@amsat.org> Reviewed-by: Aurelien Jarno Signed-off-by: Aurelien Jarno --- target/sh4/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 8569179883..f56808b45d 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -601,6 +601,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_subi_i32(addr, REG(B11_8), 4); tcg_gen_qemu_st_i32(REG(B7_4), addr, ctx->memidx, MO_TEUL); tcg_gen_mov_i32(REG(B11_8), addr); + tcg_temp_free(addr); } return; case 0x6004: /* mov.b @Rm+,Rn */ @@ -1524,6 +1525,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_qemu_ld_i32(val, REG(B11_8), ctx->memidx, MO_TEUL); gen_helper_movcal(cpu_env, REG(B11_8), val); tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); + tcg_temp_free(val); } ctx->has_movcal = 1; return; From 6d56fc6cc372284a4571f09b361a9ccd99318103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 6 Dec 2017 09:30:50 +0000 Subject: [PATCH 239/546] target/sh4: fix TCG leak during gusa sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes bug #1735384 while running java under qemu-sh4. When debug was enabled it showed a problem with TCG temps. Once fixed I was able to run java -version normally. Cc: qemu-stable@nongnu.org Reported-by: John Paul Adrian Glaubitz Suggested-by: Richard Henderson Signed-off-by: Alex Bennée Message-Id: <20171206093050.25308-1-alex.bennee@linaro.org> Reviewed-by: Richard Henderson Reviewed-by: Aurelien Jarno Signed-off-by: Aurelien Jarno --- target/sh4/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index f56808b45d..4a4a5c877e 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -2191,7 +2191,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) } /* If op_src is not a valid register, then op_arg was a constant. */ - if (op_src < 0) { + if (op_src < 0 && !TCGV_IS_UNUSED(op_arg)) { tcg_temp_free_i32(op_arg); } From f85da3081d001909929a19e530e69cea0487f00e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 Sep 2017 11:50:53 -0700 Subject: [PATCH 240/546] target/sh4: Use cmpxchg for movco when parallel_cpus As for other targets, cmpxchg isn't quite right for ll/sc, suffering from an ABA race, but is sufficient to implement portable atomic operations. Signed-off-by: Richard Henderson Message-Id: <20170907185057.23421-2-richard.henderson@linaro.org> [aurel32: fix whitespace] Signed-off-by: Aurelien Jarno --- linux-user/main.c | 19 +++++++--- target/sh4/cpu.h | 4 ++- target/sh4/helper.c | 1 + target/sh4/translate.c | 82 ++++++++++++++++++++++++++++++------------ 4 files changed, 79 insertions(+), 27 deletions(-) diff --git a/linux-user/main.c b/linux-user/main.c index 2fd2a143ed..71696ed33d 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2679,6 +2679,8 @@ void cpu_loop(CPUSH4State *env) target_siginfo_t info; while (1) { + bool arch_interrupt = true; + cpu_exec_start(cs); trapnr = cpu_exec(cs); cpu_exec_end(cs); @@ -2710,13 +2712,14 @@ void cpu_loop(CPUSH4State *env) int sig; sig = gdb_handlesig(cs, TARGET_SIGTRAP); - if (sig) - { + if (sig) { info.si_signo = sig; info.si_errno = 0; info.si_code = TARGET_TRAP_BRKPT; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } + } else { + arch_interrupt = false; + } } break; case 0xa0: @@ -2727,9 +2730,9 @@ void cpu_loop(CPUSH4State *env) info._sifields._sigfault._addr = env->tea; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; - case EXCP_ATOMIC: cpu_exec_step_atomic(cs); + arch_interrupt = false; break; default: printf ("Unhandled trap: 0x%x\n", trapnr); @@ -2737,6 +2740,14 @@ void cpu_loop(CPUSH4State *env) exit(EXIT_FAILURE); } process_pending_signals (env); + + /* Most of the traps imply an exception or interrupt, which + implies an REI instruction has been executed. Which means + that LDST (aka LOK_ADDR) should be cleared. But there are + a few exceptions for traps internal to QEMU. */ + if (arch_interrupt) { + env->lock_addr = -1; + } } } #endif diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 960b46870d..a2c26e0597 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -188,7 +188,9 @@ typedef struct CPUSH4State { tlb_t itlb[ITLB_SIZE]; /* instruction translation table */ tlb_t utlb[UTLB_SIZE]; /* unified translation table */ - uint32_t ldst; + /* LDST = LOCK_ADDR != -1. */ + uint32_t lock_addr; + uint32_t lock_value; /* Fields up to this point are cleared by a CPU reset */ struct {} end_reset_fields; diff --git a/target/sh4/helper.c b/target/sh4/helper.c index 28d93c2543..680b583e53 100644 --- a/target/sh4/helper.c +++ b/target/sh4/helper.c @@ -171,6 +171,7 @@ void superh_cpu_do_interrupt(CPUState *cs) env->spc = env->pc; env->sgr = env->gregs[15]; env->sr |= (1u << SR_BL) | (1u << SR_MD) | (1u << SR_RB); + env->lock_addr = -1; if (env->flags & DELAY_SLOT_MASK) { /* Branch instruction should be executed again before delay slot. */ diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 4a4a5c877e..f7fe1a46d8 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -69,7 +69,8 @@ static TCGv cpu_gregs[32]; static TCGv cpu_sr, cpu_sr_m, cpu_sr_q, cpu_sr_t; static TCGv cpu_pc, cpu_ssr, cpu_spc, cpu_gbr; static TCGv cpu_vbr, cpu_sgr, cpu_dbr, cpu_mach, cpu_macl; -static TCGv cpu_pr, cpu_fpscr, cpu_fpul, cpu_ldst; +static TCGv cpu_pr, cpu_fpscr, cpu_fpul; +static TCGv cpu_lock_addr, cpu_lock_value; static TCGv cpu_fregs[32]; /* internal register indexes */ @@ -147,8 +148,12 @@ void sh4_translate_init(void) offsetof(CPUSH4State, delayed_cond), "_delayed_cond_"); - cpu_ldst = tcg_global_mem_new_i32(cpu_env, - offsetof(CPUSH4State, ldst), "_ldst_"); + cpu_lock_addr = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUSH4State, lock_addr), + "_lock_addr_"); + cpu_lock_value = tcg_global_mem_new_i32(cpu_env, + offsetof(CPUSH4State, lock_value), + "_lock_value_"); for (i = 0; i < 32; i++) cpu_fregs[i] = tcg_global_mem_new_i32(cpu_env, @@ -1549,31 +1554,64 @@ static void _decode_opc(DisasContext * ctx) return; case 0x0073: /* MOVCO.L - LDST -> T - If (T == 1) R0 -> (Rn) - 0 -> LDST - */ + * LDST -> T + * If (T == 1) R0 -> (Rn) + * 0 -> LDST + * + * The above description doesn't work in a parallel context. + * Since we currently support no smp boards, this implies user-mode. + * But we can still support the official mechanism while user-mode + * is single-threaded. */ CHECK_SH4A { - TCGLabel *label = gen_new_label(); - tcg_gen_mov_i32(cpu_sr_t, cpu_ldst); - tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ldst, 0, label); - tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); - gen_set_label(label); - tcg_gen_movi_i32(cpu_ldst, 0); - return; + TCGLabel *fail = gen_new_label(); + TCGLabel *done = gen_new_label(); + + if ((tb_cflags(ctx->tb) & CF_PARALLEL)) { + TCGv tmp; + + tcg_gen_brcond_i32(TCG_COND_NE, REG(B11_8), + cpu_lock_addr, fail); + tmp = tcg_temp_new(); + tcg_gen_atomic_cmpxchg_i32(tmp, REG(B11_8), cpu_lock_value, + REG(0), ctx->memidx, MO_TEUL); + tcg_gen_setcond_i32(TCG_COND_EQ, cpu_sr_t, tmp, cpu_lock_value); + tcg_temp_free(tmp); + } else { + tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_lock_addr, -1, fail); + tcg_gen_qemu_st_i32(REG(0), REG(B11_8), ctx->memidx, MO_TEUL); + tcg_gen_movi_i32(cpu_sr_t, 1); + } + tcg_gen_br(done); + + gen_set_label(fail); + tcg_gen_movi_i32(cpu_sr_t, 0); + + gen_set_label(done); + tcg_gen_movi_i32(cpu_lock_addr, -1); } + return; case 0x0063: /* MOVLI.L @Rm,R0 - 1 -> LDST - (Rm) -> R0 - When interrupt/exception - occurred 0 -> LDST - */ + * 1 -> LDST + * (Rm) -> R0 + * When interrupt/exception + * occurred 0 -> LDST + * + * In a parallel context, we must also save the loaded value + * for use with the cmpxchg that we'll use with movco.l. */ CHECK_SH4A - tcg_gen_movi_i32(cpu_ldst, 0); - tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL); - tcg_gen_movi_i32(cpu_ldst, 1); + if ((tb_cflags(ctx->tb) & CF_PARALLEL)) { + TCGv tmp = tcg_temp_new(); + tcg_gen_mov_i32(tmp, REG(B11_8)); + tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL); + tcg_gen_mov_i32(cpu_lock_value, REG(0)); + tcg_gen_mov_i32(cpu_lock_addr, tmp); + tcg_temp_free(tmp); + } else { + tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL); + tcg_gen_movi_i32(cpu_lock_addr, 0); + } return; case 0x0093: /* ocbi @Rn */ { From 4834871bc95b67343248100e2a75ae0d287bc08b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 Sep 2017 11:50:54 -0700 Subject: [PATCH 241/546] target/sh4: Convert to DisasJumpType Signed-off-by: Richard Henderson Message-Id: <20170907185057.23421-3-richard.henderson@linaro.org> [aurel32: fix whitespace] Signed-off-by: Aurelien Jarno --- target/sh4/translate.c | 65 +++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index f7fe1a46d8..efd1081c57 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -25,10 +25,9 @@ #include "exec/exec-all.h" #include "tcg-op.h" #include "exec/cpu_ldst.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" - +#include "exec/translator.h" #include "trace-tcg.h" #include "exec/log.h" @@ -39,7 +38,7 @@ typedef struct DisasContext { uint16_t opcode; uint32_t tbflags; /* should stay unmodified during the TB translation */ uint32_t envflags; /* should stay in sync with env->flags using TCG ops */ - int bstate; + DisasJumpType bstate; int memidx; int gbank; int fbank; @@ -55,14 +54,10 @@ typedef struct DisasContext { #define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD))) #endif -enum { - BS_NONE = 0, /* We go out of the TB without reaching a branch or an - * exception condition - */ - BS_STOP = 1, /* We want to stop translation for any reason */ - BS_BRANCH = 2, /* We reached a branch condition */ - BS_EXCP = 3, /* We reached an exception condition */ -}; +/* Target-specific values for ctx->bstate. */ +/* We want to exit back to the cpu loop for some reason. + Usually this is to recognize interrupts immediately. */ +#define DISAS_STOP DISAS_TARGET_0 /* global register indexes */ static TCGv cpu_gregs[32]; @@ -258,6 +253,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) tcg_gen_lookup_and_goto_ptr(); } } + ctx->bstate = DISAS_NORETURN; } static void gen_jump(DisasContext * ctx) @@ -304,7 +300,7 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest, gen_goto_tb(ctx, 0, dest); gen_set_label(l1); gen_goto_tb(ctx, 1, ctx->pc + 2); - ctx->bstate = BS_BRANCH; + ctx->bstate = DISAS_NORETURN; } /* Delayed conditional jump (bt or bf) */ @@ -327,6 +323,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) gen_jump(ctx); gen_set_label(l1); + ctx->bstate = DISAS_NEXT; return; } @@ -468,7 +465,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); ctx->envflags |= DELAY_SLOT_RTE; ctx->delayed_pc = (uint32_t) - 1; - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; return; case 0x0058: /* sets */ tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S)); @@ -479,17 +476,17 @@ static void _decode_opc(DisasContext * ctx) case 0xfbfd: /* frchg */ CHECK_FPSCR_PR_0 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; return; case 0xf3fd: /* fschg */ CHECK_FPSCR_PR_0 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; return; case 0xf7fd: /* fpchg */ CHECK_SH4A tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; return; case 0x0009: /* nop */ return; @@ -524,7 +521,7 @@ static void _decode_opc(DisasContext * ctx) region (stored in R0) in the next TB. */ if (B11_8 == 15 && B7_0s < 0 && (tb_cflags(ctx->tb) & CF_PARALLEL)) { ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; } #endif tcg_gen_movi_i32(REG(B11_8), B7_0s); @@ -1310,7 +1307,7 @@ static void _decode_opc(DisasContext * ctx) imm = tcg_const_i32(B7_0); gen_helper_trapa(cpu_env, imm); tcg_temp_free(imm); - ctx->bstate = BS_EXCP; + ctx->bstate = DISAS_NORETURN; } return; case 0xc800: /* tst #imm,R0 */ @@ -1419,7 +1416,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3); gen_write_sr(val); tcg_temp_free(val); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; } return; case 0x4007: /* ldc.l @Rm+,SR */ @@ -1431,7 +1428,7 @@ static void _decode_opc(DisasContext * ctx) gen_write_sr(val); tcg_temp_free(val); tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; } return; case 0x0002: /* stc SR,Rn */ @@ -1493,7 +1490,7 @@ static void _decode_opc(DisasContext * ctx) case 0x406a: /* lds Rm,FPSCR */ CHECK_FPU_ENABLED gen_helper_ld_fpscr(cpu_env, REG(B11_8)); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; return; case 0x4066: /* lds.l @Rm+,FPSCR */ CHECK_FPU_ENABLED @@ -1503,7 +1500,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); gen_helper_ld_fpscr(cpu_env, addr); tcg_temp_free(addr); - ctx->bstate = BS_STOP; + ctx->bstate = DISAS_STOP; } return; case 0x006a: /* sts FPSCR,Rn */ @@ -1841,7 +1838,7 @@ static void _decode_opc(DisasContext * ctx) gen_save_cpu_state(ctx, true); gen_helper_raise_illegal_instruction(cpu_env); } - ctx->bstate = BS_EXCP; + ctx->bstate = DISAS_NORETURN; return; do_fpu_disabled: @@ -1851,7 +1848,7 @@ static void _decode_opc(DisasContext * ctx) } else { gen_helper_raise_fpu_disable(cpu_env); } - ctx->bstate = BS_EXCP; + ctx->bstate = DISAS_NORETURN; return; } @@ -1877,7 +1874,6 @@ static void decode_opc(DisasContext * ctx) ctx->envflags &= ~GUSA_MASK; tcg_gen_movi_i32(cpu_flags, ctx->envflags); - ctx->bstate = BS_BRANCH; if (old_flags & DELAY_SLOT_CONDITIONAL) { gen_delayed_conditional_jump(ctx); } else { @@ -2248,7 +2244,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) ctx->envflags |= GUSA_EXCLUSIVE; gen_save_cpu_state(ctx, false); gen_helper_exclusive(cpu_env); - ctx->bstate = BS_EXCP; + ctx->bstate = DISAS_NORETURN; /* We're not executing an instruction, but we must report one for the purposes of accounting within the TB. We might as well report the @@ -2271,7 +2267,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.pc = pc_start; ctx.tbflags = (uint32_t)tb->flags; ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK; - ctx.bstate = BS_NONE; + ctx.bstate = DISAS_NEXT; ctx.memidx = (ctx.tbflags & (1u << SR_MD)) == 0 ? 1 : 0; /* We don't know if the delayed pc came from a dynamic or static branch, so assume it is a dynamic branch. */ @@ -2309,7 +2305,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) } #endif - while (ctx.bstate == BS_NONE + while (ctx.bstate == DISAS_NEXT && num_insns < max_insns && !tcg_op_buf_full()) { tcg_gen_insn_start(ctx.pc, ctx.envflags); @@ -2319,7 +2315,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) /* We have hit a breakpoint - make sure PC is up-to-date */ gen_save_cpu_state(&ctx, true); gen_helper_debug(cpu_env); - ctx.bstate = BS_EXCP; + ctx.bstate = DISAS_NORETURN; /* The address covered by the breakpoint must be included in [tb->pc, tb->pc + tb->size) in order to for it to be properly cleared -- thus we increment the PC here so that @@ -2350,19 +2346,18 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) gen_helper_debug(cpu_env); } else { switch (ctx.bstate) { - case BS_STOP: + case DISAS_STOP: gen_save_cpu_state(&ctx, true); tcg_gen_exit_tb(0); break; - case BS_NONE: + case DISAS_NEXT: gen_save_cpu_state(&ctx, false); gen_goto_tb(&ctx, 0, ctx.pc); break; - case BS_EXCP: - /* fall through */ - case BS_BRANCH: - default: + case DISAS_NORETURN: break; + default: + g_assert_not_reached(); } } From 34cf5678088a4a1d624b39ace4f87e704c847d0e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 Sep 2017 11:50:55 -0700 Subject: [PATCH 242/546] target/sh4: Do not singlestep after exceptions If we've already raised an exception (and set NORETURN), do not emit unreachable code to raise a debug exception. Note that gen_goto_tb takes single-stepping into account. Signed-off-by: Richard Henderson Message-Id: <20170907185057.23421-4-richard.henderson@linaro.org> Signed-off-by: Aurelien Jarno --- target/sh4/translate.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index efd1081c57..dd9aaa4e63 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -270,6 +270,7 @@ static void gen_jump(DisasContext * ctx) } else { tcg_gen_lookup_and_goto_ptr(); } + ctx->bstate = DISAS_NORETURN; } else { gen_goto_tb(ctx, 0, ctx->delayed_pc); } @@ -2341,24 +2342,23 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.envflags &= ~GUSA_MASK; } - if (cs->singlestep_enabled) { + switch (ctx.bstate) { + case DISAS_STOP: gen_save_cpu_state(&ctx, true); - gen_helper_debug(cpu_env); - } else { - switch (ctx.bstate) { - case DISAS_STOP: - gen_save_cpu_state(&ctx, true); + if (cs->singlestep_enabled) { + gen_helper_debug(cpu_env); + } else { tcg_gen_exit_tb(0); - break; - case DISAS_NEXT: - gen_save_cpu_state(&ctx, false); - gen_goto_tb(&ctx, 0, ctx.pc); - break; - case DISAS_NORETURN: - break; - default: - g_assert_not_reached(); - } + } + break; + case DISAS_NEXT: + gen_save_cpu_state(&ctx, false); + gen_goto_tb(&ctx, 0, ctx.pc); + break; + case DISAS_NORETURN: + break; + default: + g_assert_not_reached(); } gen_tb_end(tb, num_insns); From 6f1c2af641d6e7aceb2e5671a45b3d6e5966dfb8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 7 Sep 2017 11:50:56 -0700 Subject: [PATCH 243/546] target/sh4: Convert to DisasContextBase Signed-off-by: Richard Henderson [aurel32: fix whitespace] Message-Id: <20170907185057.23421-5-richard.henderson@linaro.org> Signed-off-by: Aurelien Jarno --- target/sh4/translate.c | 154 +++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 76 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index dd9aaa4e63..038663cc05 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -33,19 +33,19 @@ typedef struct DisasContext { - struct TranslationBlock *tb; - target_ulong pc; - uint16_t opcode; - uint32_t tbflags; /* should stay unmodified during the TB translation */ - uint32_t envflags; /* should stay in sync with env->flags using TCG ops */ - DisasJumpType bstate; + DisasContextBase base; + + uint32_t tbflags; /* should stay unmodified during the TB translation */ + uint32_t envflags; /* should stay in sync with env->flags using TCG ops */ int memidx; int gbank; int fbank; uint32_t delayed_pc; - int singlestep_enabled; uint32_t features; - int has_movcal; + + uint16_t opcode; + + bool has_movcal; } DisasContext; #if defined(CONFIG_USER_ONLY) @@ -54,7 +54,7 @@ typedef struct DisasContext { #define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD))) #endif -/* Target-specific values for ctx->bstate. */ +/* Target-specific values for ctx->base.is_jmp. */ /* We want to exit back to the cpu loop for some reason. Usually this is to recognize interrupts immediately. */ #define DISAS_STOP DISAS_TARGET_0 @@ -209,7 +209,7 @@ static void gen_write_sr(TCGv src) static inline void gen_save_cpu_state(DisasContext *ctx, bool save_pc) { if (save_pc) { - tcg_gen_movi_i32(cpu_pc, ctx->pc); + tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next); } if (ctx->delayed_pc != (uint32_t) -1) { tcg_gen_movi_i32(cpu_delayed_pc, ctx->delayed_pc); @@ -227,11 +227,11 @@ static inline bool use_exit_tb(DisasContext *ctx) static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) { /* Use a direct jump if in same page and singlestep not enabled */ - if (unlikely(ctx->singlestep_enabled || use_exit_tb(ctx))) { + if (unlikely(ctx->base.singlestep_enabled || use_exit_tb(ctx))) { return false; } #ifndef CONFIG_USER_ONLY - return (ctx->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); + return (ctx->base.tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK); #else return true; #endif @@ -242,10 +242,10 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) if (use_goto_tb(ctx, dest)) { tcg_gen_goto_tb(n); tcg_gen_movi_i32(cpu_pc, dest); - tcg_gen_exit_tb((uintptr_t)ctx->tb + n); + tcg_gen_exit_tb((uintptr_t)ctx->base.tb + n); } else { tcg_gen_movi_i32(cpu_pc, dest); - if (ctx->singlestep_enabled) { + if (ctx->base.singlestep_enabled) { gen_helper_debug(cpu_env); } else if (use_exit_tb(ctx)) { tcg_gen_exit_tb(0); @@ -253,7 +253,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) tcg_gen_lookup_and_goto_ptr(); } } - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; } static void gen_jump(DisasContext * ctx) @@ -263,14 +263,14 @@ static void gen_jump(DisasContext * ctx) delayed jump as immediate jump are conditinal jumps */ tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc); tcg_gen_discard_i32(cpu_delayed_pc); - if (ctx->singlestep_enabled) { + if (ctx->base.singlestep_enabled) { gen_helper_debug(cpu_env); } else if (use_exit_tb(ctx)) { tcg_gen_exit_tb(0); } else { tcg_gen_lookup_and_goto_ptr(); } - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; } else { gen_goto_tb(ctx, 0, ctx->delayed_pc); } @@ -300,8 +300,8 @@ static void gen_conditional_jump(DisasContext *ctx, target_ulong dest, tcg_gen_brcondi_i32(cond_not_taken, cpu_sr_t, 0, l1); gen_goto_tb(ctx, 0, dest); gen_set_label(l1); - gen_goto_tb(ctx, 1, ctx->pc + 2); - ctx->bstate = DISAS_NORETURN; + gen_goto_tb(ctx, 1, ctx->base.pc_next + 2); + ctx->base.is_jmp = DISAS_NORETURN; } /* Delayed conditional jump (bt or bf) */ @@ -324,12 +324,12 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) gen_jump(ctx); gen_set_label(l1); - ctx->bstate = DISAS_NEXT; + ctx->base.is_jmp = DISAS_NEXT; return; } tcg_gen_brcondi_i32(TCG_COND_NE, ds, 0, l1); - gen_goto_tb(ctx, 1, ctx->pc + 2); + gen_goto_tb(ctx, 1, ctx->base.pc_next + 2); gen_set_label(l1); gen_jump(ctx); } @@ -466,7 +466,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_mov_i32(cpu_delayed_pc, cpu_spc); ctx->envflags |= DELAY_SLOT_RTE; ctx->delayed_pc = (uint32_t) - 1; - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; return; case 0x0058: /* sets */ tcg_gen_ori_i32(cpu_sr, cpu_sr, (1u << SR_S)); @@ -477,23 +477,23 @@ static void _decode_opc(DisasContext * ctx) case 0xfbfd: /* frchg */ CHECK_FPSCR_PR_0 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_FR); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; return; case 0xf3fd: /* fschg */ CHECK_FPSCR_PR_0 tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_SZ); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; return; case 0xf7fd: /* fpchg */ CHECK_SH4A tcg_gen_xori_i32(cpu_fpscr, cpu_fpscr, FPSCR_PR); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; return; case 0x0009: /* nop */ return; case 0x001b: /* sleep */ CHECK_PRIVILEGED - tcg_gen_movi_i32(cpu_pc, ctx->pc + 2); + tcg_gen_movi_i32(cpu_pc, ctx->base.pc_next + 2); gen_helper_sleep(cpu_env); return; } @@ -520,23 +520,24 @@ static void _decode_opc(DisasContext * ctx) /* Detect the start of a gUSA region. If so, update envflags and end the TB. This will allow us to see the end of the region (stored in R0) in the next TB. */ - if (B11_8 == 15 && B7_0s < 0 && (tb_cflags(ctx->tb) & CF_PARALLEL)) { + if (B11_8 == 15 && B7_0s < 0 && + (tb_cflags(ctx->base.tb) & CF_PARALLEL)) { ctx->envflags = deposit32(ctx->envflags, GUSA_SHIFT, 8, B7_0s); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; } #endif tcg_gen_movi_i32(REG(B11_8), B7_0s); return; case 0x9000: /* mov.w @(disp,PC),Rn */ { - TCGv addr = tcg_const_i32(ctx->pc + 4 + B7_0 * 2); + TCGv addr = tcg_const_i32(ctx->base.pc_next + 4 + B7_0 * 2); tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESW); tcg_temp_free(addr); } return; case 0xd000: /* mov.l @(disp,PC),Rn */ { - TCGv addr = tcg_const_i32((ctx->pc + 4 + B7_0 * 4) & ~3); + TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3); tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL); tcg_temp_free(addr); } @@ -546,13 +547,13 @@ static void _decode_opc(DisasContext * ctx) return; case 0xa000: /* bra disp */ CHECK_NOT_DELAY_SLOT - ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; + ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2; ctx->envflags |= DELAY_SLOT; return; case 0xb000: /* bsr disp */ CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); - ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2; + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); + ctx->delayed_pc = ctx->base.pc_next + 4 + B11_0s * 2; ctx->envflags |= DELAY_SLOT; return; } @@ -1180,22 +1181,22 @@ static void _decode_opc(DisasContext * ctx) return; case 0x8b00: /* bf label */ CHECK_NOT_DELAY_SLOT - gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, false); + gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, false); return; case 0x8f00: /* bf/s label */ CHECK_NOT_DELAY_SLOT tcg_gen_xori_i32(cpu_delayed_cond, cpu_sr_t, 1); - ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2; + ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2; ctx->envflags |= DELAY_SLOT_CONDITIONAL; return; case 0x8900: /* bt label */ CHECK_NOT_DELAY_SLOT - gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2, true); + gen_conditional_jump(ctx, ctx->base.pc_next + 4 + B7_0s * 2, true); return; case 0x8d00: /* bt/s label */ CHECK_NOT_DELAY_SLOT tcg_gen_mov_i32(cpu_delayed_cond, cpu_sr_t); - ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2; + ctx->delayed_pc = ctx->base.pc_next + 4 + B7_0s * 2; ctx->envflags |= DELAY_SLOT_CONDITIONAL; return; case 0x8800: /* cmp/eq #imm,R0 */ @@ -1282,7 +1283,8 @@ static void _decode_opc(DisasContext * ctx) } return; case 0xc700: /* mova @(disp,PC),R0 */ - tcg_gen_movi_i32(REG(0), ((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3); + tcg_gen_movi_i32(REG(0), ((ctx->base.pc_next & 0xfffffffc) + + 4 + B7_0 * 4) & ~3); return; case 0xcb00: /* or #imm,R0 */ tcg_gen_ori_i32(REG(0), REG(0), B7_0); @@ -1308,7 +1310,7 @@ static void _decode_opc(DisasContext * ctx) imm = tcg_const_i32(B7_0); gen_helper_trapa(cpu_env, imm); tcg_temp_free(imm); - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; } return; case 0xc800: /* tst #imm,R0 */ @@ -1376,13 +1378,13 @@ static void _decode_opc(DisasContext * ctx) switch (ctx->opcode & 0xf0ff) { case 0x0023: /* braf Rn */ CHECK_NOT_DELAY_SLOT - tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->pc + 4); + tcg_gen_addi_i32(cpu_delayed_pc, REG(B11_8), ctx->base.pc_next + 4); ctx->envflags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; return; case 0x0003: /* bsrf Rn */ CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); tcg_gen_add_i32(cpu_delayed_pc, REG(B11_8), cpu_pr); ctx->envflags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; @@ -1405,7 +1407,7 @@ static void _decode_opc(DisasContext * ctx) return; case 0x400b: /* jsr @Rn */ CHECK_NOT_DELAY_SLOT - tcg_gen_movi_i32(cpu_pr, ctx->pc + 4); + tcg_gen_movi_i32(cpu_pr, ctx->base.pc_next + 4); tcg_gen_mov_i32(cpu_delayed_pc, REG(B11_8)); ctx->envflags |= DELAY_SLOT; ctx->delayed_pc = (uint32_t) - 1; @@ -1417,7 +1419,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_andi_i32(val, REG(B11_8), 0x700083f3); gen_write_sr(val); tcg_temp_free(val); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; } return; case 0x4007: /* ldc.l @Rm+,SR */ @@ -1429,7 +1431,7 @@ static void _decode_opc(DisasContext * ctx) gen_write_sr(val); tcg_temp_free(val); tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; } return; case 0x0002: /* stc SR,Rn */ @@ -1491,7 +1493,7 @@ static void _decode_opc(DisasContext * ctx) case 0x406a: /* lds Rm,FPSCR */ CHECK_FPU_ENABLED gen_helper_ld_fpscr(cpu_env, REG(B11_8)); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; return; case 0x4066: /* lds.l @Rm+,FPSCR */ CHECK_FPU_ENABLED @@ -1501,7 +1503,7 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); gen_helper_ld_fpscr(cpu_env, addr); tcg_temp_free(addr); - ctx->bstate = DISAS_STOP; + ctx->base.is_jmp = DISAS_STOP; } return; case 0x006a: /* sts FPSCR,Rn */ @@ -1565,7 +1567,7 @@ static void _decode_opc(DisasContext * ctx) TCGLabel *fail = gen_new_label(); TCGLabel *done = gen_new_label(); - if ((tb_cflags(ctx->tb) & CF_PARALLEL)) { + if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) { TCGv tmp; tcg_gen_brcond_i32(TCG_COND_NE, REG(B11_8), @@ -1599,7 +1601,7 @@ static void _decode_opc(DisasContext * ctx) * In a parallel context, we must also save the loaded value * for use with the cmpxchg that we'll use with movco.l. */ CHECK_SH4A - if ((tb_cflags(ctx->tb) & CF_PARALLEL)) { + if ((tb_cflags(ctx->base.tb) & CF_PARALLEL)) { TCGv tmp = tcg_temp_new(); tcg_gen_mov_i32(tmp, REG(B11_8)); tcg_gen_qemu_ld_i32(REG(0), REG(B11_8), ctx->memidx, MO_TESL); @@ -1827,7 +1829,7 @@ static void _decode_opc(DisasContext * ctx) } #if 0 fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", - ctx->opcode, ctx->pc); + ctx->opcode, ctx->base.pc_next); fflush(stderr); #endif do_illegal: @@ -1839,7 +1841,7 @@ static void _decode_opc(DisasContext * ctx) gen_save_cpu_state(ctx, true); gen_helper_raise_illegal_instruction(cpu_env); } - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; return; do_fpu_disabled: @@ -1849,7 +1851,7 @@ static void _decode_opc(DisasContext * ctx) } else { gen_helper_raise_fpu_disable(cpu_env); } - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; return; } @@ -1901,8 +1903,8 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) int mv_src, mt_dst, st_src, st_mop; TCGv op_arg; - uint32_t pc = ctx->pc; - uint32_t pc_end = ctx->tb->cs_base; + uint32_t pc = ctx->base.pc_next; + uint32_t pc_end = ctx->base.tb->cs_base; int backup = sextract32(ctx->tbflags, GUSA_SHIFT, 8); int max_insns = (pc_end - pc) / 2; int i; @@ -2232,7 +2234,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) /* The entire region has been translated. */ ctx->envflags &= ~GUSA_MASK; - ctx->pc = pc_end; + ctx->base.pc_next = pc_end; return max_insns; fail: @@ -2245,13 +2247,13 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) ctx->envflags |= GUSA_EXCLUSIVE; gen_save_cpu_state(ctx, false); gen_helper_exclusive(cpu_env); - ctx->bstate = DISAS_NORETURN; + ctx->base.is_jmp = DISAS_NORETURN; /* We're not executing an instruction, but we must report one for the purposes of accounting within the TB. We might as well report the - entire region consumed via ctx->pc so that it's immediately available - in the disassembly dump. */ - ctx->pc = pc_end; + entire region consumed via ctx->base.pc_next so that it's immediately + available in the disassembly dump. */ + ctx->base.pc_next = pc_end; return 1; } #endif @@ -2265,16 +2267,16 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) int max_insns; pc_start = tb->pc; - ctx.pc = pc_start; + ctx.base.pc_next = pc_start; ctx.tbflags = (uint32_t)tb->flags; ctx.envflags = tb->flags & TB_FLAG_ENVFLAGS_MASK; - ctx.bstate = DISAS_NEXT; + ctx.base.is_jmp = DISAS_NEXT; ctx.memidx = (ctx.tbflags & (1u << SR_MD)) == 0 ? 1 : 0; /* We don't know if the delayed pc came from a dynamic or static branch, so assume it is a dynamic branch. */ ctx.delayed_pc = -1; /* use delayed pc from env pointer */ - ctx.tb = tb; - ctx.singlestep_enabled = cs->singlestep_enabled; + ctx.base.tb = tb; + ctx.base.singlestep_enabled = cs->singlestep_enabled; ctx.features = env->features; ctx.has_movcal = (ctx.tbflags & TB_FLAG_PENDING_MOVCA); ctx.gbank = ((ctx.tbflags & (1 << SR_MD)) && @@ -2289,11 +2291,11 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) /* Since the ISA is fixed-width, we can bound by the number of instructions remaining on the page. */ - num_insns = -(ctx.pc | TARGET_PAGE_MASK) / 2; + num_insns = -(ctx.base.pc_next | TARGET_PAGE_MASK) / 2; max_insns = MIN(max_insns, num_insns); /* Single stepping means just that. */ - if (ctx.singlestep_enabled || singlestep) { + if (ctx.base.singlestep_enabled || singlestep) { max_insns = 1; } @@ -2306,22 +2308,22 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) } #endif - while (ctx.bstate == DISAS_NEXT + while (ctx.base.is_jmp == DISAS_NEXT && num_insns < max_insns && !tcg_op_buf_full()) { - tcg_gen_insn_start(ctx.pc, ctx.envflags); + tcg_gen_insn_start(ctx.base.pc_next, ctx.envflags); num_insns++; - if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { + if (unlikely(cpu_breakpoint_test(cs, ctx.base.pc_next, BP_ANY))) { /* We have hit a breakpoint - make sure PC is up-to-date */ gen_save_cpu_state(&ctx, true); gen_helper_debug(cpu_env); - ctx.bstate = DISAS_NORETURN; + ctx.base.is_jmp = DISAS_NORETURN; /* The address covered by the breakpoint must be included in [tb->pc, tb->pc + tb->size) in order to for it to be properly cleared -- thus we increment the PC here so that the logic setting tb->size below does the right thing. */ - ctx.pc += 2; + ctx.base.pc_next += 2; break; } @@ -2329,9 +2331,9 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) gen_io_start(); } - ctx.opcode = cpu_lduw_code(env, ctx.pc); + ctx.opcode = cpu_lduw_code(env, ctx.base.pc_next); decode_opc(&ctx); - ctx.pc += 2; + ctx.base.pc_next += 2; } if (tb_cflags(tb) & CF_LAST_IO) { gen_io_end(); @@ -2342,10 +2344,10 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.envflags &= ~GUSA_MASK; } - switch (ctx.bstate) { + switch (ctx.base.is_jmp) { case DISAS_STOP: gen_save_cpu_state(&ctx, true); - if (cs->singlestep_enabled) { + if (ctx.base.singlestep_enabled) { gen_helper_debug(cpu_env); } else { tcg_gen_exit_tb(0); @@ -2353,7 +2355,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) break; case DISAS_NEXT: gen_save_cpu_state(&ctx, false); - gen_goto_tb(&ctx, 0, ctx.pc); + gen_goto_tb(&ctx, 0, ctx.base.pc_next); break; case DISAS_NORETURN: break; @@ -2363,7 +2365,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) gen_tb_end(tb, num_insns); - tb->size = ctx.pc - pc_start; + tb->size = ctx.base.pc_next - pc_start; tb->icount = num_insns; #ifdef DEBUG_DISAS @@ -2371,7 +2373,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) && qemu_log_in_addr_range(pc_start)) { qemu_log_lock(); qemu_log("IN:\n"); /* , lookup_symbol(pc_start)); */ - log_target_disas(cs, pc_start, ctx.pc - pc_start); + log_target_disas(cs, pc_start, ctx.base.pc_next - pc_start); qemu_log("\n"); qemu_log_unlock(); } From 2eb967c4e9898d688a75be43955bbbc2107f29f7 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 7 Feb 2017 02:43:12 -0800 Subject: [PATCH 244/546] target/xtensa: pass actual frame size to the entry helper Currently 'entry' opcode helper accepts frame size divided by 8, as it is encoded in the opcode. Make it more natural and accept actual frame size instead. Signed-off-by: Max Filippov --- target/xtensa/op_helper.c | 2 +- target/xtensa/translate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 3d990c0caa..012552817f 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -249,7 +249,7 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm) if (windowstart & ((1 << callinc) - 1)) { HELPER(window_check)(env, pc, callinc); } - env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3); + env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - imm; rotate_window(env, callinc); env->sregs[WINDOW_START] |= windowstart_bit(env->sregs[WINDOW_BASE], env); diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 20f7ddf042..225e4a5fe8 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2830,7 +2830,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) { TCGv_i32 pc = tcg_const_i32(dc->pc); TCGv_i32 s = tcg_const_i32(BRI12_S); - TCGv_i32 imm = tcg_const_i32(BRI12_IMM12); + TCGv_i32 imm = tcg_const_i32(BRI12_IMM12 << 3); gen_helper_entry(cpu_env, pc, s, imm); tcg_temp_free(imm); tcg_temp_free(s); From 7f709ce739d46ecd6df98921a20e9dce1dcc421b Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 22 Nov 2016 10:08:02 -0800 Subject: [PATCH 245/546] target/xtensa: import libisa source The canonical way of dealing with Xtensa instructions decoding and encoding is through the libisa. Libisa is a configuration-independent library with a stable interface plus generated configuration-specific xtensa-modules.c file with implementations of decoding and encoding functions. Libisa is MIT-licensed and originally disributed xtensa-modules.c files are also MIT-licensed and are available as a part of xtensa configuration overlay. Signed-off-by: Max Filippov --- include/hw/xtensa/xtensa-isa.h | 838 +++++++++++++ target/xtensa/Makefile.objs | 1 + target/xtensa/xtensa-isa-internal.h | 231 ++++ target/xtensa/xtensa-isa.c | 1745 +++++++++++++++++++++++++++ target/xtensa/xtensa-isa.h | 1 + 5 files changed, 2816 insertions(+) create mode 100644 include/hw/xtensa/xtensa-isa.h create mode 100644 target/xtensa/xtensa-isa-internal.h create mode 100644 target/xtensa/xtensa-isa.c create mode 100644 target/xtensa/xtensa-isa.h diff --git a/include/hw/xtensa/xtensa-isa.h b/include/hw/xtensa/xtensa-isa.h new file mode 100644 index 0000000000..353f82ba25 --- /dev/null +++ b/include/hw/xtensa/xtensa-isa.h @@ -0,0 +1,838 @@ +/* Interface definition for configurable Xtensa ISA support. + * + * Copyright (c) 2001-2013 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_LIBISA_H +#define XTENSA_LIBISA_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Version number: This is intended to help support code that works with + * versions of this library from multiple Xtensa releases. + */ + +#define XTENSA_ISA_VERSION 7000 + +/* + * This file defines the interface to the Xtensa ISA library. This + * library contains most of the ISA-specific information for a + * particular Xtensa processor. For example, the set of valid + * instructions, their opcode encodings and operand fields are all + * included here. + * + * This interface basically defines a number of abstract data types. + * + * . an instruction buffer - for holding the raw instruction bits + * . ISA info - information about the ISA as a whole + * . instruction formats - instruction size and slot structure + * . opcodes - information about individual instructions + * . operands - information about register and immediate instruction operands + * . stateOperands - information about processor state instruction operands + * . interfaceOperands - information about interface instruction operands + * . register files - register file information + * . processor states - internal processor state information + * . system registers - "special registers" and "user registers" + * . interfaces - TIE interfaces that are external to the processor + * . functional units - TIE shared functions + * + * The interface defines a set of functions to access each data type. + * With the exception of the instruction buffer, the internal + * representations of the data structures are hidden. All accesses must + * be made through the functions defined here. + */ + +typedef struct xtensa_isa_opaque { int unused; } *xtensa_isa; + + +/* + * Most of the Xtensa ISA entities (e.g., opcodes, regfiles, etc.) are + * represented here using sequential integers beginning with 0. The + * specific values are only fixed for a particular instantiation of an + * xtensa_isa structure, so these values should only be used + * internally. + */ + +typedef int xtensa_opcode; +typedef int xtensa_format; +typedef int xtensa_regfile; +typedef int xtensa_state; +typedef int xtensa_sysreg; +typedef int xtensa_interface; +typedef int xtensa_funcUnit; + + +/* Define a unique value for undefined items. */ + +#define XTENSA_UNDEFINED -1 + + +/* + * Overview of using this interface to decode/encode instructions: + * + * Each Xtensa instruction is associated with a particular instruction + * format, where the format defines a fixed number of slots for + * operations. The formats for the core Xtensa ISA have only one slot, + * but FLIX instructions may have multiple slots. Within each slot, + * there is a single opcode and some number of associated operands. + * + * The encoding and decoding functions operate on instruction buffers, + * not on the raw bytes of the instructions. The same instruction + * buffer data structure is used for both entire instructions and + * individual slots in those instructions -- the contents of a slot need + * to be extracted from or inserted into the buffer for the instruction + * as a whole. + * + * Decoding an instruction involves first finding the format, which + * identifies the number of slots, and then decoding each slot + * separately. A slot is decoded by finding the opcode and then using + * the opcode to determine how many operands there are. For example: + * + * xtensa_insnbuf_from_chars + * xtensa_format_decode + * for each slot { + * xtensa_format_get_slot + * xtensa_opcode_decode + * for each operand { + * xtensa_operand_get_field + * xtensa_operand_decode + * } + * } + * + * Encoding an instruction is roughly the same procedure in reverse: + * + * xtensa_format_encode + * for each slot { + * xtensa_opcode_encode + * for each operand { + * xtensa_operand_encode + * xtensa_operand_set_field + * } + * xtensa_format_set_slot + * } + * xtensa_insnbuf_to_chars + */ + + +/* Error handling. */ + +/* + * Error codes. The code for the most recent error condition can be + * retrieved with the "errno" function. For any result other than + * xtensa_isa_ok, an error message containing additional information + * about the problem can be retrieved using the "error_msg" function. + * The error messages are stored in an internal buffer, which should + * not be freed and may be overwritten by subsequent operations. + */ + +typedef enum xtensa_isa_status_enum { + xtensa_isa_ok = 0, + xtensa_isa_bad_format, + xtensa_isa_bad_slot, + xtensa_isa_bad_opcode, + xtensa_isa_bad_operand, + xtensa_isa_bad_field, + xtensa_isa_bad_iclass, + xtensa_isa_bad_regfile, + xtensa_isa_bad_sysreg, + xtensa_isa_bad_state, + xtensa_isa_bad_interface, + xtensa_isa_bad_funcUnit, + xtensa_isa_wrong_slot, + xtensa_isa_no_field, + xtensa_isa_out_of_memory, + xtensa_isa_buffer_overflow, + xtensa_isa_internal_error, + xtensa_isa_bad_value +} xtensa_isa_status; + +xtensa_isa_status xtensa_isa_errno(xtensa_isa isa); + +char *xtensa_isa_error_msg(xtensa_isa isa); + + + +/* Instruction buffers. */ + +typedef uint32_t xtensa_insnbuf_word; +typedef xtensa_insnbuf_word *xtensa_insnbuf; + + +/* Get the size in "insnbuf_words" of the xtensa_insnbuf array. */ + +int xtensa_insnbuf_size(xtensa_isa isa); + + +/* Allocate an xtensa_insnbuf of the right size. */ + +xtensa_insnbuf xtensa_insnbuf_alloc(xtensa_isa isa); + + +/* Release an xtensa_insnbuf. */ + +void xtensa_insnbuf_free(xtensa_isa isa, xtensa_insnbuf buf); + + +/* + * Conversion between raw memory (char arrays) and our internal + * instruction representation. This is complicated by the Xtensa ISA's + * variable instruction lengths. When converting to chars, the buffer + * must contain a valid instruction so we know how many bytes to copy; + * thus, the "to_chars" function returns the number of bytes copied or + * XTENSA_UNDEFINED on error. The "from_chars" function first reads the + * minimal number of bytes required to decode the instruction length and + * then proceeds to copy the entire instruction into the buffer; if the + * memory does not contain a valid instruction, it copies the maximum + * number of bytes required for the longest Xtensa instruction. The + * "num_chars" argument may be used to limit the number of bytes that + * can be read or written. Otherwise, if "num_chars" is zero, the + * functions may read or write past the end of the code. + */ + +int xtensa_insnbuf_to_chars(xtensa_isa isa, const xtensa_insnbuf insn, + unsigned char *cp, int num_chars); + +void xtensa_insnbuf_from_chars(xtensa_isa isa, xtensa_insnbuf insn, + const unsigned char *cp, int num_chars); + + + +/* ISA information. */ + +/* Initialize the ISA information. */ + +xtensa_isa xtensa_isa_init(void *xtensa_modules, xtensa_isa_status *errno_p, + char **error_msg_p); + + +/* Deallocate an xtensa_isa structure. */ + +void xtensa_isa_free(xtensa_isa isa); + + +/* Get the maximum instruction size in bytes. */ + +int xtensa_isa_maxlength(xtensa_isa isa); + + +/* + * Decode the length in bytes of an instruction in raw memory (not an + * insnbuf). This function reads only the minimal number of bytes + * required to decode the instruction length. Returns + * XTENSA_UNDEFINED on error. + */ + +int xtensa_isa_length_from_chars(xtensa_isa isa, const unsigned char *cp); + + +/* + * Get the number of stages in the processor's pipeline. The pipeline + * stage values returned by other functions in this library will range + * from 0 to N-1, where N is the value returned by this function. + * Note that the stage numbers used here may not correspond to the + * actual processor hardware, e.g., the hardware may have additional + * stages before stage 0. Returns XTENSA_UNDEFINED on error. + */ + +int xtensa_isa_num_pipe_stages(xtensa_isa isa); + + +/* Get the number of various entities that are defined for this processor. */ + +int xtensa_isa_num_formats(xtensa_isa isa); + +int xtensa_isa_num_opcodes(xtensa_isa isa); + +int xtensa_isa_num_regfiles(xtensa_isa isa); + +int xtensa_isa_num_states(xtensa_isa isa); + +int xtensa_isa_num_sysregs(xtensa_isa isa); + +int xtensa_isa_num_interfaces(xtensa_isa isa); + +int xtensa_isa_num_funcUnits(xtensa_isa isa); + + + +/* Instruction formats. */ + +/* Get the name of a format. Returns null on error. */ + +const char *xtensa_format_name(xtensa_isa isa, xtensa_format fmt); + + +/* + * Given a format name, return the format number. Returns + * XTENSA_UNDEFINED if the name is not a valid format. + */ + +xtensa_format xtensa_format_lookup(xtensa_isa isa, const char *fmtname); + + +/* + * Decode the instruction format from a binary instruction buffer. + * Returns XTENSA_UNDEFINED if the format is not recognized. + */ + +xtensa_format xtensa_format_decode(xtensa_isa isa, const xtensa_insnbuf insn); + + +/* + * Set the instruction format field(s) in a binary instruction buffer. + * All the other fields are set to zero. Returns non-zero on error. + */ + +int xtensa_format_encode(xtensa_isa isa, xtensa_format fmt, + xtensa_insnbuf insn); + + +/* + * Find the length (in bytes) of an instruction. Returns + * XTENSA_UNDEFINED on error. + */ + +int xtensa_format_length(xtensa_isa isa, xtensa_format fmt); + + +/* + * Get the number of slots in an instruction. Returns XTENSA_UNDEFINED + * on error. + */ + +int xtensa_format_num_slots(xtensa_isa isa, xtensa_format fmt); + + +/* + * Get the opcode for a no-op in a particular slot. + * Returns XTENSA_UNDEFINED on error. + */ + +xtensa_opcode xtensa_format_slot_nop_opcode(xtensa_isa isa, xtensa_format fmt, + int slot); + + +/* + * Get the bits for a specified slot out of an insnbuf for the + * instruction as a whole and put them into an insnbuf for that one + * slot, and do the opposite to set a slot. Return non-zero on error. + */ + +int xtensa_format_get_slot(xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf insn, xtensa_insnbuf slotbuf); + +int xtensa_format_set_slot(xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf insn, const xtensa_insnbuf slotbuf); + + + +/* Opcode information. */ + +/* + * Translate a mnemonic name to an opcode. Returns XTENSA_UNDEFINED if + * the name is not a valid opcode mnemonic. + */ + +xtensa_opcode xtensa_opcode_lookup(xtensa_isa isa, const char *opname); + + +/* + * Decode the opcode for one instruction slot from a binary instruction + * buffer. Returns the opcode or XTENSA_UNDEFINED if the opcode is + * illegal. + */ + +xtensa_opcode xtensa_opcode_decode(xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf); + + +/* + * Set the opcode field(s) for an instruction slot. All other fields + * in the slot are set to zero. Returns non-zero if the opcode cannot + * be encoded. + */ + +int xtensa_opcode_encode(xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, xtensa_opcode opc); + + +/* Get the mnemonic name for an opcode. Returns null on error. */ + +const char *xtensa_opcode_name(xtensa_isa isa, xtensa_opcode opc); + + +/* Check various properties of opcodes. These functions return 0 if + * the condition is false, 1 if the condition is true, and + * XTENSA_UNDEFINED on error. The instructions are classified as + * follows: + * + * branch: conditional branch; may fall through to next instruction (B*) + * jump: unconditional branch (J, JX, RET*, RF*) + * loop: zero-overhead loop (LOOP*) + * call: unconditional call; control returns to next instruction (CALL*) + * + * For the opcodes that affect control flow in some way, the branch + * target may be specified by an immediate operand or it may be an + * address stored in a register. You can distinguish these by + * checking if the instruction has a PC-relative immediate + * operand. + */ + +int xtensa_opcode_is_branch(xtensa_isa isa, xtensa_opcode opc); + +int xtensa_opcode_is_jump(xtensa_isa isa, xtensa_opcode opc); + +int xtensa_opcode_is_loop(xtensa_isa isa, xtensa_opcode opc); + +int xtensa_opcode_is_call(xtensa_isa isa, xtensa_opcode opc); + + +/* + * Find the number of ordinary operands, state operands, and interface + * operands for an instruction. These return XTENSA_UNDEFINED on + * error. + */ + +int xtensa_opcode_num_operands(xtensa_isa isa, xtensa_opcode opc); + +int xtensa_opcode_num_stateOperands(xtensa_isa isa, xtensa_opcode opc); + +int xtensa_opcode_num_interfaceOperands(xtensa_isa isa, xtensa_opcode opc); + + +/* + * Get functional unit usage requirements for an opcode. Each "use" + * is identified by a pair. The + * "num_funcUnit_uses" function returns the number of these "uses" or + * XTENSA_UNDEFINED on error. The "funcUnit_use" function returns + * a pointer to a "use" pair or null on error. + */ + +typedef struct xtensa_funcUnit_use_struct { + xtensa_funcUnit unit; + int stage; +} xtensa_funcUnit_use; + +int xtensa_opcode_num_funcUnit_uses(xtensa_isa isa, xtensa_opcode opc); + +xtensa_funcUnit_use *xtensa_opcode_funcUnit_use(xtensa_isa isa, + xtensa_opcode opc, int u); + + + +/* Operand information. */ + +/* Get the name of an operand. Returns null on error. */ + +const char *xtensa_operand_name(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * Some operands are "invisible", i.e., not explicitly specified in + * assembly language. When assembling an instruction, you need not set + * the values of invisible operands, since they are either hardwired or + * derived from other field values. The values of invisible operands + * can be examined in the same way as other operands, but remember that + * an invisible operand may get its value from another visible one, so + * the entire instruction must be available before examining the + * invisible operand values. This function returns 1 if an operand is + * visible, 0 if it is invisible, or XTENSA_UNDEFINED on error. Note + * that whether an operand is visible is orthogonal to whether it is + * "implicit", i.e., whether it is encoded in a field in the + * instruction. + */ + +int xtensa_operand_is_visible(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * Check if an operand is an input ('i'), output ('o'), or inout ('m') + * operand. Note: The output operand of a conditional assignment + * (e.g., movnez) appears here as an inout ('m') even if it is declared + * in the TIE code as an output ('o'); this allows the compiler to + * properly handle register allocation for conditional assignments. + * Returns 0 on error. + */ + +char xtensa_operand_inout(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * Get and set the raw (encoded) value of the field for the specified + * operand. The "set" function does not check if the value fits in the + * field; that is done by the "encode" function below. Both of these + * functions return non-zero on error, e.g., if the field is not defined + * for the specified slot. + */ + +int xtensa_operand_get_field(xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf, uint32_t *valp); + +int xtensa_operand_set_field(xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, uint32_t val); + + +/* + * Encode and decode operands. The raw bits in the operand field may + * be encoded in a variety of different ways. These functions hide + * the details of that encoding. The result values are returned through + * the argument pointer. The return value is non-zero on error. + */ + +int xtensa_operand_encode(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp); + +int xtensa_operand_decode(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp); + + +/* + * An operand may be either a register operand or an immediate of some + * sort (e.g., PC-relative or not). The "is_register" function returns + * 0 if the operand is an immediate, 1 if it is a register, and + * XTENSA_UNDEFINED on error. The "regfile" function returns the + * regfile for a register operand, or XTENSA_UNDEFINED on error. + */ + +int xtensa_operand_is_register(xtensa_isa isa, xtensa_opcode opc, int opnd); + +xtensa_regfile xtensa_operand_regfile(xtensa_isa isa, xtensa_opcode opc, + int opnd); + + +/* + * Register operands may span multiple consecutive registers, e.g., a + * 64-bit data type may occupy two 32-bit registers. Only the first + * register is encoded in the operand field. This function specifies + * the number of consecutive registers occupied by this operand. For + * non-register operands, the return value is undefined. Returns + * XTENSA_UNDEFINED on error. + */ + +int xtensa_operand_num_regs(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * Some register operands do not completely identify the register being + * accessed. For example, the operand value may be added to an internal + * state value. By definition, this implies that the corresponding + * regfile is not allocatable. Unknown registers should generally be + * treated with worst-case assumptions. The function returns 0 if the + * register value is unknown, 1 if known, and XTENSA_UNDEFINED on + * error. + */ + +int xtensa_operand_is_known_reg(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * Check if an immediate operand is PC-relative. Returns 0 for register + * operands and non-PC-relative immediates, 1 for PC-relative + * immediates, and XTENSA_UNDEFINED on error. + */ + +int xtensa_operand_is_PCrelative(xtensa_isa isa, xtensa_opcode opc, int opnd); + + +/* + * For PC-relative offset operands, the interpretation of the offset may + * vary between opcodes, e.g., is it relative to the current PC or that + * of the next instruction? The following functions are defined to + * perform PC-relative relocations and to undo them (as in the + * disassembler). The "do_reloc" function takes the desired address + * value and the PC of the current instruction and sets the value to the + * corresponding PC-relative offset (which can then be encoded and + * stored into the operand field). The "undo_reloc" function takes the + * unencoded offset value and the current PC and sets the value to the + * appropriate address. The return values are non-zero on error. Note + * that these functions do not replace the encode/decode functions; the + * operands must be encoded/decoded separately and the encode functions + * are responsible for detecting invalid operand values. + */ + +int xtensa_operand_do_reloc(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp, uint32_t pc); + +int xtensa_operand_undo_reloc(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp, uint32_t pc); + + + +/* State Operands. */ + +/* + * Get the state accessed by a state operand. Returns XTENSA_UNDEFINED + * on error. + */ + +xtensa_state xtensa_stateOperand_state(xtensa_isa isa, xtensa_opcode opc, + int stOp); + + +/* + * Check if a state operand is an input ('i'), output ('o'), or inout + * ('m') operand. Returns 0 on error. + */ + +char xtensa_stateOperand_inout(xtensa_isa isa, xtensa_opcode opc, int stOp); + + + +/* Interface Operands. */ + +/* + * Get the external interface accessed by an interface operand. + * Returns XTENSA_UNDEFINED on error. + */ + +xtensa_interface xtensa_interfaceOperand_interface(xtensa_isa isa, + xtensa_opcode opc, + int ifOp); + + + +/* Register Files. */ + +/* + * Regfiles include both "real" regfiles and "views", where a view + * allows a group of adjacent registers in a real "parent" regfile to be + * viewed as a single register. A regfile view has all the same + * properties as its parent except for its (long) name, bit width, number + * of entries, and default ctype. You can use the parent function to + * distinguish these two classes. + */ + +/* + * Look up a regfile by either its name or its abbreviated "short name". + * Returns XTENSA_UNDEFINED on error. The "lookup_shortname" function + * ignores "view" regfiles since they always have the same shortname as + * their parents. + */ + +xtensa_regfile xtensa_regfile_lookup(xtensa_isa isa, const char *name); + +xtensa_regfile xtensa_regfile_lookup_shortname(xtensa_isa isa, + const char *shortname); + + +/* + * Get the name or abbreviated "short name" of a regfile. + * Returns null on error. + */ + +const char *xtensa_regfile_name(xtensa_isa isa, xtensa_regfile rf); + +const char *xtensa_regfile_shortname(xtensa_isa isa, xtensa_regfile rf); + + +/* + * Get the parent regfile of a "view" regfile. If the regfile is not a + * view, the result is the same as the input parameter. Returns + * XTENSA_UNDEFINED on error. + */ + +xtensa_regfile xtensa_regfile_view_parent(xtensa_isa isa, xtensa_regfile rf); + + +/* + * Get the bit width of a regfile or regfile view. + * Returns XTENSA_UNDEFINED on error. + */ + +int xtensa_regfile_num_bits(xtensa_isa isa, xtensa_regfile rf); + + +/* + * Get the number of regfile entries. Returns XTENSA_UNDEFINED on + * error. + */ + +int xtensa_regfile_num_entries(xtensa_isa isa, xtensa_regfile rf); + + + +/* Processor States. */ + +/* Look up a state by name. Returns XTENSA_UNDEFINED on error. */ + +xtensa_state xtensa_state_lookup(xtensa_isa isa, const char *name); + + +/* Get the name for a processor state. Returns null on error. */ + +const char *xtensa_state_name(xtensa_isa isa, xtensa_state st); + + +/* + * Get the bit width for a processor state. + * Returns XTENSA_UNDEFINED on error. + */ + +int xtensa_state_num_bits(xtensa_isa isa, xtensa_state st); + + +/* + * Check if a state is exported from the processor core. Returns 0 if + * the condition is false, 1 if the condition is true, and + * XTENSA_UNDEFINED on error. + */ + +int xtensa_state_is_exported(xtensa_isa isa, xtensa_state st); + + +/* + * Check for a "shared_or" state. Returns 0 if the condition is false, + * 1 if the condition is true, and XTENSA_UNDEFINED on error. + */ + +int xtensa_state_is_shared_or(xtensa_isa isa, xtensa_state st); + + + +/* Sysregs ("special registers" and "user registers"). */ + +/* + * Look up a register by its number and whether it is a "user register" + * or a "special register". Returns XTENSA_UNDEFINED if the sysreg does + * not exist. + */ + +xtensa_sysreg xtensa_sysreg_lookup(xtensa_isa isa, int num, int is_user); + + +/* + * Check if there exists a sysreg with a given name. + * If not, this function returns XTENSA_UNDEFINED. + */ + +xtensa_sysreg xtensa_sysreg_lookup_name(xtensa_isa isa, const char *name); + + +/* Get the name of a sysreg. Returns null on error. */ + +const char *xtensa_sysreg_name(xtensa_isa isa, xtensa_sysreg sysreg); + + +/* Get the register number. Returns XTENSA_UNDEFINED on error. */ + +int xtensa_sysreg_number(xtensa_isa isa, xtensa_sysreg sysreg); + + +/* + * Check if a sysreg is a "special register" or a "user register". + * Returns 0 for special registers, 1 for user registers and + * XTENSA_UNDEFINED on error. + */ + +int xtensa_sysreg_is_user(xtensa_isa isa, xtensa_sysreg sysreg); + + + +/* Interfaces. */ + +/* + * Find an interface by name. The return value is XTENSA_UNDEFINED if + * the specified interface is not found. + */ + +xtensa_interface xtensa_interface_lookup(xtensa_isa isa, const char *ifname); + + +/* Get the name of an interface. Returns null on error. */ + +const char *xtensa_interface_name(xtensa_isa isa, xtensa_interface intf); + + +/* + * Get the bit width for an interface. + * Returns XTENSA_UNDEFINED on error. + */ + +int xtensa_interface_num_bits(xtensa_isa isa, xtensa_interface intf); + + +/* + * Check if an interface is an input ('i') or output ('o') with respect + * to the Xtensa processor core. Returns 0 on error. + */ + +char xtensa_interface_inout(xtensa_isa isa, xtensa_interface intf); + + +/* + * Check if accessing an interface has potential side effects. + * Currently "data" interfaces have side effects and "control" + * interfaces do not. Returns 1 if there are side effects, 0 if not, + * and XTENSA_UNDEFINED on error. + */ + +int xtensa_interface_has_side_effect(xtensa_isa isa, xtensa_interface intf); + + +/* + * Some interfaces may be related such that accessing one interface + * has side effects on a set of related interfaces. The interfaces + * are partitioned into equivalence classes of related interfaces, and + * each class is assigned a unique identifier number. This function + * returns the class identifier for an interface, or XTENSA_UNDEFINED + * on error. These identifiers can be compared to determine if two + * interfaces are related; the specific values of the identifiers have + * no particular meaning otherwise. + */ + +int xtensa_interface_class_id(xtensa_isa isa, xtensa_interface intf); + + +/* Functional Units. */ + +/* + * Find a functional unit by name. The return value is XTENSA_UNDEFINED if + * the specified unit is not found. + */ + +xtensa_funcUnit xtensa_funcUnit_lookup(xtensa_isa isa, const char *fname); + + +/* Get the name of a functional unit. Returns null on error. */ + +const char *xtensa_funcUnit_name(xtensa_isa isa, xtensa_funcUnit fun); + + +/* + * Functional units may be replicated. See how many instances of a + * particular function unit exist. Returns XTENSA_UNDEFINED on error. + */ + +int xtensa_funcUnit_num_copies(xtensa_isa isa, xtensa_funcUnit fun); + + +#ifdef __cplusplus +} +#endif +#endif /* XTENSA_LIBISA_H */ diff --git a/target/xtensa/Makefile.objs b/target/xtensa/Makefile.objs index 481de91973..0429706680 100644 --- a/target/xtensa/Makefile.objs +++ b/target/xtensa/Makefile.objs @@ -3,5 +3,6 @@ obj-y += core-dc232b.o obj-y += core-dc233c.o obj-y += core-fsf.o obj-$(CONFIG_SOFTMMU) += monitor.o +obj-y += xtensa-isa.o obj-y += translate.o op_helper.o helper.o cpu.o obj-y += gdbstub.o diff --git a/target/xtensa/xtensa-isa-internal.h b/target/xtensa/xtensa-isa-internal.h new file mode 100644 index 0000000000..c29295ff96 --- /dev/null +++ b/target/xtensa/xtensa-isa-internal.h @@ -0,0 +1,231 @@ +/* Internal definitions for the Xtensa ISA library. + * + * Copyright (c) 2004-2011 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef XTENSA_ISA_INTERNAL_H +#define XTENSA_ISA_INTERNAL_H + +#ifndef uint32 +#define uint32 uint32_t +#endif + +/* Flags. */ + +#define XTENSA_OPERAND_IS_REGISTER 0x00000001 +#define XTENSA_OPERAND_IS_PCRELATIVE 0x00000002 +#define XTENSA_OPERAND_IS_INVISIBLE 0x00000004 +#define XTENSA_OPERAND_IS_UNKNOWN 0x00000008 + +#define XTENSA_OPCODE_IS_BRANCH 0x00000001 +#define XTENSA_OPCODE_IS_JUMP 0x00000002 +#define XTENSA_OPCODE_IS_LOOP 0x00000004 +#define XTENSA_OPCODE_IS_CALL 0x00000008 + +#define XTENSA_STATE_IS_EXPORTED 0x00000001 +#define XTENSA_STATE_IS_SHARED_OR 0x00000002 + +#define XTENSA_INTERFACE_HAS_SIDE_EFFECT 0x00000001 + +/* Function pointer typedefs */ +typedef void (*xtensa_format_encode_fn)(xtensa_insnbuf); +typedef void (*xtensa_get_slot_fn)(const xtensa_insnbuf, xtensa_insnbuf); +typedef void (*xtensa_set_slot_fn)(xtensa_insnbuf, const xtensa_insnbuf); +typedef int (*xtensa_opcode_decode_fn)(const xtensa_insnbuf); +typedef uint32_t (*xtensa_get_field_fn)(const xtensa_insnbuf); +typedef void (*xtensa_set_field_fn)(xtensa_insnbuf, uint32_t); +typedef int (*xtensa_immed_decode_fn)(uint32_t *); +typedef int (*xtensa_immed_encode_fn)(uint32_t *); +typedef int (*xtensa_do_reloc_fn)(uint32_t *, uint32_t); +typedef int (*xtensa_undo_reloc_fn)(uint32_t *, uint32_t); +typedef void (*xtensa_opcode_encode_fn)(xtensa_insnbuf); +typedef int (*xtensa_format_decode_fn)(const xtensa_insnbuf); +typedef int (*xtensa_length_decode_fn)(const unsigned char *); + +typedef struct xtensa_format_internal_struct { + const char *name; /* Instruction format name. */ + int length; /* Instruction length in bytes. */ + xtensa_format_encode_fn encode_fn; + int num_slots; + int *slot_id; /* Array[num_slots] of slot IDs. */ +} xtensa_format_internal; + +typedef struct xtensa_slot_internal_struct { + const char *name; /* Not necessarily unique. */ + const char *format; + int position; + xtensa_get_slot_fn get_fn; + xtensa_set_slot_fn set_fn; + xtensa_get_field_fn *get_field_fns; /* Array[field_id]. */ + xtensa_set_field_fn *set_field_fns; /* Array[field_id]. */ + xtensa_opcode_decode_fn opcode_decode_fn; + const char *nop_name; +} xtensa_slot_internal; + +typedef struct xtensa_operand_internal_struct { + const char *name; + int field_id; + xtensa_regfile regfile; /* Register file. */ + int num_regs; /* Usually 1; 2 for reg pairs, etc. */ + uint32_t flags; /* See XTENSA_OPERAND_* flags. */ + xtensa_immed_encode_fn encode; /* Encode the operand value. */ + xtensa_immed_decode_fn decode; /* Decode the value from the field. */ + xtensa_do_reloc_fn do_reloc; /* Perform a PC-relative reloc. */ + xtensa_undo_reloc_fn undo_reloc; /* Undo a PC-relative relocation. */ +} xtensa_operand_internal; + +typedef struct xtensa_arg_internal_struct { + union { + int operand_id; /* For normal operands. */ + xtensa_state state; /* For stateOperands. */ + } u; + char inout; /* Direction: 'i', 'o', or 'm'. */ +} xtensa_arg_internal; + +typedef struct xtensa_iclass_internal_struct { + int num_operands; /* Size of "operands" array. */ + xtensa_arg_internal *operands; /* Array[num_operands]. */ + + int num_stateOperands; /* Size of "stateOperands" array. */ + xtensa_arg_internal *stateOperands; /* Array[num_stateOperands]. */ + + int num_interfaceOperands; /* Size of "interfaceOperands". */ + xtensa_interface *interfaceOperands; /* Array[num_interfaceOperands]. */ +} xtensa_iclass_internal; + +typedef struct xtensa_opcode_internal_struct { + const char *name; /* Opcode mnemonic. */ + int iclass_id; /* Iclass for this opcode. */ + uint32_t flags; /* See XTENSA_OPCODE_* flags. */ + xtensa_opcode_encode_fn *encode_fns; /* Array[slot_id]. */ + int num_funcUnit_uses; /* Number of funcUnit_use entries. */ + xtensa_funcUnit_use *funcUnit_uses; /* Array[num_funcUnit_uses]. */ +} xtensa_opcode_internal; + +typedef struct xtensa_regfile_internal_struct { + const char *name; /* Full name of the regfile. */ + const char *shortname; /* Abbreviated name. */ + xtensa_regfile parent; /* View parent (or identity). */ + int num_bits; /* Width of the registers. */ + int num_entries; /* Number of registers. */ +} xtensa_regfile_internal; + +typedef struct xtensa_interface_internal_struct { + const char *name; /* Interface name. */ + int num_bits; /* Width of the interface. */ + uint32_t flags; /* See XTENSA_INTERFACE_* flags. */ + int class_id; /* Class of related interfaces. */ + char inout; /* "i" or "o". */ +} xtensa_interface_internal; + +typedef struct xtensa_funcUnit_internal_struct { + const char *name; /* Functional unit name. */ + int num_copies; /* Number of instances. */ +} xtensa_funcUnit_internal; + +typedef struct xtensa_state_internal_struct { + const char *name; /* State name. */ + int num_bits; /* Number of state bits. */ + uint32_t flags; /* See XTENSA_STATE_* flags. */ +} xtensa_state_internal; + +typedef struct xtensa_sysreg_internal_struct { + const char *name; /* Register name. */ + int number; /* Register number. */ + int is_user; /* Non-zero if a "user register". */ +} xtensa_sysreg_internal; + +typedef struct xtensa_lookup_entry_struct { + const char *key; + union { + xtensa_opcode opcode; /* Internal opcode number. */ + xtensa_sysreg sysreg; /* Internal sysreg number. */ + xtensa_state state; /* Internal state number. */ + xtensa_interface intf; /* Internal interface number. */ + xtensa_funcUnit fun; /* Internal funcUnit number. */ + } u; +} xtensa_lookup_entry; + +typedef struct xtensa_isa_internal_struct { + int is_big_endian; /* Endianness. */ + int insn_size; /* Maximum length in bytes. */ + int insnbuf_size; /* Number of insnbuf_words. */ + + int num_formats; + xtensa_format_internal *formats; + xtensa_format_decode_fn format_decode_fn; + xtensa_length_decode_fn length_decode_fn; + + int num_slots; + xtensa_slot_internal *slots; + + int num_fields; + + int num_operands; + xtensa_operand_internal *operands; + + int num_iclasses; + xtensa_iclass_internal *iclasses; + + int num_opcodes; + xtensa_opcode_internal *opcodes; + xtensa_lookup_entry *opname_lookup_table; + + int num_regfiles; + xtensa_regfile_internal *regfiles; + + int num_states; + xtensa_state_internal *states; + xtensa_lookup_entry *state_lookup_table; + + int num_sysregs; + xtensa_sysreg_internal *sysregs; + xtensa_lookup_entry *sysreg_lookup_table; + + /* + * The current Xtensa ISA only supports 256 of each kind of sysreg so + * we can get away with implementing lookups with tables indexed by + * the register numbers. If we ever allow larger sysreg numbers, this + * may have to be reimplemented. The first entry in the following + * arrays corresponds to "special" registers and the second to "user" + * registers. + */ + int max_sysreg_num[2]; + xtensa_sysreg *sysreg_table[2]; + + int num_interfaces; + xtensa_interface_internal *interfaces; + xtensa_lookup_entry *interface_lookup_table; + + int num_funcUnits; + xtensa_funcUnit_internal *funcUnits; + xtensa_lookup_entry *funcUnit_lookup_table; + + int num_stages; /* Number of pipe stages. */ +} xtensa_isa_internal; + +int xtensa_isa_name_compare(const void *, const void *); + +extern xtensa_isa_status xtisa_errno; +extern char xtisa_error_msg[]; + +#endif /* !XTENSA_ISA_INTERNAL_H */ diff --git a/target/xtensa/xtensa-isa.c b/target/xtensa/xtensa-isa.c new file mode 100644 index 0000000000..e0076a694f --- /dev/null +++ b/target/xtensa/xtensa-isa.c @@ -0,0 +1,1745 @@ +/* Configurable Xtensa ISA support. + * + * Copyright (c) 2001-2011 Tensilica Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "xtensa-isa.h" +#include "xtensa-isa-internal.h" + +xtensa_isa_status xtisa_errno; +char xtisa_error_msg[1024]; + + +xtensa_isa_status xtensa_isa_errno(xtensa_isa isa __attribute__ ((unused))) +{ + return xtisa_errno; +} + + +char *xtensa_isa_error_msg(xtensa_isa isa __attribute__ ((unused))) +{ + return xtisa_error_msg; +} + + +#define CHECK_ALLOC(MEM, ERRVAL) \ + do { \ + if ((MEM) == 0) { \ + xtisa_errno = xtensa_isa_out_of_memory; \ + strcpy(xtisa_error_msg, "out of memory"); \ + return ERRVAL; \ + } \ + } while (0) + +#define CHECK_ALLOC_FOR_INIT(MEM, ERRVAL, ERRNO_P, ERROR_MSG_P) \ + do { \ + if ((MEM) == 0) { \ + xtisa_errno = xtensa_isa_out_of_memory; \ + strcpy(xtisa_error_msg, "out of memory"); \ + if (ERRNO_P) { \ + *(ERRNO_P) = xtisa_errno; \ + } \ + if (ERROR_MSG_P) { \ + *(ERROR_MSG_P) = xtisa_error_msg; \ + } \ + return ERRVAL; \ + } \ + } while (0) + + +/* Instruction buffers. */ + +int xtensa_insnbuf_size(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->insnbuf_size; +} + + +xtensa_insnbuf xtensa_insnbuf_alloc(xtensa_isa isa) +{ + xtensa_insnbuf result = (xtensa_insnbuf) + malloc(xtensa_insnbuf_size(isa) * sizeof(xtensa_insnbuf_word)); + + CHECK_ALLOC(result, 0); + return result; +} + + +void xtensa_insnbuf_free(xtensa_isa isa __attribute__ ((unused)), + xtensa_insnbuf buf) +{ + free(buf); +} + + +/* + * Given , the index of a byte in a xtensa_insnbuf, our + * internal representation of a xtensa instruction word, return the index of + * its word and the bit index of its low order byte in the xtensa_insnbuf. + */ + +static inline int byte_to_word_index(int byte_index) +{ + return byte_index / sizeof(xtensa_insnbuf_word); +} + + +static inline int byte_to_bit_index(int byte_index) +{ + return (byte_index & 0x3) * 8; +} + + +/* + * Copy an instruction in the 32-bit words pointed at by "insn" to + * characters pointed at by "cp". This is more complicated than you + * might think because we want 16-bit instructions in bytes 2 & 3 for + * big-endian configurations. This function allows us to specify + * which byte in "insn" to start with and which way to increment, + * allowing trivial implementation for both big- and little-endian + * configurations....and it seems to make pretty good code for + * both. + */ + +int xtensa_insnbuf_to_chars(xtensa_isa isa, + const xtensa_insnbuf insn, + unsigned char *cp, + int num_chars) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int insn_size = xtensa_isa_maxlength(isa); + int fence_post, start, increment, i, byte_count; + xtensa_format fmt; + + if (num_chars == 0) { + num_chars = insn_size; + } + + if (intisa->is_big_endian) { + start = insn_size - 1; + increment = -1; + } else { + start = 0; + increment = 1; + } + + /* + * Find the instruction format. Do nothing if the buffer does not contain + * a valid instruction since we need to know how many bytes to copy. + */ + fmt = xtensa_format_decode(isa, insn); + if (fmt == XTENSA_UNDEFINED) { + return XTENSA_UNDEFINED; + } + + byte_count = xtensa_format_length(isa, fmt); + if (byte_count == XTENSA_UNDEFINED) { + return XTENSA_UNDEFINED; + } + + if (byte_count > num_chars) { + xtisa_errno = xtensa_isa_buffer_overflow; + strcpy(xtisa_error_msg, "output buffer too small for instruction"); + return XTENSA_UNDEFINED; + } + + fence_post = start + (byte_count * increment); + + for (i = start; i != fence_post; i += increment, ++cp) { + int word_inx = byte_to_word_index(i); + int bit_inx = byte_to_bit_index(i); + + *cp = (insn[word_inx] >> bit_inx) & 0xff; + } + + return byte_count; +} + + +/* + * Inward conversion from byte stream to xtensa_insnbuf. See + * xtensa_insnbuf_to_chars for a discussion of why this is complicated + * by endianness. + */ + +void xtensa_insnbuf_from_chars(xtensa_isa isa, + xtensa_insnbuf insn, + const unsigned char *cp, + int num_chars) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int max_size, insn_size, fence_post, start, increment, i; + + max_size = xtensa_isa_maxlength(isa); + + /* Decode the instruction length so we know how many bytes to read. */ + insn_size = (intisa->length_decode_fn)(cp); + if (insn_size == XTENSA_UNDEFINED) { + /* + * This should never happen when the byte stream contains a + * valid instruction. Just read the maximum number of bytes.... + */ + insn_size = max_size; + } + + if (num_chars == 0 || num_chars > insn_size) { + num_chars = insn_size; + } + + if (intisa->is_big_endian) { + start = max_size - 1; + increment = -1; + } else { + start = 0; + increment = 1; + } + + fence_post = start + (num_chars * increment); + memset(insn, 0, xtensa_insnbuf_size(isa) * sizeof(xtensa_insnbuf_word)); + + for (i = start; i != fence_post; i += increment, ++cp) { + int word_inx = byte_to_word_index(i); + int bit_inx = byte_to_bit_index(i); + + insn[word_inx] |= (*cp & 0xff) << bit_inx; + } +} + + +/* ISA information. */ + +xtensa_isa xtensa_isa_init(void *xtensa_modules, xtensa_isa_status *errno_p, + char **error_msg_p) +{ + xtensa_isa_internal *isa = xtensa_modules; + int n, is_user; + + /* Set up the opcode name lookup table. */ + isa->opname_lookup_table = + malloc(isa->num_opcodes * sizeof(xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT(isa->opname_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_opcodes; n++) { + isa->opname_lookup_table[n].key = isa->opcodes[n].name; + isa->opname_lookup_table[n].u.opcode = n; + } + qsort(isa->opname_lookup_table, isa->num_opcodes, + sizeof(xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the state name lookup table. */ + isa->state_lookup_table = + malloc(isa->num_states * sizeof(xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT(isa->state_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_states; n++) { + isa->state_lookup_table[n].key = isa->states[n].name; + isa->state_lookup_table[n].u.state = n; + } + qsort(isa->state_lookup_table, isa->num_states, + sizeof(xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the sysreg name lookup table. */ + isa->sysreg_lookup_table = + malloc(isa->num_sysregs * sizeof(xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT(isa->sysreg_lookup_table, NULL, errno_p, error_msg_p); + for (n = 0; n < isa->num_sysregs; n++) { + isa->sysreg_lookup_table[n].key = isa->sysregs[n].name; + isa->sysreg_lookup_table[n].u.sysreg = n; + } + qsort(isa->sysreg_lookup_table, isa->num_sysregs, + sizeof(xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the user & system sysreg number tables. */ + for (is_user = 0; is_user < 2; is_user++) { + isa->sysreg_table[is_user] = + malloc((isa->max_sysreg_num[is_user] + 1) * sizeof(xtensa_sysreg)); + CHECK_ALLOC_FOR_INIT(isa->sysreg_table[is_user], NULL, + errno_p, error_msg_p); + + for (n = 0; n <= isa->max_sysreg_num[is_user]; n++) { + isa->sysreg_table[is_user][n] = XTENSA_UNDEFINED; + } + } + for (n = 0; n < isa->num_sysregs; n++) { + xtensa_sysreg_internal *sreg = &isa->sysregs[n]; + is_user = sreg->is_user; + + if (sreg->number >= 0) { + isa->sysreg_table[is_user][sreg->number] = n; + } + } + + /* Set up the interface lookup table. */ + isa->interface_lookup_table = + malloc(isa->num_interfaces * sizeof(xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT(isa->interface_lookup_table, NULL, errno_p, + error_msg_p); + for (n = 0; n < isa->num_interfaces; n++) { + isa->interface_lookup_table[n].key = isa->interfaces[n].name; + isa->interface_lookup_table[n].u.intf = n; + } + qsort(isa->interface_lookup_table, isa->num_interfaces, + sizeof(xtensa_lookup_entry), xtensa_isa_name_compare); + + /* Set up the funcUnit lookup table. */ + isa->funcUnit_lookup_table = + malloc(isa->num_funcUnits * sizeof(xtensa_lookup_entry)); + CHECK_ALLOC_FOR_INIT(isa->funcUnit_lookup_table, NULL, errno_p, + error_msg_p); + for (n = 0; n < isa->num_funcUnits; n++) { + isa->funcUnit_lookup_table[n].key = isa->funcUnits[n].name; + isa->funcUnit_lookup_table[n].u.fun = n; + } + qsort(isa->funcUnit_lookup_table, isa->num_funcUnits, + sizeof(xtensa_lookup_entry), xtensa_isa_name_compare); + + isa->insnbuf_size = ((isa->insn_size + sizeof(xtensa_insnbuf_word) - 1) / + sizeof(xtensa_insnbuf_word)); + isa->num_stages = XTENSA_UNDEFINED; + + return (xtensa_isa)isa; +} + + +void xtensa_isa_free(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int n; + + /* + * With this version of the code, the xtensa_isa structure is not + * dynamically allocated, so this function is not essential. Free + * the memory allocated by xtensa_isa_init and restore the xtensa_isa + * structure to its initial state. + */ + + if (intisa->opname_lookup_table) { + free(intisa->opname_lookup_table); + intisa->opname_lookup_table = 0; + } + + if (intisa->state_lookup_table) { + free(intisa->state_lookup_table); + intisa->state_lookup_table = 0; + } + + if (intisa->sysreg_lookup_table) { + free(intisa->sysreg_lookup_table); + intisa->sysreg_lookup_table = 0; + } + for (n = 0; n < 2; n++) { + if (intisa->sysreg_table[n]) { + free(intisa->sysreg_table[n]); + intisa->sysreg_table[n] = 0; + } + } + + if (intisa->interface_lookup_table) { + free(intisa->interface_lookup_table); + intisa->interface_lookup_table = 0; + } + + if (intisa->funcUnit_lookup_table) { + free(intisa->funcUnit_lookup_table); + intisa->funcUnit_lookup_table = 0; + } +} + + +int xtensa_isa_name_compare(const void *v1, const void *v2) +{ + xtensa_lookup_entry *e1 = (xtensa_lookup_entry *)v1; + xtensa_lookup_entry *e2 = (xtensa_lookup_entry *)v2; + + return strcasecmp(e1->key, e2->key); +} + + +int xtensa_isa_maxlength(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->insn_size; +} + + +int xtensa_isa_length_from_chars(xtensa_isa isa, const unsigned char *cp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return (intisa->length_decode_fn)(cp); +} + + +int xtensa_isa_num_pipe_stages(xtensa_isa isa) +{ + xtensa_opcode opcode; + xtensa_funcUnit_use *use; + int num_opcodes, num_uses; + int i, stage, max_stage; + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + /* Only compute the value once. */ + if (intisa->num_stages != XTENSA_UNDEFINED) { + return intisa->num_stages; + } + + max_stage = -1; + + num_opcodes = xtensa_isa_num_opcodes(isa); + for (opcode = 0; opcode < num_opcodes; opcode++) { + num_uses = xtensa_opcode_num_funcUnit_uses(isa, opcode); + for (i = 0; i < num_uses; i++) { + use = xtensa_opcode_funcUnit_use(isa, opcode, i); + stage = use->stage; + if (stage > max_stage) { + max_stage = stage; + } + } + } + + intisa->num_stages = max_stage + 1; + return intisa->num_states; +} + + +int xtensa_isa_num_formats(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_formats; +} + + +int xtensa_isa_num_opcodes(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_opcodes; +} + + +int xtensa_isa_num_regfiles(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_regfiles; +} + + +int xtensa_isa_num_states(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_states; +} + + +int xtensa_isa_num_sysregs(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_sysregs; +} + + +int xtensa_isa_num_interfaces(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_interfaces; +} + + +int xtensa_isa_num_funcUnits(xtensa_isa isa) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + return intisa->num_funcUnits; +} + + +/* Instruction formats. */ + + +#define CHECK_FORMAT(INTISA, FMT, ERRVAL) \ + do { \ + if ((FMT) < 0 || (FMT) >= (INTISA)->num_formats) { \ + xtisa_errno = xtensa_isa_bad_format; \ + strcpy(xtisa_error_msg, "invalid format specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +#define CHECK_SLOT(INTISA, FMT, SLOT, ERRVAL) \ + do { \ + if ((SLOT) < 0 || (SLOT) >= (INTISA)->formats[FMT].num_slots) { \ + xtisa_errno = xtensa_isa_bad_slot; \ + strcpy(xtisa_error_msg, "invalid slot specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +const char *xtensa_format_name(xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FORMAT(intisa, fmt, NULL); + return intisa->formats[fmt].name; +} + + +xtensa_format xtensa_format_lookup(xtensa_isa isa, const char *fmtname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int fmt; + + if (!fmtname || !*fmtname) { + xtisa_errno = xtensa_isa_bad_format; + strcpy(xtisa_error_msg, "invalid format name"); + return XTENSA_UNDEFINED; + } + + for (fmt = 0; fmt < intisa->num_formats; fmt++) { + if (strcasecmp(fmtname, intisa->formats[fmt].name) == 0) { + return fmt; + } + } + + xtisa_errno = xtensa_isa_bad_format; + sprintf(xtisa_error_msg, "format \"%s\" not recognized", fmtname); + return XTENSA_UNDEFINED; +} + + +xtensa_format xtensa_format_decode(xtensa_isa isa, const xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_format fmt; + + fmt = (intisa->format_decode_fn)(insn); + if (fmt != XTENSA_UNDEFINED) { + return fmt; + } + + xtisa_errno = xtensa_isa_bad_format; + strcpy(xtisa_error_msg, "cannot decode instruction format"); + return XTENSA_UNDEFINED; +} + + +int xtensa_format_encode(xtensa_isa isa, xtensa_format fmt, + xtensa_insnbuf insn) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FORMAT(intisa, fmt, -1); + (*intisa->formats[fmt].encode_fn)(insn); + return 0; +} + + +int xtensa_format_length(xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FORMAT(intisa, fmt, XTENSA_UNDEFINED); + return intisa->formats[fmt].length; +} + + +int xtensa_format_num_slots(xtensa_isa isa, xtensa_format fmt) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FORMAT(intisa, fmt, XTENSA_UNDEFINED); + return intisa->formats[fmt].num_slots; +} + + +xtensa_opcode xtensa_format_slot_nop_opcode(xtensa_isa isa, xtensa_format fmt, + int slot) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int slot_id; + + CHECK_FORMAT(intisa, fmt, XTENSA_UNDEFINED); + CHECK_SLOT(intisa, fmt, slot, XTENSA_UNDEFINED); + + slot_id = intisa->formats[fmt].slot_id[slot]; + return xtensa_opcode_lookup(isa, intisa->slots[slot_id].nop_name); +} + + +int xtensa_format_get_slot(xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf insn, xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int slot_id; + + CHECK_FORMAT(intisa, fmt, -1); + CHECK_SLOT(intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + (*intisa->slots[slot_id].get_fn)(insn, slotbuf); + return 0; +} + + +int xtensa_format_set_slot(xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf insn, const xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int slot_id; + + CHECK_FORMAT(intisa, fmt, -1); + CHECK_SLOT(intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + (*intisa->slots[slot_id].set_fn)(insn, slotbuf); + return 0; +} + + +/* Opcode information. */ + + +#define CHECK_OPCODE(INTISA, OPC, ERRVAL) \ + do { \ + if ((OPC) < 0 || (OPC) >= (INTISA)->num_opcodes) { \ + xtisa_errno = xtensa_isa_bad_opcode; \ + strcpy(xtisa_error_msg, "invalid opcode specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_opcode xtensa_opcode_lookup(xtensa_isa isa, const char *opname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_lookup_entry entry, *result = 0; + + if (!opname || !*opname) { + xtisa_errno = xtensa_isa_bad_opcode; + strcpy(xtisa_error_msg, "invalid opcode name"); + return XTENSA_UNDEFINED; + } + + if (intisa->num_opcodes != 0) { + entry.key = opname; + result = bsearch(&entry, intisa->opname_lookup_table, + intisa->num_opcodes, sizeof(xtensa_lookup_entry), + xtensa_isa_name_compare); + } + + if (!result) { + xtisa_errno = xtensa_isa_bad_opcode; + sprintf(xtisa_error_msg, "opcode \"%s\" not recognized", opname); + return XTENSA_UNDEFINED; + } + + return result->u.opcode; +} + + +xtensa_opcode xtensa_opcode_decode(xtensa_isa isa, xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int slot_id; + xtensa_opcode opc; + + CHECK_FORMAT(intisa, fmt, XTENSA_UNDEFINED); + CHECK_SLOT(intisa, fmt, slot, XTENSA_UNDEFINED); + + slot_id = intisa->formats[fmt].slot_id[slot]; + + opc = (intisa->slots[slot_id].opcode_decode_fn) (slotbuf); + if (opc != XTENSA_UNDEFINED) { + return opc; + } + + xtisa_errno = xtensa_isa_bad_opcode; + strcpy(xtisa_error_msg, "cannot decode opcode"); + return XTENSA_UNDEFINED; +} + + +int xtensa_opcode_encode(xtensa_isa isa, xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int slot_id; + xtensa_opcode_encode_fn encode_fn; + + CHECK_FORMAT(intisa, fmt, -1); + CHECK_SLOT(intisa, fmt, slot, -1); + CHECK_OPCODE(intisa, opc, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + encode_fn = intisa->opcodes[opc].encode_fns[slot_id]; + if (!encode_fn) { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf(xtisa_error_msg, + "opcode \"%s\" is not allowed in slot %d of format \"%s\"", + intisa->opcodes[opc].name, slot, intisa->formats[fmt].name); + return -1; + } + (*encode_fn)(slotbuf); + return 0; +} + + +const char *xtensa_opcode_name(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, NULL); + return intisa->opcodes[opc].name; +} + + +int xtensa_opcode_is_branch(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_BRANCH) != 0) { + return 1; + } + return 0; +} + + +int xtensa_opcode_is_jump(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_JUMP) != 0) { + return 1; + } + return 0; +} + + +int xtensa_opcode_is_loop(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_LOOP) != 0) { + return 1; + } + return 0; +} + + +int xtensa_opcode_is_call(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + if ((intisa->opcodes[opc].flags & XTENSA_OPCODE_IS_CALL) != 0) { + return 1; + } + return 0; +} + + +int xtensa_opcode_num_operands(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int iclass_id; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_operands; +} + + +int xtensa_opcode_num_stateOperands(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int iclass_id; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_stateOperands; +} + + +int xtensa_opcode_num_interfaceOperands(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int iclass_id; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + return intisa->iclasses[iclass_id].num_interfaceOperands; +} + + +int xtensa_opcode_num_funcUnit_uses(xtensa_isa isa, xtensa_opcode opc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + return intisa->opcodes[opc].num_funcUnit_uses; +} + + +xtensa_funcUnit_use *xtensa_opcode_funcUnit_use(xtensa_isa isa, + xtensa_opcode opc, int u) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_OPCODE(intisa, opc, NULL); + if (u < 0 || u >= intisa->opcodes[opc].num_funcUnit_uses) { + xtisa_errno = xtensa_isa_bad_funcUnit; + sprintf(xtisa_error_msg, "invalid functional unit use number (%d); " + "opcode \"%s\" has %d", u, intisa->opcodes[opc].name, + intisa->opcodes[opc].num_funcUnit_uses); + return NULL; + } + return &intisa->opcodes[opc].funcUnit_uses[u]; +} + + +/* Operand information. */ + + +#define CHECK_OPERAND(INTISA, OPC, ICLASS, OPND, ERRVAL) \ + do { \ + if ((OPND) < 0 || (OPND) >= (ICLASS)->num_operands) { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf(xtisa_error_msg, "invalid operand number (%d); " \ + "opcode \"%s\" has %d operands", (OPND), \ + (INTISA)->opcodes[(OPC)].name, (ICLASS)->num_operands); \ + return ERRVAL; \ + } \ + } while (0) + + +static xtensa_operand_internal *get_operand(xtensa_isa_internal *intisa, + xtensa_opcode opc, int opnd) +{ + xtensa_iclass_internal *iclass; + int iclass_id, operand_id; + + CHECK_OPCODE(intisa, opc, NULL); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND(intisa, opc, iclass, opnd, NULL); + operand_id = iclass->operands[opnd].u.operand_id; + return &intisa->operands[operand_id]; +} + + +const char *xtensa_operand_name(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return NULL; + } + return intop->name; +} + + +int xtensa_operand_is_visible(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_iclass_internal *iclass; + int iclass_id, operand_id; + xtensa_operand_internal *intop; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND(intisa, opc, iclass, opnd, XTENSA_UNDEFINED); + + /* Special case for "sout" operands. */ + if (iclass->operands[opnd].inout == 's') { + return 0; + } + + operand_id = iclass->operands[opnd].u.operand_id; + intop = &intisa->operands[operand_id]; + + if ((intop->flags & XTENSA_OPERAND_IS_INVISIBLE) == 0) { + return 1; + } + return 0; +} + + +char xtensa_operand_inout(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_iclass_internal *iclass; + int iclass_id; + char inout; + + CHECK_OPCODE(intisa, opc, 0); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_OPERAND(intisa, opc, iclass, opnd, 0); + inout = iclass->operands[opnd].inout; + + /* Special case for "sout" and "_sin" operands. */ + if (inout == 's') { + return 'o'; + } + if (inout == 't') { + return 'i'; + } + return inout; +} + + +int xtensa_operand_get_field(xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + const xtensa_insnbuf slotbuf, uint32_t *valp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + int slot_id; + xtensa_get_field_fn get_fn; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + CHECK_FORMAT(intisa, fmt, -1); + CHECK_SLOT(intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + if (intop->field_id == XTENSA_UNDEFINED) { + xtisa_errno = xtensa_isa_no_field; + strcpy(xtisa_error_msg, "implicit operand has no field"); + return -1; + } + get_fn = intisa->slots[slot_id].get_field_fns[intop->field_id]; + if (!get_fn) { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf(xtisa_error_msg, + "operand \"%s\" does not exist in slot %d of format \"%s\"", + intop->name, slot, intisa->formats[fmt].name); + return -1; + } + *valp = (*get_fn)(slotbuf); + return 0; +} + + +int xtensa_operand_set_field(xtensa_isa isa, xtensa_opcode opc, int opnd, + xtensa_format fmt, int slot, + xtensa_insnbuf slotbuf, uint32_t val) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + int slot_id; + xtensa_set_field_fn set_fn; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + CHECK_FORMAT(intisa, fmt, -1); + CHECK_SLOT(intisa, fmt, slot, -1); + + slot_id = intisa->formats[fmt].slot_id[slot]; + if (intop->field_id == XTENSA_UNDEFINED) { + xtisa_errno = xtensa_isa_no_field; + strcpy(xtisa_error_msg, "implicit operand has no field"); + return -1; + } + set_fn = intisa->slots[slot_id].set_field_fns[intop->field_id]; + if (!set_fn) { + xtisa_errno = xtensa_isa_wrong_slot; + sprintf(xtisa_error_msg, + "operand \"%s\" does not exist in slot %d of format \"%s\"", + intop->name, slot, intisa->formats[fmt].name); + return -1; + } + (*set_fn)(slotbuf, val); + return 0; +} + + +int xtensa_operand_encode(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + uint32_t test_val, orig_val; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + if (!intop->encode) { + /* + * This is a default operand for a field. How can we tell if the + * value fits in the field? Write the value into the field, + * read it back, and then make sure we get the same value. + */ + static xtensa_insnbuf tmpbuf; + int slot_id; + + if (!tmpbuf) { + tmpbuf = xtensa_insnbuf_alloc(isa); + CHECK_ALLOC(tmpbuf, -1); + } + + /* + * A default operand is always associated with a field, + * but check just to be sure.... + */ + if (intop->field_id == XTENSA_UNDEFINED) { + xtisa_errno = xtensa_isa_internal_error; + strcpy(xtisa_error_msg, "operand has no field"); + return -1; + } + + /* Find some slot that includes the field. */ + for (slot_id = 0; slot_id < intisa->num_slots; slot_id++) { + xtensa_get_field_fn get_fn = + intisa->slots[slot_id].get_field_fns[intop->field_id]; + xtensa_set_field_fn set_fn = + intisa->slots[slot_id].set_field_fns[intop->field_id]; + + if (get_fn && set_fn) { + (*set_fn)(tmpbuf, *valp); + return (*get_fn)(tmpbuf) != *valp; + } + } + + /* Couldn't find any slot containing the field.... */ + xtisa_errno = xtensa_isa_no_field; + strcpy(xtisa_error_msg, "field does not exist in any slot"); + return -1; + } + + /* + * Encode the value. In some cases, the encoding function may detect + * errors, but most of the time the only way to determine if the value + * was successfully encoded is to decode it and check if it matches + * the original value. + */ + orig_val = *valp; + if ((*intop->encode)(valp) || + (test_val = *valp, (*intop->decode)(&test_val)) || + test_val != orig_val) { + xtisa_errno = xtensa_isa_bad_value; + sprintf(xtisa_error_msg, "cannot encode operand value 0x%08x", *valp); + return -1; + } + + return 0; +} + + +int xtensa_operand_decode(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + /* Use identity function for "default" operands. */ + if (!intop->decode) { + return 0; + } + + if ((*intop->decode)(valp)) { + xtisa_errno = xtensa_isa_bad_value; + sprintf(xtisa_error_msg, "cannot decode operand value 0x%08x", *valp); + return -1; + } + return 0; +} + + +int xtensa_operand_is_register(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return XTENSA_UNDEFINED; + } + + if ((intop->flags & XTENSA_OPERAND_IS_REGISTER) != 0) { + return 1; + } + return 0; +} + + +xtensa_regfile xtensa_operand_regfile(xtensa_isa isa, xtensa_opcode opc, + int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return XTENSA_UNDEFINED; + } + + return intop->regfile; +} + + +int xtensa_operand_num_regs(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return XTENSA_UNDEFINED; + } + + return intop->num_regs; +} + + +int xtensa_operand_is_known_reg(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return XTENSA_UNDEFINED; + } + + if ((intop->flags & XTENSA_OPERAND_IS_UNKNOWN) == 0) { + return 1; + } + return 0; +} + + +int xtensa_operand_is_PCrelative(xtensa_isa isa, xtensa_opcode opc, int opnd) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return XTENSA_UNDEFINED; + } + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) != 0) { + return 1; + } + return 0; +} + + +int xtensa_operand_do_reloc(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp, uint32_t pc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0) { + return 0; + } + + if (!intop->do_reloc) { + xtisa_errno = xtensa_isa_internal_error; + strcpy(xtisa_error_msg, "operand missing do_reloc function"); + return -1; + } + + if ((*intop->do_reloc)(valp, pc)) { + xtisa_errno = xtensa_isa_bad_value; + sprintf(xtisa_error_msg, + "do_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc); + return -1; + } + + return 0; +} + + +int xtensa_operand_undo_reloc(xtensa_isa isa, xtensa_opcode opc, int opnd, + uint32_t *valp, uint32_t pc) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_operand_internal *intop; + + intop = get_operand(intisa, opc, opnd); + if (!intop) { + return -1; + } + + if ((intop->flags & XTENSA_OPERAND_IS_PCRELATIVE) == 0) { + return 0; + } + + if (!intop->undo_reloc) { + xtisa_errno = xtensa_isa_internal_error; + strcpy(xtisa_error_msg, "operand missing undo_reloc function"); + return -1; + } + + if ((*intop->undo_reloc)(valp, pc)) { + xtisa_errno = xtensa_isa_bad_value; + sprintf(xtisa_error_msg, + "undo_reloc failed for value 0x%08x at PC 0x%08x", *valp, pc); + return -1; + } + + return 0; +} + + +/* State Operands. */ + + +#define CHECK_STATE_OPERAND(INTISA, OPC, ICLASS, STOP, ERRVAL) \ + do { \ + if ((STOP) < 0 || (STOP) >= (ICLASS)->num_stateOperands) { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf(xtisa_error_msg, "invalid state operand number (%d); " \ + "opcode \"%s\" has %d state operands", (STOP), \ + (INTISA)->opcodes[(OPC)].name, \ + (ICLASS)->num_stateOperands); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_state xtensa_stateOperand_state(xtensa_isa isa, xtensa_opcode opc, + int stOp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_STATE_OPERAND(intisa, opc, iclass, stOp, XTENSA_UNDEFINED); + return iclass->stateOperands[stOp].u.state; +} + + +char xtensa_stateOperand_inout(xtensa_isa isa, xtensa_opcode opc, int stOp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE(intisa, opc, 0); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_STATE_OPERAND(intisa, opc, iclass, stOp, 0); + return iclass->stateOperands[stOp].inout; +} + + +/* Interface Operands. */ + + +#define CHECK_INTERFACE_OPERAND(INTISA, OPC, ICLASS, IFOP, ERRVAL) \ + do { \ + if ((IFOP) < 0 || (IFOP) >= (ICLASS)->num_interfaceOperands) { \ + xtisa_errno = xtensa_isa_bad_operand; \ + sprintf(xtisa_error_msg, \ + "invalid interface operand number (%d); " \ + "opcode \"%s\" has %d interface operands", (IFOP), \ + (INTISA)->opcodes[(OPC)].name, \ + (ICLASS)->num_interfaceOperands); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_interface xtensa_interfaceOperand_interface(xtensa_isa isa, + xtensa_opcode opc, + int ifOp) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_iclass_internal *iclass; + int iclass_id; + + CHECK_OPCODE(intisa, opc, XTENSA_UNDEFINED); + iclass_id = intisa->opcodes[opc].iclass_id; + iclass = &intisa->iclasses[iclass_id]; + CHECK_INTERFACE_OPERAND(intisa, opc, iclass, ifOp, XTENSA_UNDEFINED); + return iclass->interfaceOperands[ifOp]; +} + + +/* Register Files. */ + + +#define CHECK_REGFILE(INTISA, RF, ERRVAL) \ + do { \ + if ((RF) < 0 || (RF) >= (INTISA)->num_regfiles) { \ + xtisa_errno = xtensa_isa_bad_regfile; \ + strcpy(xtisa_error_msg, "invalid regfile specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_regfile xtensa_regfile_lookup(xtensa_isa isa, const char *name) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int n; + + if (!name || !*name) { + xtisa_errno = xtensa_isa_bad_regfile; + strcpy(xtisa_error_msg, "invalid regfile name"); + return XTENSA_UNDEFINED; + } + + /* The expected number of regfiles is small; use a linear search. */ + for (n = 0; n < intisa->num_regfiles; n++) { + if (!strcmp(intisa->regfiles[n].name, name)) { + return n; + } + } + + xtisa_errno = xtensa_isa_bad_regfile; + sprintf(xtisa_error_msg, "regfile \"%s\" not recognized", name); + return XTENSA_UNDEFINED; +} + + +xtensa_regfile xtensa_regfile_lookup_shortname(xtensa_isa isa, + const char *shortname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + int n; + + if (!shortname || !*shortname) { + xtisa_errno = xtensa_isa_bad_regfile; + strcpy(xtisa_error_msg, "invalid regfile shortname"); + return XTENSA_UNDEFINED; + } + + /* The expected number of regfiles is small; use a linear search. */ + for (n = 0; n < intisa->num_regfiles; n++) { + /* + * Ignore regfile views since they always have the same shortnames + * as their parents. + */ + if (intisa->regfiles[n].parent != n) { + continue; + } + if (!strcmp(intisa->regfiles[n].shortname, shortname)) { + return n; + } + } + + xtisa_errno = xtensa_isa_bad_regfile; + sprintf(xtisa_error_msg, "regfile shortname \"%s\" not recognized", + shortname); + return XTENSA_UNDEFINED; +} + + +const char *xtensa_regfile_name(xtensa_isa isa, xtensa_regfile rf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_REGFILE(intisa, rf, NULL); + return intisa->regfiles[rf].name; +} + + +const char *xtensa_regfile_shortname(xtensa_isa isa, xtensa_regfile rf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_REGFILE(intisa, rf, NULL); + return intisa->regfiles[rf].shortname; +} + + +xtensa_regfile xtensa_regfile_view_parent(xtensa_isa isa, xtensa_regfile rf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_REGFILE(intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].parent; +} + + +int xtensa_regfile_num_bits(xtensa_isa isa, xtensa_regfile rf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_REGFILE(intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].num_bits; +} + + +int xtensa_regfile_num_entries(xtensa_isa isa, xtensa_regfile rf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_REGFILE(intisa, rf, XTENSA_UNDEFINED); + return intisa->regfiles[rf].num_entries; +} + + +/* Processor States. */ + + +#define CHECK_STATE(INTISA, ST, ERRVAL) \ + do { \ + if ((ST) < 0 || (ST) >= (INTISA)->num_states) { \ + xtisa_errno = xtensa_isa_bad_state; \ + strcpy(xtisa_error_msg, "invalid state specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_state xtensa_state_lookup(xtensa_isa isa, const char *name) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_lookup_entry entry, *result = 0; + + if (!name || !*name) { + xtisa_errno = xtensa_isa_bad_state; + strcpy(xtisa_error_msg, "invalid state name"); + return XTENSA_UNDEFINED; + } + + if (intisa->num_states != 0) { + entry.key = name; + result = bsearch(&entry, intisa->state_lookup_table, + intisa->num_states, sizeof(xtensa_lookup_entry), + xtensa_isa_name_compare); + } + + if (!result) { + xtisa_errno = xtensa_isa_bad_state; + sprintf(xtisa_error_msg, "state \"%s\" not recognized", name); + return XTENSA_UNDEFINED; + } + + return result->u.state; +} + + +const char *xtensa_state_name(xtensa_isa isa, xtensa_state st) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_STATE(intisa, st, NULL); + return intisa->states[st].name; +} + + +int xtensa_state_num_bits(xtensa_isa isa, xtensa_state st) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_STATE(intisa, st, XTENSA_UNDEFINED); + return intisa->states[st].num_bits; +} + + +int xtensa_state_is_exported(xtensa_isa isa, xtensa_state st) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_STATE(intisa, st, XTENSA_UNDEFINED); + if ((intisa->states[st].flags & XTENSA_STATE_IS_EXPORTED) != 0) { + return 1; + } + return 0; +} + + +int xtensa_state_is_shared_or(xtensa_isa isa, xtensa_state st) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_STATE(intisa, st, XTENSA_UNDEFINED); + if ((intisa->states[st].flags & XTENSA_STATE_IS_SHARED_OR) != 0) { + return 1; + } + return 0; +} + + +/* Sysregs. */ + + +#define CHECK_SYSREG(INTISA, SYSREG, ERRVAL) \ + do { \ + if ((SYSREG) < 0 || (SYSREG) >= (INTISA)->num_sysregs) { \ + xtisa_errno = xtensa_isa_bad_sysreg; \ + strcpy(xtisa_error_msg, "invalid sysreg specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_sysreg xtensa_sysreg_lookup(xtensa_isa isa, int num, int is_user) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + if (is_user != 0) { + is_user = 1; + } + + if (num < 0 || num > intisa->max_sysreg_num[is_user] || + intisa->sysreg_table[is_user][num] == XTENSA_UNDEFINED) { + xtisa_errno = xtensa_isa_bad_sysreg; + strcpy(xtisa_error_msg, "sysreg not recognized"); + return XTENSA_UNDEFINED; + } + + return intisa->sysreg_table[is_user][num]; +} + + +xtensa_sysreg xtensa_sysreg_lookup_name(xtensa_isa isa, const char *name) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_lookup_entry entry, *result = 0; + + if (!name || !*name) { + xtisa_errno = xtensa_isa_bad_sysreg; + strcpy(xtisa_error_msg, "invalid sysreg name"); + return XTENSA_UNDEFINED; + } + + if (intisa->num_sysregs != 0) { + entry.key = name; + result = bsearch(&entry, intisa->sysreg_lookup_table, + intisa->num_sysregs, sizeof(xtensa_lookup_entry), + xtensa_isa_name_compare); + } + + if (!result) { + xtisa_errno = xtensa_isa_bad_sysreg; + sprintf(xtisa_error_msg, "sysreg \"%s\" not recognized", name); + return XTENSA_UNDEFINED; + } + + return result->u.sysreg; +} + + +const char *xtensa_sysreg_name(xtensa_isa isa, xtensa_sysreg sysreg) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_SYSREG(intisa, sysreg, NULL); + return intisa->sysregs[sysreg].name; +} + + +int xtensa_sysreg_number(xtensa_isa isa, xtensa_sysreg sysreg) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_SYSREG(intisa, sysreg, XTENSA_UNDEFINED); + return intisa->sysregs[sysreg].number; +} + + +int xtensa_sysreg_is_user(xtensa_isa isa, xtensa_sysreg sysreg) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_SYSREG(intisa, sysreg, XTENSA_UNDEFINED); + if (intisa->sysregs[sysreg].is_user) { + return 1; + } + return 0; +} + + +/* Interfaces. */ + + +#define CHECK_INTERFACE(INTISA, INTF, ERRVAL) \ + do { \ + if ((INTF) < 0 || (INTF) >= (INTISA)->num_interfaces) { \ + xtisa_errno = xtensa_isa_bad_interface; \ + strcpy(xtisa_error_msg, "invalid interface specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_interface xtensa_interface_lookup(xtensa_isa isa, const char *ifname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_lookup_entry entry, *result = 0; + + if (!ifname || !*ifname) { + xtisa_errno = xtensa_isa_bad_interface; + strcpy(xtisa_error_msg, "invalid interface name"); + return XTENSA_UNDEFINED; + } + + if (intisa->num_interfaces != 0) { + entry.key = ifname; + result = bsearch(&entry, intisa->interface_lookup_table, + intisa->num_interfaces, sizeof(xtensa_lookup_entry), + xtensa_isa_name_compare); + } + + if (!result) { + xtisa_errno = xtensa_isa_bad_interface; + sprintf(xtisa_error_msg, "interface \"%s\" not recognized", ifname); + return XTENSA_UNDEFINED; + } + + return result->u.intf; +} + + +const char *xtensa_interface_name(xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_INTERFACE(intisa, intf, NULL); + return intisa->interfaces[intf].name; +} + + +int xtensa_interface_num_bits(xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_INTERFACE(intisa, intf, XTENSA_UNDEFINED); + return intisa->interfaces[intf].num_bits; +} + + +char xtensa_interface_inout(xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_INTERFACE(intisa, intf, 0); + return intisa->interfaces[intf].inout; +} + + +int xtensa_interface_has_side_effect(xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_INTERFACE(intisa, intf, XTENSA_UNDEFINED); + if ((intisa->interfaces[intf].flags & + XTENSA_INTERFACE_HAS_SIDE_EFFECT) != 0) { + return 1; + } + return 0; +} + + +int xtensa_interface_class_id(xtensa_isa isa, xtensa_interface intf) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_INTERFACE(intisa, intf, XTENSA_UNDEFINED); + return intisa->interfaces[intf].class_id; +} + + +/* Functional Units. */ + + +#define CHECK_FUNCUNIT(INTISA, FUN, ERRVAL) \ + do { \ + if ((FUN) < 0 || (FUN) >= (INTISA)->num_funcUnits) { \ + xtisa_errno = xtensa_isa_bad_funcUnit; \ + strcpy(xtisa_error_msg, "invalid functional unit specifier"); \ + return ERRVAL; \ + } \ + } while (0) + + +xtensa_funcUnit xtensa_funcUnit_lookup(xtensa_isa isa, const char *fname) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + xtensa_lookup_entry entry, *result = 0; + + if (!fname || !*fname) { + xtisa_errno = xtensa_isa_bad_funcUnit; + strcpy(xtisa_error_msg, "invalid functional unit name"); + return XTENSA_UNDEFINED; + } + + if (intisa->num_funcUnits != 0) { + entry.key = fname; + result = bsearch(&entry, intisa->funcUnit_lookup_table, + intisa->num_funcUnits, sizeof(xtensa_lookup_entry), + xtensa_isa_name_compare); + } + + if (!result) { + xtisa_errno = xtensa_isa_bad_funcUnit; + sprintf(xtisa_error_msg, + "functional unit \"%s\" not recognized", fname); + return XTENSA_UNDEFINED; + } + + return result->u.fun; +} + + +const char *xtensa_funcUnit_name(xtensa_isa isa, xtensa_funcUnit fun) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FUNCUNIT(intisa, fun, NULL); + return intisa->funcUnits[fun].name; +} + + +int xtensa_funcUnit_num_copies(xtensa_isa isa, xtensa_funcUnit fun) +{ + xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa; + + CHECK_FUNCUNIT(intisa, fun, XTENSA_UNDEFINED); + return intisa->funcUnits[fun].num_copies; +} diff --git a/target/xtensa/xtensa-isa.h b/target/xtensa/xtensa-isa.h new file mode 100644 index 0000000000..d06614c187 --- /dev/null +++ b/target/xtensa/xtensa-isa.h @@ -0,0 +1 @@ +#include From 168c12b024704400c3398d22e762c9018b6f33be Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 18:29:27 -0700 Subject: [PATCH 246/546] target/xtensa: extract core opcode translators Move implementations of core opcodes into separate translation functions. Introduce data structures for mapping opcode name to translator function. Make an array of core opcode/translator structures. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 24 + target/xtensa/translate.c | 3121 +++++++++++++++++++++++++++++++++++++ 2 files changed, 3145 insertions(+) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index b17d7d96e9..d8f4034626 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -37,6 +37,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" #include "fpu/softfloat.h" +#include "xtensa-isa.h" #define NB_MMU_MODES 4 @@ -205,6 +206,8 @@ enum { #define MEMCTL_DSNP 0x2 #define MEMCTL_IL0EN 0x1 +#define MAX_INSN_LENGTH 64 +#define MAX_OPCODE_ARGS 16 #define MAX_NAREG 64 #define MAX_NINTERRUPT 32 #define MAX_NLEVEL 6 @@ -330,6 +333,23 @@ typedef struct XtensaMemory { } location[MAX_NMEMORY]; } XtensaMemory; +typedef struct DisasContext DisasContext; +typedef void (*XtensaOpcodeOp)(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]); + +typedef struct XtensaOpcodeOps { + const char *name; + XtensaOpcodeOp translate; + const uint32_t *par; +} XtensaOpcodeOps; + +typedef struct XtensaOpcodeTranslators { + unsigned num_opcodes; + const XtensaOpcodeOps *opcode; +} XtensaOpcodeTranslators; + +extern const XtensaOpcodeTranslators xtensa_core_opcodes; + struct XtensaConfig { const char *name; uint64_t options; @@ -370,6 +390,8 @@ struct XtensaConfig { uint32_t configid[2]; + void *isa_internal; + uint32_t clock_freq_khz; xtensa_tlb itlb; @@ -522,6 +544,8 @@ static inline void xtensa_select_static_vectors(CPUXtensaState *env, env->static_vectors = n; } void xtensa_runstall(CPUXtensaState *env, bool runstall); +XtensaOpcodeOps *xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t, + const char *opcode); #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) #define XTENSA_OPTION_ALL (~(uint64_t)0) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 225e4a5fe8..1c227380a6 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -75,6 +75,8 @@ typedef struct DisasContext { TCGv_i32 next_icount; unsigned cpenable; + + uint32_t *raw_arg; } DisasContext; static TCGv_i32 cpu_pc; @@ -3312,3 +3314,3122 @@ void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, { env->pc = data[0]; } + +static int compare_opcode_ops(const void *a, const void *b) +{ + return strcmp((const char *)a, + ((const XtensaOpcodeOps *)b)->name); +} + +XtensaOpcodeOps * +xtensa_find_opcode_ops(const XtensaOpcodeTranslators *t, + const char *name) +{ + XtensaOpcodeOps *ops; + + ops = bsearch(name, t->opcode, t->num_opcodes, + sizeof(XtensaOpcodeOps), compare_opcode_ops); + return ops; +} + +static void translate_abs(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 neg = tcg_temp_new_i32(); + + tcg_gen_neg_i32(neg, cpu_R[arg[1]]); + tcg_gen_movcond_i32(TCG_COND_GE, cpu_R[arg[0]], + cpu_R[arg[1]], zero, cpu_R[arg[1]], neg); + tcg_temp_free(neg); + tcg_temp_free(zero); + } +} + +static void translate_add(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_add_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_addi(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_addi_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + } +} + +static void translate_addx(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[arg[1]], par[0]); + tcg_gen_add_i32(cpu_R[arg[0]], tmp, cpu_R[arg[2]]); + tcg_temp_free(tmp); + } +} + +static void translate_all(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + uint32_t shift = par[1]; + TCGv_i32 mask = tcg_const_i32(((1 << shift) - 1) << arg[1]); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_and_i32(tmp, cpu_SR[BR], mask); + if (par[0]) { + tcg_gen_addi_i32(tmp, tmp, 1 << arg[1]); + } else { + tcg_gen_add_i32(tmp, tmp, mask); + } + tcg_gen_shri_i32(tmp, tmp, arg[1] + shift); + tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], + tmp, arg[0], 1); + tcg_temp_free(mask); + tcg_temp_free(tmp); +} + +static void translate_and(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_and_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_ball(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_and_i32(tmp, cpu_R[arg[0]], cpu_R[arg[1]]); + gen_brcond(dc, par[0], tmp, cpu_R[arg[1]], arg[2]); + tcg_temp_free(tmp); + } +} + +static void translate_bany(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_and_i32(tmp, cpu_R[arg[0]], cpu_R[arg[1]]); + gen_brcondi(dc, par[0], tmp, 0, arg[2]); + tcg_temp_free(tmp); + } +} + +static void translate_b(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + gen_brcond(dc, par[0], cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + } +} + +static void translate_bb(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { +#ifdef TARGET_WORDS_BIGENDIAN + TCGv_i32 bit = tcg_const_i32(0x80000000u); +#else + TCGv_i32 bit = tcg_const_i32(0x00000001u); +#endif + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_andi_i32(tmp, cpu_R[arg[1]], 0x1f); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_shr_i32(bit, bit, tmp); +#else + tcg_gen_shl_i32(bit, bit, tmp); +#endif + tcg_gen_and_i32(tmp, cpu_R[arg[0]], bit); + gen_brcondi(dc, par[0], tmp, 0, arg[2]); + tcg_temp_free(tmp); + tcg_temp_free(bit); + } +} + +static void translate_bbi(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = tcg_temp_new_i32(); +#ifdef TARGET_WORDS_BIGENDIAN + tcg_gen_andi_i32(tmp, cpu_R[arg[0]], 0x80000000u >> arg[1]); +#else + tcg_gen_andi_i32(tmp, cpu_R[arg[0]], 0x00000001u << arg[1]); +#endif + gen_brcondi(dc, par[0], tmp, 0, arg[2]); + tcg_temp_free(tmp); + } +} + +static void translate_bi(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + gen_brcondi(dc, par[0], cpu_R[arg[0]], arg[1], arg[2]); + } +} + +static void translate_bz(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + gen_brcondi(dc, par[0], cpu_R[arg[0]], 0, arg[1]); + } +} + +enum { + BOOLEAN_AND, + BOOLEAN_ANDC, + BOOLEAN_OR, + BOOLEAN_ORC, + BOOLEAN_XOR, +}; + +static void translate_boolean(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + static void (* const op[])(TCGv_i32, TCGv_i32, TCGv_i32) = { + [BOOLEAN_AND] = tcg_gen_and_i32, + [BOOLEAN_ANDC] = tcg_gen_andc_i32, + [BOOLEAN_OR] = tcg_gen_or_i32, + [BOOLEAN_ORC] = tcg_gen_orc_i32, + [BOOLEAN_XOR] = tcg_gen_xor_i32, + }; + + TCGv_i32 tmp1 = tcg_temp_new_i32(); + TCGv_i32 tmp2 = tcg_temp_new_i32(); + + tcg_gen_shri_i32(tmp1, cpu_SR[BR], arg[1]); + tcg_gen_shri_i32(tmp2, cpu_SR[BR], arg[2]); + op[par[0]](tmp1, tmp1, tmp2); + tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, arg[0], 1); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); +} + +static void translate_bp(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[0]); + gen_brcondi(dc, par[0], tmp, 0, arg[1]); + tcg_temp_free(tmp); +} + +static void translate_break(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (dc->debug) { + gen_debug_exception(dc, par[0]); + } +} + +static void translate_call0(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + tcg_gen_movi_i32(cpu_R[0], dc->next_pc); + gen_jumpi(dc, arg[0], 0); +} + +static void translate_callw(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, par[0] << 2)) { + gen_callwi(dc, par[0], arg[0], 0); + } +} + +static void translate_callx0(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); + tcg_gen_movi_i32(cpu_R[0], dc->next_pc); + gen_jump(dc, tmp); + tcg_temp_free(tmp); + } +} + +static void translate_callxw(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], par[0] << 2)) { + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); + gen_callw(dc, par[0], tmp); + tcg_temp_free(tmp); + } +} + +static void translate_clamps(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 tmp1 = tcg_const_i32(-1u << arg[2]); + TCGv_i32 tmp2 = tcg_const_i32((1 << arg[2]) - 1); + + tcg_gen_movcond_i32(TCG_COND_GT, tmp1, + cpu_R[arg[1]], tmp1, cpu_R[arg[1]], tmp1); + tcg_gen_movcond_i32(TCG_COND_LT, cpu_R[arg[0]], + tmp1, tmp2, tmp1, tmp2); + tcg_temp_free(tmp1); + tcg_temp_free(tmp2); + } +} + +/* par[0]: privileged, par[1]: check memory access */ +static void translate_dcache(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if ((!par[0] || gen_check_privilege(dc)) && + gen_window_check1(dc, arg[0]) && par[1]) { + TCGv_i32 addr = tcg_temp_new_i32(); + TCGv_i32 res = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[arg[0]], arg[1]); + tcg_gen_qemu_ld8u(res, addr, dc->cring); + tcg_temp_free(addr); + tcg_temp_free(res); + } +} + +static void translate_depbits(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_deposit_i32(cpu_R[arg[1]], cpu_R[arg[1]], cpu_R[arg[0]], + arg[2], arg[3]); + } +} + +static void translate_entry(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + TCGv_i32 pc = tcg_const_i32(dc->pc); + TCGv_i32 s = tcg_const_i32(arg[0]); + TCGv_i32 imm = tcg_const_i32(arg[1]); + gen_helper_entry(cpu_env, pc, s, imm); + tcg_temp_free(imm); + tcg_temp_free(s); + tcg_temp_free(pc); + /* This can change tb->flags, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); +} + +static void translate_extui(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + int maskimm = (1 << arg[3]) - 1; + + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shri_i32(tmp, cpu_R[arg[1]], arg[2]); + tcg_gen_andi_i32(cpu_R[arg[0]], tmp, maskimm); + tcg_temp_free(tmp); + } +} + +/* par[0]: privileged, par[1]: check memory access */ +static void translate_icache(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if ((!par[0] || gen_check_privilege(dc)) && + gen_window_check1(dc, arg[0]) && par[1]) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_movi_i32(cpu_pc, dc->pc); + tcg_gen_addi_i32(addr, cpu_R[arg[0]], arg[1]); + gen_helper_itlb_hit_test(cpu_env, addr); + tcg_temp_free(addr); + } +} + +static void translate_itlb(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check1(dc, arg[0])) { + TCGv_i32 dtlb = tcg_const_i32(par[0]); + + gen_helper_itlb(cpu_env, cpu_R[arg[0]], dtlb); + /* This could change memory mapping, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); + tcg_temp_free(dtlb); + } +} + +static void translate_ill(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +} + +static void translate_j(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + gen_jumpi(dc, arg[0], 0); +} + +static void translate_jx(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + gen_jump(dc, cpu_R[arg[0]]); + } +} + +static void translate_l32e(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + gen_load_store_alignment(dc, 2, addr, false); + tcg_gen_qemu_ld_tl(cpu_R[arg[0]], addr, dc->ring, MO_TEUL); + tcg_temp_free(addr); + } +} + +static void translate_ldst(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + if (par[0] & MO_SIZE) { + gen_load_store_alignment(dc, par[0] & MO_SIZE, addr, par[1]); + } + if (par[2]) { + tcg_gen_qemu_st_tl(cpu_R[arg[0]], addr, dc->cring, par[0]); + } else { + tcg_gen_qemu_ld_tl(cpu_R[arg[0]], addr, dc->cring, par[0]); + } + tcg_temp_free(addr); + } +} + +static void translate_l32r(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = (dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? + tcg_const_i32(dc->raw_arg[1] - 1) : + tcg_const_i32(arg[1]); + + if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { + tcg_gen_add_i32(tmp, tmp, dc->litbase); + } + tcg_gen_qemu_ld32u(cpu_R[arg[0]], tmp, dc->cring); + tcg_temp_free(tmp); + } +} + +static void translate_loop(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + uint32_t lend = arg[1]; + TCGv_i32 tmp = tcg_const_i32(lend); + + tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[arg[0]], 1); + tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc); + gen_helper_wsr_lend(cpu_env, tmp); + tcg_temp_free(tmp); + + if (par[0] != TCG_COND_NEVER) { + TCGLabel *label = gen_new_label(); + tcg_gen_brcondi_i32(par[0], cpu_R[arg[0]], 0, label); + gen_jumpi(dc, lend, 1); + gen_set_label(label); + } + + gen_jumpi(dc, dc->next_pc, 0); + } +} + +enum { + MAC16_UMUL, + MAC16_MUL, + MAC16_MULA, + MAC16_MULS, + MAC16_NONE, +}; + +enum { + MAC16_LL, + MAC16_HL, + MAC16_LH, + MAC16_HH, + + MAC16_HX = 0x1, + MAC16_XH = 0x2, +}; + +enum { + MAC16_AA, + MAC16_AD, + MAC16_DA, + MAC16_DD, + + MAC16_XD = 0x1, + MAC16_DX = 0x2, +}; + +static void translate_mac16(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + int op = par[0]; + bool is_m1_sr = par[1] & MAC16_DX; + bool is_m2_sr = par[1] & MAC16_XD; + unsigned half = par[2]; + uint32_t ld_offset = par[3]; + unsigned off = ld_offset ? 2 : 0; + uint32_t ar[3] = {0}; + unsigned n_ar = 0; + + if (op != MAC16_NONE) { + if (!is_m1_sr) { + ar[n_ar++] = arg[off]; + } + if (!is_m2_sr) { + ar[n_ar++] = arg[off + 1]; + } + } + + if (ld_offset) { + ar[n_ar++] = arg[1]; + } + + if (gen_window_check3(dc, ar[0], ar[1], ar[2])) { + TCGv_i32 vaddr = tcg_temp_new_i32(); + TCGv_i32 mem32 = tcg_temp_new_i32(); + + if (ld_offset) { + tcg_gen_addi_i32(vaddr, cpu_R[arg[1]], ld_offset); + gen_load_store_alignment(dc, 2, vaddr, false); + tcg_gen_qemu_ld32u(mem32, vaddr, dc->cring); + } + if (op != MAC16_NONE) { + TCGv_i32 m1 = gen_mac16_m(is_m1_sr ? + cpu_SR[MR + arg[off]] : + cpu_R[arg[off]], + half & MAC16_HX, op == MAC16_UMUL); + TCGv_i32 m2 = gen_mac16_m(is_m2_sr ? + cpu_SR[MR + arg[off + 1]] : + cpu_R[arg[off + 1]], + half & MAC16_XH, op == MAC16_UMUL); + + if (op == MAC16_MUL || op == MAC16_UMUL) { + tcg_gen_mul_i32(cpu_SR[ACCLO], m1, m2); + if (op == MAC16_UMUL) { + tcg_gen_movi_i32(cpu_SR[ACCHI], 0); + } else { + tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31); + } + } else { + TCGv_i32 lo = tcg_temp_new_i32(); + TCGv_i32 hi = tcg_temp_new_i32(); + + tcg_gen_mul_i32(lo, m1, m2); + tcg_gen_sari_i32(hi, lo, 31); + if (op == MAC16_MULA) { + tcg_gen_add2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], + cpu_SR[ACCLO], cpu_SR[ACCHI], + lo, hi); + } else { + tcg_gen_sub2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], + cpu_SR[ACCLO], cpu_SR[ACCHI], + lo, hi); + } + tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]); + + tcg_temp_free_i32(lo); + tcg_temp_free_i32(hi); + } + tcg_temp_free(m1); + tcg_temp_free(m2); + } + if (ld_offset) { + tcg_gen_mov_i32(cpu_R[arg[1]], vaddr); + tcg_gen_mov_i32(cpu_SR[MR + arg[0]], mem32); + } + tcg_temp_free(vaddr); + tcg_temp_free(mem32); + } +} + +static void translate_minmax(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_movcond_i32(par[0], cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_mov(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_mov_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + } +} + +static void translate_movcond(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i32 zero = tcg_const_i32(0); + + tcg_gen_movcond_i32(par[0], cpu_R[arg[0]], + cpu_R[arg[2]], zero, cpu_R[arg[1]], cpu_R[arg[0]]); + tcg_temp_free(zero); + } +} + +static void translate_movi(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + tcg_gen_movi_i32(cpu_R[arg[0]], arg[1]); + } +} + +static void translate_movp(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]); + tcg_gen_movcond_i32(par[0], + cpu_R[arg[0]], tmp, zero, + cpu_R[arg[1]], cpu_R[arg[0]]); + tcg_temp_free(tmp); + tcg_temp_free(zero); + } +} + +static void translate_movsp(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 pc = tcg_const_i32(dc->pc); + gen_helper_movsp(cpu_env, pc); + tcg_gen_mov_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + tcg_temp_free(pc); + } +} + +static void translate_mul16(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i32 v1 = tcg_temp_new_i32(); + TCGv_i32 v2 = tcg_temp_new_i32(); + + if (par[0]) { + tcg_gen_ext16s_i32(v1, cpu_R[arg[1]]); + tcg_gen_ext16s_i32(v2, cpu_R[arg[2]]); + } else { + tcg_gen_ext16u_i32(v1, cpu_R[arg[1]]); + tcg_gen_ext16u_i32(v2, cpu_R[arg[2]]); + } + tcg_gen_mul_i32(cpu_R[arg[0]], v1, v2); + tcg_temp_free(v2); + tcg_temp_free(v1); + } +} + +static void translate_mull(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_mul_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_mulh(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i32 lo = tcg_temp_new(); + + if (par[0]) { + tcg_gen_muls2_i32(lo, cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } else { + tcg_gen_mulu2_i32(lo, cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } + tcg_temp_free(lo); + } +} + +static void translate_neg(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_neg_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + } +} + +static void translate_nop(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ +} + +static void translate_nsa(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_clrsb_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + } +} + +static void translate_nsau(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_clzi_i32(cpu_R[arg[0]], cpu_R[arg[1]], 32); + } +} + +static void translate_or(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_or_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_ptlb(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 dtlb = tcg_const_i32(par[0]); + + tcg_gen_movi_i32(cpu_pc, dc->pc); + gen_helper_ptlb(cpu_R[arg[0]], cpu_env, cpu_R[arg[1]], dtlb); + tcg_temp_free(dtlb); + } +} + +static void gen_zero_check(DisasContext *dc, const uint32_t arg[]) +{ + TCGLabel *label = gen_new_label(); + + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[2]], 0, label); + gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE); + gen_set_label(label); +} + +static void translate_quos(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGLabel *label1 = gen_new_label(); + TCGLabel *label2 = gen_new_label(); + + gen_zero_check(dc, arg); + + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[1]], 0x80000000, + label1); + tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[arg[2]], 0xffffffff, + label1); + tcg_gen_movi_i32(cpu_R[arg[0]], + par[0] ? 0x80000000 : 0); + tcg_gen_br(label2); + gen_set_label(label1); + if (par[0]) { + tcg_gen_div_i32(cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } else { + tcg_gen_rem_i32(cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } + gen_set_label(label2); + } +} + +static void translate_quou(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + gen_zero_check(dc, arg); + if (par[0]) { + tcg_gen_divu_i32(cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } else { + tcg_gen_remu_i32(cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } + } +} + +static void translate_rer(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + gen_helper_rer(cpu_R[arg[0]], cpu_env, cpu_R[arg[1]]); + } +} + +static void translate_ret(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + gen_jump(dc, cpu_R[0]); +} + +static void translate_retw(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + TCGv_i32 tmp = tcg_const_i32(dc->pc); + gen_helper_retw(tmp, cpu_env, tmp); + gen_jump(dc, tmp); + tcg_temp_free(tmp); +} + +static void translate_rfde(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + gen_jump(dc, cpu_SR[dc->config->ndepc ? DEPC : EPC1]); + } +} + +static void translate_rfe(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); + gen_check_interrupts(dc); + gen_jump(dc, cpu_SR[EPC1]); + } +} + +static void translate_rfi(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + tcg_gen_mov_i32(cpu_SR[PS], cpu_SR[EPS2 + arg[0] - 2]); + gen_check_interrupts(dc); + gen_jump(dc, cpu_SR[EPC1 + arg[0] - 1]); + } +} + +static void translate_rfw(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + TCGv_i32 tmp = tcg_const_i32(1); + + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); + tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]); + + if (par[0]) { + tcg_gen_andc_i32(cpu_SR[WINDOW_START], + cpu_SR[WINDOW_START], tmp); + } else { + tcg_gen_or_i32(cpu_SR[WINDOW_START], + cpu_SR[WINDOW_START], tmp); + } + + gen_helper_restore_owb(cpu_env); + gen_check_interrupts(dc); + gen_jump(dc, cpu_SR[EPC1]); + + tcg_temp_free(tmp); + } +} + +static void translate_rotw(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + TCGv_i32 tmp = tcg_const_i32(arg[0]); + gen_helper_rotw(cpu_env, tmp); + tcg_temp_free(tmp); + /* This can change tb->flags, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); + } +} + +static void translate_rsil(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check1(dc, arg[0])) { + tcg_gen_mov_i32(cpu_R[arg[0]], cpu_SR[PS]); + tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); + tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], arg[1]); + gen_check_interrupts(dc); + gen_jumpi_check_loop_end(dc, 0); + } +} + +static void translate_rsr(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_sr(dc, par[0], SR_R) && + (par[0] < 64 || gen_check_privilege(dc)) && + gen_window_check1(dc, arg[0])) { + if (gen_rsr(dc, cpu_R[arg[0]], par[0])) { + gen_jumpi_check_loop_end(dc, 0); + } + } +} + +static void translate_rtlb(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + static void (* const helper[])(TCGv_i32 r, TCGv_env env, TCGv_i32 a1, + TCGv_i32 a2) = { + gen_helper_rtlb0, + gen_helper_rtlb1, + }; + + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 dtlb = tcg_const_i32(par[0]); + + helper[par[1]](cpu_R[arg[0]], cpu_env, cpu_R[arg[1]], dtlb); + tcg_temp_free(dtlb); + } +} + +static void translate_rur(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + if (uregnames[par[0]].name) { + tcg_gen_mov_i32(cpu_R[arg[0]], cpu_UR[par[0]]); + } else { + qemu_log_mask(LOG_UNIMP, "RUR %d not implemented, ", par[0]); + } + } +} + +static void translate_s32c1i(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + TCGLabel *label = gen_new_label(); + TCGv_i32 tmp = tcg_temp_local_new_i32(); + TCGv_i32 addr = tcg_temp_local_new_i32(); + TCGv_i32 tpc; + + tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); + tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + gen_load_store_alignment(dc, 2, addr, true); + + tpc = tcg_const_i32(dc->pc); + gen_helper_check_atomctl(cpu_env, tpc, addr); + tcg_gen_qemu_ld32u(cpu_R[arg[0]], addr, dc->cring); + tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[arg[0]], + cpu_SR[SCOMPARE1], label); + + tcg_gen_qemu_st32(tmp, addr, dc->cring); + + gen_set_label(label); + tcg_temp_free(tpc); + tcg_temp_free(addr); + tcg_temp_free(tmp); + } +} + +static void translate_s32e(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + gen_load_store_alignment(dc, 2, addr, false); + tcg_gen_qemu_st_tl(cpu_R[arg[0]], addr, dc->ring, MO_TEUL); + tcg_temp_free(addr); + } +} + +static void translate_sext(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + int shift = 31 - arg[2]; + + if (shift == 24) { + tcg_gen_ext8s_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + } else if (shift == 16) { + tcg_gen_ext16s_i32(cpu_R[arg[0]], cpu_R[arg[1]]); + } else { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[arg[1]], shift); + tcg_gen_sari_i32(cpu_R[arg[0]], tmp, shift); + tcg_temp_free(tmp); + } + } +} + +static void translate_simcall(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (semihosting_enabled()) { + if (gen_check_privilege(dc)) { + gen_helper_simcall(cpu_env); + } + } else { + qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + } +} + +/* + * Note: 64 bit ops are used here solely because SAR values + * have range 0..63 + */ +#define gen_shift_reg(cmd, reg) do { \ + TCGv_i64 tmp = tcg_temp_new_i64(); \ + tcg_gen_extu_i32_i64(tmp, reg); \ + tcg_gen_##cmd##_i64(v, v, tmp); \ + tcg_gen_extrl_i64_i32(cpu_R[arg[0]], v); \ + tcg_temp_free_i64(v); \ + tcg_temp_free_i64(tmp); \ + } while (0) + +#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) + +static void translate_sll(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + if (dc->sar_m32_5bit) { + tcg_gen_shl_i32(cpu_R[arg[0]], cpu_R[arg[1]], dc->sar_m32); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + TCGv_i32 s = tcg_const_i32(32); + tcg_gen_sub_i32(s, s, cpu_SR[SAR]); + tcg_gen_andi_i32(s, s, 0x3f); + tcg_gen_extu_i32_i64(v, cpu_R[arg[1]]); + gen_shift_reg(shl, s); + tcg_temp_free(s); + } + } +} + +static void translate_slli(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + if (arg[2] == 32) { + qemu_log_mask(LOG_GUEST_ERROR, "slli a%d, a%d, 32 is undefined", + arg[0], arg[1]); + } + tcg_gen_shli_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2] & 0x1f); + } +} + +static void translate_sra(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + if (dc->sar_m32_5bit) { + tcg_gen_sar_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_SR[SAR]); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_ext_i32_i64(v, cpu_R[arg[1]]); + gen_shift(sar); + } + } +} + +static void translate_srai(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_sari_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + } +} + +static void translate_src(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_concat_i32_i64(v, cpu_R[arg[2]], cpu_R[arg[1]]); + gen_shift(shr); + } +} + +static void translate_srl(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + if (dc->sar_m32_5bit) { + tcg_gen_shr_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_SR[SAR]); + } else { + TCGv_i64 v = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(v, cpu_R[arg[1]]); + gen_shift(shr); + } + } +} + +#undef gen_shift +#undef gen_shift_reg + +static void translate_srli(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + tcg_gen_shri_i32(cpu_R[arg[0]], cpu_R[arg[1]], arg[2]); + } +} + +static void translate_ssa8b(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[arg[0]], 3); + gen_left_shift_sar(dc, tmp); + tcg_temp_free(tmp); + } +} + +static void translate_ssa8l(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[arg[0]], 3); + gen_right_shift_sar(dc, tmp); + tcg_temp_free(tmp); + } +} + +static void translate_ssai(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + TCGv_i32 tmp = tcg_const_i32(arg[0]); + gen_right_shift_sar(dc, tmp); + tcg_temp_free(tmp); +} + +static void translate_ssl(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + gen_left_shift_sar(dc, cpu_R[arg[0]]); + } +} + +static void translate_ssr(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + gen_right_shift_sar(dc, cpu_R[arg[0]]); + } +} + +static void translate_sub(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_sub_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_subx(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_shli_i32(tmp, cpu_R[arg[1]], par[0]); + tcg_gen_sub_i32(cpu_R[arg[0]], tmp, cpu_R[arg[2]]); + tcg_temp_free(tmp); + } +} + +static void translate_syscall(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + gen_exception_cause(dc, SYSCALL_CAUSE); +} + +static void translate_waiti(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc)) { + gen_waiti(dc, arg[0]); + } +} + +static void translate_wtlb(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + TCGv_i32 dtlb = tcg_const_i32(par[0]); + + gen_helper_wtlb(cpu_env, cpu_R[arg[0]], cpu_R[arg[1]], dtlb); + /* This could change memory mapping, so exit tb */ + gen_jumpi_check_loop_end(dc, -1); + tcg_temp_free(dtlb); + } +} + +static void translate_wer(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_privilege(dc) && + gen_window_check2(dc, arg[0], arg[1])) { + gen_helper_wer(cpu_env, cpu_R[arg[0]], cpu_R[arg[1]]); + } +} + +static void translate_wsr(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_sr(dc, par[0], SR_W) && + (par[0] < 64 || gen_check_privilege(dc)) && + gen_window_check1(dc, arg[0])) { + gen_wsr(dc, par[0], cpu_R[arg[0]]); + } +} + +static void translate_wur(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + if (uregnames[par[0]].name) { + gen_wur(par[0], cpu_R[arg[0]]); + } else { + qemu_log_mask(LOG_UNIMP, "WUR %d not implemented, ", par[0]); + } + } +} + +static void translate_xor(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_xor_i32(cpu_R[arg[0]], cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + +static void translate_xsr(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_sr(dc, par[0], SR_X) && + (par[0] < 64 || gen_check_privilege(dc)) && + gen_window_check1(dc, arg[0])) { + TCGv_i32 tmp = tcg_temp_new_i32(); + bool rsr_end, wsr_end; + + tcg_gen_mov_i32(tmp, cpu_R[arg[0]]); + rsr_end = gen_rsr(dc, cpu_R[arg[0]], par[0]); + wsr_end = gen_wsr(dc, par[0], tmp); + tcg_temp_free(tmp); + if (rsr_end && !wsr_end) { + gen_jumpi_check_loop_end(dc, 0); + } + } +} + +static const XtensaOpcodeOps core_ops[] = { + { + .name = "abs", + .translate = translate_abs, + }, { + .name = "add", + .translate = translate_add, + }, { + .name = "add.n", + .translate = translate_add, + }, { + .name = "addi", + .translate = translate_addi, + }, { + .name = "addi.n", + .translate = translate_addi, + }, { + .name = "addmi", + .translate = translate_addi, + }, { + .name = "addx2", + .translate = translate_addx, + .par = (const uint32_t[]){1}, + }, { + .name = "addx4", + .translate = translate_addx, + .par = (const uint32_t[]){2}, + }, { + .name = "addx8", + .translate = translate_addx, + .par = (const uint32_t[]){3}, + }, { + .name = "all4", + .translate = translate_all, + .par = (const uint32_t[]){true, 4}, + }, { + .name = "all8", + .translate = translate_all, + .par = (const uint32_t[]){true, 8}, + }, { + .name = "and", + .translate = translate_and, + }, { + .name = "andb", + .translate = translate_boolean, + .par = (const uint32_t[]){BOOLEAN_AND}, + }, { + .name = "andbc", + .translate = translate_boolean, + .par = (const uint32_t[]){BOOLEAN_ANDC}, + }, { + .name = "any4", + .translate = translate_all, + .par = (const uint32_t[]){false, 4}, + }, { + .name = "any8", + .translate = translate_all, + .par = (const uint32_t[]){false, 8}, + }, { + .name = "ball", + .translate = translate_ball, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "bany", + .translate = translate_bany, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bbc", + .translate = translate_bb, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "bbci", + .translate = translate_bbi, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "bbs", + .translate = translate_bb, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bbsi", + .translate = translate_bbi, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "beq", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "beqi", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "beqz", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "beqz.n", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "bf", + .translate = translate_bp, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "bge", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "bgei", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "bgeu", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_GEU}, + }, { + .name = "bgeui", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_GEU}, + }, { + .name = "bgez", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "blt", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "blti", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "bltu", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "bltui", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "bltz", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "bnall", + .translate = translate_ball, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bne", + .translate = translate_b, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bnei", + .translate = translate_bi, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bnez", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bnez.n", + .translate = translate_bz, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "bnone", + .translate = translate_bany, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "break", + .translate = translate_break, + .par = (const uint32_t[]){DEBUGCAUSE_BI}, + }, { + .name = "break.n", + .translate = translate_break, + .par = (const uint32_t[]){DEBUGCAUSE_BN}, + }, { + .name = "bt", + .translate = translate_bp, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "call0", + .translate = translate_call0, + }, { + .name = "call12", + .translate = translate_callw, + .par = (const uint32_t[]){3}, + }, { + .name = "call4", + .translate = translate_callw, + .par = (const uint32_t[]){1}, + }, { + .name = "call8", + .translate = translate_callw, + .par = (const uint32_t[]){2}, + }, { + .name = "callx0", + .translate = translate_callx0, + }, { + .name = "callx12", + .translate = translate_callxw, + .par = (const uint32_t[]){3}, + }, { + .name = "callx4", + .translate = translate_callxw, + .par = (const uint32_t[]){1}, + }, { + .name = "callx8", + .translate = translate_callxw, + .par = (const uint32_t[]){2}, + }, { + .name = "clamps", + .translate = translate_clamps, + }, { + .name = "depbits", + .translate = translate_depbits, + }, { + .name = "dhi", + .translate = translate_dcache, + .par = (const uint32_t[]){true, true}, + }, { + .name = "dhu", + .translate = translate_dcache, + .par = (const uint32_t[]){true, true}, + }, { + .name = "dhwb", + .translate = translate_dcache, + .par = (const uint32_t[]){false, true}, + }, { + .name = "dhwbi", + .translate = translate_dcache, + .par = (const uint32_t[]){false, true}, + }, { + .name = "dii", + .translate = translate_dcache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "diu", + .translate = translate_dcache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "diwb", + .translate = translate_dcache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "diwbi", + .translate = translate_dcache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "dpfl", + .translate = translate_dcache, + .par = (const uint32_t[]){true, true}, + }, { + .name = "dpfr", + .translate = translate_dcache, + .par = (const uint32_t[]){false, false}, + }, { + .name = "dpfro", + .translate = translate_dcache, + .par = (const uint32_t[]){false, false}, + }, { + .name = "dpfw", + .translate = translate_dcache, + .par = (const uint32_t[]){false, false}, + }, { + .name = "dpfwo", + .translate = translate_dcache, + .par = (const uint32_t[]){false, false}, + }, { + .name = "dsync", + .translate = translate_nop, + }, { + .name = "entry", + .translate = translate_entry, + }, { + .name = "esync", + .translate = translate_nop, + }, { + .name = "excw", + .translate = translate_nop, + }, { + .name = "extui", + .translate = translate_extui, + }, { + .name = "extw", + .translate = translate_nop, + }, { + .name = "idtlb", + .translate = translate_itlb, + .par = (const uint32_t[]){true}, + }, { + .name = "ihi", + .translate = translate_icache, + .par = (const uint32_t[]){false, true}, + }, { + .name = "ihu", + .translate = translate_icache, + .par = (const uint32_t[]){true, true}, + }, { + .name = "iii", + .translate = translate_icache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "iitlb", + .translate = translate_itlb, + .par = (const uint32_t[]){false}, + }, { + .name = "iiu", + .translate = translate_icache, + .par = (const uint32_t[]){true, false}, + }, { + .name = "ill", + .translate = translate_ill, + }, { + .name = "ill.n", + .translate = translate_ill, + }, { + .name = "ipf", + .translate = translate_icache, + .par = (const uint32_t[]){false, false}, + }, { + .name = "ipfl", + .translate = translate_icache, + .par = (const uint32_t[]){true, true}, + }, { + .name = "isync", + .translate = translate_nop, + }, { + .name = "j", + .translate = translate_j, + }, { + .name = "jx", + .translate = translate_jx, + }, { + .name = "l16si", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TESW, false, false}, + }, { + .name = "l16ui", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUW, false, false}, + }, { + .name = "l32ai", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, true, false}, + }, { + .name = "l32e", + .translate = translate_l32e, + }, { + .name = "l32i", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, false, false}, + }, { + .name = "l32i.n", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, false, false}, + }, { + .name = "l32r", + .translate = translate_l32r, + }, { + .name = "l8ui", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_UB, false, false}, + }, { + .name = "lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_NONE, 0, 0, -4}, + }, { + .name = "ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_NONE, 0, 0, 4}, + }, { + .name = "loop", + .translate = translate_loop, + .par = (const uint32_t[]){TCG_COND_NEVER}, + }, { + .name = "loopgtz", + .translate = translate_loop, + .par = (const uint32_t[]){TCG_COND_GT}, + }, { + .name = "loopnez", + .translate = translate_loop, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "max", + .translate = translate_minmax, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "maxu", + .translate = translate_minmax, + .par = (const uint32_t[]){TCG_COND_GEU}, + }, { + .name = "memw", + .translate = translate_nop, + }, { + .name = "min", + .translate = translate_minmax, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "minu", + .translate = translate_minmax, + .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "mov", + .translate = translate_mov, + }, { + .name = "mov.n", + .translate = translate_mov, + }, { + .name = "moveqz", + .translate = translate_movcond, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "movf", + .translate = translate_movp, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "movgez", + .translate = translate_movcond, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "movi", + .translate = translate_movi, + }, { + .name = "movi.n", + .translate = translate_movi, + }, { + .name = "movltz", + .translate = translate_movcond, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "movnez", + .translate = translate_movcond, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "movsp", + .translate = translate_movsp, + }, { + .name = "movt", + .translate = translate_movp, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "mul.aa.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_HH, 0}, + }, { + .name = "mul.aa.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_HL, 0}, + }, { + .name = "mul.aa.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_LH, 0}, + }, { + .name = "mul.aa.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AA, MAC16_LL, 0}, + }, { + .name = "mul.ad.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_HH, 0}, + }, { + .name = "mul.ad.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_HL, 0}, + }, { + .name = "mul.ad.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_LH, 0}, + }, { + .name = "mul.ad.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_AD, MAC16_LL, 0}, + }, { + .name = "mul.da.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_HH, 0}, + }, { + .name = "mul.da.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_HL, 0}, + }, { + .name = "mul.da.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_LH, 0}, + }, { + .name = "mul.da.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DA, MAC16_LL, 0}, + }, { + .name = "mul.dd.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_HH, 0}, + }, { + .name = "mul.dd.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_HL, 0}, + }, { + .name = "mul.dd.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_LH, 0}, + }, { + .name = "mul.dd.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MUL, MAC16_DD, MAC16_LL, 0}, + }, { + .name = "mul16s", + .translate = translate_mul16, + .par = (const uint32_t[]){true}, + }, { + .name = "mul16u", + .translate = translate_mul16, + .par = (const uint32_t[]){false}, + }, { + .name = "mula.aa.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_HH, 0}, + }, { + .name = "mula.aa.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_HL, 0}, + }, { + .name = "mula.aa.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_LH, 0}, + }, { + .name = "mula.aa.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AA, MAC16_LL, 0}, + }, { + .name = "mula.ad.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_HH, 0}, + }, { + .name = "mula.ad.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_HL, 0}, + }, { + .name = "mula.ad.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_LH, 0}, + }, { + .name = "mula.ad.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_AD, MAC16_LL, 0}, + }, { + .name = "mula.da.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, 0}, + }, { + .name = "mula.da.hh.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, -4}, + }, { + .name = "mula.da.hh.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HH, 4}, + }, { + .name = "mula.da.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, 0}, + }, { + .name = "mula.da.hl.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, -4}, + }, { + .name = "mula.da.hl.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_HL, 4}, + }, { + .name = "mula.da.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, 0}, + }, { + .name = "mula.da.lh.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, -4}, + }, { + .name = "mula.da.lh.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LH, 4}, + }, { + .name = "mula.da.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, 0}, + }, { + .name = "mula.da.ll.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, -4}, + }, { + .name = "mula.da.ll.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DA, MAC16_LL, 4}, + }, { + .name = "mula.dd.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, 0}, + }, { + .name = "mula.dd.hh.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, -4}, + }, { + .name = "mula.dd.hh.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HH, 4}, + }, { + .name = "mula.dd.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, 0}, + }, { + .name = "mula.dd.hl.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, -4}, + }, { + .name = "mula.dd.hl.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_HL, 4}, + }, { + .name = "mula.dd.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, 0}, + }, { + .name = "mula.dd.lh.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, -4}, + }, { + .name = "mula.dd.lh.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LH, 4}, + }, { + .name = "mula.dd.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, 0}, + }, { + .name = "mula.dd.ll.lddec", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, -4}, + }, { + .name = "mula.dd.ll.ldinc", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULA, MAC16_DD, MAC16_LL, 4}, + }, { + .name = "mull", + .translate = translate_mull, + }, { + .name = "muls.aa.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_HH, 0}, + }, { + .name = "muls.aa.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_HL, 0}, + }, { + .name = "muls.aa.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_LH, 0}, + }, { + .name = "muls.aa.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AA, MAC16_LL, 0}, + }, { + .name = "muls.ad.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_HH, 0}, + }, { + .name = "muls.ad.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_HL, 0}, + }, { + .name = "muls.ad.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_LH, 0}, + }, { + .name = "muls.ad.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_AD, MAC16_LL, 0}, + }, { + .name = "muls.da.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_HH, 0}, + }, { + .name = "muls.da.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_HL, 0}, + }, { + .name = "muls.da.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_LH, 0}, + }, { + .name = "muls.da.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DA, MAC16_LL, 0}, + }, { + .name = "muls.dd.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_HH, 0}, + }, { + .name = "muls.dd.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_HL, 0}, + }, { + .name = "muls.dd.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_LH, 0}, + }, { + .name = "muls.dd.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_MULS, MAC16_DD, MAC16_LL, 0}, + }, { + .name = "mulsh", + .translate = translate_mulh, + .par = (const uint32_t[]){true}, + }, { + .name = "muluh", + .translate = translate_mulh, + .par = (const uint32_t[]){false}, + }, { + .name = "neg", + .translate = translate_neg, + }, { + .name = "nop", + .translate = translate_nop, + }, { + .name = "nop.n", + .translate = translate_nop, + }, { + .name = "nsa", + .translate = translate_nsa, + }, { + .name = "nsau", + .translate = translate_nsau, + }, { + .name = "or", + .translate = translate_or, + }, { + .name = "orb", + .translate = translate_boolean, + .par = (const uint32_t[]){BOOLEAN_OR}, + }, { + .name = "orbc", + .translate = translate_boolean, + .par = (const uint32_t[]){BOOLEAN_ORC}, + }, { + .name = "pdtlb", + .translate = translate_ptlb, + .par = (const uint32_t[]){true}, + }, { + .name = "pitlb", + .translate = translate_ptlb, + .par = (const uint32_t[]){false}, + }, { + .name = "quos", + .translate = translate_quos, + .par = (const uint32_t[]){true}, + }, { + .name = "quou", + .translate = translate_quou, + .par = (const uint32_t[]){true}, + }, { + .name = "rdtlb0", + .translate = translate_rtlb, + .par = (const uint32_t[]){true, 0}, + }, { + .name = "rdtlb1", + .translate = translate_rtlb, + .par = (const uint32_t[]){true, 1}, + }, { + .name = "rems", + .translate = translate_quos, + .par = (const uint32_t[]){false}, + }, { + .name = "remu", + .translate = translate_quou, + .par = (const uint32_t[]){false}, + }, { + .name = "rer", + .translate = translate_rer, + }, { + .name = "ret", + .translate = translate_ret, + }, { + .name = "ret.n", + .translate = translate_ret, + }, { + .name = "retw", + .translate = translate_retw, + }, { + .name = "retw.n", + .translate = translate_retw, + }, { + .name = "rfde", + .translate = translate_rfde, + }, { + .name = "rfe", + .translate = translate_rfe, + }, { + .name = "rfi", + .translate = translate_rfi, + }, { + .name = "rfwo", + .translate = translate_rfw, + .par = (const uint32_t[]){true}, + }, { + .name = "rfwu", + .translate = translate_rfw, + .par = (const uint32_t[]){false}, + }, { + .name = "ritlb0", + .translate = translate_rtlb, + .par = (const uint32_t[]){false, 0}, + }, { + .name = "ritlb1", + .translate = translate_rtlb, + .par = (const uint32_t[]){false, 1}, + }, { + .name = "rotw", + .translate = translate_rotw, + }, { + .name = "rsil", + .translate = translate_rsil, + }, { + .name = "rsr.176", + .translate = translate_rsr, + .par = (const uint32_t[]){176}, + }, { + .name = "rsr.208", + .translate = translate_rsr, + .par = (const uint32_t[]){208}, + }, { + .name = "rsr.acchi", + .translate = translate_rsr, + .par = (const uint32_t[]){ACCHI}, + }, { + .name = "rsr.acclo", + .translate = translate_rsr, + .par = (const uint32_t[]){ACCLO}, + }, { + .name = "rsr.atomctl", + .translate = translate_rsr, + .par = (const uint32_t[]){ATOMCTL}, + }, { + .name = "rsr.br", + .translate = translate_rsr, + .par = (const uint32_t[]){BR}, + }, { + .name = "rsr.cacheattr", + .translate = translate_rsr, + .par = (const uint32_t[]){CACHEATTR}, + }, { + .name = "rsr.ccompare0", + .translate = translate_rsr, + .par = (const uint32_t[]){CCOMPARE}, + }, { + .name = "rsr.ccompare1", + .translate = translate_rsr, + .par = (const uint32_t[]){CCOMPARE + 1}, + }, { + .name = "rsr.ccompare2", + .translate = translate_rsr, + .par = (const uint32_t[]){CCOMPARE + 2}, + }, { + .name = "rsr.ccount", + .translate = translate_rsr, + .par = (const uint32_t[]){CCOUNT}, + }, { + .name = "rsr.configid0", + .translate = translate_rsr, + .par = (const uint32_t[]){CONFIGID0}, + }, { + .name = "rsr.configid1", + .translate = translate_rsr, + .par = (const uint32_t[]){CONFIGID1}, + }, { + .name = "rsr.cpenable", + .translate = translate_rsr, + .par = (const uint32_t[]){CPENABLE}, + }, { + .name = "rsr.dbreaka0", + .translate = translate_rsr, + .par = (const uint32_t[]){DBREAKA}, + }, { + .name = "rsr.dbreaka1", + .translate = translate_rsr, + .par = (const uint32_t[]){DBREAKA + 1}, + }, { + .name = "rsr.dbreakc0", + .translate = translate_rsr, + .par = (const uint32_t[]){DBREAKC}, + }, { + .name = "rsr.dbreakc1", + .translate = translate_rsr, + .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "rsr.debugcause", + .translate = translate_rsr, + .par = (const uint32_t[]){DEBUGCAUSE}, + }, { + .name = "rsr.depc", + .translate = translate_rsr, + .par = (const uint32_t[]){DEPC}, + }, { + .name = "rsr.dtlbcfg", + .translate = translate_rsr, + .par = (const uint32_t[]){DTLBCFG}, + }, { + .name = "rsr.epc1", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1}, + }, { + .name = "rsr.epc2", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 1}, + }, { + .name = "rsr.epc3", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 2}, + }, { + .name = "rsr.epc4", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 3}, + }, { + .name = "rsr.epc5", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 4}, + }, { + .name = "rsr.epc6", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 5}, + }, { + .name = "rsr.epc7", + .translate = translate_rsr, + .par = (const uint32_t[]){EPC1 + 6}, + }, { + .name = "rsr.eps2", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2}, + }, { + .name = "rsr.eps3", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2 + 1}, + }, { + .name = "rsr.eps4", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2 + 2}, + }, { + .name = "rsr.eps5", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2 + 3}, + }, { + .name = "rsr.eps6", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2 + 4}, + }, { + .name = "rsr.eps7", + .translate = translate_rsr, + .par = (const uint32_t[]){EPS2 + 5}, + }, { + .name = "rsr.exccause", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCCAUSE}, + }, { + .name = "rsr.excsave1", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1}, + }, { + .name = "rsr.excsave2", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 1}, + }, { + .name = "rsr.excsave3", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 2}, + }, { + .name = "rsr.excsave4", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 3}, + }, { + .name = "rsr.excsave5", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 4}, + }, { + .name = "rsr.excsave6", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 5}, + }, { + .name = "rsr.excsave7", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCSAVE1 + 6}, + }, { + .name = "rsr.excvaddr", + .translate = translate_rsr, + .par = (const uint32_t[]){EXCVADDR}, + }, { + .name = "rsr.ibreaka0", + .translate = translate_rsr, + .par = (const uint32_t[]){IBREAKA}, + }, { + .name = "rsr.ibreaka1", + .translate = translate_rsr, + .par = (const uint32_t[]){IBREAKA + 1}, + }, { + .name = "rsr.ibreakenable", + .translate = translate_rsr, + .par = (const uint32_t[]){IBREAKENABLE}, + }, { + .name = "rsr.icount", + .translate = translate_rsr, + .par = (const uint32_t[]){ICOUNT}, + }, { + .name = "rsr.icountlevel", + .translate = translate_rsr, + .par = (const uint32_t[]){ICOUNTLEVEL}, + }, { + .name = "rsr.intclear", + .translate = translate_rsr, + .par = (const uint32_t[]){INTCLEAR}, + }, { + .name = "rsr.intenable", + .translate = translate_rsr, + .par = (const uint32_t[]){INTENABLE}, + }, { + .name = "rsr.interrupt", + .translate = translate_rsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "rsr.intset", + .translate = translate_rsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "rsr.itlbcfg", + .translate = translate_rsr, + .par = (const uint32_t[]){ITLBCFG}, + }, { + .name = "rsr.lbeg", + .translate = translate_rsr, + .par = (const uint32_t[]){LBEG}, + }, { + .name = "rsr.lcount", + .translate = translate_rsr, + .par = (const uint32_t[]){LCOUNT}, + }, { + .name = "rsr.lend", + .translate = translate_rsr, + .par = (const uint32_t[]){LEND}, + }, { + .name = "rsr.litbase", + .translate = translate_rsr, + .par = (const uint32_t[]){LITBASE}, + }, { + .name = "rsr.m0", + .translate = translate_rsr, + .par = (const uint32_t[]){MR}, + }, { + .name = "rsr.m1", + .translate = translate_rsr, + .par = (const uint32_t[]){MR + 1}, + }, { + .name = "rsr.m2", + .translate = translate_rsr, + .par = (const uint32_t[]){MR + 2}, + }, { + .name = "rsr.m3", + .translate = translate_rsr, + .par = (const uint32_t[]){MR + 3}, + }, { + .name = "rsr.memctl", + .translate = translate_rsr, + .par = (const uint32_t[]){MEMCTL}, + }, { + .name = "rsr.misc0", + .translate = translate_rsr, + .par = (const uint32_t[]){MISC}, + }, { + .name = "rsr.misc1", + .translate = translate_rsr, + .par = (const uint32_t[]){MISC + 1}, + }, { + .name = "rsr.misc2", + .translate = translate_rsr, + .par = (const uint32_t[]){MISC + 2}, + }, { + .name = "rsr.misc3", + .translate = translate_rsr, + .par = (const uint32_t[]){MISC + 3}, + }, { + .name = "rsr.prid", + .translate = translate_rsr, + .par = (const uint32_t[]){PRID}, + }, { + .name = "rsr.ps", + .translate = translate_rsr, + .par = (const uint32_t[]){PS}, + }, { + .name = "rsr.ptevaddr", + .translate = translate_rsr, + .par = (const uint32_t[]){PTEVADDR}, + }, { + .name = "rsr.rasid", + .translate = translate_rsr, + .par = (const uint32_t[]){RASID}, + }, { + .name = "rsr.sar", + .translate = translate_rsr, + .par = (const uint32_t[]){SAR}, + }, { + .name = "rsr.scompare1", + .translate = translate_rsr, + .par = (const uint32_t[]){SCOMPARE1}, + }, { + .name = "rsr.vecbase", + .translate = translate_rsr, + .par = (const uint32_t[]){VECBASE}, + }, { + .name = "rsr.windowbase", + .translate = translate_rsr, + .par = (const uint32_t[]){WINDOW_BASE}, + }, { + .name = "rsr.windowstart", + .translate = translate_rsr, + .par = (const uint32_t[]){WINDOW_START}, + }, { + .name = "rsync", + .translate = translate_nop, + }, { + .name = "rur.fcr", + .translate = translate_rur, + .par = (const uint32_t[]){FCR}, + }, { + .name = "rur.fsr", + .translate = translate_rur, + .par = (const uint32_t[]){FSR}, + }, { + .name = "rur.threadptr", + .translate = translate_rur, + .par = (const uint32_t[]){THREADPTR}, + }, { + .name = "s16i", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUW, false, true}, + }, { + .name = "s32c1i", + .translate = translate_s32c1i, + }, { + .name = "s32e", + .translate = translate_s32e, + }, { + .name = "s32i", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, false, true}, + }, { + .name = "s32i.n", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, false, true}, + }, { + .name = "s32nb", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, false, true}, + }, { + .name = "s32ri", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_TEUL, true, true}, + }, { + .name = "s8i", + .translate = translate_ldst, + .par = (const uint32_t[]){MO_UB, false, true}, + }, { + .name = "sext", + .translate = translate_sext, + }, { + .name = "simcall", + .translate = translate_simcall, + }, { + .name = "sll", + .translate = translate_sll, + }, { + .name = "slli", + .translate = translate_slli, + }, { + .name = "sra", + .translate = translate_sra, + }, { + .name = "srai", + .translate = translate_srai, + }, { + .name = "src", + .translate = translate_src, + }, { + .name = "srl", + .translate = translate_srl, + }, { + .name = "srli", + .translate = translate_srli, + }, { + .name = "ssa8b", + .translate = translate_ssa8b, + }, { + .name = "ssa8l", + .translate = translate_ssa8l, + }, { + .name = "ssai", + .translate = translate_ssai, + }, { + .name = "ssl", + .translate = translate_ssl, + }, { + .name = "ssr", + .translate = translate_ssr, + }, { + .name = "sub", + .translate = translate_sub, + }, { + .name = "subx2", + .translate = translate_subx, + .par = (const uint32_t[]){1}, + }, { + .name = "subx4", + .translate = translate_subx, + .par = (const uint32_t[]){2}, + }, { + .name = "subx8", + .translate = translate_subx, + .par = (const uint32_t[]){3}, + }, { + .name = "syscall", + .translate = translate_syscall, + }, { + .name = "umul.aa.hh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_HH, 0}, + }, { + .name = "umul.aa.hl", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_HL, 0}, + }, { + .name = "umul.aa.lh", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_LH, 0}, + }, { + .name = "umul.aa.ll", + .translate = translate_mac16, + .par = (const uint32_t[]){MAC16_UMUL, MAC16_AA, MAC16_LL, 0}, + }, { + .name = "waiti", + .translate = translate_waiti, + }, { + .name = "wdtlb", + .translate = translate_wtlb, + .par = (const uint32_t[]){true}, + }, { + .name = "wer", + .translate = translate_wer, + }, { + .name = "witlb", + .translate = translate_wtlb, + .par = (const uint32_t[]){false}, + }, { + .name = "wsr.176", + .translate = translate_wsr, + .par = (const uint32_t[]){176}, + }, { + .name = "wsr.208", + .translate = translate_wsr, + .par = (const uint32_t[]){208}, + }, { + .name = "wsr.acchi", + .translate = translate_wsr, + .par = (const uint32_t[]){ACCHI}, + }, { + .name = "wsr.acclo", + .translate = translate_wsr, + .par = (const uint32_t[]){ACCLO}, + }, { + .name = "wsr.atomctl", + .translate = translate_wsr, + .par = (const uint32_t[]){ATOMCTL}, + }, { + .name = "wsr.br", + .translate = translate_wsr, + .par = (const uint32_t[]){BR}, + }, { + .name = "wsr.cacheattr", + .translate = translate_wsr, + .par = (const uint32_t[]){CACHEATTR}, + }, { + .name = "wsr.ccompare0", + .translate = translate_wsr, + .par = (const uint32_t[]){CCOMPARE}, + }, { + .name = "wsr.ccompare1", + .translate = translate_wsr, + .par = (const uint32_t[]){CCOMPARE + 1}, + }, { + .name = "wsr.ccompare2", + .translate = translate_wsr, + .par = (const uint32_t[]){CCOMPARE + 2}, + }, { + .name = "wsr.ccount", + .translate = translate_wsr, + .par = (const uint32_t[]){CCOUNT}, + }, { + .name = "wsr.configid0", + .translate = translate_wsr, + .par = (const uint32_t[]){CONFIGID0}, + }, { + .name = "wsr.configid1", + .translate = translate_wsr, + .par = (const uint32_t[]){CONFIGID1}, + }, { + .name = "wsr.cpenable", + .translate = translate_wsr, + .par = (const uint32_t[]){CPENABLE}, + }, { + .name = "wsr.dbreaka0", + .translate = translate_wsr, + .par = (const uint32_t[]){DBREAKA}, + }, { + .name = "wsr.dbreaka1", + .translate = translate_wsr, + .par = (const uint32_t[]){DBREAKA + 1}, + }, { + .name = "wsr.dbreakc0", + .translate = translate_wsr, + .par = (const uint32_t[]){DBREAKC}, + }, { + .name = "wsr.dbreakc1", + .translate = translate_wsr, + .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "wsr.debugcause", + .translate = translate_wsr, + .par = (const uint32_t[]){DEBUGCAUSE}, + }, { + .name = "wsr.depc", + .translate = translate_wsr, + .par = (const uint32_t[]){DEPC}, + }, { + .name = "wsr.dtlbcfg", + .translate = translate_wsr, + .par = (const uint32_t[]){DTLBCFG}, + }, { + .name = "wsr.epc1", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1}, + }, { + .name = "wsr.epc2", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 1}, + }, { + .name = "wsr.epc3", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 2}, + }, { + .name = "wsr.epc4", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 3}, + }, { + .name = "wsr.epc5", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 4}, + }, { + .name = "wsr.epc6", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 5}, + }, { + .name = "wsr.epc7", + .translate = translate_wsr, + .par = (const uint32_t[]){EPC1 + 6}, + }, { + .name = "wsr.eps2", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2}, + }, { + .name = "wsr.eps3", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2 + 1}, + }, { + .name = "wsr.eps4", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2 + 2}, + }, { + .name = "wsr.eps5", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2 + 3}, + }, { + .name = "wsr.eps6", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2 + 4}, + }, { + .name = "wsr.eps7", + .translate = translate_wsr, + .par = (const uint32_t[]){EPS2 + 5}, + }, { + .name = "wsr.exccause", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCCAUSE}, + }, { + .name = "wsr.excsave1", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1}, + }, { + .name = "wsr.excsave2", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 1}, + }, { + .name = "wsr.excsave3", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 2}, + }, { + .name = "wsr.excsave4", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 3}, + }, { + .name = "wsr.excsave5", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 4}, + }, { + .name = "wsr.excsave6", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 5}, + }, { + .name = "wsr.excsave7", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCSAVE1 + 6}, + }, { + .name = "wsr.excvaddr", + .translate = translate_wsr, + .par = (const uint32_t[]){EXCVADDR}, + }, { + .name = "wsr.ibreaka0", + .translate = translate_wsr, + .par = (const uint32_t[]){IBREAKA}, + }, { + .name = "wsr.ibreaka1", + .translate = translate_wsr, + .par = (const uint32_t[]){IBREAKA + 1}, + }, { + .name = "wsr.ibreakenable", + .translate = translate_wsr, + .par = (const uint32_t[]){IBREAKENABLE}, + }, { + .name = "wsr.icount", + .translate = translate_wsr, + .par = (const uint32_t[]){ICOUNT}, + }, { + .name = "wsr.icountlevel", + .translate = translate_wsr, + .par = (const uint32_t[]){ICOUNTLEVEL}, + }, { + .name = "wsr.intclear", + .translate = translate_wsr, + .par = (const uint32_t[]){INTCLEAR}, + }, { + .name = "wsr.intenable", + .translate = translate_wsr, + .par = (const uint32_t[]){INTENABLE}, + }, { + .name = "wsr.interrupt", + .translate = translate_wsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "wsr.intset", + .translate = translate_wsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "wsr.itlbcfg", + .translate = translate_wsr, + .par = (const uint32_t[]){ITLBCFG}, + }, { + .name = "wsr.lbeg", + .translate = translate_wsr, + .par = (const uint32_t[]){LBEG}, + }, { + .name = "wsr.lcount", + .translate = translate_wsr, + .par = (const uint32_t[]){LCOUNT}, + }, { + .name = "wsr.lend", + .translate = translate_wsr, + .par = (const uint32_t[]){LEND}, + }, { + .name = "wsr.litbase", + .translate = translate_wsr, + .par = (const uint32_t[]){LITBASE}, + }, { + .name = "wsr.m0", + .translate = translate_wsr, + .par = (const uint32_t[]){MR}, + }, { + .name = "wsr.m1", + .translate = translate_wsr, + .par = (const uint32_t[]){MR + 1}, + }, { + .name = "wsr.m2", + .translate = translate_wsr, + .par = (const uint32_t[]){MR + 2}, + }, { + .name = "wsr.m3", + .translate = translate_wsr, + .par = (const uint32_t[]){MR + 3}, + }, { + .name = "wsr.memctl", + .translate = translate_wsr, + .par = (const uint32_t[]){MEMCTL}, + }, { + .name = "wsr.misc0", + .translate = translate_wsr, + .par = (const uint32_t[]){MISC}, + }, { + .name = "wsr.misc1", + .translate = translate_wsr, + .par = (const uint32_t[]){MISC + 1}, + }, { + .name = "wsr.misc2", + .translate = translate_wsr, + .par = (const uint32_t[]){MISC + 2}, + }, { + .name = "wsr.misc3", + .translate = translate_wsr, + .par = (const uint32_t[]){MISC + 3}, + }, { + .name = "wsr.prid", + .translate = translate_wsr, + .par = (const uint32_t[]){PRID}, + }, { + .name = "wsr.ps", + .translate = translate_wsr, + .par = (const uint32_t[]){PS}, + }, { + .name = "wsr.ptevaddr", + .translate = translate_wsr, + .par = (const uint32_t[]){PTEVADDR}, + }, { + .name = "wsr.rasid", + .translate = translate_wsr, + .par = (const uint32_t[]){RASID}, + }, { + .name = "wsr.sar", + .translate = translate_wsr, + .par = (const uint32_t[]){SAR}, + }, { + .name = "wsr.scompare1", + .translate = translate_wsr, + .par = (const uint32_t[]){SCOMPARE1}, + }, { + .name = "wsr.vecbase", + .translate = translate_wsr, + .par = (const uint32_t[]){VECBASE}, + }, { + .name = "wsr.windowbase", + .translate = translate_wsr, + .par = (const uint32_t[]){WINDOW_BASE}, + }, { + .name = "wsr.windowstart", + .translate = translate_wsr, + .par = (const uint32_t[]){WINDOW_START}, + }, { + .name = "wur.fcr", + .translate = translate_wur, + .par = (const uint32_t[]){FCR}, + }, { + .name = "wur.fsr", + .translate = translate_wur, + .par = (const uint32_t[]){FSR}, + }, { + .name = "wur.threadptr", + .translate = translate_wur, + .par = (const uint32_t[]){THREADPTR}, + }, { + .name = "xor", + .translate = translate_xor, + }, { + .name = "xorb", + .translate = translate_boolean, + .par = (const uint32_t[]){BOOLEAN_XOR}, + }, { + .name = "xsr.176", + .translate = translate_xsr, + .par = (const uint32_t[]){176}, + }, { + .name = "xsr.208", + .translate = translate_xsr, + .par = (const uint32_t[]){208}, + }, { + .name = "xsr.acchi", + .translate = translate_xsr, + .par = (const uint32_t[]){ACCHI}, + }, { + .name = "xsr.acclo", + .translate = translate_xsr, + .par = (const uint32_t[]){ACCLO}, + }, { + .name = "xsr.atomctl", + .translate = translate_xsr, + .par = (const uint32_t[]){ATOMCTL}, + }, { + .name = "xsr.br", + .translate = translate_xsr, + .par = (const uint32_t[]){BR}, + }, { + .name = "xsr.cacheattr", + .translate = translate_xsr, + .par = (const uint32_t[]){CACHEATTR}, + }, { + .name = "xsr.ccompare0", + .translate = translate_xsr, + .par = (const uint32_t[]){CCOMPARE}, + }, { + .name = "xsr.ccompare1", + .translate = translate_xsr, + .par = (const uint32_t[]){CCOMPARE + 1}, + }, { + .name = "xsr.ccompare2", + .translate = translate_xsr, + .par = (const uint32_t[]){CCOMPARE + 2}, + }, { + .name = "xsr.ccount", + .translate = translate_xsr, + .par = (const uint32_t[]){CCOUNT}, + }, { + .name = "xsr.configid0", + .translate = translate_xsr, + .par = (const uint32_t[]){CONFIGID0}, + }, { + .name = "xsr.configid1", + .translate = translate_xsr, + .par = (const uint32_t[]){CONFIGID1}, + }, { + .name = "xsr.cpenable", + .translate = translate_xsr, + .par = (const uint32_t[]){CPENABLE}, + }, { + .name = "xsr.dbreaka0", + .translate = translate_xsr, + .par = (const uint32_t[]){DBREAKA}, + }, { + .name = "xsr.dbreaka1", + .translate = translate_xsr, + .par = (const uint32_t[]){DBREAKA + 1}, + }, { + .name = "xsr.dbreakc0", + .translate = translate_xsr, + .par = (const uint32_t[]){DBREAKC}, + }, { + .name = "xsr.dbreakc1", + .translate = translate_xsr, + .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "xsr.debugcause", + .translate = translate_xsr, + .par = (const uint32_t[]){DEBUGCAUSE}, + }, { + .name = "xsr.depc", + .translate = translate_xsr, + .par = (const uint32_t[]){DEPC}, + }, { + .name = "xsr.dtlbcfg", + .translate = translate_xsr, + .par = (const uint32_t[]){DTLBCFG}, + }, { + .name = "xsr.epc1", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1}, + }, { + .name = "xsr.epc2", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 1}, + }, { + .name = "xsr.epc3", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 2}, + }, { + .name = "xsr.epc4", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 3}, + }, { + .name = "xsr.epc5", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 4}, + }, { + .name = "xsr.epc6", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 5}, + }, { + .name = "xsr.epc7", + .translate = translate_xsr, + .par = (const uint32_t[]){EPC1 + 6}, + }, { + .name = "xsr.eps2", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2}, + }, { + .name = "xsr.eps3", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2 + 1}, + }, { + .name = "xsr.eps4", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2 + 2}, + }, { + .name = "xsr.eps5", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2 + 3}, + }, { + .name = "xsr.eps6", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2 + 4}, + }, { + .name = "xsr.eps7", + .translate = translate_xsr, + .par = (const uint32_t[]){EPS2 + 5}, + }, { + .name = "xsr.exccause", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCCAUSE}, + }, { + .name = "xsr.excsave1", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1}, + }, { + .name = "xsr.excsave2", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 1}, + }, { + .name = "xsr.excsave3", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 2}, + }, { + .name = "xsr.excsave4", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 3}, + }, { + .name = "xsr.excsave5", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 4}, + }, { + .name = "xsr.excsave6", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 5}, + }, { + .name = "xsr.excsave7", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCSAVE1 + 6}, + }, { + .name = "xsr.excvaddr", + .translate = translate_xsr, + .par = (const uint32_t[]){EXCVADDR}, + }, { + .name = "xsr.ibreaka0", + .translate = translate_xsr, + .par = (const uint32_t[]){IBREAKA}, + }, { + .name = "xsr.ibreaka1", + .translate = translate_xsr, + .par = (const uint32_t[]){IBREAKA + 1}, + }, { + .name = "xsr.ibreakenable", + .translate = translate_xsr, + .par = (const uint32_t[]){IBREAKENABLE}, + }, { + .name = "xsr.icount", + .translate = translate_xsr, + .par = (const uint32_t[]){ICOUNT}, + }, { + .name = "xsr.icountlevel", + .translate = translate_xsr, + .par = (const uint32_t[]){ICOUNTLEVEL}, + }, { + .name = "xsr.intclear", + .translate = translate_xsr, + .par = (const uint32_t[]){INTCLEAR}, + }, { + .name = "xsr.intenable", + .translate = translate_xsr, + .par = (const uint32_t[]){INTENABLE}, + }, { + .name = "xsr.interrupt", + .translate = translate_xsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "xsr.intset", + .translate = translate_xsr, + .par = (const uint32_t[]){INTSET}, + }, { + .name = "xsr.itlbcfg", + .translate = translate_xsr, + .par = (const uint32_t[]){ITLBCFG}, + }, { + .name = "xsr.lbeg", + .translate = translate_xsr, + .par = (const uint32_t[]){LBEG}, + }, { + .name = "xsr.lcount", + .translate = translate_xsr, + .par = (const uint32_t[]){LCOUNT}, + }, { + .name = "xsr.lend", + .translate = translate_xsr, + .par = (const uint32_t[]){LEND}, + }, { + .name = "xsr.litbase", + .translate = translate_xsr, + .par = (const uint32_t[]){LITBASE}, + }, { + .name = "xsr.m0", + .translate = translate_xsr, + .par = (const uint32_t[]){MR}, + }, { + .name = "xsr.m1", + .translate = translate_xsr, + .par = (const uint32_t[]){MR + 1}, + }, { + .name = "xsr.m2", + .translate = translate_xsr, + .par = (const uint32_t[]){MR + 2}, + }, { + .name = "xsr.m3", + .translate = translate_xsr, + .par = (const uint32_t[]){MR + 3}, + }, { + .name = "xsr.memctl", + .translate = translate_xsr, + .par = (const uint32_t[]){MEMCTL}, + }, { + .name = "xsr.misc0", + .translate = translate_xsr, + .par = (const uint32_t[]){MISC}, + }, { + .name = "xsr.misc1", + .translate = translate_xsr, + .par = (const uint32_t[]){MISC + 1}, + }, { + .name = "xsr.misc2", + .translate = translate_xsr, + .par = (const uint32_t[]){MISC + 2}, + }, { + .name = "xsr.misc3", + .translate = translate_xsr, + .par = (const uint32_t[]){MISC + 3}, + }, { + .name = "xsr.prid", + .translate = translate_xsr, + .par = (const uint32_t[]){PRID}, + }, { + .name = "xsr.ps", + .translate = translate_xsr, + .par = (const uint32_t[]){PS}, + }, { + .name = "xsr.ptevaddr", + .translate = translate_xsr, + .par = (const uint32_t[]){PTEVADDR}, + }, { + .name = "xsr.rasid", + .translate = translate_xsr, + .par = (const uint32_t[]){RASID}, + }, { + .name = "xsr.sar", + .translate = translate_xsr, + .par = (const uint32_t[]){SAR}, + }, { + .name = "xsr.scompare1", + .translate = translate_xsr, + .par = (const uint32_t[]){SCOMPARE1}, + }, { + .name = "xsr.vecbase", + .translate = translate_xsr, + .par = (const uint32_t[]){VECBASE}, + }, { + .name = "xsr.windowbase", + .translate = translate_xsr, + .par = (const uint32_t[]){WINDOW_BASE}, + }, { + .name = "xsr.windowstart", + .translate = translate_xsr, + .par = (const uint32_t[]){WINDOW_START}, + }, +}; + +const XtensaOpcodeTranslators xtensa_core_opcodes = { + .num_opcodes = ARRAY_SIZE(core_ops), + .opcode = core_ops, +}; From c04e1692e3aace74018f77f1975fb7fd0bb0eb49 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 19:37:13 -0700 Subject: [PATCH 247/546] target/xtensa: extract FPU2000 opcode translators FPU2000 implements basic single-precision floating point operations and can be replaced with a different implementation, like DFPU or HiFi. Move FPU2000 opcode translators into separate functions and list them in a separate array. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 1 + target/xtensa/translate.c | 374 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 375 insertions(+) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index d8f4034626..9a34cc825e 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -349,6 +349,7 @@ typedef struct XtensaOpcodeTranslators { } XtensaOpcodeTranslators; extern const XtensaOpcodeTranslators xtensa_core_opcodes; +extern const XtensaOpcodeTranslators xtensa_fpu2000_opcodes; struct XtensaConfig { const char *name; diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 1c227380a6..f6a53cdfc2 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -6433,3 +6433,377 @@ const XtensaOpcodeTranslators xtensa_core_opcodes = { .num_opcodes = ARRAY_SIZE(core_ops), .opcode = core_ops, }; + + +static void translate_abs_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_abs_s(cpu_FR[arg[0]], cpu_FR[arg[1]]); + } +} + +static void translate_add_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_add_s(cpu_FR[arg[0]], cpu_env, + cpu_FR[arg[1]], cpu_FR[arg[2]]); + } +} + +enum { + COMPARE_UN, + COMPARE_OEQ, + COMPARE_UEQ, + COMPARE_OLT, + COMPARE_ULT, + COMPARE_OLE, + COMPARE_ULE, +}; + +static void translate_compare_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + static void (* const helper[])(TCGv_env env, TCGv_i32 bit, + TCGv_i32 s, TCGv_i32 t) = { + [COMPARE_UN] = gen_helper_un_s, + [COMPARE_OEQ] = gen_helper_oeq_s, + [COMPARE_UEQ] = gen_helper_ueq_s, + [COMPARE_OLT] = gen_helper_olt_s, + [COMPARE_ULT] = gen_helper_ult_s, + [COMPARE_OLE] = gen_helper_ole_s, + [COMPARE_ULE] = gen_helper_ule_s, + }; + + if (gen_check_cpenable(dc, 0)) { + TCGv_i32 bit = tcg_const_i32(1 << arg[0]); + + helper[par[0]](cpu_env, bit, cpu_FR[arg[1]], cpu_FR[arg[2]]); + tcg_temp_free(bit); + } +} + +static void translate_float_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) { + TCGv_i32 scale = tcg_const_i32(-arg[2]); + + if (par[0]) { + gen_helper_uitof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale); + } else { + gen_helper_itof(cpu_FR[arg[0]], cpu_env, cpu_R[arg[1]], scale); + } + tcg_temp_free(scale); + } +} + +static void translate_ftoi_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0]) && gen_check_cpenable(dc, 0)) { + TCGv_i32 rounding_mode = tcg_const_i32(par[0]); + TCGv_i32 scale = tcg_const_i32(arg[2]); + + if (par[1]) { + gen_helper_ftoui(cpu_R[arg[0]], cpu_FR[arg[1]], + rounding_mode, scale); + } else { + gen_helper_ftoi(cpu_R[arg[0]], cpu_FR[arg[1]], + rounding_mode, scale); + } + tcg_temp_free(rounding_mode); + tcg_temp_free(scale); + } +} + +static void translate_ldsti(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[1]) && gen_check_cpenable(dc, 0)) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_addi_i32(addr, cpu_R[arg[1]], arg[2]); + gen_load_store_alignment(dc, 2, addr, false); + if (par[0]) { + tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring); + } else { + tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring); + } + if (par[1]) { + tcg_gen_mov_i32(cpu_R[arg[1]], addr); + } + tcg_temp_free(addr); + } +} + +static void translate_ldstx(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[1], arg[2]) && gen_check_cpenable(dc, 0)) { + TCGv_i32 addr = tcg_temp_new_i32(); + + tcg_gen_add_i32(addr, cpu_R[arg[1]], cpu_R[arg[2]]); + gen_load_store_alignment(dc, 2, addr, false); + if (par[0]) { + tcg_gen_qemu_st32(cpu_FR[arg[0]], addr, dc->cring); + } else { + tcg_gen_qemu_ld32u(cpu_FR[arg[0]], addr, dc->cring); + } + if (par[1]) { + tcg_gen_mov_i32(cpu_R[arg[1]], addr); + } + tcg_temp_free(addr); + } +} + +static void translate_madd_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_madd_s(cpu_FR[arg[0]], cpu_env, + cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]); + } +} + +static void translate_mov_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_FR[arg[1]]); + } +} + +static void translate_movcond_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[2]) && gen_check_cpenable(dc, 0)) { + TCGv_i32 zero = tcg_const_i32(0); + + tcg_gen_movcond_i32(par[0], cpu_FR[arg[0]], + cpu_R[arg[2]], zero, + cpu_FR[arg[1]], cpu_FR[arg[2]]); + tcg_temp_free(zero); + } +} + +static void translate_movp_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + TCGv_i32 zero = tcg_const_i32(0); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << arg[2]); + tcg_gen_movcond_i32(par[0], + cpu_FR[arg[0]], tmp, zero, + cpu_FR[arg[1]], cpu_FR[arg[0]]); + tcg_temp_free(tmp); + tcg_temp_free(zero); + } +} + +static void translate_mul_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_mul_s(cpu_FR[arg[0]], cpu_env, + cpu_FR[arg[1]], cpu_FR[arg[2]]); + } +} + +static void translate_msub_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_msub_s(cpu_FR[arg[0]], cpu_env, + cpu_FR[arg[0]], cpu_FR[arg[1]], cpu_FR[arg[2]]); + } +} + +static void translate_neg_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_neg_s(cpu_FR[arg[0]], cpu_FR[arg[1]]); + } +} + +static void translate_rfr_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0]) && + gen_check_cpenable(dc, 0)) { + tcg_gen_mov_i32(cpu_R[arg[0]], cpu_FR[arg[1]]); + } +} + +static void translate_sub_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_check_cpenable(dc, 0)) { + gen_helper_sub_s(cpu_FR[arg[0]], cpu_env, + cpu_FR[arg[1]], cpu_FR[arg[2]]); + } +} + +static void translate_wfr_s(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[1]) && + gen_check_cpenable(dc, 0)) { + tcg_gen_mov_i32(cpu_FR[arg[0]], cpu_R[arg[1]]); + } +} + +static const XtensaOpcodeOps fpu2000_ops[] = { + { + .name = "abs.s", + .translate = translate_abs_s, + }, { + .name = "add.s", + .translate = translate_add_s, + }, { + .name = "ceil.s", + .translate = translate_ftoi_s, + .par = (const uint32_t[]){float_round_up, false}, + }, { + .name = "float.s", + .translate = translate_float_s, + .par = (const uint32_t[]){false}, + }, { + .name = "floor.s", + .translate = translate_ftoi_s, + .par = (const uint32_t[]){float_round_down, false}, + }, { + .name = "lsi", + .translate = translate_ldsti, + .par = (const uint32_t[]){false, false}, + }, { + .name = "lsiu", + .translate = translate_ldsti, + .par = (const uint32_t[]){false, true}, + }, { + .name = "lsx", + .translate = translate_ldstx, + .par = (const uint32_t[]){false, false}, + }, { + .name = "lsxu", + .translate = translate_ldstx, + .par = (const uint32_t[]){false, true}, + }, { + .name = "madd.s", + .translate = translate_madd_s, + }, { + .name = "mov.s", + .translate = translate_mov_s, + }, { + .name = "moveqz.s", + .translate = translate_movcond_s, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "movf.s", + .translate = translate_movp_s, + .par = (const uint32_t[]){TCG_COND_EQ}, + }, { + .name = "movgez.s", + .translate = translate_movcond_s, + .par = (const uint32_t[]){TCG_COND_GE}, + }, { + .name = "movltz.s", + .translate = translate_movcond_s, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "movnez.s", + .translate = translate_movcond_s, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "movt.s", + .translate = translate_movp_s, + .par = (const uint32_t[]){TCG_COND_NE}, + }, { + .name = "msub.s", + .translate = translate_msub_s, + }, { + .name = "mul.s", + .translate = translate_mul_s, + }, { + .name = "neg.s", + .translate = translate_neg_s, + }, { + .name = "oeq.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_OEQ}, + }, { + .name = "ole.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_OLE}, + }, { + .name = "olt.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_OLT}, + }, { + .name = "rfr.s", + .translate = translate_rfr_s, + }, { + .name = "round.s", + .translate = translate_ftoi_s, + .par = (const uint32_t[]){float_round_nearest_even, false}, + }, { + .name = "ssi", + .translate = translate_ldsti, + .par = (const uint32_t[]){true, false}, + }, { + .name = "ssiu", + .translate = translate_ldsti, + .par = (const uint32_t[]){true, true}, + }, { + .name = "ssx", + .translate = translate_ldstx, + .par = (const uint32_t[]){true, false}, + }, { + .name = "ssxu", + .translate = translate_ldstx, + .par = (const uint32_t[]){true, true}, + }, { + .name = "sub.s", + .translate = translate_sub_s, + }, { + .name = "trunc.s", + .translate = translate_ftoi_s, + .par = (const uint32_t[]){float_round_to_zero, false}, + }, { + .name = "ueq.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_UEQ}, + }, { + .name = "ufloat.s", + .translate = translate_float_s, + .par = (const uint32_t[]){true}, + }, { + .name = "ule.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_ULE}, + }, { + .name = "ult.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_ULT}, + }, { + .name = "un.s", + .translate = translate_compare_s, + .par = (const uint32_t[]){COMPARE_UN}, + }, { + .name = "utrunc.s", + .translate = translate_ftoi_s, + .par = (const uint32_t[]){float_round_to_zero, true}, + }, { + .name = "wfr.s", + .translate = translate_wfr_s, + }, +}; + +const XtensaOpcodeTranslators xtensa_fpu2000_opcodes = { + .num_opcodes = ARRAY_SIZE(fpu2000_ops), + .opcode = fpu2000_ops, +}; From 2557c3adf07ffcf12316afdbdecedfd260c77853 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 31 Oct 2017 19:14:20 -0700 Subject: [PATCH 248/546] target/xtensa: update import_core.sh script for libisa Extract xtensa-modules.c from the overlay, fix up known issues, include it into the core-$NAME.c. Signed-off-by: Max Filippov --- target/xtensa/import_core.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh index cebb6e9c4c..32255eea9b 100755 --- a/target/xtensa/import_core.sh +++ b/target/xtensa/import_core.sh @@ -23,6 +23,17 @@ tar -xf "$OVERLAY" -C "$TARGET" --strip-components=1 \ --xform='s/core/core-isa/' config/core.h tar -xf "$OVERLAY" -O gdb/xtensa-config.c | \ sed -n '1,/*\//p;/XTREG/,/XTREG_END/p' > "$TARGET"/gdb-config.c +# +# Fix up known issues in the xtensa-modules.c +# +tar -xf "$OVERLAY" -O binutils/xtensa-modules.c | \ + sed -e 's/\(xtensa_opcode_encode_fn.*\[\] =\)/static \1/' \ + -e '/^int num_bypass_groups()/,/}/d' \ + -e '/^int num_bypass_group_chunks()/,/}/d' \ + -e '/^uint32 \*bypass_entry(int i)/,/}/d' \ + -e '/^#include "ansidecl.h"/d' \ + -e '/^Slot_[a-zA-Z0-9_]\+_decode (const xtensa_insnbuf insn)/,/^}/s/^ return 0;$/ return XTENSA_UNDEFINED;/' \ + > "$TARGET"/xtensa-modules.c cat < "${TARGET}.c" #include "qemu/osdep.h" @@ -35,6 +46,9 @@ cat < "${TARGET}.c" #include "core-$NAME/core-isa.h" #include "overlay_tool.h" +#define xtensa_modules xtensa_modules_$NAME +#include "core-$NAME/xtensa-modules.c" + static XtensaConfig $NAME __attribute__((unused)) = { .name = "$NAME", .gdb_regmap = { @@ -42,6 +56,7 @@ static XtensaConfig $NAME __attribute__((unused)) = { #include "core-$NAME/gdb-config.c" } }, + .isa_internal = &xtensa_modules, .clock_freq_khz = $FREQ, DEFAULT_SECTIONS }; From 845a2f5a9f6cfa5375879611b8646e1872fb8d45 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 15:55:17 -0700 Subject: [PATCH 249/546] target/xtensa: switch dc232b to libisa Autogenerated xtensa-modules.c is added by the import_core.sh script. Signed-off-by: Max Filippov --- target/xtensa/core-dc232b.c | 4 + target/xtensa/core-dc232b/xtensa-modules.c | 14105 +++++++++++++++++++ 2 files changed, 14109 insertions(+) create mode 100644 target/xtensa/core-dc232b/xtensa-modules.c diff --git a/target/xtensa/core-dc232b.c b/target/xtensa/core-dc232b.c index bb8ed4197f..fe80582df4 100644 --- a/target/xtensa/core-dc232b.c +++ b/target/xtensa/core-dc232b.c @@ -34,6 +34,9 @@ #include "core-dc232b/core-isa.h" #include "overlay_tool.h" +#define xtensa_modules xtensa_modules_dc232b +#include "core-dc232b/xtensa-modules.c" + static XtensaConfig dc232b __attribute__((unused)) = { .name = "dc232b", .gdb_regmap = { @@ -43,6 +46,7 @@ static XtensaConfig dc232b __attribute__((unused)) = { #include "core-dc232b/gdb-config.c" } }, + .isa_internal = &xtensa_modules, .clock_freq_khz = 10000, DEFAULT_SECTIONS }; diff --git a/target/xtensa/core-dc232b/xtensa-modules.c b/target/xtensa/core-dc232b/xtensa-modules.c new file mode 100644 index 0000000000..2e103cd2f5 --- /dev/null +++ b/target/xtensa/core-dc232b/xtensa-modules.c @@ -0,0 +1,14105 @@ +/* Xtensa configuration-specific ISA information. + Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "LBEG", 0, 0 }, + { "LEND", 1, 0 }, + { "LCOUNT", 2, 0 }, + { "ACCLO", 16, 0 }, + { "ACCHI", 17, 0 }, + { "M0", 32, 0 }, + { "M1", 33, 0 }, + { "M2", 34, 0 }, + { "M3", 35, 0 }, + { "PTEVADDR", 83, 0 }, + { "MMID", 89, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "CCOMPARE1", 241, 0 }, + { "CCOMPARE2", 242, 0 }, + { "VECBASE", 231, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EPC4", 180, 0 }, + { "EPC5", 181, 0 }, + { "EPC6", 182, 0 }, + { "EPC7", 183, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EXCSAVE4", 212, 0 }, + { "EXCSAVE5", 213, 0 }, + { "EXCSAVE6", 214, 0 }, + { "EXCSAVE7", 215, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EPS4", 196, 0 }, + { "EPS5", 197, 0 }, + { "EPS6", 198, 0 }, + { "EPS7", 199, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "WINDOWBASE", 72, 0 }, + { "WINDOWSTART", 73, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "MISC0", 244, 0 }, + { "MISC1", 245, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "DBREAKA1", 145, 0 }, + { "DBREAKC1", 161, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKA1", 129, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 }, + { "RASID", 90, 0 }, + { "ITLBCFG", 91, 0 }, + { "DTLBCFG", 92, 0 }, + { "CPENABLE", 224, 0 }, + { "SCOMPARE1", 12, 0 }, + { "THREADPTR", 231, 1 }, + { "EXPSTATE", 230, 1 } +}; + +#define NUM_SYSREGS 70 +#define MAX_SPECIAL_REG 245 +#define MAX_USER_REG 231 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "LCOUNT", 32, 0 }, + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 22, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "VECBASE", 22, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EPC4", 32, 0 }, + { "EPC5", 32, 0 }, + { "EPC6", 32, 0 }, + { "EPC7", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EXCSAVE4", 32, 0 }, + { "EXCSAVE5", 32, 0 }, + { "EXCSAVE6", 32, 0 }, + { "EXCSAVE7", 32, 0 }, + { "EPS2", 15, 0 }, + { "EPS3", 15, 0 }, + { "EPS4", 15, 0 }, + { "EPS5", 15, 0 }, + { "EPS6", 15, 0 }, + { "EPS7", 15, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSWOE", 1, 0 }, + { "PSRING", 2, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "WindowBase", 3, 0 }, + { "WindowStart", 8, 0 }, + { "PSCALLINC", 2, 0 }, + { "PSOWB", 4, 0 }, + { "LBEG", 32, 0 }, + { "LEND", 32, 0 }, + { "SAR", 6, 0 }, + { "THREADPTR", 32, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "MISC0", 32, 0 }, + { "MISC1", 32, 0 }, + { "ACC", 40, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 22, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "DBREAKA1", 32, 0 }, + { "DBREAKC1", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKA1", 32, 0 }, + { "IBREAKENABLE", 2, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 }, + { "CCOMPARE1", 32, 0 }, + { "CCOMPARE2", 32, 0 }, + { "ASID3", 8, 0 }, + { "ASID2", 8, 0 }, + { "ASID1", 8, 0 }, + { "INSTPGSZID4", 2, 0 }, + { "DATAPGSZID4", 2, 0 }, + { "PTBASE", 10, 0 }, + { "CPENABLE", 8, 0 }, + { "SCOMPARE1", 32, 0 }, + { "EXPSTATE", 32, XTENSA_STATE_IS_EXPORTED } +}; + +#define NUM_STATES 73 + +/* Macros for xtensa_state numbers (for use in iclasses because the + state numbers are not available when the iclass table is generated). */ + +#define STATE_LCOUNT 0 +#define STATE_PC 1 +#define STATE_ICOUNT 2 +#define STATE_DDR 3 +#define STATE_INTERRUPT 4 +#define STATE_CCOUNT 5 +#define STATE_XTSYNC 6 +#define STATE_VECBASE 7 +#define STATE_EPC1 8 +#define STATE_EPC2 9 +#define STATE_EPC3 10 +#define STATE_EPC4 11 +#define STATE_EPC5 12 +#define STATE_EPC6 13 +#define STATE_EPC7 14 +#define STATE_EXCSAVE1 15 +#define STATE_EXCSAVE2 16 +#define STATE_EXCSAVE3 17 +#define STATE_EXCSAVE4 18 +#define STATE_EXCSAVE5 19 +#define STATE_EXCSAVE6 20 +#define STATE_EXCSAVE7 21 +#define STATE_EPS2 22 +#define STATE_EPS3 23 +#define STATE_EPS4 24 +#define STATE_EPS5 25 +#define STATE_EPS6 26 +#define STATE_EPS7 27 +#define STATE_EXCCAUSE 28 +#define STATE_PSINTLEVEL 29 +#define STATE_PSUM 30 +#define STATE_PSWOE 31 +#define STATE_PSRING 32 +#define STATE_PSEXCM 33 +#define STATE_DEPC 34 +#define STATE_EXCVADDR 35 +#define STATE_WindowBase 36 +#define STATE_WindowStart 37 +#define STATE_PSCALLINC 38 +#define STATE_PSOWB 39 +#define STATE_LBEG 40 +#define STATE_LEND 41 +#define STATE_SAR 42 +#define STATE_THREADPTR 43 +#define STATE_LITBADDR 44 +#define STATE_LITBEN 45 +#define STATE_MISC0 46 +#define STATE_MISC1 47 +#define STATE_ACC 48 +#define STATE_InOCDMode 49 +#define STATE_INTENABLE 50 +#define STATE_DBREAKA0 51 +#define STATE_DBREAKC0 52 +#define STATE_DBREAKA1 53 +#define STATE_DBREAKC1 54 +#define STATE_IBREAKA0 55 +#define STATE_IBREAKA1 56 +#define STATE_IBREAKENABLE 57 +#define STATE_ICOUNTLEVEL 58 +#define STATE_DEBUGCAUSE 59 +#define STATE_DBNUM 60 +#define STATE_CCOMPARE0 61 +#define STATE_CCOMPARE1 62 +#define STATE_CCOMPARE2 63 +#define STATE_ASID3 64 +#define STATE_ASID2 65 +#define STATE_ASID1 66 +#define STATE_INSTPGSZID4 67 +#define STATE_DATAPGSZID4 68 +#define STATE_PTBASE 69 +#define STATE_CPENABLE 70 +#define STATE_SCOMPARE1 71 +#define STATE_EXPSTATE 72 + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 8) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff000) | (tie_t << 12); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 8) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff00) | (tie_t << 8); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_mn_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_mn_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); + tie_t = (val << 28) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_r3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_rbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_rbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_rhi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_rhi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_t3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_tbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_tbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_tlo_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_tlo_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_w_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 18) >> 30); + return tie_t; +} + +static void +Field_w_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x3000) | (tie_t << 12); +} + +static unsigned +Field_y_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_y_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_x_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_x_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_xt_wbr15_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 15) | ((insn[0] << 8) >> 17); + return tie_t; +} + +static void +Field_xt_wbr15_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 17) >> 17; + insn[0] = (insn[0] & ~0xfffe00) | (tie_t << 9); +} + +static unsigned +Field_xt_wbr18_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_xt_wbr18_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_bitindex_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_s3to1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s3to1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s3to1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_ar4_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 4; +} + +static unsigned +Implicit_Field_ar8_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 8; +} + +static unsigned +Implicit_Field_ar12_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 12; +} + +static unsigned +Implicit_Field_mr0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_mr1_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 1; +} + +static unsigned +Implicit_Field_mr2_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 2; +} + +static unsigned +Implicit_Field_mr3_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 3; +} + + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", 0, 32, 32 }, + { "MR", "m", 1, 32, 4 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + { "IMPWIRE", 32, 0, 0, 'i' } +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; +} + +static int +Operand_soffsetx4_encode (uint32 *valp) +{ + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_uimm12x8_decode (uint32 *valp) +{ + unsigned uimm12x8_0, imm12_0; + imm12_0 = *valp & 0xfff; + uimm12x8_0 = imm12_0 << 3; + *valp = uimm12x8_0; + return 0; +} + +static int +Operand_uimm12x8_encode (uint32 *valp) +{ + unsigned imm12_0, uimm12x8_0; + uimm12x8_0 = *valp; + imm12_0 = ((uimm12x8_0 >> 3) & 0xfff); + *valp = imm12_0; + return 0; +} + +static int +Operand_simm4_decode (uint32 *valp) +{ + unsigned simm4_0, mn_0; + mn_0 = *valp & 0xf; + simm4_0 = ((int) mn_0 << 28) >> 28; + *valp = simm4_0; + return 0; +} + +static int +Operand_simm4_encode (uint32 *valp) +{ + unsigned mn_0, simm4_0; + simm4_0 = *valp; + mn_0 = (simm4_0 & 0xf); + *valp = mn_0; + return 0; +} + +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_arr_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_art_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar4_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar4_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar8_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar8_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar12_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar12_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ars_entry_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_entry_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_immrx4_decode (uint32 *valp) +{ + unsigned immrx4_0, r_0; + r_0 = *valp & 0xf; + immrx4_0 = (((0xfffffff) << 4) | r_0) << 2; + *valp = immrx4_0; + return 0; +} + +static int +Operand_immrx4_encode (uint32 *valp) +{ + unsigned r_0, immrx4_0; + immrx4_0 = *valp; + r_0 = ((immrx4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; +} + +static int +Operand_lsi4x4_encode (uint32 *valp) +{ + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_simm7_decode (uint32 *valp) +{ + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; +} + +static int +Operand_simm7_encode (uint32 *valp) +{ + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; +} + +static int +Operand_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + (((0) << 6) | imm6_0); + *valp = uimm6_0; + return 0; +} + +static int +Operand_uimm6_encode (uint32 *valp) +{ + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; +} + +static int +Operand_ai4const_encode (uint32 *valp) +{ + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; +} + +static int +Operand_b4const_decode (uint32 *valp) +{ + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; +} + +static int +Operand_b4const_encode (uint32 *valp) +{ + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; +} + +static int +Operand_b4constu_encode (uint32 *valp) +{ + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; +} + +static int +Operand_uimm8_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; +} + +static int +Operand_uimm8x2_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; +} + +static int +Operand_uimm8x4_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; +} + +static int +Operand_uimm4x16_encode (uint32 *valp) +{ + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; +} + +static int +Operand_simm8_decode (uint32 *valp) +{ + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; +} + +static int +Operand_simm8_encode (uint32 *valp) +{ + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; +} + +static int +Operand_simm8x256_encode (uint32 *valp) +{ + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; +} + +static int +Operand_simm12b_encode (uint32 *valp) +{ + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; +} + +static int +Operand_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; +} + +static int +Operand_msalp32_encode (uint32 *valp) +{ + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; +} + +static int +Operand_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; +} + +static int +Operand_op2p1_encode (uint32 *valp) +{ + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; +} + +static int +Operand_label8_decode (uint32 *valp) +{ + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; +} + +static int +Operand_label8_encode (uint32 *valp) +{ + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ulabel8_decode (uint32 *valp) +{ + unsigned ulabel8_0, imm8_0; + imm8_0 = *valp & 0xff; + ulabel8_0 = 0x4 + (((0) << 8) | imm8_0); + *valp = ulabel8_0; + return 0; +} + +static int +Operand_ulabel8_encode (uint32 *valp) +{ + unsigned imm8_0, ulabel8_0; + ulabel8_0 = *valp; + imm8_0 = (ulabel8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_ulabel8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_ulabel8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_decode (uint32 *valp) +{ + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; +} + +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} + +static int +Operand_soffset_encode (uint32 *valp) +{ + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = (((0xffff) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; +} + +static int +Operand_uimm16x4_encode (uint32 *valp) +{ + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_mx_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mx_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_my_decode (uint32 *valp) +{ + *valp += 2; + return 0; +} + +static int +Operand_my_encode (uint32 *valp) +{ + int error; + error = ((*valp & ~0x3) != 0) || ((*valp & 0x2) == 0); + *valp = *valp & 1; + return error; +} + +static int +Operand_mw_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mw_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr1_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr1_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr2_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr2_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr3_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr3_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static int +Operand_tp7_decode (uint32 *valp) +{ + unsigned tp7_0, t_0; + t_0 = *valp & 0xf; + tp7_0 = t_0 + 0x7; + *valp = tp7_0; + return 0; +} + +static int +Operand_tp7_encode (uint32 *valp) +{ + unsigned t_0, tp7_0; + tp7_0 = *valp; + t_0 = (tp7_0 - 0x7) & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_xt_wbr15_label_decode (uint32 *valp) +{ + unsigned xt_wbr15_label_0, xt_wbr15_imm_0; + xt_wbr15_imm_0 = *valp & 0x7fff; + xt_wbr15_label_0 = 0x4 + (((int) xt_wbr15_imm_0 << 17) >> 17); + *valp = xt_wbr15_label_0; + return 0; +} + +static int +Operand_xt_wbr15_label_encode (uint32 *valp) +{ + unsigned xt_wbr15_imm_0, xt_wbr15_label_0; + xt_wbr15_label_0 = *valp; + xt_wbr15_imm_0 = (xt_wbr15_label_0 - 0x4) & 0x7fff; + *valp = xt_wbr15_imm_0; + return 0; +} + +static int +Operand_xt_wbr15_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr15_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_xt_wbr18_label_decode (uint32 *valp) +{ + unsigned xt_wbr18_label_0, xt_wbr18_imm_0; + xt_wbr18_imm_0 = *valp & 0x3ffff; + xt_wbr18_label_0 = 0x4 + (((int) xt_wbr18_imm_0 << 14) >> 14); + *valp = xt_wbr18_label_0; + return 0; +} + +static int +Operand_xt_wbr18_label_encode (uint32 *valp) +{ + unsigned xt_wbr18_imm_0, xt_wbr18_label_0; + xt_wbr18_label_0 = *valp; + xt_wbr18_imm_0 = (xt_wbr18_label_0 - 0x4) & 0x3ffff; + *valp = xt_wbr18_imm_0; + return 0; +} + +static int +Operand_xt_wbr18_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr18_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "soffsetx4", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "uimm12x8", 3, -1, 0, + 0, + Operand_uimm12x8_encode, Operand_uimm12x8_decode, + 0, 0 }, + { "simm4", 26, -1, 0, + 0, + Operand_simm4_encode, Operand_simm4_decode, + 0, 0 }, + { "arr", 14, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ars", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "art", 0, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ar0", 48, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "ar4", 49, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar4_encode, Operand_ar4_decode, + 0, 0 }, + { "ar8", 50, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar8_encode, Operand_ar8_decode, + 0, 0 }, + { "ar12", 51, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar12_encode, Operand_ar12_decode, + 0, 0 }, + { "ars_entry", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_entry_encode, Operand_ars_entry_decode, + 0, 0 }, + { "immrx4", 14, -1, 0, + 0, + Operand_immrx4_encode, Operand_immrx4_decode, + 0, 0 }, + { "lsi4x4", 14, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", 34, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", 33, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", 0, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", 14, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", 14, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", 4, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", 4, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", 4, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", 13, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", 4, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", 4, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", 6, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", 18, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", 13, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "ulabel8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_ulabel8_encode, Operand_ulabel8_decode, + Operand_ulabel8_ator, Operand_ulabel8_rtoa }, + { "label12", 3, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", 7, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "mx", 43, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + Operand_mx_encode, Operand_mx_decode, + 0, 0 }, + { "my", 42, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + Operand_my_encode, Operand_my_decode, + 0, 0 }, + { "mw", 41, 1, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_mw_encode, Operand_mw_decode, + 0, 0 }, + { "mr0", 52, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr0_encode, Operand_mr0_decode, + 0, 0 }, + { "mr1", 53, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr1_encode, Operand_mr1_decode, + 0, 0 }, + { "mr2", 54, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr2_encode, Operand_mr2_decode, + 0, 0 }, + { "mr3", 55, 1, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr3_encode, Operand_mr3_decode, + 0, 0 }, + { "immt", 0, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", 5, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "tp7", 0, -1, 0, + 0, + Operand_tp7_encode, Operand_tp7_decode, + 0, 0 }, + { "xt_wbr15_label", 44, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr15_label_encode, Operand_xt_wbr15_label_decode, + Operand_xt_wbr15_label_ator, Operand_xt_wbr15_label_rtoa }, + { "xt_wbr18_label", 45, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr18_label_encode, Operand_xt_wbr18_label_decode, + Operand_xt_wbr18_label_ator, Operand_xt_wbr18_label_rtoa }, + { "t", 0, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", 1, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", 2, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", 3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", 4, -1, 0, 0, 0, 0, 0, 0 }, + { "s", 5, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", 6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", 7, -1, 0, 0, 0, 0, 0, 0 }, + { "m", 8, -1, 0, 0, 0, 0, 0, 0 }, + { "n", 9, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", 10, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", 11, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", 12, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", 13, -1, 0, 0, 0, 0, 0, 0 }, + { "r", 14, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", 15, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", 16, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", 17, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", 18, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", 19, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", 20, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", 21, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", 22, -1, 0, 0, 0, 0, 0, 0 }, + { "st", 23, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", 24, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", 25, -1, 0, 0, 0, 0, 0, 0 }, + { "mn", 26, -1, 0, 0, 0, 0, 0, 0 }, + { "i", 27, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", 28, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", 29, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", 30, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", 31, -1, 0, 0, 0, 0, 0, 0 }, + { "z", 32, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", 33, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", 34, -1, 0, 0, 0, 0, 0, 0 }, + { "r3", 35, -1, 0, 0, 0, 0, 0, 0 }, + { "rbit2", 36, -1, 0, 0, 0, 0, 0, 0 }, + { "rhi", 37, -1, 0, 0, 0, 0, 0, 0 }, + { "t3", 38, -1, 0, 0, 0, 0, 0, 0 }, + { "tbit2", 39, -1, 0, 0, 0, 0, 0, 0 }, + { "tlo", 40, -1, 0, 0, 0, 0, 0, 0 }, + { "w", 41, -1, 0, 0, 0, 0, 0, 0 }, + { "y", 42, -1, 0, 0, 0, 0, 0, 0 }, + { "x", 43, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr15_imm", 44, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr18_imm", 45, -1, 0, 0, 0, 0, 0, 0 }, + { "bitindex", 46, -1, 0, 0, 0, 0, 0, 0 }, + { "s3to1", 47, -1, 0, 0, 0, 0, 0, 0 } +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSRING }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_args[] = { + { { 11 /* ars_entry */ }, 's' }, + { { 4 /* ars */ }, 'i' }, + { { 1 /* uimm12x8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_stateArgs[] = { + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_stateArgs[] = { + { { STATE_WindowBase }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_args[] = { + { { 2 /* simm4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_stateArgs[] = { + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfwou_stateArgs[] = { + { { STATE_EPC1 }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSOWB }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 16 /* ai4const */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 15 /* uimm6 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { 4 /* ars */ }, 'o' }, + { { 14 /* simm7 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_args[] = { + { { 3 /* arr */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 23 /* simm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 24 /* simm8x256 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 17 /* b4const */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 47 /* bbi */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 18 /* b4constu */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 30 /* label12 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 62 /* sae */ }, 'i' }, + { { 27 /* op2p1 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { 31 /* soffset */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { 6 /* art */ }, 'o' }, + { { 32 /* uimm16x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 25 /* simm12b */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { 3 /* arr */ }, 'm' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { 66 /* sas */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 26 /* msalp32 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 64 /* sargt */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 50 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { 6 /* art */ }, 'o' }, + { { 50 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_stateArgs[] = { + { { STATE_LEND }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_stateArgs[] = { + { { STATE_LEND }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_stateArgs[] = { + { { STATE_LEND }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_stateArgs[] = { + { { STATE_LCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'm' }, + { { STATE_PSCALLINC }, 'm' }, + { { STATE_PSOWB }, 'm' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 34 /* my */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_args[] = { + { { 33 /* mx */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_args[] = { + { { 33 /* mx */ }, 'i' }, + { { 34 /* my */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 34 /* my */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_args[] = { + { { 33 /* mx */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_args[] = { + { { 33 /* mx */ }, 'i' }, + { { 34 /* my */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_args[] = { + { { 35 /* mw */ }, 'o' }, + { { 4 /* ars */ }, 'm' }, + { { 33 /* mx */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_args[] = { + { { 35 /* mw */ }, 'o' }, + { { 4 /* ars */ }, 'm' }, + { { 33 /* mx */ }, 'i' }, + { { 34 /* my */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_l_args[] = { + { { 35 /* mw */ }, 'o' }, + { { 4 /* ars */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mul16_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m0_args[] = { + { { 6 /* art */ }, 'o' }, + { { 36 /* mr0 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m0_args[] = { + { { 6 /* art */ }, 'i' }, + { { 36 /* mr0 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m0_args[] = { + { { 6 /* art */ }, 'm' }, + { { 36 /* mr0 */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m1_args[] = { + { { 6 /* art */ }, 'o' }, + { { 37 /* mr1 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m1_args[] = { + { { 6 /* art */ }, 'i' }, + { { 37 /* mr1 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m1_args[] = { + { { 6 /* art */ }, 'm' }, + { { 37 /* mr1 */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m2_args[] = { + { { 6 /* art */ }, 'o' }, + { { 38 /* mr2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m2_args[] = { + { { 6 /* art */ }, 'i' }, + { { 38 /* mr2 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m2_args[] = { + { { 6 /* art */ }, 'm' }, + { { 38 /* mr2 */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m3_args[] = { + { { 6 /* art */ }, 'o' }, + { { 39 /* mr3 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m3_args[] = { + { { 6 /* art */ }, 'i' }, + { { 39 /* mr3 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m3_args[] = { + { { 6 /* art */ }, 'm' }, + { { 39 /* mr3 */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { 50 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_EPC5 }, 'i' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_EPC7 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_EPS4 }, 'i' }, + { { STATE_EPS5 }, 'i' }, + { { STATE_EPS6 }, 'i' }, + { { STATE_EPS7 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { 50 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { 41 /* imms */ }, 'i' }, + { { 40 /* immt */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { 41 /* imms */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_args[] = { + { { 41 /* imms */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_lock_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 22 /* uimm4x16 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_lock_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 22 /* uimm4x16 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dpf_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_lock_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 22 /* uimm4x16 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_lock_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'm' }, + { { STATE_EXCVADDR }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'i' }, + { { STATE_ASID2 }, 'i' }, + { { STATE_ASID1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'o' }, + { { STATE_ASID2 }, 'o' }, + { { STATE_ASID1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'm' }, + { { STATE_ASID2 }, 'm' }, + { { STATE_ASID1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldpte_stateArgs[] = { + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwitlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwdtlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_clamp_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 42 /* tp7 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_minmax_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sx_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 42 /* tp7 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32ai_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32ri_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_args[] = { + { { 6 /* art */ }, 'm' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' }, + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_div_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_args[] = { + { { 3 /* arr */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'o' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_READ_IMPWIRE_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_iclass_READ_IMPWIRE_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_interface Iclass_iclass_READ_IMPWIRE_intfArgs[] = { + 0 /* IMPWIRE */ +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_args[] = { + { { 91 /* bitindex */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_args[] = { + { { 91 /* bitindex */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 3, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 3, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call12_args, + 1, Iclass_xt_iclass_call12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call8_args, + 1, Iclass_xt_iclass_call8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call4_args, + 1, Iclass_xt_iclass_call4_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx12_args, + 1, Iclass_xt_iclass_callx12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx8_args, + 1, Iclass_xt_iclass_callx8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx4_args, + 1, Iclass_xt_iclass_callx4_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_entry_args, + 5, Iclass_xt_iclass_entry_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movsp_args, + 2, Iclass_xt_iclass_movsp_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rotw_args, + 3, Iclass_xt_iclass_rotw_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_retw_args, + 4, Iclass_xt_iclass_retw_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfwou */, + 6, Iclass_xt_iclass_rfwou_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l32e_args, + 2, Iclass_xt_iclass_l32e_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_s32e_args, + 2, Iclass_xt_iclass_s32e_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowbase_args, + 3, Iclass_xt_iclass_rsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowbase_args, + 3, Iclass_xt_iclass_wsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowbase_args, + 3, Iclass_xt_iclass_xsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowstart_args, + 3, Iclass_xt_iclass_rsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowstart_args, + 3, Iclass_xt_iclass_wsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowstart_args, + 3, Iclass_xt_iclass_xsr_windowstart_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 1, Iclass_rur_threadptr_args, + 1, Iclass_rur_threadptr_stateArgs, 0, 0 }, + { 1, Iclass_wur_threadptr_args, + 1, Iclass_wur_threadptr_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_loop_args, + 3, Iclass_xt_iclass_loop_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_loopz_args, + 3, Iclass_xt_iclass_loopz_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 7, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lend_args, + 1, Iclass_xt_iclass_rsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lend_args, + 1, Iclass_xt_iclass_wsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lend_args, + 1, Iclass_xt_iclass_xsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lcount_args, + 1, Iclass_xt_iclass_rsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lcount_args, + 2, Iclass_xt_iclass_wsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lcount_args, + 2, Iclass_xt_iclass_xsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lbeg_args, + 1, Iclass_xt_iclass_rsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lbeg_args, + 1, Iclass_xt_iclass_wsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lbeg_args, + 1, Iclass_xt_iclass_xsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 2, Iclass_xt_iclass_rsr_176_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 2, Iclass_xt_iclass_rsr_208_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 7, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 7, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 7, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 3, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 3, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 3, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 3, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 3, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 3, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 3, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 3, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 3, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 3, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 3, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 3, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 3, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 3, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 3, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 3, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 3, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 3, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc4_args, + 3, Iclass_xt_iclass_rsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc4_args, + 3, Iclass_xt_iclass_wsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc4_args, + 3, Iclass_xt_iclass_xsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave4_args, + 3, Iclass_xt_iclass_rsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave4_args, + 3, Iclass_xt_iclass_wsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave4_args, + 3, Iclass_xt_iclass_xsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc5_args, + 3, Iclass_xt_iclass_rsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc5_args, + 3, Iclass_xt_iclass_wsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc5_args, + 3, Iclass_xt_iclass_xsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave5_args, + 3, Iclass_xt_iclass_rsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave5_args, + 3, Iclass_xt_iclass_wsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave5_args, + 3, Iclass_xt_iclass_xsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc6_args, + 3, Iclass_xt_iclass_rsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc6_args, + 3, Iclass_xt_iclass_wsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc6_args, + 3, Iclass_xt_iclass_xsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave6_args, + 3, Iclass_xt_iclass_rsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave6_args, + 3, Iclass_xt_iclass_wsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave6_args, + 3, Iclass_xt_iclass_xsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc7_args, + 3, Iclass_xt_iclass_rsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc7_args, + 3, Iclass_xt_iclass_wsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc7_args, + 3, Iclass_xt_iclass_xsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave7_args, + 3, Iclass_xt_iclass_rsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave7_args, + 3, Iclass_xt_iclass_wsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave7_args, + 3, Iclass_xt_iclass_xsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 3, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 3, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 3, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 3, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 3, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 3, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps4_args, + 3, Iclass_xt_iclass_rsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps4_args, + 3, Iclass_xt_iclass_wsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps4_args, + 3, Iclass_xt_iclass_xsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps5_args, + 3, Iclass_xt_iclass_rsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps5_args, + 3, Iclass_xt_iclass_wsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps5_args, + 3, Iclass_xt_iclass_xsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps6_args, + 3, Iclass_xt_iclass_rsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps6_args, + 3, Iclass_xt_iclass_wsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps6_args, + 3, Iclass_xt_iclass_xsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps7_args, + 3, Iclass_xt_iclass_rsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps7_args, + 3, Iclass_xt_iclass_wsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps7_args, + 3, Iclass_xt_iclass_xsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 3, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 3, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 3, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 3, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 3, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 3, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 4, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 3, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 3, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc0_args, + 3, Iclass_xt_iclass_rsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc0_args, + 3, Iclass_xt_iclass_wsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc0_args, + 3, Iclass_xt_iclass_xsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc1_args, + 3, Iclass_xt_iclass_rsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc1_args, + 3, Iclass_xt_iclass_wsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc1_args, + 3, Iclass_xt_iclass_xsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 2, Iclass_xt_iclass_rsr_prid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_vecbase_args, + 3, Iclass_xt_iclass_rsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_vecbase_args, + 3, Iclass_xt_iclass_wsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_vecbase_args, + 3, Iclass_xt_iclass_xsr_vecbase_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_aa_args, + 1, Iclass_xt_iclass_mac16_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_ad_args, + 1, Iclass_xt_iclass_mac16_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_da_args, + 1, Iclass_xt_iclass_mac16_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_dd_args, + 1, Iclass_xt_iclass_mac16_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_aa_args, + 1, Iclass_xt_iclass_mac16a_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_ad_args, + 1, Iclass_xt_iclass_mac16a_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_da_args, + 1, Iclass_xt_iclass_mac16a_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_dd_args, + 1, Iclass_xt_iclass_mac16a_dd_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_da_args, + 1, Iclass_xt_iclass_mac16al_da_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_dd_args, + 1, Iclass_xt_iclass_mac16al_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_l_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_mul16_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m3_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acclo_args, + 1, Iclass_xt_iclass_rsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acclo_args, + 1, Iclass_xt_iclass_wsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acclo_args, + 1, Iclass_xt_iclass_xsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acchi_args, + 1, Iclass_xt_iclass_rsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acchi_args, + 1, Iclass_xt_iclass_wsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acchi_args, + 1, Iclass_xt_iclass_xsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 21, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 3, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 3, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 4, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 4, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 3, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 3, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 3, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 3, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 4, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 4, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 3, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 4, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 4, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka1_args, + 3, Iclass_xt_iclass_rsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka1_args, + 4, Iclass_xt_iclass_wsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka1_args, + 4, Iclass_xt_iclass_xsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc1_args, + 3, Iclass_xt_iclass_rsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc1_args, + 4, Iclass_xt_iclass_wsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc1_args, + 4, Iclass_xt_iclass_xsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 3, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 3, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 3, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka1_args, + 3, Iclass_xt_iclass_rsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka1_args, + 3, Iclass_xt_iclass_wsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka1_args, + 3, Iclass_xt_iclass_xsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 3, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 3, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 3, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 4, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 4, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 4, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 3, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 4, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 4, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 3, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 3, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 3, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 3, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 4, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 4, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfdo_args, + 10, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_mmid_args, + 3, Iclass_xt_iclass_wsr_mmid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 3, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 4, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 4, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 3, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 4, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 4, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare1_args, + 3, Iclass_xt_iclass_rsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare1_args, + 4, Iclass_xt_iclass_wsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare1_args, + 4, Iclass_xt_iclass_xsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare2_args, + 3, Iclass_xt_iclass_rsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare2_args, + 4, Iclass_xt_iclass_wsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare2_args, + 4, Iclass_xt_iclass_xsr_ccompare2_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_icache_lock_args, + 2, Iclass_xt_iclass_icache_lock_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_inv_args, + 2, Iclass_xt_iclass_icache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_licx_args, + 2, Iclass_xt_iclass_licx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_sicx_args, + 2, Iclass_xt_iclass_sicx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_ind_args, + 2, Iclass_xt_iclass_dcache_ind_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_inv_args, + 2, Iclass_xt_iclass_dcache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dpf_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_lock_args, + 2, Iclass_xt_iclass_dcache_lock_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_sdct_args, + 2, Iclass_xt_iclass_sdct_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ldct_args, + 2, Iclass_xt_iclass_ldct_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ptevaddr_args, + 4, Iclass_xt_iclass_wsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ptevaddr_args, + 4, Iclass_xt_iclass_rsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ptevaddr_args, + 5, Iclass_xt_iclass_xsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_rasid_args, + 5, Iclass_xt_iclass_rsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_rasid_args, + 6, Iclass_xt_iclass_wsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_rasid_args, + 6, Iclass_xt_iclass_xsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_itlbcfg_args, + 3, Iclass_xt_iclass_rsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_itlbcfg_args, + 4, Iclass_xt_iclass_wsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_itlbcfg_args, + 4, Iclass_xt_iclass_xsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dtlbcfg_args, + 3, Iclass_xt_iclass_rsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dtlbcfg_args, + 4, Iclass_xt_iclass_wsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dtlbcfg_args, + 4, Iclass_xt_iclass_xsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 3, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 2, Iclass_xt_iclass_rdtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 3, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 2, Iclass_xt_iclass_iitlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 2, Iclass_xt_iclass_ritlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 2, Iclass_xt_iclass_witlb_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_ldpte */, + 2, Iclass_xt_iclass_ldpte_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwitlba */, + 1, Iclass_xt_iclass_hwwitlba_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwdtlba */, + 1, Iclass_xt_iclass_hwwdtlba_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_cpenable_args, + 3, Iclass_xt_iclass_rsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_cpenable_args, + 3, Iclass_xt_iclass_wsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_cpenable_args, + 3, Iclass_xt_iclass_xsr_cpenable_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_clamp_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_minmax_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_sx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32ai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32ri_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32c1i_args, + 2, Iclass_xt_iclass_s32c1i_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_scompare1_args, + 1, Iclass_xt_iclass_rsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_scompare1_args, + 1, Iclass_xt_iclass_wsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_scompare1_args, + 1, Iclass_xt_iclass_xsr_scompare1_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_div_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32_args, + 0, 0, 0, 0 }, + { 1, Iclass_rur_expstate_args, + 2, Iclass_rur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_wur_expstate_args, + 2, Iclass_wur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_iclass_READ_IMPWIRE_args, + 1, Iclass_iclass_READ_IMPWIRE_stateArgs, 1, Iclass_iclass_READ_IMPWIRE_intfArgs }, + { 1, Iclass_iclass_SETB_EXPSTATE_args, + 2, Iclass_iclass_SETB_EXPSTATE_stateArgs, 0, 0 }, + { 1, Iclass_iclass_CLRB_EXPSTATE_args, + 2, Iclass_iclass_CLRB_EXPSTATE_stateArgs, 0, 0 }, + { 2, Iclass_iclass_WRMSK_EXPSTATE_args, + 2, Iclass_iclass_WRMSK_EXPSTATE_stateArgs, 0, 0 } +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2080; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3000; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3200; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5000; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5100; +} + +static void +Opcode_call12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35; +} + +static void +Opcode_call8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x25; +} + +static void +Opcode_call4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x15; +} + +static void +Opcode_callx12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0; +} + +static void +Opcode_callx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0; +} + +static void +Opcode_callx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd0; +} + +static void +Opcode_entry_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36; +} + +static void +Opcode_movsp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1000; +} + +static void +Opcode_rotw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x408000; +} + +static void +Opcode_retw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90; +} + +static void +Opcode_retw_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf01d; +} + +static void +Opcode_rfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3400; +} + +static void +Opcode_rfwu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3500; +} + +static void +Opcode_l32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90000; +} + +static void +Opcode_s32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490000; +} + +static void +Opcode_rsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34800; +} + +static void +Opcode_wsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134800; +} + +static void +Opcode_xsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614800; +} + +static void +Opcode_rsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34900; +} + +static void +Opcode_wsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134900; +} + +static void +Opcode_xsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614900; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8c; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf06d; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf03d; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00d; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_rur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e70; +} + +static void +Opcode_wur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e700; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc002; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd002; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800000; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc00000; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900000; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa00000; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb00000; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00000; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe00000; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00000; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300000; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x26; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x66; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe6; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa6; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6007; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe007; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf6; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb6; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1007; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9007; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa007; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2007; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb007; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3007; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8007; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4007; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc007; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5007; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd007; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x56; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd6; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x96; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40000; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1002; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9002; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2002; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_loop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8076; +} + +static void +Opcode_loopnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9076; +} + +static void +Opcode_loopgtz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa076; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa002; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x830000; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x930000; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa30000; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb30000; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600100; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20f0; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5002; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6002; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4002; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400000; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x401000; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x402000; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x403000; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404000; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa10000; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x810000; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x910000; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb10000; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10000; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210000; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x410000; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20c0; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20d0; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2000; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2010; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2020; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2030; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6000; +} + +static void +Opcode_rsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30100; +} + +static void +Opcode_wsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130100; +} + +static void +Opcode_xsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610100; +} + +static void +Opcode_rsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30200; +} + +static void +Opcode_wsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130200; +} + +static void +Opcode_xsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610200; +} + +static void +Opcode_rsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30000; +} + +static void +Opcode_wsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130000; +} + +static void +Opcode_xsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610000; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30300; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130300; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610300; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30500; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130500; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610500; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b000; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d000; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e600; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e600; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e600; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b100; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b100; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b100; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d100; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d100; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d100; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b200; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b200; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b200; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d200; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d200; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d200; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b300; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b300; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b300; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d300; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d300; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d300; +} + +static void +Opcode_rsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b400; +} + +static void +Opcode_wsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b400; +} + +static void +Opcode_xsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b400; +} + +static void +Opcode_rsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d400; +} + +static void +Opcode_wsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d400; +} + +static void +Opcode_xsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d400; +} + +static void +Opcode_rsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b500; +} + +static void +Opcode_wsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b500; +} + +static void +Opcode_xsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b500; +} + +static void +Opcode_rsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d500; +} + +static void +Opcode_wsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d500; +} + +static void +Opcode_xsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d500; +} + +static void +Opcode_rsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b600; +} + +static void +Opcode_wsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b600; +} + +static void +Opcode_xsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b600; +} + +static void +Opcode_rsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d600; +} + +static void +Opcode_wsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d600; +} + +static void +Opcode_xsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d600; +} + +static void +Opcode_rsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b700; +} + +static void +Opcode_wsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b700; +} + +static void +Opcode_xsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b700; +} + +static void +Opcode_rsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d700; +} + +static void +Opcode_wsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d700; +} + +static void +Opcode_xsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d700; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c200; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c200; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c200; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c300; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c300; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c300; +} + +static void +Opcode_rsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c400; +} + +static void +Opcode_wsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c400; +} + +static void +Opcode_xsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c400; +} + +static void +Opcode_rsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c500; +} + +static void +Opcode_wsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c500; +} + +static void +Opcode_xsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c500; +} + +static void +Opcode_rsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c600; +} + +static void +Opcode_wsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c600; +} + +static void +Opcode_xsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c600; +} + +static void +Opcode_rsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c700; +} + +static void +Opcode_wsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c700; +} + +static void +Opcode_xsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c700; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ee00; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ee00; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ee00; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c000; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c000; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c000; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e800; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e800; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e800; +} + +static void +Opcode_rsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f400; +} + +static void +Opcode_wsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f400; +} + +static void +Opcode_xsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f400; +} + +static void +Opcode_rsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f500; +} + +static void +Opcode_wsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f500; +} + +static void +Opcode_xsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f500; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3eb00; +} + +static void +Opcode_rsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e700; +} + +static void +Opcode_wsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e700; +} + +static void +Opcode_xsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e700; +} + +static void +Opcode_mul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x740004; +} + +static void +Opcode_mul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x750004; +} + +static void +Opcode_mul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x760004; +} + +static void +Opcode_mul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x770004; +} + +static void +Opcode_umul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700004; +} + +static void +Opcode_umul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x710004; +} + +static void +Opcode_umul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x720004; +} + +static void +Opcode_umul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730004; +} + +static void +Opcode_mul_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x340004; +} + +static void +Opcode_mul_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x350004; +} + +static void +Opcode_mul_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x360004; +} + +static void +Opcode_mul_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x370004; +} + +static void +Opcode_mul_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x640004; +} + +static void +Opcode_mul_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x650004; +} + +static void +Opcode_mul_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x660004; +} + +static void +Opcode_mul_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x670004; +} + +static void +Opcode_mul_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x240004; +} + +static void +Opcode_mul_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x250004; +} + +static void +Opcode_mul_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x260004; +} + +static void +Opcode_mul_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270004; +} + +static void +Opcode_mula_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x780004; +} + +static void +Opcode_mula_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x790004; +} + +static void +Opcode_mula_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7a0004; +} + +static void +Opcode_mula_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7b0004; +} + +static void +Opcode_muls_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7c0004; +} + +static void +Opcode_muls_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7d0004; +} + +static void +Opcode_muls_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7e0004; +} + +static void +Opcode_muls_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7f0004; +} + +static void +Opcode_mula_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x380004; +} + +static void +Opcode_mula_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x390004; +} + +static void +Opcode_mula_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a0004; +} + +static void +Opcode_mula_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b0004; +} + +static void +Opcode_muls_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c0004; +} + +static void +Opcode_muls_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d0004; +} + +static void +Opcode_muls_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e0004; +} + +static void +Opcode_muls_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f0004; +} + +static void +Opcode_mula_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x680004; +} + +static void +Opcode_mula_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x690004; +} + +static void +Opcode_mula_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0004; +} + +static void +Opcode_mula_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0004; +} + +static void +Opcode_muls_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6c0004; +} + +static void +Opcode_muls_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0004; +} + +static void +Opcode_muls_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6e0004; +} + +static void +Opcode_muls_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6f0004; +} + +static void +Opcode_mula_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x280004; +} + +static void +Opcode_mula_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x290004; +} + +static void +Opcode_mula_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2a0004; +} + +static void +Opcode_mula_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2b0004; +} + +static void +Opcode_muls_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2c0004; +} + +static void +Opcode_muls_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2d0004; +} + +static void +Opcode_muls_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2e0004; +} + +static void +Opcode_muls_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2f0004; +} + +static void +Opcode_mula_da_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580004; +} + +static void +Opcode_mula_da_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x480004; +} + +static void +Opcode_mula_da_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x590004; +} + +static void +Opcode_mula_da_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490004; +} + +static void +Opcode_mula_da_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a0004; +} + +static void +Opcode_mula_da_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4a0004; +} + +static void +Opcode_mula_da_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b0004; +} + +static void +Opcode_mula_da_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4b0004; +} + +static void +Opcode_mula_dd_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x180004; +} + +static void +Opcode_mula_dd_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80004; +} + +static void +Opcode_mula_dd_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x190004; +} + +static void +Opcode_mula_dd_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90004; +} + +static void +Opcode_mula_dd_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a0004; +} + +static void +Opcode_mula_dd_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0004; +} + +static void +Opcode_mula_dd_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b0004; +} + +static void +Opcode_mula_dd_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb0004; +} + +static void +Opcode_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900004; +} + +static void +Opcode_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800004; +} + +static void +Opcode_mul16u_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc10000; +} + +static void +Opcode_mul16s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10000; +} + +static void +Opcode_rsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32000; +} + +static void +Opcode_wsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132000; +} + +static void +Opcode_xsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612000; +} + +static void +Opcode_rsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32100; +} + +static void +Opcode_wsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132100; +} + +static void +Opcode_xsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612100; +} + +static void +Opcode_rsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32200; +} + +static void +Opcode_wsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132200; +} + +static void +Opcode_xsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612200; +} + +static void +Opcode_rsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32300; +} + +static void +Opcode_wsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132300; +} + +static void +Opcode_xsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612300; +} + +static void +Opcode_rsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31000; +} + +static void +Opcode_wsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131000; +} + +static void +Opcode_xsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611000; +} + +static void +Opcode_rsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31100; +} + +static void +Opcode_wsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131100; +} + +static void +Opcode_xsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611100; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3010; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7000; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e200; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e200; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e300; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e400; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e400; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e400; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4000; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf02d; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39000; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139000; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619000; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a000; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a000; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a000; +} + +static void +Opcode_rsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39100; +} + +static void +Opcode_wsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139100; +} + +static void +Opcode_xsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619100; +} + +static void +Opcode_rsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a100; +} + +static void +Opcode_wsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a100; +} + +static void +Opcode_xsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a100; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38000; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138000; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618000; +} + +static void +Opcode_rsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38100; +} + +static void +Opcode_wsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138100; +} + +static void +Opcode_xsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618100; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36000; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136000; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616000; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e900; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e900; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e900; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ec00; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ec00; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ec00; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ed00; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ed00; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ed00; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36800; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136800; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616800; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e000; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e010; +} + +static void +Opcode_wsr_mmid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135900; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ea00; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ea00; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ea00; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f000; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f000; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f000; +} + +static void +Opcode_rsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f100; +} + +static void +Opcode_wsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f100; +} + +static void +Opcode_xsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f100; +} + +static void +Opcode_rsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f200; +} + +static void +Opcode_wsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f200; +} + +static void +Opcode_xsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f200; +} + +static void +Opcode_ipf_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70c2; +} + +static void +Opcode_ihi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70e2; +} + +static void +Opcode_ipfl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70d2; +} + +static void +Opcode_ihu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270d2; +} + +static void +Opcode_iiu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x370d2; +} + +static void +Opcode_iii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70f2; +} + +static void +Opcode_lict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf10000; +} + +static void +Opcode_licw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf12000; +} + +static void +Opcode_sict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf11000; +} + +static void +Opcode_sicw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf13000; +} + +static void +Opcode_dhwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7042; +} + +static void +Opcode_dhwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7052; +} + +static void +Opcode_diwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x47082; +} + +static void +Opcode_diwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x57082; +} + +static void +Opcode_dhi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7062; +} + +static void +Opcode_dii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7072; +} + +static void +Opcode_dpfr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7002; +} + +static void +Opcode_dpfw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7012; +} + +static void +Opcode_dpfro_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7022; +} + +static void +Opcode_dpfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7032; +} + +static void +Opcode_dpfl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7082; +} + +static void +Opcode_dhu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x27082; +} + +static void +Opcode_diu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x37082; +} + +static void +Opcode_sdct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf19000; +} + +static void +Opcode_ldct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf18000; +} + +static void +Opcode_wsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135300; +} + +static void +Opcode_rsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35300; +} + +static void +Opcode_xsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615300; +} + +static void +Opcode_rsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35a00; +} + +static void +Opcode_wsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135a00; +} + +static void +Opcode_xsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615a00; +} + +static void +Opcode_rsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35b00; +} + +static void +Opcode_wsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135b00; +} + +static void +Opcode_xsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615b00; +} + +static void +Opcode_rsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35c00; +} + +static void +Opcode_wsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135c00; +} + +static void +Opcode_xsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615c00; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50c000; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50d000; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50b000; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50f000; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50e000; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x504000; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505000; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x503000; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x507000; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x506000; +} + +static void +Opcode_ldpte_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1f000; +} + +static void +Opcode_hwwitlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x501000; +} + +static void +Opcode_hwwdtlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x509000; +} + +static void +Opcode_rsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e000; +} + +static void +Opcode_wsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e000; +} + +static void +Opcode_xsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e000; +} + +static void +Opcode_clamps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x330000; +} + +static void +Opcode_min_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x430000; +} + +static void +Opcode_max_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x530000; +} + +static void +Opcode_minu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x630000; +} + +static void +Opcode_maxu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730000; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40e000; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40f000; +} + +static void +Opcode_sext_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230000; +} + +static void +Opcode_l32ai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb002; +} + +static void +Opcode_s32ri_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf002; +} + +static void +Opcode_s32c1i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe002; +} + +static void +Opcode_rsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30c00; +} + +static void +Opcode_wsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130c00; +} + +static void +Opcode_xsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610c00; +} + +static void +Opcode_quou_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc20000; +} + +static void +Opcode_quos_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd20000; +} + +static void +Opcode_remu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe20000; +} + +static void +Opcode_rems_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf20000; +} + +static void +Opcode_mull_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x820000; +} + +static void +Opcode_rur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e60; +} + +static void +Opcode_wur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e600; +} + +static void +Opcode_read_impwire_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0000; +} + +static void +Opcode_setb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1000; +} + +static void +Opcode_clrb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1200; +} + +static void +Opcode_wrmsk_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe2000; +} + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { + Opcode_call12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { + Opcode_call8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { + Opcode_call4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { + Opcode_callx12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { + Opcode_callx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { + Opcode_callx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { + Opcode_entry_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { + Opcode_movsp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { + Opcode_rotw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { + Opcode_retw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { + 0, 0, Opcode_retw_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { + Opcode_rfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { + Opcode_rfwu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { + Opcode_l32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { + Opcode_s32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { + Opcode_rsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { + Opcode_wsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { + Opcode_xsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { + Opcode_rsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { + Opcode_wsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { + Opcode_xsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_threadptr_encode_fns[] = { + Opcode_rur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_threadptr_encode_fns[] = { + Opcode_wur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { + Opcode_loop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { + Opcode_loopnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { + Opcode_loopgtz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { + Opcode_rsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { + Opcode_wsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { + Opcode_xsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { + Opcode_rsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { + Opcode_wsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { + Opcode_xsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { + Opcode_rsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { + Opcode_wsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { + Opcode_xsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc4_encode_fns[] = { + Opcode_rsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc4_encode_fns[] = { + Opcode_wsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc4_encode_fns[] = { + Opcode_xsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave4_encode_fns[] = { + Opcode_rsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave4_encode_fns[] = { + Opcode_wsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave4_encode_fns[] = { + Opcode_xsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc5_encode_fns[] = { + Opcode_rsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc5_encode_fns[] = { + Opcode_wsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc5_encode_fns[] = { + Opcode_xsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave5_encode_fns[] = { + Opcode_rsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave5_encode_fns[] = { + Opcode_wsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave5_encode_fns[] = { + Opcode_xsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc6_encode_fns[] = { + Opcode_rsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc6_encode_fns[] = { + Opcode_wsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc6_encode_fns[] = { + Opcode_xsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave6_encode_fns[] = { + Opcode_rsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave6_encode_fns[] = { + Opcode_wsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave6_encode_fns[] = { + Opcode_xsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc7_encode_fns[] = { + Opcode_rsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc7_encode_fns[] = { + Opcode_wsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc7_encode_fns[] = { + Opcode_xsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave7_encode_fns[] = { + Opcode_rsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave7_encode_fns[] = { + Opcode_wsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave7_encode_fns[] = { + Opcode_xsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps4_encode_fns[] = { + Opcode_rsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps4_encode_fns[] = { + Opcode_wsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps4_encode_fns[] = { + Opcode_xsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps5_encode_fns[] = { + Opcode_rsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps5_encode_fns[] = { + Opcode_wsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps5_encode_fns[] = { + Opcode_xsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps6_encode_fns[] = { + Opcode_rsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps6_encode_fns[] = { + Opcode_wsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps6_encode_fns[] = { + Opcode_xsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps7_encode_fns[] = { + Opcode_rsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps7_encode_fns[] = { + Opcode_wsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps7_encode_fns[] = { + Opcode_xsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { + Opcode_rsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { + Opcode_wsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { + Opcode_xsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { + Opcode_rsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { + Opcode_wsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { + Opcode_xsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { + Opcode_rsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { + Opcode_wsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { + Opcode_xsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_ll_encode_fns[] = { + Opcode_mul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hl_encode_fns[] = { + Opcode_mul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_lh_encode_fns[] = { + Opcode_mul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hh_encode_fns[] = { + Opcode_mul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_ll_encode_fns[] = { + Opcode_umul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hl_encode_fns[] = { + Opcode_umul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_lh_encode_fns[] = { + Opcode_umul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hh_encode_fns[] = { + Opcode_umul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_ll_encode_fns[] = { + Opcode_mul_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hl_encode_fns[] = { + Opcode_mul_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_lh_encode_fns[] = { + Opcode_mul_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hh_encode_fns[] = { + Opcode_mul_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_ll_encode_fns[] = { + Opcode_mul_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hl_encode_fns[] = { + Opcode_mul_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_lh_encode_fns[] = { + Opcode_mul_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hh_encode_fns[] = { + Opcode_mul_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_ll_encode_fns[] = { + Opcode_mul_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hl_encode_fns[] = { + Opcode_mul_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_lh_encode_fns[] = { + Opcode_mul_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hh_encode_fns[] = { + Opcode_mul_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_ll_encode_fns[] = { + Opcode_mula_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hl_encode_fns[] = { + Opcode_mula_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_lh_encode_fns[] = { + Opcode_mula_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hh_encode_fns[] = { + Opcode_mula_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_ll_encode_fns[] = { + Opcode_muls_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hl_encode_fns[] = { + Opcode_muls_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_lh_encode_fns[] = { + Opcode_muls_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hh_encode_fns[] = { + Opcode_muls_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_ll_encode_fns[] = { + Opcode_mula_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hl_encode_fns[] = { + Opcode_mula_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_lh_encode_fns[] = { + Opcode_mula_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hh_encode_fns[] = { + Opcode_mula_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_ll_encode_fns[] = { + Opcode_muls_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hl_encode_fns[] = { + Opcode_muls_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_lh_encode_fns[] = { + Opcode_muls_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hh_encode_fns[] = { + Opcode_muls_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_encode_fns[] = { + Opcode_mula_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_encode_fns[] = { + Opcode_mula_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_encode_fns[] = { + Opcode_mula_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_encode_fns[] = { + Opcode_mula_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_ll_encode_fns[] = { + Opcode_muls_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hl_encode_fns[] = { + Opcode_muls_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_lh_encode_fns[] = { + Opcode_muls_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hh_encode_fns[] = { + Opcode_muls_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_encode_fns[] = { + Opcode_mula_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_encode_fns[] = { + Opcode_mula_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_encode_fns[] = { + Opcode_mula_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_encode_fns[] = { + Opcode_mula_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_ll_encode_fns[] = { + Opcode_muls_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hl_encode_fns[] = { + Opcode_muls_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_lh_encode_fns[] = { + Opcode_muls_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hh_encode_fns[] = { + Opcode_muls_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_lddec_encode_fns[] = { + Opcode_mula_da_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_ldinc_encode_fns[] = { + Opcode_mula_da_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_lddec_encode_fns[] = { + Opcode_mula_da_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_ldinc_encode_fns[] = { + Opcode_mula_da_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_lddec_encode_fns[] = { + Opcode_mula_da_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_ldinc_encode_fns[] = { + Opcode_mula_da_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_lddec_encode_fns[] = { + Opcode_mula_da_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_ldinc_encode_fns[] = { + Opcode_mula_da_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_lddec_encode_fns[] = { + Opcode_mula_dd_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_ldinc_encode_fns[] = { + Opcode_mula_dd_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_lddec_encode_fns[] = { + Opcode_mula_dd_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_ldinc_encode_fns[] = { + Opcode_mula_dd_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_lddec_encode_fns[] = { + Opcode_mula_dd_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_ldinc_encode_fns[] = { + Opcode_mula_dd_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_lddec_encode_fns[] = { + Opcode_mula_dd_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_ldinc_encode_fns[] = { + Opcode_mula_dd_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lddec_encode_fns[] = { + Opcode_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldinc_encode_fns[] = { + Opcode_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { + Opcode_mul16u_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { + Opcode_mul16s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m0_encode_fns[] = { + Opcode_rsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m0_encode_fns[] = { + Opcode_wsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m0_encode_fns[] = { + Opcode_xsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m1_encode_fns[] = { + Opcode_rsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m1_encode_fns[] = { + Opcode_wsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m1_encode_fns[] = { + Opcode_xsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m2_encode_fns[] = { + Opcode_rsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m2_encode_fns[] = { + Opcode_wsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m2_encode_fns[] = { + Opcode_xsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m3_encode_fns[] = { + Opcode_rsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m3_encode_fns[] = { + Opcode_wsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m3_encode_fns[] = { + Opcode_xsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acclo_encode_fns[] = { + Opcode_rsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acclo_encode_fns[] = { + Opcode_wsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acclo_encode_fns[] = { + Opcode_xsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acchi_encode_fns[] = { + Opcode_rsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acchi_encode_fns[] = { + Opcode_wsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acchi_encode_fns[] = { + Opcode_xsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka1_encode_fns[] = { + Opcode_rsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka1_encode_fns[] = { + Opcode_wsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka1_encode_fns[] = { + Opcode_xsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc1_encode_fns[] = { + Opcode_rsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc1_encode_fns[] = { + Opcode_wsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc1_encode_fns[] = { + Opcode_xsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka1_encode_fns[] = { + Opcode_rsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka1_encode_fns[] = { + Opcode_wsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka1_encode_fns[] = { + Opcode_xsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_mmid_encode_fns[] = { + Opcode_wsr_mmid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { + Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { + Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { + Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare2_encode_fns[] = { + Opcode_rsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare2_encode_fns[] = { + Opcode_wsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare2_encode_fns[] = { + Opcode_xsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { + Opcode_ipf_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { + Opcode_ihi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ipfl_encode_fns[] = { + Opcode_ipfl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ihu_encode_fns[] = { + Opcode_ihu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iiu_encode_fns[] = { + Opcode_iiu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { + Opcode_iii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { + Opcode_lict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { + Opcode_licw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { + Opcode_sict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { + Opcode_sicw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { + Opcode_dhwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { + Opcode_dhwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { + Opcode_diwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { + Opcode_diwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { + Opcode_dhi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { + Opcode_dii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { + Opcode_dpfr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { + Opcode_dpfw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { + Opcode_dpfro_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { + Opcode_dpfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfl_encode_fns[] = { + Opcode_dpfl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhu_encode_fns[] = { + Opcode_dhu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diu_encode_fns[] = { + Opcode_diu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { + Opcode_sdct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { + Opcode_ldct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ptevaddr_encode_fns[] = { + Opcode_wsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ptevaddr_encode_fns[] = { + Opcode_rsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ptevaddr_encode_fns[] = { + Opcode_xsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_rasid_encode_fns[] = { + Opcode_rsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_rasid_encode_fns[] = { + Opcode_wsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_rasid_encode_fns[] = { + Opcode_xsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_itlbcfg_encode_fns[] = { + Opcode_rsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_itlbcfg_encode_fns[] = { + Opcode_wsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_itlbcfg_encode_fns[] = { + Opcode_xsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dtlbcfg_encode_fns[] = { + Opcode_rsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dtlbcfg_encode_fns[] = { + Opcode_wsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dtlbcfg_encode_fns[] = { + Opcode_xsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldpte_encode_fns[] = { + Opcode_ldpte_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwitlba_encode_fns[] = { + Opcode_hwwitlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwdtlba_encode_fns[] = { + Opcode_hwwdtlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_cpenable_encode_fns[] = { + Opcode_rsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_cpenable_encode_fns[] = { + Opcode_wsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_cpenable_encode_fns[] = { + Opcode_xsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clamps_encode_fns[] = { + Opcode_clamps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_min_encode_fns[] = { + Opcode_min_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_max_encode_fns[] = { + Opcode_max_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_minu_encode_fns[] = { + Opcode_minu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_maxu_encode_fns[] = { + Opcode_maxu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sext_encode_fns[] = { + Opcode_sext_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32ai_encode_fns[] = { + Opcode_l32ai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32ri_encode_fns[] = { + Opcode_s32ri_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32c1i_encode_fns[] = { + Opcode_s32c1i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_scompare1_encode_fns[] = { + Opcode_rsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_scompare1_encode_fns[] = { + Opcode_wsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_scompare1_encode_fns[] = { + Opcode_xsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quou_encode_fns[] = { + Opcode_quou_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quos_encode_fns[] = { + Opcode_quos_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_remu_encode_fns[] = { + Opcode_remu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rems_encode_fns[] = { + Opcode_rems_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { + Opcode_mull_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_expstate_encode_fns[] = { + Opcode_rur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_expstate_encode_fns[] = { + Opcode_wur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_read_impwire_encode_fns[] = { + Opcode_read_impwire_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_setb_expstate_encode_fns[] = { + Opcode_setb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clrb_expstate_encode_fns[] = { + Opcode_clrb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wrmsk_expstate_encode_fns[] = { + Opcode_wrmsk_expstate_Slot_inst_encode, 0, 0 +}; + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", 0 /* xt_iclass_excw */, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", 1 /* xt_iclass_rfe */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", 2 /* xt_iclass_rfde */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", 3 /* xt_iclass_syscall */, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", 4 /* xt_iclass_simcall */, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "call12", 5 /* xt_iclass_call12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call12_encode_fns, 0, 0 }, + { "call8", 6 /* xt_iclass_call8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call8_encode_fns, 0, 0 }, + { "call4", 7 /* xt_iclass_call4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call4_encode_fns, 0, 0 }, + { "callx12", 8 /* xt_iclass_callx12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx12_encode_fns, 0, 0 }, + { "callx8", 9 /* xt_iclass_callx8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx8_encode_fns, 0, 0 }, + { "callx4", 10 /* xt_iclass_callx4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx4_encode_fns, 0, 0 }, + { "entry", 11 /* xt_iclass_entry */, + 0, + Opcode_entry_encode_fns, 0, 0 }, + { "movsp", 12 /* xt_iclass_movsp */, + 0, + Opcode_movsp_encode_fns, 0, 0 }, + { "rotw", 13 /* xt_iclass_rotw */, + 0, + Opcode_rotw_encode_fns, 0, 0 }, + { "retw", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_encode_fns, 0, 0 }, + { "retw.n", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_n_encode_fns, 0, 0 }, + { "rfwo", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwo_encode_fns, 0, 0 }, + { "rfwu", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwu_encode_fns, 0, 0 }, + { "l32e", 16 /* xt_iclass_l32e */, + 0, + Opcode_l32e_encode_fns, 0, 0 }, + { "s32e", 17 /* xt_iclass_s32e */, + 0, + Opcode_s32e_encode_fns, 0, 0 }, + { "rsr.windowbase", 18 /* xt_iclass_rsr.windowbase */, + 0, + Opcode_rsr_windowbase_encode_fns, 0, 0 }, + { "wsr.windowbase", 19 /* xt_iclass_wsr.windowbase */, + 0, + Opcode_wsr_windowbase_encode_fns, 0, 0 }, + { "xsr.windowbase", 20 /* xt_iclass_xsr.windowbase */, + 0, + Opcode_xsr_windowbase_encode_fns, 0, 0 }, + { "rsr.windowstart", 21 /* xt_iclass_rsr.windowstart */, + 0, + Opcode_rsr_windowstart_encode_fns, 0, 0 }, + { "wsr.windowstart", 22 /* xt_iclass_wsr.windowstart */, + 0, + Opcode_wsr_windowstart_encode_fns, 0, 0 }, + { "xsr.windowstart", 23 /* xt_iclass_xsr.windowstart */, + 0, + Opcode_xsr_windowstart_encode_fns, 0, 0 }, + { "add.n", 24 /* xt_iclass_add.n */, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", 25 /* xt_iclass_addi.n */, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", 27 /* xt_iclass_ill.n */, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", 28 /* xt_iclass_loadi4 */, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", 29 /* xt_iclass_mov.n */, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", 30 /* xt_iclass_movi.n */, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", 31 /* xt_iclass_nopn */, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", 32 /* xt_iclass_retn */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", 33 /* xt_iclass_storei4 */, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "rur.threadptr", 34 /* rur_threadptr */, + 0, + Opcode_rur_threadptr_encode_fns, 0, 0 }, + { "wur.threadptr", 35 /* wur_threadptr */, + 0, + Opcode_wur_threadptr_encode_fns, 0, 0 }, + { "addi", 36 /* xt_iclass_addi */, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", 37 /* xt_iclass_addmi */, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", 38 /* xt_iclass_addsub */, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", 38 /* xt_iclass_addsub */, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", 38 /* xt_iclass_addsub */, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", 38 /* xt_iclass_addsub */, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", 38 /* xt_iclass_addsub */, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", 38 /* xt_iclass_addsub */, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", 38 /* xt_iclass_addsub */, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", 38 /* xt_iclass_addsub */, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", 39 /* xt_iclass_bit */, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", 39 /* xt_iclass_bit */, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", 39 /* xt_iclass_bit */, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", 40 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", 40 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", 40 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", 40 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", 41 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", 41 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", 42 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", 42 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", 43 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", 44 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", 44 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", 44 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", 44 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", 45 /* xt_iclass_call0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", 46 /* xt_iclass_callx0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", 47 /* xt_iclass_exti */, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", 48 /* xt_iclass_ill */, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", 49 /* xt_iclass_jump */, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", 50 /* xt_iclass_jumpx */, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", 51 /* xt_iclass_l16ui */, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", 52 /* xt_iclass_l16si */, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", 53 /* xt_iclass_l32i */, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", 54 /* xt_iclass_l32r */, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", 55 /* xt_iclass_l8i */, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "loop", 56 /* xt_iclass_loop */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loop_encode_fns, 0, 0 }, + { "loopnez", 57 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopnez_encode_fns, 0, 0 }, + { "loopgtz", 57 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopgtz_encode_fns, 0, 0 }, + { "movi", 58 /* xt_iclass_movi */, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", 59 /* xt_iclass_movz */, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", 59 /* xt_iclass_movz */, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", 59 /* xt_iclass_movz */, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", 59 /* xt_iclass_movz */, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", 60 /* xt_iclass_neg */, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", 60 /* xt_iclass_neg */, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", 61 /* xt_iclass_nop */, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", 62 /* xt_iclass_return */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", 63 /* xt_iclass_s16i */, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", 64 /* xt_iclass_s32i */, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", 65 /* xt_iclass_s8i */, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", 66 /* xt_iclass_sar */, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", 66 /* xt_iclass_sar */, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", 66 /* xt_iclass_sar */, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", 66 /* xt_iclass_sar */, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", 67 /* xt_iclass_sari */, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", 68 /* xt_iclass_shifts */, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", 69 /* xt_iclass_shiftst */, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", 70 /* xt_iclass_shiftt */, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", 70 /* xt_iclass_shiftt */, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", 71 /* xt_iclass_slli */, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", 72 /* xt_iclass_srai */, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", 73 /* xt_iclass_srli */, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", 74 /* xt_iclass_memw */, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", 75 /* xt_iclass_extw */, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", 76 /* xt_iclass_isync */, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", 77 /* xt_iclass_sync */, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", 77 /* xt_iclass_sync */, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", 77 /* xt_iclass_sync */, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", 78 /* xt_iclass_rsil */, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.lend", 79 /* xt_iclass_rsr.lend */, + 0, + Opcode_rsr_lend_encode_fns, 0, 0 }, + { "wsr.lend", 80 /* xt_iclass_wsr.lend */, + 0, + Opcode_wsr_lend_encode_fns, 0, 0 }, + { "xsr.lend", 81 /* xt_iclass_xsr.lend */, + 0, + Opcode_xsr_lend_encode_fns, 0, 0 }, + { "rsr.lcount", 82 /* xt_iclass_rsr.lcount */, + 0, + Opcode_rsr_lcount_encode_fns, 0, 0 }, + { "wsr.lcount", 83 /* xt_iclass_wsr.lcount */, + 0, + Opcode_wsr_lcount_encode_fns, 0, 0 }, + { "xsr.lcount", 84 /* xt_iclass_xsr.lcount */, + 0, + Opcode_xsr_lcount_encode_fns, 0, 0 }, + { "rsr.lbeg", 85 /* xt_iclass_rsr.lbeg */, + 0, + Opcode_rsr_lbeg_encode_fns, 0, 0 }, + { "wsr.lbeg", 86 /* xt_iclass_wsr.lbeg */, + 0, + Opcode_wsr_lbeg_encode_fns, 0, 0 }, + { "xsr.lbeg", 87 /* xt_iclass_xsr.lbeg */, + 0, + Opcode_xsr_lbeg_encode_fns, 0, 0 }, + { "rsr.sar", 88 /* xt_iclass_rsr.sar */, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", 89 /* xt_iclass_wsr.sar */, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", 90 /* xt_iclass_xsr.sar */, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", 91 /* xt_iclass_rsr.litbase */, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", 92 /* xt_iclass_wsr.litbase */, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", 93 /* xt_iclass_xsr.litbase */, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", 94 /* xt_iclass_rsr.176 */, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "rsr.208", 95 /* xt_iclass_rsr.208 */, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", 96 /* xt_iclass_rsr.ps */, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", 97 /* xt_iclass_wsr.ps */, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", 98 /* xt_iclass_xsr.ps */, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", 99 /* xt_iclass_rsr.epc1 */, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", 100 /* xt_iclass_wsr.epc1 */, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", 101 /* xt_iclass_xsr.epc1 */, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", 102 /* xt_iclass_rsr.excsave1 */, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", 103 /* xt_iclass_wsr.excsave1 */, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", 104 /* xt_iclass_xsr.excsave1 */, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", 105 /* xt_iclass_rsr.epc2 */, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", 106 /* xt_iclass_wsr.epc2 */, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", 107 /* xt_iclass_xsr.epc2 */, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", 108 /* xt_iclass_rsr.excsave2 */, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", 109 /* xt_iclass_wsr.excsave2 */, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", 110 /* xt_iclass_xsr.excsave2 */, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", 111 /* xt_iclass_rsr.epc3 */, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", 112 /* xt_iclass_wsr.epc3 */, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", 113 /* xt_iclass_xsr.epc3 */, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", 114 /* xt_iclass_rsr.excsave3 */, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", 115 /* xt_iclass_wsr.excsave3 */, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", 116 /* xt_iclass_xsr.excsave3 */, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.epc4", 117 /* xt_iclass_rsr.epc4 */, + 0, + Opcode_rsr_epc4_encode_fns, 0, 0 }, + { "wsr.epc4", 118 /* xt_iclass_wsr.epc4 */, + 0, + Opcode_wsr_epc4_encode_fns, 0, 0 }, + { "xsr.epc4", 119 /* xt_iclass_xsr.epc4 */, + 0, + Opcode_xsr_epc4_encode_fns, 0, 0 }, + { "rsr.excsave4", 120 /* xt_iclass_rsr.excsave4 */, + 0, + Opcode_rsr_excsave4_encode_fns, 0, 0 }, + { "wsr.excsave4", 121 /* xt_iclass_wsr.excsave4 */, + 0, + Opcode_wsr_excsave4_encode_fns, 0, 0 }, + { "xsr.excsave4", 122 /* xt_iclass_xsr.excsave4 */, + 0, + Opcode_xsr_excsave4_encode_fns, 0, 0 }, + { "rsr.epc5", 123 /* xt_iclass_rsr.epc5 */, + 0, + Opcode_rsr_epc5_encode_fns, 0, 0 }, + { "wsr.epc5", 124 /* xt_iclass_wsr.epc5 */, + 0, + Opcode_wsr_epc5_encode_fns, 0, 0 }, + { "xsr.epc5", 125 /* xt_iclass_xsr.epc5 */, + 0, + Opcode_xsr_epc5_encode_fns, 0, 0 }, + { "rsr.excsave5", 126 /* xt_iclass_rsr.excsave5 */, + 0, + Opcode_rsr_excsave5_encode_fns, 0, 0 }, + { "wsr.excsave5", 127 /* xt_iclass_wsr.excsave5 */, + 0, + Opcode_wsr_excsave5_encode_fns, 0, 0 }, + { "xsr.excsave5", 128 /* xt_iclass_xsr.excsave5 */, + 0, + Opcode_xsr_excsave5_encode_fns, 0, 0 }, + { "rsr.epc6", 129 /* xt_iclass_rsr.epc6 */, + 0, + Opcode_rsr_epc6_encode_fns, 0, 0 }, + { "wsr.epc6", 130 /* xt_iclass_wsr.epc6 */, + 0, + Opcode_wsr_epc6_encode_fns, 0, 0 }, + { "xsr.epc6", 131 /* xt_iclass_xsr.epc6 */, + 0, + Opcode_xsr_epc6_encode_fns, 0, 0 }, + { "rsr.excsave6", 132 /* xt_iclass_rsr.excsave6 */, + 0, + Opcode_rsr_excsave6_encode_fns, 0, 0 }, + { "wsr.excsave6", 133 /* xt_iclass_wsr.excsave6 */, + 0, + Opcode_wsr_excsave6_encode_fns, 0, 0 }, + { "xsr.excsave6", 134 /* xt_iclass_xsr.excsave6 */, + 0, + Opcode_xsr_excsave6_encode_fns, 0, 0 }, + { "rsr.epc7", 135 /* xt_iclass_rsr.epc7 */, + 0, + Opcode_rsr_epc7_encode_fns, 0, 0 }, + { "wsr.epc7", 136 /* xt_iclass_wsr.epc7 */, + 0, + Opcode_wsr_epc7_encode_fns, 0, 0 }, + { "xsr.epc7", 137 /* xt_iclass_xsr.epc7 */, + 0, + Opcode_xsr_epc7_encode_fns, 0, 0 }, + { "rsr.excsave7", 138 /* xt_iclass_rsr.excsave7 */, + 0, + Opcode_rsr_excsave7_encode_fns, 0, 0 }, + { "wsr.excsave7", 139 /* xt_iclass_wsr.excsave7 */, + 0, + Opcode_wsr_excsave7_encode_fns, 0, 0 }, + { "xsr.excsave7", 140 /* xt_iclass_xsr.excsave7 */, + 0, + Opcode_xsr_excsave7_encode_fns, 0, 0 }, + { "rsr.eps2", 141 /* xt_iclass_rsr.eps2 */, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", 142 /* xt_iclass_wsr.eps2 */, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", 143 /* xt_iclass_xsr.eps2 */, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", 144 /* xt_iclass_rsr.eps3 */, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", 145 /* xt_iclass_wsr.eps3 */, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", 146 /* xt_iclass_xsr.eps3 */, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.eps4", 147 /* xt_iclass_rsr.eps4 */, + 0, + Opcode_rsr_eps4_encode_fns, 0, 0 }, + { "wsr.eps4", 148 /* xt_iclass_wsr.eps4 */, + 0, + Opcode_wsr_eps4_encode_fns, 0, 0 }, + { "xsr.eps4", 149 /* xt_iclass_xsr.eps4 */, + 0, + Opcode_xsr_eps4_encode_fns, 0, 0 }, + { "rsr.eps5", 150 /* xt_iclass_rsr.eps5 */, + 0, + Opcode_rsr_eps5_encode_fns, 0, 0 }, + { "wsr.eps5", 151 /* xt_iclass_wsr.eps5 */, + 0, + Opcode_wsr_eps5_encode_fns, 0, 0 }, + { "xsr.eps5", 152 /* xt_iclass_xsr.eps5 */, + 0, + Opcode_xsr_eps5_encode_fns, 0, 0 }, + { "rsr.eps6", 153 /* xt_iclass_rsr.eps6 */, + 0, + Opcode_rsr_eps6_encode_fns, 0, 0 }, + { "wsr.eps6", 154 /* xt_iclass_wsr.eps6 */, + 0, + Opcode_wsr_eps6_encode_fns, 0, 0 }, + { "xsr.eps6", 155 /* xt_iclass_xsr.eps6 */, + 0, + Opcode_xsr_eps6_encode_fns, 0, 0 }, + { "rsr.eps7", 156 /* xt_iclass_rsr.eps7 */, + 0, + Opcode_rsr_eps7_encode_fns, 0, 0 }, + { "wsr.eps7", 157 /* xt_iclass_wsr.eps7 */, + 0, + Opcode_wsr_eps7_encode_fns, 0, 0 }, + { "xsr.eps7", 158 /* xt_iclass_xsr.eps7 */, + 0, + Opcode_xsr_eps7_encode_fns, 0, 0 }, + { "rsr.excvaddr", 159 /* xt_iclass_rsr.excvaddr */, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", 160 /* xt_iclass_wsr.excvaddr */, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", 161 /* xt_iclass_xsr.excvaddr */, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", 162 /* xt_iclass_rsr.depc */, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", 163 /* xt_iclass_wsr.depc */, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", 164 /* xt_iclass_xsr.depc */, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", 165 /* xt_iclass_rsr.exccause */, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", 166 /* xt_iclass_wsr.exccause */, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", 167 /* xt_iclass_xsr.exccause */, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.misc0", 168 /* xt_iclass_rsr.misc0 */, + 0, + Opcode_rsr_misc0_encode_fns, 0, 0 }, + { "wsr.misc0", 169 /* xt_iclass_wsr.misc0 */, + 0, + Opcode_wsr_misc0_encode_fns, 0, 0 }, + { "xsr.misc0", 170 /* xt_iclass_xsr.misc0 */, + 0, + Opcode_xsr_misc0_encode_fns, 0, 0 }, + { "rsr.misc1", 171 /* xt_iclass_rsr.misc1 */, + 0, + Opcode_rsr_misc1_encode_fns, 0, 0 }, + { "wsr.misc1", 172 /* xt_iclass_wsr.misc1 */, + 0, + Opcode_wsr_misc1_encode_fns, 0, 0 }, + { "xsr.misc1", 173 /* xt_iclass_xsr.misc1 */, + 0, + Opcode_xsr_misc1_encode_fns, 0, 0 }, + { "rsr.prid", 174 /* xt_iclass_rsr.prid */, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rsr.vecbase", 175 /* xt_iclass_rsr.vecbase */, + 0, + Opcode_rsr_vecbase_encode_fns, 0, 0 }, + { "wsr.vecbase", 176 /* xt_iclass_wsr.vecbase */, + 0, + Opcode_wsr_vecbase_encode_fns, 0, 0 }, + { "xsr.vecbase", 177 /* xt_iclass_xsr.vecbase */, + 0, + Opcode_xsr_vecbase_encode_fns, 0, 0 }, + { "mul.aa.ll", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_mul_aa_ll_encode_fns, 0, 0 }, + { "mul.aa.hl", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_mul_aa_hl_encode_fns, 0, 0 }, + { "mul.aa.lh", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_mul_aa_lh_encode_fns, 0, 0 }, + { "mul.aa.hh", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_mul_aa_hh_encode_fns, 0, 0 }, + { "umul.aa.ll", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_umul_aa_ll_encode_fns, 0, 0 }, + { "umul.aa.hl", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_umul_aa_hl_encode_fns, 0, 0 }, + { "umul.aa.lh", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_umul_aa_lh_encode_fns, 0, 0 }, + { "umul.aa.hh", 178 /* xt_iclass_mac16_aa */, + 0, + Opcode_umul_aa_hh_encode_fns, 0, 0 }, + { "mul.ad.ll", 179 /* xt_iclass_mac16_ad */, + 0, + Opcode_mul_ad_ll_encode_fns, 0, 0 }, + { "mul.ad.hl", 179 /* xt_iclass_mac16_ad */, + 0, + Opcode_mul_ad_hl_encode_fns, 0, 0 }, + { "mul.ad.lh", 179 /* xt_iclass_mac16_ad */, + 0, + Opcode_mul_ad_lh_encode_fns, 0, 0 }, + { "mul.ad.hh", 179 /* xt_iclass_mac16_ad */, + 0, + Opcode_mul_ad_hh_encode_fns, 0, 0 }, + { "mul.da.ll", 180 /* xt_iclass_mac16_da */, + 0, + Opcode_mul_da_ll_encode_fns, 0, 0 }, + { "mul.da.hl", 180 /* xt_iclass_mac16_da */, + 0, + Opcode_mul_da_hl_encode_fns, 0, 0 }, + { "mul.da.lh", 180 /* xt_iclass_mac16_da */, + 0, + Opcode_mul_da_lh_encode_fns, 0, 0 }, + { "mul.da.hh", 180 /* xt_iclass_mac16_da */, + 0, + Opcode_mul_da_hh_encode_fns, 0, 0 }, + { "mul.dd.ll", 181 /* xt_iclass_mac16_dd */, + 0, + Opcode_mul_dd_ll_encode_fns, 0, 0 }, + { "mul.dd.hl", 181 /* xt_iclass_mac16_dd */, + 0, + Opcode_mul_dd_hl_encode_fns, 0, 0 }, + { "mul.dd.lh", 181 /* xt_iclass_mac16_dd */, + 0, + Opcode_mul_dd_lh_encode_fns, 0, 0 }, + { "mul.dd.hh", 181 /* xt_iclass_mac16_dd */, + 0, + Opcode_mul_dd_hh_encode_fns, 0, 0 }, + { "mula.aa.ll", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_mula_aa_ll_encode_fns, 0, 0 }, + { "mula.aa.hl", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_mula_aa_hl_encode_fns, 0, 0 }, + { "mula.aa.lh", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_mula_aa_lh_encode_fns, 0, 0 }, + { "mula.aa.hh", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_mula_aa_hh_encode_fns, 0, 0 }, + { "muls.aa.ll", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_muls_aa_ll_encode_fns, 0, 0 }, + { "muls.aa.hl", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_muls_aa_hl_encode_fns, 0, 0 }, + { "muls.aa.lh", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_muls_aa_lh_encode_fns, 0, 0 }, + { "muls.aa.hh", 182 /* xt_iclass_mac16a_aa */, + 0, + Opcode_muls_aa_hh_encode_fns, 0, 0 }, + { "mula.ad.ll", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_mula_ad_ll_encode_fns, 0, 0 }, + { "mula.ad.hl", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_mula_ad_hl_encode_fns, 0, 0 }, + { "mula.ad.lh", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_mula_ad_lh_encode_fns, 0, 0 }, + { "mula.ad.hh", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_mula_ad_hh_encode_fns, 0, 0 }, + { "muls.ad.ll", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_muls_ad_ll_encode_fns, 0, 0 }, + { "muls.ad.hl", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_muls_ad_hl_encode_fns, 0, 0 }, + { "muls.ad.lh", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_muls_ad_lh_encode_fns, 0, 0 }, + { "muls.ad.hh", 183 /* xt_iclass_mac16a_ad */, + 0, + Opcode_muls_ad_hh_encode_fns, 0, 0 }, + { "mula.da.ll", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_mula_da_ll_encode_fns, 0, 0 }, + { "mula.da.hl", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_mula_da_hl_encode_fns, 0, 0 }, + { "mula.da.lh", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_mula_da_lh_encode_fns, 0, 0 }, + { "mula.da.hh", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_mula_da_hh_encode_fns, 0, 0 }, + { "muls.da.ll", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_muls_da_ll_encode_fns, 0, 0 }, + { "muls.da.hl", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_muls_da_hl_encode_fns, 0, 0 }, + { "muls.da.lh", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_muls_da_lh_encode_fns, 0, 0 }, + { "muls.da.hh", 184 /* xt_iclass_mac16a_da */, + 0, + Opcode_muls_da_hh_encode_fns, 0, 0 }, + { "mula.dd.ll", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_mula_dd_ll_encode_fns, 0, 0 }, + { "mula.dd.hl", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_mula_dd_hl_encode_fns, 0, 0 }, + { "mula.dd.lh", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_mula_dd_lh_encode_fns, 0, 0 }, + { "mula.dd.hh", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_mula_dd_hh_encode_fns, 0, 0 }, + { "muls.dd.ll", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_muls_dd_ll_encode_fns, 0, 0 }, + { "muls.dd.hl", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_muls_dd_hl_encode_fns, 0, 0 }, + { "muls.dd.lh", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_muls_dd_lh_encode_fns, 0, 0 }, + { "muls.dd.hh", 185 /* xt_iclass_mac16a_dd */, + 0, + Opcode_muls_dd_hh_encode_fns, 0, 0 }, + { "mula.da.ll.lddec", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_ll_lddec_encode_fns, 0, 0 }, + { "mula.da.ll.ldinc", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_ll_ldinc_encode_fns, 0, 0 }, + { "mula.da.hl.lddec", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_hl_lddec_encode_fns, 0, 0 }, + { "mula.da.hl.ldinc", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_hl_ldinc_encode_fns, 0, 0 }, + { "mula.da.lh.lddec", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_lh_lddec_encode_fns, 0, 0 }, + { "mula.da.lh.ldinc", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_lh_ldinc_encode_fns, 0, 0 }, + { "mula.da.hh.lddec", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_hh_lddec_encode_fns, 0, 0 }, + { "mula.da.hh.ldinc", 186 /* xt_iclass_mac16al_da */, + 0, + Opcode_mula_da_hh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.ll.lddec", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_ll_lddec_encode_fns, 0, 0 }, + { "mula.dd.ll.ldinc", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_ll_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hl.lddec", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_hl_lddec_encode_fns, 0, 0 }, + { "mula.dd.hl.ldinc", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_hl_ldinc_encode_fns, 0, 0 }, + { "mula.dd.lh.lddec", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_lh_lddec_encode_fns, 0, 0 }, + { "mula.dd.lh.ldinc", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_lh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hh.lddec", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_hh_lddec_encode_fns, 0, 0 }, + { "mula.dd.hh.ldinc", 187 /* xt_iclass_mac16al_dd */, + 0, + Opcode_mula_dd_hh_ldinc_encode_fns, 0, 0 }, + { "lddec", 188 /* xt_iclass_mac16_l */, + 0, + Opcode_lddec_encode_fns, 0, 0 }, + { "ldinc", 188 /* xt_iclass_mac16_l */, + 0, + Opcode_ldinc_encode_fns, 0, 0 }, + { "mul16u", 189 /* xt_iclass_mul16 */, + 0, + Opcode_mul16u_encode_fns, 0, 0 }, + { "mul16s", 189 /* xt_iclass_mul16 */, + 0, + Opcode_mul16s_encode_fns, 0, 0 }, + { "rsr.m0", 190 /* xt_iclass_rsr.m0 */, + 0, + Opcode_rsr_m0_encode_fns, 0, 0 }, + { "wsr.m0", 191 /* xt_iclass_wsr.m0 */, + 0, + Opcode_wsr_m0_encode_fns, 0, 0 }, + { "xsr.m0", 192 /* xt_iclass_xsr.m0 */, + 0, + Opcode_xsr_m0_encode_fns, 0, 0 }, + { "rsr.m1", 193 /* xt_iclass_rsr.m1 */, + 0, + Opcode_rsr_m1_encode_fns, 0, 0 }, + { "wsr.m1", 194 /* xt_iclass_wsr.m1 */, + 0, + Opcode_wsr_m1_encode_fns, 0, 0 }, + { "xsr.m1", 195 /* xt_iclass_xsr.m1 */, + 0, + Opcode_xsr_m1_encode_fns, 0, 0 }, + { "rsr.m2", 196 /* xt_iclass_rsr.m2 */, + 0, + Opcode_rsr_m2_encode_fns, 0, 0 }, + { "wsr.m2", 197 /* xt_iclass_wsr.m2 */, + 0, + Opcode_wsr_m2_encode_fns, 0, 0 }, + { "xsr.m2", 198 /* xt_iclass_xsr.m2 */, + 0, + Opcode_xsr_m2_encode_fns, 0, 0 }, + { "rsr.m3", 199 /* xt_iclass_rsr.m3 */, + 0, + Opcode_rsr_m3_encode_fns, 0, 0 }, + { "wsr.m3", 200 /* xt_iclass_wsr.m3 */, + 0, + Opcode_wsr_m3_encode_fns, 0, 0 }, + { "xsr.m3", 201 /* xt_iclass_xsr.m3 */, + 0, + Opcode_xsr_m3_encode_fns, 0, 0 }, + { "rsr.acclo", 202 /* xt_iclass_rsr.acclo */, + 0, + Opcode_rsr_acclo_encode_fns, 0, 0 }, + { "wsr.acclo", 203 /* xt_iclass_wsr.acclo */, + 0, + Opcode_wsr_acclo_encode_fns, 0, 0 }, + { "xsr.acclo", 204 /* xt_iclass_xsr.acclo */, + 0, + Opcode_xsr_acclo_encode_fns, 0, 0 }, + { "rsr.acchi", 205 /* xt_iclass_rsr.acchi */, + 0, + Opcode_rsr_acchi_encode_fns, 0, 0 }, + { "wsr.acchi", 206 /* xt_iclass_wsr.acchi */, + 0, + Opcode_wsr_acchi_encode_fns, 0, 0 }, + { "xsr.acchi", 207 /* xt_iclass_xsr.acchi */, + 0, + Opcode_xsr_acchi_encode_fns, 0, 0 }, + { "rfi", 208 /* xt_iclass_rfi */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", 209 /* xt_iclass_wait */, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", 210 /* xt_iclass_rsr.interrupt */, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", 211 /* xt_iclass_wsr.intset */, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", 212 /* xt_iclass_wsr.intclear */, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", 213 /* xt_iclass_rsr.intenable */, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", 214 /* xt_iclass_wsr.intenable */, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", 215 /* xt_iclass_xsr.intenable */, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", 216 /* xt_iclass_break */, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", 217 /* xt_iclass_break.n */, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", 218 /* xt_iclass_rsr.dbreaka0 */, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", 219 /* xt_iclass_wsr.dbreaka0 */, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", 220 /* xt_iclass_xsr.dbreaka0 */, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", 221 /* xt_iclass_rsr.dbreakc0 */, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", 222 /* xt_iclass_wsr.dbreakc0 */, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", 223 /* xt_iclass_xsr.dbreakc0 */, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.dbreaka1", 224 /* xt_iclass_rsr.dbreaka1 */, + 0, + Opcode_rsr_dbreaka1_encode_fns, 0, 0 }, + { "wsr.dbreaka1", 225 /* xt_iclass_wsr.dbreaka1 */, + 0, + Opcode_wsr_dbreaka1_encode_fns, 0, 0 }, + { "xsr.dbreaka1", 226 /* xt_iclass_xsr.dbreaka1 */, + 0, + Opcode_xsr_dbreaka1_encode_fns, 0, 0 }, + { "rsr.dbreakc1", 227 /* xt_iclass_rsr.dbreakc1 */, + 0, + Opcode_rsr_dbreakc1_encode_fns, 0, 0 }, + { "wsr.dbreakc1", 228 /* xt_iclass_wsr.dbreakc1 */, + 0, + Opcode_wsr_dbreakc1_encode_fns, 0, 0 }, + { "xsr.dbreakc1", 229 /* xt_iclass_xsr.dbreakc1 */, + 0, + Opcode_xsr_dbreakc1_encode_fns, 0, 0 }, + { "rsr.ibreaka0", 230 /* xt_iclass_rsr.ibreaka0 */, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", 231 /* xt_iclass_wsr.ibreaka0 */, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", 232 /* xt_iclass_xsr.ibreaka0 */, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreaka1", 233 /* xt_iclass_rsr.ibreaka1 */, + 0, + Opcode_rsr_ibreaka1_encode_fns, 0, 0 }, + { "wsr.ibreaka1", 234 /* xt_iclass_wsr.ibreaka1 */, + 0, + Opcode_wsr_ibreaka1_encode_fns, 0, 0 }, + { "xsr.ibreaka1", 235 /* xt_iclass_xsr.ibreaka1 */, + 0, + Opcode_xsr_ibreaka1_encode_fns, 0, 0 }, + { "rsr.ibreakenable", 236 /* xt_iclass_rsr.ibreakenable */, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", 237 /* xt_iclass_wsr.ibreakenable */, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", 238 /* xt_iclass_xsr.ibreakenable */, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", 239 /* xt_iclass_rsr.debugcause */, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", 240 /* xt_iclass_wsr.debugcause */, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", 241 /* xt_iclass_xsr.debugcause */, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", 242 /* xt_iclass_rsr.icount */, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", 243 /* xt_iclass_wsr.icount */, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", 244 /* xt_iclass_xsr.icount */, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", 245 /* xt_iclass_rsr.icountlevel */, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", 246 /* xt_iclass_wsr.icountlevel */, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", 247 /* xt_iclass_xsr.icountlevel */, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", 248 /* xt_iclass_rsr.ddr */, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", 249 /* xt_iclass_wsr.ddr */, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", 250 /* xt_iclass_xsr.ddr */, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", 251 /* xt_iclass_rfdo */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", 252 /* xt_iclass_rfdd */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "wsr.mmid", 253 /* xt_iclass_wsr.mmid */, + 0, + Opcode_wsr_mmid_encode_fns, 0, 0 }, + { "rsr.ccount", 254 /* xt_iclass_rsr.ccount */, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", 255 /* xt_iclass_wsr.ccount */, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", 256 /* xt_iclass_xsr.ccount */, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", 257 /* xt_iclass_rsr.ccompare0 */, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", 258 /* xt_iclass_wsr.ccompare0 */, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", 259 /* xt_iclass_xsr.ccompare0 */, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "rsr.ccompare1", 260 /* xt_iclass_rsr.ccompare1 */, + 0, + Opcode_rsr_ccompare1_encode_fns, 0, 0 }, + { "wsr.ccompare1", 261 /* xt_iclass_wsr.ccompare1 */, + 0, + Opcode_wsr_ccompare1_encode_fns, 0, 0 }, + { "xsr.ccompare1", 262 /* xt_iclass_xsr.ccompare1 */, + 0, + Opcode_xsr_ccompare1_encode_fns, 0, 0 }, + { "rsr.ccompare2", 263 /* xt_iclass_rsr.ccompare2 */, + 0, + Opcode_rsr_ccompare2_encode_fns, 0, 0 }, + { "wsr.ccompare2", 264 /* xt_iclass_wsr.ccompare2 */, + 0, + Opcode_wsr_ccompare2_encode_fns, 0, 0 }, + { "xsr.ccompare2", 265 /* xt_iclass_xsr.ccompare2 */, + 0, + Opcode_xsr_ccompare2_encode_fns, 0, 0 }, + { "ipf", 266 /* xt_iclass_icache */, + 0, + Opcode_ipf_encode_fns, 0, 0 }, + { "ihi", 266 /* xt_iclass_icache */, + 0, + Opcode_ihi_encode_fns, 0, 0 }, + { "ipfl", 267 /* xt_iclass_icache_lock */, + 0, + Opcode_ipfl_encode_fns, 0, 0 }, + { "ihu", 267 /* xt_iclass_icache_lock */, + 0, + Opcode_ihu_encode_fns, 0, 0 }, + { "iiu", 267 /* xt_iclass_icache_lock */, + 0, + Opcode_iiu_encode_fns, 0, 0 }, + { "iii", 268 /* xt_iclass_icache_inv */, + 0, + Opcode_iii_encode_fns, 0, 0 }, + { "lict", 269 /* xt_iclass_licx */, + 0, + Opcode_lict_encode_fns, 0, 0 }, + { "licw", 269 /* xt_iclass_licx */, + 0, + Opcode_licw_encode_fns, 0, 0 }, + { "sict", 270 /* xt_iclass_sicx */, + 0, + Opcode_sict_encode_fns, 0, 0 }, + { "sicw", 270 /* xt_iclass_sicx */, + 0, + Opcode_sicw_encode_fns, 0, 0 }, + { "dhwb", 271 /* xt_iclass_dcache */, + 0, + Opcode_dhwb_encode_fns, 0, 0 }, + { "dhwbi", 271 /* xt_iclass_dcache */, + 0, + Opcode_dhwbi_encode_fns, 0, 0 }, + { "diwb", 272 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwb_encode_fns, 0, 0 }, + { "diwbi", 272 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwbi_encode_fns, 0, 0 }, + { "dhi", 273 /* xt_iclass_dcache_inv */, + 0, + Opcode_dhi_encode_fns, 0, 0 }, + { "dii", 273 /* xt_iclass_dcache_inv */, + 0, + Opcode_dii_encode_fns, 0, 0 }, + { "dpfr", 274 /* xt_iclass_dpf */, + 0, + Opcode_dpfr_encode_fns, 0, 0 }, + { "dpfw", 274 /* xt_iclass_dpf */, + 0, + Opcode_dpfw_encode_fns, 0, 0 }, + { "dpfro", 274 /* xt_iclass_dpf */, + 0, + Opcode_dpfro_encode_fns, 0, 0 }, + { "dpfwo", 274 /* xt_iclass_dpf */, + 0, + Opcode_dpfwo_encode_fns, 0, 0 }, + { "dpfl", 275 /* xt_iclass_dcache_lock */, + 0, + Opcode_dpfl_encode_fns, 0, 0 }, + { "dhu", 275 /* xt_iclass_dcache_lock */, + 0, + Opcode_dhu_encode_fns, 0, 0 }, + { "diu", 275 /* xt_iclass_dcache_lock */, + 0, + Opcode_diu_encode_fns, 0, 0 }, + { "sdct", 276 /* xt_iclass_sdct */, + 0, + Opcode_sdct_encode_fns, 0, 0 }, + { "ldct", 277 /* xt_iclass_ldct */, + 0, + Opcode_ldct_encode_fns, 0, 0 }, + { "wsr.ptevaddr", 278 /* xt_iclass_wsr.ptevaddr */, + 0, + Opcode_wsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.ptevaddr", 279 /* xt_iclass_rsr.ptevaddr */, + 0, + Opcode_rsr_ptevaddr_encode_fns, 0, 0 }, + { "xsr.ptevaddr", 280 /* xt_iclass_xsr.ptevaddr */, + 0, + Opcode_xsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.rasid", 281 /* xt_iclass_rsr.rasid */, + 0, + Opcode_rsr_rasid_encode_fns, 0, 0 }, + { "wsr.rasid", 282 /* xt_iclass_wsr.rasid */, + 0, + Opcode_wsr_rasid_encode_fns, 0, 0 }, + { "xsr.rasid", 283 /* xt_iclass_xsr.rasid */, + 0, + Opcode_xsr_rasid_encode_fns, 0, 0 }, + { "rsr.itlbcfg", 284 /* xt_iclass_rsr.itlbcfg */, + 0, + Opcode_rsr_itlbcfg_encode_fns, 0, 0 }, + { "wsr.itlbcfg", 285 /* xt_iclass_wsr.itlbcfg */, + 0, + Opcode_wsr_itlbcfg_encode_fns, 0, 0 }, + { "xsr.itlbcfg", 286 /* xt_iclass_xsr.itlbcfg */, + 0, + Opcode_xsr_itlbcfg_encode_fns, 0, 0 }, + { "rsr.dtlbcfg", 287 /* xt_iclass_rsr.dtlbcfg */, + 0, + Opcode_rsr_dtlbcfg_encode_fns, 0, 0 }, + { "wsr.dtlbcfg", 288 /* xt_iclass_wsr.dtlbcfg */, + 0, + Opcode_wsr_dtlbcfg_encode_fns, 0, 0 }, + { "xsr.dtlbcfg", 289 /* xt_iclass_xsr.dtlbcfg */, + 0, + Opcode_xsr_dtlbcfg_encode_fns, 0, 0 }, + { "idtlb", 290 /* xt_iclass_idtlb */, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", 291 /* xt_iclass_rdtlb */, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", 291 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", 291 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", 292 /* xt_iclass_wdtlb */, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", 293 /* xt_iclass_iitlb */, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", 294 /* xt_iclass_ritlb */, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", 294 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", 294 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", 295 /* xt_iclass_witlb */, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "ldpte", 296 /* xt_iclass_ldpte */, + 0, + Opcode_ldpte_encode_fns, 0, 0 }, + { "hwwitlba", 297 /* xt_iclass_hwwitlba */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_hwwitlba_encode_fns, 0, 0 }, + { "hwwdtlba", 298 /* xt_iclass_hwwdtlba */, + 0, + Opcode_hwwdtlba_encode_fns, 0, 0 }, + { "rsr.cpenable", 299 /* xt_iclass_rsr.cpenable */, + 0, + Opcode_rsr_cpenable_encode_fns, 0, 0 }, + { "wsr.cpenable", 300 /* xt_iclass_wsr.cpenable */, + 0, + Opcode_wsr_cpenable_encode_fns, 0, 0 }, + { "xsr.cpenable", 301 /* xt_iclass_xsr.cpenable */, + 0, + Opcode_xsr_cpenable_encode_fns, 0, 0 }, + { "clamps", 302 /* xt_iclass_clamp */, + 0, + Opcode_clamps_encode_fns, 0, 0 }, + { "min", 303 /* xt_iclass_minmax */, + 0, + Opcode_min_encode_fns, 0, 0 }, + { "max", 303 /* xt_iclass_minmax */, + 0, + Opcode_max_encode_fns, 0, 0 }, + { "minu", 303 /* xt_iclass_minmax */, + 0, + Opcode_minu_encode_fns, 0, 0 }, + { "maxu", 303 /* xt_iclass_minmax */, + 0, + Opcode_maxu_encode_fns, 0, 0 }, + { "nsa", 304 /* xt_iclass_nsa */, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", 304 /* xt_iclass_nsa */, + 0, + Opcode_nsau_encode_fns, 0, 0 }, + { "sext", 305 /* xt_iclass_sx */, + 0, + Opcode_sext_encode_fns, 0, 0 }, + { "l32ai", 306 /* xt_iclass_l32ai */, + 0, + Opcode_l32ai_encode_fns, 0, 0 }, + { "s32ri", 307 /* xt_iclass_s32ri */, + 0, + Opcode_s32ri_encode_fns, 0, 0 }, + { "s32c1i", 308 /* xt_iclass_s32c1i */, + 0, + Opcode_s32c1i_encode_fns, 0, 0 }, + { "rsr.scompare1", 309 /* xt_iclass_rsr.scompare1 */, + 0, + Opcode_rsr_scompare1_encode_fns, 0, 0 }, + { "wsr.scompare1", 310 /* xt_iclass_wsr.scompare1 */, + 0, + Opcode_wsr_scompare1_encode_fns, 0, 0 }, + { "xsr.scompare1", 311 /* xt_iclass_xsr.scompare1 */, + 0, + Opcode_xsr_scompare1_encode_fns, 0, 0 }, + { "quou", 312 /* xt_iclass_div */, + 0, + Opcode_quou_encode_fns, 0, 0 }, + { "quos", 312 /* xt_iclass_div */, + 0, + Opcode_quos_encode_fns, 0, 0 }, + { "remu", 312 /* xt_iclass_div */, + 0, + Opcode_remu_encode_fns, 0, 0 }, + { "rems", 312 /* xt_iclass_div */, + 0, + Opcode_rems_encode_fns, 0, 0 }, + { "mull", 313 /* xt_mul32 */, + 0, + Opcode_mull_encode_fns, 0, 0 }, + { "rur.expstate", 314 /* rur_expstate */, + 0, + Opcode_rur_expstate_encode_fns, 0, 0 }, + { "wur.expstate", 315 /* wur_expstate */, + 0, + Opcode_wur_expstate_encode_fns, 0, 0 }, + { "read_impwire", 316 /* iclass_READ_IMPWIRE */, + 0, + Opcode_read_impwire_encode_fns, 0, 0 }, + { "setb_expstate", 317 /* iclass_SETB_EXPSTATE */, + 0, + Opcode_setb_expstate_encode_fns, 0, 0 }, + { "clrb_expstate", 318 /* iclass_CLRB_EXPSTATE */, + 0, + Opcode_clrb_expstate_encode_fns, 0, 0 }, + { "wrmsk_expstate", 319 /* iclass_WRMSK_EXPSTATE */, + 0, + Opcode_wrmsk_expstate_encode_fns, 0, 0 } +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return 79; /* ill */ + break; + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 98; /* ret */ + case 1: + return 14; /* retw */ + case 2: + return 81; /* jx */ + } + break; + case 3: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 77; /* callx0 */ + case 1: + return 10; /* callx4 */ + case 2: + return 9; /* callx8 */ + case 3: + return 8; /* callx12 */ + } + break; + } + break; + case 1: + return 12; /* movsp */ + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 116; /* isync */ + case 1: + return 117; /* rsync */ + case 2: + return 118; /* esync */ + case 3: + return 119; /* dsync */ + case 8: + return 0; /* excw */ + case 12: + return 114; /* memw */ + case 13: + return 115; /* extw */ + case 15: + return 97; /* nop */ + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 1; /* rfe */ + case 2: + return 2; /* rfde */ + case 4: + return 16; /* rfwo */ + case 5: + return 17; /* rfwu */ + } + break; + case 1: + return 310; /* rfi */ + } + break; + case 4: + return 318; /* break */ + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 3; /* syscall */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 4; /* simcall */ + break; + } + break; + case 6: + return 120; /* rsil */ + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return 311; /* waiti */ + break; + } + break; + case 1: + return 49; /* and */ + case 2: + return 50; /* or */ + case 3: + return 51; /* xor */ + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 102; /* ssr */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 103; /* ssl */ + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return 104; /* ssa8l */ + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return 105; /* ssa8b */ + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return 106; /* ssai */ + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0) + return 13; /* rotw */ + break; + case 14: + return 426; /* nsa */ + case 15: + return 427; /* nsau */ + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 1: + return 416; /* hwwitlba */ + case 3: + return 412; /* ritlb0 */ + case 4: + if (Field_t_Slot_inst_get (insn) == 0) + return 410; /* iitlb */ + break; + case 5: + return 411; /* pitlb */ + case 6: + return 414; /* witlb */ + case 7: + return 413; /* ritlb1 */ + case 9: + return 417; /* hwwdtlba */ + case 11: + return 407; /* rdtlb0 */ + case 12: + if (Field_t_Slot_inst_get (insn) == 0) + return 405; /* idtlb */ + break; + case 13: + return 406; /* pdtlb */ + case 14: + return 409; /* wdtlb */ + case 15: + return 408; /* rdtlb1 */ + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 95; /* neg */ + case 1: + return 96; /* abs */ + } + break; + case 8: + return 41; /* add */ + case 9: + return 43; /* addx2 */ + case 10: + return 44; /* addx4 */ + case 11: + return 45; /* addx8 */ + case 12: + return 42; /* sub */ + case 13: + return 46; /* subx2 */ + case 14: + return 47; /* subx4 */ + case 15: + return 48; /* subx8 */ + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return 111; /* slli */ + case 2: + case 3: + return 112; /* srai */ + case 4: + return 113; /* srli */ + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 129; /* xsr.lbeg */ + case 1: + return 123; /* xsr.lend */ + case 2: + return 126; /* xsr.lcount */ + case 3: + return 132; /* xsr.sar */ + case 5: + return 135; /* xsr.litbase */ + case 12: + return 434; /* xsr.scompare1 */ + case 16: + return 306; /* xsr.acclo */ + case 17: + return 309; /* xsr.acchi */ + case 32: + return 294; /* xsr.m0 */ + case 33: + return 297; /* xsr.m1 */ + case 34: + return 300; /* xsr.m2 */ + case 35: + return 303; /* xsr.m3 */ + case 72: + return 22; /* xsr.windowbase */ + case 73: + return 25; /* xsr.windowstart */ + case 83: + return 395; /* xsr.ptevaddr */ + case 90: + return 398; /* xsr.rasid */ + case 91: + return 401; /* xsr.itlbcfg */ + case 92: + return 404; /* xsr.dtlbcfg */ + case 96: + return 340; /* xsr.ibreakenable */ + case 104: + return 352; /* xsr.ddr */ + case 128: + return 334; /* xsr.ibreaka0 */ + case 129: + return 337; /* xsr.ibreaka1 */ + case 144: + return 322; /* xsr.dbreaka0 */ + case 145: + return 328; /* xsr.dbreaka1 */ + case 160: + return 325; /* xsr.dbreakc0 */ + case 161: + return 331; /* xsr.dbreakc1 */ + case 177: + return 143; /* xsr.epc1 */ + case 178: + return 149; /* xsr.epc2 */ + case 179: + return 155; /* xsr.epc3 */ + case 180: + return 161; /* xsr.epc4 */ + case 181: + return 167; /* xsr.epc5 */ + case 182: + return 173; /* xsr.epc6 */ + case 183: + return 179; /* xsr.epc7 */ + case 192: + return 206; /* xsr.depc */ + case 194: + return 185; /* xsr.eps2 */ + case 195: + return 188; /* xsr.eps3 */ + case 196: + return 191; /* xsr.eps4 */ + case 197: + return 194; /* xsr.eps5 */ + case 198: + return 197; /* xsr.eps6 */ + case 199: + return 200; /* xsr.eps7 */ + case 209: + return 146; /* xsr.excsave1 */ + case 210: + return 152; /* xsr.excsave2 */ + case 211: + return 158; /* xsr.excsave3 */ + case 212: + return 164; /* xsr.excsave4 */ + case 213: + return 170; /* xsr.excsave5 */ + case 214: + return 176; /* xsr.excsave6 */ + case 215: + return 182; /* xsr.excsave7 */ + case 224: + return 420; /* xsr.cpenable */ + case 228: + return 317; /* xsr.intenable */ + case 230: + return 140; /* xsr.ps */ + case 231: + return 219; /* xsr.vecbase */ + case 232: + return 209; /* xsr.exccause */ + case 233: + return 343; /* xsr.debugcause */ + case 234: + return 358; /* xsr.ccount */ + case 236: + return 346; /* xsr.icount */ + case 237: + return 349; /* xsr.icountlevel */ + case 238: + return 203; /* xsr.excvaddr */ + case 240: + return 361; /* xsr.ccompare0 */ + case 241: + return 364; /* xsr.ccompare1 */ + case 242: + return 367; /* xsr.ccompare2 */ + case 244: + return 212; /* xsr.misc0 */ + case 245: + return 215; /* xsr.misc1 */ + } + break; + case 8: + return 108; /* src */ + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return 109; /* srl */ + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return 107; /* sll */ + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return 110; /* sra */ + break; + case 12: + return 290; /* mul16u */ + case 13: + return 291; /* mul16s */ + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 374; /* lict */ + case 1: + return 376; /* sict */ + case 2: + return 375; /* licw */ + case 3: + return 377; /* sicw */ + case 8: + return 392; /* ldct */ + case 9: + return 391; /* sdct */ + case 14: + if (Field_t_Slot_inst_get (insn) == 0) + return 353; /* rfdo */ + if (Field_t_Slot_inst_get (insn) == 1) + return 354; /* rfdd */ + break; + case 15: + return 415; /* ldpte */ + } + break; + } + break; + case 2: + switch (Field_op2_Slot_inst_get (insn)) + { + case 8: + return 439; /* mull */ + case 12: + return 435; /* quou */ + case 13: + return 436; /* quos */ + case 14: + return 437; /* remu */ + case 15: + return 438; /* rems */ + } + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 127; /* rsr.lbeg */ + case 1: + return 121; /* rsr.lend */ + case 2: + return 124; /* rsr.lcount */ + case 3: + return 130; /* rsr.sar */ + case 5: + return 133; /* rsr.litbase */ + case 12: + return 432; /* rsr.scompare1 */ + case 16: + return 304; /* rsr.acclo */ + case 17: + return 307; /* rsr.acchi */ + case 32: + return 292; /* rsr.m0 */ + case 33: + return 295; /* rsr.m1 */ + case 34: + return 298; /* rsr.m2 */ + case 35: + return 301; /* rsr.m3 */ + case 72: + return 20; /* rsr.windowbase */ + case 73: + return 23; /* rsr.windowstart */ + case 83: + return 394; /* rsr.ptevaddr */ + case 90: + return 396; /* rsr.rasid */ + case 91: + return 399; /* rsr.itlbcfg */ + case 92: + return 402; /* rsr.dtlbcfg */ + case 96: + return 338; /* rsr.ibreakenable */ + case 104: + return 350; /* rsr.ddr */ + case 128: + return 332; /* rsr.ibreaka0 */ + case 129: + return 335; /* rsr.ibreaka1 */ + case 144: + return 320; /* rsr.dbreaka0 */ + case 145: + return 326; /* rsr.dbreaka1 */ + case 160: + return 323; /* rsr.dbreakc0 */ + case 161: + return 329; /* rsr.dbreakc1 */ + case 176: + return 136; /* rsr.176 */ + case 177: + return 141; /* rsr.epc1 */ + case 178: + return 147; /* rsr.epc2 */ + case 179: + return 153; /* rsr.epc3 */ + case 180: + return 159; /* rsr.epc4 */ + case 181: + return 165; /* rsr.epc5 */ + case 182: + return 171; /* rsr.epc6 */ + case 183: + return 177; /* rsr.epc7 */ + case 192: + return 204; /* rsr.depc */ + case 194: + return 183; /* rsr.eps2 */ + case 195: + return 186; /* rsr.eps3 */ + case 196: + return 189; /* rsr.eps4 */ + case 197: + return 192; /* rsr.eps5 */ + case 198: + return 195; /* rsr.eps6 */ + case 199: + return 198; /* rsr.eps7 */ + case 208: + return 137; /* rsr.208 */ + case 209: + return 144; /* rsr.excsave1 */ + case 210: + return 150; /* rsr.excsave2 */ + case 211: + return 156; /* rsr.excsave3 */ + case 212: + return 162; /* rsr.excsave4 */ + case 213: + return 168; /* rsr.excsave5 */ + case 214: + return 174; /* rsr.excsave6 */ + case 215: + return 180; /* rsr.excsave7 */ + case 224: + return 418; /* rsr.cpenable */ + case 226: + return 312; /* rsr.interrupt */ + case 228: + return 315; /* rsr.intenable */ + case 230: + return 138; /* rsr.ps */ + case 231: + return 217; /* rsr.vecbase */ + case 232: + return 207; /* rsr.exccause */ + case 233: + return 341; /* rsr.debugcause */ + case 234: + return 356; /* rsr.ccount */ + case 235: + return 216; /* rsr.prid */ + case 236: + return 344; /* rsr.icount */ + case 237: + return 347; /* rsr.icountlevel */ + case 238: + return 201; /* rsr.excvaddr */ + case 240: + return 359; /* rsr.ccompare0 */ + case 241: + return 362; /* rsr.ccompare1 */ + case 242: + return 365; /* rsr.ccompare2 */ + case 244: + return 210; /* rsr.misc0 */ + case 245: + return 213; /* rsr.misc1 */ + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 128; /* wsr.lbeg */ + case 1: + return 122; /* wsr.lend */ + case 2: + return 125; /* wsr.lcount */ + case 3: + return 131; /* wsr.sar */ + case 5: + return 134; /* wsr.litbase */ + case 12: + return 433; /* wsr.scompare1 */ + case 16: + return 305; /* wsr.acclo */ + case 17: + return 308; /* wsr.acchi */ + case 32: + return 293; /* wsr.m0 */ + case 33: + return 296; /* wsr.m1 */ + case 34: + return 299; /* wsr.m2 */ + case 35: + return 302; /* wsr.m3 */ + case 72: + return 21; /* wsr.windowbase */ + case 73: + return 24; /* wsr.windowstart */ + case 83: + return 393; /* wsr.ptevaddr */ + case 89: + return 355; /* wsr.mmid */ + case 90: + return 397; /* wsr.rasid */ + case 91: + return 400; /* wsr.itlbcfg */ + case 92: + return 403; /* wsr.dtlbcfg */ + case 96: + return 339; /* wsr.ibreakenable */ + case 104: + return 351; /* wsr.ddr */ + case 128: + return 333; /* wsr.ibreaka0 */ + case 129: + return 336; /* wsr.ibreaka1 */ + case 144: + return 321; /* wsr.dbreaka0 */ + case 145: + return 327; /* wsr.dbreaka1 */ + case 160: + return 324; /* wsr.dbreakc0 */ + case 161: + return 330; /* wsr.dbreakc1 */ + case 177: + return 142; /* wsr.epc1 */ + case 178: + return 148; /* wsr.epc2 */ + case 179: + return 154; /* wsr.epc3 */ + case 180: + return 160; /* wsr.epc4 */ + case 181: + return 166; /* wsr.epc5 */ + case 182: + return 172; /* wsr.epc6 */ + case 183: + return 178; /* wsr.epc7 */ + case 192: + return 205; /* wsr.depc */ + case 194: + return 184; /* wsr.eps2 */ + case 195: + return 187; /* wsr.eps3 */ + case 196: + return 190; /* wsr.eps4 */ + case 197: + return 193; /* wsr.eps5 */ + case 198: + return 196; /* wsr.eps6 */ + case 199: + return 199; /* wsr.eps7 */ + case 209: + return 145; /* wsr.excsave1 */ + case 210: + return 151; /* wsr.excsave2 */ + case 211: + return 157; /* wsr.excsave3 */ + case 212: + return 163; /* wsr.excsave4 */ + case 213: + return 169; /* wsr.excsave5 */ + case 214: + return 175; /* wsr.excsave6 */ + case 215: + return 181; /* wsr.excsave7 */ + case 224: + return 419; /* wsr.cpenable */ + case 226: + return 313; /* wsr.intset */ + case 227: + return 314; /* wsr.intclear */ + case 228: + return 316; /* wsr.intenable */ + case 230: + return 139; /* wsr.ps */ + case 231: + return 218; /* wsr.vecbase */ + case 232: + return 208; /* wsr.exccause */ + case 233: + return 342; /* wsr.debugcause */ + case 234: + return 357; /* wsr.ccount */ + case 236: + return 345; /* wsr.icount */ + case 237: + return 348; /* wsr.icountlevel */ + case 238: + return 202; /* wsr.excvaddr */ + case 240: + return 360; /* wsr.ccompare0 */ + case 241: + return 363; /* wsr.ccompare1 */ + case 242: + return 366; /* wsr.ccompare2 */ + case 244: + return 211; /* wsr.misc0 */ + case 245: + return 214; /* wsr.misc1 */ + } + break; + case 2: + return 428; /* sext */ + case 3: + return 421; /* clamps */ + case 4: + return 422; /* min */ + case 5: + return 423; /* max */ + case 6: + return 424; /* minu */ + case 7: + return 425; /* maxu */ + case 8: + return 91; /* moveqz */ + case 9: + return 92; /* movnez */ + case 10: + return 93; /* movltz */ + case 11: + return 94; /* movgez */ + case 14: + switch (Field_st_Slot_inst_get (insn)) + { + case 230: + return 440; /* rur.expstate */ + case 231: + return 37; /* rur.threadptr */ + } + break; + case 15: + switch (Field_sr_Slot_inst_get (insn)) + { + case 230: + return 441; /* wur.expstate */ + case 231: + return 38; /* wur.threadptr */ + } + break; + } + break; + case 4: + case 5: + return 78; /* extui */ + case 9: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + return 18; /* l32e */ + case 4: + return 19; /* s32e */ + } + break; + } + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return 442; /* read_impwire */ + break; + case 1: + if (Field_s3to1_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return 443; /* setb_expstate */ + if (Field_s3to1_Slot_inst_get (insn) == 1 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return 444; /* clrb_expstate */ + break; + case 2: + if (Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return 445; /* wrmsk_expstate */ + break; + } + break; + case 1: + return 85; /* l32r */ + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 86; /* l8ui */ + case 1: + return 82; /* l16ui */ + case 2: + return 84; /* l32i */ + case 4: + return 101; /* s8i */ + case 5: + return 99; /* s16i */ + case 6: + return 100; /* s32i */ + case 7: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 384; /* dpfr */ + case 1: + return 385; /* dpfw */ + case 2: + return 386; /* dpfro */ + case 3: + return 387; /* dpfwo */ + case 4: + return 378; /* dhwb */ + case 5: + return 379; /* dhwbi */ + case 6: + return 382; /* dhi */ + case 7: + return 383; /* dii */ + case 8: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + return 388; /* dpfl */ + case 2: + return 389; /* dhu */ + case 3: + return 390; /* diu */ + case 4: + return 380; /* diwb */ + case 5: + return 381; /* diwbi */ + } + break; + case 12: + return 368; /* ipf */ + case 13: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + return 370; /* ipfl */ + case 2: + return 371; /* ihu */ + case 3: + return 372; /* iiu */ + } + break; + case 14: + return 369; /* ihi */ + case 15: + return 373; /* iii */ + } + break; + case 9: + return 83; /* l16si */ + case 10: + return 90; /* movi */ + case 11: + return 429; /* l32ai */ + case 12: + return 39; /* addi */ + case 13: + return 40; /* addmi */ + case 14: + return 431; /* s32c1i */ + case 15: + return 430; /* s32ri */ + } + break; + case 4: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 281; /* mula.dd.ll.ldinc */ + break; + case 9: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 283; /* mula.dd.hl.ldinc */ + break; + case 10: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 285; /* mula.dd.lh.ldinc */ + break; + case 11: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 287; /* mula.dd.hh.ldinc */ + break; + } + break; + case 1: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 280; /* mula.dd.ll.lddec */ + break; + case 9: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 282; /* mula.dd.hl.lddec */ + break; + case 10: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 284; /* mula.dd.lh.lddec */ + break; + case 11: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 286; /* mula.dd.hh.lddec */ + break; + } + break; + case 2: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 236; /* mul.dd.ll */ + break; + case 5: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 237; /* mul.dd.hl */ + break; + case 6: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 238; /* mul.dd.lh */ + break; + case 7: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 239; /* mul.dd.hh */ + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 264; /* mula.dd.ll */ + break; + case 9: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 265; /* mula.dd.hl */ + break; + case 10: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 266; /* mula.dd.lh */ + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 267; /* mula.dd.hh */ + break; + case 12: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 268; /* muls.dd.ll */ + break; + case 13: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 269; /* muls.dd.hl */ + break; + case 14: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 270; /* muls.dd.lh */ + break; + case 15: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 271; /* muls.dd.hh */ + break; + } + break; + case 3: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 228; /* mul.ad.ll */ + break; + case 5: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 229; /* mul.ad.hl */ + break; + case 6: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 230; /* mul.ad.lh */ + break; + case 7: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 231; /* mul.ad.hh */ + break; + case 8: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 248; /* mula.ad.ll */ + break; + case 9: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 249; /* mula.ad.hl */ + break; + case 10: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 250; /* mula.ad.lh */ + break; + case 11: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 251; /* mula.ad.hh */ + break; + case 12: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 252; /* muls.ad.ll */ + break; + case 13: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 253; /* muls.ad.hl */ + break; + case 14: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 254; /* muls.ad.lh */ + break; + case 15: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return 255; /* muls.ad.hh */ + break; + } + break; + case 4: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_r3_Slot_inst_get (insn) == 0) + return 273; /* mula.da.ll.ldinc */ + break; + case 9: + if (Field_r3_Slot_inst_get (insn) == 0) + return 275; /* mula.da.hl.ldinc */ + break; + case 10: + if (Field_r3_Slot_inst_get (insn) == 0) + return 277; /* mula.da.lh.ldinc */ + break; + case 11: + if (Field_r3_Slot_inst_get (insn) == 0) + return 279; /* mula.da.hh.ldinc */ + break; + } + break; + case 5: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_r3_Slot_inst_get (insn) == 0) + return 272; /* mula.da.ll.lddec */ + break; + case 9: + if (Field_r3_Slot_inst_get (insn) == 0) + return 274; /* mula.da.hl.lddec */ + break; + case 10: + if (Field_r3_Slot_inst_get (insn) == 0) + return 276; /* mula.da.lh.lddec */ + break; + case 11: + if (Field_r3_Slot_inst_get (insn) == 0) + return 278; /* mula.da.hh.lddec */ + break; + } + break; + case 6: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 232; /* mul.da.ll */ + break; + case 5: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 233; /* mul.da.hl */ + break; + case 6: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 234; /* mul.da.lh */ + break; + case 7: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 235; /* mul.da.hh */ + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 256; /* mula.da.ll */ + break; + case 9: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 257; /* mula.da.hl */ + break; + case 10: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 258; /* mula.da.lh */ + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 259; /* mula.da.hh */ + break; + case 12: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 260; /* muls.da.ll */ + break; + case 13: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 261; /* muls.da.hl */ + break; + case 14: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 262; /* muls.da.lh */ + break; + case 15: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return 263; /* muls.da.hh */ + break; + } + break; + case 7: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + if (Field_r_Slot_inst_get (insn) == 0) + return 224; /* umul.aa.ll */ + break; + case 1: + if (Field_r_Slot_inst_get (insn) == 0) + return 225; /* umul.aa.hl */ + break; + case 2: + if (Field_r_Slot_inst_get (insn) == 0) + return 226; /* umul.aa.lh */ + break; + case 3: + if (Field_r_Slot_inst_get (insn) == 0) + return 227; /* umul.aa.hh */ + break; + case 4: + if (Field_r_Slot_inst_get (insn) == 0) + return 220; /* mul.aa.ll */ + break; + case 5: + if (Field_r_Slot_inst_get (insn) == 0) + return 221; /* mul.aa.hl */ + break; + case 6: + if (Field_r_Slot_inst_get (insn) == 0) + return 222; /* mul.aa.lh */ + break; + case 7: + if (Field_r_Slot_inst_get (insn) == 0) + return 223; /* mul.aa.hh */ + break; + case 8: + if (Field_r_Slot_inst_get (insn) == 0) + return 240; /* mula.aa.ll */ + break; + case 9: + if (Field_r_Slot_inst_get (insn) == 0) + return 241; /* mula.aa.hl */ + break; + case 10: + if (Field_r_Slot_inst_get (insn) == 0) + return 242; /* mula.aa.lh */ + break; + case 11: + if (Field_r_Slot_inst_get (insn) == 0) + return 243; /* mula.aa.hh */ + break; + case 12: + if (Field_r_Slot_inst_get (insn) == 0) + return 244; /* muls.aa.ll */ + break; + case 13: + if (Field_r_Slot_inst_get (insn) == 0) + return 245; /* muls.aa.hl */ + break; + case 14: + if (Field_r_Slot_inst_get (insn) == 0) + return 246; /* muls.aa.lh */ + break; + case 15: + if (Field_r_Slot_inst_get (insn) == 0) + return 247; /* muls.aa.hh */ + break; + } + break; + case 8: + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return 289; /* ldinc */ + break; + case 9: + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return 288; /* lddec */ + break; + } + break; + case 5: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 76; /* call0 */ + case 1: + return 7; /* call4 */ + case 2: + return 6; /* call8 */ + case 3: + return 5; /* call12 */ + } + break; + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 80; /* j */ + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 72; /* beqz */ + case 1: + return 73; /* bnez */ + case 2: + return 75; /* bltz */ + case 3: + return 74; /* bgez */ + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 52; /* beqi */ + case 1: + return 53; /* bnei */ + case 2: + return 55; /* blti */ + case 3: + return 54; /* bgei */ + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 11; /* entry */ + case 1: + switch (Field_r_Slot_inst_get (insn)) + { + case 8: + return 87; /* loop */ + case 9: + return 88; /* loopnez */ + case 10: + return 89; /* loopgtz */ + } + break; + case 2: + return 59; /* bltui */ + case 3: + return 58; /* bgeui */ + } + break; + } + break; + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 67; /* bnone */ + case 1: + return 60; /* beq */ + case 2: + return 63; /* blt */ + case 3: + return 65; /* bltu */ + case 4: + return 68; /* ball */ + case 5: + return 70; /* bbc */ + case 6: + case 7: + return 56; /* bbci */ + case 8: + return 66; /* bany */ + case 9: + return 61; /* bne */ + case 10: + return 62; /* bge */ + case 11: + return 64; /* bgeu */ + case 12: + return 69; /* bnall */ + case 13: + return 71; /* bbs */ + case 14: + case 15: + return 57; /* bbsi */ + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return 33; /* movi.n */ + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return 28; /* beqz.n */ + case 1: + return 29; /* bnez.n */ + } + break; + } + break; + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return 32; /* mov.n */ + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return 35; /* ret.n */ + case 1: + return 15; /* retw.n */ + case 2: + return 319; /* break.n */ + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return 34; /* nop.n */ + break; + case 6: + if (Field_s_Slot_inst16b_get (insn) == 0) + return 30; /* ill.n */ + break; + } + break; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return 31; /* l32i.n */ + case 9: + return 36; /* s32i.n */ + case 10: + return 26; /* add.n */ + case 11: + return 27; /* addi.n */ + } + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + Field_mn_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_get, + Field_rbit2_Slot_inst_get, + Field_rhi_Slot_inst_get, + Field_t3_Slot_inst_get, + Field_tbit2_Slot_inst_get, + Field_tlo_Slot_inst_get, + Field_w_Slot_inst_get, + Field_y_Slot_inst_get, + Field_x_Slot_inst_get, + Field_xt_wbr15_imm_Slot_inst_get, + Field_xt_wbr18_imm_Slot_inst_get, + Field_bitindex_Slot_inst_get, + Field_s3to1_Slot_inst_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + Field_mn_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_set, + Field_rbit2_Slot_inst_set, + Field_rhi_Slot_inst_set, + Field_t3_Slot_inst_set, + Field_tbit2_Slot_inst_set, + Field_tlo_Slot_inst_set, + Field_w_Slot_inst_set, + Field_y_Slot_inst_set, + Field_x_Slot_inst_set, + Field_xt_wbr15_imm_Slot_inst_set, + Field_xt_wbr18_imm_Slot_inst_set, + Field_bitindex_Slot_inst_set, + Field_s3to1_Slot_inst_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + 0, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_get, + Field_s3to1_Slot_inst16a_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + 0, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_set, + Field_s3to1_Slot_inst16a_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + 0, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_get, + Field_s3to1_Slot_inst16b_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + 0, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_set, + Field_s3to1_Slot_inst16b_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x8; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x8) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc) == 0x8) + return 1; /* x16a */ + if ((insn[0] & 0xe) == 0xc) + return 2; /* x16b */ + return -1; +} + +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int op0 = insn[0] & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +xtensa_isa_internal xtensa_modules = { + 0 /* little-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 56 /* num_fields */, + 93, operands, + 320, iclasses, + 446, opcodes, 0, + 2, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 1, interfaces, 0, + 0, funcUnits, 0 +}; From e763684f82d6997554642bab9067e2041315f9d3 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 15:55:38 -0700 Subject: [PATCH 250/546] target/xtensa: switch dc233c to libisa Autogenerated xtensa-modules.c is added by the import_core.sh script. Signed-off-by: Max Filippov --- target/xtensa/core-dc233c.c | 4 + target/xtensa/core-dc233c/xtensa-modules.c | 15232 +++++++++++++++++++ 2 files changed, 15236 insertions(+) create mode 100644 target/xtensa/core-dc233c/xtensa-modules.c diff --git a/target/xtensa/core-dc233c.c b/target/xtensa/core-dc233c.c index 40475e5205..00301c28a2 100644 --- a/target/xtensa/core-dc233c.c +++ b/target/xtensa/core-dc233c.c @@ -35,6 +35,9 @@ #include "core-dc233c/core-isa.h" #include "overlay_tool.h" +#define xtensa_modules xtensa_modules_dc233c +#include "core-dc233c/xtensa-modules.c" + static XtensaConfig dc233c __attribute__((unused)) = { .name = "dc233c", .gdb_regmap = { @@ -44,6 +47,7 @@ static XtensaConfig dc233c __attribute__((unused)) = { #include "core-dc233c/gdb-config.c" } }, + .isa_internal = &xtensa_modules, .clock_freq_khz = 10000, DEFAULT_SECTIONS }; diff --git a/target/xtensa/core-dc233c/xtensa-modules.c b/target/xtensa/core-dc233c/xtensa-modules.c new file mode 100644 index 0000000000..2728311c9a --- /dev/null +++ b/target/xtensa/core-dc233c/xtensa-modules.c @@ -0,0 +1,15232 @@ +/* Xtensa configuration-specific ISA information. + + Customer ID=4869; Build=0x2cfec; Copyright (c) 2003-2010 Tensilica Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "LBEG", 0, 0 }, + { "LEND", 1, 0 }, + { "LCOUNT", 2, 0 }, + { "ACCLO", 16, 0 }, + { "ACCHI", 17, 0 }, + { "M0", 32, 0 }, + { "M1", 33, 0 }, + { "M2", 34, 0 }, + { "M3", 35, 0 }, + { "PTEVADDR", 83, 0 }, + { "MMID", 89, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "CCOMPARE1", 241, 0 }, + { "CCOMPARE2", 242, 0 }, + { "VECBASE", 231, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EPC4", 180, 0 }, + { "EPC5", 181, 0 }, + { "EPC6", 182, 0 }, + { "EPC7", 183, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EXCSAVE4", 212, 0 }, + { "EXCSAVE5", 213, 0 }, + { "EXCSAVE6", 214, 0 }, + { "EXCSAVE7", 215, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EPS4", 196, 0 }, + { "EPS5", 197, 0 }, + { "EPS6", 198, 0 }, + { "EPS7", 199, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "WINDOWBASE", 72, 0 }, + { "WINDOWSTART", 73, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "MISC0", 244, 0 }, + { "MISC1", 245, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "DBREAKA1", 145, 0 }, + { "DBREAKC1", 161, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKA1", 129, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 }, + { "RASID", 90, 0 }, + { "ITLBCFG", 91, 0 }, + { "DTLBCFG", 92, 0 }, + { "CPENABLE", 224, 0 }, + { "SCOMPARE1", 12, 0 }, + { "ATOMCTL", 99, 0 }, + { "THREADPTR", 231, 1 }, + { "EXPSTATE", 230, 1 } +}; + +#define NUM_SYSREGS 71 +#define MAX_SPECIAL_REG 245 +#define MAX_USER_REG 231 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "LCOUNT", 32, 0 }, + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 22, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "VECBASE", 22, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EPC4", 32, 0 }, + { "EPC5", 32, 0 }, + { "EPC6", 32, 0 }, + { "EPC7", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EXCSAVE4", 32, 0 }, + { "EXCSAVE5", 32, 0 }, + { "EXCSAVE6", 32, 0 }, + { "EXCSAVE7", 32, 0 }, + { "EPS2", 15, 0 }, + { "EPS3", 15, 0 }, + { "EPS4", 15, 0 }, + { "EPS5", 15, 0 }, + { "EPS6", 15, 0 }, + { "EPS7", 15, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSWOE", 1, 0 }, + { "PSRING", 2, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "WindowBase", 3, 0 }, + { "WindowStart", 8, 0 }, + { "PSCALLINC", 2, 0 }, + { "PSOWB", 4, 0 }, + { "LBEG", 32, 0 }, + { "LEND", 32, 0 }, + { "SAR", 6, 0 }, + { "THREADPTR", 32, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "MISC0", 32, 0 }, + { "MISC1", 32, 0 }, + { "ACC", 40, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 22, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "DBREAKA1", 32, 0 }, + { "DBREAKC1", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKA1", 32, 0 }, + { "IBREAKENABLE", 2, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 }, + { "CCOMPARE1", 32, 0 }, + { "CCOMPARE2", 32, 0 }, + { "ASID3", 8, 0 }, + { "ASID2", 8, 0 }, + { "ASID1", 8, 0 }, + { "INSTPGSZID6", 1, 0 }, + { "INSTPGSZID5", 1, 0 }, + { "INSTPGSZID4", 2, 0 }, + { "DATAPGSZID6", 1, 0 }, + { "DATAPGSZID5", 1, 0 }, + { "DATAPGSZID4", 2, 0 }, + { "PTBASE", 10, 0 }, + { "CPENABLE", 8, 0 }, + { "SCOMPARE1", 32, 0 }, + { "ATOMCTL", 6, 0 }, + { "EXPSTATE", 32, XTENSA_STATE_IS_EXPORTED } +}; + +#define NUM_STATES 78 + +enum xtensa_state_id { + STATE_LCOUNT, + STATE_PC, + STATE_ICOUNT, + STATE_DDR, + STATE_INTERRUPT, + STATE_CCOUNT, + STATE_XTSYNC, + STATE_VECBASE, + STATE_EPC1, + STATE_EPC2, + STATE_EPC3, + STATE_EPC4, + STATE_EPC5, + STATE_EPC6, + STATE_EPC7, + STATE_EXCSAVE1, + STATE_EXCSAVE2, + STATE_EXCSAVE3, + STATE_EXCSAVE4, + STATE_EXCSAVE5, + STATE_EXCSAVE6, + STATE_EXCSAVE7, + STATE_EPS2, + STATE_EPS3, + STATE_EPS4, + STATE_EPS5, + STATE_EPS6, + STATE_EPS7, + STATE_EXCCAUSE, + STATE_PSINTLEVEL, + STATE_PSUM, + STATE_PSWOE, + STATE_PSRING, + STATE_PSEXCM, + STATE_DEPC, + STATE_EXCVADDR, + STATE_WindowBase, + STATE_WindowStart, + STATE_PSCALLINC, + STATE_PSOWB, + STATE_LBEG, + STATE_LEND, + STATE_SAR, + STATE_THREADPTR, + STATE_LITBADDR, + STATE_LITBEN, + STATE_MISC0, + STATE_MISC1, + STATE_ACC, + STATE_InOCDMode, + STATE_INTENABLE, + STATE_DBREAKA0, + STATE_DBREAKC0, + STATE_DBREAKA1, + STATE_DBREAKC1, + STATE_IBREAKA0, + STATE_IBREAKA1, + STATE_IBREAKENABLE, + STATE_ICOUNTLEVEL, + STATE_DEBUGCAUSE, + STATE_DBNUM, + STATE_CCOMPARE0, + STATE_CCOMPARE1, + STATE_CCOMPARE2, + STATE_ASID3, + STATE_ASID2, + STATE_ASID1, + STATE_INSTPGSZID6, + STATE_INSTPGSZID5, + STATE_INSTPGSZID4, + STATE_DATAPGSZID6, + STATE_DATAPGSZID5, + STATE_DATAPGSZID4, + STATE_PTBASE, + STATE_CPENABLE, + STATE_SCOMPARE1, + STATE_ATOMCTL, + STATE_EXPSTATE +}; + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 24) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0) | (tie_t << 5); +} + +static unsigned +Field_t3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_t3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_tlo_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_tlo_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_w_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 18) >> 30); + return tie_t; +} + +static void +Field_w_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x3000) | (tie_t << 12); +} + +static unsigned +Field_r3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 16) >> 31); + return tie_t; +} + +static void +Field_r3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x8000) | (tie_t << 15); +} + +static unsigned +Field_rhi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 16) >> 30); + return tie_t; +} + +static void +Field_rhi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc000) | (tie_t << 14); +} + +static unsigned +Field_s3to1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 19) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1000) | (tie_t << 12); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 8) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff000) | (tie_t << 12); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 8) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff0000) | (tie_t << 16); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 8) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff00) | (tie_t << 8); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 11) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100000) | (tie_t << 20); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_mn_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 24) >> 30); + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_mn_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); + tie_t = (val << 28) >> 30; + insn[0] = (insn[0] & ~0xc0) | (tie_t << 6); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 24) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x80) | (tie_t << 7); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 26) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x30) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 25) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x70) | (tie_t << 4); +} + +static unsigned +Field_rbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_rbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_tbit2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_tbit2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_y_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 25) >> 31); + return tie_t; +} + +static void +Field_y_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x40) | (tie_t << 6); +} + +static unsigned +Field_x_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 17) >> 31); + return tie_t; +} + +static void +Field_x_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x4000) | (tie_t << 14); +} + +static unsigned +Field_xt_wbr15_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 15) | ((insn[0] << 8) >> 17); + return tie_t; +} + +static void +Field_xt_wbr15_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 17) >> 17; + insn[0] = (insn[0] & ~0xfffe00) | (tie_t << 9); +} + +static unsigned +Field_xt_wbr18_imm_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 8) >> 14); + return tie_t; +} + +static void +Field_xt_wbr18_imm_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0xffffc0) | (tie_t << 6); +} + +static unsigned +Field_bitindex_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bitindex_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_bitindex_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_s3to1_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static unsigned +Field_s3to1_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 20) >> 29); + return tie_t; +} + +static void +Field_s3to1_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe00) | (tie_t << 9); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_ar4_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 4; +} + +static unsigned +Implicit_Field_ar8_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 8; +} + +static unsigned +Implicit_Field_ar12_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 12; +} + +static unsigned +Implicit_Field_mr0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_mr1_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 1; +} + +static unsigned +Implicit_Field_mr2_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 2; +} + +static unsigned +Implicit_Field_mr3_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 3; +} + +enum xtensa_field_id { + FIELD_t, + FIELD_bbi4, + FIELD_bbi, + FIELD_imm12, + FIELD_imm8, + FIELD_s, + FIELD_imm12b, + FIELD_imm16, + FIELD_m, + FIELD_n, + FIELD_offset, + FIELD_op0, + FIELD_op1, + FIELD_op2, + FIELD_r, + FIELD_sa4, + FIELD_sae4, + FIELD_sae, + FIELD_sal, + FIELD_sargt, + FIELD_sas4, + FIELD_sas, + FIELD_sr, + FIELD_st, + FIELD_thi3, + FIELD_imm4, + FIELD_mn, + FIELD_i, + FIELD_imm6lo, + FIELD_imm6hi, + FIELD_imm7lo, + FIELD_imm7hi, + FIELD_z, + FIELD_imm6, + FIELD_imm7, + FIELD_r3, + FIELD_rbit2, + FIELD_rhi, + FIELD_t3, + FIELD_tbit2, + FIELD_tlo, + FIELD_w, + FIELD_y, + FIELD_x, + FIELD_xt_wbr15_imm, + FIELD_xt_wbr18_imm, + FIELD_bitindex, + FIELD_s3to1, + FIELD__ar0, + FIELD__ar4, + FIELD__ar8, + FIELD__ar12, + FIELD__mr0, + FIELD__mr1, + FIELD__mr2, + FIELD__mr3 +}; + + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +enum xtensa_regfile_id { + REGFILE_AR, + REGFILE_MR +}; + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", REGFILE_AR, 32, 32 }, + { "MR", "m", REGFILE_MR, 32, 4 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + { "IMPWIRE", 32, 0, 0, 'i' } +}; + +enum xtensa_interface_id { + INTERFACE_IMPWIRE +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; +} + +static int +Operand_soffsetx4_encode (uint32 *valp) +{ + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_uimm12x8_decode (uint32 *valp) +{ + unsigned uimm12x8_0, imm12_0; + imm12_0 = *valp & 0xfff; + uimm12x8_0 = imm12_0 << 3; + *valp = uimm12x8_0; + return 0; +} + +static int +Operand_uimm12x8_encode (uint32 *valp) +{ + unsigned imm12_0, uimm12x8_0; + uimm12x8_0 = *valp; + imm12_0 = ((uimm12x8_0 >> 3) & 0xfff); + *valp = imm12_0; + return 0; +} + +static int +Operand_simm4_decode (uint32 *valp) +{ + unsigned simm4_0, mn_0; + mn_0 = *valp & 0xf; + simm4_0 = ((int) mn_0 << 28) >> 28; + *valp = simm4_0; + return 0; +} + +static int +Operand_simm4_encode (uint32 *valp) +{ + unsigned mn_0, simm4_0; + simm4_0 = *valp; + mn_0 = (simm4_0 & 0xf); + *valp = mn_0; + return 0; +} + +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_arr_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_art_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar4_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar4_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar8_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar8_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ar12_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar12_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_ars_entry_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_entry_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x1f) != 0; + return error; +} + +static int +Operand_immrx4_decode (uint32 *valp) +{ + unsigned immrx4_0, r_0; + r_0 = *valp & 0xf; + immrx4_0 = (((0xfffffff) << 4) | r_0) << 2; + *valp = immrx4_0; + return 0; +} + +static int +Operand_immrx4_encode (uint32 *valp) +{ + unsigned r_0, immrx4_0; + immrx4_0 = *valp; + r_0 = ((immrx4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; +} + +static int +Operand_lsi4x4_encode (uint32 *valp) +{ + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_simm7_decode (uint32 *valp) +{ + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; +} + +static int +Operand_simm7_encode (uint32 *valp) +{ + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; +} + +static int +Operand_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + (((0) << 6) | imm6_0); + *valp = uimm6_0; + return 0; +} + +static int +Operand_uimm6_encode (uint32 *valp) +{ + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; +} + +static int +Operand_ai4const_encode (uint32 *valp) +{ + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; +} + +static int +Operand_b4const_decode (uint32 *valp) +{ + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; +} + +static int +Operand_b4const_encode (uint32 *valp) +{ + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; +} + +static int +Operand_b4constu_encode (uint32 *valp) +{ + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; +} + +static int +Operand_uimm8_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; +} + +static int +Operand_uimm8x2_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; +} + +static int +Operand_uimm8x4_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; +} + +static int +Operand_uimm4x16_encode (uint32 *valp) +{ + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; +} + +static int +Operand_simm8_decode (uint32 *valp) +{ + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; +} + +static int +Operand_simm8_encode (uint32 *valp) +{ + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; +} + +static int +Operand_simm8x256_encode (uint32 *valp) +{ + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; +} + +static int +Operand_simm12b_encode (uint32 *valp) +{ + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; +} + +static int +Operand_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; +} + +static int +Operand_msalp32_encode (uint32 *valp) +{ + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; +} + +static int +Operand_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; +} + +static int +Operand_op2p1_encode (uint32 *valp) +{ + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; +} + +static int +Operand_label8_decode (uint32 *valp) +{ + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; +} + +static int +Operand_label8_encode (uint32 *valp) +{ + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ulabel8_decode (uint32 *valp) +{ + unsigned ulabel8_0, imm8_0; + imm8_0 = *valp & 0xff; + ulabel8_0 = 0x4 + (((0) << 8) | imm8_0); + *valp = ulabel8_0; + return 0; +} + +static int +Operand_ulabel8_encode (uint32 *valp) +{ + unsigned imm8_0, ulabel8_0; + ulabel8_0 = *valp; + imm8_0 = (ulabel8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_ulabel8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_ulabel8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_decode (uint32 *valp) +{ + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; +} + +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} + +static int +Operand_soffset_encode (uint32 *valp) +{ + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = (((0xffff) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; +} + +static int +Operand_uimm16x4_encode (uint32 *valp) +{ + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_mx_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mx_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_my_decode (uint32 *valp) +{ + *valp += 2; + return 0; +} + +static int +Operand_my_encode (uint32 *valp) +{ + int error; + error = ((*valp & ~0x3) != 0) || ((*valp & 0x2) == 0); + *valp = *valp & 1; + return error; +} + +static int +Operand_mw_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mw_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr1_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr1_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr2_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr2_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_mr3_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_mr3_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3) != 0; + return error; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static int +Operand_tp7_decode (uint32 *valp) +{ + unsigned tp7_0, t_0; + t_0 = *valp & 0xf; + tp7_0 = t_0 + 0x7; + *valp = tp7_0; + return 0; +} + +static int +Operand_tp7_encode (uint32 *valp) +{ + unsigned t_0, tp7_0; + tp7_0 = *valp; + t_0 = (tp7_0 - 0x7) & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_xt_wbr15_label_decode (uint32 *valp) +{ + unsigned xt_wbr15_label_0, xt_wbr15_imm_0; + xt_wbr15_imm_0 = *valp & 0x7fff; + xt_wbr15_label_0 = 0x4 + (((int) xt_wbr15_imm_0 << 17) >> 17); + *valp = xt_wbr15_label_0; + return 0; +} + +static int +Operand_xt_wbr15_label_encode (uint32 *valp) +{ + unsigned xt_wbr15_imm_0, xt_wbr15_label_0; + xt_wbr15_label_0 = *valp; + xt_wbr15_imm_0 = (xt_wbr15_label_0 - 0x4) & 0x7fff; + *valp = xt_wbr15_imm_0; + return 0; +} + +static int +Operand_xt_wbr15_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr15_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_xt_wbr18_label_decode (uint32 *valp) +{ + unsigned xt_wbr18_label_0, xt_wbr18_imm_0; + xt_wbr18_imm_0 = *valp & 0x3ffff; + xt_wbr18_label_0 = 0x4 + (((int) xt_wbr18_imm_0 << 14) >> 14); + *valp = xt_wbr18_label_0; + return 0; +} + +static int +Operand_xt_wbr18_label_encode (uint32 *valp) +{ + unsigned xt_wbr18_imm_0, xt_wbr18_label_0; + xt_wbr18_label_0 = *valp; + xt_wbr18_imm_0 = (xt_wbr18_label_0 - 0x4) & 0x3ffff; + *valp = xt_wbr18_imm_0; + return 0; +} + +static int +Operand_xt_wbr18_label_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_xt_wbr18_label_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "soffsetx4", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "uimm12x8", FIELD_imm12, -1, 0, + 0, + Operand_uimm12x8_encode, Operand_uimm12x8_decode, + 0, 0 }, + { "simm4", FIELD_mn, -1, 0, + 0, + Operand_simm4_encode, Operand_simm4_decode, + 0, 0 }, + { "arr", FIELD_r, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ars", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "art", FIELD_t, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ar0", FIELD__ar0, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "ar4", FIELD__ar4, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar4_encode, Operand_ar4_decode, + 0, 0 }, + { "ar8", FIELD__ar8, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar8_encode, Operand_ar8_decode, + 0, 0 }, + { "ar12", FIELD__ar12, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar12_encode, Operand_ar12_decode, + 0, 0 }, + { "ars_entry", FIELD_s, REGFILE_AR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_entry_encode, Operand_ars_entry_decode, + 0, 0 }, + { "immrx4", FIELD_r, -1, 0, + 0, + Operand_immrx4_encode, Operand_immrx4_decode, + 0, 0 }, + { "lsi4x4", FIELD_r, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", FIELD_imm7, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", FIELD_imm6, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", FIELD_t, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", FIELD_r, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", FIELD_r, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", FIELD_imm8, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", FIELD_imm8, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", FIELD_op2, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", FIELD_imm8, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", FIELD_imm8, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", FIELD_imm12b, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", FIELD_sal, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", FIELD_op2, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "ulabel8", FIELD_imm8, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_ulabel8_encode, Operand_ulabel8_decode, + Operand_ulabel8_ator, Operand_ulabel8_rtoa }, + { "label12", FIELD_imm12, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", FIELD_offset, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", FIELD_imm16, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "mx", FIELD_x, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + Operand_mx_encode, Operand_mx_decode, + 0, 0 }, + { "my", FIELD_y, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_UNKNOWN, + Operand_my_encode, Operand_my_decode, + 0, 0 }, + { "mw", FIELD_w, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_mw_encode, Operand_mw_decode, + 0, 0 }, + { "mr0", FIELD__mr0, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr0_encode, Operand_mr0_decode, + 0, 0 }, + { "mr1", FIELD__mr1, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr1_encode, Operand_mr1_decode, + 0, 0 }, + { "mr2", FIELD__mr2, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr2_encode, Operand_mr2_decode, + 0, 0 }, + { "mr3", FIELD__mr3, REGFILE_MR, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_mr3_encode, Operand_mr3_decode, + 0, 0 }, + { "immt", FIELD_t, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", FIELD_s, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "tp7", FIELD_t, -1, 0, + 0, + Operand_tp7_encode, Operand_tp7_decode, + 0, 0 }, + { "xt_wbr15_label", FIELD_xt_wbr15_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr15_label_encode, Operand_xt_wbr15_label_decode, + Operand_xt_wbr15_label_ator, Operand_xt_wbr15_label_rtoa }, + { "xt_wbr18_label", FIELD_xt_wbr18_imm, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_xt_wbr18_label_encode, Operand_xt_wbr18_label_decode, + Operand_xt_wbr18_label_ator, Operand_xt_wbr18_label_rtoa }, + { "t", FIELD_t, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", FIELD_bbi4, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", FIELD_bbi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", FIELD_imm12, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", FIELD_imm8, -1, 0, 0, 0, 0, 0, 0 }, + { "s", FIELD_s, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", FIELD_imm12b, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", FIELD_imm16, -1, 0, 0, 0, 0, 0, 0 }, + { "m", FIELD_m, -1, 0, 0, 0, 0, 0, 0 }, + { "n", FIELD_n, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", FIELD_offset, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", FIELD_op0, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", FIELD_op1, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", FIELD_op2, -1, 0, 0, 0, 0, 0, 0 }, + { "r", FIELD_r, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", FIELD_sa4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", FIELD_sae4, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", FIELD_sae, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", FIELD_sal, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", FIELD_sargt, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", FIELD_sas4, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", FIELD_sas, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", FIELD_sr, -1, 0, 0, 0, 0, 0, 0 }, + { "st", FIELD_st, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", FIELD_thi3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", FIELD_imm4, -1, 0, 0, 0, 0, 0, 0 }, + { "mn", FIELD_mn, -1, 0, 0, 0, 0, 0, 0 }, + { "i", FIELD_i, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", FIELD_imm6lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", FIELD_imm6hi, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", FIELD_imm7lo, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", FIELD_imm7hi, -1, 0, 0, 0, 0, 0, 0 }, + { "z", FIELD_z, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", FIELD_imm6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", FIELD_imm7, -1, 0, 0, 0, 0, 0, 0 }, + { "r3", FIELD_r3, -1, 0, 0, 0, 0, 0, 0 }, + { "rbit2", FIELD_rbit2, -1, 0, 0, 0, 0, 0, 0 }, + { "rhi", FIELD_rhi, -1, 0, 0, 0, 0, 0, 0 }, + { "t3", FIELD_t3, -1, 0, 0, 0, 0, 0, 0 }, + { "tbit2", FIELD_tbit2, -1, 0, 0, 0, 0, 0, 0 }, + { "tlo", FIELD_tlo, -1, 0, 0, 0, 0, 0, 0 }, + { "w", FIELD_w, -1, 0, 0, 0, 0, 0, 0 }, + { "y", FIELD_y, -1, 0, 0, 0, 0, 0, 0 }, + { "x", FIELD_x, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr15_imm", FIELD_xt_wbr15_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "xt_wbr18_imm", FIELD_xt_wbr18_imm, -1, 0, 0, 0, 0, 0, 0 }, + { "bitindex", FIELD_bitindex, -1, 0, 0, 0, 0, 0, 0 }, + { "s3to1", FIELD_s3to1, -1, 0, 0, 0, 0, 0, 0 } +}; + +enum xtensa_operand_id { + OPERAND_soffsetx4, + OPERAND_uimm12x8, + OPERAND_simm4, + OPERAND_arr, + OPERAND_ars, + OPERAND__ars_invisible, + OPERAND_art, + OPERAND_ar0, + OPERAND_ar4, + OPERAND_ar8, + OPERAND_ar12, + OPERAND_ars_entry, + OPERAND_immrx4, + OPERAND_lsi4x4, + OPERAND_simm7, + OPERAND_uimm6, + OPERAND_ai4const, + OPERAND_b4const, + OPERAND_b4constu, + OPERAND_uimm8, + OPERAND_uimm8x2, + OPERAND_uimm8x4, + OPERAND_uimm4x16, + OPERAND_simm8, + OPERAND_simm8x256, + OPERAND_simm12b, + OPERAND_msalp32, + OPERAND_op2p1, + OPERAND_label8, + OPERAND_ulabel8, + OPERAND_label12, + OPERAND_soffset, + OPERAND_uimm16x4, + OPERAND_mx, + OPERAND_my, + OPERAND_mw, + OPERAND_mr0, + OPERAND_mr1, + OPERAND_mr2, + OPERAND_mr3, + OPERAND_immt, + OPERAND_imms, + OPERAND_tp7, + OPERAND_xt_wbr15_label, + OPERAND_xt_wbr18_label, + OPERAND_t, + OPERAND_bbi4, + OPERAND_bbi, + OPERAND_imm12, + OPERAND_imm8, + OPERAND_s, + OPERAND_imm12b, + OPERAND_imm16, + OPERAND_m, + OPERAND_n, + OPERAND_offset, + OPERAND_op0, + OPERAND_op1, + OPERAND_op2, + OPERAND_r, + OPERAND_sa4, + OPERAND_sae4, + OPERAND_sae, + OPERAND_sal, + OPERAND_sargt, + OPERAND_sas4, + OPERAND_sas, + OPERAND_sr, + OPERAND_st, + OPERAND_thi3, + OPERAND_imm4, + OPERAND_mn, + OPERAND_i, + OPERAND_imm6lo, + OPERAND_imm6hi, + OPERAND_imm7lo, + OPERAND_imm7hi, + OPERAND_z, + OPERAND_imm6, + OPERAND_imm7, + OPERAND_r3, + OPERAND_rbit2, + OPERAND_rhi, + OPERAND_t3, + OPERAND_tbit2, + OPERAND_tlo, + OPERAND_w, + OPERAND_y, + OPERAND_x, + OPERAND_xt_wbr15_imm, + OPERAND_xt_wbr18_imm, + OPERAND_bitindex, + OPERAND_s3to1 +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSRING }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar12 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar8 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar12 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar8 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_args[] = { + { { OPERAND_ars_entry }, 's' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm12x8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_stateArgs[] = { + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_stateArgs[] = { + { { STATE_WindowBase }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_args[] = { + { { OPERAND_simm4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_stateArgs[] = { + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfwou_stateArgs[] = { + { { STATE_EPC1 }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSOWB }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_immrx4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_immrx4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_ai4const }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { OPERAND_ars }, 'o' }, + { { OPERAND_simm7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_lsi4x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_threadptr_stateArgs[] = { + { { STATE_THREADPTR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_simm8x256 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4const }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_bbi }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_b4constu }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_label8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_label12 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { OPERAND_soffsetx4 }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ar0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sae }, 'i' }, + { { OPERAND_op2p1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { OPERAND_soffset }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_uimm16x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ulabel8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_ulabel8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_simm12b }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { OPERAND_arr }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { OPERAND__ars_invisible }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { OPERAND_sas }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_msalp32 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_sargt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_art }, 'i' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_stateArgs[] = { + { { STATE_LEND }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_stateArgs[] = { + { { STATE_LEND }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_stateArgs[] = { + { { STATE_LEND }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_stateArgs[] = { + { { STATE_LCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_176_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_176_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'm' }, + { { STATE_PSCALLINC }, 'm' }, + { { STATE_PSOWB }, 'm' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps5_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS5 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps6_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS6 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps7_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS7 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_vecbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_VECBASE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_mul16_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_mul32_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_aa_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_ad_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_da_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_dd_stateArgs[] = { + { { STATE_ACC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_aa_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_ad_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_args[] = { + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16a_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_mx }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_da_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' }, + { { OPERAND_mx }, 'i' }, + { { OPERAND_my }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16al_dd_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mac16_l_args[] = { + { { OPERAND_mw }, 'o' }, + { { OPERAND_ars }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m0_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m0_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m0_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m1_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m1_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m1_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m2_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m2_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m2_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_m3_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_mr3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_m3_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_mr3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_m3_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_mr3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acclo_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_acchi_stateArgs[] = { + { { STATE_ACC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_EPC5 }, 'i' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_EPC7 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_EPS4 }, 'i' }, + { { STATE_EPS5 }, 'i' }, + { { STATE_EPS6 }, 'i' }, + { { STATE_EPS7 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { OPERAND_s }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { OPERAND_imms }, 'i' }, + { { OPERAND_immt }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_args[] = { + { { OPERAND_imms }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC6 }, 'i' }, + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS6 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_mmid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_lock_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm4x16 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_lock_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm4x16 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dpf_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_lock_args[] = { + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm4x16 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_lock_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'm' }, + { { STATE_EXCVADDR }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'i' }, + { { STATE_ASID2 }, 'i' }, + { { STATE_ASID1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'o' }, + { { STATE_ASID2 }, 'o' }, + { { STATE_ASID1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'm' }, + { { STATE_ASID2 }, 'm' }, + { { STATE_ASID1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID6 }, 'i' }, + { { STATE_INSTPGSZID5 }, 'i' }, + { { STATE_INSTPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID6 }, 'o' }, + { { STATE_INSTPGSZID5 }, 'o' }, + { { STATE_INSTPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID6 }, 'm' }, + { { STATE_INSTPGSZID5 }, 'm' }, + { { STATE_INSTPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID6 }, 'i' }, + { { STATE_DATAPGSZID5 }, 'i' }, + { { STATE_DATAPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID6 }, 'o' }, + { { STATE_DATAPGSZID5 }, 'o' }, + { { STATE_DATAPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID6 }, 'm' }, + { { STATE_DATAPGSZID5 }, 'm' }, + { { STATE_DATAPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldpte_stateArgs[] = { + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwitlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwdtlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_cpenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CPENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_clamp_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_tp7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_minmax_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sx_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_tp7 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32ai_args[] = { + { { OPERAND_art }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32ri_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_args[] = { + { { OPERAND_art }, 'm' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_uimm8x4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32c1i_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' }, + { { STATE_XTSYNC }, 'i' }, + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_scompare1_stateArgs[] = { + { { STATE_SCOMPARE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_atomctl_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_atomctl_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ATOMCTL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_atomctl_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_atomctl_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ATOMCTL }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_atomctl_args[] = { + { { OPERAND_art }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_atomctl_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ATOMCTL }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_div_args[] = { + { { OPERAND_arr }, 'o' }, + { { OPERAND_ars }, 'i' }, + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rer_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wer_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_args[] = { + { { OPERAND_arr }, 'o' } +}; + +static xtensa_arg_internal Iclass_rur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'i' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_args[] = { + { { OPERAND_art }, 'i' } +}; + +static xtensa_arg_internal Iclass_wur_expstate_stateArgs[] = { + { { STATE_EXPSTATE }, 'o' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_READ_IMPWIRE_args[] = { + { { OPERAND_art }, 'o' } +}; + +static xtensa_arg_internal Iclass_iclass_READ_IMPWIRE_stateArgs[] = { + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_interface Iclass_iclass_READ_IMPWIRE_intfArgs[] = { + INTERFACE_IMPWIRE +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_args[] = { + { { OPERAND_bitindex }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_SETB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_args[] = { + { { OPERAND_bitindex }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_CLRB_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_args[] = { + { { OPERAND_art }, 'i' }, + { { OPERAND_ars }, 'i' } +}; + +static xtensa_arg_internal Iclass_iclass_WRMSK_EXPSTATE_stateArgs[] = { + { { STATE_EXPSTATE }, 'm' }, + { { STATE_CPENABLE }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 3, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 3, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call12_args, + 1, Iclass_xt_iclass_call12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call8_args, + 1, Iclass_xt_iclass_call8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call4_args, + 1, Iclass_xt_iclass_call4_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx12_args, + 1, Iclass_xt_iclass_callx12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx8_args, + 1, Iclass_xt_iclass_callx8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx4_args, + 1, Iclass_xt_iclass_callx4_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_entry_args, + 5, Iclass_xt_iclass_entry_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movsp_args, + 2, Iclass_xt_iclass_movsp_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rotw_args, + 3, Iclass_xt_iclass_rotw_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_retw_args, + 4, Iclass_xt_iclass_retw_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfwou */, + 6, Iclass_xt_iclass_rfwou_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l32e_args, + 2, Iclass_xt_iclass_l32e_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_s32e_args, + 2, Iclass_xt_iclass_s32e_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowbase_args, + 3, Iclass_xt_iclass_rsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowbase_args, + 3, Iclass_xt_iclass_wsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowbase_args, + 3, Iclass_xt_iclass_xsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowstart_args, + 3, Iclass_xt_iclass_rsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowstart_args, + 3, Iclass_xt_iclass_wsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowstart_args, + 3, Iclass_xt_iclass_xsr_windowstart_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 1, Iclass_rur_threadptr_args, + 1, Iclass_rur_threadptr_stateArgs, 0, 0 }, + { 1, Iclass_wur_threadptr_args, + 1, Iclass_wur_threadptr_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_loop_args, + 3, Iclass_xt_iclass_loop_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_loopz_args, + 3, Iclass_xt_iclass_loopz_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 7, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lend_args, + 1, Iclass_xt_iclass_rsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lend_args, + 1, Iclass_xt_iclass_wsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lend_args, + 1, Iclass_xt_iclass_xsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lcount_args, + 1, Iclass_xt_iclass_rsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lcount_args, + 2, Iclass_xt_iclass_wsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lcount_args, + 2, Iclass_xt_iclass_xsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lbeg_args, + 1, Iclass_xt_iclass_rsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lbeg_args, + 1, Iclass_xt_iclass_wsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lbeg_args, + 1, Iclass_xt_iclass_xsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 2, Iclass_xt_iclass_rsr_176_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_176_args, + 2, Iclass_xt_iclass_wsr_176_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 2, Iclass_xt_iclass_rsr_208_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 7, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 7, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 7, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 3, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 3, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 3, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 3, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 3, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 3, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 3, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 3, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 3, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 3, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 3, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 3, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 3, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 3, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 3, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 3, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 3, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 3, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc4_args, + 3, Iclass_xt_iclass_rsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc4_args, + 3, Iclass_xt_iclass_wsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc4_args, + 3, Iclass_xt_iclass_xsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave4_args, + 3, Iclass_xt_iclass_rsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave4_args, + 3, Iclass_xt_iclass_wsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave4_args, + 3, Iclass_xt_iclass_xsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc5_args, + 3, Iclass_xt_iclass_rsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc5_args, + 3, Iclass_xt_iclass_wsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc5_args, + 3, Iclass_xt_iclass_xsr_epc5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave5_args, + 3, Iclass_xt_iclass_rsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave5_args, + 3, Iclass_xt_iclass_wsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave5_args, + 3, Iclass_xt_iclass_xsr_excsave5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc6_args, + 3, Iclass_xt_iclass_rsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc6_args, + 3, Iclass_xt_iclass_wsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc6_args, + 3, Iclass_xt_iclass_xsr_epc6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave6_args, + 3, Iclass_xt_iclass_rsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave6_args, + 3, Iclass_xt_iclass_wsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave6_args, + 3, Iclass_xt_iclass_xsr_excsave6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc7_args, + 3, Iclass_xt_iclass_rsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc7_args, + 3, Iclass_xt_iclass_wsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc7_args, + 3, Iclass_xt_iclass_xsr_epc7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave7_args, + 3, Iclass_xt_iclass_rsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave7_args, + 3, Iclass_xt_iclass_wsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave7_args, + 3, Iclass_xt_iclass_xsr_excsave7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 3, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 3, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 3, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 3, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 3, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 3, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps4_args, + 3, Iclass_xt_iclass_rsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps4_args, + 3, Iclass_xt_iclass_wsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps4_args, + 3, Iclass_xt_iclass_xsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps5_args, + 3, Iclass_xt_iclass_rsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps5_args, + 3, Iclass_xt_iclass_wsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps5_args, + 3, Iclass_xt_iclass_xsr_eps5_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps6_args, + 3, Iclass_xt_iclass_rsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps6_args, + 3, Iclass_xt_iclass_wsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps6_args, + 3, Iclass_xt_iclass_xsr_eps6_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps7_args, + 3, Iclass_xt_iclass_rsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps7_args, + 3, Iclass_xt_iclass_wsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps7_args, + 3, Iclass_xt_iclass_xsr_eps7_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 3, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 3, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 3, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 3, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 3, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 3, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 4, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 3, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 3, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc0_args, + 3, Iclass_xt_iclass_rsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc0_args, + 3, Iclass_xt_iclass_wsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc0_args, + 3, Iclass_xt_iclass_xsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc1_args, + 3, Iclass_xt_iclass_rsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc1_args, + 3, Iclass_xt_iclass_wsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc1_args, + 3, Iclass_xt_iclass_xsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 2, Iclass_xt_iclass_rsr_prid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_vecbase_args, + 3, Iclass_xt_iclass_rsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_vecbase_args, + 3, Iclass_xt_iclass_wsr_vecbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_vecbase_args, + 3, Iclass_xt_iclass_xsr_vecbase_stateArgs, 0, 0 }, + { 3, Iclass_xt_mul16_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_mul32_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_aa_args, + 1, Iclass_xt_iclass_mac16_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_ad_args, + 1, Iclass_xt_iclass_mac16_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_da_args, + 1, Iclass_xt_iclass_mac16_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_dd_args, + 1, Iclass_xt_iclass_mac16_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_aa_args, + 1, Iclass_xt_iclass_mac16a_aa_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_ad_args, + 1, Iclass_xt_iclass_mac16a_ad_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_da_args, + 1, Iclass_xt_iclass_mac16a_da_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16a_dd_args, + 1, Iclass_xt_iclass_mac16a_dd_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_da_args, + 1, Iclass_xt_iclass_mac16al_da_stateArgs, 0, 0 }, + { 4, Iclass_xt_iclass_mac16al_dd_args, + 1, Iclass_xt_iclass_mac16al_dd_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_mac16_l_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m1_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m2_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_rsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_wsr_m3_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_xsr_m3_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acclo_args, + 1, Iclass_xt_iclass_rsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acclo_args, + 1, Iclass_xt_iclass_wsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acclo_args, + 1, Iclass_xt_iclass_xsr_acclo_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_acchi_args, + 1, Iclass_xt_iclass_rsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_acchi_args, + 1, Iclass_xt_iclass_wsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_acchi_args, + 1, Iclass_xt_iclass_xsr_acchi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 21, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 3, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 3, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 4, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 4, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 3, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 3, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 3, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 3, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 4, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 4, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 3, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 4, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 4, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka1_args, + 3, Iclass_xt_iclass_rsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka1_args, + 4, Iclass_xt_iclass_wsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka1_args, + 4, Iclass_xt_iclass_xsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc1_args, + 3, Iclass_xt_iclass_rsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc1_args, + 4, Iclass_xt_iclass_wsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc1_args, + 4, Iclass_xt_iclass_xsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 3, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 3, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 3, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka1_args, + 3, Iclass_xt_iclass_rsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka1_args, + 3, Iclass_xt_iclass_wsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka1_args, + 3, Iclass_xt_iclass_xsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 3, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 3, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 3, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 4, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 4, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 4, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 3, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 4, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 4, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 3, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 3, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 3, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 3, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 4, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 4, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfdo_args, + 10, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_mmid_args, + 3, Iclass_xt_iclass_wsr_mmid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 3, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 4, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 4, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 3, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 4, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 4, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare1_args, + 3, Iclass_xt_iclass_rsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare1_args, + 4, Iclass_xt_iclass_wsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare1_args, + 4, Iclass_xt_iclass_xsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare2_args, + 3, Iclass_xt_iclass_rsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare2_args, + 4, Iclass_xt_iclass_wsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare2_args, + 4, Iclass_xt_iclass_xsr_ccompare2_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_icache_lock_args, + 2, Iclass_xt_iclass_icache_lock_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_inv_args, + 2, Iclass_xt_iclass_icache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_licx_args, + 2, Iclass_xt_iclass_licx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_sicx_args, + 2, Iclass_xt_iclass_sicx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_ind_args, + 2, Iclass_xt_iclass_dcache_ind_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_inv_args, + 2, Iclass_xt_iclass_dcache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dpf_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_lock_args, + 2, Iclass_xt_iclass_dcache_lock_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_sdct_args, + 2, Iclass_xt_iclass_sdct_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ldct_args, + 2, Iclass_xt_iclass_ldct_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ptevaddr_args, + 4, Iclass_xt_iclass_wsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ptevaddr_args, + 4, Iclass_xt_iclass_rsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ptevaddr_args, + 5, Iclass_xt_iclass_xsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_rasid_args, + 5, Iclass_xt_iclass_rsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_rasid_args, + 6, Iclass_xt_iclass_wsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_rasid_args, + 6, Iclass_xt_iclass_xsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_itlbcfg_args, + 5, Iclass_xt_iclass_rsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_itlbcfg_args, + 6, Iclass_xt_iclass_wsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_itlbcfg_args, + 6, Iclass_xt_iclass_xsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dtlbcfg_args, + 5, Iclass_xt_iclass_rsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dtlbcfg_args, + 6, Iclass_xt_iclass_wsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dtlbcfg_args, + 6, Iclass_xt_iclass_xsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 3, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 2, Iclass_xt_iclass_rdtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 3, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 2, Iclass_xt_iclass_iitlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 2, Iclass_xt_iclass_ritlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 2, Iclass_xt_iclass_witlb_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_ldpte */, + 2, Iclass_xt_iclass_ldpte_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwitlba */, + 1, Iclass_xt_iclass_hwwitlba_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwdtlba */, + 1, Iclass_xt_iclass_hwwdtlba_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_cpenable_args, + 3, Iclass_xt_iclass_rsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_cpenable_args, + 3, Iclass_xt_iclass_wsr_cpenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_cpenable_args, + 3, Iclass_xt_iclass_xsr_cpenable_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_clamp_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_minmax_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_sx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32ai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32ri_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32c1i_args, + 3, Iclass_xt_iclass_s32c1i_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_scompare1_args, + 1, Iclass_xt_iclass_rsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_scompare1_args, + 1, Iclass_xt_iclass_wsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_scompare1_args, + 1, Iclass_xt_iclass_xsr_scompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_atomctl_args, + 3, Iclass_xt_iclass_rsr_atomctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_atomctl_args, + 4, Iclass_xt_iclass_wsr_atomctl_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_atomctl_args, + 4, Iclass_xt_iclass_xsr_atomctl_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_div_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rer */, + 2, Iclass_xt_iclass_rer_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_wer */, + 2, Iclass_xt_iclass_wer_stateArgs, 0, 0 }, + { 1, Iclass_rur_expstate_args, + 2, Iclass_rur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_wur_expstate_args, + 2, Iclass_wur_expstate_stateArgs, 0, 0 }, + { 1, Iclass_iclass_READ_IMPWIRE_args, + 1, Iclass_iclass_READ_IMPWIRE_stateArgs, 1, Iclass_iclass_READ_IMPWIRE_intfArgs }, + { 1, Iclass_iclass_SETB_EXPSTATE_args, + 2, Iclass_iclass_SETB_EXPSTATE_stateArgs, 0, 0 }, + { 1, Iclass_iclass_CLRB_EXPSTATE_args, + 2, Iclass_iclass_CLRB_EXPSTATE_stateArgs, 0, 0 }, + { 2, Iclass_iclass_WRMSK_EXPSTATE_args, + 2, Iclass_iclass_WRMSK_EXPSTATE_stateArgs, 0, 0 } +}; + +enum xtensa_iclass_id { + ICLASS_xt_iclass_excw, + ICLASS_xt_iclass_rfe, + ICLASS_xt_iclass_rfde, + ICLASS_xt_iclass_syscall, + ICLASS_xt_iclass_simcall, + ICLASS_xt_iclass_call12, + ICLASS_xt_iclass_call8, + ICLASS_xt_iclass_call4, + ICLASS_xt_iclass_callx12, + ICLASS_xt_iclass_callx8, + ICLASS_xt_iclass_callx4, + ICLASS_xt_iclass_entry, + ICLASS_xt_iclass_movsp, + ICLASS_xt_iclass_rotw, + ICLASS_xt_iclass_retw, + ICLASS_xt_iclass_rfwou, + ICLASS_xt_iclass_l32e, + ICLASS_xt_iclass_s32e, + ICLASS_xt_iclass_rsr_windowbase, + ICLASS_xt_iclass_wsr_windowbase, + ICLASS_xt_iclass_xsr_windowbase, + ICLASS_xt_iclass_rsr_windowstart, + ICLASS_xt_iclass_wsr_windowstart, + ICLASS_xt_iclass_xsr_windowstart, + ICLASS_xt_iclass_add_n, + ICLASS_xt_iclass_addi_n, + ICLASS_xt_iclass_bz6, + ICLASS_xt_iclass_ill_n, + ICLASS_xt_iclass_loadi4, + ICLASS_xt_iclass_mov_n, + ICLASS_xt_iclass_movi_n, + ICLASS_xt_iclass_nopn, + ICLASS_xt_iclass_retn, + ICLASS_xt_iclass_storei4, + ICLASS_rur_threadptr, + ICLASS_wur_threadptr, + ICLASS_xt_iclass_addi, + ICLASS_xt_iclass_addmi, + ICLASS_xt_iclass_addsub, + ICLASS_xt_iclass_bit, + ICLASS_xt_iclass_bsi8, + ICLASS_xt_iclass_bsi8b, + ICLASS_xt_iclass_bsi8u, + ICLASS_xt_iclass_bst8, + ICLASS_xt_iclass_bsz12, + ICLASS_xt_iclass_call0, + ICLASS_xt_iclass_callx0, + ICLASS_xt_iclass_exti, + ICLASS_xt_iclass_ill, + ICLASS_xt_iclass_jump, + ICLASS_xt_iclass_jumpx, + ICLASS_xt_iclass_l16ui, + ICLASS_xt_iclass_l16si, + ICLASS_xt_iclass_l32i, + ICLASS_xt_iclass_l32r, + ICLASS_xt_iclass_l8i, + ICLASS_xt_iclass_loop, + ICLASS_xt_iclass_loopz, + ICLASS_xt_iclass_movi, + ICLASS_xt_iclass_movz, + ICLASS_xt_iclass_neg, + ICLASS_xt_iclass_nop, + ICLASS_xt_iclass_return, + ICLASS_xt_iclass_s16i, + ICLASS_xt_iclass_s32i, + ICLASS_xt_iclass_s8i, + ICLASS_xt_iclass_sar, + ICLASS_xt_iclass_sari, + ICLASS_xt_iclass_shifts, + ICLASS_xt_iclass_shiftst, + ICLASS_xt_iclass_shiftt, + ICLASS_xt_iclass_slli, + ICLASS_xt_iclass_srai, + ICLASS_xt_iclass_srli, + ICLASS_xt_iclass_memw, + ICLASS_xt_iclass_extw, + ICLASS_xt_iclass_isync, + ICLASS_xt_iclass_sync, + ICLASS_xt_iclass_rsil, + ICLASS_xt_iclass_rsr_lend, + ICLASS_xt_iclass_wsr_lend, + ICLASS_xt_iclass_xsr_lend, + ICLASS_xt_iclass_rsr_lcount, + ICLASS_xt_iclass_wsr_lcount, + ICLASS_xt_iclass_xsr_lcount, + ICLASS_xt_iclass_rsr_lbeg, + ICLASS_xt_iclass_wsr_lbeg, + ICLASS_xt_iclass_xsr_lbeg, + ICLASS_xt_iclass_rsr_sar, + ICLASS_xt_iclass_wsr_sar, + ICLASS_xt_iclass_xsr_sar, + ICLASS_xt_iclass_rsr_litbase, + ICLASS_xt_iclass_wsr_litbase, + ICLASS_xt_iclass_xsr_litbase, + ICLASS_xt_iclass_rsr_176, + ICLASS_xt_iclass_wsr_176, + ICLASS_xt_iclass_rsr_208, + ICLASS_xt_iclass_rsr_ps, + ICLASS_xt_iclass_wsr_ps, + ICLASS_xt_iclass_xsr_ps, + ICLASS_xt_iclass_rsr_epc1, + ICLASS_xt_iclass_wsr_epc1, + ICLASS_xt_iclass_xsr_epc1, + ICLASS_xt_iclass_rsr_excsave1, + ICLASS_xt_iclass_wsr_excsave1, + ICLASS_xt_iclass_xsr_excsave1, + ICLASS_xt_iclass_rsr_epc2, + ICLASS_xt_iclass_wsr_epc2, + ICLASS_xt_iclass_xsr_epc2, + ICLASS_xt_iclass_rsr_excsave2, + ICLASS_xt_iclass_wsr_excsave2, + ICLASS_xt_iclass_xsr_excsave2, + ICLASS_xt_iclass_rsr_epc3, + ICLASS_xt_iclass_wsr_epc3, + ICLASS_xt_iclass_xsr_epc3, + ICLASS_xt_iclass_rsr_excsave3, + ICLASS_xt_iclass_wsr_excsave3, + ICLASS_xt_iclass_xsr_excsave3, + ICLASS_xt_iclass_rsr_epc4, + ICLASS_xt_iclass_wsr_epc4, + ICLASS_xt_iclass_xsr_epc4, + ICLASS_xt_iclass_rsr_excsave4, + ICLASS_xt_iclass_wsr_excsave4, + ICLASS_xt_iclass_xsr_excsave4, + ICLASS_xt_iclass_rsr_epc5, + ICLASS_xt_iclass_wsr_epc5, + ICLASS_xt_iclass_xsr_epc5, + ICLASS_xt_iclass_rsr_excsave5, + ICLASS_xt_iclass_wsr_excsave5, + ICLASS_xt_iclass_xsr_excsave5, + ICLASS_xt_iclass_rsr_epc6, + ICLASS_xt_iclass_wsr_epc6, + ICLASS_xt_iclass_xsr_epc6, + ICLASS_xt_iclass_rsr_excsave6, + ICLASS_xt_iclass_wsr_excsave6, + ICLASS_xt_iclass_xsr_excsave6, + ICLASS_xt_iclass_rsr_epc7, + ICLASS_xt_iclass_wsr_epc7, + ICLASS_xt_iclass_xsr_epc7, + ICLASS_xt_iclass_rsr_excsave7, + ICLASS_xt_iclass_wsr_excsave7, + ICLASS_xt_iclass_xsr_excsave7, + ICLASS_xt_iclass_rsr_eps2, + ICLASS_xt_iclass_wsr_eps2, + ICLASS_xt_iclass_xsr_eps2, + ICLASS_xt_iclass_rsr_eps3, + ICLASS_xt_iclass_wsr_eps3, + ICLASS_xt_iclass_xsr_eps3, + ICLASS_xt_iclass_rsr_eps4, + ICLASS_xt_iclass_wsr_eps4, + ICLASS_xt_iclass_xsr_eps4, + ICLASS_xt_iclass_rsr_eps5, + ICLASS_xt_iclass_wsr_eps5, + ICLASS_xt_iclass_xsr_eps5, + ICLASS_xt_iclass_rsr_eps6, + ICLASS_xt_iclass_wsr_eps6, + ICLASS_xt_iclass_xsr_eps6, + ICLASS_xt_iclass_rsr_eps7, + ICLASS_xt_iclass_wsr_eps7, + ICLASS_xt_iclass_xsr_eps7, + ICLASS_xt_iclass_rsr_excvaddr, + ICLASS_xt_iclass_wsr_excvaddr, + ICLASS_xt_iclass_xsr_excvaddr, + ICLASS_xt_iclass_rsr_depc, + ICLASS_xt_iclass_wsr_depc, + ICLASS_xt_iclass_xsr_depc, + ICLASS_xt_iclass_rsr_exccause, + ICLASS_xt_iclass_wsr_exccause, + ICLASS_xt_iclass_xsr_exccause, + ICLASS_xt_iclass_rsr_misc0, + ICLASS_xt_iclass_wsr_misc0, + ICLASS_xt_iclass_xsr_misc0, + ICLASS_xt_iclass_rsr_misc1, + ICLASS_xt_iclass_wsr_misc1, + ICLASS_xt_iclass_xsr_misc1, + ICLASS_xt_iclass_rsr_prid, + ICLASS_xt_iclass_rsr_vecbase, + ICLASS_xt_iclass_wsr_vecbase, + ICLASS_xt_iclass_xsr_vecbase, + ICLASS_xt_mul16, + ICLASS_xt_mul32, + ICLASS_xt_iclass_mac16_aa, + ICLASS_xt_iclass_mac16_ad, + ICLASS_xt_iclass_mac16_da, + ICLASS_xt_iclass_mac16_dd, + ICLASS_xt_iclass_mac16a_aa, + ICLASS_xt_iclass_mac16a_ad, + ICLASS_xt_iclass_mac16a_da, + ICLASS_xt_iclass_mac16a_dd, + ICLASS_xt_iclass_mac16al_da, + ICLASS_xt_iclass_mac16al_dd, + ICLASS_xt_iclass_mac16_l, + ICLASS_xt_iclass_rsr_m0, + ICLASS_xt_iclass_wsr_m0, + ICLASS_xt_iclass_xsr_m0, + ICLASS_xt_iclass_rsr_m1, + ICLASS_xt_iclass_wsr_m1, + ICLASS_xt_iclass_xsr_m1, + ICLASS_xt_iclass_rsr_m2, + ICLASS_xt_iclass_wsr_m2, + ICLASS_xt_iclass_xsr_m2, + ICLASS_xt_iclass_rsr_m3, + ICLASS_xt_iclass_wsr_m3, + ICLASS_xt_iclass_xsr_m3, + ICLASS_xt_iclass_rsr_acclo, + ICLASS_xt_iclass_wsr_acclo, + ICLASS_xt_iclass_xsr_acclo, + ICLASS_xt_iclass_rsr_acchi, + ICLASS_xt_iclass_wsr_acchi, + ICLASS_xt_iclass_xsr_acchi, + ICLASS_xt_iclass_rfi, + ICLASS_xt_iclass_wait, + ICLASS_xt_iclass_rsr_interrupt, + ICLASS_xt_iclass_wsr_intset, + ICLASS_xt_iclass_wsr_intclear, + ICLASS_xt_iclass_rsr_intenable, + ICLASS_xt_iclass_wsr_intenable, + ICLASS_xt_iclass_xsr_intenable, + ICLASS_xt_iclass_break, + ICLASS_xt_iclass_break_n, + ICLASS_xt_iclass_rsr_dbreaka0, + ICLASS_xt_iclass_wsr_dbreaka0, + ICLASS_xt_iclass_xsr_dbreaka0, + ICLASS_xt_iclass_rsr_dbreakc0, + ICLASS_xt_iclass_wsr_dbreakc0, + ICLASS_xt_iclass_xsr_dbreakc0, + ICLASS_xt_iclass_rsr_dbreaka1, + ICLASS_xt_iclass_wsr_dbreaka1, + ICLASS_xt_iclass_xsr_dbreaka1, + ICLASS_xt_iclass_rsr_dbreakc1, + ICLASS_xt_iclass_wsr_dbreakc1, + ICLASS_xt_iclass_xsr_dbreakc1, + ICLASS_xt_iclass_rsr_ibreaka0, + ICLASS_xt_iclass_wsr_ibreaka0, + ICLASS_xt_iclass_xsr_ibreaka0, + ICLASS_xt_iclass_rsr_ibreaka1, + ICLASS_xt_iclass_wsr_ibreaka1, + ICLASS_xt_iclass_xsr_ibreaka1, + ICLASS_xt_iclass_rsr_ibreakenable, + ICLASS_xt_iclass_wsr_ibreakenable, + ICLASS_xt_iclass_xsr_ibreakenable, + ICLASS_xt_iclass_rsr_debugcause, + ICLASS_xt_iclass_wsr_debugcause, + ICLASS_xt_iclass_xsr_debugcause, + ICLASS_xt_iclass_rsr_icount, + ICLASS_xt_iclass_wsr_icount, + ICLASS_xt_iclass_xsr_icount, + ICLASS_xt_iclass_rsr_icountlevel, + ICLASS_xt_iclass_wsr_icountlevel, + ICLASS_xt_iclass_xsr_icountlevel, + ICLASS_xt_iclass_rsr_ddr, + ICLASS_xt_iclass_wsr_ddr, + ICLASS_xt_iclass_xsr_ddr, + ICLASS_xt_iclass_rfdo, + ICLASS_xt_iclass_rfdd, + ICLASS_xt_iclass_wsr_mmid, + ICLASS_xt_iclass_rsr_ccount, + ICLASS_xt_iclass_wsr_ccount, + ICLASS_xt_iclass_xsr_ccount, + ICLASS_xt_iclass_rsr_ccompare0, + ICLASS_xt_iclass_wsr_ccompare0, + ICLASS_xt_iclass_xsr_ccompare0, + ICLASS_xt_iclass_rsr_ccompare1, + ICLASS_xt_iclass_wsr_ccompare1, + ICLASS_xt_iclass_xsr_ccompare1, + ICLASS_xt_iclass_rsr_ccompare2, + ICLASS_xt_iclass_wsr_ccompare2, + ICLASS_xt_iclass_xsr_ccompare2, + ICLASS_xt_iclass_icache, + ICLASS_xt_iclass_icache_lock, + ICLASS_xt_iclass_icache_inv, + ICLASS_xt_iclass_licx, + ICLASS_xt_iclass_sicx, + ICLASS_xt_iclass_dcache, + ICLASS_xt_iclass_dcache_ind, + ICLASS_xt_iclass_dcache_inv, + ICLASS_xt_iclass_dpf, + ICLASS_xt_iclass_dcache_lock, + ICLASS_xt_iclass_sdct, + ICLASS_xt_iclass_ldct, + ICLASS_xt_iclass_wsr_ptevaddr, + ICLASS_xt_iclass_rsr_ptevaddr, + ICLASS_xt_iclass_xsr_ptevaddr, + ICLASS_xt_iclass_rsr_rasid, + ICLASS_xt_iclass_wsr_rasid, + ICLASS_xt_iclass_xsr_rasid, + ICLASS_xt_iclass_rsr_itlbcfg, + ICLASS_xt_iclass_wsr_itlbcfg, + ICLASS_xt_iclass_xsr_itlbcfg, + ICLASS_xt_iclass_rsr_dtlbcfg, + ICLASS_xt_iclass_wsr_dtlbcfg, + ICLASS_xt_iclass_xsr_dtlbcfg, + ICLASS_xt_iclass_idtlb, + ICLASS_xt_iclass_rdtlb, + ICLASS_xt_iclass_wdtlb, + ICLASS_xt_iclass_iitlb, + ICLASS_xt_iclass_ritlb, + ICLASS_xt_iclass_witlb, + ICLASS_xt_iclass_ldpte, + ICLASS_xt_iclass_hwwitlba, + ICLASS_xt_iclass_hwwdtlba, + ICLASS_xt_iclass_rsr_cpenable, + ICLASS_xt_iclass_wsr_cpenable, + ICLASS_xt_iclass_xsr_cpenable, + ICLASS_xt_iclass_clamp, + ICLASS_xt_iclass_minmax, + ICLASS_xt_iclass_nsa, + ICLASS_xt_iclass_sx, + ICLASS_xt_iclass_l32ai, + ICLASS_xt_iclass_s32ri, + ICLASS_xt_iclass_s32c1i, + ICLASS_xt_iclass_rsr_scompare1, + ICLASS_xt_iclass_wsr_scompare1, + ICLASS_xt_iclass_xsr_scompare1, + ICLASS_xt_iclass_rsr_atomctl, + ICLASS_xt_iclass_wsr_atomctl, + ICLASS_xt_iclass_xsr_atomctl, + ICLASS_xt_iclass_div, + ICLASS_xt_iclass_rer, + ICLASS_xt_iclass_wer, + ICLASS_rur_expstate, + ICLASS_wur_expstate, + ICLASS_iclass_READ_IMPWIRE, + ICLASS_iclass_SETB_EXPSTATE, + ICLASS_iclass_CLRB_EXPSTATE, + ICLASS_iclass_WRMSK_EXPSTATE +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2080; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3000; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3200; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5000; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5100; +} + +static void +Opcode_call12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35; +} + +static void +Opcode_call8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x25; +} + +static void +Opcode_call4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x15; +} + +static void +Opcode_callx12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0; +} + +static void +Opcode_callx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0; +} + +static void +Opcode_callx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd0; +} + +static void +Opcode_entry_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36; +} + +static void +Opcode_movsp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1000; +} + +static void +Opcode_rotw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x408000; +} + +static void +Opcode_retw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90; +} + +static void +Opcode_retw_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf01d; +} + +static void +Opcode_rfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3400; +} + +static void +Opcode_rfwu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3500; +} + +static void +Opcode_l32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90000; +} + +static void +Opcode_s32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490000; +} + +static void +Opcode_rsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34800; +} + +static void +Opcode_wsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134800; +} + +static void +Opcode_xsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614800; +} + +static void +Opcode_rsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x34900; +} + +static void +Opcode_wsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x134900; +} + +static void +Opcode_xsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x614900; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8c; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf06d; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf03d; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00d; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_rur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e70; +} + +static void +Opcode_wur_threadptr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e700; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc002; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd002; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800000; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc00000; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900000; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa00000; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb00000; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00000; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe00000; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf00000; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300000; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x26; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x66; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe6; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa6; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6007; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe007; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf6; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb6; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1007; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9007; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa007; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2007; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb007; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3007; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8007; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4007; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc007; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5007; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd007; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x56; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd6; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x96; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40000; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1002; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9002; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2002; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_loop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8076; +} + +static void +Opcode_loopnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9076; +} + +static void +Opcode_loopgtz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa076; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa002; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x830000; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x930000; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa30000; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb30000; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600100; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20f0; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5002; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6002; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4002; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400000; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x401000; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x402000; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x403000; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404000; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa10000; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x810000; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x910000; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb10000; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10000; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210000; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x410000; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20c0; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20d0; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2000; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2010; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2020; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2030; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6000; +} + +static void +Opcode_rsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30100; +} + +static void +Opcode_wsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130100; +} + +static void +Opcode_xsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610100; +} + +static void +Opcode_rsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30200; +} + +static void +Opcode_wsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130200; +} + +static void +Opcode_xsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610200; +} + +static void +Opcode_rsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30000; +} + +static void +Opcode_wsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130000; +} + +static void +Opcode_xsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610000; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30300; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130300; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610300; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30500; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130500; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610500; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b000; +} + +static void +Opcode_wsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b000; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d000; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e600; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e600; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e600; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b100; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b100; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b100; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d100; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d100; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d100; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b200; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b200; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b200; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d200; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d200; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d200; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b300; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b300; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b300; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d300; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d300; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d300; +} + +static void +Opcode_rsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b400; +} + +static void +Opcode_wsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b400; +} + +static void +Opcode_xsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b400; +} + +static void +Opcode_rsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d400; +} + +static void +Opcode_wsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d400; +} + +static void +Opcode_xsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d400; +} + +static void +Opcode_rsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b500; +} + +static void +Opcode_wsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b500; +} + +static void +Opcode_xsr_epc5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b500; +} + +static void +Opcode_rsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d500; +} + +static void +Opcode_wsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d500; +} + +static void +Opcode_xsr_excsave5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d500; +} + +static void +Opcode_rsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b600; +} + +static void +Opcode_wsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b600; +} + +static void +Opcode_xsr_epc6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b600; +} + +static void +Opcode_rsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d600; +} + +static void +Opcode_wsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d600; +} + +static void +Opcode_xsr_excsave6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d600; +} + +static void +Opcode_rsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b700; +} + +static void +Opcode_wsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13b700; +} + +static void +Opcode_xsr_epc7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61b700; +} + +static void +Opcode_rsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d700; +} + +static void +Opcode_wsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13d700; +} + +static void +Opcode_xsr_excsave7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61d700; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c200; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c200; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c200; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c300; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c300; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c300; +} + +static void +Opcode_rsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c400; +} + +static void +Opcode_wsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c400; +} + +static void +Opcode_xsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c400; +} + +static void +Opcode_rsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c500; +} + +static void +Opcode_wsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c500; +} + +static void +Opcode_xsr_eps5_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c500; +} + +static void +Opcode_rsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c600; +} + +static void +Opcode_wsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c600; +} + +static void +Opcode_xsr_eps6_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c600; +} + +static void +Opcode_rsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c700; +} + +static void +Opcode_wsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c700; +} + +static void +Opcode_xsr_eps7_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c700; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ee00; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ee00; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ee00; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c000; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13c000; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61c000; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e800; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e800; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e800; +} + +static void +Opcode_rsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f400; +} + +static void +Opcode_wsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f400; +} + +static void +Opcode_xsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f400; +} + +static void +Opcode_rsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f500; +} + +static void +Opcode_wsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f500; +} + +static void +Opcode_xsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f500; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3eb00; +} + +static void +Opcode_rsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e700; +} + +static void +Opcode_wsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e700; +} + +static void +Opcode_xsr_vecbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e700; +} + +static void +Opcode_mul16u_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc10000; +} + +static void +Opcode_mul16s_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10000; +} + +static void +Opcode_mull_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x820000; +} + +static void +Opcode_mul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x740004; +} + +static void +Opcode_mul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x750004; +} + +static void +Opcode_mul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x760004; +} + +static void +Opcode_mul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x770004; +} + +static void +Opcode_umul_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700004; +} + +static void +Opcode_umul_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x710004; +} + +static void +Opcode_umul_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x720004; +} + +static void +Opcode_umul_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730004; +} + +static void +Opcode_mul_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x340004; +} + +static void +Opcode_mul_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x350004; +} + +static void +Opcode_mul_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x360004; +} + +static void +Opcode_mul_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x370004; +} + +static void +Opcode_mul_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x640004; +} + +static void +Opcode_mul_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x650004; +} + +static void +Opcode_mul_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x660004; +} + +static void +Opcode_mul_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x670004; +} + +static void +Opcode_mul_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x240004; +} + +static void +Opcode_mul_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x250004; +} + +static void +Opcode_mul_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x260004; +} + +static void +Opcode_mul_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270004; +} + +static void +Opcode_mula_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x780004; +} + +static void +Opcode_mula_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x790004; +} + +static void +Opcode_mula_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7a0004; +} + +static void +Opcode_mula_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7b0004; +} + +static void +Opcode_muls_aa_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7c0004; +} + +static void +Opcode_muls_aa_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7d0004; +} + +static void +Opcode_muls_aa_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7e0004; +} + +static void +Opcode_muls_aa_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7f0004; +} + +static void +Opcode_mula_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x380004; +} + +static void +Opcode_mula_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x390004; +} + +static void +Opcode_mula_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a0004; +} + +static void +Opcode_mula_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b0004; +} + +static void +Opcode_muls_ad_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3c0004; +} + +static void +Opcode_muls_ad_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3d0004; +} + +static void +Opcode_muls_ad_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e0004; +} + +static void +Opcode_muls_ad_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f0004; +} + +static void +Opcode_mula_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x680004; +} + +static void +Opcode_mula_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x690004; +} + +static void +Opcode_mula_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0004; +} + +static void +Opcode_mula_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0004; +} + +static void +Opcode_muls_da_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6c0004; +} + +static void +Opcode_muls_da_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0004; +} + +static void +Opcode_muls_da_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6e0004; +} + +static void +Opcode_muls_da_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6f0004; +} + +static void +Opcode_mula_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x280004; +} + +static void +Opcode_mula_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x290004; +} + +static void +Opcode_mula_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2a0004; +} + +static void +Opcode_mula_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2b0004; +} + +static void +Opcode_muls_dd_ll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2c0004; +} + +static void +Opcode_muls_dd_hl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2d0004; +} + +static void +Opcode_muls_dd_lh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2e0004; +} + +static void +Opcode_muls_dd_hh_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2f0004; +} + +static void +Opcode_mula_da_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580004; +} + +static void +Opcode_mula_da_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x480004; +} + +static void +Opcode_mula_da_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x590004; +} + +static void +Opcode_mula_da_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x490004; +} + +static void +Opcode_mula_da_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a0004; +} + +static void +Opcode_mula_da_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4a0004; +} + +static void +Opcode_mula_da_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b0004; +} + +static void +Opcode_mula_da_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4b0004; +} + +static void +Opcode_mula_dd_ll_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x180004; +} + +static void +Opcode_mula_dd_ll_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80004; +} + +static void +Opcode_mula_dd_hl_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x190004; +} + +static void +Opcode_mula_dd_hl_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90004; +} + +static void +Opcode_mula_dd_lh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a0004; +} + +static void +Opcode_mula_dd_lh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0004; +} + +static void +Opcode_mula_dd_hh_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b0004; +} + +static void +Opcode_mula_dd_hh_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb0004; +} + +static void +Opcode_lddec_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x900004; +} + +static void +Opcode_ldinc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x800004; +} + +static void +Opcode_rsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32000; +} + +static void +Opcode_wsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132000; +} + +static void +Opcode_xsr_m0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612000; +} + +static void +Opcode_rsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32100; +} + +static void +Opcode_wsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132100; +} + +static void +Opcode_xsr_m1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612100; +} + +static void +Opcode_rsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32200; +} + +static void +Opcode_wsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132200; +} + +static void +Opcode_xsr_m2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612200; +} + +static void +Opcode_rsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x32300; +} + +static void +Opcode_wsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x132300; +} + +static void +Opcode_xsr_m3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x612300; +} + +static void +Opcode_rsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31000; +} + +static void +Opcode_wsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131000; +} + +static void +Opcode_xsr_acclo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611000; +} + +static void +Opcode_rsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31100; +} + +static void +Opcode_wsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131100; +} + +static void +Opcode_xsr_acchi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x611100; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3010; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7000; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e200; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e200; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e300; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e400; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e400; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e400; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4000; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf02d; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39000; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139000; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619000; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a000; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a000; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a000; +} + +static void +Opcode_rsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39100; +} + +static void +Opcode_wsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x139100; +} + +static void +Opcode_xsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x619100; +} + +static void +Opcode_rsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a100; +} + +static void +Opcode_wsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13a100; +} + +static void +Opcode_xsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61a100; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38000; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138000; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618000; +} + +static void +Opcode_rsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38100; +} + +static void +Opcode_wsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x138100; +} + +static void +Opcode_xsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x618100; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36000; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136000; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616000; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e900; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e900; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e900; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ec00; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ec00; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ec00; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ed00; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ed00; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ed00; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36800; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136800; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616800; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e000; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1e010; +} + +static void +Opcode_wsr_mmid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135900; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3ea00; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13ea00; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61ea00; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f000; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f000; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f000; +} + +static void +Opcode_rsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f100; +} + +static void +Opcode_wsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f100; +} + +static void +Opcode_xsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f100; +} + +static void +Opcode_rsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3f200; +} + +static void +Opcode_wsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13f200; +} + +static void +Opcode_xsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61f200; +} + +static void +Opcode_ipf_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70c2; +} + +static void +Opcode_ihi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70e2; +} + +static void +Opcode_ipfl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70d2; +} + +static void +Opcode_ihu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270d2; +} + +static void +Opcode_iiu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x370d2; +} + +static void +Opcode_iii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70f2; +} + +static void +Opcode_lict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf10000; +} + +static void +Opcode_licw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf12000; +} + +static void +Opcode_sict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf11000; +} + +static void +Opcode_sicw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf13000; +} + +static void +Opcode_dhwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7042; +} + +static void +Opcode_dhwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7052; +} + +static void +Opcode_diwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x47082; +} + +static void +Opcode_diwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x57082; +} + +static void +Opcode_dhi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7062; +} + +static void +Opcode_dii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7072; +} + +static void +Opcode_dpfr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7002; +} + +static void +Opcode_dpfw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7012; +} + +static void +Opcode_dpfro_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7022; +} + +static void +Opcode_dpfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7032; +} + +static void +Opcode_dpfl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x7082; +} + +static void +Opcode_dhu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x27082; +} + +static void +Opcode_diu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x37082; +} + +static void +Opcode_sdct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf19000; +} + +static void +Opcode_ldct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf18000; +} + +static void +Opcode_wsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135300; +} + +static void +Opcode_rsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35300; +} + +static void +Opcode_xsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615300; +} + +static void +Opcode_rsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35a00; +} + +static void +Opcode_wsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135a00; +} + +static void +Opcode_xsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615a00; +} + +static void +Opcode_rsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35b00; +} + +static void +Opcode_wsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135b00; +} + +static void +Opcode_xsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615b00; +} + +static void +Opcode_rsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x35c00; +} + +static void +Opcode_wsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x135c00; +} + +static void +Opcode_xsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x615c00; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50c000; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50d000; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50b000; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50f000; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x50e000; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x504000; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505000; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x503000; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x507000; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x506000; +} + +static void +Opcode_ldpte_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1f000; +} + +static void +Opcode_hwwitlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x501000; +} + +static void +Opcode_hwwdtlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x509000; +} + +static void +Opcode_rsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3e000; +} + +static void +Opcode_wsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x13e000; +} + +static void +Opcode_xsr_cpenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x61e000; +} + +static void +Opcode_clamps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x330000; +} + +static void +Opcode_min_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x430000; +} + +static void +Opcode_max_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x530000; +} + +static void +Opcode_minu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x630000; +} + +static void +Opcode_maxu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x730000; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40e000; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40f000; +} + +static void +Opcode_sext_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230000; +} + +static void +Opcode_l32ai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb002; +} + +static void +Opcode_s32ri_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf002; +} + +static void +Opcode_s32c1i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe002; +} + +static void +Opcode_rsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30c00; +} + +static void +Opcode_wsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130c00; +} + +static void +Opcode_xsr_scompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x610c00; +} + +static void +Opcode_rsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x36300; +} + +static void +Opcode_wsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x136300; +} + +static void +Opcode_xsr_atomctl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x616300; +} + +static void +Opcode_quou_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc20000; +} + +static void +Opcode_quos_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd20000; +} + +static void +Opcode_remu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe20000; +} + +static void +Opcode_rems_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf20000; +} + +static void +Opcode_rer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x406000; +} + +static void +Opcode_wer_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x407000; +} + +static void +Opcode_rur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe30e60; +} + +static void +Opcode_wur_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf3e600; +} + +static void +Opcode_read_impwire_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe0000; +} + +static void +Opcode_setb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1000; +} + +static void +Opcode_clrb_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1200; +} + +static void +Opcode_wrmsk_expstate_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe2000; +} + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { + Opcode_call12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { + Opcode_call8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { + Opcode_call4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { + Opcode_callx12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { + Opcode_callx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { + Opcode_callx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { + Opcode_entry_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { + Opcode_movsp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { + Opcode_rotw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { + Opcode_retw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { + 0, 0, Opcode_retw_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { + Opcode_rfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { + Opcode_rfwu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { + Opcode_l32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { + Opcode_s32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { + Opcode_rsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { + Opcode_wsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { + Opcode_xsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { + Opcode_rsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { + Opcode_wsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { + Opcode_xsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_threadptr_encode_fns[] = { + Opcode_rur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_threadptr_encode_fns[] = { + Opcode_wur_threadptr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { + Opcode_loop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { + Opcode_loopnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { + Opcode_loopgtz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { + Opcode_rsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { + Opcode_wsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { + Opcode_xsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { + Opcode_rsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { + Opcode_wsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { + Opcode_xsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { + Opcode_rsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { + Opcode_wsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { + Opcode_xsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_176_encode_fns[] = { + Opcode_wsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc4_encode_fns[] = { + Opcode_rsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc4_encode_fns[] = { + Opcode_wsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc4_encode_fns[] = { + Opcode_xsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave4_encode_fns[] = { + Opcode_rsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave4_encode_fns[] = { + Opcode_wsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave4_encode_fns[] = { + Opcode_xsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc5_encode_fns[] = { + Opcode_rsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc5_encode_fns[] = { + Opcode_wsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc5_encode_fns[] = { + Opcode_xsr_epc5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave5_encode_fns[] = { + Opcode_rsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave5_encode_fns[] = { + Opcode_wsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave5_encode_fns[] = { + Opcode_xsr_excsave5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc6_encode_fns[] = { + Opcode_rsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc6_encode_fns[] = { + Opcode_wsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc6_encode_fns[] = { + Opcode_xsr_epc6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave6_encode_fns[] = { + Opcode_rsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave6_encode_fns[] = { + Opcode_wsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave6_encode_fns[] = { + Opcode_xsr_excsave6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc7_encode_fns[] = { + Opcode_rsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc7_encode_fns[] = { + Opcode_wsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc7_encode_fns[] = { + Opcode_xsr_epc7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave7_encode_fns[] = { + Opcode_rsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave7_encode_fns[] = { + Opcode_wsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave7_encode_fns[] = { + Opcode_xsr_excsave7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps4_encode_fns[] = { + Opcode_rsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps4_encode_fns[] = { + Opcode_wsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps4_encode_fns[] = { + Opcode_xsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps5_encode_fns[] = { + Opcode_rsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps5_encode_fns[] = { + Opcode_wsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps5_encode_fns[] = { + Opcode_xsr_eps5_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps6_encode_fns[] = { + Opcode_rsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps6_encode_fns[] = { + Opcode_wsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps6_encode_fns[] = { + Opcode_xsr_eps6_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps7_encode_fns[] = { + Opcode_rsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps7_encode_fns[] = { + Opcode_wsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps7_encode_fns[] = { + Opcode_xsr_eps7_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { + Opcode_rsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { + Opcode_wsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { + Opcode_xsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { + Opcode_rsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { + Opcode_wsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { + Opcode_xsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_vecbase_encode_fns[] = { + Opcode_rsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_vecbase_encode_fns[] = { + Opcode_wsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_vecbase_encode_fns[] = { + Opcode_xsr_vecbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16u_encode_fns[] = { + Opcode_mul16u_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul16s_encode_fns[] = { + Opcode_mul16s_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mull_encode_fns[] = { + Opcode_mull_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_ll_encode_fns[] = { + Opcode_mul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hl_encode_fns[] = { + Opcode_mul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_lh_encode_fns[] = { + Opcode_mul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_aa_hh_encode_fns[] = { + Opcode_mul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_ll_encode_fns[] = { + Opcode_umul_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hl_encode_fns[] = { + Opcode_umul_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_lh_encode_fns[] = { + Opcode_umul_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_umul_aa_hh_encode_fns[] = { + Opcode_umul_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_ll_encode_fns[] = { + Opcode_mul_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hl_encode_fns[] = { + Opcode_mul_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_lh_encode_fns[] = { + Opcode_mul_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_ad_hh_encode_fns[] = { + Opcode_mul_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_ll_encode_fns[] = { + Opcode_mul_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hl_encode_fns[] = { + Opcode_mul_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_lh_encode_fns[] = { + Opcode_mul_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_da_hh_encode_fns[] = { + Opcode_mul_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_ll_encode_fns[] = { + Opcode_mul_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hl_encode_fns[] = { + Opcode_mul_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_lh_encode_fns[] = { + Opcode_mul_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mul_dd_hh_encode_fns[] = { + Opcode_mul_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_ll_encode_fns[] = { + Opcode_mula_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hl_encode_fns[] = { + Opcode_mula_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_lh_encode_fns[] = { + Opcode_mula_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_aa_hh_encode_fns[] = { + Opcode_mula_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_ll_encode_fns[] = { + Opcode_muls_aa_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hl_encode_fns[] = { + Opcode_muls_aa_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_lh_encode_fns[] = { + Opcode_muls_aa_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_aa_hh_encode_fns[] = { + Opcode_muls_aa_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_ll_encode_fns[] = { + Opcode_mula_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hl_encode_fns[] = { + Opcode_mula_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_lh_encode_fns[] = { + Opcode_mula_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_ad_hh_encode_fns[] = { + Opcode_mula_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_ll_encode_fns[] = { + Opcode_muls_ad_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hl_encode_fns[] = { + Opcode_muls_ad_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_lh_encode_fns[] = { + Opcode_muls_ad_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_ad_hh_encode_fns[] = { + Opcode_muls_ad_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_encode_fns[] = { + Opcode_mula_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_encode_fns[] = { + Opcode_mula_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_encode_fns[] = { + Opcode_mula_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_encode_fns[] = { + Opcode_mula_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_ll_encode_fns[] = { + Opcode_muls_da_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hl_encode_fns[] = { + Opcode_muls_da_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_lh_encode_fns[] = { + Opcode_muls_da_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_da_hh_encode_fns[] = { + Opcode_muls_da_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_encode_fns[] = { + Opcode_mula_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_encode_fns[] = { + Opcode_mula_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_encode_fns[] = { + Opcode_mula_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_encode_fns[] = { + Opcode_mula_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_ll_encode_fns[] = { + Opcode_muls_dd_ll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hl_encode_fns[] = { + Opcode_muls_dd_hl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_lh_encode_fns[] = { + Opcode_muls_dd_lh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_muls_dd_hh_encode_fns[] = { + Opcode_muls_dd_hh_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_lddec_encode_fns[] = { + Opcode_mula_da_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_ll_ldinc_encode_fns[] = { + Opcode_mula_da_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_lddec_encode_fns[] = { + Opcode_mula_da_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hl_ldinc_encode_fns[] = { + Opcode_mula_da_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_lddec_encode_fns[] = { + Opcode_mula_da_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_lh_ldinc_encode_fns[] = { + Opcode_mula_da_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_lddec_encode_fns[] = { + Opcode_mula_da_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_da_hh_ldinc_encode_fns[] = { + Opcode_mula_da_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_lddec_encode_fns[] = { + Opcode_mula_dd_ll_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_ll_ldinc_encode_fns[] = { + Opcode_mula_dd_ll_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_lddec_encode_fns[] = { + Opcode_mula_dd_hl_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hl_ldinc_encode_fns[] = { + Opcode_mula_dd_hl_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_lddec_encode_fns[] = { + Opcode_mula_dd_lh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_lh_ldinc_encode_fns[] = { + Opcode_mula_dd_lh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_lddec_encode_fns[] = { + Opcode_mula_dd_hh_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mula_dd_hh_ldinc_encode_fns[] = { + Opcode_mula_dd_hh_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lddec_encode_fns[] = { + Opcode_lddec_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldinc_encode_fns[] = { + Opcode_ldinc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m0_encode_fns[] = { + Opcode_rsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m0_encode_fns[] = { + Opcode_wsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m0_encode_fns[] = { + Opcode_xsr_m0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m1_encode_fns[] = { + Opcode_rsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m1_encode_fns[] = { + Opcode_wsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m1_encode_fns[] = { + Opcode_xsr_m1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m2_encode_fns[] = { + Opcode_rsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m2_encode_fns[] = { + Opcode_wsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m2_encode_fns[] = { + Opcode_xsr_m2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_m3_encode_fns[] = { + Opcode_rsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_m3_encode_fns[] = { + Opcode_wsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_m3_encode_fns[] = { + Opcode_xsr_m3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acclo_encode_fns[] = { + Opcode_rsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acclo_encode_fns[] = { + Opcode_wsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acclo_encode_fns[] = { + Opcode_xsr_acclo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_acchi_encode_fns[] = { + Opcode_rsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_acchi_encode_fns[] = { + Opcode_wsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_acchi_encode_fns[] = { + Opcode_xsr_acchi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka1_encode_fns[] = { + Opcode_rsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka1_encode_fns[] = { + Opcode_wsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka1_encode_fns[] = { + Opcode_xsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc1_encode_fns[] = { + Opcode_rsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc1_encode_fns[] = { + Opcode_wsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc1_encode_fns[] = { + Opcode_xsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka1_encode_fns[] = { + Opcode_rsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka1_encode_fns[] = { + Opcode_wsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka1_encode_fns[] = { + Opcode_xsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_mmid_encode_fns[] = { + Opcode_wsr_mmid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { + Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { + Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { + Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare2_encode_fns[] = { + Opcode_rsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare2_encode_fns[] = { + Opcode_wsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare2_encode_fns[] = { + Opcode_xsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { + Opcode_ipf_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { + Opcode_ihi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ipfl_encode_fns[] = { + Opcode_ipfl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ihu_encode_fns[] = { + Opcode_ihu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iiu_encode_fns[] = { + Opcode_iiu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { + Opcode_iii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { + Opcode_lict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { + Opcode_licw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { + Opcode_sict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { + Opcode_sicw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { + Opcode_dhwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { + Opcode_dhwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { + Opcode_diwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { + Opcode_diwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { + Opcode_dhi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { + Opcode_dii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { + Opcode_dpfr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { + Opcode_dpfw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { + Opcode_dpfro_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { + Opcode_dpfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfl_encode_fns[] = { + Opcode_dpfl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhu_encode_fns[] = { + Opcode_dhu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diu_encode_fns[] = { + Opcode_diu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { + Opcode_sdct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { + Opcode_ldct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ptevaddr_encode_fns[] = { + Opcode_wsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ptevaddr_encode_fns[] = { + Opcode_rsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ptevaddr_encode_fns[] = { + Opcode_xsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_rasid_encode_fns[] = { + Opcode_rsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_rasid_encode_fns[] = { + Opcode_wsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_rasid_encode_fns[] = { + Opcode_xsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_itlbcfg_encode_fns[] = { + Opcode_rsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_itlbcfg_encode_fns[] = { + Opcode_wsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_itlbcfg_encode_fns[] = { + Opcode_xsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dtlbcfg_encode_fns[] = { + Opcode_rsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dtlbcfg_encode_fns[] = { + Opcode_wsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dtlbcfg_encode_fns[] = { + Opcode_xsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldpte_encode_fns[] = { + Opcode_ldpte_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwitlba_encode_fns[] = { + Opcode_hwwitlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwdtlba_encode_fns[] = { + Opcode_hwwdtlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_cpenable_encode_fns[] = { + Opcode_rsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_cpenable_encode_fns[] = { + Opcode_wsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_cpenable_encode_fns[] = { + Opcode_xsr_cpenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clamps_encode_fns[] = { + Opcode_clamps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_min_encode_fns[] = { + Opcode_min_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_max_encode_fns[] = { + Opcode_max_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_minu_encode_fns[] = { + Opcode_minu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_maxu_encode_fns[] = { + Opcode_maxu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sext_encode_fns[] = { + Opcode_sext_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32ai_encode_fns[] = { + Opcode_l32ai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32ri_encode_fns[] = { + Opcode_s32ri_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32c1i_encode_fns[] = { + Opcode_s32c1i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_scompare1_encode_fns[] = { + Opcode_rsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_scompare1_encode_fns[] = { + Opcode_wsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_scompare1_encode_fns[] = { + Opcode_xsr_scompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_atomctl_encode_fns[] = { + Opcode_rsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_atomctl_encode_fns[] = { + Opcode_wsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_atomctl_encode_fns[] = { + Opcode_xsr_atomctl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quou_encode_fns[] = { + Opcode_quou_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_quos_encode_fns[] = { + Opcode_quos_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_remu_encode_fns[] = { + Opcode_remu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rems_encode_fns[] = { + Opcode_rems_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rer_encode_fns[] = { + Opcode_rer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wer_encode_fns[] = { + Opcode_wer_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rur_expstate_encode_fns[] = { + Opcode_rur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wur_expstate_encode_fns[] = { + Opcode_wur_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_read_impwire_encode_fns[] = { + Opcode_read_impwire_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_setb_expstate_encode_fns[] = { + Opcode_setb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_clrb_expstate_encode_fns[] = { + Opcode_clrb_expstate_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wrmsk_expstate_encode_fns[] = { + Opcode_wrmsk_expstate_Slot_inst_encode, 0, 0 +}; + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", ICLASS_xt_iclass_excw, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", ICLASS_xt_iclass_rfe, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", ICLASS_xt_iclass_rfde, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", ICLASS_xt_iclass_syscall, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", ICLASS_xt_iclass_simcall, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "call12", ICLASS_xt_iclass_call12, + XTENSA_OPCODE_IS_CALL, + Opcode_call12_encode_fns, 0, 0 }, + { "call8", ICLASS_xt_iclass_call8, + XTENSA_OPCODE_IS_CALL, + Opcode_call8_encode_fns, 0, 0 }, + { "call4", ICLASS_xt_iclass_call4, + XTENSA_OPCODE_IS_CALL, + Opcode_call4_encode_fns, 0, 0 }, + { "callx12", ICLASS_xt_iclass_callx12, + XTENSA_OPCODE_IS_CALL, + Opcode_callx12_encode_fns, 0, 0 }, + { "callx8", ICLASS_xt_iclass_callx8, + XTENSA_OPCODE_IS_CALL, + Opcode_callx8_encode_fns, 0, 0 }, + { "callx4", ICLASS_xt_iclass_callx4, + XTENSA_OPCODE_IS_CALL, + Opcode_callx4_encode_fns, 0, 0 }, + { "entry", ICLASS_xt_iclass_entry, + 0, + Opcode_entry_encode_fns, 0, 0 }, + { "movsp", ICLASS_xt_iclass_movsp, + 0, + Opcode_movsp_encode_fns, 0, 0 }, + { "rotw", ICLASS_xt_iclass_rotw, + 0, + Opcode_rotw_encode_fns, 0, 0 }, + { "retw", ICLASS_xt_iclass_retw, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_encode_fns, 0, 0 }, + { "retw.n", ICLASS_xt_iclass_retw, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_n_encode_fns, 0, 0 }, + { "rfwo", ICLASS_xt_iclass_rfwou, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwo_encode_fns, 0, 0 }, + { "rfwu", ICLASS_xt_iclass_rfwou, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwu_encode_fns, 0, 0 }, + { "l32e", ICLASS_xt_iclass_l32e, + 0, + Opcode_l32e_encode_fns, 0, 0 }, + { "s32e", ICLASS_xt_iclass_s32e, + 0, + Opcode_s32e_encode_fns, 0, 0 }, + { "rsr.windowbase", ICLASS_xt_iclass_rsr_windowbase, + 0, + Opcode_rsr_windowbase_encode_fns, 0, 0 }, + { "wsr.windowbase", ICLASS_xt_iclass_wsr_windowbase, + 0, + Opcode_wsr_windowbase_encode_fns, 0, 0 }, + { "xsr.windowbase", ICLASS_xt_iclass_xsr_windowbase, + 0, + Opcode_xsr_windowbase_encode_fns, 0, 0 }, + { "rsr.windowstart", ICLASS_xt_iclass_rsr_windowstart, + 0, + Opcode_rsr_windowstart_encode_fns, 0, 0 }, + { "wsr.windowstart", ICLASS_xt_iclass_wsr_windowstart, + 0, + Opcode_wsr_windowstart_encode_fns, 0, 0 }, + { "xsr.windowstart", ICLASS_xt_iclass_xsr_windowstart, + 0, + Opcode_xsr_windowstart_encode_fns, 0, 0 }, + { "add.n", ICLASS_xt_iclass_add_n, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", ICLASS_xt_iclass_addi_n, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", ICLASS_xt_iclass_bz6, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", ICLASS_xt_iclass_ill_n, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", ICLASS_xt_iclass_loadi4, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", ICLASS_xt_iclass_mov_n, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", ICLASS_xt_iclass_movi_n, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", ICLASS_xt_iclass_nopn, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", ICLASS_xt_iclass_retn, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", ICLASS_xt_iclass_storei4, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "rur.threadptr", ICLASS_rur_threadptr, + 0, + Opcode_rur_threadptr_encode_fns, 0, 0 }, + { "wur.threadptr", ICLASS_wur_threadptr, + 0, + Opcode_wur_threadptr_encode_fns, 0, 0 }, + { "addi", ICLASS_xt_iclass_addi, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", ICLASS_xt_iclass_addmi, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", ICLASS_xt_iclass_addsub, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", ICLASS_xt_iclass_addsub, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", ICLASS_xt_iclass_addsub, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", ICLASS_xt_iclass_bit, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", ICLASS_xt_iclass_bit, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", ICLASS_xt_iclass_bit, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", ICLASS_xt_iclass_bsi8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", ICLASS_xt_iclass_bsi8b, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", ICLASS_xt_iclass_bsi8u, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", ICLASS_xt_iclass_bst8, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", ICLASS_xt_iclass_bsz12, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", ICLASS_xt_iclass_call0, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", ICLASS_xt_iclass_callx0, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", ICLASS_xt_iclass_exti, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", ICLASS_xt_iclass_ill, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", ICLASS_xt_iclass_jump, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", ICLASS_xt_iclass_jumpx, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", ICLASS_xt_iclass_l16ui, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", ICLASS_xt_iclass_l16si, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", ICLASS_xt_iclass_l32i, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", ICLASS_xt_iclass_l32r, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", ICLASS_xt_iclass_l8i, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "loop", ICLASS_xt_iclass_loop, + XTENSA_OPCODE_IS_LOOP, + Opcode_loop_encode_fns, 0, 0 }, + { "loopnez", ICLASS_xt_iclass_loopz, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopnez_encode_fns, 0, 0 }, + { "loopgtz", ICLASS_xt_iclass_loopz, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopgtz_encode_fns, 0, 0 }, + { "movi", ICLASS_xt_iclass_movi, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", ICLASS_xt_iclass_movz, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", ICLASS_xt_iclass_movz, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", ICLASS_xt_iclass_movz, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", ICLASS_xt_iclass_movz, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", ICLASS_xt_iclass_neg, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", ICLASS_xt_iclass_neg, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", ICLASS_xt_iclass_nop, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", ICLASS_xt_iclass_return, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", ICLASS_xt_iclass_s16i, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", ICLASS_xt_iclass_s32i, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", ICLASS_xt_iclass_s8i, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", ICLASS_xt_iclass_sar, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", ICLASS_xt_iclass_sar, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", ICLASS_xt_iclass_sar, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", ICLASS_xt_iclass_sari, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", ICLASS_xt_iclass_shifts, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", ICLASS_xt_iclass_shiftst, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", ICLASS_xt_iclass_shiftt, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", ICLASS_xt_iclass_shiftt, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", ICLASS_xt_iclass_slli, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", ICLASS_xt_iclass_srai, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", ICLASS_xt_iclass_srli, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", ICLASS_xt_iclass_memw, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", ICLASS_xt_iclass_extw, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", ICLASS_xt_iclass_isync, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", ICLASS_xt_iclass_sync, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", ICLASS_xt_iclass_sync, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", ICLASS_xt_iclass_sync, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", ICLASS_xt_iclass_rsil, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.lend", ICLASS_xt_iclass_rsr_lend, + 0, + Opcode_rsr_lend_encode_fns, 0, 0 }, + { "wsr.lend", ICLASS_xt_iclass_wsr_lend, + 0, + Opcode_wsr_lend_encode_fns, 0, 0 }, + { "xsr.lend", ICLASS_xt_iclass_xsr_lend, + 0, + Opcode_xsr_lend_encode_fns, 0, 0 }, + { "rsr.lcount", ICLASS_xt_iclass_rsr_lcount, + 0, + Opcode_rsr_lcount_encode_fns, 0, 0 }, + { "wsr.lcount", ICLASS_xt_iclass_wsr_lcount, + 0, + Opcode_wsr_lcount_encode_fns, 0, 0 }, + { "xsr.lcount", ICLASS_xt_iclass_xsr_lcount, + 0, + Opcode_xsr_lcount_encode_fns, 0, 0 }, + { "rsr.lbeg", ICLASS_xt_iclass_rsr_lbeg, + 0, + Opcode_rsr_lbeg_encode_fns, 0, 0 }, + { "wsr.lbeg", ICLASS_xt_iclass_wsr_lbeg, + 0, + Opcode_wsr_lbeg_encode_fns, 0, 0 }, + { "xsr.lbeg", ICLASS_xt_iclass_xsr_lbeg, + 0, + Opcode_xsr_lbeg_encode_fns, 0, 0 }, + { "rsr.sar", ICLASS_xt_iclass_rsr_sar, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", ICLASS_xt_iclass_wsr_sar, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", ICLASS_xt_iclass_xsr_sar, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", ICLASS_xt_iclass_rsr_litbase, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", ICLASS_xt_iclass_wsr_litbase, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", ICLASS_xt_iclass_xsr_litbase, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", ICLASS_xt_iclass_rsr_176, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "wsr.176", ICLASS_xt_iclass_wsr_176, + 0, + Opcode_wsr_176_encode_fns, 0, 0 }, + { "rsr.208", ICLASS_xt_iclass_rsr_208, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", ICLASS_xt_iclass_rsr_ps, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", ICLASS_xt_iclass_wsr_ps, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", ICLASS_xt_iclass_xsr_ps, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", ICLASS_xt_iclass_rsr_epc1, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", ICLASS_xt_iclass_wsr_epc1, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", ICLASS_xt_iclass_xsr_epc1, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", ICLASS_xt_iclass_rsr_excsave1, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", ICLASS_xt_iclass_wsr_excsave1, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", ICLASS_xt_iclass_xsr_excsave1, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", ICLASS_xt_iclass_rsr_epc2, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", ICLASS_xt_iclass_wsr_epc2, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", ICLASS_xt_iclass_xsr_epc2, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", ICLASS_xt_iclass_rsr_excsave2, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", ICLASS_xt_iclass_wsr_excsave2, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", ICLASS_xt_iclass_xsr_excsave2, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", ICLASS_xt_iclass_rsr_epc3, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", ICLASS_xt_iclass_wsr_epc3, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", ICLASS_xt_iclass_xsr_epc3, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", ICLASS_xt_iclass_rsr_excsave3, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", ICLASS_xt_iclass_wsr_excsave3, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", ICLASS_xt_iclass_xsr_excsave3, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.epc4", ICLASS_xt_iclass_rsr_epc4, + 0, + Opcode_rsr_epc4_encode_fns, 0, 0 }, + { "wsr.epc4", ICLASS_xt_iclass_wsr_epc4, + 0, + Opcode_wsr_epc4_encode_fns, 0, 0 }, + { "xsr.epc4", ICLASS_xt_iclass_xsr_epc4, + 0, + Opcode_xsr_epc4_encode_fns, 0, 0 }, + { "rsr.excsave4", ICLASS_xt_iclass_rsr_excsave4, + 0, + Opcode_rsr_excsave4_encode_fns, 0, 0 }, + { "wsr.excsave4", ICLASS_xt_iclass_wsr_excsave4, + 0, + Opcode_wsr_excsave4_encode_fns, 0, 0 }, + { "xsr.excsave4", ICLASS_xt_iclass_xsr_excsave4, + 0, + Opcode_xsr_excsave4_encode_fns, 0, 0 }, + { "rsr.epc5", ICLASS_xt_iclass_rsr_epc5, + 0, + Opcode_rsr_epc5_encode_fns, 0, 0 }, + { "wsr.epc5", ICLASS_xt_iclass_wsr_epc5, + 0, + Opcode_wsr_epc5_encode_fns, 0, 0 }, + { "xsr.epc5", ICLASS_xt_iclass_xsr_epc5, + 0, + Opcode_xsr_epc5_encode_fns, 0, 0 }, + { "rsr.excsave5", ICLASS_xt_iclass_rsr_excsave5, + 0, + Opcode_rsr_excsave5_encode_fns, 0, 0 }, + { "wsr.excsave5", ICLASS_xt_iclass_wsr_excsave5, + 0, + Opcode_wsr_excsave5_encode_fns, 0, 0 }, + { "xsr.excsave5", ICLASS_xt_iclass_xsr_excsave5, + 0, + Opcode_xsr_excsave5_encode_fns, 0, 0 }, + { "rsr.epc6", ICLASS_xt_iclass_rsr_epc6, + 0, + Opcode_rsr_epc6_encode_fns, 0, 0 }, + { "wsr.epc6", ICLASS_xt_iclass_wsr_epc6, + 0, + Opcode_wsr_epc6_encode_fns, 0, 0 }, + { "xsr.epc6", ICLASS_xt_iclass_xsr_epc6, + 0, + Opcode_xsr_epc6_encode_fns, 0, 0 }, + { "rsr.excsave6", ICLASS_xt_iclass_rsr_excsave6, + 0, + Opcode_rsr_excsave6_encode_fns, 0, 0 }, + { "wsr.excsave6", ICLASS_xt_iclass_wsr_excsave6, + 0, + Opcode_wsr_excsave6_encode_fns, 0, 0 }, + { "xsr.excsave6", ICLASS_xt_iclass_xsr_excsave6, + 0, + Opcode_xsr_excsave6_encode_fns, 0, 0 }, + { "rsr.epc7", ICLASS_xt_iclass_rsr_epc7, + 0, + Opcode_rsr_epc7_encode_fns, 0, 0 }, + { "wsr.epc7", ICLASS_xt_iclass_wsr_epc7, + 0, + Opcode_wsr_epc7_encode_fns, 0, 0 }, + { "xsr.epc7", ICLASS_xt_iclass_xsr_epc7, + 0, + Opcode_xsr_epc7_encode_fns, 0, 0 }, + { "rsr.excsave7", ICLASS_xt_iclass_rsr_excsave7, + 0, + Opcode_rsr_excsave7_encode_fns, 0, 0 }, + { "wsr.excsave7", ICLASS_xt_iclass_wsr_excsave7, + 0, + Opcode_wsr_excsave7_encode_fns, 0, 0 }, + { "xsr.excsave7", ICLASS_xt_iclass_xsr_excsave7, + 0, + Opcode_xsr_excsave7_encode_fns, 0, 0 }, + { "rsr.eps2", ICLASS_xt_iclass_rsr_eps2, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", ICLASS_xt_iclass_wsr_eps2, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", ICLASS_xt_iclass_xsr_eps2, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", ICLASS_xt_iclass_rsr_eps3, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", ICLASS_xt_iclass_wsr_eps3, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", ICLASS_xt_iclass_xsr_eps3, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.eps4", ICLASS_xt_iclass_rsr_eps4, + 0, + Opcode_rsr_eps4_encode_fns, 0, 0 }, + { "wsr.eps4", ICLASS_xt_iclass_wsr_eps4, + 0, + Opcode_wsr_eps4_encode_fns, 0, 0 }, + { "xsr.eps4", ICLASS_xt_iclass_xsr_eps4, + 0, + Opcode_xsr_eps4_encode_fns, 0, 0 }, + { "rsr.eps5", ICLASS_xt_iclass_rsr_eps5, + 0, + Opcode_rsr_eps5_encode_fns, 0, 0 }, + { "wsr.eps5", ICLASS_xt_iclass_wsr_eps5, + 0, + Opcode_wsr_eps5_encode_fns, 0, 0 }, + { "xsr.eps5", ICLASS_xt_iclass_xsr_eps5, + 0, + Opcode_xsr_eps5_encode_fns, 0, 0 }, + { "rsr.eps6", ICLASS_xt_iclass_rsr_eps6, + 0, + Opcode_rsr_eps6_encode_fns, 0, 0 }, + { "wsr.eps6", ICLASS_xt_iclass_wsr_eps6, + 0, + Opcode_wsr_eps6_encode_fns, 0, 0 }, + { "xsr.eps6", ICLASS_xt_iclass_xsr_eps6, + 0, + Opcode_xsr_eps6_encode_fns, 0, 0 }, + { "rsr.eps7", ICLASS_xt_iclass_rsr_eps7, + 0, + Opcode_rsr_eps7_encode_fns, 0, 0 }, + { "wsr.eps7", ICLASS_xt_iclass_wsr_eps7, + 0, + Opcode_wsr_eps7_encode_fns, 0, 0 }, + { "xsr.eps7", ICLASS_xt_iclass_xsr_eps7, + 0, + Opcode_xsr_eps7_encode_fns, 0, 0 }, + { "rsr.excvaddr", ICLASS_xt_iclass_rsr_excvaddr, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", ICLASS_xt_iclass_wsr_excvaddr, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", ICLASS_xt_iclass_xsr_excvaddr, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", ICLASS_xt_iclass_rsr_depc, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", ICLASS_xt_iclass_wsr_depc, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", ICLASS_xt_iclass_xsr_depc, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", ICLASS_xt_iclass_rsr_exccause, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", ICLASS_xt_iclass_wsr_exccause, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", ICLASS_xt_iclass_xsr_exccause, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.misc0", ICLASS_xt_iclass_rsr_misc0, + 0, + Opcode_rsr_misc0_encode_fns, 0, 0 }, + { "wsr.misc0", ICLASS_xt_iclass_wsr_misc0, + 0, + Opcode_wsr_misc0_encode_fns, 0, 0 }, + { "xsr.misc0", ICLASS_xt_iclass_xsr_misc0, + 0, + Opcode_xsr_misc0_encode_fns, 0, 0 }, + { "rsr.misc1", ICLASS_xt_iclass_rsr_misc1, + 0, + Opcode_rsr_misc1_encode_fns, 0, 0 }, + { "wsr.misc1", ICLASS_xt_iclass_wsr_misc1, + 0, + Opcode_wsr_misc1_encode_fns, 0, 0 }, + { "xsr.misc1", ICLASS_xt_iclass_xsr_misc1, + 0, + Opcode_xsr_misc1_encode_fns, 0, 0 }, + { "rsr.prid", ICLASS_xt_iclass_rsr_prid, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rsr.vecbase", ICLASS_xt_iclass_rsr_vecbase, + 0, + Opcode_rsr_vecbase_encode_fns, 0, 0 }, + { "wsr.vecbase", ICLASS_xt_iclass_wsr_vecbase, + 0, + Opcode_wsr_vecbase_encode_fns, 0, 0 }, + { "xsr.vecbase", ICLASS_xt_iclass_xsr_vecbase, + 0, + Opcode_xsr_vecbase_encode_fns, 0, 0 }, + { "mul16u", ICLASS_xt_mul16, + 0, + Opcode_mul16u_encode_fns, 0, 0 }, + { "mul16s", ICLASS_xt_mul16, + 0, + Opcode_mul16s_encode_fns, 0, 0 }, + { "mull", ICLASS_xt_mul32, + 0, + Opcode_mull_encode_fns, 0, 0 }, + { "mul.aa.ll", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_ll_encode_fns, 0, 0 }, + { "mul.aa.hl", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_hl_encode_fns, 0, 0 }, + { "mul.aa.lh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_lh_encode_fns, 0, 0 }, + { "mul.aa.hh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_mul_aa_hh_encode_fns, 0, 0 }, + { "umul.aa.ll", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_ll_encode_fns, 0, 0 }, + { "umul.aa.hl", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_hl_encode_fns, 0, 0 }, + { "umul.aa.lh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_lh_encode_fns, 0, 0 }, + { "umul.aa.hh", ICLASS_xt_iclass_mac16_aa, + 0, + Opcode_umul_aa_hh_encode_fns, 0, 0 }, + { "mul.ad.ll", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_ll_encode_fns, 0, 0 }, + { "mul.ad.hl", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_hl_encode_fns, 0, 0 }, + { "mul.ad.lh", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_lh_encode_fns, 0, 0 }, + { "mul.ad.hh", ICLASS_xt_iclass_mac16_ad, + 0, + Opcode_mul_ad_hh_encode_fns, 0, 0 }, + { "mul.da.ll", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_ll_encode_fns, 0, 0 }, + { "mul.da.hl", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_hl_encode_fns, 0, 0 }, + { "mul.da.lh", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_lh_encode_fns, 0, 0 }, + { "mul.da.hh", ICLASS_xt_iclass_mac16_da, + 0, + Opcode_mul_da_hh_encode_fns, 0, 0 }, + { "mul.dd.ll", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_ll_encode_fns, 0, 0 }, + { "mul.dd.hl", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_hl_encode_fns, 0, 0 }, + { "mul.dd.lh", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_lh_encode_fns, 0, 0 }, + { "mul.dd.hh", ICLASS_xt_iclass_mac16_dd, + 0, + Opcode_mul_dd_hh_encode_fns, 0, 0 }, + { "mula.aa.ll", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_ll_encode_fns, 0, 0 }, + { "mula.aa.hl", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_hl_encode_fns, 0, 0 }, + { "mula.aa.lh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_lh_encode_fns, 0, 0 }, + { "mula.aa.hh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_mula_aa_hh_encode_fns, 0, 0 }, + { "muls.aa.ll", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_ll_encode_fns, 0, 0 }, + { "muls.aa.hl", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_hl_encode_fns, 0, 0 }, + { "muls.aa.lh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_lh_encode_fns, 0, 0 }, + { "muls.aa.hh", ICLASS_xt_iclass_mac16a_aa, + 0, + Opcode_muls_aa_hh_encode_fns, 0, 0 }, + { "mula.ad.ll", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_ll_encode_fns, 0, 0 }, + { "mula.ad.hl", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_hl_encode_fns, 0, 0 }, + { "mula.ad.lh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_lh_encode_fns, 0, 0 }, + { "mula.ad.hh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_mula_ad_hh_encode_fns, 0, 0 }, + { "muls.ad.ll", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_ll_encode_fns, 0, 0 }, + { "muls.ad.hl", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_hl_encode_fns, 0, 0 }, + { "muls.ad.lh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_lh_encode_fns, 0, 0 }, + { "muls.ad.hh", ICLASS_xt_iclass_mac16a_ad, + 0, + Opcode_muls_ad_hh_encode_fns, 0, 0 }, + { "mula.da.ll", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_ll_encode_fns, 0, 0 }, + { "mula.da.hl", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_hl_encode_fns, 0, 0 }, + { "mula.da.lh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_lh_encode_fns, 0, 0 }, + { "mula.da.hh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_mula_da_hh_encode_fns, 0, 0 }, + { "muls.da.ll", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_ll_encode_fns, 0, 0 }, + { "muls.da.hl", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_hl_encode_fns, 0, 0 }, + { "muls.da.lh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_lh_encode_fns, 0, 0 }, + { "muls.da.hh", ICLASS_xt_iclass_mac16a_da, + 0, + Opcode_muls_da_hh_encode_fns, 0, 0 }, + { "mula.dd.ll", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_ll_encode_fns, 0, 0 }, + { "mula.dd.hl", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_hl_encode_fns, 0, 0 }, + { "mula.dd.lh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_lh_encode_fns, 0, 0 }, + { "mula.dd.hh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_mula_dd_hh_encode_fns, 0, 0 }, + { "muls.dd.ll", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_ll_encode_fns, 0, 0 }, + { "muls.dd.hl", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_hl_encode_fns, 0, 0 }, + { "muls.dd.lh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_lh_encode_fns, 0, 0 }, + { "muls.dd.hh", ICLASS_xt_iclass_mac16a_dd, + 0, + Opcode_muls_dd_hh_encode_fns, 0, 0 }, + { "mula.da.ll.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_ll_lddec_encode_fns, 0, 0 }, + { "mula.da.ll.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_ll_ldinc_encode_fns, 0, 0 }, + { "mula.da.hl.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hl_lddec_encode_fns, 0, 0 }, + { "mula.da.hl.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hl_ldinc_encode_fns, 0, 0 }, + { "mula.da.lh.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_lh_lddec_encode_fns, 0, 0 }, + { "mula.da.lh.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_lh_ldinc_encode_fns, 0, 0 }, + { "mula.da.hh.lddec", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hh_lddec_encode_fns, 0, 0 }, + { "mula.da.hh.ldinc", ICLASS_xt_iclass_mac16al_da, + 0, + Opcode_mula_da_hh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.ll.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_ll_lddec_encode_fns, 0, 0 }, + { "mula.dd.ll.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_ll_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hl.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hl_lddec_encode_fns, 0, 0 }, + { "mula.dd.hl.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hl_ldinc_encode_fns, 0, 0 }, + { "mula.dd.lh.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_lh_lddec_encode_fns, 0, 0 }, + { "mula.dd.lh.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_lh_ldinc_encode_fns, 0, 0 }, + { "mula.dd.hh.lddec", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hh_lddec_encode_fns, 0, 0 }, + { "mula.dd.hh.ldinc", ICLASS_xt_iclass_mac16al_dd, + 0, + Opcode_mula_dd_hh_ldinc_encode_fns, 0, 0 }, + { "lddec", ICLASS_xt_iclass_mac16_l, + 0, + Opcode_lddec_encode_fns, 0, 0 }, + { "ldinc", ICLASS_xt_iclass_mac16_l, + 0, + Opcode_ldinc_encode_fns, 0, 0 }, + { "rsr.m0", ICLASS_xt_iclass_rsr_m0, + 0, + Opcode_rsr_m0_encode_fns, 0, 0 }, + { "wsr.m0", ICLASS_xt_iclass_wsr_m0, + 0, + Opcode_wsr_m0_encode_fns, 0, 0 }, + { "xsr.m0", ICLASS_xt_iclass_xsr_m0, + 0, + Opcode_xsr_m0_encode_fns, 0, 0 }, + { "rsr.m1", ICLASS_xt_iclass_rsr_m1, + 0, + Opcode_rsr_m1_encode_fns, 0, 0 }, + { "wsr.m1", ICLASS_xt_iclass_wsr_m1, + 0, + Opcode_wsr_m1_encode_fns, 0, 0 }, + { "xsr.m1", ICLASS_xt_iclass_xsr_m1, + 0, + Opcode_xsr_m1_encode_fns, 0, 0 }, + { "rsr.m2", ICLASS_xt_iclass_rsr_m2, + 0, + Opcode_rsr_m2_encode_fns, 0, 0 }, + { "wsr.m2", ICLASS_xt_iclass_wsr_m2, + 0, + Opcode_wsr_m2_encode_fns, 0, 0 }, + { "xsr.m2", ICLASS_xt_iclass_xsr_m2, + 0, + Opcode_xsr_m2_encode_fns, 0, 0 }, + { "rsr.m3", ICLASS_xt_iclass_rsr_m3, + 0, + Opcode_rsr_m3_encode_fns, 0, 0 }, + { "wsr.m3", ICLASS_xt_iclass_wsr_m3, + 0, + Opcode_wsr_m3_encode_fns, 0, 0 }, + { "xsr.m3", ICLASS_xt_iclass_xsr_m3, + 0, + Opcode_xsr_m3_encode_fns, 0, 0 }, + { "rsr.acclo", ICLASS_xt_iclass_rsr_acclo, + 0, + Opcode_rsr_acclo_encode_fns, 0, 0 }, + { "wsr.acclo", ICLASS_xt_iclass_wsr_acclo, + 0, + Opcode_wsr_acclo_encode_fns, 0, 0 }, + { "xsr.acclo", ICLASS_xt_iclass_xsr_acclo, + 0, + Opcode_xsr_acclo_encode_fns, 0, 0 }, + { "rsr.acchi", ICLASS_xt_iclass_rsr_acchi, + 0, + Opcode_rsr_acchi_encode_fns, 0, 0 }, + { "wsr.acchi", ICLASS_xt_iclass_wsr_acchi, + 0, + Opcode_wsr_acchi_encode_fns, 0, 0 }, + { "xsr.acchi", ICLASS_xt_iclass_xsr_acchi, + 0, + Opcode_xsr_acchi_encode_fns, 0, 0 }, + { "rfi", ICLASS_xt_iclass_rfi, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", ICLASS_xt_iclass_wait, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", ICLASS_xt_iclass_rsr_interrupt, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", ICLASS_xt_iclass_wsr_intset, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", ICLASS_xt_iclass_wsr_intclear, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", ICLASS_xt_iclass_rsr_intenable, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", ICLASS_xt_iclass_wsr_intenable, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", ICLASS_xt_iclass_xsr_intenable, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", ICLASS_xt_iclass_break, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", ICLASS_xt_iclass_break_n, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", ICLASS_xt_iclass_rsr_dbreaka0, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", ICLASS_xt_iclass_wsr_dbreaka0, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", ICLASS_xt_iclass_xsr_dbreaka0, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", ICLASS_xt_iclass_rsr_dbreakc0, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", ICLASS_xt_iclass_wsr_dbreakc0, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", ICLASS_xt_iclass_xsr_dbreakc0, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.dbreaka1", ICLASS_xt_iclass_rsr_dbreaka1, + 0, + Opcode_rsr_dbreaka1_encode_fns, 0, 0 }, + { "wsr.dbreaka1", ICLASS_xt_iclass_wsr_dbreaka1, + 0, + Opcode_wsr_dbreaka1_encode_fns, 0, 0 }, + { "xsr.dbreaka1", ICLASS_xt_iclass_xsr_dbreaka1, + 0, + Opcode_xsr_dbreaka1_encode_fns, 0, 0 }, + { "rsr.dbreakc1", ICLASS_xt_iclass_rsr_dbreakc1, + 0, + Opcode_rsr_dbreakc1_encode_fns, 0, 0 }, + { "wsr.dbreakc1", ICLASS_xt_iclass_wsr_dbreakc1, + 0, + Opcode_wsr_dbreakc1_encode_fns, 0, 0 }, + { "xsr.dbreakc1", ICLASS_xt_iclass_xsr_dbreakc1, + 0, + Opcode_xsr_dbreakc1_encode_fns, 0, 0 }, + { "rsr.ibreaka0", ICLASS_xt_iclass_rsr_ibreaka0, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", ICLASS_xt_iclass_wsr_ibreaka0, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", ICLASS_xt_iclass_xsr_ibreaka0, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreaka1", ICLASS_xt_iclass_rsr_ibreaka1, + 0, + Opcode_rsr_ibreaka1_encode_fns, 0, 0 }, + { "wsr.ibreaka1", ICLASS_xt_iclass_wsr_ibreaka1, + 0, + Opcode_wsr_ibreaka1_encode_fns, 0, 0 }, + { "xsr.ibreaka1", ICLASS_xt_iclass_xsr_ibreaka1, + 0, + Opcode_xsr_ibreaka1_encode_fns, 0, 0 }, + { "rsr.ibreakenable", ICLASS_xt_iclass_rsr_ibreakenable, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", ICLASS_xt_iclass_wsr_ibreakenable, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", ICLASS_xt_iclass_xsr_ibreakenable, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", ICLASS_xt_iclass_rsr_debugcause, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", ICLASS_xt_iclass_wsr_debugcause, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", ICLASS_xt_iclass_xsr_debugcause, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", ICLASS_xt_iclass_rsr_icount, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", ICLASS_xt_iclass_wsr_icount, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", ICLASS_xt_iclass_xsr_icount, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", ICLASS_xt_iclass_rsr_icountlevel, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", ICLASS_xt_iclass_wsr_icountlevel, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", ICLASS_xt_iclass_xsr_icountlevel, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", ICLASS_xt_iclass_rsr_ddr, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", ICLASS_xt_iclass_wsr_ddr, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", ICLASS_xt_iclass_xsr_ddr, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", ICLASS_xt_iclass_rfdo, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", ICLASS_xt_iclass_rfdd, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "wsr.mmid", ICLASS_xt_iclass_wsr_mmid, + 0, + Opcode_wsr_mmid_encode_fns, 0, 0 }, + { "rsr.ccount", ICLASS_xt_iclass_rsr_ccount, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", ICLASS_xt_iclass_wsr_ccount, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", ICLASS_xt_iclass_xsr_ccount, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", ICLASS_xt_iclass_rsr_ccompare0, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", ICLASS_xt_iclass_wsr_ccompare0, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", ICLASS_xt_iclass_xsr_ccompare0, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "rsr.ccompare1", ICLASS_xt_iclass_rsr_ccompare1, + 0, + Opcode_rsr_ccompare1_encode_fns, 0, 0 }, + { "wsr.ccompare1", ICLASS_xt_iclass_wsr_ccompare1, + 0, + Opcode_wsr_ccompare1_encode_fns, 0, 0 }, + { "xsr.ccompare1", ICLASS_xt_iclass_xsr_ccompare1, + 0, + Opcode_xsr_ccompare1_encode_fns, 0, 0 }, + { "rsr.ccompare2", ICLASS_xt_iclass_rsr_ccompare2, + 0, + Opcode_rsr_ccompare2_encode_fns, 0, 0 }, + { "wsr.ccompare2", ICLASS_xt_iclass_wsr_ccompare2, + 0, + Opcode_wsr_ccompare2_encode_fns, 0, 0 }, + { "xsr.ccompare2", ICLASS_xt_iclass_xsr_ccompare2, + 0, + Opcode_xsr_ccompare2_encode_fns, 0, 0 }, + { "ipf", ICLASS_xt_iclass_icache, + 0, + Opcode_ipf_encode_fns, 0, 0 }, + { "ihi", ICLASS_xt_iclass_icache, + 0, + Opcode_ihi_encode_fns, 0, 0 }, + { "ipfl", ICLASS_xt_iclass_icache_lock, + 0, + Opcode_ipfl_encode_fns, 0, 0 }, + { "ihu", ICLASS_xt_iclass_icache_lock, + 0, + Opcode_ihu_encode_fns, 0, 0 }, + { "iiu", ICLASS_xt_iclass_icache_lock, + 0, + Opcode_iiu_encode_fns, 0, 0 }, + { "iii", ICLASS_xt_iclass_icache_inv, + 0, + Opcode_iii_encode_fns, 0, 0 }, + { "lict", ICLASS_xt_iclass_licx, + 0, + Opcode_lict_encode_fns, 0, 0 }, + { "licw", ICLASS_xt_iclass_licx, + 0, + Opcode_licw_encode_fns, 0, 0 }, + { "sict", ICLASS_xt_iclass_sicx, + 0, + Opcode_sict_encode_fns, 0, 0 }, + { "sicw", ICLASS_xt_iclass_sicx, + 0, + Opcode_sicw_encode_fns, 0, 0 }, + { "dhwb", ICLASS_xt_iclass_dcache, + 0, + Opcode_dhwb_encode_fns, 0, 0 }, + { "dhwbi", ICLASS_xt_iclass_dcache, + 0, + Opcode_dhwbi_encode_fns, 0, 0 }, + { "diwb", ICLASS_xt_iclass_dcache_ind, + 0, + Opcode_diwb_encode_fns, 0, 0 }, + { "diwbi", ICLASS_xt_iclass_dcache_ind, + 0, + Opcode_diwbi_encode_fns, 0, 0 }, + { "dhi", ICLASS_xt_iclass_dcache_inv, + 0, + Opcode_dhi_encode_fns, 0, 0 }, + { "dii", ICLASS_xt_iclass_dcache_inv, + 0, + Opcode_dii_encode_fns, 0, 0 }, + { "dpfr", ICLASS_xt_iclass_dpf, + 0, + Opcode_dpfr_encode_fns, 0, 0 }, + { "dpfw", ICLASS_xt_iclass_dpf, + 0, + Opcode_dpfw_encode_fns, 0, 0 }, + { "dpfro", ICLASS_xt_iclass_dpf, + 0, + Opcode_dpfro_encode_fns, 0, 0 }, + { "dpfwo", ICLASS_xt_iclass_dpf, + 0, + Opcode_dpfwo_encode_fns, 0, 0 }, + { "dpfl", ICLASS_xt_iclass_dcache_lock, + 0, + Opcode_dpfl_encode_fns, 0, 0 }, + { "dhu", ICLASS_xt_iclass_dcache_lock, + 0, + Opcode_dhu_encode_fns, 0, 0 }, + { "diu", ICLASS_xt_iclass_dcache_lock, + 0, + Opcode_diu_encode_fns, 0, 0 }, + { "sdct", ICLASS_xt_iclass_sdct, + 0, + Opcode_sdct_encode_fns, 0, 0 }, + { "ldct", ICLASS_xt_iclass_ldct, + 0, + Opcode_ldct_encode_fns, 0, 0 }, + { "wsr.ptevaddr", ICLASS_xt_iclass_wsr_ptevaddr, + 0, + Opcode_wsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.ptevaddr", ICLASS_xt_iclass_rsr_ptevaddr, + 0, + Opcode_rsr_ptevaddr_encode_fns, 0, 0 }, + { "xsr.ptevaddr", ICLASS_xt_iclass_xsr_ptevaddr, + 0, + Opcode_xsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.rasid", ICLASS_xt_iclass_rsr_rasid, + 0, + Opcode_rsr_rasid_encode_fns, 0, 0 }, + { "wsr.rasid", ICLASS_xt_iclass_wsr_rasid, + 0, + Opcode_wsr_rasid_encode_fns, 0, 0 }, + { "xsr.rasid", ICLASS_xt_iclass_xsr_rasid, + 0, + Opcode_xsr_rasid_encode_fns, 0, 0 }, + { "rsr.itlbcfg", ICLASS_xt_iclass_rsr_itlbcfg, + 0, + Opcode_rsr_itlbcfg_encode_fns, 0, 0 }, + { "wsr.itlbcfg", ICLASS_xt_iclass_wsr_itlbcfg, + 0, + Opcode_wsr_itlbcfg_encode_fns, 0, 0 }, + { "xsr.itlbcfg", ICLASS_xt_iclass_xsr_itlbcfg, + 0, + Opcode_xsr_itlbcfg_encode_fns, 0, 0 }, + { "rsr.dtlbcfg", ICLASS_xt_iclass_rsr_dtlbcfg, + 0, + Opcode_rsr_dtlbcfg_encode_fns, 0, 0 }, + { "wsr.dtlbcfg", ICLASS_xt_iclass_wsr_dtlbcfg, + 0, + Opcode_wsr_dtlbcfg_encode_fns, 0, 0 }, + { "xsr.dtlbcfg", ICLASS_xt_iclass_xsr_dtlbcfg, + 0, + Opcode_xsr_dtlbcfg_encode_fns, 0, 0 }, + { "idtlb", ICLASS_xt_iclass_idtlb, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", ICLASS_xt_iclass_rdtlb, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", ICLASS_xt_iclass_wdtlb, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", ICLASS_xt_iclass_iitlb, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", ICLASS_xt_iclass_ritlb, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", ICLASS_xt_iclass_ritlb, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", ICLASS_xt_iclass_witlb, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "ldpte", ICLASS_xt_iclass_ldpte, + 0, + Opcode_ldpte_encode_fns, 0, 0 }, + { "hwwitlba", ICLASS_xt_iclass_hwwitlba, + XTENSA_OPCODE_IS_BRANCH, + Opcode_hwwitlba_encode_fns, 0, 0 }, + { "hwwdtlba", ICLASS_xt_iclass_hwwdtlba, + 0, + Opcode_hwwdtlba_encode_fns, 0, 0 }, + { "rsr.cpenable", ICLASS_xt_iclass_rsr_cpenable, + 0, + Opcode_rsr_cpenable_encode_fns, 0, 0 }, + { "wsr.cpenable", ICLASS_xt_iclass_wsr_cpenable, + 0, + Opcode_wsr_cpenable_encode_fns, 0, 0 }, + { "xsr.cpenable", ICLASS_xt_iclass_xsr_cpenable, + 0, + Opcode_xsr_cpenable_encode_fns, 0, 0 }, + { "clamps", ICLASS_xt_iclass_clamp, + 0, + Opcode_clamps_encode_fns, 0, 0 }, + { "min", ICLASS_xt_iclass_minmax, + 0, + Opcode_min_encode_fns, 0, 0 }, + { "max", ICLASS_xt_iclass_minmax, + 0, + Opcode_max_encode_fns, 0, 0 }, + { "minu", ICLASS_xt_iclass_minmax, + 0, + Opcode_minu_encode_fns, 0, 0 }, + { "maxu", ICLASS_xt_iclass_minmax, + 0, + Opcode_maxu_encode_fns, 0, 0 }, + { "nsa", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", ICLASS_xt_iclass_nsa, + 0, + Opcode_nsau_encode_fns, 0, 0 }, + { "sext", ICLASS_xt_iclass_sx, + 0, + Opcode_sext_encode_fns, 0, 0 }, + { "l32ai", ICLASS_xt_iclass_l32ai, + 0, + Opcode_l32ai_encode_fns, 0, 0 }, + { "s32ri", ICLASS_xt_iclass_s32ri, + 0, + Opcode_s32ri_encode_fns, 0, 0 }, + { "s32c1i", ICLASS_xt_iclass_s32c1i, + 0, + Opcode_s32c1i_encode_fns, 0, 0 }, + { "rsr.scompare1", ICLASS_xt_iclass_rsr_scompare1, + 0, + Opcode_rsr_scompare1_encode_fns, 0, 0 }, + { "wsr.scompare1", ICLASS_xt_iclass_wsr_scompare1, + 0, + Opcode_wsr_scompare1_encode_fns, 0, 0 }, + { "xsr.scompare1", ICLASS_xt_iclass_xsr_scompare1, + 0, + Opcode_xsr_scompare1_encode_fns, 0, 0 }, + { "rsr.atomctl", ICLASS_xt_iclass_rsr_atomctl, + 0, + Opcode_rsr_atomctl_encode_fns, 0, 0 }, + { "wsr.atomctl", ICLASS_xt_iclass_wsr_atomctl, + 0, + Opcode_wsr_atomctl_encode_fns, 0, 0 }, + { "xsr.atomctl", ICLASS_xt_iclass_xsr_atomctl, + 0, + Opcode_xsr_atomctl_encode_fns, 0, 0 }, + { "quou", ICLASS_xt_iclass_div, + 0, + Opcode_quou_encode_fns, 0, 0 }, + { "quos", ICLASS_xt_iclass_div, + 0, + Opcode_quos_encode_fns, 0, 0 }, + { "remu", ICLASS_xt_iclass_div, + 0, + Opcode_remu_encode_fns, 0, 0 }, + { "rems", ICLASS_xt_iclass_div, + 0, + Opcode_rems_encode_fns, 0, 0 }, + { "rer", ICLASS_xt_iclass_rer, + 0, + Opcode_rer_encode_fns, 0, 0 }, + { "wer", ICLASS_xt_iclass_wer, + 0, + Opcode_wer_encode_fns, 0, 0 }, + { "rur.expstate", ICLASS_rur_expstate, + 0, + Opcode_rur_expstate_encode_fns, 0, 0 }, + { "wur.expstate", ICLASS_wur_expstate, + 0, + Opcode_wur_expstate_encode_fns, 0, 0 }, + { "read_impwire", ICLASS_iclass_READ_IMPWIRE, + 0, + Opcode_read_impwire_encode_fns, 0, 0 }, + { "setb_expstate", ICLASS_iclass_SETB_EXPSTATE, + 0, + Opcode_setb_expstate_encode_fns, 0, 0 }, + { "clrb_expstate", ICLASS_iclass_CLRB_EXPSTATE, + 0, + Opcode_clrb_expstate_encode_fns, 0, 0 }, + { "wrmsk_expstate", ICLASS_iclass_WRMSK_EXPSTATE, + 0, + Opcode_wrmsk_expstate_encode_fns, 0, 0 } +}; + +enum xtensa_opcode_id { + OPCODE_EXCW, + OPCODE_RFE, + OPCODE_RFDE, + OPCODE_SYSCALL, + OPCODE_SIMCALL, + OPCODE_CALL12, + OPCODE_CALL8, + OPCODE_CALL4, + OPCODE_CALLX12, + OPCODE_CALLX8, + OPCODE_CALLX4, + OPCODE_ENTRY, + OPCODE_MOVSP, + OPCODE_ROTW, + OPCODE_RETW, + OPCODE_RETW_N, + OPCODE_RFWO, + OPCODE_RFWU, + OPCODE_L32E, + OPCODE_S32E, + OPCODE_RSR_WINDOWBASE, + OPCODE_WSR_WINDOWBASE, + OPCODE_XSR_WINDOWBASE, + OPCODE_RSR_WINDOWSTART, + OPCODE_WSR_WINDOWSTART, + OPCODE_XSR_WINDOWSTART, + OPCODE_ADD_N, + OPCODE_ADDI_N, + OPCODE_BEQZ_N, + OPCODE_BNEZ_N, + OPCODE_ILL_N, + OPCODE_L32I_N, + OPCODE_MOV_N, + OPCODE_MOVI_N, + OPCODE_NOP_N, + OPCODE_RET_N, + OPCODE_S32I_N, + OPCODE_RUR_THREADPTR, + OPCODE_WUR_THREADPTR, + OPCODE_ADDI, + OPCODE_ADDMI, + OPCODE_ADD, + OPCODE_SUB, + OPCODE_ADDX2, + OPCODE_ADDX4, + OPCODE_ADDX8, + OPCODE_SUBX2, + OPCODE_SUBX4, + OPCODE_SUBX8, + OPCODE_AND, + OPCODE_OR, + OPCODE_XOR, + OPCODE_BEQI, + OPCODE_BNEI, + OPCODE_BGEI, + OPCODE_BLTI, + OPCODE_BBCI, + OPCODE_BBSI, + OPCODE_BGEUI, + OPCODE_BLTUI, + OPCODE_BEQ, + OPCODE_BNE, + OPCODE_BGE, + OPCODE_BLT, + OPCODE_BGEU, + OPCODE_BLTU, + OPCODE_BANY, + OPCODE_BNONE, + OPCODE_BALL, + OPCODE_BNALL, + OPCODE_BBC, + OPCODE_BBS, + OPCODE_BEQZ, + OPCODE_BNEZ, + OPCODE_BGEZ, + OPCODE_BLTZ, + OPCODE_CALL0, + OPCODE_CALLX0, + OPCODE_EXTUI, + OPCODE_ILL, + OPCODE_J, + OPCODE_JX, + OPCODE_L16UI, + OPCODE_L16SI, + OPCODE_L32I, + OPCODE_L32R, + OPCODE_L8UI, + OPCODE_LOOP, + OPCODE_LOOPNEZ, + OPCODE_LOOPGTZ, + OPCODE_MOVI, + OPCODE_MOVEQZ, + OPCODE_MOVNEZ, + OPCODE_MOVLTZ, + OPCODE_MOVGEZ, + OPCODE_NEG, + OPCODE_ABS, + OPCODE_NOP, + OPCODE_RET, + OPCODE_S16I, + OPCODE_S32I, + OPCODE_S8I, + OPCODE_SSR, + OPCODE_SSL, + OPCODE_SSA8L, + OPCODE_SSA8B, + OPCODE_SSAI, + OPCODE_SLL, + OPCODE_SRC, + OPCODE_SRL, + OPCODE_SRA, + OPCODE_SLLI, + OPCODE_SRAI, + OPCODE_SRLI, + OPCODE_MEMW, + OPCODE_EXTW, + OPCODE_ISYNC, + OPCODE_RSYNC, + OPCODE_ESYNC, + OPCODE_DSYNC, + OPCODE_RSIL, + OPCODE_RSR_LEND, + OPCODE_WSR_LEND, + OPCODE_XSR_LEND, + OPCODE_RSR_LCOUNT, + OPCODE_WSR_LCOUNT, + OPCODE_XSR_LCOUNT, + OPCODE_RSR_LBEG, + OPCODE_WSR_LBEG, + OPCODE_XSR_LBEG, + OPCODE_RSR_SAR, + OPCODE_WSR_SAR, + OPCODE_XSR_SAR, + OPCODE_RSR_LITBASE, + OPCODE_WSR_LITBASE, + OPCODE_XSR_LITBASE, + OPCODE_RSR_176, + OPCODE_WSR_176, + OPCODE_RSR_208, + OPCODE_RSR_PS, + OPCODE_WSR_PS, + OPCODE_XSR_PS, + OPCODE_RSR_EPC1, + OPCODE_WSR_EPC1, + OPCODE_XSR_EPC1, + OPCODE_RSR_EXCSAVE1, + OPCODE_WSR_EXCSAVE1, + OPCODE_XSR_EXCSAVE1, + OPCODE_RSR_EPC2, + OPCODE_WSR_EPC2, + OPCODE_XSR_EPC2, + OPCODE_RSR_EXCSAVE2, + OPCODE_WSR_EXCSAVE2, + OPCODE_XSR_EXCSAVE2, + OPCODE_RSR_EPC3, + OPCODE_WSR_EPC3, + OPCODE_XSR_EPC3, + OPCODE_RSR_EXCSAVE3, + OPCODE_WSR_EXCSAVE3, + OPCODE_XSR_EXCSAVE3, + OPCODE_RSR_EPC4, + OPCODE_WSR_EPC4, + OPCODE_XSR_EPC4, + OPCODE_RSR_EXCSAVE4, + OPCODE_WSR_EXCSAVE4, + OPCODE_XSR_EXCSAVE4, + OPCODE_RSR_EPC5, + OPCODE_WSR_EPC5, + OPCODE_XSR_EPC5, + OPCODE_RSR_EXCSAVE5, + OPCODE_WSR_EXCSAVE5, + OPCODE_XSR_EXCSAVE5, + OPCODE_RSR_EPC6, + OPCODE_WSR_EPC6, + OPCODE_XSR_EPC6, + OPCODE_RSR_EXCSAVE6, + OPCODE_WSR_EXCSAVE6, + OPCODE_XSR_EXCSAVE6, + OPCODE_RSR_EPC7, + OPCODE_WSR_EPC7, + OPCODE_XSR_EPC7, + OPCODE_RSR_EXCSAVE7, + OPCODE_WSR_EXCSAVE7, + OPCODE_XSR_EXCSAVE7, + OPCODE_RSR_EPS2, + OPCODE_WSR_EPS2, + OPCODE_XSR_EPS2, + OPCODE_RSR_EPS3, + OPCODE_WSR_EPS3, + OPCODE_XSR_EPS3, + OPCODE_RSR_EPS4, + OPCODE_WSR_EPS4, + OPCODE_XSR_EPS4, + OPCODE_RSR_EPS5, + OPCODE_WSR_EPS5, + OPCODE_XSR_EPS5, + OPCODE_RSR_EPS6, + OPCODE_WSR_EPS6, + OPCODE_XSR_EPS6, + OPCODE_RSR_EPS7, + OPCODE_WSR_EPS7, + OPCODE_XSR_EPS7, + OPCODE_RSR_EXCVADDR, + OPCODE_WSR_EXCVADDR, + OPCODE_XSR_EXCVADDR, + OPCODE_RSR_DEPC, + OPCODE_WSR_DEPC, + OPCODE_XSR_DEPC, + OPCODE_RSR_EXCCAUSE, + OPCODE_WSR_EXCCAUSE, + OPCODE_XSR_EXCCAUSE, + OPCODE_RSR_MISC0, + OPCODE_WSR_MISC0, + OPCODE_XSR_MISC0, + OPCODE_RSR_MISC1, + OPCODE_WSR_MISC1, + OPCODE_XSR_MISC1, + OPCODE_RSR_PRID, + OPCODE_RSR_VECBASE, + OPCODE_WSR_VECBASE, + OPCODE_XSR_VECBASE, + OPCODE_MUL16U, + OPCODE_MUL16S, + OPCODE_MULL, + OPCODE_MUL_AA_LL, + OPCODE_MUL_AA_HL, + OPCODE_MUL_AA_LH, + OPCODE_MUL_AA_HH, + OPCODE_UMUL_AA_LL, + OPCODE_UMUL_AA_HL, + OPCODE_UMUL_AA_LH, + OPCODE_UMUL_AA_HH, + OPCODE_MUL_AD_LL, + OPCODE_MUL_AD_HL, + OPCODE_MUL_AD_LH, + OPCODE_MUL_AD_HH, + OPCODE_MUL_DA_LL, + OPCODE_MUL_DA_HL, + OPCODE_MUL_DA_LH, + OPCODE_MUL_DA_HH, + OPCODE_MUL_DD_LL, + OPCODE_MUL_DD_HL, + OPCODE_MUL_DD_LH, + OPCODE_MUL_DD_HH, + OPCODE_MULA_AA_LL, + OPCODE_MULA_AA_HL, + OPCODE_MULA_AA_LH, + OPCODE_MULA_AA_HH, + OPCODE_MULS_AA_LL, + OPCODE_MULS_AA_HL, + OPCODE_MULS_AA_LH, + OPCODE_MULS_AA_HH, + OPCODE_MULA_AD_LL, + OPCODE_MULA_AD_HL, + OPCODE_MULA_AD_LH, + OPCODE_MULA_AD_HH, + OPCODE_MULS_AD_LL, + OPCODE_MULS_AD_HL, + OPCODE_MULS_AD_LH, + OPCODE_MULS_AD_HH, + OPCODE_MULA_DA_LL, + OPCODE_MULA_DA_HL, + OPCODE_MULA_DA_LH, + OPCODE_MULA_DA_HH, + OPCODE_MULS_DA_LL, + OPCODE_MULS_DA_HL, + OPCODE_MULS_DA_LH, + OPCODE_MULS_DA_HH, + OPCODE_MULA_DD_LL, + OPCODE_MULA_DD_HL, + OPCODE_MULA_DD_LH, + OPCODE_MULA_DD_HH, + OPCODE_MULS_DD_LL, + OPCODE_MULS_DD_HL, + OPCODE_MULS_DD_LH, + OPCODE_MULS_DD_HH, + OPCODE_MULA_DA_LL_LDDEC, + OPCODE_MULA_DA_LL_LDINC, + OPCODE_MULA_DA_HL_LDDEC, + OPCODE_MULA_DA_HL_LDINC, + OPCODE_MULA_DA_LH_LDDEC, + OPCODE_MULA_DA_LH_LDINC, + OPCODE_MULA_DA_HH_LDDEC, + OPCODE_MULA_DA_HH_LDINC, + OPCODE_MULA_DD_LL_LDDEC, + OPCODE_MULA_DD_LL_LDINC, + OPCODE_MULA_DD_HL_LDDEC, + OPCODE_MULA_DD_HL_LDINC, + OPCODE_MULA_DD_LH_LDDEC, + OPCODE_MULA_DD_LH_LDINC, + OPCODE_MULA_DD_HH_LDDEC, + OPCODE_MULA_DD_HH_LDINC, + OPCODE_LDDEC, + OPCODE_LDINC, + OPCODE_RSR_M0, + OPCODE_WSR_M0, + OPCODE_XSR_M0, + OPCODE_RSR_M1, + OPCODE_WSR_M1, + OPCODE_XSR_M1, + OPCODE_RSR_M2, + OPCODE_WSR_M2, + OPCODE_XSR_M2, + OPCODE_RSR_M3, + OPCODE_WSR_M3, + OPCODE_XSR_M3, + OPCODE_RSR_ACCLO, + OPCODE_WSR_ACCLO, + OPCODE_XSR_ACCLO, + OPCODE_RSR_ACCHI, + OPCODE_WSR_ACCHI, + OPCODE_XSR_ACCHI, + OPCODE_RFI, + OPCODE_WAITI, + OPCODE_RSR_INTERRUPT, + OPCODE_WSR_INTSET, + OPCODE_WSR_INTCLEAR, + OPCODE_RSR_INTENABLE, + OPCODE_WSR_INTENABLE, + OPCODE_XSR_INTENABLE, + OPCODE_BREAK, + OPCODE_BREAK_N, + OPCODE_RSR_DBREAKA0, + OPCODE_WSR_DBREAKA0, + OPCODE_XSR_DBREAKA0, + OPCODE_RSR_DBREAKC0, + OPCODE_WSR_DBREAKC0, + OPCODE_XSR_DBREAKC0, + OPCODE_RSR_DBREAKA1, + OPCODE_WSR_DBREAKA1, + OPCODE_XSR_DBREAKA1, + OPCODE_RSR_DBREAKC1, + OPCODE_WSR_DBREAKC1, + OPCODE_XSR_DBREAKC1, + OPCODE_RSR_IBREAKA0, + OPCODE_WSR_IBREAKA0, + OPCODE_XSR_IBREAKA0, + OPCODE_RSR_IBREAKA1, + OPCODE_WSR_IBREAKA1, + OPCODE_XSR_IBREAKA1, + OPCODE_RSR_IBREAKENABLE, + OPCODE_WSR_IBREAKENABLE, + OPCODE_XSR_IBREAKENABLE, + OPCODE_RSR_DEBUGCAUSE, + OPCODE_WSR_DEBUGCAUSE, + OPCODE_XSR_DEBUGCAUSE, + OPCODE_RSR_ICOUNT, + OPCODE_WSR_ICOUNT, + OPCODE_XSR_ICOUNT, + OPCODE_RSR_ICOUNTLEVEL, + OPCODE_WSR_ICOUNTLEVEL, + OPCODE_XSR_ICOUNTLEVEL, + OPCODE_RSR_DDR, + OPCODE_WSR_DDR, + OPCODE_XSR_DDR, + OPCODE_RFDO, + OPCODE_RFDD, + OPCODE_WSR_MMID, + OPCODE_RSR_CCOUNT, + OPCODE_WSR_CCOUNT, + OPCODE_XSR_CCOUNT, + OPCODE_RSR_CCOMPARE0, + OPCODE_WSR_CCOMPARE0, + OPCODE_XSR_CCOMPARE0, + OPCODE_RSR_CCOMPARE1, + OPCODE_WSR_CCOMPARE1, + OPCODE_XSR_CCOMPARE1, + OPCODE_RSR_CCOMPARE2, + OPCODE_WSR_CCOMPARE2, + OPCODE_XSR_CCOMPARE2, + OPCODE_IPF, + OPCODE_IHI, + OPCODE_IPFL, + OPCODE_IHU, + OPCODE_IIU, + OPCODE_III, + OPCODE_LICT, + OPCODE_LICW, + OPCODE_SICT, + OPCODE_SICW, + OPCODE_DHWB, + OPCODE_DHWBI, + OPCODE_DIWB, + OPCODE_DIWBI, + OPCODE_DHI, + OPCODE_DII, + OPCODE_DPFR, + OPCODE_DPFW, + OPCODE_DPFRO, + OPCODE_DPFWO, + OPCODE_DPFL, + OPCODE_DHU, + OPCODE_DIU, + OPCODE_SDCT, + OPCODE_LDCT, + OPCODE_WSR_PTEVADDR, + OPCODE_RSR_PTEVADDR, + OPCODE_XSR_PTEVADDR, + OPCODE_RSR_RASID, + OPCODE_WSR_RASID, + OPCODE_XSR_RASID, + OPCODE_RSR_ITLBCFG, + OPCODE_WSR_ITLBCFG, + OPCODE_XSR_ITLBCFG, + OPCODE_RSR_DTLBCFG, + OPCODE_WSR_DTLBCFG, + OPCODE_XSR_DTLBCFG, + OPCODE_IDTLB, + OPCODE_PDTLB, + OPCODE_RDTLB0, + OPCODE_RDTLB1, + OPCODE_WDTLB, + OPCODE_IITLB, + OPCODE_PITLB, + OPCODE_RITLB0, + OPCODE_RITLB1, + OPCODE_WITLB, + OPCODE_LDPTE, + OPCODE_HWWITLBA, + OPCODE_HWWDTLBA, + OPCODE_RSR_CPENABLE, + OPCODE_WSR_CPENABLE, + OPCODE_XSR_CPENABLE, + OPCODE_CLAMPS, + OPCODE_MIN, + OPCODE_MAX, + OPCODE_MINU, + OPCODE_MAXU, + OPCODE_NSA, + OPCODE_NSAU, + OPCODE_SEXT, + OPCODE_L32AI, + OPCODE_S32RI, + OPCODE_S32C1I, + OPCODE_RSR_SCOMPARE1, + OPCODE_WSR_SCOMPARE1, + OPCODE_XSR_SCOMPARE1, + OPCODE_RSR_ATOMCTL, + OPCODE_WSR_ATOMCTL, + OPCODE_XSR_ATOMCTL, + OPCODE_QUOU, + OPCODE_QUOS, + OPCODE_REMU, + OPCODE_REMS, + OPCODE_RER, + OPCODE_WER, + OPCODE_RUR_EXPSTATE, + OPCODE_WUR_EXPSTATE, + OPCODE_READ_IMPWIRE, + OPCODE_SETB_EXPSTATE, + OPCODE_CLRB_EXPSTATE, + OPCODE_WRMSK_EXPSTATE +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return OPCODE_ILL; + break; + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RET; + case 1: + return OPCODE_RETW; + case 2: + return OPCODE_JX; + } + break; + case 3: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_CALLX0; + case 1: + return OPCODE_CALLX4; + case 2: + return OPCODE_CALLX8; + case 3: + return OPCODE_CALLX12; + } + break; + } + break; + case 1: + return OPCODE_MOVSP; + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return OPCODE_ISYNC; + case 1: + return OPCODE_RSYNC; + case 2: + return OPCODE_ESYNC; + case 3: + return OPCODE_DSYNC; + case 8: + return OPCODE_EXCW; + case 12: + return OPCODE_MEMW; + case 13: + return OPCODE_EXTW; + case 15: + return OPCODE_NOP; + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RFE; + case 2: + return OPCODE_RFDE; + case 4: + return OPCODE_RFWO; + case 5: + return OPCODE_RFWU; + } + break; + case 1: + return OPCODE_RFI; + } + break; + case 4: + return OPCODE_BREAK; + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SYSCALL; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SIMCALL; + break; + } + break; + case 6: + return OPCODE_RSIL; + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_WAITI; + break; + } + break; + case 1: + return OPCODE_AND; + case 2: + return OPCODE_OR; + case 3: + return OPCODE_XOR; + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSR; + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSL; + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8L; + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SSA8B; + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return OPCODE_SSAI; + break; + case 6: + return OPCODE_RER; + case 7: + return OPCODE_WER; + case 8: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_ROTW; + break; + case 14: + return OPCODE_NSA; + case 15: + return OPCODE_NSAU; + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 1: + return OPCODE_HWWITLBA; + case 3: + return OPCODE_RITLB0; + case 4: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IITLB; + break; + case 5: + return OPCODE_PITLB; + case 6: + return OPCODE_WITLB; + case 7: + return OPCODE_RITLB1; + case 9: + return OPCODE_HWWDTLBA; + case 11: + return OPCODE_RDTLB0; + case 12: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_IDTLB; + break; + case 13: + return OPCODE_PDTLB; + case 14: + return OPCODE_WDTLB; + case 15: + return OPCODE_RDTLB1; + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return OPCODE_NEG; + case 1: + return OPCODE_ABS; + } + break; + case 8: + return OPCODE_ADD; + case 9: + return OPCODE_ADDX2; + case 10: + return OPCODE_ADDX4; + case 11: + return OPCODE_ADDX8; + case 12: + return OPCODE_SUB; + case 13: + return OPCODE_SUBX2; + case 14: + return OPCODE_SUBX4; + case 15: + return OPCODE_SUBX8; + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return OPCODE_SLLI; + case 2: + case 3: + return OPCODE_SRAI; + case 4: + return OPCODE_SRLI; + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return OPCODE_XSR_LBEG; + case 1: + return OPCODE_XSR_LEND; + case 2: + return OPCODE_XSR_LCOUNT; + case 3: + return OPCODE_XSR_SAR; + case 5: + return OPCODE_XSR_LITBASE; + case 12: + return OPCODE_XSR_SCOMPARE1; + case 16: + return OPCODE_XSR_ACCLO; + case 17: + return OPCODE_XSR_ACCHI; + case 32: + return OPCODE_XSR_M0; + case 33: + return OPCODE_XSR_M1; + case 34: + return OPCODE_XSR_M2; + case 35: + return OPCODE_XSR_M3; + case 72: + return OPCODE_XSR_WINDOWBASE; + case 73: + return OPCODE_XSR_WINDOWSTART; + case 83: + return OPCODE_XSR_PTEVADDR; + case 90: + return OPCODE_XSR_RASID; + case 91: + return OPCODE_XSR_ITLBCFG; + case 92: + return OPCODE_XSR_DTLBCFG; + case 96: + return OPCODE_XSR_IBREAKENABLE; + case 99: + return OPCODE_XSR_ATOMCTL; + case 104: + return OPCODE_XSR_DDR; + case 128: + return OPCODE_XSR_IBREAKA0; + case 129: + return OPCODE_XSR_IBREAKA1; + case 144: + return OPCODE_XSR_DBREAKA0; + case 145: + return OPCODE_XSR_DBREAKA1; + case 160: + return OPCODE_XSR_DBREAKC0; + case 161: + return OPCODE_XSR_DBREAKC1; + case 177: + return OPCODE_XSR_EPC1; + case 178: + return OPCODE_XSR_EPC2; + case 179: + return OPCODE_XSR_EPC3; + case 180: + return OPCODE_XSR_EPC4; + case 181: + return OPCODE_XSR_EPC5; + case 182: + return OPCODE_XSR_EPC6; + case 183: + return OPCODE_XSR_EPC7; + case 192: + return OPCODE_XSR_DEPC; + case 194: + return OPCODE_XSR_EPS2; + case 195: + return OPCODE_XSR_EPS3; + case 196: + return OPCODE_XSR_EPS4; + case 197: + return OPCODE_XSR_EPS5; + case 198: + return OPCODE_XSR_EPS6; + case 199: + return OPCODE_XSR_EPS7; + case 209: + return OPCODE_XSR_EXCSAVE1; + case 210: + return OPCODE_XSR_EXCSAVE2; + case 211: + return OPCODE_XSR_EXCSAVE3; + case 212: + return OPCODE_XSR_EXCSAVE4; + case 213: + return OPCODE_XSR_EXCSAVE5; + case 214: + return OPCODE_XSR_EXCSAVE6; + case 215: + return OPCODE_XSR_EXCSAVE7; + case 224: + return OPCODE_XSR_CPENABLE; + case 228: + return OPCODE_XSR_INTENABLE; + case 230: + return OPCODE_XSR_PS; + case 231: + return OPCODE_XSR_VECBASE; + case 232: + return OPCODE_XSR_EXCCAUSE; + case 233: + return OPCODE_XSR_DEBUGCAUSE; + case 234: + return OPCODE_XSR_CCOUNT; + case 236: + return OPCODE_XSR_ICOUNT; + case 237: + return OPCODE_XSR_ICOUNTLEVEL; + case 238: + return OPCODE_XSR_EXCVADDR; + case 240: + return OPCODE_XSR_CCOMPARE0; + case 241: + return OPCODE_XSR_CCOMPARE1; + case 242: + return OPCODE_XSR_CCOMPARE2; + case 244: + return OPCODE_XSR_MISC0; + case 245: + return OPCODE_XSR_MISC1; + } + break; + case 8: + return OPCODE_SRC; + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRL; + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_SLL; + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return OPCODE_SRA; + break; + case 12: + return OPCODE_MUL16U; + case 13: + return OPCODE_MUL16S; + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_LICT; + case 1: + return OPCODE_SICT; + case 2: + return OPCODE_LICW; + case 3: + return OPCODE_SICW; + case 8: + return OPCODE_LDCT; + case 9: + return OPCODE_SDCT; + case 14: + if (Field_t_Slot_inst_get (insn) == 0) + return OPCODE_RFDO; + if (Field_t_Slot_inst_get (insn) == 1) + return OPCODE_RFDD; + break; + case 15: + return OPCODE_LDPTE; + } + break; + } + break; + case 2: + switch (Field_op2_Slot_inst_get (insn)) + { + case 8: + return OPCODE_MULL; + case 12: + return OPCODE_QUOU; + case 13: + return OPCODE_QUOS; + case 14: + return OPCODE_REMU; + case 15: + return OPCODE_REMS; + } + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return OPCODE_RSR_LBEG; + case 1: + return OPCODE_RSR_LEND; + case 2: + return OPCODE_RSR_LCOUNT; + case 3: + return OPCODE_RSR_SAR; + case 5: + return OPCODE_RSR_LITBASE; + case 12: + return OPCODE_RSR_SCOMPARE1; + case 16: + return OPCODE_RSR_ACCLO; + case 17: + return OPCODE_RSR_ACCHI; + case 32: + return OPCODE_RSR_M0; + case 33: + return OPCODE_RSR_M1; + case 34: + return OPCODE_RSR_M2; + case 35: + return OPCODE_RSR_M3; + case 72: + return OPCODE_RSR_WINDOWBASE; + case 73: + return OPCODE_RSR_WINDOWSTART; + case 83: + return OPCODE_RSR_PTEVADDR; + case 90: + return OPCODE_RSR_RASID; + case 91: + return OPCODE_RSR_ITLBCFG; + case 92: + return OPCODE_RSR_DTLBCFG; + case 96: + return OPCODE_RSR_IBREAKENABLE; + case 99: + return OPCODE_RSR_ATOMCTL; + case 104: + return OPCODE_RSR_DDR; + case 128: + return OPCODE_RSR_IBREAKA0; + case 129: + return OPCODE_RSR_IBREAKA1; + case 144: + return OPCODE_RSR_DBREAKA0; + case 145: + return OPCODE_RSR_DBREAKA1; + case 160: + return OPCODE_RSR_DBREAKC0; + case 161: + return OPCODE_RSR_DBREAKC1; + case 176: + return OPCODE_RSR_176; + case 177: + return OPCODE_RSR_EPC1; + case 178: + return OPCODE_RSR_EPC2; + case 179: + return OPCODE_RSR_EPC3; + case 180: + return OPCODE_RSR_EPC4; + case 181: + return OPCODE_RSR_EPC5; + case 182: + return OPCODE_RSR_EPC6; + case 183: + return OPCODE_RSR_EPC7; + case 192: + return OPCODE_RSR_DEPC; + case 194: + return OPCODE_RSR_EPS2; + case 195: + return OPCODE_RSR_EPS3; + case 196: + return OPCODE_RSR_EPS4; + case 197: + return OPCODE_RSR_EPS5; + case 198: + return OPCODE_RSR_EPS6; + case 199: + return OPCODE_RSR_EPS7; + case 208: + return OPCODE_RSR_208; + case 209: + return OPCODE_RSR_EXCSAVE1; + case 210: + return OPCODE_RSR_EXCSAVE2; + case 211: + return OPCODE_RSR_EXCSAVE3; + case 212: + return OPCODE_RSR_EXCSAVE4; + case 213: + return OPCODE_RSR_EXCSAVE5; + case 214: + return OPCODE_RSR_EXCSAVE6; + case 215: + return OPCODE_RSR_EXCSAVE7; + case 224: + return OPCODE_RSR_CPENABLE; + case 226: + return OPCODE_RSR_INTERRUPT; + case 228: + return OPCODE_RSR_INTENABLE; + case 230: + return OPCODE_RSR_PS; + case 231: + return OPCODE_RSR_VECBASE; + case 232: + return OPCODE_RSR_EXCCAUSE; + case 233: + return OPCODE_RSR_DEBUGCAUSE; + case 234: + return OPCODE_RSR_CCOUNT; + case 235: + return OPCODE_RSR_PRID; + case 236: + return OPCODE_RSR_ICOUNT; + case 237: + return OPCODE_RSR_ICOUNTLEVEL; + case 238: + return OPCODE_RSR_EXCVADDR; + case 240: + return OPCODE_RSR_CCOMPARE0; + case 241: + return OPCODE_RSR_CCOMPARE1; + case 242: + return OPCODE_RSR_CCOMPARE2; + case 244: + return OPCODE_RSR_MISC0; + case 245: + return OPCODE_RSR_MISC1; + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return OPCODE_WSR_LBEG; + case 1: + return OPCODE_WSR_LEND; + case 2: + return OPCODE_WSR_LCOUNT; + case 3: + return OPCODE_WSR_SAR; + case 5: + return OPCODE_WSR_LITBASE; + case 12: + return OPCODE_WSR_SCOMPARE1; + case 16: + return OPCODE_WSR_ACCLO; + case 17: + return OPCODE_WSR_ACCHI; + case 32: + return OPCODE_WSR_M0; + case 33: + return OPCODE_WSR_M1; + case 34: + return OPCODE_WSR_M2; + case 35: + return OPCODE_WSR_M3; + case 72: + return OPCODE_WSR_WINDOWBASE; + case 73: + return OPCODE_WSR_WINDOWSTART; + case 83: + return OPCODE_WSR_PTEVADDR; + case 89: + return OPCODE_WSR_MMID; + case 90: + return OPCODE_WSR_RASID; + case 91: + return OPCODE_WSR_ITLBCFG; + case 92: + return OPCODE_WSR_DTLBCFG; + case 96: + return OPCODE_WSR_IBREAKENABLE; + case 99: + return OPCODE_WSR_ATOMCTL; + case 104: + return OPCODE_WSR_DDR; + case 128: + return OPCODE_WSR_IBREAKA0; + case 129: + return OPCODE_WSR_IBREAKA1; + case 144: + return OPCODE_WSR_DBREAKA0; + case 145: + return OPCODE_WSR_DBREAKA1; + case 160: + return OPCODE_WSR_DBREAKC0; + case 161: + return OPCODE_WSR_DBREAKC1; + case 176: + return OPCODE_WSR_176; + case 177: + return OPCODE_WSR_EPC1; + case 178: + return OPCODE_WSR_EPC2; + case 179: + return OPCODE_WSR_EPC3; + case 180: + return OPCODE_WSR_EPC4; + case 181: + return OPCODE_WSR_EPC5; + case 182: + return OPCODE_WSR_EPC6; + case 183: + return OPCODE_WSR_EPC7; + case 192: + return OPCODE_WSR_DEPC; + case 194: + return OPCODE_WSR_EPS2; + case 195: + return OPCODE_WSR_EPS3; + case 196: + return OPCODE_WSR_EPS4; + case 197: + return OPCODE_WSR_EPS5; + case 198: + return OPCODE_WSR_EPS6; + case 199: + return OPCODE_WSR_EPS7; + case 209: + return OPCODE_WSR_EXCSAVE1; + case 210: + return OPCODE_WSR_EXCSAVE2; + case 211: + return OPCODE_WSR_EXCSAVE3; + case 212: + return OPCODE_WSR_EXCSAVE4; + case 213: + return OPCODE_WSR_EXCSAVE5; + case 214: + return OPCODE_WSR_EXCSAVE6; + case 215: + return OPCODE_WSR_EXCSAVE7; + case 224: + return OPCODE_WSR_CPENABLE; + case 226: + return OPCODE_WSR_INTSET; + case 227: + return OPCODE_WSR_INTCLEAR; + case 228: + return OPCODE_WSR_INTENABLE; + case 230: + return OPCODE_WSR_PS; + case 231: + return OPCODE_WSR_VECBASE; + case 232: + return OPCODE_WSR_EXCCAUSE; + case 233: + return OPCODE_WSR_DEBUGCAUSE; + case 234: + return OPCODE_WSR_CCOUNT; + case 236: + return OPCODE_WSR_ICOUNT; + case 237: + return OPCODE_WSR_ICOUNTLEVEL; + case 238: + return OPCODE_WSR_EXCVADDR; + case 240: + return OPCODE_WSR_CCOMPARE0; + case 241: + return OPCODE_WSR_CCOMPARE1; + case 242: + return OPCODE_WSR_CCOMPARE2; + case 244: + return OPCODE_WSR_MISC0; + case 245: + return OPCODE_WSR_MISC1; + } + break; + case 2: + return OPCODE_SEXT; + case 3: + return OPCODE_CLAMPS; + case 4: + return OPCODE_MIN; + case 5: + return OPCODE_MAX; + case 6: + return OPCODE_MINU; + case 7: + return OPCODE_MAXU; + case 8: + return OPCODE_MOVEQZ; + case 9: + return OPCODE_MOVNEZ; + case 10: + return OPCODE_MOVLTZ; + case 11: + return OPCODE_MOVGEZ; + case 14: + switch (Field_st_Slot_inst_get (insn)) + { + case 230: + return OPCODE_RUR_EXPSTATE; + case 231: + return OPCODE_RUR_THREADPTR; + } + break; + case 15: + switch (Field_sr_Slot_inst_get (insn)) + { + case 230: + return OPCODE_WUR_EXPSTATE; + case 231: + return OPCODE_WUR_THREADPTR; + } + break; + } + break; + case 4: + case 5: + return OPCODE_EXTUI; + case 9: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + return OPCODE_L32E; + case 4: + return OPCODE_S32E; + } + break; + } + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_READ_IMPWIRE; + break; + case 1: + if (Field_s3to1_Slot_inst_get (insn) == 0 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_SETB_EXPSTATE; + if (Field_s3to1_Slot_inst_get (insn) == 1 && + Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_CLRB_EXPSTATE; + break; + case 2: + if (Field_op2_Slot_inst_get (insn) == 0 && + Field_op1_Slot_inst_get (insn) == 14) + return OPCODE_WRMSK_EXPSTATE; + break; + } + break; + case 1: + return OPCODE_L32R; + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_L8UI; + case 1: + return OPCODE_L16UI; + case 2: + return OPCODE_L32I; + case 4: + return OPCODE_S8I; + case 5: + return OPCODE_S16I; + case 6: + return OPCODE_S32I; + case 7: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return OPCODE_DPFR; + case 1: + return OPCODE_DPFW; + case 2: + return OPCODE_DPFRO; + case 3: + return OPCODE_DPFWO; + case 4: + return OPCODE_DHWB; + case 5: + return OPCODE_DHWBI; + case 6: + return OPCODE_DHI; + case 7: + return OPCODE_DII; + case 8: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + return OPCODE_DPFL; + case 2: + return OPCODE_DHU; + case 3: + return OPCODE_DIU; + case 4: + return OPCODE_DIWB; + case 5: + return OPCODE_DIWBI; + } + break; + case 12: + return OPCODE_IPF; + case 13: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + return OPCODE_IPFL; + case 2: + return OPCODE_IHU; + case 3: + return OPCODE_IIU; + } + break; + case 14: + return OPCODE_IHI; + case 15: + return OPCODE_III; + } + break; + case 9: + return OPCODE_L16SI; + case 10: + return OPCODE_MOVI; + case 11: + return OPCODE_L32AI; + case 12: + return OPCODE_ADDI; + case 13: + return OPCODE_ADDMI; + case 14: + return OPCODE_S32C1I; + case 15: + return OPCODE_S32RI; + } + break; + case 4: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL_LDINC; + break; + case 9: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL_LDINC; + break; + case 10: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH_LDINC; + break; + case 11: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH_LDINC; + break; + } + break; + case 1: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL_LDDEC; + break; + case 9: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL_LDDEC; + break; + case 10: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH_LDDEC; + break; + case 11: + if (Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH_LDDEC; + break; + } + break; + case 2: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_LL; + break; + case 5: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_HL; + break; + case 6: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_LH; + break; + case 7: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DD_HH; + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LL; + break; + case 9: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HL; + break; + case 10: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_LH; + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DD_HH; + break; + case 12: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_LL; + break; + case 13: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_HL; + break; + case 14: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_LH; + break; + case 15: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DD_HH; + break; + } + break; + case 3: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_LL; + break; + case 5: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_HL; + break; + case 6: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_LH; + break; + case 7: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AD_HH; + break; + case 8: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_LL; + break; + case 9: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_HL; + break; + case 10: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_LH; + break; + case 11: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AD_HH; + break; + case 12: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_LL; + break; + case 13: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_HL; + break; + case 14: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_LH; + break; + case 15: + if (Field_r_Slot_inst_get (insn) == 0 && + Field_t3_Slot_inst_get (insn) == 0 && + Field_tlo_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AD_HH; + break; + } + break; + case 4: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL_LDINC; + break; + case 9: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL_LDINC; + break; + case 10: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH_LDINC; + break; + case 11: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH_LDINC; + break; + } + break; + case 5: + switch (Field_op1_Slot_inst_get (insn)) + { + case 8: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL_LDDEC; + break; + case 9: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL_LDDEC; + break; + case 10: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH_LDDEC; + break; + case 11: + if (Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH_LDDEC; + break; + } + break; + case 6: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_LL; + break; + case 5: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_HL; + break; + case 6: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_LH; + break; + case 7: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MUL_DA_HH; + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LL; + break; + case 9: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HL; + break; + case 10: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_LH; + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULA_DA_HH; + break; + case 12: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_LL; + break; + case 13: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_HL; + break; + case 14: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_LH; + break; + case 15: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_w_Slot_inst_get (insn) == 0 && + Field_r3_Slot_inst_get (insn) == 0) + return OPCODE_MULS_DA_HH; + break; + } + break; + case 7: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_LL; + break; + case 1: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_HL; + break; + case 2: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_LH; + break; + case 3: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_UMUL_AA_HH; + break; + case 4: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_LL; + break; + case 5: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_HL; + break; + case 6: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_LH; + break; + case 7: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MUL_AA_HH; + break; + case 8: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_LL; + break; + case 9: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_HL; + break; + case 10: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_LH; + break; + case 11: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULA_AA_HH; + break; + case 12: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_LL; + break; + case 13: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_HL; + break; + case 14: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_LH; + break; + case 15: + if (Field_r_Slot_inst_get (insn) == 0) + return OPCODE_MULS_AA_HH; + break; + } + break; + case 8: + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return OPCODE_LDINC; + break; + case 9: + if (Field_op1_Slot_inst_get (insn) == 0 && + Field_t_Slot_inst_get (insn) == 0 && + Field_rhi_Slot_inst_get (insn) == 0) + return OPCODE_LDDEC; + break; + } + break; + case 5: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_CALL0; + case 1: + return OPCODE_CALL4; + case 2: + return OPCODE_CALL8; + case 3: + return OPCODE_CALL12; + } + break; + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return OPCODE_J; + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQZ; + case 1: + return OPCODE_BNEZ; + case 2: + return OPCODE_BLTZ; + case 3: + return OPCODE_BGEZ; + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BEQI; + case 1: + return OPCODE_BNEI; + case 2: + return OPCODE_BLTI; + case 3: + return OPCODE_BGEI; + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return OPCODE_ENTRY; + case 1: + switch (Field_r_Slot_inst_get (insn)) + { + case 8: + return OPCODE_LOOP; + case 9: + return OPCODE_LOOPNEZ; + case 10: + return OPCODE_LOOPGTZ; + } + break; + case 2: + return OPCODE_BLTUI; + case 3: + return OPCODE_BGEUI; + } + break; + } + break; + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return OPCODE_BNONE; + case 1: + return OPCODE_BEQ; + case 2: + return OPCODE_BLT; + case 3: + return OPCODE_BLTU; + case 4: + return OPCODE_BALL; + case 5: + return OPCODE_BBC; + case 6: + case 7: + return OPCODE_BBCI; + case 8: + return OPCODE_BANY; + case 9: + return OPCODE_BNE; + case 10: + return OPCODE_BGE; + case 11: + return OPCODE_BGEU; + case 12: + return OPCODE_BNALL; + case 13: + return OPCODE_BBS; + case 14: + case 15: + return OPCODE_BBSI; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOVI_N; + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_BEQZ_N; + case 1: + return OPCODE_BNEZ_N; + } + break; + } + break; + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_MOV_N; + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return OPCODE_RET_N; + case 1: + return OPCODE_RETW_N; + case 2: + return OPCODE_BREAK_N; + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_NOP_N; + break; + case 6: + if (Field_s_Slot_inst16b_get (insn) == 0) + return OPCODE_ILL_N; + break; + } + break; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return OPCODE_L32I_N; + case 9: + return OPCODE_S32I_N; + case 10: + return OPCODE_ADD_N; + case 11: + return OPCODE_ADDI_N; + } + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffff); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff) | (slotbuf[0] & 0xffff); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + Field_mn_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_get, + Field_rbit2_Slot_inst_get, + Field_rhi_Slot_inst_get, + Field_t3_Slot_inst_get, + Field_tbit2_Slot_inst_get, + Field_tlo_Slot_inst_get, + Field_w_Slot_inst_get, + Field_y_Slot_inst_get, + Field_x_Slot_inst_get, + Field_xt_wbr15_imm_Slot_inst_get, + Field_xt_wbr18_imm_Slot_inst_get, + Field_bitindex_Slot_inst_get, + Field_s3to1_Slot_inst_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + Field_mn_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_r3_Slot_inst_set, + Field_rbit2_Slot_inst_set, + Field_rhi_Slot_inst_set, + Field_t3_Slot_inst_set, + Field_tbit2_Slot_inst_set, + Field_tlo_Slot_inst_set, + Field_w_Slot_inst_set, + Field_y_Slot_inst_set, + Field_x_Slot_inst_set, + Field_xt_wbr15_imm_Slot_inst_set, + Field_xt_wbr18_imm_Slot_inst_set, + Field_bitindex_Slot_inst_set, + Field_s3to1_Slot_inst_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + 0, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_get, + Field_s3to1_Slot_inst16a_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + 0, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16a_set, + Field_s3to1_Slot_inst16a_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + 0, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_get, + Field_s3to1_Slot_inst16b_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get, + Implicit_Field_mr0_get, + Implicit_Field_mr1_get, + Implicit_Field_mr2_get, + Implicit_Field_mr3_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + 0, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_bitindex_Slot_inst16b_set, + Field_s3to1_Slot_inst16b_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x8; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x8) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc) == 0x8) + return 1; /* x16a */ + if ((insn[0] & 0xe) == 0xc) + return 2; /* x16b */ + return -1; +} + +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int op0 = insn[0] & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +xtensa_isa_internal xtensa_modules = { + 0 /* little-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 56 /* num_fields */, + 93, operands, + 326, iclasses, + 452, opcodes, 0, + 2, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 1, interfaces, 0, + 0, funcUnits, 0 +}; From 502d0f361b690df7d5b19ed8869d7f465fd51ed1 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 15:46:55 -0700 Subject: [PATCH 251/546] target/xtensa: switch fsf to libisa Autogenerated xtensa-modules.c is added by the import_core.sh script. Signed-off-by: Max Filippov --- target/xtensa/core-fsf.c | 5 + target/xtensa/core-fsf/xtensa-modules.c | 9841 +++++++++++++++++++++++ 2 files changed, 9846 insertions(+) create mode 100644 target/xtensa/core-fsf/xtensa-modules.c diff --git a/target/xtensa/core-fsf.c b/target/xtensa/core-fsf.c index 15ef470e8b..f41de9a1aa 100644 --- a/target/xtensa/core-fsf.c +++ b/target/xtensa/core-fsf.c @@ -29,11 +29,15 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" +#include "qemu-common.h" #include "qemu/host-utils.h" #include "core-fsf/core-isa.h" #include "overlay_tool.h" +#define xtensa_modules xtensa_modules_fsf +#include "core-fsf/xtensa-modules.c" + static XtensaConfig fsf __attribute__((unused)) = { .name = "fsf", .gdb_regmap = { @@ -42,6 +46,7 @@ static XtensaConfig fsf __attribute__((unused)) = { XTREG_END }, }, + .isa_internal = &xtensa_modules, .clock_freq_khz = 10000, DEFAULT_SECTIONS }; diff --git a/target/xtensa/core-fsf/xtensa-modules.c b/target/xtensa/core-fsf/xtensa-modules.c new file mode 100644 index 0000000000..238800d823 --- /dev/null +++ b/target/xtensa/core-fsf/xtensa-modules.c @@ -0,0 +1,9841 @@ +/* Xtensa configuration-specific ISA information. + Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include +#include "xtensa-isa-internal.h" + + +/* Sysregs. */ + +static xtensa_sysreg_internal sysregs[] = { + { "LBEG", 0, 0 }, + { "LEND", 1, 0 }, + { "LCOUNT", 2, 0 }, + { "PTEVADDR", 83, 0 }, + { "DDR", 104, 0 }, + { "176", 176, 0 }, + { "208", 208, 0 }, + { "INTERRUPT", 226, 0 }, + { "INTCLEAR", 227, 0 }, + { "CCOUNT", 234, 0 }, + { "PRID", 235, 0 }, + { "ICOUNT", 236, 0 }, + { "CCOMPARE0", 240, 0 }, + { "CCOMPARE1", 241, 0 }, + { "CCOMPARE2", 242, 0 }, + { "EPC1", 177, 0 }, + { "EPC2", 178, 0 }, + { "EPC3", 179, 0 }, + { "EPC4", 180, 0 }, + { "EXCSAVE1", 209, 0 }, + { "EXCSAVE2", 210, 0 }, + { "EXCSAVE3", 211, 0 }, + { "EXCSAVE4", 212, 0 }, + { "EPS2", 194, 0 }, + { "EPS3", 195, 0 }, + { "EPS4", 196, 0 }, + { "EXCCAUSE", 232, 0 }, + { "DEPC", 192, 0 }, + { "EXCVADDR", 238, 0 }, + { "WINDOWBASE", 72, 0 }, + { "WINDOWSTART", 73, 0 }, + { "SAR", 3, 0 }, + { "LITBASE", 5, 0 }, + { "PS", 230, 0 }, + { "MISC0", 244, 0 }, + { "MISC1", 245, 0 }, + { "INTENABLE", 228, 0 }, + { "DBREAKA0", 144, 0 }, + { "DBREAKC0", 160, 0 }, + { "DBREAKA1", 145, 0 }, + { "DBREAKC1", 161, 0 }, + { "IBREAKA0", 128, 0 }, + { "IBREAKA1", 129, 0 }, + { "IBREAKENABLE", 96, 0 }, + { "ICOUNTLEVEL", 237, 0 }, + { "DEBUGCAUSE", 233, 0 }, + { "RASID", 90, 0 }, + { "ITLBCFG", 91, 0 }, + { "DTLBCFG", 92, 0 } +}; + +#define NUM_SYSREGS 49 +#define MAX_SPECIAL_REG 245 +#define MAX_USER_REG 0 + + +/* Processor states. */ + +static xtensa_state_internal states[] = { + { "LCOUNT", 32, 0 }, + { "PC", 32, 0 }, + { "ICOUNT", 32, 0 }, + { "DDR", 32, 0 }, + { "INTERRUPT", 17, 0 }, + { "CCOUNT", 32, 0 }, + { "XTSYNC", 1, 0 }, + { "EPC1", 32, 0 }, + { "EPC2", 32, 0 }, + { "EPC3", 32, 0 }, + { "EPC4", 32, 0 }, + { "EXCSAVE1", 32, 0 }, + { "EXCSAVE2", 32, 0 }, + { "EXCSAVE3", 32, 0 }, + { "EXCSAVE4", 32, 0 }, + { "EPS2", 15, 0 }, + { "EPS3", 15, 0 }, + { "EPS4", 15, 0 }, + { "EXCCAUSE", 6, 0 }, + { "PSINTLEVEL", 4, 0 }, + { "PSUM", 1, 0 }, + { "PSWOE", 1, 0 }, + { "PSRING", 2, 0 }, + { "PSEXCM", 1, 0 }, + { "DEPC", 32, 0 }, + { "EXCVADDR", 32, 0 }, + { "WindowBase", 4, 0 }, + { "WindowStart", 16, 0 }, + { "PSCALLINC", 2, 0 }, + { "PSOWB", 4, 0 }, + { "LBEG", 32, 0 }, + { "LEND", 32, 0 }, + { "SAR", 6, 0 }, + { "LITBADDR", 20, 0 }, + { "LITBEN", 1, 0 }, + { "MISC0", 32, 0 }, + { "MISC1", 32, 0 }, + { "InOCDMode", 1, 0 }, + { "INTENABLE", 17, 0 }, + { "DBREAKA0", 32, 0 }, + { "DBREAKC0", 8, 0 }, + { "DBREAKA1", 32, 0 }, + { "DBREAKC1", 8, 0 }, + { "IBREAKA0", 32, 0 }, + { "IBREAKA1", 32, 0 }, + { "IBREAKENABLE", 2, 0 }, + { "ICOUNTLEVEL", 4, 0 }, + { "DEBUGCAUSE", 6, 0 }, + { "DBNUM", 4, 0 }, + { "CCOMPARE0", 32, 0 }, + { "CCOMPARE1", 32, 0 }, + { "CCOMPARE2", 32, 0 }, + { "ASID3", 8, 0 }, + { "ASID2", 8, 0 }, + { "ASID1", 8, 0 }, + { "INSTPGSZID4", 2, 0 }, + { "DATAPGSZID4", 2, 0 }, + { "PTBASE", 10, 0 } +}; + +#define NUM_STATES 58 + +/* Macros for xtensa_state numbers (for use in iclasses because the + state numbers are not available when the iclass table is generated). */ + +#define STATE_LCOUNT 0 +#define STATE_PC 1 +#define STATE_ICOUNT 2 +#define STATE_DDR 3 +#define STATE_INTERRUPT 4 +#define STATE_CCOUNT 5 +#define STATE_XTSYNC 6 +#define STATE_EPC1 7 +#define STATE_EPC2 8 +#define STATE_EPC3 9 +#define STATE_EPC4 10 +#define STATE_EXCSAVE1 11 +#define STATE_EXCSAVE2 12 +#define STATE_EXCSAVE3 13 +#define STATE_EXCSAVE4 14 +#define STATE_EPS2 15 +#define STATE_EPS3 16 +#define STATE_EPS4 17 +#define STATE_EXCCAUSE 18 +#define STATE_PSINTLEVEL 19 +#define STATE_PSUM 20 +#define STATE_PSWOE 21 +#define STATE_PSRING 22 +#define STATE_PSEXCM 23 +#define STATE_DEPC 24 +#define STATE_EXCVADDR 25 +#define STATE_WindowBase 26 +#define STATE_WindowStart 27 +#define STATE_PSCALLINC 28 +#define STATE_PSOWB 29 +#define STATE_LBEG 30 +#define STATE_LEND 31 +#define STATE_SAR 32 +#define STATE_LITBADDR 33 +#define STATE_LITBEN 34 +#define STATE_MISC0 35 +#define STATE_MISC1 36 +#define STATE_InOCDMode 37 +#define STATE_INTENABLE 38 +#define STATE_DBREAKA0 39 +#define STATE_DBREAKC0 40 +#define STATE_DBREAKA1 41 +#define STATE_DBREAKC1 42 +#define STATE_IBREAKA0 43 +#define STATE_IBREAKA1 44 +#define STATE_IBREAKENABLE 45 +#define STATE_ICOUNTLEVEL 46 +#define STATE_DEBUGCAUSE 47 +#define STATE_DBNUM 48 +#define STATE_CCOMPARE0 49 +#define STATE_CCOMPARE1 50 +#define STATE_CCOMPARE2 51 +#define STATE_ASID3 52 +#define STATE_ASID2 53 +#define STATE_ASID1 54 +#define STATE_INSTPGSZID4 55 +#define STATE_DATAPGSZID4 56 +#define STATE_PTBASE 57 + + +/* Field definitions. */ + +static unsigned +Field_t_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); +} + +static unsigned +Field_s_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_r_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_op2_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_op2_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op1_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_op1_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_op0_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 8) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00000) | (tie_t << 20); +} + +static unsigned +Field_n_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 12) >> 30); + return tie_t; +} + +static void +Field_n_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0xc0000) | (tie_t << 18); +} + +static unsigned +Field_m_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 14) >> 30); + return tie_t; +} + +static void +Field_m_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30000) | (tie_t << 16); +} + +static unsigned +Field_sr_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_thi3_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 12) >> 29); + return tie_t; +} + +static void +Field_thi3_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0xe0000) | (tie_t << 17); +} + +static unsigned +Field_op0_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_t_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_r_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_op0_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_op0_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_z_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 21) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x400) | (tie_t << 10); +} + +static unsigned +Field_i_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); +} + +static unsigned +Field_s_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_t_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_t_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_bbi4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + return tie_t; +} + +static void +Field_bbi4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_bbi_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 23) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_bbi_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x100) | (tie_t << 8); +} + +static unsigned +Field_imm12_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 12) | ((insn[0] << 20) >> 20); + return tie_t; +} + +static void +Field_imm12_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 20) >> 20; + insn[0] = (insn[0] & ~0xfff) | (tie_t << 0); +} + +static unsigned +Field_imm8_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 8) | ((insn[0] << 24) >> 24); + return tie_t; +} + +static void +Field_imm8_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff) | (tie_t << 0); +} + +static unsigned +Field_s_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + return tie_t; +} + +static void +Field_s_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_imm12b_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 8) | ((insn[0] << 24) >> 24); + return tie_t; +} + +static void +Field_imm12b_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 24) >> 24; + insn[0] = (insn[0] & ~0xff) | (tie_t << 0); + tie_t = (val << 20) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_imm16_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 16) | ((insn[0] << 16) >> 16); + return tie_t; +} + +static void +Field_imm16_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 16) >> 16; + insn[0] = (insn[0] & ~0xffff) | (tie_t << 0); +} + +static unsigned +Field_offset_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 18) | ((insn[0] << 14) >> 14); + return tie_t; +} + +static void +Field_offset_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 14) >> 14; + insn[0] = (insn[0] & ~0x3ffff) | (tie_t << 0); +} + +static unsigned +Field_r_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_r_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_sa4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + return tie_t; +} + +static void +Field_sa4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); +} + +static unsigned +Field_sae4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + return tie_t; +} + +static void +Field_sae4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sae_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 27) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_sae_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10) | (tie_t << 4); +} + +static unsigned +Field_sal_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_sal_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); +} + +static unsigned +Field_sargt_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 31) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_sargt_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x1) | (tie_t << 0); +} + +static unsigned +Field_sas4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + return tie_t; +} + +static void +Field_sas4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sas_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 15) >> 31); + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + return tie_t; +} + +static void +Field_sas_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); + tie_t = (val << 27) >> 31; + insn[0] = (insn[0] & ~0x10000) | (tie_t << 16); +} + +static unsigned +Field_sr_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_sr_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_sr_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_st_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 16) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 12) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf0000) | (tie_t << 16); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf000) | (tie_t << 12); +} + +static unsigned +Field_st_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_st_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 24) >> 28); + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_st_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); + tie_t = (val << 24) >> 28; + insn[0] = (insn[0] & ~0xf0) | (tie_t << 4); +} + +static unsigned +Field_imm4_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 20) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf00) | (tie_t << 8); +} + +static unsigned +Field_imm4_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_imm4_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm4_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_mn_Slot_inst_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 12) >> 30); + tie_t = (tie_t << 2) | ((insn[0] << 14) >> 30); + return tie_t; +} + +static void +Field_mn_Slot_inst_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x30000) | (tie_t << 16); + tie_t = (val << 28) >> 30; + insn[0] = (insn[0] & ~0xc0000) | (tie_t << 18); +} + +static unsigned +Field_i_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 20) >> 31); + return tie_t; +} + +static void +Field_i_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x800) | (tie_t << 11); +} + +static unsigned +Field_imm6lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_imm6lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm6lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_imm6hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); +} + +static unsigned +Field_imm6hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + return tie_t; +} + +static void +Field_imm6hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 30) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); +} + +static unsigned +Field_imm7lo_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_imm7lo_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm7lo_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); +} + +static unsigned +Field_imm7hi_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); +} + +static unsigned +Field_imm7hi_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + return tie_t; +} + +static void +Field_imm7hi_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 29) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); +} + +static unsigned +Field_z_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 1) | ((insn[0] << 21) >> 31); + return tie_t; +} + +static void +Field_z_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 31) >> 31; + insn[0] = (insn[0] & ~0x400) | (tie_t << 10); +} + +static unsigned +Field_imm6_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); +} + +static unsigned +Field_imm6_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 2) | ((insn[0] << 22) >> 30); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm6_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 26) >> 30; + insn[0] = (insn[0] & ~0x300) | (tie_t << 8); +} + +static unsigned +Field_imm7_Slot_inst16a_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16a_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); +} + +static unsigned +Field_imm7_Slot_inst16b_get (const xtensa_insnbuf insn) +{ + unsigned tie_t = 0; + tie_t = (tie_t << 3) | ((insn[0] << 21) >> 29); + tie_t = (tie_t << 4) | ((insn[0] << 28) >> 28); + return tie_t; +} + +static void +Field_imm7_Slot_inst16b_set (xtensa_insnbuf insn, uint32 val) +{ + uint32 tie_t; + tie_t = (val << 28) >> 28; + insn[0] = (insn[0] & ~0xf) | (tie_t << 0); + tie_t = (val << 25) >> 29; + insn[0] = (insn[0] & ~0x700) | (tie_t << 8); +} + +static void +Implicit_Field_set (xtensa_insnbuf insn ATTRIBUTE_UNUSED, + uint32 val ATTRIBUTE_UNUSED) +{ + /* Do nothing. */ +} + +static unsigned +Implicit_Field_ar0_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 0; +} + +static unsigned +Implicit_Field_ar4_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 4; +} + +static unsigned +Implicit_Field_ar8_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 8; +} + +static unsigned +Implicit_Field_ar12_get (const xtensa_insnbuf insn ATTRIBUTE_UNUSED) +{ + return 12; +} + + +/* Functional units. */ + +static xtensa_funcUnit_internal funcUnits[] = { + +}; + + +/* Register files. */ + +static xtensa_regfile_internal regfiles[] = { + { "AR", "a", 0, 32, 64 } +}; + + +/* Interfaces. */ + +static xtensa_interface_internal interfaces[] = { + +}; + + +/* Constant tables. */ + +/* constant table ai4c */ +static const unsigned CONST_TBL_ai4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xa, + 0xb, + 0xc, + 0xd, + 0xe, + 0xf, + 0 +}; + +/* constant table b4c */ +static const unsigned CONST_TBL_b4c_0[] = { + 0xffffffff, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + +/* constant table b4cu */ +static const unsigned CONST_TBL_b4cu_0[] = { + 0x8000, + 0x10000, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0xa, + 0xc, + 0x10, + 0x20, + 0x40, + 0x80, + 0x100, + 0 +}; + + +/* Instruction operands. */ + +static int +Operand_soffsetx4_decode (uint32 *valp) +{ + unsigned soffsetx4_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffsetx4_0 = 0x4 + ((((int) offset_0 << 14) >> 14) << 2); + *valp = soffsetx4_0; + return 0; +} + +static int +Operand_soffsetx4_encode (uint32 *valp) +{ + unsigned offset_0, soffsetx4_0; + soffsetx4_0 = *valp; + offset_0 = ((soffsetx4_0 - 0x4) >> 2) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffsetx4_ator (uint32 *valp, uint32 pc) +{ + *valp -= (pc & ~0x3); + return 0; +} + +static int +Operand_soffsetx4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += (pc & ~0x3); + return 0; +} + +static int +Operand_uimm12x8_decode (uint32 *valp) +{ + unsigned uimm12x8_0, imm12_0; + imm12_0 = *valp & 0xfff; + uimm12x8_0 = imm12_0 << 3; + *valp = uimm12x8_0; + return 0; +} + +static int +Operand_uimm12x8_encode (uint32 *valp) +{ + unsigned imm12_0, uimm12x8_0; + uimm12x8_0 = *valp; + imm12_0 = ((uimm12x8_0 >> 3) & 0xfff); + *valp = imm12_0; + return 0; +} + +static int +Operand_simm4_decode (uint32 *valp) +{ + unsigned simm4_0, mn_0; + mn_0 = *valp & 0xf; + simm4_0 = ((int) mn_0 << 28) >> 28; + *valp = simm4_0; + return 0; +} + +static int +Operand_simm4_encode (uint32 *valp) +{ + unsigned mn_0, simm4_0; + simm4_0 = *valp; + mn_0 = (simm4_0 & 0xf); + *valp = mn_0; + return 0; +} + +static int +Operand_arr_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_arr_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ars_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_art_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_art_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0xf) != 0; + return error; +} + +static int +Operand_ar0_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar0_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; +} + +static int +Operand_ar4_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar4_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; +} + +static int +Operand_ar8_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar8_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; +} + +static int +Operand_ar12_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ar12_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; +} + +static int +Operand_ars_entry_decode (uint32 *valp ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +Operand_ars_entry_encode (uint32 *valp) +{ + int error; + error = (*valp & ~0x3f) != 0; + return error; +} + +static int +Operand_immrx4_decode (uint32 *valp) +{ + unsigned immrx4_0, r_0; + r_0 = *valp & 0xf; + immrx4_0 = ((((0xfffffff)) << 4) | r_0) << 2; + *valp = immrx4_0; + return 0; +} + +static int +Operand_immrx4_encode (uint32 *valp) +{ + unsigned r_0, immrx4_0; + immrx4_0 = *valp; + r_0 = ((immrx4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_lsi4x4_decode (uint32 *valp) +{ + unsigned lsi4x4_0, r_0; + r_0 = *valp & 0xf; + lsi4x4_0 = r_0 << 2; + *valp = lsi4x4_0; + return 0; +} + +static int +Operand_lsi4x4_encode (uint32 *valp) +{ + unsigned r_0, lsi4x4_0; + lsi4x4_0 = *valp; + r_0 = ((lsi4x4_0 >> 2) & 0xf); + *valp = r_0; + return 0; +} + +static int +Operand_simm7_decode (uint32 *valp) +{ + unsigned simm7_0, imm7_0; + imm7_0 = *valp & 0x7f; + simm7_0 = ((((-((((imm7_0 >> 6) & 1)) & (((imm7_0 >> 5) & 1)))) & 0x1ffffff)) << 7) | imm7_0; + *valp = simm7_0; + return 0; +} + +static int +Operand_simm7_encode (uint32 *valp) +{ + unsigned imm7_0, simm7_0; + simm7_0 = *valp; + imm7_0 = (simm7_0 & 0x7f); + *valp = imm7_0; + return 0; +} + +static int +Operand_uimm6_decode (uint32 *valp) +{ + unsigned uimm6_0, imm6_0; + imm6_0 = *valp & 0x3f; + uimm6_0 = 0x4 + ((((0)) << 6) | imm6_0); + *valp = uimm6_0; + return 0; +} + +static int +Operand_uimm6_encode (uint32 *valp) +{ + unsigned imm6_0, uimm6_0; + uimm6_0 = *valp; + imm6_0 = (uimm6_0 - 0x4) & 0x3f; + *valp = imm6_0; + return 0; +} + +static int +Operand_uimm6_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_uimm6_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ai4const_decode (uint32 *valp) +{ + unsigned ai4const_0, t_0; + t_0 = *valp & 0xf; + ai4const_0 = CONST_TBL_ai4c_0[t_0 & 0xf]; + *valp = ai4const_0; + return 0; +} + +static int +Operand_ai4const_encode (uint32 *valp) +{ + unsigned t_0, ai4const_0; + ai4const_0 = *valp; + switch (ai4const_0) + { + case 0xffffffff: t_0 = 0; break; + case 0x1: t_0 = 0x1; break; + case 0x2: t_0 = 0x2; break; + case 0x3: t_0 = 0x3; break; + case 0x4: t_0 = 0x4; break; + case 0x5: t_0 = 0x5; break; + case 0x6: t_0 = 0x6; break; + case 0x7: t_0 = 0x7; break; + case 0x8: t_0 = 0x8; break; + case 0x9: t_0 = 0x9; break; + case 0xa: t_0 = 0xa; break; + case 0xb: t_0 = 0xb; break; + case 0xc: t_0 = 0xc; break; + case 0xd: t_0 = 0xd; break; + case 0xe: t_0 = 0xe; break; + default: t_0 = 0xf; break; + } + *valp = t_0; + return 0; +} + +static int +Operand_b4const_decode (uint32 *valp) +{ + unsigned b4const_0, r_0; + r_0 = *valp & 0xf; + b4const_0 = CONST_TBL_b4c_0[r_0 & 0xf]; + *valp = b4const_0; + return 0; +} + +static int +Operand_b4const_encode (uint32 *valp) +{ + unsigned r_0, b4const_0; + b4const_0 = *valp; + switch (b4const_0) + { + case 0xffffffff: r_0 = 0; break; + case 0x1: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_b4constu_decode (uint32 *valp) +{ + unsigned b4constu_0, r_0; + r_0 = *valp & 0xf; + b4constu_0 = CONST_TBL_b4cu_0[r_0 & 0xf]; + *valp = b4constu_0; + return 0; +} + +static int +Operand_b4constu_encode (uint32 *valp) +{ + unsigned r_0, b4constu_0; + b4constu_0 = *valp; + switch (b4constu_0) + { + case 0x8000: r_0 = 0; break; + case 0x10000: r_0 = 0x1; break; + case 0x2: r_0 = 0x2; break; + case 0x3: r_0 = 0x3; break; + case 0x4: r_0 = 0x4; break; + case 0x5: r_0 = 0x5; break; + case 0x6: r_0 = 0x6; break; + case 0x7: r_0 = 0x7; break; + case 0x8: r_0 = 0x8; break; + case 0xa: r_0 = 0x9; break; + case 0xc: r_0 = 0xa; break; + case 0x10: r_0 = 0xb; break; + case 0x20: r_0 = 0xc; break; + case 0x40: r_0 = 0xd; break; + case 0x80: r_0 = 0xe; break; + default: r_0 = 0xf; break; + } + *valp = r_0; + return 0; +} + +static int +Operand_uimm8_decode (uint32 *valp) +{ + unsigned uimm8_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8_0 = imm8_0; + *valp = uimm8_0; + return 0; +} + +static int +Operand_uimm8_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8_0; + uimm8_0 = *valp; + imm8_0 = (uimm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x2_decode (uint32 *valp) +{ + unsigned uimm8x2_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x2_0 = imm8_0 << 1; + *valp = uimm8x2_0; + return 0; +} + +static int +Operand_uimm8x2_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x2_0; + uimm8x2_0 = *valp; + imm8_0 = ((uimm8x2_0 >> 1) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm8x4_decode (uint32 *valp) +{ + unsigned uimm8x4_0, imm8_0; + imm8_0 = *valp & 0xff; + uimm8x4_0 = imm8_0 << 2; + *valp = uimm8x4_0; + return 0; +} + +static int +Operand_uimm8x4_encode (uint32 *valp) +{ + unsigned imm8_0, uimm8x4_0; + uimm8x4_0 = *valp; + imm8_0 = ((uimm8x4_0 >> 2) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_uimm4x16_decode (uint32 *valp) +{ + unsigned uimm4x16_0, op2_0; + op2_0 = *valp & 0xf; + uimm4x16_0 = op2_0 << 4; + *valp = uimm4x16_0; + return 0; +} + +static int +Operand_uimm4x16_encode (uint32 *valp) +{ + unsigned op2_0, uimm4x16_0; + uimm4x16_0 = *valp; + op2_0 = ((uimm4x16_0 >> 4) & 0xf); + *valp = op2_0; + return 0; +} + +static int +Operand_simm8_decode (uint32 *valp) +{ + unsigned simm8_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8_0 = ((int) imm8_0 << 24) >> 24; + *valp = simm8_0; + return 0; +} + +static int +Operand_simm8_encode (uint32 *valp) +{ + unsigned imm8_0, simm8_0; + simm8_0 = *valp; + imm8_0 = (simm8_0 & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm8x256_decode (uint32 *valp) +{ + unsigned simm8x256_0, imm8_0; + imm8_0 = *valp & 0xff; + simm8x256_0 = (((int) imm8_0 << 24) >> 24) << 8; + *valp = simm8x256_0; + return 0; +} + +static int +Operand_simm8x256_encode (uint32 *valp) +{ + unsigned imm8_0, simm8x256_0; + simm8x256_0 = *valp; + imm8_0 = ((simm8x256_0 >> 8) & 0xff); + *valp = imm8_0; + return 0; +} + +static int +Operand_simm12b_decode (uint32 *valp) +{ + unsigned simm12b_0, imm12b_0; + imm12b_0 = *valp & 0xfff; + simm12b_0 = ((int) imm12b_0 << 20) >> 20; + *valp = simm12b_0; + return 0; +} + +static int +Operand_simm12b_encode (uint32 *valp) +{ + unsigned imm12b_0, simm12b_0; + simm12b_0 = *valp; + imm12b_0 = (simm12b_0 & 0xfff); + *valp = imm12b_0; + return 0; +} + +static int +Operand_msalp32_decode (uint32 *valp) +{ + unsigned msalp32_0, sal_0; + sal_0 = *valp & 0x1f; + msalp32_0 = 0x20 - sal_0; + *valp = msalp32_0; + return 0; +} + +static int +Operand_msalp32_encode (uint32 *valp) +{ + unsigned sal_0, msalp32_0; + msalp32_0 = *valp; + sal_0 = (0x20 - msalp32_0) & 0x1f; + *valp = sal_0; + return 0; +} + +static int +Operand_op2p1_decode (uint32 *valp) +{ + unsigned op2p1_0, op2_0; + op2_0 = *valp & 0xf; + op2p1_0 = op2_0 + 0x1; + *valp = op2p1_0; + return 0; +} + +static int +Operand_op2p1_encode (uint32 *valp) +{ + unsigned op2_0, op2p1_0; + op2p1_0 = *valp; + op2_0 = (op2p1_0 - 0x1) & 0xf; + *valp = op2_0; + return 0; +} + +static int +Operand_label8_decode (uint32 *valp) +{ + unsigned label8_0, imm8_0; + imm8_0 = *valp & 0xff; + label8_0 = 0x4 + (((int) imm8_0 << 24) >> 24); + *valp = label8_0; + return 0; +} + +static int +Operand_label8_encode (uint32 *valp) +{ + unsigned imm8_0, label8_0; + label8_0 = *valp; + imm8_0 = (label8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_label8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_ulabel8_decode (uint32 *valp) +{ + unsigned ulabel8_0, imm8_0; + imm8_0 = *valp & 0xff; + ulabel8_0 = 0x4 + ((((0)) << 8) | imm8_0); + *valp = ulabel8_0; + return 0; +} + +static int +Operand_ulabel8_encode (uint32 *valp) +{ + unsigned imm8_0, ulabel8_0; + ulabel8_0 = *valp; + imm8_0 = (ulabel8_0 - 0x4) & 0xff; + *valp = imm8_0; + return 0; +} + +static int +Operand_ulabel8_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_ulabel8_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_label12_decode (uint32 *valp) +{ + unsigned label12_0, imm12_0; + imm12_0 = *valp & 0xfff; + label12_0 = 0x4 + (((int) imm12_0 << 20) >> 20); + *valp = label12_0; + return 0; +} + +static int +Operand_label12_encode (uint32 *valp) +{ + unsigned imm12_0, label12_0; + label12_0 = *valp; + imm12_0 = (label12_0 - 0x4) & 0xfff; + *valp = imm12_0; + return 0; +} + +static int +Operand_label12_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_label12_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_soffset_decode (uint32 *valp) +{ + unsigned soffset_0, offset_0; + offset_0 = *valp & 0x3ffff; + soffset_0 = 0x4 + (((int) offset_0 << 14) >> 14); + *valp = soffset_0; + return 0; +} + +static int +Operand_soffset_encode (uint32 *valp) +{ + unsigned offset_0, soffset_0; + soffset_0 = *valp; + offset_0 = (soffset_0 - 0x4) & 0x3ffff; + *valp = offset_0; + return 0; +} + +static int +Operand_soffset_ator (uint32 *valp, uint32 pc) +{ + *valp -= pc; + return 0; +} + +static int +Operand_soffset_rtoa (uint32 *valp, uint32 pc) +{ + *valp += pc; + return 0; +} + +static int +Operand_uimm16x4_decode (uint32 *valp) +{ + unsigned uimm16x4_0, imm16_0; + imm16_0 = *valp & 0xffff; + uimm16x4_0 = ((((0xffff)) << 16) | imm16_0) << 2; + *valp = uimm16x4_0; + return 0; +} + +static int +Operand_uimm16x4_encode (uint32 *valp) +{ + unsigned imm16_0, uimm16x4_0; + uimm16x4_0 = *valp; + imm16_0 = (uimm16x4_0 >> 2) & 0xffff; + *valp = imm16_0; + return 0; +} + +static int +Operand_uimm16x4_ator (uint32 *valp, uint32 pc) +{ + *valp -= ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_uimm16x4_rtoa (uint32 *valp, uint32 pc) +{ + *valp += ((pc + 3) & ~0x3); + return 0; +} + +static int +Operand_immt_decode (uint32 *valp) +{ + unsigned immt_0, t_0; + t_0 = *valp & 0xf; + immt_0 = t_0; + *valp = immt_0; + return 0; +} + +static int +Operand_immt_encode (uint32 *valp) +{ + unsigned t_0, immt_0; + immt_0 = *valp; + t_0 = immt_0 & 0xf; + *valp = t_0; + return 0; +} + +static int +Operand_imms_decode (uint32 *valp) +{ + unsigned imms_0, s_0; + s_0 = *valp & 0xf; + imms_0 = s_0; + *valp = imms_0; + return 0; +} + +static int +Operand_imms_encode (uint32 *valp) +{ + unsigned s_0, imms_0; + imms_0 = *valp; + s_0 = imms_0 & 0xf; + *valp = s_0; + return 0; +} + +static xtensa_operand_internal operands[] = { + { "soffsetx4", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffsetx4_encode, Operand_soffsetx4_decode, + Operand_soffsetx4_ator, Operand_soffsetx4_rtoa }, + { "uimm12x8", 3, -1, 0, + 0, + Operand_uimm12x8_encode, Operand_uimm12x8_decode, + 0, 0 }, + { "simm4", 26, -1, 0, + 0, + Operand_simm4_encode, Operand_simm4_decode, + 0, 0 }, + { "arr", 14, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_arr_encode, Operand_arr_decode, + 0, 0 }, + { "ars", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "*ars_invisible", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ars_encode, Operand_ars_decode, + 0, 0 }, + { "art", 0, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_art_encode, Operand_art_decode, + 0, 0 }, + { "ar0", 35, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar0_encode, Operand_ar0_decode, + 0, 0 }, + { "ar4", 36, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar4_encode, Operand_ar4_decode, + 0, 0 }, + { "ar8", 37, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar8_encode, Operand_ar8_decode, + 0, 0 }, + { "ar12", 38, 0, 1, + XTENSA_OPERAND_IS_REGISTER | XTENSA_OPERAND_IS_INVISIBLE, + Operand_ar12_encode, Operand_ar12_decode, + 0, 0 }, + { "ars_entry", 5, 0, 1, + XTENSA_OPERAND_IS_REGISTER, + Operand_ars_entry_encode, Operand_ars_entry_decode, + 0, 0 }, + { "immrx4", 14, -1, 0, + 0, + Operand_immrx4_encode, Operand_immrx4_decode, + 0, 0 }, + { "lsi4x4", 14, -1, 0, + 0, + Operand_lsi4x4_encode, Operand_lsi4x4_decode, + 0, 0 }, + { "simm7", 34, -1, 0, + 0, + Operand_simm7_encode, Operand_simm7_decode, + 0, 0 }, + { "uimm6", 33, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm6_encode, Operand_uimm6_decode, + Operand_uimm6_ator, Operand_uimm6_rtoa }, + { "ai4const", 0, -1, 0, + 0, + Operand_ai4const_encode, Operand_ai4const_decode, + 0, 0 }, + { "b4const", 14, -1, 0, + 0, + Operand_b4const_encode, Operand_b4const_decode, + 0, 0 }, + { "b4constu", 14, -1, 0, + 0, + Operand_b4constu_encode, Operand_b4constu_decode, + 0, 0 }, + { "uimm8", 4, -1, 0, + 0, + Operand_uimm8_encode, Operand_uimm8_decode, + 0, 0 }, + { "uimm8x2", 4, -1, 0, + 0, + Operand_uimm8x2_encode, Operand_uimm8x2_decode, + 0, 0 }, + { "uimm8x4", 4, -1, 0, + 0, + Operand_uimm8x4_encode, Operand_uimm8x4_decode, + 0, 0 }, + { "uimm4x16", 13, -1, 0, + 0, + Operand_uimm4x16_encode, Operand_uimm4x16_decode, + 0, 0 }, + { "simm8", 4, -1, 0, + 0, + Operand_simm8_encode, Operand_simm8_decode, + 0, 0 }, + { "simm8x256", 4, -1, 0, + 0, + Operand_simm8x256_encode, Operand_simm8x256_decode, + 0, 0 }, + { "simm12b", 6, -1, 0, + 0, + Operand_simm12b_encode, Operand_simm12b_decode, + 0, 0 }, + { "msalp32", 18, -1, 0, + 0, + Operand_msalp32_encode, Operand_msalp32_decode, + 0, 0 }, + { "op2p1", 13, -1, 0, + 0, + Operand_op2p1_encode, Operand_op2p1_decode, + 0, 0 }, + { "label8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label8_encode, Operand_label8_decode, + Operand_label8_ator, Operand_label8_rtoa }, + { "ulabel8", 4, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_ulabel8_encode, Operand_ulabel8_decode, + Operand_ulabel8_ator, Operand_ulabel8_rtoa }, + { "label12", 3, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_label12_encode, Operand_label12_decode, + Operand_label12_ator, Operand_label12_rtoa }, + { "soffset", 10, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_soffset_encode, Operand_soffset_decode, + Operand_soffset_ator, Operand_soffset_rtoa }, + { "uimm16x4", 7, -1, 0, + XTENSA_OPERAND_IS_PCRELATIVE, + Operand_uimm16x4_encode, Operand_uimm16x4_decode, + Operand_uimm16x4_ator, Operand_uimm16x4_rtoa }, + { "immt", 0, -1, 0, + 0, + Operand_immt_encode, Operand_immt_decode, + 0, 0 }, + { "imms", 5, -1, 0, + 0, + Operand_imms_encode, Operand_imms_decode, + 0, 0 }, + { "t", 0, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi4", 1, -1, 0, 0, 0, 0, 0, 0 }, + { "bbi", 2, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12", 3, -1, 0, 0, 0, 0, 0, 0 }, + { "imm8", 4, -1, 0, 0, 0, 0, 0, 0 }, + { "s", 5, -1, 0, 0, 0, 0, 0, 0 }, + { "imm12b", 6, -1, 0, 0, 0, 0, 0, 0 }, + { "imm16", 7, -1, 0, 0, 0, 0, 0, 0 }, + { "m", 8, -1, 0, 0, 0, 0, 0, 0 }, + { "n", 9, -1, 0, 0, 0, 0, 0, 0 }, + { "offset", 10, -1, 0, 0, 0, 0, 0, 0 }, + { "op0", 11, -1, 0, 0, 0, 0, 0, 0 }, + { "op1", 12, -1, 0, 0, 0, 0, 0, 0 }, + { "op2", 13, -1, 0, 0, 0, 0, 0, 0 }, + { "r", 14, -1, 0, 0, 0, 0, 0, 0 }, + { "sa4", 15, -1, 0, 0, 0, 0, 0, 0 }, + { "sae4", 16, -1, 0, 0, 0, 0, 0, 0 }, + { "sae", 17, -1, 0, 0, 0, 0, 0, 0 }, + { "sal", 18, -1, 0, 0, 0, 0, 0, 0 }, + { "sargt", 19, -1, 0, 0, 0, 0, 0, 0 }, + { "sas4", 20, -1, 0, 0, 0, 0, 0, 0 }, + { "sas", 21, -1, 0, 0, 0, 0, 0, 0 }, + { "sr", 22, -1, 0, 0, 0, 0, 0, 0 }, + { "st", 23, -1, 0, 0, 0, 0, 0, 0 }, + { "thi3", 24, -1, 0, 0, 0, 0, 0, 0 }, + { "imm4", 25, -1, 0, 0, 0, 0, 0, 0 }, + { "mn", 26, -1, 0, 0, 0, 0, 0, 0 }, + { "i", 27, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6lo", 28, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6hi", 29, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7lo", 30, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7hi", 31, -1, 0, 0, 0, 0, 0, 0 }, + { "z", 32, -1, 0, 0, 0, 0, 0, 0 }, + { "imm6", 33, -1, 0, 0, 0, 0, 0, 0 }, + { "imm7", 34, -1, 0, 0, 0, 0, 0, 0 } +}; + + +/* Iclass table. */ + +static xtensa_arg_internal Iclass_xt_iclass_rfe_stateArgs[] = { + { { STATE_PSRING }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfde_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 10 /* ar12 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx12_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 9 /* ar8 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx8_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 8 /* ar4 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx4_stateArgs[] = { + { { STATE_PSCALLINC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_args[] = { + { { 11 /* ars_entry */ }, 's' }, + { { 4 /* ars */ }, 'i' }, + { { 1 /* uimm12x8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_entry_stateArgs[] = { + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movsp_stateArgs[] = { + { { STATE_WindowBase }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_args[] = { + { { 2 /* simm4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rotw_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retw_stateArgs[] = { + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSWOE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfwou_stateArgs[] = { + { { STATE_EPC1 }, 'i' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' }, + { { STATE_WindowStart }, 'm' }, + { { STATE_PSOWB }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 12 /* immrx4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32e_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowbase_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowBase }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_windowstart_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_WindowStart }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_add_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_n_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 16 /* ai4const */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bz6_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 15 /* uimm6 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loadi4_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_mov_n_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_n_args[] = { + { { 4 /* ars */ }, 'o' }, + { { 14 /* simm7 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_retn_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_storei4_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 13 /* lsi4x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 23 /* simm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addmi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 24 /* simm8x256 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_addsub_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bit_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 17 /* b4const */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8b_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 37 /* bbi */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsi8u_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 18 /* b4constu */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bst8_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' }, + { { 28 /* label8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_bsz12_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 30 /* label12 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_call0_args[] = { + { { 0 /* soffsetx4 */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_callx0_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 7 /* ar0 */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_exti_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 52 /* sae */ }, 'i' }, + { { 27 /* op2p1 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jump_args[] = { + { { 31 /* soffset */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_jumpx_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16ui_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l16si_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_args[] = { + { { 6 /* art */ }, 'o' }, + { { 32 /* uimm16x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l32r_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_l8i_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loop_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 29 /* ulabel8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_loopz_stateArgs[] = { + { { STATE_LBEG }, 'o' }, + { { STATE_LEND }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movi_args[] = { + { { 6 /* art */ }, 'o' }, + { { 25 /* simm12b */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_movz_args[] = { + { { 3 /* arr */ }, 'm' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_neg_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_return_args[] = { + { { 5 /* *ars_invisible */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s16i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 20 /* uimm8x2 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s32i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_s8i_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' }, + { { 19 /* uimm8 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sar_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_args[] = { + { { 56 /* sas */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sari_stateArgs[] = { + { { STATE_SAR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shifts_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftst_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_shiftt_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_slli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 4 /* ars */ }, 'i' }, + { { 26 /* msalp32 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srai_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 54 /* sargt */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_srli_args[] = { + { { 3 /* arr */ }, 'o' }, + { { 6 /* art */ }, 'i' }, + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sync_stateArgs[] = { + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_args[] = { + { { 6 /* art */ }, 'o' }, + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsil_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lend_stateArgs[] = { + { { STATE_LEND }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lend_stateArgs[] = { + { { STATE_LEND }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lend_stateArgs[] = { + { { STATE_LEND }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lcount_stateArgs[] = { + { { STATE_LCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lcount_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_LCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_lbeg_stateArgs[] = { + { { STATE_LBEG }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_sar_stateArgs[] = { + { { STATE_SAR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_sar_stateArgs[] = { + { { STATE_SAR }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_sar_stateArgs[] = { + { { STATE_SAR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'i' }, + { { STATE_LITBEN }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'o' }, + { { STATE_LITBEN }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_litbase_stateArgs[] = { + { { STATE_LITBADDR }, 'm' }, + { { STATE_LITBEN }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_176_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_208_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'i' }, + { { STATE_PSCALLINC }, 'i' }, + { { STATE_PSOWB }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSUM }, 'i' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ps_stateArgs[] = { + { { STATE_PSWOE }, 'm' }, + { { STATE_PSCALLINC }, 'm' }, + { { STATE_PSOWB }, 'm' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'm' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_epc4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPC4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excsave4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCSAVE4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS2 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps3_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS3 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_eps4_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EPS4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_excvaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCVADDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_depc_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEPC }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'i' }, + { { STATE_XTSYNC }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_exccause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_EXCCAUSE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_misc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_MISC1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_prid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_args[] = { + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfi_stateArgs[] = { + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'm' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'm' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPC1 }, 'i' }, + { { STATE_EPC2 }, 'i' }, + { { STATE_EPC3 }, 'i' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_EPS2 }, 'i' }, + { { STATE_EPS3 }, 'i' }, + { { STATE_EPS4 }, 'i' }, + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_args[] = { + { { 40 /* s */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wait_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PSINTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_interrupt_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTERRUPT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intset_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intclear_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_intenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INTENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_args[] = { + { { 34 /* imms */ }, 'i' }, + { { 33 /* immt */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_args[] = { + { { 34 /* imms */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_break_n_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSINTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC0 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKA1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dbreakc1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DBREAKC1 }, 'm' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA0 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreaka1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKA1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ibreakenable_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_IBREAKENABLE }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'i' }, + { { STATE_DBNUM }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'o' }, + { { STATE_DBNUM }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_debugcause_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DEBUGCAUSE }, 'm' }, + { { STATE_DBNUM }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_ICOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_icountlevel_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ICOUNTLEVEL }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_DDR }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdo_stateArgs[] = { + { { STATE_InOCDMode }, 'm' }, + { { STATE_EPC4 }, 'i' }, + { { STATE_PSWOE }, 'o' }, + { { STATE_PSCALLINC }, 'o' }, + { { STATE_PSOWB }, 'o' }, + { { STATE_PSRING }, 'o' }, + { { STATE_PSUM }, 'o' }, + { { STATE_PSEXCM }, 'o' }, + { { STATE_PSINTLEVEL }, 'o' }, + { { STATE_EPS4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rfdd_stateArgs[] = { + { { STATE_InOCDMode }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOUNT }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccount_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' }, + { { STATE_CCOUNT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare0_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE0 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare1_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE1 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'o' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ccompare2_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_CCOMPARE2 }, 'm' }, + { { STATE_INTERRUPT }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_icache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_licx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sicx_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 22 /* uimm4x16 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_ind_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dcache_inv_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_dpf_args[] = { + { { 4 /* ars */ }, 'i' }, + { { 21 /* uimm8x4 */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_sdct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldct_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'o' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_ptevaddr_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_PTBASE }, 'm' }, + { { STATE_EXCVADDR }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_rasid_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'i' }, + { { STATE_ASID2 }, 'i' }, + { { STATE_ASID1 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'o' }, + { { STATE_ASID2 }, 'o' }, + { { STATE_ASID1 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_rasid_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_ASID3 }, 'm' }, + { { STATE_ASID2 }, 'm' }, + { { STATE_ASID1 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_itlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_itlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_INSTPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rsr_dtlbcfg_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_args[] = { + { { 6 /* art */ }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_xsr_dtlbcfg_stateArgs[] = { + { { STATE_XTSYNC }, 'o' }, + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_DATAPGSZID4 }, 'm' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_idtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_rdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_wdtlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' }, + { { STATE_XTSYNC }, 'o' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_args[] = { + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_iitlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ritlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_args[] = { + { { 6 /* art */ }, 'i' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_witlb_stateArgs[] = { + { { STATE_PSEXCM }, 'i' }, + { { STATE_PSRING }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_ldpte_stateArgs[] = { + { { STATE_PTBASE }, 'i' }, + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwitlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_hwwdtlba_stateArgs[] = { + { { STATE_EXCVADDR }, 'i' } +}; + +static xtensa_arg_internal Iclass_xt_iclass_nsa_args[] = { + { { 6 /* art */ }, 'o' }, + { { 4 /* ars */ }, 'i' } +}; + +static xtensa_iclass_internal iclasses[] = { + { 0, 0 /* xt_iclass_excw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_rfe */, + 3, Iclass_xt_iclass_rfe_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfde */, + 3, Iclass_xt_iclass_rfde_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_syscall */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_simcall */, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call12_args, + 1, Iclass_xt_iclass_call12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call8_args, + 1, Iclass_xt_iclass_call8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_call4_args, + 1, Iclass_xt_iclass_call4_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx12_args, + 1, Iclass_xt_iclass_callx12_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx8_args, + 1, Iclass_xt_iclass_callx8_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_callx4_args, + 1, Iclass_xt_iclass_callx4_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_entry_args, + 5, Iclass_xt_iclass_entry_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movsp_args, + 2, Iclass_xt_iclass_movsp_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rotw_args, + 3, Iclass_xt_iclass_rotw_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_retw_args, + 4, Iclass_xt_iclass_retw_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfwou */, + 6, Iclass_xt_iclass_rfwou_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l32e_args, + 2, Iclass_xt_iclass_l32e_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_s32e_args, + 2, Iclass_xt_iclass_s32e_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowbase_args, + 3, Iclass_xt_iclass_rsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowbase_args, + 3, Iclass_xt_iclass_wsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowbase_args, + 3, Iclass_xt_iclass_xsr_windowbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_windowstart_args, + 3, Iclass_xt_iclass_rsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_windowstart_args, + 3, Iclass_xt_iclass_wsr_windowstart_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_windowstart_args, + 3, Iclass_xt_iclass_xsr_windowstart_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_add_n_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bz6_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill_n */, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_loadi4_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_mov_n_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_movi_n_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nopn */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_retn_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_storei4_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addmi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_addsub_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bit_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8b_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bsi8u_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_bst8_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_bsz12_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_call0_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_callx0_args, + 0, 0, 0, 0 }, + { 4, Iclass_xt_iclass_exti_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_ill */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jump_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_jumpx_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16ui_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l16si_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_l32i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_l32r_args, + 2, Iclass_xt_iclass_l32r_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_l8i_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_loop_args, + 3, Iclass_xt_iclass_loop_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_loopz_args, + 3, Iclass_xt_iclass_loopz_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_movi_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_movz_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_neg_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_nop */, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_return_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s16i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s32i_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_s8i_args, + 0, 0, 0, 0 }, + { 1, Iclass_xt_iclass_sar_args, + 1, Iclass_xt_iclass_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_sari_args, + 1, Iclass_xt_iclass_sari_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shifts_args, + 1, Iclass_xt_iclass_shifts_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_shiftst_args, + 1, Iclass_xt_iclass_shiftst_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_shiftt_args, + 1, Iclass_xt_iclass_shiftt_stateArgs, 0, 0 }, + { 3, Iclass_xt_iclass_slli_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srai_args, + 0, 0, 0, 0 }, + { 3, Iclass_xt_iclass_srli_args, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_memw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_extw */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_isync */, + 0, 0, 0, 0 }, + { 0, 0 /* xt_iclass_sync */, + 1, Iclass_xt_iclass_sync_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rsil_args, + 7, Iclass_xt_iclass_rsil_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lend_args, + 1, Iclass_xt_iclass_rsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lend_args, + 1, Iclass_xt_iclass_wsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lend_args, + 1, Iclass_xt_iclass_xsr_lend_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lcount_args, + 1, Iclass_xt_iclass_rsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lcount_args, + 2, Iclass_xt_iclass_wsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lcount_args, + 2, Iclass_xt_iclass_xsr_lcount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_lbeg_args, + 1, Iclass_xt_iclass_rsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_lbeg_args, + 1, Iclass_xt_iclass_wsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_lbeg_args, + 1, Iclass_xt_iclass_xsr_lbeg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_sar_args, + 1, Iclass_xt_iclass_rsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_sar_args, + 2, Iclass_xt_iclass_wsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_sar_args, + 1, Iclass_xt_iclass_xsr_sar_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_litbase_args, + 2, Iclass_xt_iclass_rsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_litbase_args, + 2, Iclass_xt_iclass_wsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_litbase_args, + 2, Iclass_xt_iclass_xsr_litbase_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_176_args, + 2, Iclass_xt_iclass_rsr_176_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_208_args, + 2, Iclass_xt_iclass_rsr_208_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ps_args, + 7, Iclass_xt_iclass_rsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ps_args, + 7, Iclass_xt_iclass_wsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ps_args, + 7, Iclass_xt_iclass_xsr_ps_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc1_args, + 3, Iclass_xt_iclass_rsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc1_args, + 3, Iclass_xt_iclass_wsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc1_args, + 3, Iclass_xt_iclass_xsr_epc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave1_args, + 3, Iclass_xt_iclass_rsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave1_args, + 3, Iclass_xt_iclass_wsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave1_args, + 3, Iclass_xt_iclass_xsr_excsave1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc2_args, + 3, Iclass_xt_iclass_rsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc2_args, + 3, Iclass_xt_iclass_wsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc2_args, + 3, Iclass_xt_iclass_xsr_epc2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave2_args, + 3, Iclass_xt_iclass_rsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave2_args, + 3, Iclass_xt_iclass_wsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave2_args, + 3, Iclass_xt_iclass_xsr_excsave2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc3_args, + 3, Iclass_xt_iclass_rsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc3_args, + 3, Iclass_xt_iclass_wsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc3_args, + 3, Iclass_xt_iclass_xsr_epc3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave3_args, + 3, Iclass_xt_iclass_rsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave3_args, + 3, Iclass_xt_iclass_wsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave3_args, + 3, Iclass_xt_iclass_xsr_excsave3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_epc4_args, + 3, Iclass_xt_iclass_rsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_epc4_args, + 3, Iclass_xt_iclass_wsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_epc4_args, + 3, Iclass_xt_iclass_xsr_epc4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excsave4_args, + 3, Iclass_xt_iclass_rsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excsave4_args, + 3, Iclass_xt_iclass_wsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excsave4_args, + 3, Iclass_xt_iclass_xsr_excsave4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps2_args, + 3, Iclass_xt_iclass_rsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps2_args, + 3, Iclass_xt_iclass_wsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps2_args, + 3, Iclass_xt_iclass_xsr_eps2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps3_args, + 3, Iclass_xt_iclass_rsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps3_args, + 3, Iclass_xt_iclass_wsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps3_args, + 3, Iclass_xt_iclass_xsr_eps3_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_eps4_args, + 3, Iclass_xt_iclass_rsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_eps4_args, + 3, Iclass_xt_iclass_wsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_eps4_args, + 3, Iclass_xt_iclass_xsr_eps4_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_excvaddr_args, + 3, Iclass_xt_iclass_rsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_excvaddr_args, + 3, Iclass_xt_iclass_wsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_excvaddr_args, + 3, Iclass_xt_iclass_xsr_excvaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_depc_args, + 3, Iclass_xt_iclass_rsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_depc_args, + 3, Iclass_xt_iclass_wsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_depc_args, + 3, Iclass_xt_iclass_xsr_depc_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_exccause_args, + 4, Iclass_xt_iclass_rsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_exccause_args, + 3, Iclass_xt_iclass_wsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_exccause_args, + 3, Iclass_xt_iclass_xsr_exccause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc0_args, + 3, Iclass_xt_iclass_rsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc0_args, + 3, Iclass_xt_iclass_wsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc0_args, + 3, Iclass_xt_iclass_xsr_misc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_misc1_args, + 3, Iclass_xt_iclass_rsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_misc1_args, + 3, Iclass_xt_iclass_wsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_misc1_args, + 3, Iclass_xt_iclass_xsr_misc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_prid_args, + 2, Iclass_xt_iclass_rsr_prid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rfi_args, + 15, Iclass_xt_iclass_rfi_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wait_args, + 3, Iclass_xt_iclass_wait_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_interrupt_args, + 3, Iclass_xt_iclass_rsr_interrupt_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intset_args, + 4, Iclass_xt_iclass_wsr_intset_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intclear_args, + 4, Iclass_xt_iclass_wsr_intclear_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_intenable_args, + 3, Iclass_xt_iclass_rsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_intenable_args, + 3, Iclass_xt_iclass_wsr_intenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_intenable_args, + 3, Iclass_xt_iclass_xsr_intenable_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_break_args, + 2, Iclass_xt_iclass_break_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_break_n_args, + 2, Iclass_xt_iclass_break_n_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka0_args, + 3, Iclass_xt_iclass_rsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka0_args, + 4, Iclass_xt_iclass_wsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka0_args, + 4, Iclass_xt_iclass_xsr_dbreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc0_args, + 3, Iclass_xt_iclass_rsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc0_args, + 4, Iclass_xt_iclass_wsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc0_args, + 4, Iclass_xt_iclass_xsr_dbreakc0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreaka1_args, + 3, Iclass_xt_iclass_rsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreaka1_args, + 4, Iclass_xt_iclass_wsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreaka1_args, + 4, Iclass_xt_iclass_xsr_dbreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dbreakc1_args, + 3, Iclass_xt_iclass_rsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dbreakc1_args, + 4, Iclass_xt_iclass_wsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dbreakc1_args, + 4, Iclass_xt_iclass_xsr_dbreakc1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka0_args, + 3, Iclass_xt_iclass_rsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka0_args, + 3, Iclass_xt_iclass_wsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka0_args, + 3, Iclass_xt_iclass_xsr_ibreaka0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreaka1_args, + 3, Iclass_xt_iclass_rsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreaka1_args, + 3, Iclass_xt_iclass_wsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreaka1_args, + 3, Iclass_xt_iclass_xsr_ibreaka1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ibreakenable_args, + 3, Iclass_xt_iclass_rsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ibreakenable_args, + 3, Iclass_xt_iclass_wsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ibreakenable_args, + 3, Iclass_xt_iclass_xsr_ibreakenable_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_debugcause_args, + 4, Iclass_xt_iclass_rsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_debugcause_args, + 4, Iclass_xt_iclass_wsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_debugcause_args, + 4, Iclass_xt_iclass_xsr_debugcause_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icount_args, + 3, Iclass_xt_iclass_rsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icount_args, + 4, Iclass_xt_iclass_wsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icount_args, + 4, Iclass_xt_iclass_xsr_icount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_icountlevel_args, + 3, Iclass_xt_iclass_rsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_icountlevel_args, + 3, Iclass_xt_iclass_wsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_icountlevel_args, + 3, Iclass_xt_iclass_xsr_icountlevel_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ddr_args, + 3, Iclass_xt_iclass_rsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ddr_args, + 4, Iclass_xt_iclass_wsr_ddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ddr_args, + 4, Iclass_xt_iclass_xsr_ddr_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdo */, + 10, Iclass_xt_iclass_rfdo_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_rfdd */, + 1, Iclass_xt_iclass_rfdd_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccount_args, + 3, Iclass_xt_iclass_rsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccount_args, + 4, Iclass_xt_iclass_wsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccount_args, + 4, Iclass_xt_iclass_xsr_ccount_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare0_args, + 3, Iclass_xt_iclass_rsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare0_args, + 4, Iclass_xt_iclass_wsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare0_args, + 4, Iclass_xt_iclass_xsr_ccompare0_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare1_args, + 3, Iclass_xt_iclass_rsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare1_args, + 4, Iclass_xt_iclass_wsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare1_args, + 4, Iclass_xt_iclass_xsr_ccompare1_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ccompare2_args, + 3, Iclass_xt_iclass_rsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ccompare2_args, + 4, Iclass_xt_iclass_wsr_ccompare2_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ccompare2_args, + 4, Iclass_xt_iclass_xsr_ccompare2_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_icache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_icache_inv_args, + 2, Iclass_xt_iclass_icache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_licx_args, + 2, Iclass_xt_iclass_licx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_sicx_args, + 2, Iclass_xt_iclass_sicx_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_ind_args, + 2, Iclass_xt_iclass_dcache_ind_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dcache_inv_args, + 2, Iclass_xt_iclass_dcache_inv_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_dpf_args, + 0, 0, 0, 0 }, + { 2, Iclass_xt_iclass_sdct_args, + 2, Iclass_xt_iclass_sdct_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ldct_args, + 2, Iclass_xt_iclass_ldct_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_ptevaddr_args, + 4, Iclass_xt_iclass_wsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_ptevaddr_args, + 4, Iclass_xt_iclass_rsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_ptevaddr_args, + 5, Iclass_xt_iclass_xsr_ptevaddr_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_rasid_args, + 5, Iclass_xt_iclass_rsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_rasid_args, + 6, Iclass_xt_iclass_wsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_rasid_args, + 6, Iclass_xt_iclass_xsr_rasid_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_itlbcfg_args, + 3, Iclass_xt_iclass_rsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_itlbcfg_args, + 4, Iclass_xt_iclass_wsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_itlbcfg_args, + 4, Iclass_xt_iclass_xsr_itlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_rsr_dtlbcfg_args, + 3, Iclass_xt_iclass_rsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_wsr_dtlbcfg_args, + 4, Iclass_xt_iclass_wsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_xsr_dtlbcfg_args, + 4, Iclass_xt_iclass_xsr_dtlbcfg_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_idtlb_args, + 3, Iclass_xt_iclass_idtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_rdtlb_args, + 2, Iclass_xt_iclass_rdtlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_wdtlb_args, + 3, Iclass_xt_iclass_wdtlb_stateArgs, 0, 0 }, + { 1, Iclass_xt_iclass_iitlb_args, + 2, Iclass_xt_iclass_iitlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_ritlb_args, + 2, Iclass_xt_iclass_ritlb_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_witlb_args, + 2, Iclass_xt_iclass_witlb_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_ldpte */, + 2, Iclass_xt_iclass_ldpte_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwitlba */, + 1, Iclass_xt_iclass_hwwitlba_stateArgs, 0, 0 }, + { 0, 0 /* xt_iclass_hwwdtlba */, + 1, Iclass_xt_iclass_hwwdtlba_stateArgs, 0, 0 }, + { 2, Iclass_xt_iclass_nsa_args, + 0, 0, 0, 0 } +}; + + +/* Opcode encodings. */ + +static void +Opcode_excw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x80200; +} + +static void +Opcode_rfe_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x300; +} + +static void +Opcode_rfde_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2300; +} + +static void +Opcode_syscall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x500; +} + +static void +Opcode_simcall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1500; +} + +static void +Opcode_call12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5c0000; +} + +static void +Opcode_call8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x580000; +} + +static void +Opcode_call4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x540000; +} + +static void +Opcode_callx12_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0000; +} + +static void +Opcode_callx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb0000; +} + +static void +Opcode_callx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x70000; +} + +static void +Opcode_entry_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6c0000; +} + +static void +Opcode_movsp_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100; +} + +static void +Opcode_rotw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x804; +} + +static void +Opcode_retw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x60000; +} + +static void +Opcode_retw_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd10f; +} + +static void +Opcode_rfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4300; +} + +static void +Opcode_rfwu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5300; +} + +static void +Opcode_l32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x90; +} + +static void +Opcode_s32e_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x94; +} + +static void +Opcode_rsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4830; +} + +static void +Opcode_wsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4831; +} + +static void +Opcode_xsr_windowbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4816; +} + +static void +Opcode_rsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4930; +} + +static void +Opcode_wsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4931; +} + +static void +Opcode_xsr_windowstart_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4916; +} + +static void +Opcode_add_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa000; +} + +static void +Opcode_addi_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb000; +} + +static void +Opcode_beqz_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc800; +} + +static void +Opcode_bnez_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xcc00; +} + +static void +Opcode_ill_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd60f; +} + +static void +Opcode_l32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8000; +} + +static void +Opcode_mov_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd000; +} + +static void +Opcode_movi_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc000; +} + +static void +Opcode_nop_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd30f; +} + +static void +Opcode_ret_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd00f; +} + +static void +Opcode_s32i_n_Slot_inst16a_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9000; +} + +static void +Opcode_addi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200c00; +} + +static void +Opcode_addmi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200d00; +} + +static void +Opcode_add_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8; +} + +static void +Opcode_sub_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc; +} + +static void +Opcode_addx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9; +} + +static void +Opcode_addx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa; +} + +static void +Opcode_addx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb; +} + +static void +Opcode_subx2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd; +} + +static void +Opcode_subx4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe; +} + +static void +Opcode_subx8_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf; +} + +static void +Opcode_and_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1; +} + +static void +Opcode_or_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2; +} + +static void +Opcode_xor_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3; +} + +static void +Opcode_beqi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x680000; +} + +static void +Opcode_bnei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x690000; +} + +static void +Opcode_bgei_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6b0000; +} + +static void +Opcode_blti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6a0000; +} + +static void +Opcode_bbci_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700600; +} + +static void +Opcode_bbsi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700e00; +} + +static void +Opcode_bgeui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6f0000; +} + +static void +Opcode_bltui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6e0000; +} + +static void +Opcode_beq_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700100; +} + +static void +Opcode_bne_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700900; +} + +static void +Opcode_bge_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700a00; +} + +static void +Opcode_blt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700200; +} + +static void +Opcode_bgeu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700b00; +} + +static void +Opcode_bltu_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700300; +} + +static void +Opcode_bany_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700800; +} + +static void +Opcode_bnone_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700000; +} + +static void +Opcode_ball_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700400; +} + +static void +Opcode_bnall_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700c00; +} + +static void +Opcode_bbc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700500; +} + +static void +Opcode_bbs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700d00; +} + +static void +Opcode_beqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x640000; +} + +static void +Opcode_bnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x650000; +} + +static void +Opcode_bgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x670000; +} + +static void +Opcode_bltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x660000; +} + +static void +Opcode_call0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x500000; +} + +static void +Opcode_callx0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30000; +} + +static void +Opcode_extui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x40; +} + +static void +Opcode_ill_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0; +} + +static void +Opcode_j_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600000; +} + +static void +Opcode_jx_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa0000; +} + +static void +Opcode_l16ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200100; +} + +static void +Opcode_l16si_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200900; +} + +static void +Opcode_l32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200200; +} + +static void +Opcode_l32r_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x100000; +} + +static void +Opcode_l8ui_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200000; +} + +static void +Opcode_loop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0800; +} + +static void +Opcode_loopnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0900; +} + +static void +Opcode_loopgtz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6d0a00; +} + +static void +Opcode_movi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200a00; +} + +static void +Opcode_moveqz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x38; +} + +static void +Opcode_movnez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x39; +} + +static void +Opcode_movltz_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3a; +} + +static void +Opcode_movgez_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x3b; +} + +static void +Opcode_neg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6; +} + +static void +Opcode_abs_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1006; +} + +static void +Opcode_nop_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf0200; +} + +static void +Opcode_ret_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20000; +} + +static void +Opcode_s16i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200500; +} + +static void +Opcode_s32i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200600; +} + +static void +Opcode_s8i_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200400; +} + +static void +Opcode_ssr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x4; +} + +static void +Opcode_ssl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x104; +} + +static void +Opcode_ssa8l_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x204; +} + +static void +Opcode_ssa8b_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x304; +} + +static void +Opcode_ssai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x404; +} + +static void +Opcode_sll_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1a; +} + +static void +Opcode_src_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x18; +} + +static void +Opcode_srl_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x19; +} + +static void +Opcode_sra_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1b; +} + +static void +Opcode_slli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10; +} + +static void +Opcode_srai_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x12; +} + +static void +Opcode_srli_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x14; +} + +static void +Opcode_memw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc0200; +} + +static void +Opcode_extw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd0200; +} + +static void +Opcode_isync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200; +} + +static void +Opcode_rsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10200; +} + +static void +Opcode_esync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x20200; +} + +static void +Opcode_dsync_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30200; +} + +static void +Opcode_rsil_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x600; +} + +static void +Opcode_rsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x130; +} + +static void +Opcode_wsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x131; +} + +static void +Opcode_xsr_lend_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x116; +} + +static void +Opcode_rsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230; +} + +static void +Opcode_wsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x231; +} + +static void +Opcode_xsr_lcount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x216; +} + +static void +Opcode_rsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x30; +} + +static void +Opcode_wsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31; +} + +static void +Opcode_xsr_lbeg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x16; +} + +static void +Opcode_rsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x330; +} + +static void +Opcode_wsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x331; +} + +static void +Opcode_xsr_sar_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x316; +} + +static void +Opcode_rsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x530; +} + +static void +Opcode_wsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x531; +} + +static void +Opcode_xsr_litbase_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x516; +} + +static void +Opcode_rsr_176_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb030; +} + +static void +Opcode_rsr_208_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd030; +} + +static void +Opcode_rsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe630; +} + +static void +Opcode_wsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe631; +} + +static void +Opcode_xsr_ps_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe616; +} + +static void +Opcode_rsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb130; +} + +static void +Opcode_wsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb131; +} + +static void +Opcode_xsr_epc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb116; +} + +static void +Opcode_rsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd130; +} + +static void +Opcode_wsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd131; +} + +static void +Opcode_xsr_excsave1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd116; +} + +static void +Opcode_rsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb230; +} + +static void +Opcode_wsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb231; +} + +static void +Opcode_xsr_epc2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb216; +} + +static void +Opcode_rsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd230; +} + +static void +Opcode_wsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd231; +} + +static void +Opcode_xsr_excsave2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd216; +} + +static void +Opcode_rsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb330; +} + +static void +Opcode_wsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb331; +} + +static void +Opcode_xsr_epc3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb316; +} + +static void +Opcode_rsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd330; +} + +static void +Opcode_wsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd331; +} + +static void +Opcode_xsr_excsave3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd316; +} + +static void +Opcode_rsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb430; +} + +static void +Opcode_wsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb431; +} + +static void +Opcode_xsr_epc4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb416; +} + +static void +Opcode_rsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd430; +} + +static void +Opcode_wsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd431; +} + +static void +Opcode_xsr_excsave4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd416; +} + +static void +Opcode_rsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc230; +} + +static void +Opcode_wsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc231; +} + +static void +Opcode_xsr_eps2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc216; +} + +static void +Opcode_rsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc330; +} + +static void +Opcode_wsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc331; +} + +static void +Opcode_xsr_eps3_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc316; +} + +static void +Opcode_rsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc430; +} + +static void +Opcode_wsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc431; +} + +static void +Opcode_xsr_eps4_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc416; +} + +static void +Opcode_rsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee30; +} + +static void +Opcode_wsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee31; +} + +static void +Opcode_xsr_excvaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xee16; +} + +static void +Opcode_rsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc030; +} + +static void +Opcode_wsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc031; +} + +static void +Opcode_xsr_depc_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc016; +} + +static void +Opcode_rsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe830; +} + +static void +Opcode_wsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe831; +} + +static void +Opcode_xsr_exccause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe816; +} + +static void +Opcode_rsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf430; +} + +static void +Opcode_wsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf431; +} + +static void +Opcode_xsr_misc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf416; +} + +static void +Opcode_rsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf530; +} + +static void +Opcode_wsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf531; +} + +static void +Opcode_xsr_misc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf516; +} + +static void +Opcode_rsr_prid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xeb30; +} + +static void +Opcode_rfi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10300; +} + +static void +Opcode_waiti_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x700; +} + +static void +Opcode_rsr_interrupt_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe230; +} + +static void +Opcode_wsr_intset_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe231; +} + +static void +Opcode_wsr_intclear_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe331; +} + +static void +Opcode_rsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe430; +} + +static void +Opcode_wsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe431; +} + +static void +Opcode_xsr_intenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe416; +} + +static void +Opcode_break_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x400; +} + +static void +Opcode_break_n_Slot_inst16b_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd20f; +} + +static void +Opcode_rsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9030; +} + +static void +Opcode_wsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9031; +} + +static void +Opcode_xsr_dbreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9016; +} + +static void +Opcode_rsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa030; +} + +static void +Opcode_wsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa031; +} + +static void +Opcode_xsr_dbreakc0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa016; +} + +static void +Opcode_rsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9130; +} + +static void +Opcode_wsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9131; +} + +static void +Opcode_xsr_dbreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x9116; +} + +static void +Opcode_rsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa130; +} + +static void +Opcode_wsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa131; +} + +static void +Opcode_xsr_dbreakc1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xa116; +} + +static void +Opcode_rsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8030; +} + +static void +Opcode_wsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8031; +} + +static void +Opcode_xsr_ibreaka0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8016; +} + +static void +Opcode_rsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8130; +} + +static void +Opcode_wsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8131; +} + +static void +Opcode_xsr_ibreaka1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x8116; +} + +static void +Opcode_rsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6030; +} + +static void +Opcode_wsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6031; +} + +static void +Opcode_xsr_ibreakenable_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6016; +} + +static void +Opcode_rsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe930; +} + +static void +Opcode_wsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe931; +} + +static void +Opcode_xsr_debugcause_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe916; +} + +static void +Opcode_rsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xec30; +} + +static void +Opcode_wsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xec31; +} + +static void +Opcode_xsr_icount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xec16; +} + +static void +Opcode_rsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xed30; +} + +static void +Opcode_wsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xed31; +} + +static void +Opcode_xsr_icountlevel_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xed16; +} + +static void +Opcode_rsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6830; +} + +static void +Opcode_wsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6831; +} + +static void +Opcode_xsr_ddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x6816; +} + +static void +Opcode_rfdo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe1f; +} + +static void +Opcode_rfdd_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x10e1f; +} + +static void +Opcode_rsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xea30; +} + +static void +Opcode_wsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xea31; +} + +static void +Opcode_xsr_ccount_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xea16; +} + +static void +Opcode_rsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf030; +} + +static void +Opcode_wsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf031; +} + +static void +Opcode_xsr_ccompare0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf016; +} + +static void +Opcode_rsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf130; +} + +static void +Opcode_wsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf131; +} + +static void +Opcode_xsr_ccompare1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf116; +} + +static void +Opcode_rsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf230; +} + +static void +Opcode_wsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf231; +} + +static void +Opcode_xsr_ccompare2_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf216; +} + +static void +Opcode_ipf_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2c0700; +} + +static void +Opcode_ihi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2e0700; +} + +static void +Opcode_iii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x2f0700; +} + +static void +Opcode_lict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x1f; +} + +static void +Opcode_licw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x21f; +} + +static void +Opcode_sict_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x11f; +} + +static void +Opcode_sicw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x31f; +} + +static void +Opcode_dhwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x240700; +} + +static void +Opcode_dhwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x250700; +} + +static void +Opcode_diwb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x280740; +} + +static void +Opcode_diwbi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x280750; +} + +static void +Opcode_dhi_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x260700; +} + +static void +Opcode_dii_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x270700; +} + +static void +Opcode_dpfr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x200700; +} + +static void +Opcode_dpfw_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x210700; +} + +static void +Opcode_dpfro_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x220700; +} + +static void +Opcode_dpfwo_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x230700; +} + +static void +Opcode_sdct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x91f; +} + +static void +Opcode_ldct_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x81f; +} + +static void +Opcode_wsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5331; +} + +static void +Opcode_rsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5330; +} + +static void +Opcode_xsr_ptevaddr_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5316; +} + +static void +Opcode_rsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a30; +} + +static void +Opcode_wsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a31; +} + +static void +Opcode_xsr_rasid_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5a16; +} + +static void +Opcode_rsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b30; +} + +static void +Opcode_wsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b31; +} + +static void +Opcode_xsr_itlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5b16; +} + +static void +Opcode_rsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5c30; +} + +static void +Opcode_wsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5c31; +} + +static void +Opcode_xsr_dtlbcfg_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x5c16; +} + +static void +Opcode_idtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xc05; +} + +static void +Opcode_pdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xd05; +} + +static void +Opcode_rdtlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xb05; +} + +static void +Opcode_rdtlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf05; +} + +static void +Opcode_wdtlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe05; +} + +static void +Opcode_iitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x405; +} + +static void +Opcode_pitlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x505; +} + +static void +Opcode_ritlb0_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x305; +} + +static void +Opcode_ritlb1_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x705; +} + +static void +Opcode_witlb_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x605; +} + +static void +Opcode_ldpte_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf1f; +} + +static void +Opcode_hwwitlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x105; +} + +static void +Opcode_hwwdtlba_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0x905; +} + +static void +Opcode_nsa_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xe04; +} + +static void +Opcode_nsau_Slot_inst_encode (xtensa_insnbuf slotbuf) +{ + slotbuf[0] = 0xf04; +} + +static xtensa_opcode_encode_fn Opcode_excw_encode_fns[] = { + Opcode_excw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfe_encode_fns[] = { + Opcode_rfe_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfde_encode_fns[] = { + Opcode_rfde_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_syscall_encode_fns[] = { + Opcode_syscall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_simcall_encode_fns[] = { + Opcode_simcall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call12_encode_fns[] = { + Opcode_call12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call8_encode_fns[] = { + Opcode_call8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call4_encode_fns[] = { + Opcode_call4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx12_encode_fns[] = { + Opcode_callx12_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx8_encode_fns[] = { + Opcode_callx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx4_encode_fns[] = { + Opcode_callx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_entry_encode_fns[] = { + Opcode_entry_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movsp_encode_fns[] = { + Opcode_movsp_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rotw_encode_fns[] = { + Opcode_rotw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_encode_fns[] = { + Opcode_retw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_retw_n_encode_fns[] = { + 0, 0, Opcode_retw_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rfwo_encode_fns[] = { + Opcode_rfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfwu_encode_fns[] = { + Opcode_rfwu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32e_encode_fns[] = { + Opcode_l32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32e_encode_fns[] = { + Opcode_s32e_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowbase_encode_fns[] = { + Opcode_rsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowbase_encode_fns[] = { + Opcode_wsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowbase_encode_fns[] = { + Opcode_xsr_windowbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_windowstart_encode_fns[] = { + Opcode_rsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_windowstart_encode_fns[] = { + Opcode_wsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_windowstart_encode_fns[] = { + Opcode_xsr_windowstart_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_n_encode_fns[] = { + 0, Opcode_add_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_n_encode_fns[] = { + 0, Opcode_addi_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_n_encode_fns[] = { + 0, 0, Opcode_beqz_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_bnez_n_encode_fns[] = { + 0, 0, Opcode_bnez_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ill_n_encode_fns[] = { + 0, 0, Opcode_ill_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_l32i_n_encode_fns[] = { + 0, Opcode_l32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_mov_n_encode_fns[] = { + 0, 0, Opcode_mov_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_movi_n_encode_fns[] = { + 0, 0, Opcode_movi_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_nop_n_encode_fns[] = { + 0, 0, Opcode_nop_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_ret_n_encode_fns[] = { + 0, 0, Opcode_ret_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_s32i_n_encode_fns[] = { + 0, Opcode_s32i_n_Slot_inst16a_encode, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addi_encode_fns[] = { + Opcode_addi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addmi_encode_fns[] = { + Opcode_addmi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_add_encode_fns[] = { + Opcode_add_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sub_encode_fns[] = { + Opcode_sub_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx2_encode_fns[] = { + Opcode_addx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx4_encode_fns[] = { + Opcode_addx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_addx8_encode_fns[] = { + Opcode_addx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx2_encode_fns[] = { + Opcode_subx2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx4_encode_fns[] = { + Opcode_subx4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_subx8_encode_fns[] = { + Opcode_subx8_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_and_encode_fns[] = { + Opcode_and_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_or_encode_fns[] = { + Opcode_or_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xor_encode_fns[] = { + Opcode_xor_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqi_encode_fns[] = { + Opcode_beqi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnei_encode_fns[] = { + Opcode_bnei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgei_encode_fns[] = { + Opcode_bgei_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blti_encode_fns[] = { + Opcode_blti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbci_encode_fns[] = { + Opcode_bbci_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbsi_encode_fns[] = { + Opcode_bbsi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeui_encode_fns[] = { + Opcode_bgeui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltui_encode_fns[] = { + Opcode_bltui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beq_encode_fns[] = { + Opcode_beq_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bne_encode_fns[] = { + Opcode_bne_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bge_encode_fns[] = { + Opcode_bge_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_blt_encode_fns[] = { + Opcode_blt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgeu_encode_fns[] = { + Opcode_bgeu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltu_encode_fns[] = { + Opcode_bltu_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bany_encode_fns[] = { + Opcode_bany_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnone_encode_fns[] = { + Opcode_bnone_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ball_encode_fns[] = { + Opcode_ball_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnall_encode_fns[] = { + Opcode_bnall_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbc_encode_fns[] = { + Opcode_bbc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bbs_encode_fns[] = { + Opcode_bbs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_beqz_encode_fns[] = { + Opcode_beqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bnez_encode_fns[] = { + Opcode_bnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bgez_encode_fns[] = { + Opcode_bgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_bltz_encode_fns[] = { + Opcode_bltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_call0_encode_fns[] = { + Opcode_call0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_callx0_encode_fns[] = { + Opcode_callx0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extui_encode_fns[] = { + Opcode_extui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ill_encode_fns[] = { + Opcode_ill_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_j_encode_fns[] = { + Opcode_j_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_jx_encode_fns[] = { + Opcode_jx_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16ui_encode_fns[] = { + Opcode_l16ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l16si_encode_fns[] = { + Opcode_l16si_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32i_encode_fns[] = { + Opcode_l32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l32r_encode_fns[] = { + Opcode_l32r_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_l8ui_encode_fns[] = { + Opcode_l8ui_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loop_encode_fns[] = { + Opcode_loop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopnez_encode_fns[] = { + Opcode_loopnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_loopgtz_encode_fns[] = { + Opcode_loopgtz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movi_encode_fns[] = { + Opcode_movi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_moveqz_encode_fns[] = { + Opcode_moveqz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movnez_encode_fns[] = { + Opcode_movnez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movltz_encode_fns[] = { + Opcode_movltz_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_movgez_encode_fns[] = { + Opcode_movgez_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_neg_encode_fns[] = { + Opcode_neg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_abs_encode_fns[] = { + Opcode_abs_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nop_encode_fns[] = { + Opcode_nop_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ret_encode_fns[] = { + Opcode_ret_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s16i_encode_fns[] = { + Opcode_s16i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s32i_encode_fns[] = { + Opcode_s32i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_s8i_encode_fns[] = { + Opcode_s8i_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssr_encode_fns[] = { + Opcode_ssr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssl_encode_fns[] = { + Opcode_ssl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8l_encode_fns[] = { + Opcode_ssa8l_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssa8b_encode_fns[] = { + Opcode_ssa8b_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ssai_encode_fns[] = { + Opcode_ssai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sll_encode_fns[] = { + Opcode_sll_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_src_encode_fns[] = { + Opcode_src_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srl_encode_fns[] = { + Opcode_srl_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sra_encode_fns[] = { + Opcode_sra_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_slli_encode_fns[] = { + Opcode_slli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srai_encode_fns[] = { + Opcode_srai_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_srli_encode_fns[] = { + Opcode_srli_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_memw_encode_fns[] = { + Opcode_memw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_extw_encode_fns[] = { + Opcode_extw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_isync_encode_fns[] = { + Opcode_isync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsync_encode_fns[] = { + Opcode_rsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_esync_encode_fns[] = { + Opcode_esync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dsync_encode_fns[] = { + Opcode_dsync_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsil_encode_fns[] = { + Opcode_rsil_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lend_encode_fns[] = { + Opcode_rsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lend_encode_fns[] = { + Opcode_wsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lend_encode_fns[] = { + Opcode_xsr_lend_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lcount_encode_fns[] = { + Opcode_rsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lcount_encode_fns[] = { + Opcode_wsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lcount_encode_fns[] = { + Opcode_xsr_lcount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_lbeg_encode_fns[] = { + Opcode_rsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_lbeg_encode_fns[] = { + Opcode_wsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_lbeg_encode_fns[] = { + Opcode_xsr_lbeg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_sar_encode_fns[] = { + Opcode_rsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_sar_encode_fns[] = { + Opcode_wsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_sar_encode_fns[] = { + Opcode_xsr_sar_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_litbase_encode_fns[] = { + Opcode_rsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_litbase_encode_fns[] = { + Opcode_wsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_litbase_encode_fns[] = { + Opcode_xsr_litbase_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_176_encode_fns[] = { + Opcode_rsr_176_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_208_encode_fns[] = { + Opcode_rsr_208_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ps_encode_fns[] = { + Opcode_rsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ps_encode_fns[] = { + Opcode_wsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ps_encode_fns[] = { + Opcode_xsr_ps_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc1_encode_fns[] = { + Opcode_rsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc1_encode_fns[] = { + Opcode_wsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc1_encode_fns[] = { + Opcode_xsr_epc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave1_encode_fns[] = { + Opcode_rsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave1_encode_fns[] = { + Opcode_wsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave1_encode_fns[] = { + Opcode_xsr_excsave1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc2_encode_fns[] = { + Opcode_rsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc2_encode_fns[] = { + Opcode_wsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc2_encode_fns[] = { + Opcode_xsr_epc2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave2_encode_fns[] = { + Opcode_rsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave2_encode_fns[] = { + Opcode_wsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave2_encode_fns[] = { + Opcode_xsr_excsave2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc3_encode_fns[] = { + Opcode_rsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc3_encode_fns[] = { + Opcode_wsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc3_encode_fns[] = { + Opcode_xsr_epc3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave3_encode_fns[] = { + Opcode_rsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave3_encode_fns[] = { + Opcode_wsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave3_encode_fns[] = { + Opcode_xsr_excsave3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_epc4_encode_fns[] = { + Opcode_rsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_epc4_encode_fns[] = { + Opcode_wsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_epc4_encode_fns[] = { + Opcode_xsr_epc4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excsave4_encode_fns[] = { + Opcode_rsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excsave4_encode_fns[] = { + Opcode_wsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excsave4_encode_fns[] = { + Opcode_xsr_excsave4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps2_encode_fns[] = { + Opcode_rsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps2_encode_fns[] = { + Opcode_wsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps2_encode_fns[] = { + Opcode_xsr_eps2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps3_encode_fns[] = { + Opcode_rsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps3_encode_fns[] = { + Opcode_wsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps3_encode_fns[] = { + Opcode_xsr_eps3_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_eps4_encode_fns[] = { + Opcode_rsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_eps4_encode_fns[] = { + Opcode_wsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_eps4_encode_fns[] = { + Opcode_xsr_eps4_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_excvaddr_encode_fns[] = { + Opcode_rsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_excvaddr_encode_fns[] = { + Opcode_wsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_excvaddr_encode_fns[] = { + Opcode_xsr_excvaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_depc_encode_fns[] = { + Opcode_rsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_depc_encode_fns[] = { + Opcode_wsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_depc_encode_fns[] = { + Opcode_xsr_depc_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_exccause_encode_fns[] = { + Opcode_rsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_exccause_encode_fns[] = { + Opcode_wsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_exccause_encode_fns[] = { + Opcode_xsr_exccause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc0_encode_fns[] = { + Opcode_rsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc0_encode_fns[] = { + Opcode_wsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc0_encode_fns[] = { + Opcode_xsr_misc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_misc1_encode_fns[] = { + Opcode_rsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_misc1_encode_fns[] = { + Opcode_wsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_misc1_encode_fns[] = { + Opcode_xsr_misc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_prid_encode_fns[] = { + Opcode_rsr_prid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfi_encode_fns[] = { + Opcode_rfi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_waiti_encode_fns[] = { + Opcode_waiti_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_interrupt_encode_fns[] = { + Opcode_rsr_interrupt_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intset_encode_fns[] = { + Opcode_wsr_intset_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intclear_encode_fns[] = { + Opcode_wsr_intclear_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_intenable_encode_fns[] = { + Opcode_rsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_intenable_encode_fns[] = { + Opcode_wsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_intenable_encode_fns[] = { + Opcode_xsr_intenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_encode_fns[] = { + Opcode_break_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_break_n_encode_fns[] = { + 0, 0, Opcode_break_n_Slot_inst16b_encode +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka0_encode_fns[] = { + Opcode_rsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka0_encode_fns[] = { + Opcode_wsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka0_encode_fns[] = { + Opcode_xsr_dbreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc0_encode_fns[] = { + Opcode_rsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc0_encode_fns[] = { + Opcode_wsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc0_encode_fns[] = { + Opcode_xsr_dbreakc0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreaka1_encode_fns[] = { + Opcode_rsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreaka1_encode_fns[] = { + Opcode_wsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreaka1_encode_fns[] = { + Opcode_xsr_dbreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dbreakc1_encode_fns[] = { + Opcode_rsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dbreakc1_encode_fns[] = { + Opcode_wsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dbreakc1_encode_fns[] = { + Opcode_xsr_dbreakc1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka0_encode_fns[] = { + Opcode_rsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka0_encode_fns[] = { + Opcode_wsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka0_encode_fns[] = { + Opcode_xsr_ibreaka0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreaka1_encode_fns[] = { + Opcode_rsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreaka1_encode_fns[] = { + Opcode_wsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreaka1_encode_fns[] = { + Opcode_xsr_ibreaka1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ibreakenable_encode_fns[] = { + Opcode_rsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ibreakenable_encode_fns[] = { + Opcode_wsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ibreakenable_encode_fns[] = { + Opcode_xsr_ibreakenable_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_debugcause_encode_fns[] = { + Opcode_rsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_debugcause_encode_fns[] = { + Opcode_wsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_debugcause_encode_fns[] = { + Opcode_xsr_debugcause_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icount_encode_fns[] = { + Opcode_rsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icount_encode_fns[] = { + Opcode_wsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icount_encode_fns[] = { + Opcode_xsr_icount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_icountlevel_encode_fns[] = { + Opcode_rsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_icountlevel_encode_fns[] = { + Opcode_wsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_icountlevel_encode_fns[] = { + Opcode_xsr_icountlevel_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ddr_encode_fns[] = { + Opcode_rsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ddr_encode_fns[] = { + Opcode_wsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ddr_encode_fns[] = { + Opcode_xsr_ddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdo_encode_fns[] = { + Opcode_rfdo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rfdd_encode_fns[] = { + Opcode_rfdd_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccount_encode_fns[] = { + Opcode_rsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccount_encode_fns[] = { + Opcode_wsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccount_encode_fns[] = { + Opcode_xsr_ccount_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare0_encode_fns[] = { + Opcode_rsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare0_encode_fns[] = { + Opcode_wsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare0_encode_fns[] = { + Opcode_xsr_ccompare0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare1_encode_fns[] = { + Opcode_rsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare1_encode_fns[] = { + Opcode_wsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare1_encode_fns[] = { + Opcode_xsr_ccompare1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ccompare2_encode_fns[] = { + Opcode_rsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ccompare2_encode_fns[] = { + Opcode_wsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ccompare2_encode_fns[] = { + Opcode_xsr_ccompare2_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ipf_encode_fns[] = { + Opcode_ipf_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ihi_encode_fns[] = { + Opcode_ihi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iii_encode_fns[] = { + Opcode_iii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_lict_encode_fns[] = { + Opcode_lict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_licw_encode_fns[] = { + Opcode_licw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sict_encode_fns[] = { + Opcode_sict_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sicw_encode_fns[] = { + Opcode_sicw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwb_encode_fns[] = { + Opcode_dhwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhwbi_encode_fns[] = { + Opcode_dhwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwb_encode_fns[] = { + Opcode_diwb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_diwbi_encode_fns[] = { + Opcode_diwbi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dhi_encode_fns[] = { + Opcode_dhi_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dii_encode_fns[] = { + Opcode_dii_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfr_encode_fns[] = { + Opcode_dpfr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfw_encode_fns[] = { + Opcode_dpfw_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfro_encode_fns[] = { + Opcode_dpfro_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_dpfwo_encode_fns[] = { + Opcode_dpfwo_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_sdct_encode_fns[] = { + Opcode_sdct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldct_encode_fns[] = { + Opcode_ldct_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_ptevaddr_encode_fns[] = { + Opcode_wsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_ptevaddr_encode_fns[] = { + Opcode_rsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_ptevaddr_encode_fns[] = { + Opcode_xsr_ptevaddr_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_rasid_encode_fns[] = { + Opcode_rsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_rasid_encode_fns[] = { + Opcode_wsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_rasid_encode_fns[] = { + Opcode_xsr_rasid_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_itlbcfg_encode_fns[] = { + Opcode_rsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_itlbcfg_encode_fns[] = { + Opcode_wsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_itlbcfg_encode_fns[] = { + Opcode_xsr_itlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rsr_dtlbcfg_encode_fns[] = { + Opcode_rsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wsr_dtlbcfg_encode_fns[] = { + Opcode_wsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_xsr_dtlbcfg_encode_fns[] = { + Opcode_xsr_dtlbcfg_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_idtlb_encode_fns[] = { + Opcode_idtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pdtlb_encode_fns[] = { + Opcode_pdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb0_encode_fns[] = { + Opcode_rdtlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_rdtlb1_encode_fns[] = { + Opcode_rdtlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_wdtlb_encode_fns[] = { + Opcode_wdtlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_iitlb_encode_fns[] = { + Opcode_iitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_pitlb_encode_fns[] = { + Opcode_pitlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb0_encode_fns[] = { + Opcode_ritlb0_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ritlb1_encode_fns[] = { + Opcode_ritlb1_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_witlb_encode_fns[] = { + Opcode_witlb_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_ldpte_encode_fns[] = { + Opcode_ldpte_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwitlba_encode_fns[] = { + Opcode_hwwitlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_hwwdtlba_encode_fns[] = { + Opcode_hwwdtlba_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsa_encode_fns[] = { + Opcode_nsa_Slot_inst_encode, 0, 0 +}; + +static xtensa_opcode_encode_fn Opcode_nsau_encode_fns[] = { + Opcode_nsau_Slot_inst_encode, 0, 0 +}; + + +/* Opcode table. */ + +static xtensa_opcode_internal opcodes[] = { + { "excw", 0 /* xt_iclass_excw */, + 0, + Opcode_excw_encode_fns, 0, 0 }, + { "rfe", 1 /* xt_iclass_rfe */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfe_encode_fns, 0, 0 }, + { "rfde", 2 /* xt_iclass_rfde */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfde_encode_fns, 0, 0 }, + { "syscall", 3 /* xt_iclass_syscall */, + 0, + Opcode_syscall_encode_fns, 0, 0 }, + { "simcall", 4 /* xt_iclass_simcall */, + 0, + Opcode_simcall_encode_fns, 0, 0 }, + { "call12", 5 /* xt_iclass_call12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call12_encode_fns, 0, 0 }, + { "call8", 6 /* xt_iclass_call8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call8_encode_fns, 0, 0 }, + { "call4", 7 /* xt_iclass_call4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call4_encode_fns, 0, 0 }, + { "callx12", 8 /* xt_iclass_callx12 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx12_encode_fns, 0, 0 }, + { "callx8", 9 /* xt_iclass_callx8 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx8_encode_fns, 0, 0 }, + { "callx4", 10 /* xt_iclass_callx4 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx4_encode_fns, 0, 0 }, + { "entry", 11 /* xt_iclass_entry */, + 0, + Opcode_entry_encode_fns, 0, 0 }, + { "movsp", 12 /* xt_iclass_movsp */, + 0, + Opcode_movsp_encode_fns, 0, 0 }, + { "rotw", 13 /* xt_iclass_rotw */, + 0, + Opcode_rotw_encode_fns, 0, 0 }, + { "retw", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_encode_fns, 0, 0 }, + { "retw.n", 14 /* xt_iclass_retw */, + XTENSA_OPCODE_IS_JUMP, + Opcode_retw_n_encode_fns, 0, 0 }, + { "rfwo", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwo_encode_fns, 0, 0 }, + { "rfwu", 15 /* xt_iclass_rfwou */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfwu_encode_fns, 0, 0 }, + { "l32e", 16 /* xt_iclass_l32e */, + 0, + Opcode_l32e_encode_fns, 0, 0 }, + { "s32e", 17 /* xt_iclass_s32e */, + 0, + Opcode_s32e_encode_fns, 0, 0 }, + { "rsr.windowbase", 18 /* xt_iclass_rsr.windowbase */, + 0, + Opcode_rsr_windowbase_encode_fns, 0, 0 }, + { "wsr.windowbase", 19 /* xt_iclass_wsr.windowbase */, + 0, + Opcode_wsr_windowbase_encode_fns, 0, 0 }, + { "xsr.windowbase", 20 /* xt_iclass_xsr.windowbase */, + 0, + Opcode_xsr_windowbase_encode_fns, 0, 0 }, + { "rsr.windowstart", 21 /* xt_iclass_rsr.windowstart */, + 0, + Opcode_rsr_windowstart_encode_fns, 0, 0 }, + { "wsr.windowstart", 22 /* xt_iclass_wsr.windowstart */, + 0, + Opcode_wsr_windowstart_encode_fns, 0, 0 }, + { "xsr.windowstart", 23 /* xt_iclass_xsr.windowstart */, + 0, + Opcode_xsr_windowstart_encode_fns, 0, 0 }, + { "add.n", 24 /* xt_iclass_add.n */, + 0, + Opcode_add_n_encode_fns, 0, 0 }, + { "addi.n", 25 /* xt_iclass_addi.n */, + 0, + Opcode_addi_n_encode_fns, 0, 0 }, + { "beqz.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_n_encode_fns, 0, 0 }, + { "bnez.n", 26 /* xt_iclass_bz6 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_n_encode_fns, 0, 0 }, + { "ill.n", 27 /* xt_iclass_ill.n */, + 0, + Opcode_ill_n_encode_fns, 0, 0 }, + { "l32i.n", 28 /* xt_iclass_loadi4 */, + 0, + Opcode_l32i_n_encode_fns, 0, 0 }, + { "mov.n", 29 /* xt_iclass_mov.n */, + 0, + Opcode_mov_n_encode_fns, 0, 0 }, + { "movi.n", 30 /* xt_iclass_movi.n */, + 0, + Opcode_movi_n_encode_fns, 0, 0 }, + { "nop.n", 31 /* xt_iclass_nopn */, + 0, + Opcode_nop_n_encode_fns, 0, 0 }, + { "ret.n", 32 /* xt_iclass_retn */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_n_encode_fns, 0, 0 }, + { "s32i.n", 33 /* xt_iclass_storei4 */, + 0, + Opcode_s32i_n_encode_fns, 0, 0 }, + { "addi", 34 /* xt_iclass_addi */, + 0, + Opcode_addi_encode_fns, 0, 0 }, + { "addmi", 35 /* xt_iclass_addmi */, + 0, + Opcode_addmi_encode_fns, 0, 0 }, + { "add", 36 /* xt_iclass_addsub */, + 0, + Opcode_add_encode_fns, 0, 0 }, + { "sub", 36 /* xt_iclass_addsub */, + 0, + Opcode_sub_encode_fns, 0, 0 }, + { "addx2", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx2_encode_fns, 0, 0 }, + { "addx4", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx4_encode_fns, 0, 0 }, + { "addx8", 36 /* xt_iclass_addsub */, + 0, + Opcode_addx8_encode_fns, 0, 0 }, + { "subx2", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx2_encode_fns, 0, 0 }, + { "subx4", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx4_encode_fns, 0, 0 }, + { "subx8", 36 /* xt_iclass_addsub */, + 0, + Opcode_subx8_encode_fns, 0, 0 }, + { "and", 37 /* xt_iclass_bit */, + 0, + Opcode_and_encode_fns, 0, 0 }, + { "or", 37 /* xt_iclass_bit */, + 0, + Opcode_or_encode_fns, 0, 0 }, + { "xor", 37 /* xt_iclass_bit */, + 0, + Opcode_xor_encode_fns, 0, 0 }, + { "beqi", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqi_encode_fns, 0, 0 }, + { "bnei", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnei_encode_fns, 0, 0 }, + { "bgei", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgei_encode_fns, 0, 0 }, + { "blti", 38 /* xt_iclass_bsi8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blti_encode_fns, 0, 0 }, + { "bbci", 39 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbci_encode_fns, 0, 0 }, + { "bbsi", 39 /* xt_iclass_bsi8b */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbsi_encode_fns, 0, 0 }, + { "bgeui", 40 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeui_encode_fns, 0, 0 }, + { "bltui", 40 /* xt_iclass_bsi8u */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltui_encode_fns, 0, 0 }, + { "beq", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beq_encode_fns, 0, 0 }, + { "bne", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bne_encode_fns, 0, 0 }, + { "bge", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bge_encode_fns, 0, 0 }, + { "blt", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_blt_encode_fns, 0, 0 }, + { "bgeu", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgeu_encode_fns, 0, 0 }, + { "bltu", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltu_encode_fns, 0, 0 }, + { "bany", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bany_encode_fns, 0, 0 }, + { "bnone", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnone_encode_fns, 0, 0 }, + { "ball", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_ball_encode_fns, 0, 0 }, + { "bnall", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnall_encode_fns, 0, 0 }, + { "bbc", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbc_encode_fns, 0, 0 }, + { "bbs", 41 /* xt_iclass_bst8 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bbs_encode_fns, 0, 0 }, + { "beqz", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_beqz_encode_fns, 0, 0 }, + { "bnez", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bnez_encode_fns, 0, 0 }, + { "bgez", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bgez_encode_fns, 0, 0 }, + { "bltz", 42 /* xt_iclass_bsz12 */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_bltz_encode_fns, 0, 0 }, + { "call0", 43 /* xt_iclass_call0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_call0_encode_fns, 0, 0 }, + { "callx0", 44 /* xt_iclass_callx0 */, + XTENSA_OPCODE_IS_CALL, + Opcode_callx0_encode_fns, 0, 0 }, + { "extui", 45 /* xt_iclass_exti */, + 0, + Opcode_extui_encode_fns, 0, 0 }, + { "ill", 46 /* xt_iclass_ill */, + 0, + Opcode_ill_encode_fns, 0, 0 }, + { "j", 47 /* xt_iclass_jump */, + XTENSA_OPCODE_IS_JUMP, + Opcode_j_encode_fns, 0, 0 }, + { "jx", 48 /* xt_iclass_jumpx */, + XTENSA_OPCODE_IS_JUMP, + Opcode_jx_encode_fns, 0, 0 }, + { "l16ui", 49 /* xt_iclass_l16ui */, + 0, + Opcode_l16ui_encode_fns, 0, 0 }, + { "l16si", 50 /* xt_iclass_l16si */, + 0, + Opcode_l16si_encode_fns, 0, 0 }, + { "l32i", 51 /* xt_iclass_l32i */, + 0, + Opcode_l32i_encode_fns, 0, 0 }, + { "l32r", 52 /* xt_iclass_l32r */, + 0, + Opcode_l32r_encode_fns, 0, 0 }, + { "l8ui", 53 /* xt_iclass_l8i */, + 0, + Opcode_l8ui_encode_fns, 0, 0 }, + { "loop", 54 /* xt_iclass_loop */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loop_encode_fns, 0, 0 }, + { "loopnez", 55 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopnez_encode_fns, 0, 0 }, + { "loopgtz", 55 /* xt_iclass_loopz */, + XTENSA_OPCODE_IS_LOOP, + Opcode_loopgtz_encode_fns, 0, 0 }, + { "movi", 56 /* xt_iclass_movi */, + 0, + Opcode_movi_encode_fns, 0, 0 }, + { "moveqz", 57 /* xt_iclass_movz */, + 0, + Opcode_moveqz_encode_fns, 0, 0 }, + { "movnez", 57 /* xt_iclass_movz */, + 0, + Opcode_movnez_encode_fns, 0, 0 }, + { "movltz", 57 /* xt_iclass_movz */, + 0, + Opcode_movltz_encode_fns, 0, 0 }, + { "movgez", 57 /* xt_iclass_movz */, + 0, + Opcode_movgez_encode_fns, 0, 0 }, + { "neg", 58 /* xt_iclass_neg */, + 0, + Opcode_neg_encode_fns, 0, 0 }, + { "abs", 58 /* xt_iclass_neg */, + 0, + Opcode_abs_encode_fns, 0, 0 }, + { "nop", 59 /* xt_iclass_nop */, + 0, + Opcode_nop_encode_fns, 0, 0 }, + { "ret", 60 /* xt_iclass_return */, + XTENSA_OPCODE_IS_JUMP, + Opcode_ret_encode_fns, 0, 0 }, + { "s16i", 61 /* xt_iclass_s16i */, + 0, + Opcode_s16i_encode_fns, 0, 0 }, + { "s32i", 62 /* xt_iclass_s32i */, + 0, + Opcode_s32i_encode_fns, 0, 0 }, + { "s8i", 63 /* xt_iclass_s8i */, + 0, + Opcode_s8i_encode_fns, 0, 0 }, + { "ssr", 64 /* xt_iclass_sar */, + 0, + Opcode_ssr_encode_fns, 0, 0 }, + { "ssl", 64 /* xt_iclass_sar */, + 0, + Opcode_ssl_encode_fns, 0, 0 }, + { "ssa8l", 64 /* xt_iclass_sar */, + 0, + Opcode_ssa8l_encode_fns, 0, 0 }, + { "ssa8b", 64 /* xt_iclass_sar */, + 0, + Opcode_ssa8b_encode_fns, 0, 0 }, + { "ssai", 65 /* xt_iclass_sari */, + 0, + Opcode_ssai_encode_fns, 0, 0 }, + { "sll", 66 /* xt_iclass_shifts */, + 0, + Opcode_sll_encode_fns, 0, 0 }, + { "src", 67 /* xt_iclass_shiftst */, + 0, + Opcode_src_encode_fns, 0, 0 }, + { "srl", 68 /* xt_iclass_shiftt */, + 0, + Opcode_srl_encode_fns, 0, 0 }, + { "sra", 68 /* xt_iclass_shiftt */, + 0, + Opcode_sra_encode_fns, 0, 0 }, + { "slli", 69 /* xt_iclass_slli */, + 0, + Opcode_slli_encode_fns, 0, 0 }, + { "srai", 70 /* xt_iclass_srai */, + 0, + Opcode_srai_encode_fns, 0, 0 }, + { "srli", 71 /* xt_iclass_srli */, + 0, + Opcode_srli_encode_fns, 0, 0 }, + { "memw", 72 /* xt_iclass_memw */, + 0, + Opcode_memw_encode_fns, 0, 0 }, + { "extw", 73 /* xt_iclass_extw */, + 0, + Opcode_extw_encode_fns, 0, 0 }, + { "isync", 74 /* xt_iclass_isync */, + 0, + Opcode_isync_encode_fns, 0, 0 }, + { "rsync", 75 /* xt_iclass_sync */, + 0, + Opcode_rsync_encode_fns, 0, 0 }, + { "esync", 75 /* xt_iclass_sync */, + 0, + Opcode_esync_encode_fns, 0, 0 }, + { "dsync", 75 /* xt_iclass_sync */, + 0, + Opcode_dsync_encode_fns, 0, 0 }, + { "rsil", 76 /* xt_iclass_rsil */, + 0, + Opcode_rsil_encode_fns, 0, 0 }, + { "rsr.lend", 77 /* xt_iclass_rsr.lend */, + 0, + Opcode_rsr_lend_encode_fns, 0, 0 }, + { "wsr.lend", 78 /* xt_iclass_wsr.lend */, + 0, + Opcode_wsr_lend_encode_fns, 0, 0 }, + { "xsr.lend", 79 /* xt_iclass_xsr.lend */, + 0, + Opcode_xsr_lend_encode_fns, 0, 0 }, + { "rsr.lcount", 80 /* xt_iclass_rsr.lcount */, + 0, + Opcode_rsr_lcount_encode_fns, 0, 0 }, + { "wsr.lcount", 81 /* xt_iclass_wsr.lcount */, + 0, + Opcode_wsr_lcount_encode_fns, 0, 0 }, + { "xsr.lcount", 82 /* xt_iclass_xsr.lcount */, + 0, + Opcode_xsr_lcount_encode_fns, 0, 0 }, + { "rsr.lbeg", 83 /* xt_iclass_rsr.lbeg */, + 0, + Opcode_rsr_lbeg_encode_fns, 0, 0 }, + { "wsr.lbeg", 84 /* xt_iclass_wsr.lbeg */, + 0, + Opcode_wsr_lbeg_encode_fns, 0, 0 }, + { "xsr.lbeg", 85 /* xt_iclass_xsr.lbeg */, + 0, + Opcode_xsr_lbeg_encode_fns, 0, 0 }, + { "rsr.sar", 86 /* xt_iclass_rsr.sar */, + 0, + Opcode_rsr_sar_encode_fns, 0, 0 }, + { "wsr.sar", 87 /* xt_iclass_wsr.sar */, + 0, + Opcode_wsr_sar_encode_fns, 0, 0 }, + { "xsr.sar", 88 /* xt_iclass_xsr.sar */, + 0, + Opcode_xsr_sar_encode_fns, 0, 0 }, + { "rsr.litbase", 89 /* xt_iclass_rsr.litbase */, + 0, + Opcode_rsr_litbase_encode_fns, 0, 0 }, + { "wsr.litbase", 90 /* xt_iclass_wsr.litbase */, + 0, + Opcode_wsr_litbase_encode_fns, 0, 0 }, + { "xsr.litbase", 91 /* xt_iclass_xsr.litbase */, + 0, + Opcode_xsr_litbase_encode_fns, 0, 0 }, + { "rsr.176", 92 /* xt_iclass_rsr.176 */, + 0, + Opcode_rsr_176_encode_fns, 0, 0 }, + { "rsr.208", 93 /* xt_iclass_rsr.208 */, + 0, + Opcode_rsr_208_encode_fns, 0, 0 }, + { "rsr.ps", 94 /* xt_iclass_rsr.ps */, + 0, + Opcode_rsr_ps_encode_fns, 0, 0 }, + { "wsr.ps", 95 /* xt_iclass_wsr.ps */, + 0, + Opcode_wsr_ps_encode_fns, 0, 0 }, + { "xsr.ps", 96 /* xt_iclass_xsr.ps */, + 0, + Opcode_xsr_ps_encode_fns, 0, 0 }, + { "rsr.epc1", 97 /* xt_iclass_rsr.epc1 */, + 0, + Opcode_rsr_epc1_encode_fns, 0, 0 }, + { "wsr.epc1", 98 /* xt_iclass_wsr.epc1 */, + 0, + Opcode_wsr_epc1_encode_fns, 0, 0 }, + { "xsr.epc1", 99 /* xt_iclass_xsr.epc1 */, + 0, + Opcode_xsr_epc1_encode_fns, 0, 0 }, + { "rsr.excsave1", 100 /* xt_iclass_rsr.excsave1 */, + 0, + Opcode_rsr_excsave1_encode_fns, 0, 0 }, + { "wsr.excsave1", 101 /* xt_iclass_wsr.excsave1 */, + 0, + Opcode_wsr_excsave1_encode_fns, 0, 0 }, + { "xsr.excsave1", 102 /* xt_iclass_xsr.excsave1 */, + 0, + Opcode_xsr_excsave1_encode_fns, 0, 0 }, + { "rsr.epc2", 103 /* xt_iclass_rsr.epc2 */, + 0, + Opcode_rsr_epc2_encode_fns, 0, 0 }, + { "wsr.epc2", 104 /* xt_iclass_wsr.epc2 */, + 0, + Opcode_wsr_epc2_encode_fns, 0, 0 }, + { "xsr.epc2", 105 /* xt_iclass_xsr.epc2 */, + 0, + Opcode_xsr_epc2_encode_fns, 0, 0 }, + { "rsr.excsave2", 106 /* xt_iclass_rsr.excsave2 */, + 0, + Opcode_rsr_excsave2_encode_fns, 0, 0 }, + { "wsr.excsave2", 107 /* xt_iclass_wsr.excsave2 */, + 0, + Opcode_wsr_excsave2_encode_fns, 0, 0 }, + { "xsr.excsave2", 108 /* xt_iclass_xsr.excsave2 */, + 0, + Opcode_xsr_excsave2_encode_fns, 0, 0 }, + { "rsr.epc3", 109 /* xt_iclass_rsr.epc3 */, + 0, + Opcode_rsr_epc3_encode_fns, 0, 0 }, + { "wsr.epc3", 110 /* xt_iclass_wsr.epc3 */, + 0, + Opcode_wsr_epc3_encode_fns, 0, 0 }, + { "xsr.epc3", 111 /* xt_iclass_xsr.epc3 */, + 0, + Opcode_xsr_epc3_encode_fns, 0, 0 }, + { "rsr.excsave3", 112 /* xt_iclass_rsr.excsave3 */, + 0, + Opcode_rsr_excsave3_encode_fns, 0, 0 }, + { "wsr.excsave3", 113 /* xt_iclass_wsr.excsave3 */, + 0, + Opcode_wsr_excsave3_encode_fns, 0, 0 }, + { "xsr.excsave3", 114 /* xt_iclass_xsr.excsave3 */, + 0, + Opcode_xsr_excsave3_encode_fns, 0, 0 }, + { "rsr.epc4", 115 /* xt_iclass_rsr.epc4 */, + 0, + Opcode_rsr_epc4_encode_fns, 0, 0 }, + { "wsr.epc4", 116 /* xt_iclass_wsr.epc4 */, + 0, + Opcode_wsr_epc4_encode_fns, 0, 0 }, + { "xsr.epc4", 117 /* xt_iclass_xsr.epc4 */, + 0, + Opcode_xsr_epc4_encode_fns, 0, 0 }, + { "rsr.excsave4", 118 /* xt_iclass_rsr.excsave4 */, + 0, + Opcode_rsr_excsave4_encode_fns, 0, 0 }, + { "wsr.excsave4", 119 /* xt_iclass_wsr.excsave4 */, + 0, + Opcode_wsr_excsave4_encode_fns, 0, 0 }, + { "xsr.excsave4", 120 /* xt_iclass_xsr.excsave4 */, + 0, + Opcode_xsr_excsave4_encode_fns, 0, 0 }, + { "rsr.eps2", 121 /* xt_iclass_rsr.eps2 */, + 0, + Opcode_rsr_eps2_encode_fns, 0, 0 }, + { "wsr.eps2", 122 /* xt_iclass_wsr.eps2 */, + 0, + Opcode_wsr_eps2_encode_fns, 0, 0 }, + { "xsr.eps2", 123 /* xt_iclass_xsr.eps2 */, + 0, + Opcode_xsr_eps2_encode_fns, 0, 0 }, + { "rsr.eps3", 124 /* xt_iclass_rsr.eps3 */, + 0, + Opcode_rsr_eps3_encode_fns, 0, 0 }, + { "wsr.eps3", 125 /* xt_iclass_wsr.eps3 */, + 0, + Opcode_wsr_eps3_encode_fns, 0, 0 }, + { "xsr.eps3", 126 /* xt_iclass_xsr.eps3 */, + 0, + Opcode_xsr_eps3_encode_fns, 0, 0 }, + { "rsr.eps4", 127 /* xt_iclass_rsr.eps4 */, + 0, + Opcode_rsr_eps4_encode_fns, 0, 0 }, + { "wsr.eps4", 128 /* xt_iclass_wsr.eps4 */, + 0, + Opcode_wsr_eps4_encode_fns, 0, 0 }, + { "xsr.eps4", 129 /* xt_iclass_xsr.eps4 */, + 0, + Opcode_xsr_eps4_encode_fns, 0, 0 }, + { "rsr.excvaddr", 130 /* xt_iclass_rsr.excvaddr */, + 0, + Opcode_rsr_excvaddr_encode_fns, 0, 0 }, + { "wsr.excvaddr", 131 /* xt_iclass_wsr.excvaddr */, + 0, + Opcode_wsr_excvaddr_encode_fns, 0, 0 }, + { "xsr.excvaddr", 132 /* xt_iclass_xsr.excvaddr */, + 0, + Opcode_xsr_excvaddr_encode_fns, 0, 0 }, + { "rsr.depc", 133 /* xt_iclass_rsr.depc */, + 0, + Opcode_rsr_depc_encode_fns, 0, 0 }, + { "wsr.depc", 134 /* xt_iclass_wsr.depc */, + 0, + Opcode_wsr_depc_encode_fns, 0, 0 }, + { "xsr.depc", 135 /* xt_iclass_xsr.depc */, + 0, + Opcode_xsr_depc_encode_fns, 0, 0 }, + { "rsr.exccause", 136 /* xt_iclass_rsr.exccause */, + 0, + Opcode_rsr_exccause_encode_fns, 0, 0 }, + { "wsr.exccause", 137 /* xt_iclass_wsr.exccause */, + 0, + Opcode_wsr_exccause_encode_fns, 0, 0 }, + { "xsr.exccause", 138 /* xt_iclass_xsr.exccause */, + 0, + Opcode_xsr_exccause_encode_fns, 0, 0 }, + { "rsr.misc0", 139 /* xt_iclass_rsr.misc0 */, + 0, + Opcode_rsr_misc0_encode_fns, 0, 0 }, + { "wsr.misc0", 140 /* xt_iclass_wsr.misc0 */, + 0, + Opcode_wsr_misc0_encode_fns, 0, 0 }, + { "xsr.misc0", 141 /* xt_iclass_xsr.misc0 */, + 0, + Opcode_xsr_misc0_encode_fns, 0, 0 }, + { "rsr.misc1", 142 /* xt_iclass_rsr.misc1 */, + 0, + Opcode_rsr_misc1_encode_fns, 0, 0 }, + { "wsr.misc1", 143 /* xt_iclass_wsr.misc1 */, + 0, + Opcode_wsr_misc1_encode_fns, 0, 0 }, + { "xsr.misc1", 144 /* xt_iclass_xsr.misc1 */, + 0, + Opcode_xsr_misc1_encode_fns, 0, 0 }, + { "rsr.prid", 145 /* xt_iclass_rsr.prid */, + 0, + Opcode_rsr_prid_encode_fns, 0, 0 }, + { "rfi", 146 /* xt_iclass_rfi */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfi_encode_fns, 0, 0 }, + { "waiti", 147 /* xt_iclass_wait */, + 0, + Opcode_waiti_encode_fns, 0, 0 }, + { "rsr.interrupt", 148 /* xt_iclass_rsr.interrupt */, + 0, + Opcode_rsr_interrupt_encode_fns, 0, 0 }, + { "wsr.intset", 149 /* xt_iclass_wsr.intset */, + 0, + Opcode_wsr_intset_encode_fns, 0, 0 }, + { "wsr.intclear", 150 /* xt_iclass_wsr.intclear */, + 0, + Opcode_wsr_intclear_encode_fns, 0, 0 }, + { "rsr.intenable", 151 /* xt_iclass_rsr.intenable */, + 0, + Opcode_rsr_intenable_encode_fns, 0, 0 }, + { "wsr.intenable", 152 /* xt_iclass_wsr.intenable */, + 0, + Opcode_wsr_intenable_encode_fns, 0, 0 }, + { "xsr.intenable", 153 /* xt_iclass_xsr.intenable */, + 0, + Opcode_xsr_intenable_encode_fns, 0, 0 }, + { "break", 154 /* xt_iclass_break */, + 0, + Opcode_break_encode_fns, 0, 0 }, + { "break.n", 155 /* xt_iclass_break.n */, + 0, + Opcode_break_n_encode_fns, 0, 0 }, + { "rsr.dbreaka0", 156 /* xt_iclass_rsr.dbreaka0 */, + 0, + Opcode_rsr_dbreaka0_encode_fns, 0, 0 }, + { "wsr.dbreaka0", 157 /* xt_iclass_wsr.dbreaka0 */, + 0, + Opcode_wsr_dbreaka0_encode_fns, 0, 0 }, + { "xsr.dbreaka0", 158 /* xt_iclass_xsr.dbreaka0 */, + 0, + Opcode_xsr_dbreaka0_encode_fns, 0, 0 }, + { "rsr.dbreakc0", 159 /* xt_iclass_rsr.dbreakc0 */, + 0, + Opcode_rsr_dbreakc0_encode_fns, 0, 0 }, + { "wsr.dbreakc0", 160 /* xt_iclass_wsr.dbreakc0 */, + 0, + Opcode_wsr_dbreakc0_encode_fns, 0, 0 }, + { "xsr.dbreakc0", 161 /* xt_iclass_xsr.dbreakc0 */, + 0, + Opcode_xsr_dbreakc0_encode_fns, 0, 0 }, + { "rsr.dbreaka1", 162 /* xt_iclass_rsr.dbreaka1 */, + 0, + Opcode_rsr_dbreaka1_encode_fns, 0, 0 }, + { "wsr.dbreaka1", 163 /* xt_iclass_wsr.dbreaka1 */, + 0, + Opcode_wsr_dbreaka1_encode_fns, 0, 0 }, + { "xsr.dbreaka1", 164 /* xt_iclass_xsr.dbreaka1 */, + 0, + Opcode_xsr_dbreaka1_encode_fns, 0, 0 }, + { "rsr.dbreakc1", 165 /* xt_iclass_rsr.dbreakc1 */, + 0, + Opcode_rsr_dbreakc1_encode_fns, 0, 0 }, + { "wsr.dbreakc1", 166 /* xt_iclass_wsr.dbreakc1 */, + 0, + Opcode_wsr_dbreakc1_encode_fns, 0, 0 }, + { "xsr.dbreakc1", 167 /* xt_iclass_xsr.dbreakc1 */, + 0, + Opcode_xsr_dbreakc1_encode_fns, 0, 0 }, + { "rsr.ibreaka0", 168 /* xt_iclass_rsr.ibreaka0 */, + 0, + Opcode_rsr_ibreaka0_encode_fns, 0, 0 }, + { "wsr.ibreaka0", 169 /* xt_iclass_wsr.ibreaka0 */, + 0, + Opcode_wsr_ibreaka0_encode_fns, 0, 0 }, + { "xsr.ibreaka0", 170 /* xt_iclass_xsr.ibreaka0 */, + 0, + Opcode_xsr_ibreaka0_encode_fns, 0, 0 }, + { "rsr.ibreaka1", 171 /* xt_iclass_rsr.ibreaka1 */, + 0, + Opcode_rsr_ibreaka1_encode_fns, 0, 0 }, + { "wsr.ibreaka1", 172 /* xt_iclass_wsr.ibreaka1 */, + 0, + Opcode_wsr_ibreaka1_encode_fns, 0, 0 }, + { "xsr.ibreaka1", 173 /* xt_iclass_xsr.ibreaka1 */, + 0, + Opcode_xsr_ibreaka1_encode_fns, 0, 0 }, + { "rsr.ibreakenable", 174 /* xt_iclass_rsr.ibreakenable */, + 0, + Opcode_rsr_ibreakenable_encode_fns, 0, 0 }, + { "wsr.ibreakenable", 175 /* xt_iclass_wsr.ibreakenable */, + 0, + Opcode_wsr_ibreakenable_encode_fns, 0, 0 }, + { "xsr.ibreakenable", 176 /* xt_iclass_xsr.ibreakenable */, + 0, + Opcode_xsr_ibreakenable_encode_fns, 0, 0 }, + { "rsr.debugcause", 177 /* xt_iclass_rsr.debugcause */, + 0, + Opcode_rsr_debugcause_encode_fns, 0, 0 }, + { "wsr.debugcause", 178 /* xt_iclass_wsr.debugcause */, + 0, + Opcode_wsr_debugcause_encode_fns, 0, 0 }, + { "xsr.debugcause", 179 /* xt_iclass_xsr.debugcause */, + 0, + Opcode_xsr_debugcause_encode_fns, 0, 0 }, + { "rsr.icount", 180 /* xt_iclass_rsr.icount */, + 0, + Opcode_rsr_icount_encode_fns, 0, 0 }, + { "wsr.icount", 181 /* xt_iclass_wsr.icount */, + 0, + Opcode_wsr_icount_encode_fns, 0, 0 }, + { "xsr.icount", 182 /* xt_iclass_xsr.icount */, + 0, + Opcode_xsr_icount_encode_fns, 0, 0 }, + { "rsr.icountlevel", 183 /* xt_iclass_rsr.icountlevel */, + 0, + Opcode_rsr_icountlevel_encode_fns, 0, 0 }, + { "wsr.icountlevel", 184 /* xt_iclass_wsr.icountlevel */, + 0, + Opcode_wsr_icountlevel_encode_fns, 0, 0 }, + { "xsr.icountlevel", 185 /* xt_iclass_xsr.icountlevel */, + 0, + Opcode_xsr_icountlevel_encode_fns, 0, 0 }, + { "rsr.ddr", 186 /* xt_iclass_rsr.ddr */, + 0, + Opcode_rsr_ddr_encode_fns, 0, 0 }, + { "wsr.ddr", 187 /* xt_iclass_wsr.ddr */, + 0, + Opcode_wsr_ddr_encode_fns, 0, 0 }, + { "xsr.ddr", 188 /* xt_iclass_xsr.ddr */, + 0, + Opcode_xsr_ddr_encode_fns, 0, 0 }, + { "rfdo", 189 /* xt_iclass_rfdo */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdo_encode_fns, 0, 0 }, + { "rfdd", 190 /* xt_iclass_rfdd */, + XTENSA_OPCODE_IS_JUMP, + Opcode_rfdd_encode_fns, 0, 0 }, + { "rsr.ccount", 191 /* xt_iclass_rsr.ccount */, + 0, + Opcode_rsr_ccount_encode_fns, 0, 0 }, + { "wsr.ccount", 192 /* xt_iclass_wsr.ccount */, + 0, + Opcode_wsr_ccount_encode_fns, 0, 0 }, + { "xsr.ccount", 193 /* xt_iclass_xsr.ccount */, + 0, + Opcode_xsr_ccount_encode_fns, 0, 0 }, + { "rsr.ccompare0", 194 /* xt_iclass_rsr.ccompare0 */, + 0, + Opcode_rsr_ccompare0_encode_fns, 0, 0 }, + { "wsr.ccompare0", 195 /* xt_iclass_wsr.ccompare0 */, + 0, + Opcode_wsr_ccompare0_encode_fns, 0, 0 }, + { "xsr.ccompare0", 196 /* xt_iclass_xsr.ccompare0 */, + 0, + Opcode_xsr_ccompare0_encode_fns, 0, 0 }, + { "rsr.ccompare1", 197 /* xt_iclass_rsr.ccompare1 */, + 0, + Opcode_rsr_ccompare1_encode_fns, 0, 0 }, + { "wsr.ccompare1", 198 /* xt_iclass_wsr.ccompare1 */, + 0, + Opcode_wsr_ccompare1_encode_fns, 0, 0 }, + { "xsr.ccompare1", 199 /* xt_iclass_xsr.ccompare1 */, + 0, + Opcode_xsr_ccompare1_encode_fns, 0, 0 }, + { "rsr.ccompare2", 200 /* xt_iclass_rsr.ccompare2 */, + 0, + Opcode_rsr_ccompare2_encode_fns, 0, 0 }, + { "wsr.ccompare2", 201 /* xt_iclass_wsr.ccompare2 */, + 0, + Opcode_wsr_ccompare2_encode_fns, 0, 0 }, + { "xsr.ccompare2", 202 /* xt_iclass_xsr.ccompare2 */, + 0, + Opcode_xsr_ccompare2_encode_fns, 0, 0 }, + { "ipf", 203 /* xt_iclass_icache */, + 0, + Opcode_ipf_encode_fns, 0, 0 }, + { "ihi", 203 /* xt_iclass_icache */, + 0, + Opcode_ihi_encode_fns, 0, 0 }, + { "iii", 204 /* xt_iclass_icache_inv */, + 0, + Opcode_iii_encode_fns, 0, 0 }, + { "lict", 205 /* xt_iclass_licx */, + 0, + Opcode_lict_encode_fns, 0, 0 }, + { "licw", 205 /* xt_iclass_licx */, + 0, + Opcode_licw_encode_fns, 0, 0 }, + { "sict", 206 /* xt_iclass_sicx */, + 0, + Opcode_sict_encode_fns, 0, 0 }, + { "sicw", 206 /* xt_iclass_sicx */, + 0, + Opcode_sicw_encode_fns, 0, 0 }, + { "dhwb", 207 /* xt_iclass_dcache */, + 0, + Opcode_dhwb_encode_fns, 0, 0 }, + { "dhwbi", 207 /* xt_iclass_dcache */, + 0, + Opcode_dhwbi_encode_fns, 0, 0 }, + { "diwb", 208 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwb_encode_fns, 0, 0 }, + { "diwbi", 208 /* xt_iclass_dcache_ind */, + 0, + Opcode_diwbi_encode_fns, 0, 0 }, + { "dhi", 209 /* xt_iclass_dcache_inv */, + 0, + Opcode_dhi_encode_fns, 0, 0 }, + { "dii", 209 /* xt_iclass_dcache_inv */, + 0, + Opcode_dii_encode_fns, 0, 0 }, + { "dpfr", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfr_encode_fns, 0, 0 }, + { "dpfw", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfw_encode_fns, 0, 0 }, + { "dpfro", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfro_encode_fns, 0, 0 }, + { "dpfwo", 210 /* xt_iclass_dpf */, + 0, + Opcode_dpfwo_encode_fns, 0, 0 }, + { "sdct", 211 /* xt_iclass_sdct */, + 0, + Opcode_sdct_encode_fns, 0, 0 }, + { "ldct", 212 /* xt_iclass_ldct */, + 0, + Opcode_ldct_encode_fns, 0, 0 }, + { "wsr.ptevaddr", 213 /* xt_iclass_wsr.ptevaddr */, + 0, + Opcode_wsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.ptevaddr", 214 /* xt_iclass_rsr.ptevaddr */, + 0, + Opcode_rsr_ptevaddr_encode_fns, 0, 0 }, + { "xsr.ptevaddr", 215 /* xt_iclass_xsr.ptevaddr */, + 0, + Opcode_xsr_ptevaddr_encode_fns, 0, 0 }, + { "rsr.rasid", 216 /* xt_iclass_rsr.rasid */, + 0, + Opcode_rsr_rasid_encode_fns, 0, 0 }, + { "wsr.rasid", 217 /* xt_iclass_wsr.rasid */, + 0, + Opcode_wsr_rasid_encode_fns, 0, 0 }, + { "xsr.rasid", 218 /* xt_iclass_xsr.rasid */, + 0, + Opcode_xsr_rasid_encode_fns, 0, 0 }, + { "rsr.itlbcfg", 219 /* xt_iclass_rsr.itlbcfg */, + 0, + Opcode_rsr_itlbcfg_encode_fns, 0, 0 }, + { "wsr.itlbcfg", 220 /* xt_iclass_wsr.itlbcfg */, + 0, + Opcode_wsr_itlbcfg_encode_fns, 0, 0 }, + { "xsr.itlbcfg", 221 /* xt_iclass_xsr.itlbcfg */, + 0, + Opcode_xsr_itlbcfg_encode_fns, 0, 0 }, + { "rsr.dtlbcfg", 222 /* xt_iclass_rsr.dtlbcfg */, + 0, + Opcode_rsr_dtlbcfg_encode_fns, 0, 0 }, + { "wsr.dtlbcfg", 223 /* xt_iclass_wsr.dtlbcfg */, + 0, + Opcode_wsr_dtlbcfg_encode_fns, 0, 0 }, + { "xsr.dtlbcfg", 224 /* xt_iclass_xsr.dtlbcfg */, + 0, + Opcode_xsr_dtlbcfg_encode_fns, 0, 0 }, + { "idtlb", 225 /* xt_iclass_idtlb */, + 0, + Opcode_idtlb_encode_fns, 0, 0 }, + { "pdtlb", 226 /* xt_iclass_rdtlb */, + 0, + Opcode_pdtlb_encode_fns, 0, 0 }, + { "rdtlb0", 226 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb0_encode_fns, 0, 0 }, + { "rdtlb1", 226 /* xt_iclass_rdtlb */, + 0, + Opcode_rdtlb1_encode_fns, 0, 0 }, + { "wdtlb", 227 /* xt_iclass_wdtlb */, + 0, + Opcode_wdtlb_encode_fns, 0, 0 }, + { "iitlb", 228 /* xt_iclass_iitlb */, + 0, + Opcode_iitlb_encode_fns, 0, 0 }, + { "pitlb", 229 /* xt_iclass_ritlb */, + 0, + Opcode_pitlb_encode_fns, 0, 0 }, + { "ritlb0", 229 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb0_encode_fns, 0, 0 }, + { "ritlb1", 229 /* xt_iclass_ritlb */, + 0, + Opcode_ritlb1_encode_fns, 0, 0 }, + { "witlb", 230 /* xt_iclass_witlb */, + 0, + Opcode_witlb_encode_fns, 0, 0 }, + { "ldpte", 231 /* xt_iclass_ldpte */, + 0, + Opcode_ldpte_encode_fns, 0, 0 }, + { "hwwitlba", 232 /* xt_iclass_hwwitlba */, + XTENSA_OPCODE_IS_BRANCH, + Opcode_hwwitlba_encode_fns, 0, 0 }, + { "hwwdtlba", 233 /* xt_iclass_hwwdtlba */, + 0, + Opcode_hwwdtlba_encode_fns, 0, 0 }, + { "nsa", 234 /* xt_iclass_nsa */, + 0, + Opcode_nsa_encode_fns, 0, 0 }, + { "nsau", 234 /* xt_iclass_nsa */, + 0, + Opcode_nsau_encode_fns, 0, 0 } +}; + + +/* Slot-specific opcode decode functions. */ + +static int +Slot_inst_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst_get (insn)) + { + case 0: + switch (Field_op1_Slot_inst_get (insn)) + { + case 0: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + if (Field_s_Slot_inst_get (insn) == 0 && + Field_n_Slot_inst_get (insn) == 0) + return 77; /* ill */ + break; + case 2: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 96; /* ret */ + case 1: + return 14; /* retw */ + case 2: + return 79; /* jx */ + } + break; + case 3: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 75; /* callx0 */ + case 1: + return 10; /* callx4 */ + case 2: + return 9; /* callx8 */ + case 3: + return 8; /* callx12 */ + } + break; + } + break; + case 1: + return 12; /* movsp */ + case 2: + if (Field_s_Slot_inst_get (insn) == 0) + { + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 114; /* isync */ + case 1: + return 115; /* rsync */ + case 2: + return 116; /* esync */ + case 3: + return 117; /* dsync */ + case 8: + return 0; /* excw */ + case 12: + return 112; /* memw */ + case 13: + return 113; /* extw */ + case 15: + return 95; /* nop */ + } + } + break; + case 3: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 1; /* rfe */ + case 2: + return 2; /* rfde */ + case 4: + return 16; /* rfwo */ + case 5: + return 17; /* rfwu */ + } + break; + case 1: + return 188; /* rfi */ + } + break; + case 4: + return 196; /* break */ + case 5: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 3; /* syscall */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 4; /* simcall */ + break; + } + break; + case 6: + return 118; /* rsil */ + case 7: + if (Field_t_Slot_inst_get (insn) == 0) + return 189; /* waiti */ + break; + } + break; + case 1: + return 47; /* and */ + case 2: + return 48; /* or */ + case 3: + return 49; /* xor */ + case 4: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + if (Field_t_Slot_inst_get (insn) == 0) + return 100; /* ssr */ + break; + case 1: + if (Field_t_Slot_inst_get (insn) == 0) + return 101; /* ssl */ + break; + case 2: + if (Field_t_Slot_inst_get (insn) == 0) + return 102; /* ssa8l */ + break; + case 3: + if (Field_t_Slot_inst_get (insn) == 0) + return 103; /* ssa8b */ + break; + case 4: + if (Field_thi3_Slot_inst_get (insn) == 0) + return 104; /* ssai */ + break; + case 8: + if (Field_s_Slot_inst_get (insn) == 0) + return 13; /* rotw */ + break; + case 14: + return 289; /* nsa */ + case 15: + return 290; /* nsau */ + } + break; + case 5: + switch (Field_r_Slot_inst_get (insn)) + { + case 1: + return 287; /* hwwitlba */ + case 3: + return 283; /* ritlb0 */ + case 4: + if (Field_t_Slot_inst_get (insn) == 0) + return 281; /* iitlb */ + break; + case 5: + return 282; /* pitlb */ + case 6: + return 285; /* witlb */ + case 7: + return 284; /* ritlb1 */ + case 9: + return 288; /* hwwdtlba */ + case 11: + return 278; /* rdtlb0 */ + case 12: + if (Field_t_Slot_inst_get (insn) == 0) + return 276; /* idtlb */ + break; + case 13: + return 277; /* pdtlb */ + case 14: + return 280; /* wdtlb */ + case 15: + return 279; /* rdtlb1 */ + } + break; + case 6: + switch (Field_s_Slot_inst_get (insn)) + { + case 0: + return 93; /* neg */ + case 1: + return 94; /* abs */ + } + break; + case 8: + return 39; /* add */ + case 9: + return 41; /* addx2 */ + case 10: + return 42; /* addx4 */ + case 11: + return 43; /* addx8 */ + case 12: + return 40; /* sub */ + case 13: + return 44; /* subx2 */ + case 14: + return 45; /* subx4 */ + case 15: + return 46; /* subx8 */ + } + break; + case 1: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + case 1: + return 109; /* slli */ + case 2: + case 3: + return 110; /* srai */ + case 4: + return 111; /* srli */ + case 6: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 127; /* xsr.lbeg */ + case 1: + return 121; /* xsr.lend */ + case 2: + return 124; /* xsr.lcount */ + case 3: + return 130; /* xsr.sar */ + case 5: + return 133; /* xsr.litbase */ + case 72: + return 22; /* xsr.windowbase */ + case 73: + return 25; /* xsr.windowstart */ + case 83: + return 266; /* xsr.ptevaddr */ + case 90: + return 269; /* xsr.rasid */ + case 91: + return 272; /* xsr.itlbcfg */ + case 92: + return 275; /* xsr.dtlbcfg */ + case 96: + return 218; /* xsr.ibreakenable */ + case 104: + return 230; /* xsr.ddr */ + case 128: + return 212; /* xsr.ibreaka0 */ + case 129: + return 215; /* xsr.ibreaka1 */ + case 144: + return 200; /* xsr.dbreaka0 */ + case 145: + return 206; /* xsr.dbreaka1 */ + case 160: + return 203; /* xsr.dbreakc0 */ + case 161: + return 209; /* xsr.dbreakc1 */ + case 177: + return 141; /* xsr.epc1 */ + case 178: + return 147; /* xsr.epc2 */ + case 179: + return 153; /* xsr.epc3 */ + case 180: + return 159; /* xsr.epc4 */ + case 192: + return 177; /* xsr.depc */ + case 194: + return 165; /* xsr.eps2 */ + case 195: + return 168; /* xsr.eps3 */ + case 196: + return 171; /* xsr.eps4 */ + case 209: + return 144; /* xsr.excsave1 */ + case 210: + return 150; /* xsr.excsave2 */ + case 211: + return 156; /* xsr.excsave3 */ + case 212: + return 162; /* xsr.excsave4 */ + case 228: + return 195; /* xsr.intenable */ + case 230: + return 138; /* xsr.ps */ + case 232: + return 180; /* xsr.exccause */ + case 233: + return 221; /* xsr.debugcause */ + case 234: + return 235; /* xsr.ccount */ + case 236: + return 224; /* xsr.icount */ + case 237: + return 227; /* xsr.icountlevel */ + case 238: + return 174; /* xsr.excvaddr */ + case 240: + return 238; /* xsr.ccompare0 */ + case 241: + return 241; /* xsr.ccompare1 */ + case 242: + return 244; /* xsr.ccompare2 */ + case 244: + return 183; /* xsr.misc0 */ + case 245: + return 186; /* xsr.misc1 */ + } + break; + case 8: + return 106; /* src */ + case 9: + if (Field_s_Slot_inst_get (insn) == 0) + return 107; /* srl */ + break; + case 10: + if (Field_t_Slot_inst_get (insn) == 0) + return 105; /* sll */ + break; + case 11: + if (Field_s_Slot_inst_get (insn) == 0) + return 108; /* sra */ + break; + case 15: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 248; /* lict */ + case 1: + return 250; /* sict */ + case 2: + return 249; /* licw */ + case 3: + return 251; /* sicw */ + case 8: + return 263; /* ldct */ + case 9: + return 262; /* sdct */ + case 14: + if (Field_t_Slot_inst_get (insn) == 0 && + Field_s_Slot_inst_get (insn) == 0) + return 231; /* rfdo */ + if (Field_t_Slot_inst_get (insn) == 1 && + Field_s_Slot_inst_get (insn) == 0) + return 232; /* rfdd */ + break; + case 15: + return 286; /* ldpte */ + } + break; + } + break; + case 3: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 125; /* rsr.lbeg */ + case 1: + return 119; /* rsr.lend */ + case 2: + return 122; /* rsr.lcount */ + case 3: + return 128; /* rsr.sar */ + case 5: + return 131; /* rsr.litbase */ + case 72: + return 20; /* rsr.windowbase */ + case 73: + return 23; /* rsr.windowstart */ + case 83: + return 265; /* rsr.ptevaddr */ + case 90: + return 267; /* rsr.rasid */ + case 91: + return 270; /* rsr.itlbcfg */ + case 92: + return 273; /* rsr.dtlbcfg */ + case 96: + return 216; /* rsr.ibreakenable */ + case 104: + return 228; /* rsr.ddr */ + case 128: + return 210; /* rsr.ibreaka0 */ + case 129: + return 213; /* rsr.ibreaka1 */ + case 144: + return 198; /* rsr.dbreaka0 */ + case 145: + return 204; /* rsr.dbreaka1 */ + case 160: + return 201; /* rsr.dbreakc0 */ + case 161: + return 207; /* rsr.dbreakc1 */ + case 176: + return 134; /* rsr.176 */ + case 177: + return 139; /* rsr.epc1 */ + case 178: + return 145; /* rsr.epc2 */ + case 179: + return 151; /* rsr.epc3 */ + case 180: + return 157; /* rsr.epc4 */ + case 192: + return 175; /* rsr.depc */ + case 194: + return 163; /* rsr.eps2 */ + case 195: + return 166; /* rsr.eps3 */ + case 196: + return 169; /* rsr.eps4 */ + case 208: + return 135; /* rsr.208 */ + case 209: + return 142; /* rsr.excsave1 */ + case 210: + return 148; /* rsr.excsave2 */ + case 211: + return 154; /* rsr.excsave3 */ + case 212: + return 160; /* rsr.excsave4 */ + case 226: + return 190; /* rsr.interrupt */ + case 228: + return 193; /* rsr.intenable */ + case 230: + return 136; /* rsr.ps */ + case 232: + return 178; /* rsr.exccause */ + case 233: + return 219; /* rsr.debugcause */ + case 234: + return 233; /* rsr.ccount */ + case 235: + return 187; /* rsr.prid */ + case 236: + return 222; /* rsr.icount */ + case 237: + return 225; /* rsr.icountlevel */ + case 238: + return 172; /* rsr.excvaddr */ + case 240: + return 236; /* rsr.ccompare0 */ + case 241: + return 239; /* rsr.ccompare1 */ + case 242: + return 242; /* rsr.ccompare2 */ + case 244: + return 181; /* rsr.misc0 */ + case 245: + return 184; /* rsr.misc1 */ + } + break; + case 1: + switch (Field_sr_Slot_inst_get (insn)) + { + case 0: + return 126; /* wsr.lbeg */ + case 1: + return 120; /* wsr.lend */ + case 2: + return 123; /* wsr.lcount */ + case 3: + return 129; /* wsr.sar */ + case 5: + return 132; /* wsr.litbase */ + case 72: + return 21; /* wsr.windowbase */ + case 73: + return 24; /* wsr.windowstart */ + case 83: + return 264; /* wsr.ptevaddr */ + case 90: + return 268; /* wsr.rasid */ + case 91: + return 271; /* wsr.itlbcfg */ + case 92: + return 274; /* wsr.dtlbcfg */ + case 96: + return 217; /* wsr.ibreakenable */ + case 104: + return 229; /* wsr.ddr */ + case 128: + return 211; /* wsr.ibreaka0 */ + case 129: + return 214; /* wsr.ibreaka1 */ + case 144: + return 199; /* wsr.dbreaka0 */ + case 145: + return 205; /* wsr.dbreaka1 */ + case 160: + return 202; /* wsr.dbreakc0 */ + case 161: + return 208; /* wsr.dbreakc1 */ + case 177: + return 140; /* wsr.epc1 */ + case 178: + return 146; /* wsr.epc2 */ + case 179: + return 152; /* wsr.epc3 */ + case 180: + return 158; /* wsr.epc4 */ + case 192: + return 176; /* wsr.depc */ + case 194: + return 164; /* wsr.eps2 */ + case 195: + return 167; /* wsr.eps3 */ + case 196: + return 170; /* wsr.eps4 */ + case 209: + return 143; /* wsr.excsave1 */ + case 210: + return 149; /* wsr.excsave2 */ + case 211: + return 155; /* wsr.excsave3 */ + case 212: + return 161; /* wsr.excsave4 */ + case 226: + return 191; /* wsr.intset */ + case 227: + return 192; /* wsr.intclear */ + case 228: + return 194; /* wsr.intenable */ + case 230: + return 137; /* wsr.ps */ + case 232: + return 179; /* wsr.exccause */ + case 233: + return 220; /* wsr.debugcause */ + case 234: + return 234; /* wsr.ccount */ + case 236: + return 223; /* wsr.icount */ + case 237: + return 226; /* wsr.icountlevel */ + case 238: + return 173; /* wsr.excvaddr */ + case 240: + return 237; /* wsr.ccompare0 */ + case 241: + return 240; /* wsr.ccompare1 */ + case 242: + return 243; /* wsr.ccompare2 */ + case 244: + return 182; /* wsr.misc0 */ + case 245: + return 185; /* wsr.misc1 */ + } + break; + case 8: + return 89; /* moveqz */ + case 9: + return 90; /* movnez */ + case 10: + return 91; /* movltz */ + case 11: + return 92; /* movgez */ + } + break; + case 4: + case 5: + return 76; /* extui */ + case 9: + switch (Field_op2_Slot_inst_get (insn)) + { + case 0: + return 18; /* l32e */ + case 4: + return 19; /* s32e */ + } + break; + } + break; + case 1: + return 83; /* l32r */ + case 2: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 84; /* l8ui */ + case 1: + return 80; /* l16ui */ + case 2: + return 82; /* l32i */ + case 4: + return 99; /* s8i */ + case 5: + return 97; /* s16i */ + case 6: + return 98; /* s32i */ + case 7: + switch (Field_t_Slot_inst_get (insn)) + { + case 0: + return 258; /* dpfr */ + case 1: + return 259; /* dpfw */ + case 2: + return 260; /* dpfro */ + case 3: + return 261; /* dpfwo */ + case 4: + return 252; /* dhwb */ + case 5: + return 253; /* dhwbi */ + case 6: + return 256; /* dhi */ + case 7: + return 257; /* dii */ + case 8: + switch (Field_op1_Slot_inst_get (insn)) + { + case 4: + return 254; /* diwb */ + case 5: + return 255; /* diwbi */ + } + break; + case 12: + return 245; /* ipf */ + case 14: + return 246; /* ihi */ + case 15: + return 247; /* iii */ + } + break; + case 9: + return 81; /* l16si */ + case 10: + return 88; /* movi */ + case 12: + return 37; /* addi */ + case 13: + return 38; /* addmi */ + } + break; + case 5: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 74; /* call0 */ + case 1: + return 7; /* call4 */ + case 2: + return 6; /* call8 */ + case 3: + return 5; /* call12 */ + } + break; + case 6: + switch (Field_n_Slot_inst_get (insn)) + { + case 0: + return 78; /* j */ + case 1: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 70; /* beqz */ + case 1: + return 71; /* bnez */ + case 2: + return 73; /* bltz */ + case 3: + return 72; /* bgez */ + } + break; + case 2: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 50; /* beqi */ + case 1: + return 51; /* bnei */ + case 2: + return 53; /* blti */ + case 3: + return 52; /* bgei */ + } + break; + case 3: + switch (Field_m_Slot_inst_get (insn)) + { + case 0: + return 11; /* entry */ + case 1: + switch (Field_r_Slot_inst_get (insn)) + { + case 8: + return 85; /* loop */ + case 9: + return 86; /* loopnez */ + case 10: + return 87; /* loopgtz */ + } + break; + case 2: + return 57; /* bltui */ + case 3: + return 56; /* bgeui */ + } + break; + } + break; + case 7: + switch (Field_r_Slot_inst_get (insn)) + { + case 0: + return 65; /* bnone */ + case 1: + return 58; /* beq */ + case 2: + return 61; /* blt */ + case 3: + return 63; /* bltu */ + case 4: + return 66; /* ball */ + case 5: + return 68; /* bbc */ + case 6: + case 7: + return 54; /* bbci */ + case 8: + return 64; /* bany */ + case 9: + return 59; /* bne */ + case 10: + return 60; /* bge */ + case 11: + return 62; /* bgeu */ + case 12: + return 67; /* bnall */ + case 13: + return 69; /* bbs */ + case 14: + case 15: + return 55; /* bbsi */ + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16b_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16b_get (insn)) + { + case 12: + switch (Field_i_Slot_inst16b_get (insn)) + { + case 0: + return 33; /* movi.n */ + case 1: + switch (Field_z_Slot_inst16b_get (insn)) + { + case 0: + return 28; /* beqz.n */ + case 1: + return 29; /* bnez.n */ + } + break; + } + break; + case 13: + switch (Field_r_Slot_inst16b_get (insn)) + { + case 0: + return 32; /* mov.n */ + case 15: + switch (Field_t_Slot_inst16b_get (insn)) + { + case 0: + return 35; /* ret.n */ + case 1: + return 15; /* retw.n */ + case 2: + return 197; /* break.n */ + case 3: + if (Field_s_Slot_inst16b_get (insn) == 0) + return 34; /* nop.n */ + break; + case 6: + if (Field_s_Slot_inst16b_get (insn) == 0) + return 30; /* ill.n */ + break; + } + break; + } + break; + } + return XTENSA_UNDEFINED; +} + +static int +Slot_inst16a_decode (const xtensa_insnbuf insn) +{ + switch (Field_op0_Slot_inst16a_get (insn)) + { + case 8: + return 31; /* l32i.n */ + case 9: + return 36; /* s32i.n */ + case 10: + return 26; /* add.n */ + case 11: + return 27; /* addi.n */ + } + return XTENSA_UNDEFINED; +} + + +/* Instruction slots. */ + +static void +Slot_x24_Format_inst_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = (insn[0] & 0xffffff); +} + +static void +Slot_x24_Format_inst_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffffff) | (slotbuf[0] & 0xffffff); +} + +static void +Slot_x16a_Format_inst16a_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = ((insn[0] & 0xffff00) >> 8); +} + +static void +Slot_x16a_Format_inst16a_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff00) | ((slotbuf[0] & 0xffff) << 8); +} + +static void +Slot_x16b_Format_inst16b_0_get (const xtensa_insnbuf insn, + xtensa_insnbuf slotbuf) +{ + slotbuf[0] = ((insn[0] & 0xffff00) >> 8); +} + +static void +Slot_x16b_Format_inst16b_0_set (xtensa_insnbuf insn, + const xtensa_insnbuf slotbuf) +{ + insn[0] = (insn[0] & ~0xffff00) | ((slotbuf[0] & 0xffff) << 8); +} + +static xtensa_get_field_fn +Slot_inst_get_field_fns[] = { + Field_t_Slot_inst_get, + Field_bbi4_Slot_inst_get, + Field_bbi_Slot_inst_get, + Field_imm12_Slot_inst_get, + Field_imm8_Slot_inst_get, + Field_s_Slot_inst_get, + Field_imm12b_Slot_inst_get, + Field_imm16_Slot_inst_get, + Field_m_Slot_inst_get, + Field_n_Slot_inst_get, + Field_offset_Slot_inst_get, + Field_op0_Slot_inst_get, + Field_op1_Slot_inst_get, + Field_op2_Slot_inst_get, + Field_r_Slot_inst_get, + Field_sa4_Slot_inst_get, + Field_sae4_Slot_inst_get, + Field_sae_Slot_inst_get, + Field_sal_Slot_inst_get, + Field_sargt_Slot_inst_get, + Field_sas4_Slot_inst_get, + Field_sas_Slot_inst_get, + Field_sr_Slot_inst_get, + Field_st_Slot_inst_get, + Field_thi3_Slot_inst_get, + Field_imm4_Slot_inst_get, + Field_mn_Slot_inst_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst_set_field_fns[] = { + Field_t_Slot_inst_set, + Field_bbi4_Slot_inst_set, + Field_bbi_Slot_inst_set, + Field_imm12_Slot_inst_set, + Field_imm8_Slot_inst_set, + Field_s_Slot_inst_set, + Field_imm12b_Slot_inst_set, + Field_imm16_Slot_inst_set, + Field_m_Slot_inst_set, + Field_n_Slot_inst_set, + Field_offset_Slot_inst_set, + Field_op0_Slot_inst_set, + Field_op1_Slot_inst_set, + Field_op2_Slot_inst_set, + Field_r_Slot_inst_set, + Field_sa4_Slot_inst_set, + Field_sae4_Slot_inst_set, + Field_sae_Slot_inst_set, + Field_sal_Slot_inst_set, + Field_sargt_Slot_inst_set, + Field_sas4_Slot_inst_set, + Field_sas_Slot_inst_set, + Field_sr_Slot_inst_set, + Field_st_Slot_inst_set, + Field_thi3_Slot_inst_set, + Field_imm4_Slot_inst_set, + Field_mn_Slot_inst_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16a_get_field_fns[] = { + Field_t_Slot_inst16a_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_get, + 0, + 0, + Field_r_Slot_inst16a_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_get, + Field_st_Slot_inst16a_get, + 0, + Field_imm4_Slot_inst16a_get, + 0, + Field_i_Slot_inst16a_get, + Field_imm6lo_Slot_inst16a_get, + Field_imm6hi_Slot_inst16a_get, + Field_imm7lo_Slot_inst16a_get, + Field_imm7hi_Slot_inst16a_get, + Field_z_Slot_inst16a_get, + Field_imm6_Slot_inst16a_get, + Field_imm7_Slot_inst16a_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst16a_set_field_fns[] = { + Field_t_Slot_inst16a_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16a_set, + 0, + 0, + Field_r_Slot_inst16a_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16a_set, + Field_st_Slot_inst16a_set, + 0, + Field_imm4_Slot_inst16a_set, + 0, + Field_i_Slot_inst16a_set, + Field_imm6lo_Slot_inst16a_set, + Field_imm6hi_Slot_inst16a_set, + Field_imm7lo_Slot_inst16a_set, + Field_imm7hi_Slot_inst16a_set, + Field_z_Slot_inst16a_set, + Field_imm6_Slot_inst16a_set, + Field_imm7_Slot_inst16a_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_get_field_fn +Slot_inst16b_get_field_fns[] = { + Field_t_Slot_inst16b_get, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_get, + 0, + 0, + Field_r_Slot_inst16b_get, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_get, + Field_st_Slot_inst16b_get, + 0, + Field_imm4_Slot_inst16b_get, + 0, + Field_i_Slot_inst16b_get, + Field_imm6lo_Slot_inst16b_get, + Field_imm6hi_Slot_inst16b_get, + Field_imm7lo_Slot_inst16b_get, + Field_imm7hi_Slot_inst16b_get, + Field_z_Slot_inst16b_get, + Field_imm6_Slot_inst16b_get, + Field_imm7_Slot_inst16b_get, + Implicit_Field_ar0_get, + Implicit_Field_ar4_get, + Implicit_Field_ar8_get, + Implicit_Field_ar12_get +}; + +static xtensa_set_field_fn +Slot_inst16b_set_field_fns[] = { + Field_t_Slot_inst16b_set, + 0, + 0, + 0, + 0, + Field_s_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + Field_op0_Slot_inst16b_set, + 0, + 0, + Field_r_Slot_inst16b_set, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + Field_sr_Slot_inst16b_set, + Field_st_Slot_inst16b_set, + 0, + Field_imm4_Slot_inst16b_set, + 0, + Field_i_Slot_inst16b_set, + Field_imm6lo_Slot_inst16b_set, + Field_imm6hi_Slot_inst16b_set, + Field_imm7lo_Slot_inst16b_set, + Field_imm7hi_Slot_inst16b_set, + Field_z_Slot_inst16b_set, + Field_imm6_Slot_inst16b_set, + Field_imm7_Slot_inst16b_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set, + Implicit_Field_set +}; + +static xtensa_slot_internal slots[] = { + { "Inst", "x24", 0, + Slot_x24_Format_inst_0_get, Slot_x24_Format_inst_0_set, + Slot_inst_get_field_fns, Slot_inst_set_field_fns, + Slot_inst_decode, "nop" }, + { "Inst16a", "x16a", 0, + Slot_x16a_Format_inst16a_0_get, Slot_x16a_Format_inst16a_0_set, + Slot_inst16a_get_field_fns, Slot_inst16a_set_field_fns, + Slot_inst16a_decode, "" }, + { "Inst16b", "x16b", 0, + Slot_x16b_Format_inst16b_0_get, Slot_x16b_Format_inst16b_0_set, + Slot_inst16b_get_field_fns, Slot_inst16b_set_field_fns, + Slot_inst16b_decode, "nop.n" } +}; + + +/* Instruction formats. */ + +static void +Format_x24_encode (xtensa_insnbuf insn) +{ + insn[0] = 0; +} + +static void +Format_x16a_encode (xtensa_insnbuf insn) +{ + insn[0] = 0x800000; +} + +static void +Format_x16b_encode (xtensa_insnbuf insn) +{ + insn[0] = 0xc00000; +} + +static int Format_x24_slots[] = { 0 }; + +static int Format_x16a_slots[] = { 1 }; + +static int Format_x16b_slots[] = { 2 }; + +static xtensa_format_internal formats[] = { + { "x24", 3, Format_x24_encode, 1, Format_x24_slots }, + { "x16a", 2, Format_x16a_encode, 1, Format_x16a_slots }, + { "x16b", 2, Format_x16b_encode, 1, Format_x16b_slots } +}; + + +static int +format_decoder (const xtensa_insnbuf insn) +{ + if ((insn[0] & 0x800000) == 0) + return 0; /* x24 */ + if ((insn[0] & 0xc00000) == 0x800000) + return 1; /* x16a */ + if ((insn[0] & 0xe00000) == 0xc00000) + return 2; /* x16b */ + return -1; +} + +static int length_table[16] = { + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1 +}; + +static int +length_decoder (const unsigned char *insn) +{ + int op0 = (insn[0] >> 4) & 0xf; + return length_table[op0]; +} + + +/* Top-level ISA structure. */ + +xtensa_isa_internal xtensa_modules = { + 1 /* big-endian */, + 3 /* insn_size */, 0, + 3, formats, format_decoder, length_decoder, + 3, slots, + 39 /* num_fields */, + 70, operands, + 235, iclasses, + 291, opcodes, 0, + 1, regfiles, + NUM_STATES, states, 0, + NUM_SYSREGS, sysregs, 0, + { MAX_SPECIAL_REG, MAX_USER_REG }, { 0, 0 }, + 0, interfaces, 0, + 0, funcUnits, 0 +}; From 78f1d3d6a6904459b0b6cfd735278e4e2b7b68c5 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 9 Nov 2017 10:26:52 +0000 Subject: [PATCH 252/546] coroutine: simplify co_aio_sleep_ns() prototype The AioContext pointer argument to co_aio_sleep_ns() is only used for the sleep timer. It does not affect where the caller coroutine is resumed. Due to changes to coroutine and AIO APIs it is now possible to drop the AioContext pointer argument. This is safe to do since no caller has specific requirements for which AioContext the timer must run in. This patch drops the AioContext pointer argument and renames the function to simplify the API. Reported-by: Paolo Bonzini Reported-by: Eric Blake Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171109102652.6360-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block/null.c | 3 +-- block/sheepdog.c | 3 +-- include/qemu/coroutine.h | 6 +----- util/qemu-coroutine-sleep.c | 4 ++-- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/block/null.c b/block/null.c index dd9c13f9ba..0cdabaa440 100644 --- a/block/null.c +++ b/block/null.c @@ -110,8 +110,7 @@ static coroutine_fn int null_co_common(BlockDriverState *bs) BDRVNullState *s = bs->opaque; if (s->latency_ns) { - co_aio_sleep_ns(bdrv_get_aio_context(bs), QEMU_CLOCK_REALTIME, - s->latency_ns); + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, s->latency_ns); } return 0; } diff --git a/block/sheepdog.c b/block/sheepdog.c index 696a71442a..a1edb992ff 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -776,8 +776,7 @@ static coroutine_fn void reconnect_to_sdog(void *opaque) if (s->fd < 0) { DPRINTF("Wait for connection to be established\n"); error_report_err(local_err); - co_aio_sleep_ns(bdrv_get_aio_context(s->bs), QEMU_CLOCK_REALTIME, - 1000000000ULL); + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000000ULL); } }; diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index 9aff9a735e..ce2eb73670 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -261,12 +261,8 @@ void qemu_co_rwlock_unlock(CoRwlock *lock); /** * Yield the coroutine for a given duration - * - * Behaves similarly to co_sleep_ns(), but the sleeping coroutine will be - * resumed when using aio_poll(). */ -void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type, - int64_t ns); +void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns); /** * Yield until a file descriptor becomes readable diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c index 254349cdbb..afb678fbe5 100644 --- a/util/qemu-coroutine-sleep.c +++ b/util/qemu-coroutine-sleep.c @@ -31,9 +31,9 @@ static void co_sleep_cb(void *opaque) aio_co_wake(sleep_cb->co); } -void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type, - int64_t ns) +void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns) { + AioContext *ctx = qemu_get_current_aio_context(); CoSleepCB sleep_cb = { .co = qemu_coroutine_self(), }; From e01d6a415bec6fb93a7413929fb1438a22d28419 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 22 Nov 2017 11:08:43 +0800 Subject: [PATCH 253/546] hw/block/nvme: Convert to realize Convert nvme_init() to realize and rename it to nvme_realize(). Cc: John Snow Cc: Keith Busch Cc: Kevin Wolf Cc: Max Reitz Cc: Markus Armbruster Signed-off-by: Mao Zhongyi Message-id: 2882e72d795e04cbe2120f569d551aef2467ac60.1511317952.git.maozy.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi --- hw/block/nvme.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index 441e21ed1f..e530ba7a30 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -920,7 +920,7 @@ static const MemoryRegionOps nvme_cmb_ops = { }, }; -static int nvme_init(PCIDevice *pci_dev) +static void nvme_realize(PCIDevice *pci_dev, Error **errp) { NvmeCtrl *n = NVME(pci_dev); NvmeIdCtrl *id = &n->id_ctrl; @@ -931,24 +931,27 @@ static int nvme_init(PCIDevice *pci_dev) Error *local_err = NULL; if (!n->conf.blk) { - return -1; + error_setg(errp, "drive property not set"); + return; } bs_size = blk_getlength(n->conf.blk); if (bs_size < 0) { - return -1; + error_setg(errp, "could not get backing file size"); + return; } blkconf_serial(&n->conf, &n->serial); if (!n->serial) { - return -1; + error_setg(errp, "serial property not set"); + return; } blkconf_blocksizes(&n->conf); blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), false, &local_err); if (local_err) { - error_report_err(local_err); - return -1; + error_propagate(errp, local_err); + return; } pci_conf = pci_dev->config; @@ -1046,7 +1049,6 @@ static int nvme_init(PCIDevice *pci_dev) cpu_to_le64(n->ns_size >> id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(ns->id_ns.flbas)].ds); } - return 0; } static void nvme_exit(PCIDevice *pci_dev) @@ -1081,7 +1083,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); - pc->init = nvme_init; + pc->realize = nvme_realize; pc->exit = nvme_exit; pc->class_id = PCI_CLASS_STORAGE_EXPRESS; pc->vendor_id = PCI_VENDOR_ID_INTEL; From 9d3b155186c2788570f4802700d030c84e0f0746 Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 22 Nov 2017 11:08:44 +0800 Subject: [PATCH 254/546] hw/block: Fix the return type When the function no success value to transmit, it usually make the function return void. It has turned out not to be a success, because it means that the extra local_err variable and error_propagate() will be needed. It leads to cumbersome code, therefore, transmit success/ failure in the return value is worth. So fix the return type of blkconf_apply_backend_options(), blkconf_geometry() and virtio_blk_data_plane_create() to avoid it. Cc: John Snow Cc: Kevin Wolf Cc: Max Reitz Cc: Stefan Hajnoczi Signed-off-by: Mao Zhongyi Reviewed-by: Stefan Hajnoczi Message-id: ac0edc1fc70c4457e5cec94405eb7d1f89f9c2c1.1511317952.git.maozy.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi --- hw/block/block.c | 15 +++++++++------ hw/block/dataplane/virtio-blk.c | 12 +++++++----- hw/block/dataplane/virtio-blk.h | 2 +- include/hw/block/block.h | 4 ++-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/hw/block/block.c b/hw/block/block.c index 27878d0087..b0269c857f 100644 --- a/hw/block/block.c +++ b/hw/block/block.c @@ -51,7 +51,7 @@ void blkconf_blocksizes(BlockConf *conf) } } -void blkconf_apply_backend_options(BlockConf *conf, bool readonly, +bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, bool resizable, Error **errp) { BlockBackend *blk = conf->blk; @@ -76,7 +76,7 @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly, ret = blk_set_perm(blk, perm, shared_perm, errp); if (ret < 0) { - return; + return false; } switch (conf->wce) { @@ -99,9 +99,11 @@ void blkconf_apply_backend_options(BlockConf *conf, bool readonly, blk_set_enable_write_cache(blk, wce); blk_set_on_error(blk, rerror, werror); + + return true; } -void blkconf_geometry(BlockConf *conf, int *ptrans, +bool blkconf_geometry(BlockConf *conf, int *ptrans, unsigned cyls_max, unsigned heads_max, unsigned secs_max, Error **errp) { @@ -129,15 +131,16 @@ void blkconf_geometry(BlockConf *conf, int *ptrans, if (conf->cyls || conf->heads || conf->secs) { if (conf->cyls < 1 || conf->cyls > cyls_max) { error_setg(errp, "cyls must be between 1 and %u", cyls_max); - return; + return false; } if (conf->heads < 1 || conf->heads > heads_max) { error_setg(errp, "heads must be between 1 and %u", heads_max); - return; + return false; } if (conf->secs < 1 || conf->secs > secs_max) { error_setg(errp, "secs must be between 1 and %u", secs_max); - return; + return false; } } + return true; } diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 5556f0e64e..f6fc639e88 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -76,7 +76,7 @@ static void notify_guest_bh(void *opaque) } /* Context: QEMU global mutex held */ -void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, VirtIOBlockDataPlane **dataplane, Error **errp) { @@ -91,11 +91,11 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, error_setg(errp, "device is incompatible with iothread " "(transport does not support notifiers)"); - return; + return false; } if (!virtio_device_ioeventfd_enabled(vdev)) { error_setg(errp, "ioeventfd is required for iothread"); - return; + return false; } /* If dataplane is (re-)enabled while the guest is running there could @@ -103,12 +103,12 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, */ if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { error_prepend(errp, "cannot start virtio-blk dataplane: "); - return; + return false; } } /* Don't try if transport does not support notifiers. */ if (!virtio_device_ioeventfd_enabled(vdev)) { - return; + return false; } s = g_new0(VirtIOBlockDataPlane, 1); @@ -126,6 +126,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, s->batch_notify_vqs = bitmap_new(conf->num_queues); *dataplane = s; + + return true; } /* Context: QEMU global mutex held */ diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h index db3f47b173..5e18bb99ae 100644 --- a/hw/block/dataplane/virtio-blk.h +++ b/hw/block/dataplane/virtio-blk.h @@ -19,7 +19,7 @@ typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane; -void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, +bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, VirtIOBlockDataPlane **dataplane, Error **errp); void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); diff --git a/include/hw/block/block.h b/include/hw/block/block.h index f3f6e8ef02..64b9298829 100644 --- a/include/hw/block/block.h +++ b/include/hw/block/block.h @@ -72,11 +72,11 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf) /* Configuration helpers */ void blkconf_serial(BlockConf *conf, char **serial); -void blkconf_geometry(BlockConf *conf, int *trans, +bool blkconf_geometry(BlockConf *conf, int *trans, unsigned cyls_max, unsigned heads_max, unsigned secs_max, Error **errp); void blkconf_blocksizes(BlockConf *conf); -void blkconf_apply_backend_options(BlockConf *conf, bool readonly, +bool blkconf_apply_backend_options(BlockConf *conf, bool readonly, bool resizable, Error **errp); /* Hard disk geometry */ From ceff3e1f01ee8c0d77de7e3750e7297c3af7e2ec Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 22 Nov 2017 11:08:45 +0800 Subject: [PATCH 255/546] hw/block: Use errp directly rather than local_err [Drop virtio_blk_data_plane_create() change that misinterprets return value when the virtio transport does not support dataplane. --Stefan] Cc: John Snow Cc: Kevin Wolf Cc: Max Reitz Cc: Keith Busch Cc: Stefan Hajnoczi Cc: "Michael S. Tsirkin" Cc: Paolo Bonzini Cc: Gerd Hoffmann Cc: Markus Armbruster Signed-off-by: Mao Zhongyi Reviewed-by: Stefan Hajnoczi Message-id: e77848d3735ba590f23ffbf8094379c646c33d79.1511317952.git.maozy.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi --- hw/block/fdc.c | 17 ++++++----------- hw/block/nvme.c | 7 ++----- hw/block/virtio-blk.c | 13 +++++-------- hw/ide/qdev.c | 12 ++++-------- hw/scsi/scsi-disk.c | 13 ++++--------- hw/usb/dev-storage.c | 9 +++------ 6 files changed, 24 insertions(+), 47 deletions(-) diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 67f78ac702..7b7dd41296 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -473,16 +473,13 @@ static void fd_revalidate(FDrive *drv) static void fd_change_cb(void *opaque, bool load, Error **errp) { FDrive *drive = opaque; - Error *local_err = NULL; if (!load) { blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort); } else { - blkconf_apply_backend_options(drive->conf, - blk_is_read_only(drive->blk), false, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!blkconf_apply_backend_options(drive->conf, + blk_is_read_only(drive->blk), false, + errp)) { return; } } @@ -522,7 +519,6 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) FloppyDrive *dev = FLOPPY_DRIVE(qdev); FloppyBus *bus = FLOPPY_BUS(qdev->parent_bus); FDrive *drive; - Error *local_err = NULL; int ret; if (dev->unit == -1) { @@ -568,10 +564,9 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO; dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO; - blkconf_apply_backend_options(&dev->conf, blk_is_read_only(dev->conf.blk), - false, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!blkconf_apply_backend_options(&dev->conf, + blk_is_read_only(dev->conf.blk), + false, errp)) { return; } diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e530ba7a30..e529e88e4e 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -928,7 +928,6 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) int i; int64_t bs_size; uint8_t *pci_conf; - Error *local_err = NULL; if (!n->conf.blk) { error_setg(errp, "drive property not set"); @@ -947,10 +946,8 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) return; } blkconf_blocksizes(&n->conf); - blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), - false, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk), + false, errp)) { return; } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 05d1440786..41a4ccdede 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -930,19 +930,16 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) } blkconf_serial(&conf->conf, &conf->serial); - blkconf_apply_backend_options(&conf->conf, - blk_is_read_only(conf->conf.blk), true, - &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_apply_backend_options(&conf->conf, + blk_is_read_only(conf->conf.blk), true, + errp)) { return; } s->original_wce = blk_enable_write_cache(conf->conf.blk); - blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, errp)) { return; } + blkconf_blocksizes(&conf->conf); virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index a5181b4448..f395d24592 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -160,7 +160,6 @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp) { IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus); IDEState *s = bus->ifs + dev->unit; - Error *err = NULL; int ret; if (!dev->conf.blk) { @@ -191,16 +190,13 @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp) blkconf_serial(&dev->conf, &dev->serial); if (kind != IDE_CD) { - blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255, + errp)) { return; } } - blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, kind != IDE_CD, - &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_apply_backend_options(&dev->conf, kind == IDE_CD, + kind != IDE_CD, errp)) { return; } diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 12431177a7..870d9ae85a 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -2332,7 +2332,6 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev) static void scsi_realize(SCSIDevice *dev, Error **errp) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); - Error *err = NULL; if (!s->qdev.conf.blk) { error_setg(errp, "drive property not set"); @@ -2356,17 +2355,13 @@ static void scsi_realize(SCSIDevice *dev, Error **errp) } if (dev->type == TYPE_DISK) { - blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, errp)) { return; } } - blkconf_apply_backend_options(&dev->conf, - blk_is_read_only(s->qdev.conf.blk), - dev->type == TYPE_DISK, &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_apply_backend_options(&dev->conf, + blk_is_read_only(s->qdev.conf.blk), + dev->type == TYPE_DISK, errp)) { return; } diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 8a61ec94c8..a9bcc67e67 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -601,7 +601,6 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) MSDState *s = USB_STORAGE_DEV(dev); BlockBackend *blk = s->conf.blk; SCSIDevice *scsi_dev; - Error *err = NULL; if (!blk) { error_setg(errp, "drive property not set"); @@ -610,9 +609,8 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) blkconf_serial(&s->conf, &dev->serial); blkconf_blocksizes(&s->conf); - blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, &err); - if (err) { - error_propagate(errp, err); + if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true, + errp)) { return; } @@ -636,10 +634,9 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) &usb_msd_scsi_info_storage, NULL); scsi_dev = scsi_bus_legacy_add_drive(&s->bus, blk, 0, !!s->removable, s->conf.bootindex, dev->serial, - &err); + errp); blk_unref(blk); if (!scsi_dev) { - error_propagate(errp, err); return; } usb_msd_handle_reset(dev); From 6db3ea39e2650dc4fbcd18e075510f162265512f Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Wed, 22 Nov 2017 11:08:46 +0800 Subject: [PATCH 256/546] dev-storage: Fix the unusual function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function name of usb_msd_{realize,unrealize}_*, usb_msd_class_initfn_* are unusual. Rename it to usb_msd_*_{realize,unrealize}, usb_msd_class_*_initfn. Cc: Gerd Hoffmann Signed-off-by: Mao Zhongyi Reviewed-by: Philippe Mathieu-Daudé Message-id: 11e6003433abce35f3f4970e1acc71ee92dbcf51.1511317952.git.maozy.fnst@cn.fujitsu.com Signed-off-by: Stefan Hajnoczi --- hw/usb/dev-storage.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index a9bcc67e67..9722ac854c 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -596,7 +596,7 @@ static void usb_msd_unrealize_storage(USBDevice *dev, Error **errp) object_unref(OBJECT(&s->bus)); } -static void usb_msd_realize_storage(USBDevice *dev, Error **errp) +static void usb_msd_storage_realize(USBDevice *dev, Error **errp) { MSDState *s = USB_STORAGE_DEV(dev); BlockBackend *blk = s->conf.blk; @@ -643,14 +643,14 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp) s->scsi_dev = scsi_dev; } -static void usb_msd_unrealize_bot(USBDevice *dev, Error **errp) +static void usb_msd_bot_unrealize(USBDevice *dev, Error **errp) { MSDState *s = USB_STORAGE_DEV(dev); object_unref(OBJECT(&s->bus)); } -static void usb_msd_realize_bot(USBDevice *dev, Error **errp) +static void usb_msd_bot_realize(USBDevice *dev, Error **errp) { MSDState *s = USB_STORAGE_DEV(dev); DeviceState *d = DEVICE(dev); @@ -764,12 +764,12 @@ static void usb_msd_class_initfn_common(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_msd; } -static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data) +static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->realize = usb_msd_realize_storage; + uc->realize = usb_msd_storage_realize; uc->unrealize = usb_msd_unrealize_storage; dc->props = msd_properties; } @@ -828,26 +828,26 @@ static void usb_msd_instance_init(Object *obj) object_property_set_int(obj, -1, "bootindex", NULL); } -static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) +static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->realize = usb_msd_realize_bot; - uc->unrealize = usb_msd_unrealize_bot; + uc->realize = usb_msd_bot_realize; + uc->unrealize = usb_msd_bot_unrealize; uc->attached_settable = true; } static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_STORAGE, - .class_init = usb_msd_class_initfn_storage, + .class_init = usb_msd_class_storage_initfn, .instance_init = usb_msd_instance_init, }; static const TypeInfo bot_info = { .name = "usb-bot", .parent = TYPE_USB_STORAGE, - .class_init = usb_msd_class_initfn_bot, + .class_init = usb_msd_class_bot_initfn, }; static void usb_msd_register_types(void) From a12aef24fa3e3312fac024ac22809ee9deb4d98a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Dec 2017 13:39:54 +0000 Subject: [PATCH 257/546] qdev: drop unused #include "sysemu/iothread.h" Commit 1351d1ec89eabebc9fdff20451a62c413d7accc1 ("qdev: drop iothread property type") forgot to remove this include. Signed-off-by: Stefan Hajnoczi Message-id: 20171205133954.31006-1-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/core/qdev-properties-system.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index c17364655c..46b3843cf8 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -22,7 +22,6 @@ #include "qapi/visitor.h" #include "chardev/char-fe.h" #include "sysemu/tpm_backend.h" -#include "sysemu/iothread.h" static void get_pointer(Object *obj, Visitor *v, Property *prop, char *(*print)(void *ptr), From b9464ba19f821ea6b29969104dc48dcdb26243dd Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:42 +0000 Subject: [PATCH 258/546] blockdev: hold AioContext for bdrv_unref() in external_snapshot_clean() bdrv_unref() requires the AioContext lock because bdrv_flush() uses BDRV_POLL_WHILE(), which assumes the AioContext is currently held. If BDRV_POLL_WHILE() runs without AioContext held the pthread_mutex_unlock() call in aio_context_release() fails. This patch moves bdrv_unref() into the AioContext locked region to solve the following pthread_mutex_unlock() failure: #0 0x00007f566181969b in raise () at /lib64/libc.so.6 #1 0x00007f566181b3b1 in abort () at /lib64/libc.so.6 #2 0x00005592cd590458 in error_exit (err=, msg=msg@entry=0x5592cdaf6d60 <__func__.23977> "qemu_mutex_unlock") at util/qemu-thread-posix.c:36 #3 0x00005592cd96e738 in qemu_mutex_unlock (mutex=mutex@entry=0x5592ce9505e0) at util/qemu-thread-posix.c:96 #4 0x00005592cd969b69 in aio_context_release (ctx=ctx@entry=0x5592ce950580) at util/async.c:507 #5 0x00005592cd8ead78 in bdrv_flush (bs=bs@entry=0x5592cfa87210) at block/io.c:2478 #6 0x00005592cd89df30 in bdrv_close (bs=0x5592cfa87210) at block.c:3207 #7 0x00005592cd89df30 in bdrv_delete (bs=0x5592cfa87210) at block.c:3395 #8 0x00005592cd89df30 in bdrv_unref (bs=0x5592cfa87210) at block.c:4418 #9 0x00005592cd6b7f86 in qmp_transaction (dev_list=, has_props=, props=, errp=errp@entry=0x7ffe4a1fc9d8) at blockdev.c:2308 Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-2-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockdev.c b/blockdev.c index 56a6b24a0b..3c8d994ced 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1812,8 +1812,8 @@ static void external_snapshot_clean(BlkActionState *common) DO_UPCAST(ExternalSnapshotState, common, common); if (state->aio_context) { bdrv_drained_end(state->old_bs); - aio_context_release(state->aio_context); bdrv_unref(state->new_bs); + aio_context_release(state->aio_context); } } From 2d24b60b7747f7bf40fd00b0375b6bd988d4f0d9 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:43 +0000 Subject: [PATCH 259/546] block: don't keep AioContext acquired after external_snapshot_prepare() It is not necessary to hold AioContext across transactions anymore since bdrv_drained_begin/end() is used to keep the nodes quiesced. In fact, using the AioContext lock for this purpose was always buggy. This patch reduces the scope of AioContext locked regions. This is not just a cleanup but also fixes hangs that occur in BDRV_POLL_WHILE() because it is unware of recursive locking and does not release the AioContext the necessary number of times to allow progress to be made. Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 71 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/blockdev.c b/blockdev.c index 3c8d994ced..3b598f8f0e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1606,7 +1606,6 @@ typedef struct ExternalSnapshotState { BlkActionState common; BlockDriverState *old_bs; BlockDriverState *new_bs; - AioContext *aio_context; bool overlay_appended; } ExternalSnapshotState; @@ -1626,6 +1625,7 @@ static void external_snapshot_prepare(BlkActionState *common, ExternalSnapshotState *state = DO_UPCAST(ExternalSnapshotState, common, common); TransactionAction *action = common->action; + AioContext *aio_context; /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar * purpose but a different set of parameters */ @@ -1662,31 +1662,32 @@ static void external_snapshot_prepare(BlkActionState *common, return; } - /* Acquire AioContext now so any threads operating on old_bs stop */ - state->aio_context = bdrv_get_aio_context(state->old_bs); - aio_context_acquire(state->aio_context); + aio_context = bdrv_get_aio_context(state->old_bs); + aio_context_acquire(aio_context); + + /* Paired with .clean() */ bdrv_drained_begin(state->old_bs); if (!bdrv_is_inserted(state->old_bs)) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); - return; + goto out; } if (bdrv_op_is_blocked(state->old_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) { - return; + goto out; } if (!bdrv_is_read_only(state->old_bs)) { if (bdrv_flush(state->old_bs)) { error_setg(errp, QERR_IO_ERROR); - return; + goto out; } } if (!bdrv_is_first_non_filter(state->old_bs)) { error_setg(errp, QERR_FEATURE_DISABLED, "snapshot"); - return; + goto out; } if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) { @@ -1698,13 +1699,13 @@ static void external_snapshot_prepare(BlkActionState *common, if (node_name && !snapshot_node_name) { error_setg(errp, "New snapshot node name missing"); - return; + goto out; } if (snapshot_node_name && bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) { error_setg(errp, "New snapshot node name already in use"); - return; + goto out; } flags = state->old_bs->open_flags; @@ -1717,7 +1718,7 @@ static void external_snapshot_prepare(BlkActionState *common, int64_t size = bdrv_getlength(state->old_bs); if (size < 0) { error_setg_errno(errp, -size, "bdrv_getlength failed"); - return; + goto out; } bdrv_img_create(new_image_file, format, state->old_bs->filename, @@ -1725,7 +1726,7 @@ static void external_snapshot_prepare(BlkActionState *common, NULL, size, flags, false, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } } @@ -1740,30 +1741,30 @@ static void external_snapshot_prepare(BlkActionState *common, errp); /* We will manually add the backing_hd field to the bs later */ if (!state->new_bs) { - return; + goto out; } if (bdrv_has_blk(state->new_bs)) { error_setg(errp, "The snapshot is already in use"); - return; + goto out; } if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) { - return; + goto out; } if (state->new_bs->backing != NULL) { error_setg(errp, "The snapshot already has a backing image"); - return; + goto out; } if (!state->new_bs->drv->supports_backing) { error_setg(errp, "The snapshot does not support backing images"); - return; + goto out; } - bdrv_set_aio_context(state->new_bs, state->aio_context); + bdrv_set_aio_context(state->new_bs, aio_context); /* This removes our old bs and adds the new bs. This is an operation that * can fail, so we need to do it in .prepare; undoing it for abort is @@ -1772,15 +1773,22 @@ static void external_snapshot_prepare(BlkActionState *common, bdrv_append(state->new_bs, state->old_bs, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } state->overlay_appended = true; + +out: + aio_context_release(aio_context); } static void external_snapshot_commit(BlkActionState *common) { ExternalSnapshotState *state = DO_UPCAST(ExternalSnapshotState, common, common); + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->old_bs); + aio_context_acquire(aio_context); /* We don't need (or want) to use the transactional * bdrv_reopen_multiple() across all the entries at once, because we @@ -1789,6 +1797,8 @@ static void external_snapshot_commit(BlkActionState *common) bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR, NULL); } + + aio_context_release(aio_context); } static void external_snapshot_abort(BlkActionState *common) @@ -1797,11 +1807,18 @@ static void external_snapshot_abort(BlkActionState *common) DO_UPCAST(ExternalSnapshotState, common, common); if (state->new_bs) { if (state->overlay_appended) { + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->old_bs); + aio_context_acquire(aio_context); + bdrv_ref(state->old_bs); /* we can't let bdrv_set_backind_hd() close state->old_bs; we need it */ bdrv_set_backing_hd(state->new_bs, NULL, &error_abort); bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */ + + aio_context_release(aio_context); } } } @@ -1810,11 +1827,19 @@ static void external_snapshot_clean(BlkActionState *common) { ExternalSnapshotState *state = DO_UPCAST(ExternalSnapshotState, common, common); - if (state->aio_context) { - bdrv_drained_end(state->old_bs); - bdrv_unref(state->new_bs); - aio_context_release(state->aio_context); + AioContext *aio_context; + + if (!state->old_bs) { + return; } + + aio_context = bdrv_get_aio_context(state->old_bs); + aio_context_acquire(aio_context); + + bdrv_drained_end(state->old_bs); + bdrv_unref(state->new_bs); + + aio_context_release(aio_context); } typedef struct DriveBackupState { From 66d56054bca3c1c45861d18ea97f147f7d376d21 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:44 +0000 Subject: [PATCH 260/546] block: don't keep AioContext acquired after drive_backup_prepare() Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-4-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/blockdev.c b/blockdev.c index 3b598f8f0e..5a56a1abf2 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1845,7 +1845,6 @@ static void external_snapshot_clean(BlkActionState *common) typedef struct DriveBackupState { BlkActionState common; BlockDriverState *bs; - AioContext *aio_context; BlockJob *job; } DriveBackupState; @@ -1857,6 +1856,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); BlockDriverState *bs; DriveBackup *backup; + AioContext *aio_context; Error *local_err = NULL; assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); @@ -1867,24 +1867,36 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp) return; } - /* AioContext is released in .clean() */ - state->aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(state->aio_context); + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); + + /* Paired with .clean() */ bdrv_drained_begin(bs); + state->bs = bs; state->job = do_drive_backup(backup, common->block_job_txn, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } + +out: + aio_context_release(aio_context); } static void drive_backup_commit(BlkActionState *common) { DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + assert(state->job); block_job_start(state->job); + + aio_context_release(aio_context); } static void drive_backup_abort(BlkActionState *common) @@ -1892,18 +1904,32 @@ static void drive_backup_abort(BlkActionState *common) DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); if (state->job) { + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + block_job_cancel_sync(state->job); + + aio_context_release(aio_context); } } static void drive_backup_clean(BlkActionState *common) { DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); + AioContext *aio_context; - if (state->aio_context) { - bdrv_drained_end(state->bs); - aio_context_release(state->aio_context); + if (!state->bs) { + return; } + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + + bdrv_drained_end(state->bs); + + aio_context_release(aio_context); } typedef struct BlockdevBackupState { From edd5adeecddf665e7954bc146ff458bb30f178ae Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:45 +0000 Subject: [PATCH 261/546] block: don't keep AioContext acquired after blockdev_backup_prepare() Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-5-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/blockdev.c b/blockdev.c index 5a56a1abf2..d7ad76416e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1936,7 +1936,6 @@ typedef struct BlockdevBackupState { BlkActionState common; BlockDriverState *bs; BlockJob *job; - AioContext *aio_context; } BlockdevBackupState; static BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, @@ -1947,6 +1946,7 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); BlockdevBackup *backup; BlockDriverState *bs, *target; + AioContext *aio_context; Error *local_err = NULL; assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); @@ -1962,29 +1962,39 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp) return; } - /* AioContext is released in .clean() */ - state->aio_context = bdrv_get_aio_context(bs); - if (state->aio_context != bdrv_get_aio_context(target)) { - state->aio_context = NULL; + aio_context = bdrv_get_aio_context(bs); + if (aio_context != bdrv_get_aio_context(target)) { error_setg(errp, "Backup between two IO threads is not implemented"); return; } - aio_context_acquire(state->aio_context); + aio_context_acquire(aio_context); state->bs = bs; + + /* Paired with .clean() */ bdrv_drained_begin(state->bs); state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } + +out: + aio_context_release(aio_context); } static void blockdev_backup_commit(BlkActionState *common) { BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + assert(state->job); block_job_start(state->job); + + aio_context_release(aio_context); } static void blockdev_backup_abort(BlkActionState *common) @@ -1992,18 +2002,32 @@ static void blockdev_backup_abort(BlkActionState *common) BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); if (state->job) { + AioContext *aio_context; + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + block_job_cancel_sync(state->job); + + aio_context_release(aio_context); } } static void blockdev_backup_clean(BlkActionState *common) { BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); + AioContext *aio_context; - if (state->aio_context) { - bdrv_drained_end(state->bs); - aio_context_release(state->aio_context); + if (!state->bs) { + return; } + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + + bdrv_drained_end(state->bs); + + aio_context_release(aio_context); } typedef struct BlockDirtyBitmapState { From a36e458cdda0196911c1cbe7cfe6f9530f2280e3 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:46 +0000 Subject: [PATCH 262/546] block: don't keep AioContext acquired after internal_snapshot_prepare() Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-6-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/blockdev.c b/blockdev.c index d7ad76416e..6332a249ea 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1454,7 +1454,6 @@ struct BlkActionState { typedef struct InternalSnapshotState { BlkActionState common; BlockDriverState *bs; - AioContext *aio_context; QEMUSnapshotInfo sn; bool created; } InternalSnapshotState; @@ -1485,6 +1484,7 @@ static void internal_snapshot_prepare(BlkActionState *common, qemu_timeval tv; BlockdevSnapshotInternal *internal; InternalSnapshotState *state; + AioContext *aio_context; int ret1; g_assert(common->action->type == @@ -1506,32 +1506,33 @@ static void internal_snapshot_prepare(BlkActionState *common, return; } - /* AioContext is released in .clean() */ - state->aio_context = bdrv_get_aio_context(bs); - aio_context_acquire(state->aio_context); + aio_context = bdrv_get_aio_context(bs); + aio_context_acquire(aio_context); state->bs = bs; + + /* Paired with .clean() */ bdrv_drained_begin(bs); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) { - return; + goto out; } if (bdrv_is_read_only(bs)) { error_setg(errp, "Device '%s' is read only", device); - return; + goto out; } if (!bdrv_can_snapshot(bs)) { error_setg(errp, "Block format '%s' used by device '%s' " "does not support internal snapshots", bs->drv->format_name, device); - return; + goto out; } if (!strlen(name)) { error_setg(errp, "Name is empty"); - return; + goto out; } /* check whether a snapshot with name exist */ @@ -1539,12 +1540,12 @@ static void internal_snapshot_prepare(BlkActionState *common, &local_err); if (local_err) { error_propagate(errp, local_err); - return; + goto out; } else if (ret) { error_setg(errp, "Snapshot with name '%s' already exists on device '%s'", name, device); - return; + goto out; } /* 3. take the snapshot */ @@ -1560,11 +1561,14 @@ static void internal_snapshot_prepare(BlkActionState *common, error_setg_errno(errp, -ret1, "Failed to create snapshot '%s' on device '%s'", name, device); - return; + goto out; } /* 4. succeed, mark a snapshot is created */ state->created = true; + +out: + aio_context_release(aio_context); } static void internal_snapshot_abort(BlkActionState *common) @@ -1573,12 +1577,16 @@ static void internal_snapshot_abort(BlkActionState *common) DO_UPCAST(InternalSnapshotState, common, common); BlockDriverState *bs = state->bs; QEMUSnapshotInfo *sn = &state->sn; + AioContext *aio_context; Error *local_error = NULL; if (!state->created) { return; } + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) { error_reportf_err(local_error, "Failed to delete snapshot with id '%s' and " @@ -1586,19 +1594,26 @@ static void internal_snapshot_abort(BlkActionState *common) sn->id_str, sn->name, bdrv_get_device_name(bs)); } + + aio_context_release(aio_context); } static void internal_snapshot_clean(BlkActionState *common) { InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState, common, common); + AioContext *aio_context; - if (state->aio_context) { - if (state->bs) { - bdrv_drained_end(state->bs); - } - aio_context_release(state->aio_context); + if (!state->bs) { + return; } + + aio_context = bdrv_get_aio_context(state->bs); + aio_context_acquire(aio_context); + + bdrv_drained_end(state->bs); + + aio_context_release(aio_context); } /* external snapshot private data */ From 5016f21b705152d138395f90219b665ddce89c1b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:47 +0000 Subject: [PATCH 263/546] block: drop unused BlockDirtyBitmapState->aio_context field The dirty bitmap actions in qmp_transaction have not used AioContext since the dirty bitmap locking discipline was introduced in commit 2119882c7eb7e2c612b24fc0c8d86f5887d6f1c3 ("block: introduce dirty_bitmap_mutex"). Remove the unused field. Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-7-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/blockdev.c b/blockdev.c index 6332a249ea..e865ae4873 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2049,7 +2049,6 @@ typedef struct BlockDirtyBitmapState { BlkActionState common; BdrvDirtyBitmap *bitmap; BlockDriverState *bs; - AioContext *aio_context; HBitmap *backup; bool prepared; } BlockDirtyBitmapState; @@ -2128,7 +2127,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common, } bdrv_clear_dirty_bitmap(state->bitmap, &state->backup); - /* AioContext is released in .clean() */ } static void block_dirty_bitmap_clear_abort(BlkActionState *common) @@ -2149,16 +2147,6 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common) hbitmap_free(state->backup); } -static void block_dirty_bitmap_clear_clean(BlkActionState *common) -{ - BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState, - common, common); - - if (state->aio_context) { - aio_context_release(state->aio_context); - } -} - static void abort_prepare(BlkActionState *common, Error **errp) { error_setg(errp, "Transaction aborted using Abort action"); @@ -2219,7 +2207,6 @@ static const BlkActionOps actions[] = { .prepare = block_dirty_bitmap_clear_prepare, .commit = block_dirty_bitmap_clear_commit, .abort = block_dirty_bitmap_clear_abort, - .clean = block_dirty_bitmap_clear_clean, } }; From fbcc6923b00c2b468a7470fec7863f0403a65736 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:48 +0000 Subject: [PATCH 264/546] iothread: add iothread_by_id() API Encapsulate IOThread QOM object lookup so that callers don't need to know how and where IOThread objects live. Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-8-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- include/sysemu/iothread.h | 1 + iothread.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 110329b2b4..55de1715c7 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -42,6 +42,7 @@ typedef struct { OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) char *iothread_get_id(IOThread *iothread); +IOThread *iothread_by_id(const char *id); AioContext *iothread_get_aio_context(IOThread *iothread); void iothread_stop_all(void); GMainContext *iothread_get_g_main_context(IOThread *iothread); diff --git a/iothread.c b/iothread.c index 27a4288578..e7b93e02a3 100644 --- a/iothread.c +++ b/iothread.c @@ -380,3 +380,10 @@ void iothread_destroy(IOThread *iothread) { object_unparent(OBJECT(iothread)); } + +/* Lookup IOThread by its id. Only finds user-created objects, not internal + * iothread_create() objects. */ +IOThread *iothread_by_id(const char *id) +{ + return IOTHREAD(object_resolve_path_type(id, TYPE_IOTHREAD, NULL)); +} From ca00bbb153d03c5338d8c8136812163f463f841e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:49 +0000 Subject: [PATCH 265/546] blockdev: add x-blockdev-set-iothread testing command Currently there is no easy way for iotests to ensure that a BDS is bound to a particular IOThread. Normally the virtio-blk device calls blk_set_aio_context() when dataplane is enabled during guest driver initialization. This never happens in iotests since -machine accel=qtest means there is no guest activity (including device driver initialization). This patch adds a QMP command to explicitly assign IOThreads in test cases. See qapi/block-core.json for a description of the command. Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-9-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 41 +++++++++++++++++++++++++++++++++++++++++ qapi/block-core.json | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/blockdev.c b/blockdev.c index e865ae4873..f75c01f664 100644 --- a/blockdev.c +++ b/blockdev.c @@ -45,6 +45,7 @@ #include "qapi/qmp/qerror.h" #include "qapi/qobject-output-visitor.h" #include "sysemu/sysemu.h" +#include "sysemu/iothread.h" #include "block/block_int.h" #include "qmp-commands.h" #include "block/trace.h" @@ -4129,6 +4130,46 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) return head; } +void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, + Error **errp) +{ + AioContext *old_context; + AioContext *new_context; + BlockDriverState *bs; + + bs = bdrv_find_node(node_name); + if (!bs) { + error_setg(errp, "Cannot find node %s", node_name); + return; + } + + /* If we want to allow more extreme test scenarios this guard could be + * removed. For now it protects against accidents. */ + if (bdrv_has_blk(bs)) { + error_setg(errp, "Node %s is in use", node_name); + return; + } + + if (iothread->type == QTYPE_QSTRING) { + IOThread *obj = iothread_by_id(iothread->u.s); + if (!obj) { + error_setg(errp, "Cannot find iothread %s", iothread->u.s); + return; + } + + new_context = iothread_get_aio_context(obj); + } else { + new_context = qemu_get_aio_context(); + } + + old_context = bdrv_get_aio_context(bs); + aio_context_acquire(old_context); + + bdrv_set_aio_context(bs, new_context); + + aio_context_release(old_context); +} + QemuOptsList qemu_common_drive_opts = { .name = "drive", .head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head), diff --git a/qapi/block-core.json b/qapi/block-core.json index dd763dcf87..741d6c4367 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3949,3 +3949,39 @@ 'data' : { 'parent': 'str', '*child': 'str', '*node': 'str' } } + +## +# @x-blockdev-set-iothread: +# +# Move @node and its children into the @iothread. If @iothread is null then +# move @node and its children into the main loop. +# +# The node must not be attached to a BlockBackend. +# +# @node-name: the name of the block driver node +# +# @iothread: the name of the IOThread object or null for the main loop +# +# Note: this command is experimental and intended for test cases that need +# control over IOThreads only. +# +# Since: 2.12 +# +# Example: +# +# 1. Move a node into an IOThread +# -> { "execute": "x-blockdev-set-iothread", +# "arguments": { "node-name": "disk1", +# "iothread": "iothread0" } } +# <- { "return": {} } +# +# 2. Move a node into the main loop +# -> { "execute": "x-blockdev-set-iothread", +# "arguments": { "node-name": "disk1", +# "iothread": null } } +# <- { "return": {} } +# +## +{ 'command': 'x-blockdev-set-iothread', + 'data' : { 'node-name': 'str', + 'iothread': 'StrOrNull' } } From 6dd64919ea36db9fd7e754ed394c25ced45ea39a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 6 Dec 2017 14:45:50 +0000 Subject: [PATCH 266/546] qemu-iotests: add 202 external snapshots IOThread test QMP 'transaction' blockdev-snapshot-sync with multiple disks in an IOThread is an untested code path. Several bugs have been found in connection with this command. This patch adds a test case to prevent future regressions. Signed-off-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Eric Blake Message-id: 20171206144550.22295-10-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/202 | 95 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/202.out | 11 +++++ tests/qemu-iotests/group | 1 + 3 files changed, 107 insertions(+) create mode 100755 tests/qemu-iotests/202 create mode 100644 tests/qemu-iotests/202.out diff --git a/tests/qemu-iotests/202 b/tests/qemu-iotests/202 new file mode 100755 index 0000000000..581ca34d79 --- /dev/null +++ b/tests/qemu-iotests/202 @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Creator/Owner: Stefan Hajnoczi +# +# Check that QMP 'transaction' blockdev-snapshot-sync with multiple drives on a +# single IOThread completes successfully. This particular command triggered a +# hang due to recursive AioContext locking and BDRV_POLL_WHILE(). Protect +# against regressions. + +import iotests + +iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.verify_platform(['linux']) + +with iotests.FilePath('disk0.img') as disk0_img_path, \ + iotests.FilePath('disk1.img') as disk1_img_path, \ + iotests.FilePath('disk0-snap.img') as disk0_snap_img_path, \ + iotests.FilePath('disk1-snap.img') as disk1_snap_img_path, \ + iotests.VM() as vm: + + img_size = '10M' + iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size) + iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size) + + iotests.log('Launching VM...') + vm.launch() + + iotests.log('Adding IOThread...') + iotests.log(vm.qmp('object-add', + qom_type='iothread', + id='iothread0')) + + iotests.log('Adding blockdevs...') + iotests.log(vm.qmp('blockdev-add', + driver=iotests.imgfmt, + node_name='disk0', + file={ + 'driver': 'file', + 'filename': disk0_img_path, + })) + iotests.log(vm.qmp('blockdev-add', + driver=iotests.imgfmt, + node_name='disk1', + file={ + 'driver': 'file', + 'filename': disk1_img_path, + })) + + iotests.log('Setting iothread...') + iotests.log(vm.qmp('x-blockdev-set-iothread', + node_name='disk0', + iothread='iothread0')) + iotests.log(vm.qmp('x-blockdev-set-iothread', + node_name='disk1', + iothread='iothread0')) + + iotests.log('Creating external snapshots...') + iotests.log(vm.qmp( + 'transaction', + actions=[ + { + 'data': { + 'node-name': 'disk0', + 'snapshot-file': disk0_snap_img_path, + 'snapshot-node-name': 'disk0-snap', + 'mode': 'absolute-paths', + 'format': iotests.imgfmt, + }, + 'type': 'blockdev-snapshot-sync' + }, { + 'data': { + 'node-name': 'disk1', + 'snapshot-file': disk1_snap_img_path, + 'snapshot-node-name': 'disk1-snap', + 'mode': 'absolute-paths', + 'format': iotests.imgfmt + }, + 'type': 'blockdev-snapshot-sync' + } + ])) diff --git a/tests/qemu-iotests/202.out b/tests/qemu-iotests/202.out new file mode 100644 index 0000000000..d5ea374e17 --- /dev/null +++ b/tests/qemu-iotests/202.out @@ -0,0 +1,11 @@ +Launching VM... +Adding IOThread... +{u'return': {}} +Adding blockdevs... +{u'return': {}} +{u'return': {}} +Setting iothread... +{u'return': {}} +{u'return': {}} +Creating external snapshots... +{u'return': {}} diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 3e688678dd..d0ee1e2e55 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -197,3 +197,4 @@ 197 rw auto quick 198 rw auto 200 rw auto +202 rw auto quick From 6040aedddb5f474a9c2304b6a432a652d82b3d3c Mon Sep 17 00:00:00 2001 From: Mark Kanda Date: Mon, 11 Dec 2017 09:16:24 -0600 Subject: [PATCH 267/546] virtio-blk: make queue size configurable Depending on the configuration, it can be beneficial to adjust the virtio-blk queue size to something other than the current default of 128. Add a new property to make the queue size configurable. Signed-off-by: Mark Kanda Reviewed-by: Karl Heubaum Reviewed-by: Martin K. Petersen Reviewed-by: Ameya More Message-id: 52e6d742811f10dbd16e996e86cf375b9577c187.1513005190.git.mark.kanda@oracle.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 10 +++++++++- include/hw/virtio/virtio-blk.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 41a4ccdede..66ab0b19c8 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -928,6 +928,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "num-queues property must be larger than 0"); return; } + if (!is_power_of_2(conf->queue_size) || + conf->queue_size > VIRTQUEUE_MAX_SIZE) { + error_setg(errp, "invalid queue-size property (%" PRIu16 "), " + "must be a power of 2 (max %d)", + conf->queue_size, VIRTQUEUE_MAX_SIZE); + return; + } blkconf_serial(&conf->conf, &conf->serial); if (!blkconf_apply_backend_options(&conf->conf, @@ -950,7 +957,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1; for (i = 0; i < conf->num_queues; i++) { - virtio_add_queue(vdev, 128, virtio_blk_handle_output); + virtio_add_queue(vdev, conf->queue_size, virtio_blk_handle_output); } virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { @@ -1009,6 +1016,7 @@ static Property virtio_blk_properties[] = { DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1), + DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128), DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD, IOThread *), DEFINE_PROP_END_OF_LIST(), diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index d3c8a6fa8c..5117431d96 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -39,6 +39,7 @@ struct VirtIOBlkConf uint32_t config_wce; uint32_t request_merging; uint16_t num_queues; + uint16_t queue_size; }; struct VirtIOBlockDataPlane; From 0a75b60cdb685fed09ac0c0783bc0d6052a00e5d Mon Sep 17 00:00:00 2001 From: Mark Kanda Date: Mon, 11 Dec 2017 09:16:25 -0600 Subject: [PATCH 268/546] virtio-blk: reject configs with logical block size > physical block size virtio-blk logical block size should never be larger than physical block size because it doesn't make sense to have such configurations. QEMU doesn't have a way to effectively express this condition; the best it can do is report the physical block exponent as 0 - indicating the logical block size equals the physical block size. This is identical to commit 3da023b5827543ee4c022986ea2ad9d1274410b2 but applied to virtio-blk (instead of virtio-scsi). Signed-off-by: Mark Kanda Reviewed-by: Konrad Rzeszutek Wilk Reviewed-by: Ameya More Reviewed-by: Martin K. Petersen Reviewed-by: Stefan Hajnoczi Message-id: 773169891f9f2deb4cb7c4ef2655580dbe24c1d1.1513005190.git.mark.kanda@oracle.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 66ab0b19c8..b1532e4e91 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -949,6 +949,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) blkconf_blocksizes(&conf->conf); + if (conf->conf.logical_block_size > + conf->conf.physical_block_size) { + error_setg(errp, + "logical_block_size > physical_block_size not supported"); + return; + } + virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, sizeof(struct virtio_blk_config)); From bd6458e410c1e7d2912357aeb399fe7d8ee9f9a3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 7 Dec 2017 20:13:15 +0000 Subject: [PATCH 269/546] block: avoid recursive AioContext acquire in bdrv_inactivate_all() BDRV_POLL_WHILE() does not support recursive AioContext locking. It only releases the AioContext lock once regardless of how many times the caller has acquired it. This results in a hang since the IOThread does not make progress while the AioContext is still locked. The following steps trigger the hang: $ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \ -object iothread,id=iothread0 \ -device virtio-scsi-pci,iothread=iothread0 \ -drive if=none,id=drive0,file=test.img,format=raw \ -device scsi-hd,drive=drive0 \ -drive if=none,id=drive1,file=test.img,format=raw \ -device scsi-hd,drive=drive1 $ qemu-system-x86_64 ...same options... \ -incoming tcp::1234 (qemu) migrate tcp:127.0.0.1:1234 ...hang... Tested-by: Stefan Hajnoczi Signed-off-by: Paolo Bonzini Reviewed-by: Eric Blake Message-id: 20171207201320.19284-2-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- block.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 9a1a0d1e73..1c37ce4554 100644 --- a/block.c +++ b/block.c @@ -4320,9 +4320,15 @@ int bdrv_inactivate_all(void) BdrvNextIterator it; int ret = 0; int pass; + GSList *aio_ctxs = NULL, *ctx; for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { - aio_context_acquire(bdrv_get_aio_context(bs)); + AioContext *aio_context = bdrv_get_aio_context(bs); + + if (!g_slist_find(aio_ctxs, aio_context)) { + aio_ctxs = g_slist_prepend(aio_ctxs, aio_context); + aio_context_acquire(aio_context); + } } /* We do two passes of inactivation. The first pass calls to drivers' @@ -4340,9 +4346,11 @@ int bdrv_inactivate_all(void) } out: - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { - aio_context_release(bdrv_get_aio_context(bs)); + for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) { + AioContext *aio_context = ctx->data; + aio_context_release(aio_context); } + g_slist_free(aio_ctxs); return ret; } From d02d8dde0c0fe3d77a31046e104a55f2e6c50bf6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Dec 2017 20:13:16 +0000 Subject: [PATCH 270/546] docs: mark nested AioContext locking as a legacy API See the patch for why nested AioContext locking is no longer allowed. Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171207201320.19284-3-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- docs/devel/multiple-iothreads.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt index e4d340bbb7..4f9012d154 100644 --- a/docs/devel/multiple-iothreads.txt +++ b/docs/devel/multiple-iothreads.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 Red Hat Inc. +Copyright (c) 2014-2017 Red Hat Inc. This work is licensed under the terms of the GNU GPL, version 2 or later. See the COPYING file in the top-level directory. @@ -92,8 +92,9 @@ aio_context_acquire()/aio_context_release() for mutual exclusion. Once the context is acquired no other thread can access it or run event loop iterations in this AioContext. -aio_context_acquire()/aio_context_release() calls may be nested. This -means you can call them if you're not sure whether #2 applies. +Legacy code sometimes nests aio_context_acquire()/aio_context_release() calls. +Do not use nesting anymore, it is incompatible with the BDRV_POLL_WHILE() macro +used in the block layer and can lead to hangs. There is currently no lock ordering rule if a thread needs to acquire multiple AioContexts simultaneously. Therefore, it is only safe for code holding the From 882e9b89af7c1086d97cee11b2437337e756fa00 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Dec 2017 20:13:17 +0000 Subject: [PATCH 271/546] blockdev: add x-blockdev-set-iothread force boolean When a node is already associated with a BlockBackend the x-blockdev-set-iothread command refuses to set the IOThread. This is to prevent accidentally changing the IOThread when the nodes are in use. When the nodes are created with -drive they automatically get a BlockBackend. In that case we know nothing is using them yet and it's safe to set the IOThread. Add a force boolean to override the check. Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171207201320.19284-4-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- blockdev.c | 11 ++++++----- qapi/block-core.json | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/blockdev.c b/blockdev.c index f75c01f664..9c3a430cfb 100644 --- a/blockdev.c +++ b/blockdev.c @@ -4131,7 +4131,7 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp) } void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, - Error **errp) + bool has_force, bool force, Error **errp) { AioContext *old_context; AioContext *new_context; @@ -4143,10 +4143,11 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread, return; } - /* If we want to allow more extreme test scenarios this guard could be - * removed. For now it protects against accidents. */ - if (bdrv_has_blk(bs)) { - error_setg(errp, "Node %s is in use", node_name); + /* Protects against accidents. */ + if (!(has_force && force) && bdrv_has_blk(bs)) { + error_setg(errp, "Node %s is associated with a BlockBackend and could " + "be in use (use force=true to override this check)", + node_name); return; } diff --git a/qapi/block-core.json b/qapi/block-core.json index 741d6c4367..a8cdbc300b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3962,6 +3962,9 @@ # # @iothread: the name of the IOThread object or null for the main loop # +# @force: true if the node and its children should be moved when a BlockBackend +# is already attached +# # Note: this command is experimental and intended for test cases that need # control over IOThreads only. # @@ -3984,4 +3987,5 @@ ## { 'command': 'x-blockdev-set-iothread', 'data' : { 'node-name': 'str', - 'iothread': 'StrOrNull' } } + 'iothread': 'StrOrNull', + '*force': 'bool' } } From ccc15f7dafff63cbcc3f6a7c51e380025d67f7f4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Dec 2017 20:13:18 +0000 Subject: [PATCH 272/546] iotests: add VM.add_object() The VM.add_object() method can be used to add IOThreads or memory backend objects. Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171207201320.19284-5-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/iotests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 6f057904a9..44477e9295 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -197,6 +197,11 @@ def __init__(self, path_suffix=''): socket_scm_helper=socket_scm_helper) self._num_drives = 0 + def add_object(self, opts): + self._args.append('-object') + self._args.append(opts) + return self + def add_device(self, opts): self._args.append('-device') self._args.append(opts) From 2362a28ea11c145e1a13ae79342d76dc118a72a6 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Dec 2017 20:13:19 +0000 Subject: [PATCH 273/546] iothread: fix iothread_stop() race condition There is a small chance that iothread_stop() hangs as follows: Thread 3 (Thread 0x7f63eba5f700 (LWP 16105)): #0 0x00007f64012c09b6 in ppoll () at /lib64/libc.so.6 #1 0x000055959992eac9 in ppoll (__ss=0x0, __timeout=0x0, __nfds=, __fds=) at /usr/include/bits/poll2.h:77 #2 0x000055959992eac9 in qemu_poll_ns (fds=, nfds=, timeout=) at util/qemu-timer.c:322 #3 0x0000559599930711 in aio_poll (ctx=0x55959bdb83c0, blocking=blocking@entry=true) at util/aio-posix.c:629 #4 0x00005595996806fe in iothread_run (opaque=0x55959bd78400) at iothread.c:59 #5 0x00007f640159f609 in start_thread () at /lib64/libpthread.so.0 #6 0x00007f64012cce6f in clone () at /lib64/libc.so.6 Thread 1 (Thread 0x7f640b45b280 (LWP 16103)): #0 0x00007f64015a0b6d in pthread_join () at /lib64/libpthread.so.0 #1 0x00005595999332ef in qemu_thread_join (thread=) at util/qemu-thread-posix.c:547 #2 0x00005595996808ae in iothread_stop (iothread=) at iothread.c:91 #3 0x000055959968094d in iothread_stop_iter (object=, opaque=) at iothread.c:102 #4 0x0000559599857d97 in do_object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 , opaque=opaque@entry=0x0, recurse=recurse@entry=false) at qom/object.c:852 #5 0x0000559599859477 in object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 , opaque=opaque@entry=0x0) at qom/object.c:867 #6 0x0000559599680a6e in iothread_stop_all () at iothread.c:341 #7 0x000055959955b1d5 in main (argc=, argv=, envp=) at vl.c:4913 The relevant code from iothread_run() is: while (!atomic_read(&iothread->stopping)) { aio_poll(iothread->ctx, true); and iothread_stop(): iothread->stopping = true; aio_notify(iothread->ctx); ... qemu_thread_join(&iothread->thread); The following scenario can occur: 1. IOThread: while (!atomic_read(&iothread->stopping)) -> stopping=false 2. Main loop: iothread->stopping = true; aio_notify(iothread->ctx); 3. IOThread: aio_poll(iothread->ctx, true); -> hang The bug is explained by the AioContext->notify_me doc comments: "If this field is 0, everything (file descriptors, bottom halves, timers) will be re-evaluated before the next blocking poll(), thus the event_notifier_set call can be skipped." The problem is that "everything" does not include checking iothread->stopping. This means iothread_run() will block in aio_poll() if aio_notify() was called just before aio_poll(). This patch fixes the hang by replacing aio_notify() with aio_bh_schedule_oneshot(). This makes aio_poll() or g_main_loop_run() to return. Implementing this properly required a new bool running flag. The new flag prevents races that are tricky if we try to use iothread->stopping. Now iothread->stopping is purely for iothread_stop() and iothread->running is purely for the iothread_run() thread. Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171207201320.19284-6-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- include/sysemu/iothread.h | 3 ++- iothread.c | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h index 55de1715c7..799614ffd2 100644 --- a/include/sysemu/iothread.h +++ b/include/sysemu/iothread.h @@ -29,7 +29,8 @@ typedef struct { GOnce once; QemuMutex init_done_lock; QemuCond init_done_cond; /* is thread initialization done? */ - bool stopping; + bool stopping; /* has iothread_stop() been called? */ + bool running; /* should iothread_run() continue? */ int thread_id; /* AioContext poll parameters */ diff --git a/iothread.c b/iothread.c index e7b93e02a3..d8b6c1fb27 100644 --- a/iothread.c +++ b/iothread.c @@ -55,7 +55,7 @@ static void *iothread_run(void *opaque) qemu_cond_signal(&iothread->init_done_cond); qemu_mutex_unlock(&iothread->init_done_lock); - while (!atomic_read(&iothread->stopping)) { + while (iothread->running) { aio_poll(iothread->ctx, true); if (atomic_read(&iothread->worker_context)) { @@ -78,16 +78,25 @@ static void *iothread_run(void *opaque) return NULL; } +/* Runs in iothread_run() thread */ +static void iothread_stop_bh(void *opaque) +{ + IOThread *iothread = opaque; + + iothread->running = false; /* stop iothread_run() */ + + if (iothread->main_loop) { + g_main_loop_quit(iothread->main_loop); + } +} + void iothread_stop(IOThread *iothread) { if (!iothread->ctx || iothread->stopping) { return; } iothread->stopping = true; - aio_notify(iothread->ctx); - if (atomic_read(&iothread->main_loop)) { - g_main_loop_quit(iothread->main_loop); - } + aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread); qemu_thread_join(&iothread->thread); } @@ -134,6 +143,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) char *name, *thread_name; iothread->stopping = false; + iothread->running = true; iothread->thread_id = -1; iothread->ctx = aio_context_new(&local_error); if (!iothread->ctx) { From 7a9dda0d7f9831c2432620dcfefdadbb7ae888dc Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 7 Dec 2017 20:13:20 +0000 Subject: [PATCH 274/546] qemu-iotests: add 203 savevm with IOThreads test This test case will prevent future regressions with savevm and IOThreads. Signed-off-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-id: 20171207201320.19284-7-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- tests/qemu-iotests/203 | 59 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/203.out | 6 ++++ tests/qemu-iotests/group | 1 + 3 files changed, 66 insertions(+) create mode 100755 tests/qemu-iotests/203 create mode 100644 tests/qemu-iotests/203.out diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203 new file mode 100755 index 0000000000..2c811917d8 --- /dev/null +++ b/tests/qemu-iotests/203 @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Creator/Owner: Stefan Hajnoczi +# +# Check that QMP 'migrate' with multiple drives on a single IOThread completes +# successfully. This particular command triggered a hang in the source QEMU +# process due to recursive AioContext locking in bdrv_invalidate_all() and +# BDRV_POLL_WHILE(). + +import iotests + +iotests.verify_image_format(supported_fmts=['qcow2']) +iotests.verify_platform(['linux']) + +with iotests.FilePath('disk0.img') as disk0_img_path, \ + iotests.FilePath('disk1.img') as disk1_img_path, \ + iotests.VM() as vm: + + img_size = '10M' + iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size) + iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size) + + iotests.log('Launching VM...') + (vm.add_object('iothread,id=iothread0') + .add_drive(disk0_img_path, 'node-name=drive0-node', interface='none') + .add_drive(disk1_img_path, 'node-name=drive1-node', interface='none') + .launch()) + + iotests.log('Setting IOThreads...') + iotests.log(vm.qmp('x-blockdev-set-iothread', + node_name='drive0-node', iothread='iothread0', + force=True)) + iotests.log(vm.qmp('x-blockdev-set-iothread', + node_name='drive1-node', iothread='iothread0', + force=True)) + + iotests.log('Starting migration...') + iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null')) + while True: + vm.get_qmp_event(wait=60.0) + result = vm.qmp('query-migrate') + status = result.get('return', {}).get('status', None) + if status == 'completed': + break diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out new file mode 100644 index 0000000000..3f1ff900e4 --- /dev/null +++ b/tests/qemu-iotests/203.out @@ -0,0 +1,6 @@ +Launching VM... +Setting IOThreads... +{u'return': {}} +{u'return': {}} +Starting migration... +{u'return': {}} diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index d0ee1e2e55..93d96fb22f 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -198,3 +198,4 @@ 198 rw auto 200 rw auto 202 rw auto quick +203 rw auto From 89be9e99c83095af25ce16907143c31f2959188b Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 18 Dec 2017 19:36:31 +0100 Subject: [PATCH 275/546] tpm: move qdev_prop_tpm to hw/tpm/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building with --disable-tpm yields ../hw/core/qdev-properties-system.o: In function `set_tpm': /home/cohuck/git/qemu/hw/core/qdev-properties-system.c:274: undefined reference to `qemu_find_tpm_be' /home/cohuck/git/qemu/hw/core/qdev-properties-system.c:278: undefined reference to `tpm_backend_init' ../hw/core/qdev-properties-system.o: In function `release_tpm': /home/cohuck/git/qemu/hw/core/qdev-properties-system.c:291: undefined reference to `tpm_backend_reset' Move the implementation of DEFINE_PROP_TPMBE to hw/tpm/ so that it is only built when tpm is actually configured, and build tpm_util in every case. Fixes: 493b78303532 ("qdev: add DEFINE_PROP_TPMBE") Reported-by: Thomas Huth Reviewed-by: Marc-André Lureau Signed-off-by: Cornelia Huck Reviewed-by: Laurent Vivier Signed-off-by: Stefan Berger --- hw/core/qdev-properties-system.c | 64 ------------------------------ hw/tpm/Makefile.objs | 5 ++- hw/tpm/tpm_util.c | 67 ++++++++++++++++++++++++++++++++ hw/tpm/tpm_util.h | 3 ++ include/hw/qdev-properties.h | 2 - 5 files changed, 73 insertions(+), 68 deletions(-) diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index c17364655c..ec10da7424 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -21,7 +21,6 @@ #include "net/hub.h" #include "qapi/visitor.h" #include "chardev/char-fe.h" -#include "sysemu/tpm_backend.h" #include "sysemu/iothread.h" static void get_pointer(Object *obj, Visitor *v, Property *prop, @@ -237,69 +236,6 @@ const PropertyInfo qdev_prop_chr = { .release = release_chr, }; -/* --- character device --- */ - -static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - DeviceState *dev = DEVICE(obj); - TPMBackend **be = qdev_get_prop_ptr(dev, opaque); - char *p; - - p = g_strdup(*be ? (*be)->id : ""); - visit_type_str(v, name, &p, errp); - g_free(p); -} - -static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, - Error **errp) -{ - DeviceState *dev = DEVICE(obj); - Error *local_err = NULL; - Property *prop = opaque; - TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); - char *str; - - if (dev->realized) { - qdev_prop_set_after_realize(dev, name, errp); - return; - } - - visit_type_str(v, name, &str, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - - s = qemu_find_tpm_be(str); - if (s == NULL) { - error_setg(errp, "Property '%s.%s' can't find value '%s'", - object_get_typename(obj), prop->name, str); - } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) { - *be = s; /* weak reference, avoid cyclic ref */ - } - g_free(str); -} - -static void release_tpm(Object *obj, const char *name, void *opaque) -{ - DeviceState *dev = DEVICE(obj); - Property *prop = opaque; - TPMBackend **be = qdev_get_prop_ptr(dev, prop); - - if (*be) { - tpm_backend_reset(*be); - } -} - -const PropertyInfo qdev_prop_tpm = { - .name = "str", - .description = "ID of a tpm to use as a backend", - .get = get_tpm, - .set = set_tpm, - .release = release_tpm, -}; - /* --- netdev device --- */ static void get_netdev(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs index 41f0b7a590..7a93b24636 100644 --- a/hw/tpm/Makefile.objs +++ b/hw/tpm/Makefile.objs @@ -1,3 +1,4 @@ +common-obj-y += tpm_util.o common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o -common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o -common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o +common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index a317243a7e..17cafbe6b3 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -21,9 +21,13 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qapi/error.h" +#include "qapi/visitor.h" #include "tpm_util.h" #include "tpm_int.h" #include "exec/memory.h" +#include "sysemu/tpm_backend.h" +#include "hw/qdev.h" #define DEBUG_TPM 0 @@ -33,6 +37,69 @@ } \ } while (0) +/* tpm backend property */ + +static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + TPMBackend **be = qdev_get_prop_ptr(dev, opaque); + char *p; + + p = g_strdup(*be ? (*be)->id : ""); + visit_type_str(v, name, &p, errp); + g_free(p); +} + +static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + Property *prop = opaque; + TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); + char *str; + + if (dev->realized) { + qdev_prop_set_after_realize(dev, name, errp); + return; + } + + visit_type_str(v, name, &str, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + s = qemu_find_tpm_be(str); + if (s == NULL) { + error_setg(errp, "Property '%s.%s' can't find value '%s'", + object_get_typename(obj), prop->name, str); + } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) { + *be = s; /* weak reference, avoid cyclic ref */ + } + g_free(str); +} + +static void release_tpm(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + TPMBackend **be = qdev_get_prop_ptr(dev, prop); + + if (*be) { + tpm_backend_reset(*be); + } +} + +const PropertyInfo qdev_prop_tpm = { + .name = "str", + .description = "ID of a tpm to use as a backend", + .get = get_tpm, + .set = set_tpm, + .release = release_tpm, +}; + /* * Write an error message in the given output buffer. */ diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index 1c17e3913b..2393b6bc0e 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -39,4 +39,7 @@ static inline uint32_t tpm_cmd_get_size(const void *b) int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, size_t *buffersize); +#define DEFINE_PROP_TPMBE(_n, _s, _f) \ + DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) + #endif /* TPM_TPM_UTIL_H */ diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 4d24cdf8d6..60b42ac561 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -187,8 +187,6 @@ extern const PropertyInfo qdev_prop_link; #define DEFINE_PROP_CHR(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend) -#define DEFINE_PROP_TPMBE(_n, _s, _f) \ - DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) #define DEFINE_PROP_STRING(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) #define DEFINE_PROP_NETDEV(_n, _s, _f) \ From de6b4f908c300c7e7e0dc057310f5cbdcf1aed78 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:00 +0200 Subject: [PATCH 276/546] qemu-options: Remove stray colons from output of --help MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 43f187a broke --help: it put colons into blank lines. It removed the colon from DEFHEADING(TITLE:) and added it back in the macro expansion of DEFHEADING(TITLE), so hxtool can emit "@subsection TITLE" more easily. Trouble is it's added back even for the blank lines made with DEFHEADING(). Put the colons back where they were before commit 43f187a, and strip them in hxtool instead. Cc: Paolo Bonzini CC: qemu-stable@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-2-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qemu-options-wrapper.h | 2 +- qemu-options.hx | 27 ++++++++++++++------------- scripts/hxtool | 3 ++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/qemu-options-wrapper.h b/qemu-options-wrapper.h index 4d7aeb1352..13bfea0294 100644 --- a/qemu-options-wrapper.h +++ b/qemu-options-wrapper.h @@ -14,7 +14,7 @@ #define ARCHHEADING(text, arch_mask) \ if ((arch_mask) & arch_type) \ - puts(stringify(text) ":"); + puts(stringify(text)); #define DEFHEADING(text) ARCHHEADING(text, QEMU_ARCH_ALL) diff --git a/qemu-options.hx b/qemu-options.hx index 32d9378172..9090f10257 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -6,7 +6,7 @@ HXCOMM construct option structures, enums and help message for specified HXCOMM architectures. HXCOMM HXCOMM can be used for comments, discarded from both texi and C -DEFHEADING(Standard options) +DEFHEADING(Standard options:) STEXI @table @option ETEXI @@ -584,7 +584,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Block device options) +DEFHEADING(Block device options:) STEXI @table @option ETEXI @@ -1187,7 +1187,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(USB options) +DEFHEADING(USB options:) STEXI @table @option ETEXI @@ -1252,7 +1252,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Display options) +DEFHEADING(Display options:) STEXI @table @option ETEXI @@ -1789,7 +1789,7 @@ STEXI ETEXI ARCHHEADING(, QEMU_ARCH_I386) -ARCHHEADING(i386 target only, QEMU_ARCH_I386) +ARCHHEADING(i386 target only:, QEMU_ARCH_I386) STEXI @table @option ETEXI @@ -1905,7 +1905,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Network options) +DEFHEADING(Network options:) STEXI @table @option ETEXI @@ -2486,7 +2486,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Character device options) +DEFHEADING(Character device options:) STEXI The general form of a character device option is: @@ -2819,7 +2819,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Device URL Syntax) +DEFHEADING(Device URL Syntax:) STEXI In addition to using normal file images for the emulated storage devices, @@ -3049,7 +3049,7 @@ STEXI @end table ETEXI -DEFHEADING(Bluetooth(R) options) +DEFHEADING(Bluetooth(R) options:) STEXI @table @option ETEXI @@ -3125,7 +3125,7 @@ ETEXI DEFHEADING() #ifdef CONFIG_TPM -DEFHEADING(TPM device options) +DEFHEADING(TPM device options:) DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n" @@ -3215,7 +3215,7 @@ DEFHEADING() #endif -DEFHEADING(Linux/Multiboot boot specific) +DEFHEADING(Linux/Multiboot boot specific:) STEXI When using these options, you can use a given Linux or Multiboot @@ -3271,7 +3271,7 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Debug/Expert options) +DEFHEADING(Debug/Expert options:) STEXI @table @option ETEXI @@ -4178,7 +4178,8 @@ STEXI @end table ETEXI DEFHEADING() -DEFHEADING(Generic object creation) + +DEFHEADING(Generic object creation:) STEXI @table @option ETEXI diff --git a/scripts/hxtool b/scripts/hxtool index 1e2c97c5e6..7d7c4289e3 100644 --- a/scripts/hxtool +++ b/scripts/hxtool @@ -19,7 +19,8 @@ hxtoh() print_texi_heading() { if test "$*" != ""; then - printf "@subsection %s\n" "$*" + title="$*" + printf "@subsection %s\n" "${title%:}" fi } From 1e9a7379bfe2cf73c3d3361fece41ab19624c342 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:01 +0200 Subject: [PATCH 277/546] qemu-options: Fix markup of -netdev l2tpv3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The table of option parameters lacks @table and @end table. The parameters become items in the enclosing table of options. Screwed up when l2tpv3 was added in commit 3fb69aa. Fix the obvious way. Cc: Jason Wang Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-3-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qemu-options.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 9090f10257..9d7c9539c5 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2377,6 +2377,7 @@ two systems. It is present in routers, firewalls and the Linux kernel This transport allows a VM to communicate to another VM, router or firewall directly. +@table @option @item src=@var{srcaddr} source address (mandatory) @item dst=@var{dstaddr} @@ -2404,6 +2405,7 @@ draft-mkonstan-l2tpext-keyed-ipv6-tunnel-00 networks which have packet reorder. @item offset=@var{offset} Add an extra offset between header and data +@end table For example, to attach a VM running on host 4.3.2.1 via L2TPv3 to the bridge br-lan on the remote Linux host 1.2.3.4: From e896d0f9ca6efb52ee44fbe890af43f23145e367 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:02 +0200 Subject: [PATCH 278/546] qemu-options qemu-doc: Move "Device URL Syntax" to qemu-doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 0f5314a (v1.0) added section "Device URL Syntax" to qemu-options.hx. It's enclosed in STEXI..ETEXI, thus affects only qemu-options.texi, not --help. It appears as a subsection under section "Invocation". Similarly, qemu.1 has it as a subsection under "OPTIONS". Commit f9dadc9 (v1.1.0) dropped new option -iscsi into the middle of this section. No effect on qemu-options.texi. It appears in --help run together with the "Bluetooth(R) options:" header. Commit c70a01e (v1.5.0) gives it is own heading in --help by moving commit 0f5314a's DEFHEADING(Device URL Syntax:) outside STEXI..ETEXI. Trouble is the heading makes no sense for -iscsi. Move all of the "Device URL Syntax" Texinfo to qemu-doc.texi. Mark it for inclusion in qemu.1 with '@c man begin NOTES'. This turns it into a separate section outside the list of options both in qemu-doc and in qemu.1. There's substantial overlap with the existing qemu-doc section "Disk Images". Mark with a TODO comment. Output of --help will be fixed next. Cc: Ronnie Sahlberg Cc: Kevin Wolf Cc: Max Reitz Cc: qemu-block@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-4-armbru@redhat.com> Reviewed-by: Marc-André Lureau Reviewed-by: Ronnie Sahlberg [Unwanted @node dropped] --- qemu-doc.texi | 216 ++++++++++++++++++++++++++++++++++++++++++++++ qemu-options.hx | 222 ------------------------------------------------ 2 files changed, 216 insertions(+), 222 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index f7317dfc66..69e2953dc6 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -245,6 +245,222 @@ targets do not need a disk image. @c man end +@subsection Device URL Syntax +@c TODO merge this with section Disk Images + +@c man begin NOTES + +In addition to using normal file images for the emulated storage devices, +QEMU can also use networked resources such as iSCSI devices. These are +specified using a special URL syntax. + +@table @option +@item iSCSI +iSCSI support allows QEMU to access iSCSI resources directly and use as +images for the guest storage. Both disk and cdrom images are supported. + +Syntax for specifying iSCSI LUNs is +``iscsi://[:]//'' + +By default qemu will use the iSCSI initiator-name +'iqn.2008-11.org.linux-kvm[:]' but this can also be set from the command +line or a configuration file. + +Since version Qemu 2.4 it is possible to specify a iSCSI request timeout to detect +stalled requests and force a reestablishment of the session. The timeout +is specified in seconds. The default is 0 which means no timeout. Libiscsi +1.15.0 or greater is required for this feature. + +Example (without authentication): +@example +qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ + -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ + -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 +@end example + +Example (CHAP username/password via URL): +@example +qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 +@end example + +Example (CHAP username/password via environment variables): +@example +LIBISCSI_CHAP_USERNAME="user" \ +LIBISCSI_CHAP_PASSWORD="password" \ +qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 +@end example + +@item NBD +QEMU supports NBD (Network Block Devices) both using TCP protocol as well +as Unix Domain Sockets. + +Syntax for specifying a NBD device using TCP +``nbd::[:exportname=]'' + +Syntax for specifying a NBD device using Unix Domain Sockets +``nbd:unix:[:exportname=]'' + +Example for TCP +@example +qemu-system-i386 --drive file=nbd:192.0.2.1:30000 +@end example + +Example for Unix Domain Sockets +@example +qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket +@end example + +@item SSH +QEMU supports SSH (Secure Shell) access to remote disks. + +Examples: +@example +qemu-system-i386 -drive file=ssh://user@@host/path/to/disk.img +qemu-system-i386 -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img +@end example + +Currently authentication must be done using ssh-agent. Other +authentication methods may be supported in future. + +@item Sheepdog +Sheepdog is a distributed storage system for QEMU. +QEMU supports using either local sheepdog devices or remote networked +devices. + +Syntax for specifying a sheepdog device +@example +sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] +@end example + +Example +@example +qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine +@end example + +See also @url{https://sheepdog.github.io/sheepdog/}. + +@item GlusterFS +GlusterFS is a user space distributed file system. +QEMU supports the use of GlusterFS volumes for hosting VM disk images using +TCP, Unix Domain Sockets and RDMA transport protocols. + +Syntax for specifying a VM disk image on GlusterFS volume is +@example + +URI: +gluster[+type]://[host[:port]]/volume/path[?socket=...][,debug=N][,logfile=...] + +JSON: +'json:@{"driver":"qcow2","file":@{"driver":"gluster","volume":"testvol","path":"a.img","debug":N,"logfile":"...", +@ "server":[@{"type":"tcp","host":"...","port":"..."@}, +@ @{"type":"unix","socket":"..."@}]@}@}' +@end example + + +Example +@example +URI: +qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img, +@ file.debug=9,file.logfile=/var/log/qemu-gluster.log + +JSON: +qemu-system-x86_64 'json:@{"driver":"qcow2", +@ "file":@{"driver":"gluster", +@ "volume":"testvol","path":"a.img", +@ "debug":9,"logfile":"/var/log/qemu-gluster.log", +@ "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, +@ @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' +qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, +@ file.debug=9,file.logfile=/var/log/qemu-gluster.log, +@ file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, +@ file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket +@end example + +See also @url{http://www.gluster.org}. + +@item HTTP/HTTPS/FTP/FTPS +QEMU supports read-only access to files accessed over http(s) and ftp(s). + +Syntax using a single filename: +@example +://[[:]@@]/ +@end example + +where: +@table @option +@item protocol +'http', 'https', 'ftp', or 'ftps'. + +@item username +Optional username for authentication to the remote server. + +@item password +Optional password for authentication to the remote server. + +@item host +Address of the remote server. + +@item path +Path on the remote server, including any query string. +@end table + +The following options are also supported: +@table @option +@item url +The full URL when passing options to the driver explicitly. + +@item readahead +The amount of data to read ahead with each range request to the remote server. +This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it +does not have a suffix, it will be assumed to be in bytes. The value must be a +multiple of 512 bytes. It defaults to 256k. + +@item sslverify +Whether to verify the remote server's certificate when connecting over SSL. It +can have the value 'on' or 'off'. It defaults to 'on'. + +@item cookie +Send this cookie (it can also be a list of cookies separated by ';') with +each outgoing request. Only supported when using protocols such as HTTP +which support cookies, otherwise ignored. + +@item timeout +Set the timeout in seconds of the CURL connection. This timeout is the time +that CURL waits for a response from the remote server to get the size of the +image to be downloaded. If not set, the default timeout of 5 seconds is used. +@end table + +Note that when passing options to qemu explicitly, @option{driver} is the value +of . + +Example: boot from a remote Fedora 20 live ISO image +@example +qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly + +qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly +@end example + +Example: boot from a remote Fedora 20 cloud image using a local overlay for +writes, copy-on-read, and a readahead of 64k +@example +qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2 + +qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on +@end example + +Example: boot from an image stored on a VMware vSphere server with a self-signed +certificate using a local overlay for writes, a readahead of 64k and a timeout +of 10 seconds. +@example +qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k",, "file.timeout":10@}' /tmp/test.qcow2 + +qemu-system-x86_64 -drive file=/tmp/test.qcow2 +@end example + +@end table + +@c man end + @node pcsys_keys @section Keys in the graphical frontends diff --git a/qemu-options.hx b/qemu-options.hx index 9d7c9539c5..4c50ed6f13 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2822,234 +2822,12 @@ ETEXI DEFHEADING() DEFHEADING(Device URL Syntax:) -STEXI - -In addition to using normal file images for the emulated storage devices, -QEMU can also use networked resources such as iSCSI devices. These are -specified using a special URL syntax. - -@table @option -@item iSCSI -iSCSI support allows QEMU to access iSCSI resources directly and use as -images for the guest storage. Both disk and cdrom images are supported. - -Syntax for specifying iSCSI LUNs is -``iscsi://[:]//'' - -By default qemu will use the iSCSI initiator-name -'iqn.2008-11.org.linux-kvm[:]' but this can also be set from the command -line or a configuration file. - -Since version Qemu 2.4 it is possible to specify a iSCSI request timeout to detect -stalled requests and force a reestablishment of the session. The timeout -is specified in seconds. The default is 0 which means no timeout. Libiscsi -1.15.0 or greater is required for this feature. - -Example (without authentication): -@example -qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \ - -cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \ - -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 -@end example - -Example (CHAP username/password via URL): -@example -qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1 -@end example - -Example (CHAP username/password via environment variables): -@example -LIBISCSI_CHAP_USERNAME="user" \ -LIBISCSI_CHAP_PASSWORD="password" \ -qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1 -@end example - -iSCSI support is an optional feature of QEMU and only available when -compiled and linked against libiscsi. -ETEXI DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, "-iscsi [user=user][,password=password]\n" " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n" " [,initiator-name=initiator-iqn][,id=target-iqn]\n" " [,timeout=timeout]\n" " iSCSI session parameters\n", QEMU_ARCH_ALL) -STEXI - -iSCSI parameters such as username and password can also be specified via -a configuration file. See qemu-doc for more information and examples. - -@item NBD -QEMU supports NBD (Network Block Devices) both using TCP protocol as well -as Unix Domain Sockets. - -Syntax for specifying a NBD device using TCP -``nbd::[:exportname=]'' - -Syntax for specifying a NBD device using Unix Domain Sockets -``nbd:unix:[:exportname=]'' - - -Example for TCP -@example -qemu-system-i386 --drive file=nbd:192.0.2.1:30000 -@end example - -Example for Unix Domain Sockets -@example -qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket -@end example - -@item SSH -QEMU supports SSH (Secure Shell) access to remote disks. - -Examples: -@example -qemu-system-i386 -drive file=ssh://user@@host/path/to/disk.img -qemu-system-i386 -drive file.driver=ssh,file.user=user,file.host=host,file.port=22,file.path=/path/to/disk.img -@end example - -Currently authentication must be done using ssh-agent. Other -authentication methods may be supported in future. - -@item Sheepdog -Sheepdog is a distributed storage system for QEMU. -QEMU supports using either local sheepdog devices or remote networked -devices. - -Syntax for specifying a sheepdog device -@example -sheepdog[+tcp|+unix]://[host:port]/vdiname[?socket=path][#snapid|#tag] -@end example - -Example -@example -qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine -@end example - -See also @url{https://sheepdog.github.io/sheepdog/}. - -@item GlusterFS -GlusterFS is a user space distributed file system. -QEMU supports the use of GlusterFS volumes for hosting VM disk images using -TCP, Unix Domain Sockets and RDMA transport protocols. - -Syntax for specifying a VM disk image on GlusterFS volume is -@example - -URI: -gluster[+type]://[host[:port]]/volume/path[?socket=...][,debug=N][,logfile=...] - -JSON: -'json:@{"driver":"qcow2","file":@{"driver":"gluster","volume":"testvol","path":"a.img","debug":N,"logfile":"...", -@ "server":[@{"type":"tcp","host":"...","port":"..."@}, -@ @{"type":"unix","socket":"..."@}]@}@}' -@end example - - -Example -@example -URI: -qemu-system-x86_64 --drive file=gluster://192.0.2.1/testvol/a.img, -@ file.debug=9,file.logfile=/var/log/qemu-gluster.log - -JSON: -qemu-system-x86_64 'json:@{"driver":"qcow2", -@ "file":@{"driver":"gluster", -@ "volume":"testvol","path":"a.img", -@ "debug":9,"logfile":"/var/log/qemu-gluster.log", -@ "server":[@{"type":"tcp","host":"1.2.3.4","port":24007@}, -@ @{"type":"unix","socket":"/var/run/glusterd.socket"@}]@}@}' -qemu-system-x86_64 -drive driver=qcow2,file.driver=gluster,file.volume=testvol,file.path=/path/a.img, -@ file.debug=9,file.logfile=/var/log/qemu-gluster.log, -@ file.server.0.type=tcp,file.server.0.host=1.2.3.4,file.server.0.port=24007, -@ file.server.1.type=unix,file.server.1.socket=/var/run/glusterd.socket -@end example - -See also @url{http://www.gluster.org}. - -@item HTTP/HTTPS/FTP/FTPS -QEMU supports read-only access to files accessed over http(s) and ftp(s). - -Syntax using a single filename: -@example -://[[:]@@]/ -@end example - -where: -@table @option -@item protocol -'http', 'https', 'ftp', or 'ftps'. - -@item username -Optional username for authentication to the remote server. - -@item password -Optional password for authentication to the remote server. - -@item host -Address of the remote server. - -@item path -Path on the remote server, including any query string. -@end table - -The following options are also supported: -@table @option -@item url -The full URL when passing options to the driver explicitly. - -@item readahead -The amount of data to read ahead with each range request to the remote server. -This value may optionally have the suffix 'T', 'G', 'M', 'K', 'k' or 'b'. If it -does not have a suffix, it will be assumed to be in bytes. The value must be a -multiple of 512 bytes. It defaults to 256k. - -@item sslverify -Whether to verify the remote server's certificate when connecting over SSL. It -can have the value 'on' or 'off'. It defaults to 'on'. - -@item cookie -Send this cookie (it can also be a list of cookies separated by ';') with -each outgoing request. Only supported when using protocols such as HTTP -which support cookies, otherwise ignored. - -@item timeout -Set the timeout in seconds of the CURL connection. This timeout is the time -that CURL waits for a response from the remote server to get the size of the -image to be downloaded. If not set, the default timeout of 5 seconds is used. -@end table - -Note that when passing options to qemu explicitly, @option{driver} is the value -of . - -Example: boot from a remote Fedora 20 live ISO image -@example -qemu-system-x86_64 --drive media=cdrom,file=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly - -qemu-system-x86_64 --drive media=cdrom,file.driver=http,file.url=http://dl.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso,readonly -@end example - -Example: boot from a remote Fedora 20 cloud image using a local overlay for -writes, copy-on-read, and a readahead of 64k -@example -qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"http",, "file.url":"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2",, "file.readahead":"64k"@}' /tmp/Fedora-x86_64-20-20131211.1-sda.qcow2 - -qemu-system-x86_64 -drive file=/tmp/Fedora-x86_64-20-20131211.1-sda.qcow2,copy-on-read=on -@end example - -Example: boot from an image stored on a VMware vSphere server with a self-signed -certificate using a local overlay for writes, a readahead of 64k and a timeout -of 10 seconds. -@example -qemu-img create -f qcow2 -o backing_file='json:@{"file.driver":"https",, "file.url":"https://user:password@@vsphere.example.com/folder/test/test-flat.vmdk?dcPath=Datacenter&dsName=datastore1",, "file.sslverify":"off",, "file.readahead":"64k",, "file.timeout":10@}' /tmp/test.qcow2 - -qemu-system-x86_64 -drive file=/tmp/test.qcow2 -@end example -ETEXI - -STEXI -@end table -ETEXI DEFHEADING(Bluetooth(R) options:) STEXI From 61d704870ab053c6405829b423b2d83f055a8488 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:03 +0200 Subject: [PATCH 279/546] qemu-options: Move -iscsi under "Block device options" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -iscsi ended up under the "Device URL Syntax" heading by a sequence of errors, as explained in the previous commit. Move it under the "Block device options" heading. Nothing left under "Device URL Syntax"; drop the heading. Cc: Ronnie Sahlberg Cc: Kevin Wolf Cc: Max Reitz Cc: qemu-block@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-5-armbru@redhat.com> Reviewed-by: Marc-André Lureau Reviewed-by: Ronnie Sahlberg --- qemu-options.hx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 4c50ed6f13..426abc83d8 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1182,6 +1182,13 @@ STEXI Create synthetic file system image ETEXI +DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, + "-iscsi [user=user][,password=password]\n" + " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n" + " [,initiator-name=initiator-iqn][,id=target-iqn]\n" + " [,timeout=timeout]\n" + " iSCSI session parameters\n", QEMU_ARCH_ALL) + STEXI @end table ETEXI @@ -2821,14 +2828,6 @@ STEXI ETEXI DEFHEADING() -DEFHEADING(Device URL Syntax:) -DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, - "-iscsi [user=user][,password=password]\n" - " [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE\n" - " [,initiator-name=initiator-iqn][,id=target-iqn]\n" - " [,timeout=timeout]\n" - " iSCSI session parameters\n", QEMU_ARCH_ALL) - DEFHEADING(Bluetooth(R) options:) STEXI @table @option From 44743148460cc9fb5537ad268a8e0e9ddf58beb8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:04 +0200 Subject: [PATCH 280/546] qemu-options: Add missing -iscsi Texinfo documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Ronnie Sahlberg Cc: Kevin Wolf Cc: Max Reitz Cc: qemu-block@nongnu.org Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-6-armbru@redhat.com> Reviewed-by: Marc-André Lureau Reviewed-by: Ronnie Sahlberg --- qemu-options.hx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qemu-options.hx b/qemu-options.hx index 426abc83d8..ef52be908a 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1189,6 +1189,12 @@ DEF("iscsi", HAS_ARG, QEMU_OPTION_iscsi, " [,timeout=timeout]\n" " iSCSI session parameters\n", QEMU_ARCH_ALL) +STEXI +@item -iscsi +@findex -iscsi +Configure iSCSI session parameters. +ETEXI + STEXI @end table ETEXI From 2252aaf08786de5a4df8350e5362a98646a3e481 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:05 +0200 Subject: [PATCH 281/546] qemu-options: Polish section "TPM device options" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Stefan Berger Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-7-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qemu-options.hx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index ef52be908a..31d54abc05 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2927,19 +2927,18 @@ The general form of a TPM device option is: @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] @findex -tpmdev -Backend type must be either one of the following: -@option{passthrough}, @option{emulator}. The specific backend type will determine the applicable options. The @code{-tpmdev} option creates the TPM backend and requires a @code{-device} option that specifies the TPM frontend interface model. -Options to each backend are described below. +Use @code{-tpmdev help} to print all available TPM backend types. -Use 'help' to print all available TPM backend types. -@example -qemu -tpmdev help -@end example +@end table + +The available backends are: + +@table @option @item -tpmdev passthrough, id=@var{id}, path=@var{path}, cancel-path=@var{cancel-path} @@ -2992,10 +2991,11 @@ To create a TPM emulator backend device with chardev socket backend: @end example -@end table - ETEXI +STEXI +@end table +ETEXI DEFHEADING() #endif From dddba0688af1a68bc7c61adc6c2290fbaa31c37d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:06 +0200 Subject: [PATCH 282/546] qemu-options: Polish section "Character device options" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Paolo Bonzini CC: Marc-André Lureau Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-8-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qemu-options.hx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 31d54abc05..07add8bedc 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2502,11 +2502,6 @@ ETEXI DEFHEADING() DEFHEADING(Character device options:) -STEXI - -The general form of a character device option is: -@table @option -ETEXI DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev help\n" @@ -2552,6 +2547,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, ) STEXI + +The general form of a character device option is: +@table @option @item -chardev @var{backend} ,id=@var{id} [,mux=on|off] [,@var{options}] @findex -chardev Backend is one of: @@ -2575,7 +2573,7 @@ Backend is one of: @option{spiceport}. The specific backend will determine the applicable options. -Use "-chardev help" to print all available chardev backend types. +Use @code{-chardev help} to print all available chardev backend types. All devices must have an id, which can be any string up to 127 characters long. It is used to uniquely identify this device in other command line directives. @@ -2630,8 +2628,11 @@ to a file to record all data transmitted via the backend. The @option{logappend} option controls whether the log file will be truncated or appended to when opened. -Further options to each backend are described below. +@end table +The available backends are: + +@table @option @item -chardev null ,id=@var{id} A void device. This device will not emit any data, and will drop any data it receives. The null backend does not take any options. From 7ad9270ee21fdf0262a44ebf7e280c6a85022ced Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:03:07 +0200 Subject: [PATCH 283/546] qemu-options: Belatedly document --watchdog-action inject-nmi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Missed in commit 795dc6e46d, v2.4.0. Signed-off-by: Markus Armbruster Message-Id: <20171002140307.5292-9-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qemu-options.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index 07add8bedc..b1e5781908 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3623,7 +3623,7 @@ A virtual watchdog for s390x backed by the diagnose 288 hypercall ETEXI DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \ - "-watchdog-action reset|shutdown|poweroff|pause|debug|none\n" \ + "-watchdog-action reset|shutdown|poweroff|inject-nmi|pause|debug|none\n" \ " action when watchdog fires [default=reset]\n", QEMU_ARCH_ALL) STEXI @@ -3637,6 +3637,7 @@ The default is Other possible actions are: @code{shutdown} (attempt to gracefully shutdown the guest), @code{poweroff} (forcefully poweroff the guest), +@code{inject-nmi} (inject a NMI into the guest), @code{pause} (pause the guest), @code{debug} (print a debug message and continue), or @code{none} (do nothing). From da78e382dddc499882120590ae0ac834881a96b8 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 5 Oct 2017 20:07:25 +0100 Subject: [PATCH 284/546] option: Remove shadowing opt decl from qemu_opt_print() opt was declared as a separate local inside the last loop, shadowing the local at the top of the function. Signed-off-by: Dr. David Alan Gilbert Message-Id: <20171005190725.18712-1-dgilbert@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- util/qemu-option.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/qemu-option.c b/util/qemu-option.c index 9b1dc8093b..877c5b4d67 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -766,7 +766,7 @@ void qemu_opts_print(QemuOpts *opts, const char *separator) } for (; desc && desc->name; desc++) { const char *value; - QemuOpt *opt = qemu_opt_find(opts, desc->name); + opt = qemu_opt_find(opts, desc->name); value = opt ? opt->str : desc->def_value_str; if (!value) { From 3e05349de8bd6744d23a26beac9ed6fb2e286f80 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Fri, 6 Oct 2017 15:16:45 +0200 Subject: [PATCH 285/546] option: Drop unused get_param_value(), get_next_param_value() Their last user went away in commit f51074cdc6, "pci-hotplug-old: Has been dead for five major releases, bury", v2.3.0. Remove them, as new code should use QemuOpts or maybe keyval_parse() instead. Signed-off-by: Markus Armbruster Message-Id: <20171006131645.17729-1-armbru@redhat.com> Reviewed-by: Eric Blake --- include/qemu/option.h | 5 ----- util/qemu-option.c | 34 ---------------------------------- 2 files changed, 39 deletions(-) diff --git a/include/qemu/option.h b/include/qemu/option.h index f7338dbe80..a88c5f02b1 100644 --- a/include/qemu/option.h +++ b/include/qemu/option.h @@ -31,11 +31,6 @@ const char *get_opt_name(char *buf, int buf_size, const char *p, char delim); const char *get_opt_value(char *buf, int buf_size, const char *p); -int get_next_param_value(char *buf, int buf_size, - const char *tag, const char **pstr); -int get_param_value(char *buf, int buf_size, - const char *tag, const char *str); - void parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp); diff --git a/util/qemu-option.c b/util/qemu-option.c index 877c5b4d67..553d3dc552 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -91,40 +91,6 @@ const char *get_opt_value(char *buf, int buf_size, const char *p) return p; } -int get_next_param_value(char *buf, int buf_size, - const char *tag, const char **pstr) -{ - const char *p; - char option[128]; - - p = *pstr; - for(;;) { - p = get_opt_name(option, sizeof(option), p, '='); - if (*p != '=') - break; - p++; - if (!strcmp(tag, option)) { - *pstr = get_opt_value(buf, buf_size, p); - if (**pstr == ',') { - (*pstr)++; - } - return strlen(buf); - } else { - p = get_opt_value(NULL, 0, p); - } - if (*p != ',') - break; - p++; - } - return 0; -} - -int get_param_value(char *buf, int buf_size, - const char *tag, const char *str) -{ - return get_next_param_value(buf, buf_size, tag, &str); -} - static void parse_option_bool(const char *name, const char *value, bool *ret, Error **errp) { From dbd73b569b61893ebfe460b0be254997e2cbfb0a Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 18 Oct 2017 16:20:02 +0800 Subject: [PATCH 286/546] Revert "docker: Enable features explicitly in test-full" This reverts commit 5e8a7fe673ca5949bd51939ee36faaf3b1320de8. It's hard to get all images to have all these packages, the usual "FEATURES" and "require" mechanism doesn't scale with so many features. With that change, the test basically only works in ubuntu. Until a better way comes up, leave the feature enabling to ./configure detection. But don't remove the "-e" removal. Reported-by: Paolo Bonzini Signed-off-by: Fam Zheng Message-Id: <20171018082002.9406-1-famz@redhat.com> Signed-off-by: Fam Zheng --- tests/docker/test-full | 79 +++--------------------------------------- 1 file changed, 4 insertions(+), 75 deletions(-) diff --git a/tests/docker/test-full b/tests/docker/test-full index 816d5a3eec..b4e42d25d7 100755 --- a/tests/docker/test-full +++ b/tests/docker/test-full @@ -1,8 +1,8 @@ #!/bin/bash # -# Compile all the targets with as many features enabled as possible +# Compile all the targets. # -# Copyright 2016, 2017 Red Hat Inc. +# Copyright (c) 2016 Red Hat Inc. # # Authors: # Fam Zheng @@ -13,77 +13,6 @@ . common.rc -cd "$BUILD_DIR" || exit 1 +cd "$BUILD_DIR" -build_qemu \ - --enable-attr \ - --enable-bluez \ - --enable-brlapi \ - --enable-bsd-user \ - --enable-bzip2 \ - --enable-cap-ng \ - --enable-coroutine-pool \ - --enable-crypto-afalg \ - --enable-curl \ - --enable-curses \ - --enable-debug \ - --enable-debug-info \ - --enable-debug-tcg \ - --enable-docs \ - --enable-fdt \ - --enable-gcrypt \ - --enable-glusterfs \ - --enable-gnutls \ - --enable-gprof \ - --enable-gtk \ - --enable-guest-agent \ - --enable-jemalloc \ - --enable-kvm \ - --enable-libiscsi \ - --enable-libnfs \ - --enable-libssh2 \ - --enable-libusb \ - --enable-linux-aio \ - --enable-linux-user \ - --enable-live-block-migration \ - --enable-lzo \ - --enable-modules \ - --enable-numa \ - --enable-opengl \ - --enable-pie \ - --enable-profiler \ - --enable-qom-cast-debug \ - --enable-rbd \ - --enable-rdma \ - --enable-replication \ - --enable-sdl \ - --enable-seccomp \ - --enable-smartcard \ - --enable-snappy \ - --enable-spice \ - --enable-stack-protector \ - --enable-system \ - --enable-tcg \ - --enable-tcg-interpreter \ - --enable-tools \ - --enable-tpm \ - --enable-trace-backend=ftrace \ - --enable-usb-redir \ - --enable-user \ - --enable-vde \ - --enable-vhost-net \ - --enable-vhost-scsi \ - --enable-vhost-user \ - --enable-vhost-vsock \ - --enable-virtfs \ - --enable-vnc \ - --enable-vnc-jpeg \ - --enable-vnc-png \ - --enable-vnc-sasl \ - --enable-vte \ - --enable-werror \ - --enable-xen \ - --enable-xen-pci-passthrough \ - --enable-xen-pv-domain-build \ - --enable-xfsctl \ -&& make check $MAKEFLAGS && install_qemu +build_qemu && make check $MAKEFLAGS && install_qemu From bfab1aede07f864b8fbd749c3a0545b949b4cc84 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Mon, 27 Nov 2017 15:43:55 +0300 Subject: [PATCH 287/546] util: add is_equal to UUID API It's going to be useful, in particular, in VMBus code massively using uuids aka GUIDs. Signed-off-by: Roman Kagan Message-Id: <20171127124355.26015-1-rkagan@virtuozzo.com> Signed-off-by: Fam Zheng --- include/qemu/uuid.h | 2 ++ tests/test-uuid.c | 8 +++++++- util/uuid.c | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h index afe4840296..09489ce5c5 100644 --- a/include/qemu/uuid.h +++ b/include/qemu/uuid.h @@ -48,6 +48,8 @@ void qemu_uuid_generate(QemuUUID *out); int qemu_uuid_is_null(const QemuUUID *uu); +int qemu_uuid_is_equal(const QemuUUID *lhv, const QemuUUID *rhv); + void qemu_uuid_unparse(const QemuUUID *uuid, char *out); char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); diff --git a/tests/test-uuid.c b/tests/test-uuid.c index d3a2791fd4..22b4b0727d 100644 --- a/tests/test-uuid.c +++ b/tests/test-uuid.c @@ -93,12 +93,18 @@ static inline bool uuid_is_valid(QemuUUID *uuid) static void test_uuid_generate(void) { + QemuUUID uuid_not_null = { { { + 0x58, 0x6e, 0xce, 0x27, 0x7f, 0x09, 0x41, 0xe0, + 0x9e, 0x74, 0xe9, 0x01, 0x31, 0x7e, 0x9d, 0x42 + } } }; QemuUUID uuid; int i; for (i = 0; i < 100; ++i) { qemu_uuid_generate(&uuid); g_assert(uuid_is_valid(&uuid)); + g_assert_false(qemu_uuid_is_null(&uuid)); + g_assert_false(qemu_uuid_is_equal(&uuid_not_null, &uuid)); } } @@ -168,8 +174,8 @@ static void test_uuid_unparse_strdup(void) int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); - g_test_add_func("/uuid/generate", test_uuid_generate); g_test_add_func("/uuid/is_null", test_uuid_is_null); + g_test_add_func("/uuid/generate", test_uuid_generate); g_test_add_func("/uuid/parse", test_uuid_parse); g_test_add_func("/uuid/unparse", test_uuid_unparse); g_test_add_func("/uuid/unparse_strdup", test_uuid_unparse_strdup); diff --git a/util/uuid.c b/util/uuid.c index dd6b5fdf05..ebf06c049a 100644 --- a/util/uuid.c +++ b/util/uuid.c @@ -41,7 +41,12 @@ void qemu_uuid_generate(QemuUUID *uuid) int qemu_uuid_is_null(const QemuUUID *uu) { static QemuUUID null_uuid; - return memcmp(uu, &null_uuid, sizeof(QemuUUID)) == 0; + return qemu_uuid_is_equal(uu, &null_uuid); +} + +int qemu_uuid_is_equal(const QemuUUID *lhv, const QemuUUID *rhv) +{ + return memcmp(lhv, rhv, sizeof(QemuUUID)) == 0; } void qemu_uuid_unparse(const QemuUUID *uuid, char *out) From c6a1a98b4222114fbebbb40814ba765ac4530937 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:31 +0200 Subject: [PATCH 288/546] qapi-schema: Fix query-vm-generation-id's doc comment markup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Daniel P. Berrange Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-2-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- qapi-schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi-schema.json b/qapi-schema.json index 18457954a8..ea3723f903 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3188,7 +3188,7 @@ # # Show Virtual Machine Generation ID # -# Since 2.9 +# Since: 2.9 ## { 'command': 'query-vm-generation-id', 'returns': 'GuidInfo' } From 67ab1ce9263f77b352faea1104f0ebc2e50a3d42 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:32 +0200 Subject: [PATCH 289/546] qapi: Stop rejecting #optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 1d8bda1 got rid of #optional tags, and added a check to keep them from getting added back, to make sure patches then in flight don't add them back. It's been six months, time to drop that check. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-3-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 62dc52ed6e..dc92bca620 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -234,10 +234,6 @@ def _append_freeform(self, line): raise QAPIParseError(self.parser, "'%s' not allowed in free-form documentation" % match.group(1)) - # TODO Drop this once the dust has settled - if (isinstance(self.section, QAPIDoc.ArgSection) - and '#optional' in line): - raise QAPISemError(self.info, "Please drop the #optional tag") self.section.append(line) def connect_member(self, member): From 2281d00c3d75e684d9c0051169a6ac1cc60b66cd Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:33 +0200 Subject: [PATCH 290/546] qapi: Eliminate QAPISchemaParser.__init__()'s local fname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-4-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index dc92bca620..6c8001e96d 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -261,8 +261,7 @@ class QAPISchemaParser(object): def __init__(self, fp, previously_included=[], incl_info=None): abs_fname = os.path.abspath(fp.name) - fname = fp.name - self.fname = fname + self.fname = fp.name previously_included.append(abs_fname) self.incl_info = incl_info self.src = fp.read() @@ -277,7 +276,7 @@ def __init__(self, fp, previously_included=[], incl_info=None): self.accept() while self.tok is not None: - info = {'file': fname, 'line': self.line, + info = {'file': self.fname, 'line': self.line, 'parent': self.incl_info} if self.tok == '#': self.reject_expr_doc() From 64d6033b203b32f02d0986220af5dc3cd1301ba6 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:34 +0200 Subject: [PATCH 291/546] qapi: Make cur_doc local to QAPISchemaParser.__init__() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QAPISchemaParser.cur_doc is used only by .__init__() and its helper .reject_expr_doc(). Make it local to __init__() and pass it to .reject_expr_doc() explicitly. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-5-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 6c8001e96d..2f2738f562 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -272,21 +272,21 @@ def __init__(self, fp, previously_included=[], incl_info=None): self.line_pos = 0 self.exprs = [] self.docs = [] - self.cur_doc = None self.accept() + cur_doc = None while self.tok is not None: info = {'file': self.fname, 'line': self.line, 'parent': self.incl_info} if self.tok == '#': - self.reject_expr_doc() - self.cur_doc = self.get_doc(info) - self.docs.append(self.cur_doc) + self.reject_expr_doc(cur_doc) + cur_doc = self.get_doc(info) + self.docs.append(cur_doc) continue expr = self.get_expr(False) if 'include' in expr: - self.reject_expr_doc() + self.reject_expr_doc(cur_doc) if len(expr) != 1: raise QAPISemError(info, "Invalid 'include' directive") include = expr['include'] @@ -296,7 +296,7 @@ def __init__(self, fp, previously_included=[], incl_info=None): self._include(include, info, os.path.dirname(abs_fname), previously_included) elif "pragma" in expr: - self.reject_expr_doc() + self.reject_expr_doc(cur_doc) if len(expr) != 1: raise QAPISemError(info, "Invalid 'pragma' directive") pragma = expr['pragma'] @@ -308,22 +308,22 @@ def __init__(self, fp, previously_included=[], incl_info=None): else: expr_elem = {'expr': expr, 'info': info} - if self.cur_doc: - if not self.cur_doc.symbol: + if cur_doc: + if not cur_doc.symbol: raise QAPISemError( - self.cur_doc.info, - "Expression documentation required") - expr_elem['doc'] = self.cur_doc + cur_doc.info, "Expression documentation required") + expr_elem['doc'] = cur_doc self.exprs.append(expr_elem) - self.cur_doc = None - self.reject_expr_doc() + cur_doc = None + self.reject_expr_doc(cur_doc) - def reject_expr_doc(self): - if self.cur_doc and self.cur_doc.symbol: + @staticmethod + def reject_expr_doc(doc): + if doc and doc.symbol: raise QAPISemError( - self.cur_doc.info, + doc.info, "Documentation for '%s' is not followed by the definition" - % self.cur_doc.symbol) + % doc.symbol) def _include(self, include, info, base_dir, previously_included): incl_abs_fname = os.path.join(base_dir, include) From cfa438ff53937c78c9a0e50b4b774ea5a6430710 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:35 +0200 Subject: [PATCH 292/546] tests/qapi-schema/doc-bad-section: New, factored out of doc-good MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A negative test case crept into doc-good.json: invalid use of section markup we currently fail to reject. Move this into its own doc-bad-section.json. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-6-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- tests/Makefile.include | 3 ++- tests/qapi-schema/doc-bad-section.err | 0 tests/qapi-schema/doc-bad-section.exit | 1 + tests/qapi-schema/doc-bad-section.json | 11 +++++++++++ tests/qapi-schema/doc-bad-section.out | 13 +++++++++++++ tests/qapi-schema/doc-good.json | 1 - tests/qapi-schema/doc-good.out | 2 +- tests/qapi-schema/doc-good.texi | 2 +- 8 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/qapi-schema/doc-bad-section.err create mode 100644 tests/qapi-schema/doc-bad-section.exit create mode 100644 tests/qapi-schema/doc-bad-section.json create mode 100644 tests/qapi-schema/doc-bad-section.out diff --git a/tests/Makefile.include b/tests/Makefile.include index b4bcc872f2..f8e20d9f5d 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -416,6 +416,7 @@ qapi-schema += command-int.json qapi-schema += comments.json qapi-schema += doc-bad-alternate-member.json qapi-schema += doc-bad-command-arg.json +qapi-schema += doc-bad-section.json qapi-schema += doc-bad-symbol.json qapi-schema += doc-bad-union-member.json qapi-schema += doc-before-include.json @@ -433,10 +434,10 @@ qapi-schema += doc-invalid-end2.json qapi-schema += doc-invalid-return.json qapi-schema += doc-invalid-section.json qapi-schema += doc-invalid-start.json -qapi-schema += doc-missing.json qapi-schema += doc-missing-colon.json qapi-schema += doc-missing-expr.json qapi-schema += doc-missing-space.json +qapi-schema += doc-missing.json qapi-schema += doc-no-symbol.json qapi-schema += double-data.json qapi-schema += double-type.json diff --git a/tests/qapi-schema/doc-bad-section.err b/tests/qapi-schema/doc-bad-section.err new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/qapi-schema/doc-bad-section.exit b/tests/qapi-schema/doc-bad-section.exit new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/tests/qapi-schema/doc-bad-section.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/doc-bad-section.json b/tests/qapi-schema/doc-bad-section.json new file mode 100644 index 0000000000..560df4b087 --- /dev/null +++ b/tests/qapi-schema/doc-bad-section.json @@ -0,0 +1,11 @@ +# = section within an expression comment +# BUG: not rejected + +## +# @Enum: +# == Produces *invalid* texinfo +# @one: The _one_ {and only} +# +# @two is undocumented +## +{ 'enum': 'Enum', 'data': [ 'one', 'two' ] } diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out new file mode 100644 index 0000000000..6fce84dd34 --- /dev/null +++ b/tests/qapi-schema/doc-bad-section.out @@ -0,0 +1,13 @@ +enum Enum ['one', 'two'] +enum QType ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', 'qbool'] + prefix QTYPE +object q_empty +doc symbol=Enum + body= +== Produces *invalid* texinfo + arg=one +The _one_ {and only} + arg=two + + section= +@two is undocumented diff --git a/tests/qapi-schema/doc-good.json b/tests/qapi-schema/doc-good.json index cfdc0a8a81..97ab4625ff 100644 --- a/tests/qapi-schema/doc-good.json +++ b/tests/qapi-schema/doc-good.json @@ -51,7 +51,6 @@ ## # @Enum: -# == Produces *invalid* texinfo # @one: The _one_ {and only} # # @two is undocumented diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 63ca25a8b9..c55e394e8a 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -77,7 +77,7 @@ Examples: - {braces} doc symbol=Enum body= -== Produces *invalid* texinfo + arg=one The _one_ {and only} arg=two diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index c410626e4a..a331349756 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -76,7 +76,7 @@ Examples: @deftp {Enum} Enum -@subsection Produces @strong{invalid} texinfo + @b{Values:} @table @asis From 0968dc9ae4d3f309c4ab4bddc2a69c8d9b2786ae Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:36 +0200 Subject: [PATCH 293/546] qapi2texi: Clean up texi_sections() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repurposing the function parameter doc for stepping through doc.sections.__str__() is not nice. Use new variable @text instead. While there, eliminate variables name and func. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-7-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi2texi.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py index a317526e51..f876d9a174 100755 --- a/scripts/qapi2texi.py +++ b/scripts/qapi2texi.py @@ -180,16 +180,14 @@ def texi_sections(doc): """Format additional sections following arguments""" body = '' for section in doc.sections: - name, doc = (section.name, str(section)) - func = texi_format - if name.startswith('Example'): - func = texi_example - - if name: + if section.name: # prefer @b over @strong, so txt doesn't translate it to *Foo:* - body += '\n\n@b{%s:}\n' % name - - body += func(doc) + body += '\n\n@b{%s:}\n' % section.name + text = str(section) + if section.name.startswith('Example'): + body += texi_example(text) + else: + body += texi_format(text) return body From fc3f0df18711121ddbcd04bac3a6abb3fb9392be Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:37 +0200 Subject: [PATCH 294/546] qapi: Unify representation of doc section without name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have two representations of sections without a name: the main section uses name=None, the others name=''. Standardize on name=None. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-8-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 2 +- scripts/qapi2texi.py | 2 +- tests/qapi-schema/doc-bad-section.out | 2 +- tests/qapi-schema/doc-good.out | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 2f2738f562..2137067b48 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -204,7 +204,7 @@ def _start_args_section(self, name): self.section = QAPIDoc.ArgSection(name) self.args[name] = self.section - def _start_section(self, name=''): + def _start_section(self, name=None): if name in ('Returns', 'Since') and self.has_section(name): raise QAPIParseError(self.parser, "Duplicated '%s' section" % name) diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py index f876d9a174..f16fa1ba53 100755 --- a/scripts/qapi2texi.py +++ b/scripts/qapi2texi.py @@ -184,7 +184,7 @@ def texi_sections(doc): # prefer @b over @strong, so txt doesn't translate it to *Foo:* body += '\n\n@b{%s:}\n' % section.name text = str(section) - if section.name.startswith('Example'): + if section.name and section.name.startswith('Example'): body += texi_example(text) else: body += texi_format(text) diff --git a/tests/qapi-schema/doc-bad-section.out b/tests/qapi-schema/doc-bad-section.out index 6fce84dd34..089bde1381 100644 --- a/tests/qapi-schema/doc-bad-section.out +++ b/tests/qapi-schema/doc-bad-section.out @@ -9,5 +9,5 @@ doc symbol=Enum The _one_ {and only} arg=two - section= + section=None @two is undocumented diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index c55e394e8a..1d2c250527 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -82,7 +82,7 @@ doc symbol=Enum The _one_ {and only} arg=two - section= + section=None @two is undocumented doc symbol=Base body= From 09331fced1c4e04109ccc9d6852f29e0453cf583 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:38 +0200 Subject: [PATCH 295/546] qapi: Simplify representation of QAPIDoc section text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a string instead of a list of strings. This makes qapi2texi.py generate additional blank lines. They're harmless, and the next commit will get rid of them again. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-9-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 16 ++++++---------- scripts/qapi2texi.py | 14 +++++++------- tests/qapi-schema/doc-good.texi | 1 + tests/qapi-schema/test-qapi.py | 6 +++--- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index 2137067b48..e338868a52 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -106,13 +106,10 @@ def __init__(self, name=None): # optional section name (argument/member or section name) self.name = name # the list of lines for this section - self.content = [] + self.text = '' def append(self, line): - self.content.append(line) - - def __repr__(self): - return '\n'.join(self.content).strip() + self.text += line.rstrip() + '\n' class ArgSection(Section): def __init__(self, name): @@ -160,7 +157,7 @@ def append(self, line): # recognized, and get silently treated as ordinary text if self.symbol: self._append_symbol_line(line) - elif not self.body.content and line.startswith('@'): + elif not self.body.text and line.startswith('@'): if not line.endswith(':'): raise QAPIParseError(self.parser, "Line should end with :") self.symbol = line[1:-1] @@ -214,16 +211,15 @@ def _start_section(self, name=None): def _end_section(self): if self.section: - contents = str(self.section) - if self.section.name and (not contents or contents.isspace()): + text = self.section.text = self.section.text.strip() + if self.section.name and (not text or text.isspace()): raise QAPIParseError(self.parser, "Empty doc section '%s'" % self.section.name) self.section = None def _append_freeform(self, line): in_arg = isinstance(self.section, QAPIDoc.ArgSection) - if (in_arg and self.section.content - and not self.section.content[-1] + if (in_arg and self.section.text.endswith('\n\n') and line and not line[0].isspace()): self._start_section() if (in_arg or not self.section.name diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py index f16fa1ba53..379d27643d 100755 --- a/scripts/qapi2texi.py +++ b/scripts/qapi2texi.py @@ -125,7 +125,7 @@ def texi_format(doc): def texi_body(doc): """Format the main documentation body""" - return texi_format(str(doc.body)) + '\n' + return texi_format(doc.body.text) + '\n' def texi_enum_value(value): @@ -149,8 +149,8 @@ def texi_members(doc, what, base, variants, member_func): items = '' for section in doc.args.itervalues(): # TODO Drop fallbacks when undocumented members are outlawed - if section.content: - desc = texi_format(str(section)) + if section.text: + desc = texi_format(section.text) elif (variants and variants.tag_member == section.member and not section.member.type.doc_type()): values = section.member.type.member_names() @@ -183,11 +183,10 @@ def texi_sections(doc): if section.name: # prefer @b over @strong, so txt doesn't translate it to *Foo:* body += '\n\n@b{%s:}\n' % section.name - text = str(section) if section.name and section.name.startswith('Example'): - body += texi_example(text) + body += texi_example(section.text) else: - body += texi_format(text) + body += texi_format(section.text) return body @@ -240,7 +239,8 @@ def visit_command(self, name, info, arg_type, ret_type, self.out += '\n' if boxed: body = texi_body(doc) - body += '\n@b{Arguments:} the members of @code{%s}' % arg_type.name + body += ('\n@b{Arguments:} the members of @code{%s}\n' + % arg_type.name) body += texi_sections(doc) else: body = texi_entity(doc, 'Arguments') diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index a331349756..c032f23fc1 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -230,6 +230,7 @@ If you're bored enough to read this, go see a video of boxed cats @b{Arguments:} the members of @code{Object} + @b{Example:} @example -> in diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py index c7724d3437..fe0ca08d78 100644 --- a/tests/qapi-schema/test-qapi.py +++ b/tests/qapi-schema/test-qapi.py @@ -61,8 +61,8 @@ def _print_variants(variants): print 'doc symbol=%s' % doc.symbol else: print 'doc freeform' - print ' body=\n%s' % doc.body + print ' body=\n%s' % doc.body.text for arg, section in doc.args.iteritems(): - print ' arg=%s\n%s' % (arg, section) + print ' arg=%s\n%s' % (arg, section.text) for section in doc.sections: - print ' section=%s\n%s' % (section.name, section) + print ' section=%s\n%s' % (section.name, section.text) From 76eb6b60edbb15fd2f3beda7da3991951a3b8883 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:39 +0200 Subject: [PATCH 296/546] qapi2texi: Simplify representation of section text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a string instead of a list of strings. While there, generate fewer superfluous blank lines. Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-10-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi2texi.py | 33 ++++++++++++++++----------------- tests/qapi-schema/doc-good.texi | 10 ---------- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py index 379d27643d..58add26c11 100755 --- a/scripts/qapi2texi.py +++ b/scripts/qapi2texi.py @@ -13,7 +13,6 @@ @deftypefn {type} {{}} {name} {body} - @end deftypefn """.format @@ -22,7 +21,6 @@ @deftp {{{type}}} {name} {body} - @end deftp """.format @@ -74,7 +72,7 @@ def texi_format(doc): - 1. or 1): generates an @enumerate @item - */-: generates an @itemize list """ - lines = [] + ret = '' doc = subst_braces(doc) doc = subst_vars(doc) doc = subst_emph(doc) @@ -100,32 +98,32 @@ def texi_format(doc): line = '@subsection ' + line[3:] elif re.match(r'^([0-9]*\.) ', line): if not inlist: - lines.append('@enumerate') + ret += '@enumerate\n' inlist = 'enumerate' + ret += '@item\n' line = line[line.find(' ')+1:] - lines.append('@item') elif re.match(r'^[*-] ', line): if not inlist: - lines.append('@itemize %s' % {'*': '@bullet', - '-': '@minus'}[line[0]]) + ret += '@itemize %s\n' % {'*': '@bullet', + '-': '@minus'}[line[0]] inlist = 'itemize' - lines.append('@item') + ret += '@item\n' line = line[2:] elif lastempty and inlist: - lines.append('@end %s\n' % inlist) + ret += '@end %s\n\n' % inlist inlist = '' lastempty = empty - lines.append(line) + ret += line + '\n' if inlist: - lines.append('@end %s\n' % inlist) - return '\n'.join(lines) + ret += '@end %s\n\n' % inlist + return ret def texi_body(doc): """Format the main documentation body""" - return texi_format(doc.body.text) + '\n' + return texi_format(doc.body.text) def texi_enum_value(value): @@ -154,10 +152,11 @@ def texi_members(doc, what, base, variants, member_func): elif (variants and variants.tag_member == section.member and not section.member.type.doc_type()): values = section.member.type.member_names() - desc = 'One of ' + ', '.join(['@t{"%s"}' % v for v in values]) + members_text = ', '.join(['@t{"%s"}' % v for v in values]) + desc = 'One of ' + members_text + '\n' else: - desc = 'Not documented' - items += member_func(section.member) + desc + '\n' + desc = 'Not documented\n' + items += member_func(section.member) + desc if base: items += '@item The members of @code{%s}\n' % base.doc_type() if variants: @@ -182,7 +181,7 @@ def texi_sections(doc): for section in doc.sections: if section.name: # prefer @b over @strong, so txt doesn't translate it to *Foo:* - body += '\n\n@b{%s:}\n' % section.name + body += '\n@b{%s:}\n' % section.name if section.name and section.name.startswith('Example'): body += texi_example(section.text) else: diff --git a/tests/qapi-schema/doc-good.texi b/tests/qapi-schema/doc-good.texi index c032f23fc1..1778312581 100644 --- a/tests/qapi-schema/doc-good.texi +++ b/tests/qapi-schema/doc-good.texi @@ -101,7 +101,6 @@ Not documented the first member @end table - @end deftp @@ -118,7 +117,6 @@ Another paragraph (but no @code{var}: line) Not documented @end table - @end deftp @@ -127,7 +125,6 @@ Not documented - @end deftp @@ -143,7 +140,6 @@ Not documented @item The members of @code{Variant2} when @code{base1} is @t{"two"} @end table - @end deftp @@ -160,7 +156,6 @@ One of @t{"one"}, @t{"two"} @item @code{data: Variant2} when @code{type} is @t{"two"} @end table - @end deftp @@ -182,7 +177,6 @@ argument Not documented @end table - @b{Note:} @code{arg3} is undocumented @@ -209,14 +203,12 @@ Duis aute irure dolor <- out @end example - @b{Examples:} @example - *verbatim* - @{braces@} @end example - @b{Since:} 2.10 @@ -230,7 +222,6 @@ If you're bored enough to read this, go see a video of boxed cats @b{Arguments:} the members of @code{Object} - @b{Example:} @example -> in @@ -238,7 +229,6 @@ If you're bored enough to read this, go see a video of boxed cats <- out @end example - @end deftypefn From 8cbf1a537a61b2a1832948f20582839cebdb69de Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:40 +0200 Subject: [PATCH 297/546] qapi: Rename QAPIDoc.parser, .section to ._parser, ._section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-11-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi.py | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/scripts/qapi.py b/scripts/qapi.py index e338868a52..43a54bf40f 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -120,11 +120,11 @@ def connect(self, member): self.member = member def __init__(self, parser, info): - # self.parser is used to report errors with QAPIParseError. The + # self._parser is used to report errors with QAPIParseError. The # resulting error position depends on the state of the parser. # It happens to be the beginning of the comment. More or less # servicable, but action at a distance. - self.parser = parser + self._parser = parser self.info = info self.symbol = None self.body = QAPIDoc.Section() @@ -133,7 +133,7 @@ def __init__(self, parser, info): # a list of Section self.sections = [] # the current section - self.section = self.body + self._section = self.body def has_section(self, name): """Return True if we have a section with this name.""" @@ -150,7 +150,7 @@ def append(self, line): return if line[0] != ' ': - raise QAPIParseError(self.parser, "Missing space after #") + raise QAPIParseError(self._parser, "Missing space after #") line = line[1:] # FIXME not nice: things like '# @foo:' and '# @foo: ' aren't @@ -159,11 +159,11 @@ def append(self, line): self._append_symbol_line(line) elif not self.body.text and line.startswith('@'): if not line.endswith(':'): - raise QAPIParseError(self.parser, "Line should end with :") + raise QAPIParseError(self._parser, "Line should end with :") self.symbol = line[1:-1] # FIXME invalid names other than the empty string aren't flagged if not self.symbol: - raise QAPIParseError(self.parser, "Invalid name") + raise QAPIParseError(self._parser, "Invalid name") else: self._append_freeform(line) @@ -189,48 +189,48 @@ def _append_symbol_line(self, line): def _start_args_section(self, name): # FIXME invalid names other than the empty string aren't flagged if not name: - raise QAPIParseError(self.parser, "Invalid parameter name") + raise QAPIParseError(self._parser, "Invalid parameter name") if name in self.args: - raise QAPIParseError(self.parser, + raise QAPIParseError(self._parser, "'%s' parameter name duplicated" % name) if self.sections: - raise QAPIParseError(self.parser, + raise QAPIParseError(self._parser, "'@%s:' can't follow '%s' section" % (name, self.sections[0].name)) self._end_section() - self.section = QAPIDoc.ArgSection(name) - self.args[name] = self.section + self._section = QAPIDoc.ArgSection(name) + self.args[name] = self._section def _start_section(self, name=None): if name in ('Returns', 'Since') and self.has_section(name): - raise QAPIParseError(self.parser, + raise QAPIParseError(self._parser, "Duplicated '%s' section" % name) self._end_section() - self.section = QAPIDoc.Section(name) - self.sections.append(self.section) + self._section = QAPIDoc.Section(name) + self.sections.append(self._section) def _end_section(self): - if self.section: - text = self.section.text = self.section.text.strip() - if self.section.name and (not text or text.isspace()): - raise QAPIParseError(self.parser, "Empty doc section '%s'" - % self.section.name) - self.section = None + if self._section: + text = self._section.text = self._section.text.strip() + if self._section.name and (not text or text.isspace()): + raise QAPIParseError(self._parser, "Empty doc section '%s'" + % self._section.name) + self._section = None def _append_freeform(self, line): - in_arg = isinstance(self.section, QAPIDoc.ArgSection) - if (in_arg and self.section.text.endswith('\n\n') + in_arg = isinstance(self._section, QAPIDoc.ArgSection) + if (in_arg and self._section.text.endswith('\n\n') and line and not line[0].isspace()): self._start_section() - if (in_arg or not self.section.name - or not self.section.name.startswith('Example')): + if (in_arg or not self._section.name + or not self._section.name.startswith('Example')): line = line.strip() match = re.match(r'(@\S+:)', line) if match: - raise QAPIParseError(self.parser, + raise QAPIParseError(self._parser, "'%s' not allowed in free-form documentation" % match.group(1)) - self.section.append(line) + self._section.append(line) def connect_member(self, member): if member.name not in self.args: From 7e21572ce768a1b4cd4d4b24405d5f75448bbf62 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 2 Oct 2017 16:13:41 +0200 Subject: [PATCH 298/546] qapi2texi: De-duplicate code to add blank line before symbol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Markus Armbruster Message-Id: <20171002141341.24616-12-armbru@redhat.com> Reviewed-by: Marc-André Lureau --- scripts/qapi2texi.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py index 58add26c11..92e2af2cd6 100755 --- a/scripts/qapi2texi.py +++ b/scripts/qapi2texi.py @@ -206,8 +206,6 @@ def visit_begin(self, schema): def visit_enum_type(self, name, info, values, prefix): doc = self.cur_doc - if self.out: - self.out += '\n' self.out += TYPE_FMT(type='Enum', name=doc.symbol, body=texi_entity(doc, 'Values', @@ -217,16 +215,12 @@ def visit_object_type(self, name, info, base, members, variants): doc = self.cur_doc if base and base.is_implicit(): base = None - if self.out: - self.out += '\n' self.out += TYPE_FMT(type='Object', name=doc.symbol, body=texi_entity(doc, 'Members', base, variants)) def visit_alternate_type(self, name, info, variants): doc = self.cur_doc - if self.out: - self.out += '\n' self.out += TYPE_FMT(type='Alternate', name=doc.symbol, body=texi_entity(doc, 'Members')) @@ -234,8 +228,6 @@ def visit_alternate_type(self, name, info, variants): def visit_command(self, name, info, arg_type, ret_type, gen, success_response, boxed): doc = self.cur_doc - if self.out: - self.out += '\n' if boxed: body = texi_body(doc) body += ('\n@b{Arguments:} the members of @code{%s}\n' @@ -249,13 +241,13 @@ def visit_command(self, name, info, arg_type, ret_type, def visit_event(self, name, info, arg_type, boxed): doc = self.cur_doc - if self.out: - self.out += '\n' self.out += MSG_FMT(type='Event', name=doc.symbol, body=texi_entity(doc, 'Arguments')) def symbol(self, doc, entity): + if self.out: + self.out += '\n' self.cur_doc = doc entity.visit(self) self.cur_doc = None From 0b263ecbcf71273abc8f79762e2349841a003c27 Mon Sep 17 00:00:00 2001 From: Chen Hanxiao Date: Thu, 12 Oct 2017 14:44:48 +0800 Subject: [PATCH 299/546] qapi-docs: fix a comment typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit s/Subection/Subsection Signed-off-by: Chen Hanxiao Message-Id: <20171012064448.20276-1-chen_han_xiao@126.com> Reviewed-by: Marc-André Lureau Signed-off-by: Markus Armbruster --- docs/devel/qapi-code-gen.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index f04c63fe82..06ab699066 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -63,7 +63,7 @@ Comment text starting with '=' is a section title: Double the '=' for a subsection title: - # == Subection title + # == Subsection title '|' denotes examples: From 49ccefde303c84d291c70842922c37b6de6ef15a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 20 Dec 2017 08:23:04 -0200 Subject: [PATCH 300/546] qmp: remove qmp_cpu 'qmp_cpu' was implemented in commit 755f196898 ("qapi: Convert the cpu command") as a functional no-op, a QMP call that does nothing and return success. The idea, apparently, was to provide a counterpart for the HMP 'hmp_cpu' command, introduced in the same commit. After 6 years of its creation, qmp_cpu remains a functional no-op that does nothing, having no value for any caller/user. A proposal was sent to implement qmp_cpu like hmp_cpu works, but it was denied [1]. The reason is that QMP must be as stateless as possible and a function that changes its state (the current CPU monitor in the case of qmp_cpu) goes against it. Any QMP command that needs a specific monitor CPU setup must provide it in its arguments, instead of relying in the current QMP monitor state. After discussions that happened in [2] it was decided that a command that does nothing since its birth, no one uses for anything and will not be implemented, should be deprecated and erased. Given that we will *not* provide any replacement for qmp_cpu and we believe that there is no user relying on it, there is no point in adding a deprecation delay for it. So, this patch nukes qmp_cpu from QEMU code, removing both its blank implementation in qmp.c and its doc in qapi-schema.json. [1] https://lists.gnu.org/archive/html/qemu-devel/2017-12/msg02283.html [2] https://lists.gnu.org/archive/html/qemu-devel/2017-12/msg03696.html Signed-off-by: Daniel Henrique Barboza CC: Markus Armbruster CC: Eric Blake CC: Daniel P. Berrange Message-Id: <20171220102304.8288-1-danielhb@linux.vnet.ibm.com> Reviewed-by: Daniel P. Berrange Signed-off-by: Markus Armbruster --- qapi-schema.json | 11 ----------- qmp.c | 5 ----- 2 files changed, 16 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index ea3723f903..5c06745c79 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1045,17 +1045,6 @@ ## { 'command': 'system_powerdown' } -## -# @cpu: -# -# This command is a nop that is only provided for the purposes of compatibility. -# -# Since: 0.14.0 -# -# Notes: Do not use this command. -## -{ 'command': 'cpu', 'data': {'index': 'int'} } - ## # @cpu-add: # diff --git a/qmp.c b/qmp.c index e8c303116a..52cfd2d81c 100644 --- a/qmp.c +++ b/qmp.c @@ -113,11 +113,6 @@ void qmp_system_powerdown(Error **erp) qemu_system_powerdown_request(); } -void qmp_cpu(int64_t index, Error **errp) -{ - /* Just do nothing */ -} - void qmp_cpu_add(int64_t id, Error **errp) { MachineClass *mc; From 75e5b70e6b5dcc4f2219992d7cffa462aa406af0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 28 Nov 2017 11:51:27 +0100 Subject: [PATCH 301/546] memfd: fix configure test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Recent glibc added memfd_create in sys/mman.h. This conflicts with the definition in util/memfd.c: /builddir/build/BUILD/qemu-2.11.0-rc1/util/memfd.c:40:12: error: static declaration of memfd_create follows non-static declaration Fix the configure test, and remove the sys/memfd.h inclusion since the file actually does not exist---it is a typo in the memfd_create(2) man page. Cc: Marc-André Lureau Signed-off-by: Paolo Bonzini --- configure | 2 +- util/memfd.c | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 9c8aa5a98b..99ccc1725a 100755 --- a/configure +++ b/configure @@ -3923,7 +3923,7 @@ fi # check if memfd is supported memfd=no cat > $TMPC << EOF -#include +#include int main(void) { diff --git a/util/memfd.c b/util/memfd.c index 4571d1aba8..412e94a405 100644 --- a/util/memfd.c +++ b/util/memfd.c @@ -31,9 +31,7 @@ #include "qemu/memfd.h" -#ifdef CONFIG_MEMFD -#include -#elif defined CONFIG_LINUX +#if defined CONFIG_LINUX && !defined CONFIG_MEMFD #include #include From 68a9398261ca38979bbc2b7c89ed5bb044ccc9e6 Mon Sep 17 00:00:00 2001 From: linzhecheng Date: Tue, 28 Nov 2017 12:46:56 +0800 Subject: [PATCH 302/546] qemu-thread: fix races on threads that exit very quickly If we create a thread with QEMU_THREAD_DETACHED mode, QEMU may get a segfault with low probability. The backtrace is: #0 0x00007f46c60291d7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 #1 0x00007f46c602a8c8 in __GI_abort () at abort.c:90 #2 0x00000000008543c9 in PAT_abort () #3 0x000000000085140d in patchIllInsHandler () #4 #5 pthread_detach (th=139933037614848) at pthread_detach.c:50 #6 0x0000000000829759 in qemu_thread_create (thread=thread@entry=0x7ffdaa8205e0, name=name@entry=0x94d94a "io-task-worker", start_routine=start_routine@entry=0x7eb9a0 , arg=arg@entry=0x3f5cf70, mode=mode@entry=1) at util/qemu_thread_posix.c:512 #7 0x00000000007ebc96 in qio_task_run_in_thread (task=0x31db2c0, worker=worker@entry=0x7e7e40 , opaque=0xcd23380, destroy=0x7f1180 ) at io/task.c:141 #8 0x00000000007e7f33 in qio_channel_socket_connect_async (ioc=ioc@entry=0x626c0b0, addr=, callback=callback@entry=0x55e080 , opaque=opaque@entry=0x42862c0, destroy=destroy@entry=0x0) at io/channel_socket.c:194 #9 0x000000000055bdd1 in socket_reconnect_timeout (opaque=0x42862c0) at qemu_char.c:4744 #10 0x00007f46c72483b3 in g_timeout_dispatch () from /usr/lib64/libglib-2.0.so.0 #11 0x00007f46c724799a in g_main_context_dispatch () from /usr/lib64/libglib-2.0.so.0 #12 0x000000000076c646 in glib_pollfds_poll () at main_loop.c:228 #13 0x000000000076c6eb in os_host_main_loop_wait (timeout=348000000) at main_loop.c:273 #14 0x000000000076c815 in main_loop_wait (nonblocking=nonblocking@entry=0) at main_loop.c:521 #15 0x000000000056a511 in main_loop () at vl.c:2076 #16 0x0000000000420705 in main (argc=, argv=, envp=) at vl.c:4940 The cause of this problem is a glibc bug; for more information, see https://sourceware.org/bugzilla/show_bug.cgi?id=19951. The solution for this bug is to use pthread_attr_setdetachstate. There is a similar issue with pthread_setname_np, which is moved from creating thread to created thread. Signed-off-by: linzhecheng Message-Id: <20171128044656.10592-1-linzhecheng@huawei.com> Reviewed-by: Fam Zheng [Simplify the code by removing qemu_thread_set_name, and free the arguments before invoking the start routine. - Paolo] Signed-off-by: Paolo Bonzini --- util/qemu-thread-posix.c | 61 ++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 7306475899..959a57079f 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -479,15 +479,29 @@ static void __attribute__((constructor)) qemu_thread_atexit_init(void) } -/* Attempt to set the threads name; note that this is for debug, so - * we're not going to fail if we can't set it. - */ -static void qemu_thread_set_name(QemuThread *thread, const char *name) -{ #ifdef CONFIG_PTHREAD_SETNAME_NP - pthread_setname_np(thread->thread, name); -#endif +typedef struct { + void *(*start_routine)(void *); + void *arg; + char *name; +} QemuThreadArgs; + +static void *qemu_thread_start(void *args) +{ + QemuThreadArgs *qemu_thread_args = args; + void *(*start_routine)(void *) = qemu_thread_args->start_routine; + void *arg = qemu_thread_args->arg; + + /* Attempt to set the threads name; note that this is for debug, so + * we're not going to fail if we can't set it. + */ + pthread_setname_np(pthread_self(), qemu_thread_args->name); + g_free(qemu_thread_args->name); + g_free(qemu_thread_args); + return start_routine(arg); } +#endif + void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void*), @@ -502,23 +516,34 @@ void qemu_thread_create(QemuThread *thread, const char *name, error_exit(err, __func__); } + if (mode == QEMU_THREAD_DETACHED) { + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + } + /* Leave signal handling to the iothread. */ sigfillset(&set); pthread_sigmask(SIG_SETMASK, &set, &oldset); - err = pthread_create(&thread->thread, &attr, start_routine, arg); + +#ifdef CONFIG_PTHREAD_SETNAME_NP + if (name_threads) { + QemuThreadArgs *qemu_thread_args; + qemu_thread_args = g_new0(QemuThreadArgs, 1); + qemu_thread_args->name = g_strdup(name); + qemu_thread_args->start_routine = start_routine; + qemu_thread_args->arg = arg; + + err = pthread_create(&thread->thread, &attr, + qemu_thread_start, qemu_thread_args); + } else +#endif + { + err = pthread_create(&thread->thread, &attr, + start_routine, arg); + } + if (err) error_exit(err, __func__); - if (name_threads) { - qemu_thread_set_name(thread, name); - } - - if (mode == QEMU_THREAD_DETACHED) { - err = pthread_detach(thread->thread); - if (err) { - error_exit(err, __func__); - } - } pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_attr_destroy(&attr); From a4a9b6eaf35dbe4bf0e069854945bf5e45fc7eab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 1 Dec 2017 18:40:06 +0100 Subject: [PATCH 303/546] qemu-pr-helper: miscellaneous fixes 1) Return a generic sense if TEST UNIT READY does not provide one; 2) Fix two mistakes in copying from the spec. Cc: qemu-stable@nongnu.org Reported-by: Dr. David Alan Gilbert Signed-off-by: Paolo Bonzini --- include/scsi/utils.h | 6 +++++- scsi/qemu-pr-helper.c | 30 ++++++++++++++++++++++++++---- scsi/utils.c | 10 ++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/include/scsi/utils.h b/include/scsi/utils.h index 00a4bdb080..eb07e474ee 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -76,7 +76,11 @@ extern const struct SCSISense sense_code_LUN_FAILURE; extern const struct SCSISense sense_code_LUN_COMM_FAILURE; /* Command aborted, Overlapped Commands Attempted */ extern const struct SCSISense sense_code_OVERLAPPED_COMMANDS; -/* LUN not ready, Capacity data has changed */ +/* Medium error, Unrecovered read error */ +extern const struct SCSISense sense_code_READ_ERROR; +/* LUN not ready, Cause not reportable */ +extern const struct SCSISense sense_code_NOT_READY; +/* Unit attention, Capacity data has changed */ extern const struct SCSISense sense_code_CAPACITY_CHANGED; /* Unit attention, SCSI bus reset */ extern const struct SCSISense sense_code_SCSI_BUS_RESET; diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c index dd9785143b..9fe615c73c 100644 --- a/scsi/qemu-pr-helper.c +++ b/scsi/qemu-pr-helper.c @@ -314,6 +314,22 @@ static int is_mpath(int fd) return !strncmp(tgt->target_type, "multipath", DM_MAX_TYPE_NAME); } +static SCSISense mpath_generic_sense(int r) +{ + switch (r) { + case MPATH_PR_SENSE_NOT_READY: + return SENSE_CODE(NOT_READY); + case MPATH_PR_SENSE_MEDIUM_ERROR: + return SENSE_CODE(READ_ERROR); + case MPATH_PR_SENSE_HARDWARE_ERROR: + return SENSE_CODE(TARGET_FAILURE); + case MPATH_PR_SENSE_ABORTED_COMMAND: + return SENSE_CODE(IO_ERROR); + default: + abort(); + } +} + static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) { switch (r) { @@ -329,7 +345,13 @@ static int mpath_reconstruct_sense(int fd, int r, uint8_t *sense) */ uint8_t cdb[6] = { TEST_UNIT_READY }; int sz = 0; - return do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); + int r = do_sgio(fd, cdb, sense, NULL, &sz, SG_DXFER_NONE); + + if (r != GOOD) { + return r; + } + scsi_build_sense(sense, mpath_generic_sense(r)); + return CHECK_CONDITION; } case MPATH_PR_SENSE_UNIT_ATTENTION: @@ -449,7 +471,7 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, memset(¶mp, 0, sizeof(paramp)); memcpy(¶mp.key, ¶m[0], 8); memcpy(¶mp.sa_key, ¶m[8], 8); - paramp.sa_flags = param[10]; + paramp.sa_flags = param[20]; if (sz > PR_OUT_FIXED_PARAM_SIZE) { size_t transportid_len; int i, j; @@ -478,8 +500,8 @@ static int multipath_pr_out(int fd, const uint8_t *cdb, uint8_t *sense, j += offsetof(struct transportid, n_port_name[8]); i += 24; break; - case 3: - case 0x43: + case 5: + case 0x45: /* iSCSI transport. */ len = lduw_be_p(¶m[i + 2]); if (len > 252 || (len & 3) || i + len + 4 > transportid_len) { diff --git a/scsi/utils.c b/scsi/utils.c index 5684951b12..e4182a9b09 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -211,6 +211,16 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = { .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00 }; +/* Medium Error, Unrecovered read error */ +const struct SCSISense sense_code_READ_ERROR = { + .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00 +}; + +/* Not ready, Cause not reportable */ +const struct SCSISense sense_code_NOT_READY = { + .key = NOT_READY, .asc = 0x04, .ascq = 0x00 +}; + /* Unit attention, Capacity data has changed */ const struct SCSISense sense_code_CAPACITY_CHANGED = { .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 From 2ba60ec1751844fe75d32dd80ebb3d72480b4b17 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Nov 2017 17:44:22 +0100 Subject: [PATCH 304/546] contrib: add systemd unit files This lets distros standardize on how QEMU should install systemd services for qemu-ga and qemu-pr-helper. The qemu-ga unit file comes from Fedora, but I checked that Debian is using the same path for the virtio-serisal port. I would like to include this in 2.11, so that the qemu-pr-helper socket can be standardized across distros. Note however that the files are not installed. We can add a configure option in 2.12 perhaps, but it's too late now; documenting the files in the release notes should do. Suggested-by: Daniel P. Berrange Signed-off-by: Paolo Bonzini Message-Id: <20171124164422.3960-1-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- contrib/systemd/qemu-guest-agent.service | 11 +++++++++++ contrib/systemd/qemu-pr-helper.service | 15 +++++++++++++++ contrib/systemd/qemu-pr-helper.socket | 9 +++++++++ 3 files changed, 35 insertions(+) create mode 100644 contrib/systemd/qemu-guest-agent.service create mode 100644 contrib/systemd/qemu-pr-helper.service create mode 100644 contrib/systemd/qemu-pr-helper.socket diff --git a/contrib/systemd/qemu-guest-agent.service b/contrib/systemd/qemu-guest-agent.service new file mode 100644 index 0000000000..51cd7b37ff --- /dev/null +++ b/contrib/systemd/qemu-guest-agent.service @@ -0,0 +1,11 @@ +[Unit] +Description=QEMU Guest Agent +BindTo=dev-virtio\x2dports-org.qemu.guest_agent.0.device +After=dev-virtio\x2dports-org.qemu.guest_agent.0.device + +[Service] +ExecStart=-/usr/bin/qemu-ga +Restart=always +RestartSec=0 + +[Install] diff --git a/contrib/systemd/qemu-pr-helper.service b/contrib/systemd/qemu-pr-helper.service new file mode 100644 index 0000000000..a1d27b0221 --- /dev/null +++ b/contrib/systemd/qemu-pr-helper.service @@ -0,0 +1,15 @@ +[Unit] +Description=Persistent Reservation Daemon for QEMU + +[Service] +WorkingDirectory=/tmp +Type=simple +ExecStart=/usr/bin/qemu-pr-helper +PrivateTmp=yes +ProtectSystem=strict +ReadWritePaths=/var/run +RestrictAddressFamilies=AF_UNIX +Restart=always +RestartSec=0 + +[Install] diff --git a/contrib/systemd/qemu-pr-helper.socket b/contrib/systemd/qemu-pr-helper.socket new file mode 100644 index 0000000000..9d7c3e5e2c --- /dev/null +++ b/contrib/systemd/qemu-pr-helper.socket @@ -0,0 +1,9 @@ +[Unit] +Description=Persistent Reservation Daemon for QEMU + +[Socket] +ListenStream=/run/qemu-pr-helper.sock +SocketMode=0600 + +[Install] +WantedBy=multi-user.target From 07488549f884a658689370b9ef878dc50eced83e Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 5 Dec 2017 15:19:28 +0800 Subject: [PATCH 305/546] scsi-block: Add share-rw option Scsi-block doesn't use the DEFINE_BLOCK_PROPERTIES() macro so it didn't gain the share-rw back when it was added to all other storage devices. This option is meaningful here, and need to be used when attaching a shared storage to guest. Signed-off-by: Fam Zheng Message-Id: <20171205071928.30242-1-famz@redhat.com> Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-disk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 870d9ae85a..e58833a087 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3004,6 +3004,7 @@ static const TypeInfo scsi_cd_info = { static Property scsi_block_properties[] = { DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \ DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk), + DEFINE_PROP_BOOL("share-rw", SCSIDiskState, qdev.conf.share_rw, false), DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), DEFINE_PROP_END_OF_LIST(), }; From c2380365d1d6c8c9f920651a2a429c75d977a589 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 5 Dec 2017 15:22:20 +0800 Subject: [PATCH 306/546] MAITAINERS: List Fam Zheng as reviewer for SCSI patches Just so that I notice those patches more easily. Signed-off-by: Fam Zheng Message-Id: <20171205072220.885-1-famz@redhat.com> Signed-off-by: Paolo Bonzini --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8859a50c36..73a5555735 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1011,6 +1011,7 @@ T: git git://github.com/jasowang/qemu.git net SCSI M: Paolo Bonzini +R: Fam Zheng S: Supported F: include/hw/scsi/* F: hw/scsi/* @@ -1271,6 +1272,7 @@ T: git git://github.com/stefanha/qemu.git block Block SCSI subsystem M: Paolo Bonzini +R: Fam Zheng L: qemu-block@nongnu.org S: Supported F: include/scsi/* From aff9e6e46a343e1404498be4edd03db1112f0950 Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Wed, 22 Nov 2017 15:27:56 +0800 Subject: [PATCH 307/546] x86/cpu: Enable new SSE/AVX/AVX512 cpu features Intel IceLake cpu has added new cpu features,AVX512_VBMI2/GFNI/ VAES/VPCLMULQDQ/AVX512_VNNI/AVX512_BITALG. Those new cpu features need expose to guest VM. The bit definition: CPUID.(EAX=7,ECX=0):ECX[bit 06] AVX512_VBMI2 CPUID.(EAX=7,ECX=0):ECX[bit 08] GFNI CPUID.(EAX=7,ECX=0):ECX[bit 09] VAES CPUID.(EAX=7,ECX=0):ECX[bit 10] VPCLMULQDQ CPUID.(EAX=7,ECX=0):ECX[bit 11] AVX512_VNNI CPUID.(EAX=7,ECX=0):ECX[bit 12] AVX512_BITALG The release document ref below link: https://software.intel.com/sites/default/files/managed/c5/15/\ architecture-instruction-set-extensions-programming-reference.pdf Signed-off-by: Yang Zhong Message-Id: <1511335676-20797-1-git-send-email-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 6 +++--- target/i386/cpu.h | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 82603e3130..325b52e325 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -437,9 +437,9 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_7_0_ECX] = { .feat_names = { NULL, "avx512vbmi", "umip", "pku", - "ospke", NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, "avx512-vpopcntdq", NULL, + "ospke", NULL, "avx512vbmi2", NULL, + "gfni", "vaes", "vpclmulqdq", "avx512vnni", + "avx512bitalg", NULL, "avx512-vpopcntdq", NULL, "la57", NULL, NULL, NULL, NULL, NULL, "rdpid", NULL, NULL, NULL, NULL, NULL, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index b086b1528b..cdbf8b0cd7 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -635,6 +635,12 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_ECX_UMIP (1U << 2) #define CPUID_7_0_ECX_PKU (1U << 3) #define CPUID_7_0_ECX_OSPKE (1U << 4) +#define CPUID_7_0_ECX_VBMI2 (1U << 6) /* Additional VBMI Instrs */ +#define CPUID_7_0_ECX_GFNI (1U << 8) +#define CPUID_7_0_ECX_VAES (1U << 9) +#define CPUID_7_0_ECX_VPCLMULQDQ (1U << 10) +#define CPUID_7_0_ECX_AVX512VNNI (1U << 11) +#define CPUID_7_0_ECX_AVX512BITALG (1U << 12) #define CPUID_7_0_ECX_AVX512_VPOPCNTDQ (1U << 14) /* POPCNT for vectors of DW/QW */ #define CPUID_7_0_ECX_LA57 (1U << 16) #define CPUID_7_0_ECX_RDPID (1U << 22) From da1cc323b8aee60d4816ce7521177b14ec3008b4 Mon Sep 17 00:00:00 2001 From: Evgeny Yakovlev Date: Wed, 22 Nov 2017 21:14:16 +0300 Subject: [PATCH 308/546] hyperv: set partition-wide MSRs only on first vcpu Hyper-V has a notion of partition-wide MSRs. Those MSRs are read and written as usual on each VCPU, however the hypervisor maintains a single global value for all VCPUs. Thus writing such an MSR from any single VCPU affects the global value that is read by all other VCPUs. This leads to an issue during VCPU hotplug: the zero-initialzied values of those MSRs get synced into KVM and override the global values as has already been set by the guest. This change makes the partition-wide MSRs only be synchronized on the first vcpu. Signed-off-by: Evgeny Yakovlev Signed-off-by: Roman Kagan Message-Id: <20171122181418.14180-2-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 5 ++++- target/i386/kvm.c | 23 +++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index cdbf8b0cd7..17f1bb7ecb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1097,10 +1097,13 @@ typedef struct CPUX86State { uint64_t async_pf_en_msr; uint64_t pv_eoi_en_msr; + /* Partition-wide HV MSRs, will be updated only on the first vcpu */ uint64_t msr_hv_hypercall; uint64_t msr_hv_guest_os_id; - uint64_t msr_hv_vapic; uint64_t msr_hv_tsc; + + /* Per-VCPU HV MSRs */ + uint64_t msr_hv_vapic; uint64_t msr_hv_crash_params[HV_CRASH_PARAMS]; uint64_t msr_hv_runtime; uint64_t msr_hv_synic_control; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index d4b2ce2e94..89fa65e243 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1678,19 +1678,26 @@ static int kvm_put_msrs(X86CPU *cpu, int level) kvm_msr_entry_add(cpu, MSR_CORE_PERF_GLOBAL_CTRL, env->msr_global_ctrl); } - if (has_msr_hv_hypercall) { - kvm_msr_entry_add(cpu, HV_X64_MSR_GUEST_OS_ID, - env->msr_hv_guest_os_id); - kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, - env->msr_hv_hypercall); + /* + * Hyper-V partition-wide MSRs: to avoid clearing them on cpu hot-add, + * only sync them to KVM on the first cpu + */ + if (current_cpu == first_cpu) { + if (has_msr_hv_hypercall) { + kvm_msr_entry_add(cpu, HV_X64_MSR_GUEST_OS_ID, + env->msr_hv_guest_os_id); + kvm_msr_entry_add(cpu, HV_X64_MSR_HYPERCALL, + env->msr_hv_hypercall); + } + if (cpu->hyperv_time) { + kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, + env->msr_hv_tsc); + } } if (cpu->hyperv_vapic) { kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE, env->msr_hv_vapic); } - if (cpu->hyperv_time) { - kvm_msr_entry_add(cpu, HV_X64_MSR_REFERENCE_TSC, env->msr_hv_tsc); - } if (has_msr_hv_crash) { int j; From 689141dde2957894ae99315bb4e42e6ecd980248 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Wed, 22 Nov 2017 21:14:17 +0300 Subject: [PATCH 309/546] hyperv: ensure SINTx msrs are reset properly Initially SINTx msrs should be in "masked" state. To ensure that happens on *every* reset, move setting their values to kvm_arch_vcpu_reset. Signed-off-by: Roman Kagan Message-Id: <20171122181418.14180-3-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini --- target/i386/kvm.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 89fa65e243..5d93391d79 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -662,8 +662,6 @@ static int hyperv_handle_properties(CPUState *cs) env->features[FEAT_HYPERV_EAX] |= HV_VP_RUNTIME_AVAILABLE; } if (cpu->hyperv_synic) { - int sint; - if (!has_msr_hv_synic || kvm_vcpu_enable_cap(cs, KVM_CAP_HYPERV_SYNIC, 0)) { fprintf(stderr, "Hyper-V SynIC is not supported by kernel\n"); @@ -672,9 +670,6 @@ static int hyperv_handle_properties(CPUState *cs) env->features[FEAT_HYPERV_EAX] |= HV_SYNIC_AVAILABLE; env->msr_hv_synic_version = HV_SYNIC_VERSION; - for (sint = 0; sint < ARRAY_SIZE(env->msr_hv_synic_sint); sint++) { - env->msr_hv_synic_sint[sint] = HV_SINT_MASKED; - } } if (cpu->hyperv_stimer) { if (!has_msr_hv_stimer) { @@ -1053,6 +1048,13 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) } else { env->mp_state = KVM_MP_STATE_RUNNABLE; } + + if (cpu->hyperv_synic) { + int i; + for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) { + env->msr_hv_synic_sint[i] = HV_SINT_MASKED; + } + } } void kvm_arch_do_init_vcpu(X86CPU *cpu) From 09df29b665a91ba78b2187ce3b1967526ce121f6 Mon Sep 17 00:00:00 2001 From: Roman Kagan Date: Wed, 22 Nov 2017 21:14:18 +0300 Subject: [PATCH 310/546] hyperv: make SynIC version msr constant The value of HV_X64_MSR_SVERSION is initialized once at vcpu init, and is reset to zero on vcpu reset, which is wrong. It is supposed to be a constant, so drop the field from X86CPU, set the msr with the constant value, and don't bother getting it. Signed-off-by: Roman Kagan Message-Id: <20171122181418.14180-4-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 - target/i386/kvm.c | 9 ++------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 17f1bb7ecb..d605cc6ccb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1107,7 +1107,6 @@ typedef struct CPUX86State { uint64_t msr_hv_crash_params[HV_CRASH_PARAMS]; uint64_t msr_hv_runtime; uint64_t msr_hv_synic_control; - uint64_t msr_hv_synic_version; uint64_t msr_hv_synic_evt_page; uint64_t msr_hv_synic_msg_page; uint64_t msr_hv_synic_sint[HV_SINT_COUNT]; diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 5d93391d79..351b64f77c 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -669,7 +669,6 @@ static int hyperv_handle_properties(CPUState *cs) } env->features[FEAT_HYPERV_EAX] |= HV_SYNIC_AVAILABLE; - env->msr_hv_synic_version = HV_SYNIC_VERSION; } if (cpu->hyperv_stimer) { if (!has_msr_hv_stimer) { @@ -1715,10 +1714,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level) if (cpu->hyperv_synic) { int j; + kvm_msr_entry_add(cpu, HV_X64_MSR_SVERSION, HV_SYNIC_VERSION); + kvm_msr_entry_add(cpu, HV_X64_MSR_SCONTROL, env->msr_hv_synic_control); - kvm_msr_entry_add(cpu, HV_X64_MSR_SVERSION, - env->msr_hv_synic_version); kvm_msr_entry_add(cpu, HV_X64_MSR_SIEFP, env->msr_hv_synic_evt_page); kvm_msr_entry_add(cpu, HV_X64_MSR_SIMP, @@ -2082,7 +2081,6 @@ static int kvm_get_msrs(X86CPU *cpu) uint32_t msr; kvm_msr_entry_add(cpu, HV_X64_MSR_SCONTROL, 0); - kvm_msr_entry_add(cpu, HV_X64_MSR_SVERSION, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_SIEFP, 0); kvm_msr_entry_add(cpu, HV_X64_MSR_SIMP, 0); for (msr = HV_X64_MSR_SINT0; msr <= HV_X64_MSR_SINT15; msr++) { @@ -2286,9 +2284,6 @@ static int kvm_get_msrs(X86CPU *cpu) case HV_X64_MSR_SCONTROL: env->msr_hv_synic_control = msrs[i].data; break; - case HV_X64_MSR_SVERSION: - env->msr_hv_synic_version = msrs[i].data; - break; case HV_X64_MSR_SIEFP: env->msr_hv_synic_evt_page = msrs[i].data; break; From ebd05fea9be1dfd043aaa763fb6d2cd971346a58 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 29 Nov 2017 20:12:15 +0100 Subject: [PATCH 311/546] cpus: make pause_all_cpus() play with SMP on single threaded TCG pause_all_cpus() is sometimes called from a VCPU thread (e.g. s390x during special reset). It cannot deal with multiple VCPUs per Thread (single threaded TCG) yet. Booting an s390x guest with -smp 2 and single threaded TCG from disk currently fails. The DIAG 308 will issue a pause_all_cpus() and wait forever for the CPUs to actually stop. But it is waiting for itself. So let's stop all VCPUs belonging to the current thread. Factor out stopping of a VCPU. Signed-off-by: David Hildenbrand Message-Id: <20171129191215.11323-1-david@redhat.com> Signed-off-by: Paolo Bonzini --- cpus.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/cpus.c b/cpus.c index 114c29b6a0..3740c4db62 100644 --- a/cpus.c +++ b/cpus.c @@ -1057,13 +1057,22 @@ static void qemu_tcg_destroy_vcpu(CPUState *cpu) { } +static void qemu_cpu_stop(CPUState *cpu, bool exit) +{ + g_assert(qemu_cpu_is_self(cpu)); + cpu->stop = false; + cpu->stopped = true; + if (exit) { + cpu_exit(cpu); + } + qemu_cond_broadcast(&qemu_pause_cond); +} + static void qemu_wait_io_event_common(CPUState *cpu) { atomic_mb_set(&cpu->thread_kicked, false); if (cpu->stop) { - cpu->stop = false; - cpu->stopped = true; - qemu_cond_broadcast(&qemu_pause_cond); + qemu_cpu_stop(cpu, false); } process_queued_cpu_work(cpu); } @@ -1610,12 +1619,12 @@ void pause_all_vcpus(void) qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false); CPU_FOREACH(cpu) { - cpu->stop = true; - qemu_cpu_kick(cpu); - } - - if (qemu_in_vcpu_thread()) { - cpu_stop_current(); + if (qemu_cpu_is_self(cpu)) { + qemu_cpu_stop(cpu, true); + } else { + cpu->stop = true; + qemu_cpu_kick(cpu); + } } while (!all_vcpus_paused()) { @@ -1799,10 +1808,7 @@ void qemu_init_vcpu(CPUState *cpu) void cpu_stop_current(void) { if (current_cpu) { - current_cpu->stop = false; - current_cpu->stopped = true; - cpu_exit(current_cpu); - qemu_cond_broadcast(&qemu_pause_cond); + qemu_cpu_stop(current_cpu, true); } } From d84be02d69a23dea249f351324d497f613994129 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Wed, 29 Nov 2017 20:13:19 +0100 Subject: [PATCH 312/546] cpu-exec: fix missed CPU kick during interrupt injection The conditional memory barrier not only looks strange but actually is wrong. On s390x, I can reproduce interrupts via cpu_interrupt() not leading to a proper kick out of emulation every now and then. cpu_interrupt() is especially used for inter CPU communication via SIGP (esp. external calls and emergency interrupts). With this patch, I was not able to reproduce. (esp. no stalls or hangs in the guest). My setup is s390x MTTCG with 16 VCPUs on 8 CPU host, running make -j16. Signed-off-by: David Hildenbrand Message-Id: <20171129191319.11483-1-david@redhat.com> Signed-off-by: Paolo Bonzini --- accel/tcg/cpu-exec.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 9b544d88c8..4452cd9856 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -525,19 +525,13 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, TranslationBlock **last_tb) { CPUClass *cc = CPU_GET_CLASS(cpu); - int32_t insns_left; /* Clear the interrupt flag now since we're processing * cpu->interrupt_request and cpu->exit_request. + * Ensure zeroing happens before reading cpu->exit_request or + * cpu->interrupt_request (see also smp_wmb in cpu_exit()) */ - insns_left = atomic_read(&cpu->icount_decr.u32); - atomic_set(&cpu->icount_decr.u16.high, 0); - if (unlikely(insns_left < 0)) { - /* Ensure the zeroing of icount_decr comes before the next read - * of cpu->exit_request or cpu->interrupt_request. - */ - smp_mb(); - } + atomic_mb_set(&cpu->icount_decr.u16.high, 0); if (unlikely(atomic_read(&cpu->interrupt_request))) { int interrupt_request; From a4926d99129a1d8072fc4681cd4efdb214f65ed4 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 13 Nov 2017 07:48:45 +0100 Subject: [PATCH 313/546] target/i386: Fix compiler warnings These gcc warnings are fixed: target/i386/translate.c:4461:12: warning: variable 'prefixes' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered] target/i386/translate.c:4466:9: warning: variable 'rex_w' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered] target/i386/translate.c:4466:16: warning: variable 'rex_r' might be clobbered by 'longjmp' or 'vfork' [-Wclobbered] Tested with x86_64-w64-mingw32-gcc from Debian stretch. Signed-off-by: Stefan Weil Message-Id: <20171113064845.29142-1-sw@weilnetz.de> Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index 088a9d9766..f410938244 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -4467,10 +4467,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) target_ulong pc_start = s->base.pc_next; s->pc_start = s->pc = pc_start; - prefixes = 0; s->override = -1; - rex_w = -1; - rex_r = 0; #ifdef TARGET_X86_64 s->rex_x = 0; s->rex_b = 0; @@ -4484,6 +4481,10 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) return s->pc; } + prefixes = 0; + rex_w = -1; + rex_r = 0; + next_byte: b = x86_ldub_code(env, s); /* Collect prefixes. */ From 1ef7c96ee2133753f4aa48617ddbef10d5a88fc9 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 11 Dec 2017 01:19:50 +0100 Subject: [PATCH 314/546] baum: Truncate braille device size to 84x1 Baum device bigger than 84 do not actually exist, but the user's own Braille device might be wider than 84 columns. Some guest drivers would be upset by such sizes, so clamp the device size. Signed-off-by: Samuel Thibault Message-Id: <20171211001950.27843-1-samuel.thibault@ens-lyon.org> Signed-off-by: Paolo Bonzini --- chardev/baum.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/chardev/baum.c b/chardev/baum.c index 67fd783a59..78b0c87625 100644 --- a/chardev/baum.c +++ b/chardev/baum.c @@ -1,7 +1,7 @@ /* * QEMU Baum Braille Device * - * Copyright (c) 2008, 2010-2011, 2016 Samuel Thibault + * Copyright (c) 2008, 2010-2011, 2016-2017 Samuel Thibault * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -239,6 +239,12 @@ static int baum_deferred_init(BaumChardev *baum) brlapi_perror("baum: brlapi__getDisplaySize"); return 0; } + if (baum->y > 1) { + baum->y = 1; + } + if (baum->x > 84) { + baum->x = 84; + } con = qemu_console_lookup_by_index(0); if (con && qemu_console_is_graphic(con)) { From 62473511ecbabdf737ba9053845e3551099b04bc Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 12 Dec 2017 11:12:19 +0000 Subject: [PATCH 315/546] sockets: remove obsolete code that updated listen address When listening on unix/tcp sockets there was optional code that would update the original SocketAddress struct with the info about the actual address that was listened on. Since the conversion of everything to QIOChannelSocket, no remaining caller made use of this feature. It has been replaced with the ability to query the listen address after the fact using the function qio_channel_socket_get_local_address. This is a better model when the input address can result in listening on multiple distinct sockets. Signed-off-by: Daniel P. Berrange Reviewed-by: Peter Xu Message-Id: <20171212111219.32601-1-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- include/qemu/sockets.h | 2 +- qga/channel-posix.c | 2 +- util/qemu-sockets.c | 31 +++++-------------------------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 4f7311b52a..8889bcb1ec 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -35,7 +35,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp); NetworkAddressFamily inet_netfamily(int family); -int unix_listen(const char *path, char *ostr, int olen, Error **errp); +int unix_listen(const char *path, Error **errp); int unix_connect(const char *path, Error **errp); SocketAddress *socket_parse(const char *str, Error **errp); diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 3f34465159..b812bf4d51 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -190,7 +190,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, if (fd < 0) { Error *local_err = NULL; - fd = unix_listen(path, NULL, strlen(path), &local_err); + fd = unix_listen(path, &local_err); if (local_err != NULL) { g_critical("%s", error_get_pretty(local_err)); error_free(local_err); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index af4f01211a..d6a1e1759e 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -198,7 +198,6 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e) static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, - bool update_addr, Error **errp) { struct addrinfo ai,*res,*e; @@ -326,15 +325,6 @@ listen_failed: return -1; listen_ok: - if (update_addr) { - g_free(saddr->host); - saddr->host = g_strdup(uaddr); - g_free(saddr->port); - saddr->port = g_strdup_printf("%d", - inet_getport(e) - port_offset); - saddr->has_ipv6 = saddr->ipv6 = e->ai_family == PF_INET6; - saddr->has_ipv4 = saddr->ipv4 = e->ai_family != PF_INET6; - } freeaddrinfo(res); return slisten; } @@ -790,7 +780,6 @@ static int vsock_parse(VsockSocketAddress *addr, const char *str, #ifndef _WIN32 static int unix_listen_saddr(UnixSocketAddress *saddr, - bool update_addr, Error **errp) { struct sockaddr_un un; @@ -855,12 +844,7 @@ static int unix_listen_saddr(UnixSocketAddress *saddr, goto err; } - if (update_addr && pathbuf) { - g_free(saddr->path); - saddr->path = pathbuf; - } else { - g_free(pathbuf); - } + g_free(pathbuf); return sock; err: @@ -920,7 +904,6 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) #else static int unix_listen_saddr(UnixSocketAddress *saddr, - bool update_addr, Error **errp) { error_setg(errp, "unix sockets are not available on windows"); @@ -937,7 +920,7 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) #endif /* compatibility wrapper */ -int unix_listen(const char *str, char *ostr, int olen, Error **errp) +int unix_listen(const char *str, Error **errp) { char *path, *optstr; int sock, len; @@ -957,11 +940,7 @@ int unix_listen(const char *str, char *ostr, int olen, Error **errp) saddr->path = g_strdup(str); } - sock = unix_listen_saddr(saddr, true, errp); - - if (sock != -1 && ostr) { - snprintf(ostr, olen, "%s%s", saddr->path, optstr ? optstr : ""); - } + sock = unix_listen_saddr(saddr, errp); qapi_free_UnixSocketAddress(saddr); return sock; @@ -1052,11 +1031,11 @@ int socket_listen(SocketAddress *addr, Error **errp) switch (addr->type) { case SOCKET_ADDRESS_TYPE_INET: - fd = inet_listen_saddr(&addr->u.inet, 0, false, errp); + fd = inet_listen_saddr(&addr->u.inet, 0, errp); break; case SOCKET_ADDRESS_TYPE_UNIX: - fd = unix_listen_saddr(&addr->u.q_unix, false, errp); + fd = unix_listen_saddr(&addr->u.q_unix, errp); break; case SOCKET_ADDRESS_TYPE_FD: From cfcca361d77142f25fb1128755084cf91faa4db7 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 11:19:19 +0000 Subject: [PATCH 316/546] target/i386: Fix handling of VEX prefixes In commit e3af7c788b73a6495eb9d94992ef11f6ad6f3c56 we replaced direct calls to to cpu_ld*_code() with calls to the x86_ld*_code() wrappers which incorporate an advance of s->pc. Unfortunately we didn't notice that in one place the old code was deliberately not incrementing s->pc: @@ -4501,7 +4528,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) static const int pp_prefix[4] = { 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ }; - int vex3, vex2 = cpu_ldub_code(env, s->pc); + int vex3, vex2 = x86_ldub_code(env, s); if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) { /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b, This meant we were mishandling this set of instructions. Remove the manual advance of s->pc for the "is VEX" case (which is now done by x86_ldub_code()) and instead rewind PC in the case where we decide that this isn't really VEX. Signed-off-by: Peter Maydell Cc: qemu-stable@nongnu.org Reported-by: Alexandro Sanchez Bach Message-Id: <1513163959-17545-1-git-send-email-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- target/i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/translate.c b/target/i386/translate.c index f410938244..23d7eec964 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -4548,9 +4548,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) { /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b, otherwise the instruction is LES or LDS. */ + s->pc--; /* rewind the advance_pc() x86_ldub_code() did */ break; } - s->pc++; /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ From 92b540dac9fc3a572c7342edd0b073000f5a6abf Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Nov 2017 09:53:02 +0100 Subject: [PATCH 317/546] tests/boot-serial-test: Make sure that we check the timeout regularly If the guest continuesly writes characters to the UART, we never leave the inner while loop and thus never check whether we've reached the timeout value. So if we fail to find the expected string in the UART output, the test just hangs and never finishs. Use a counter to regularly break out of the while loop to check the timeout. Signed-off-by: Thomas Huth Message-Id: <1512031988-32490-2-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- tests/boot-serial-test.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index c935d69824..fa4183de29 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -43,12 +43,13 @@ static testdef_t tests[] = { static void check_guest_output(const testdef_t *test, int fd) { bool output_ok = false; - int i, nbr, pos = 0; + int i, nbr, pos = 0, ccnt; char ch; /* Poll serial output... Wait at most 60 seconds */ for (i = 0; i < 6000; ++i) { - while ((nbr = read(fd, &ch, 1)) == 1) { + ccnt = 0; + while ((nbr = read(fd, &ch, 1)) == 1 && ccnt++ < 512) { if (ch == test->expect[pos]) { pos += 1; if (test->expect[pos] == '\0') { From e12c08d3b67c4f4e5a16ee815188fc13632530ce Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Nov 2017 09:53:03 +0100 Subject: [PATCH 318/546] tests/boot-serial-test: Add code to allow to specify our own kernel or bios QEMU only ships with some few firmware images, i.e. we can currently run the boot-serial test only on a very limited set of machines. But writing some characters to the default UART of a machine can often be done with some few lines of assembly, so we add the possibility to the boot-serial tester to use its own mini-kernels or mini-firmwares. We write such images then into a file that we can load with the "-kernel" or "-bios" parameter when we launch QEMU. Signed-off-by: Thomas Huth Message-Id: <1512031988-32490-3-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- tests/boot-serial-test.c | 54 +++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index fa4183de29..d99726919e 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -7,9 +7,10 @@ * or later. See the COPYING file in the top-level directory. * * This test is used to check that the serial output of the firmware - * (that we provide for some machines) contains an expected string. - * Thus we check that the firmware still boots at least to a certain - * point and so we know that the machine is not completely broken. + * (that we provide for some machines) or some small mini-kernels that + * we provide here contains an expected string. Thus we check that the + * firmware/kernel still boots at least to a certain point and so we + * know that the machine is not completely broken. */ #include "qemu/osdep.h" @@ -20,6 +21,9 @@ typedef struct testdef { const char *machine; /* Name of the machine */ const char *extra; /* Additional parameters */ const char *expect; /* Expected string in the serial output */ + size_t codesize; /* Size of the kernel or bios data */ + const uint8_t *kernel; /* Set in case we use our own mini kernel */ + const uint8_t *bios; /* Set in case we use our own mini bios */ } testdef_t; static testdef_t tests[] = { @@ -72,26 +76,52 @@ done: static void test_machine(const void *data) { const testdef_t *test = data; - char tmpname[] = "/tmp/qtest-boot-serial-XXXXXX"; - int fd; + char serialtmp[] = "/tmp/qtest-boot-serial-sXXXXXX"; + char codetmp[] = "/tmp/qtest-boot-serial-cXXXXXX"; + const char *codeparam = ""; + const uint8_t *code = NULL; + int ser_fd; - fd = mkstemp(tmpname); - g_assert(fd != -1); + ser_fd = mkstemp(serialtmp); + g_assert(ser_fd != -1); + + if (test->kernel) { + code = test->kernel; + codeparam = "-kernel"; + } else if (test->bios) { + code = test->bios; + codeparam = "-bios"; + } + + if (code) { + ssize_t wlen; + int code_fd; + + code_fd = mkstemp(codetmp); + g_assert(code_fd != -1); + wlen = write(code_fd, code, test->codesize); + g_assert(wlen == test->codesize); + close(code_fd); + } /* * Make sure that this test uses tcg if available: It is used as a * fast-enough smoketest for that. */ - global_qtest = qtest_startf("-M %s,accel=tcg:kvm " + global_qtest = qtest_startf("%s %s -M %s,accel=tcg:kvm " "-chardev file,id=serial0,path=%s " "-no-shutdown -serial chardev:serial0 %s", - test->machine, tmpname, test->extra); - unlink(tmpname); + codeparam, code ? codetmp : "", + test->machine, serialtmp, test->extra); + unlink(serialtmp); + if (code) { + unlink(codetmp); + } - check_guest_output(test, fd); + check_guest_output(test, ser_fd); qtest_quit(global_qtest); - close(fd); + close(ser_fd); } int main(int argc, char *argv[]) From 7ce32f3005afef1feb6f6cd3a7e4f36a3ff300ab Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Nov 2017 09:53:06 +0100 Subject: [PATCH 319/546] hw/moxie/moxiesim: Add support for loading a BIOS on moxiesim The moxiesim machine already defines a memory region for a firmware, but does not provide the possibility to load an image via "-bios" yet. This will be needed for the boot-serial tester, so let's add support for "-bios" here now. Signed-off-by: Thomas Huth Message-Id: <1512031988-32490-6-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- hw/moxie/moxiesim.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c index 3c3ba9d8c5..6c200becab 100644 --- a/hw/moxie/moxiesim.c +++ b/hw/moxie/moxiesim.c @@ -25,6 +25,7 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qapi/error.h" #include "qemu-common.h" #include "cpu.h" @@ -40,6 +41,8 @@ #include "elf.h" #define PHYS_MEM_BASE 0x80000000 +#define FIRMWARE_BASE 0x1000 +#define FIRMWARE_SIZE (128 * 0x1000) typedef struct { uint64_t ram_size; @@ -122,8 +125,8 @@ static void moxiesim_init(MachineState *machine) memory_region_init_ram(ram, NULL, "moxiesim.ram", ram_size, &error_fatal); memory_region_add_subregion(address_space_mem, ram_base, ram); - memory_region_init_ram(rom, NULL, "moxie.rom", 128 * 0x1000, &error_fatal); - memory_region_add_subregion(get_system_memory(), 0x1000, rom); + memory_region_init_ram(rom, NULL, "moxie.rom", FIRMWARE_SIZE, &error_fatal); + memory_region_add_subregion(get_system_memory(), FIRMWARE_BASE, rom); if (kernel_filename) { loader_params.ram_size = ram_size; @@ -132,6 +135,11 @@ static void moxiesim_init(MachineState *machine) loader_params.initrd_filename = initrd_filename; load_kernel(cpu, &loader_params); } + if (bios_name) { + if (load_image_targphys(bios_name, FIRMWARE_BASE, FIRMWARE_SIZE) < 0) { + error_report("Failed to load firmware '%s'", bios_name); + } + } /* A single 16450 sits at offset 0x3f8. */ if (serial_hds[0]) { From 80ceb07a83375e3a0091591f96bd47bce2f640ce Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 23 Nov 2017 17:23:32 +0800 Subject: [PATCH 320/546] cpu: refactor cpu_address_space_init() Normally we create an address space for that CPU and pass that address space into the function. Let's just do it inside to unify address space creations. It'll simplify my next patch to rename those address spaces. Signed-off-by: Peter Xu Message-Id: <20171123092333.16085-3-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- cpus.c | 5 +---- exec.c | 7 ++++++- include/exec/exec-all.h | 6 ++++-- target/arm/cpu.c | 13 +++---------- target/i386/cpu.c | 10 ++-------- 5 files changed, 16 insertions(+), 25 deletions(-) diff --git a/cpus.c b/cpus.c index 3740c4db62..83700c1716 100644 --- a/cpus.c +++ b/cpus.c @@ -1787,11 +1787,8 @@ void qemu_init_vcpu(CPUState *cpu) /* If the target cpu hasn't set up any address spaces itself, * give it the default one. */ - AddressSpace *as = g_new0(AddressSpace, 1); - - address_space_init(as, cpu->memory, "cpu-memory"); cpu->num_ases = 1; - cpu_address_space_init(cpu, as, 0); + cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory); } if (kvm_enabled()) { diff --git a/exec.c b/exec.c index 3e7c57e914..3ab515e47c 100644 --- a/exec.c +++ b/exec.c @@ -705,9 +705,14 @@ CPUState *qemu_get_cpu(int index) } #if !defined(CONFIG_USER_ONLY) -void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx) +void cpu_address_space_init(CPUState *cpu, int asidx, + const char *prefix, MemoryRegion *mr) { CPUAddressSpace *newas; + AddressSpace *as = g_new0(AddressSpace, 1); + + assert(mr); + address_space_init(as, mr, prefix); /* Target code should have set num_ases before calling us */ assert(asidx < cpu->num_ases); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 0f51c92adb..b37f7d8d92 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -74,8 +74,9 @@ void cpu_reloading_memory_map(void); /** * cpu_address_space_init: * @cpu: CPU to add this address space to - * @as: address space to add * @asidx: integer index of this address space + * @prefix: prefix to be used as name of address space + * @mr: the root memory region of address space * * Add the specified address space to the CPU's cpu_ases list. * The address space added with @asidx 0 is the one used for the @@ -89,7 +90,8 @@ void cpu_reloading_memory_map(void); * * Note that with KVM only one address space is supported. */ -void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx); +void cpu_address_space_init(CPUState *cpu, int asidx, + const char *prefix, MemoryRegion *mr); #endif #if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7f7a3d1e32..cc1856c32b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -705,9 +705,6 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) CPUARMState *env = &cpu->env; int pagebits; Error *local_err = NULL; -#ifndef CONFIG_USER_ONLY - AddressSpace *as; -#endif cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { @@ -912,21 +909,17 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (cpu->has_el3 || arm_feature(env, ARM_FEATURE_M_SECURITY)) { - as = g_new0(AddressSpace, 1); - cs->num_ases = 2; if (!cpu->secure_memory) { cpu->secure_memory = cs->memory; } - address_space_init(as, cpu->secure_memory, "cpu-secure-memory"); - cpu_address_space_init(cs, as, ARMASIdx_S); + cpu_address_space_init(cs, ARMASIdx_S, "cpu-secure-memory", + cpu->secure_memory); } else { cs->num_ases = 1; } - as = g_new0(AddressSpace, 1); - address_space_init(as, cs->memory, "cpu-memory"); - cpu_address_space_init(cs, as, ARMASIdx_NS); + cpu_address_space_init(cs, ARMASIdx_NS, "cpu-memory", cs->memory); #endif qemu_init_vcpu(cs); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 325b52e325..b069eafcc6 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3736,11 +3736,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) #ifndef CONFIG_USER_ONLY if (tcg_enabled()) { - AddressSpace *as_normal = g_new0(AddressSpace, 1); - AddressSpace *as_smm = g_new(AddressSpace, 1); - - address_space_init(as_normal, cs->memory, "cpu-memory"); - cpu->cpu_as_mem = g_new(MemoryRegion, 1); cpu->cpu_as_root = g_new(MemoryRegion, 1); @@ -3755,11 +3750,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) get_system_memory(), 0, ~0ull); memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); memory_region_set_enabled(cpu->cpu_as_mem, true); - address_space_init(as_smm, cpu->cpu_as_root, "CPU"); cs->num_ases = 2; - cpu_address_space_init(cs, as_normal, 0); - cpu_address_space_init(cs, as_smm, 1); + cpu_address_space_init(cs, 0, "cpu-memory", cs->memory); + cpu_address_space_init(cs, 1, "cpu-smm", cpu->cpu_as_root); /* ... SMRAM with higher priority, linked from /machine/smram. */ cpu->machine_done.notify = x86_cpu_machine_done; From 87a621d857be1b2b3dd1d0847ca311a863dbcb53 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 23 Nov 2017 17:23:33 +0800 Subject: [PATCH 321/546] cpu: suffix cpu address spaces with cpu index Renaming cpu address space names so that they won't be the same when there are more than one. Signed-off-by: Peter Xu Message-Id: <20171123092333.16085-4-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- exec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 3ab515e47c..6b5828ee6e 100644 --- a/exec.c +++ b/exec.c @@ -710,9 +710,12 @@ void cpu_address_space_init(CPUState *cpu, int asidx, { CPUAddressSpace *newas; AddressSpace *as = g_new0(AddressSpace, 1); + char *as_name; assert(mr); - address_space_init(as, mr, prefix); + as_name = g_strdup_printf("%s-%d", prefix, cpu->cpu_index); + address_space_init(as, mr, as_name); + g_free(as_name); /* Target code should have set num_ases before calling us */ assert(asidx < cpu->num_ases); From aef172ffdc2f9c41d9cc043a55f1259e7c07e587 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 8 Dec 2017 12:51:07 +0100 Subject: [PATCH 322/546] block/iscsi: dont leave allocmap in an invalid state on UNMAP failure we forgot to set the allocmap to invalid if an UNMAP call fails. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Lieven Message-Id: <1512733868-9009-2-git-send-email-pl@kamp.de> Reviewed-by: Eric Blake Signed-off-by: Paolo Bonzini --- block/iscsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index 4683f3b244..c532ec79d1 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2,7 +2,7 @@ * QEMU Block driver for iSCSI images * * Copyright (c) 2010-2011 Ronnie Sahlberg - * Copyright (c) 2012-2016 Peter Lieven + * Copyright (c) 2012-2017 Peter Lieven * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1128,6 +1128,9 @@ retry: goto retry; } + iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, + bytes >> BDRV_SECTOR_BITS); + if (iTask.status == SCSI_STATUS_CHECK_CONDITION) { /* the target might fail with a check condition if it is not happy with the alignment of the UNMAP request @@ -1140,9 +1143,6 @@ retry: goto out_unlock; } - iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, - bytes >> BDRV_SECTOR_BITS); - out_unlock: qemu_mutex_unlock(&iscsilun->mutex); return r; From e38bc23454ef763deb4405ebdee6a1081aa00bc8 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Fri, 8 Dec 2017 12:51:08 +0100 Subject: [PATCH 323/546] block/iscsi: only report an iSCSI Failure if we don't handle it gracefully we currently report an "iSCSI Failure" in iscsi_co_generic_cb if the task hasn't completed with SCSI_STATUS_GOOD. However, we expect a failure in some cases and handle it gracefully. This is the case for misaligned UNMAPs and WRITESAME10/16 calls without UNMAP. In this case a failure in the logs can be quite misleading. While we are at it improve the logging to reveal which operation failed at what LBA. Signed-off-by: Peter Lieven Message-Id: <1512733868-9009-3-git-send-email-pl@kamp.de> Signed-off-by: Paolo Bonzini --- block/iscsi.c | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/block/iscsi.c b/block/iscsi.c index c532ec79d1..5c0a9e55b6 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -104,6 +104,7 @@ typedef struct IscsiTask { IscsiLun *iscsilun; QEMUTimer retry_timer; int err_code; + char *err_str; } IscsiTask; typedef struct IscsiAIOCB { @@ -265,7 +266,7 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status, } } iTask->err_code = iscsi_translate_sense(&task->sense); - error_report("iSCSI Failure: %s", iscsi_get_error(iscsi)); + iTask->err_str = g_strdup(iscsi_get_error(iscsi)); } out: @@ -629,6 +630,8 @@ retry: if (iTask.status != SCSI_STATUS_GOOD) { iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors); + error_report("iSCSI WRITE10/16 failed at lba %" PRIu64 ": %s", lba, + iTask.err_str); r = iTask.err_code; goto out_unlock; } @@ -637,6 +640,7 @@ retry: out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } @@ -651,10 +655,9 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, struct scsi_get_lba_status *lbas = NULL; struct scsi_lba_status_descriptor *lbasd = NULL; struct IscsiTask iTask; + uint64_t lba; int64_t ret; - iscsi_co_init_iscsitask(iscsilun, &iTask); - if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { ret = -EINVAL; goto out; @@ -670,11 +673,13 @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs, goto out; } + lba = sector_qemu2lun(sector_num, iscsilun); + + iscsi_co_init_iscsitask(iscsilun, &iTask); qemu_mutex_lock(&iscsilun->mutex); retry: if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun, - sector_qemu2lun(sector_num, iscsilun), - 8 + 16, iscsi_co_generic_cb, + lba, 8 + 16, iscsi_co_generic_cb, &iTask) == NULL) { ret = -ENOMEM; goto out_unlock; @@ -701,6 +706,8 @@ retry: * because the device is busy or the cmd is not * supported) we pretend all blocks are allocated * for backwards compatibility */ + error_report("iSCSI GET_LBA_STATUS failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); goto out_unlock; } @@ -738,6 +745,7 @@ retry: } out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); out: if (iTask.task != NULL) { scsi_free_scsi_task(iTask.task); @@ -756,6 +764,7 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs, struct IscsiTask iTask; uint64_t lba; uint32_t num_sectors; + int r = 0; if (!is_sector_request_lun_aligned(sector_num, nb_sectors, iscsilun)) { return -EINVAL; @@ -853,19 +862,23 @@ retry: iTask.complete = 0; goto retry; } - qemu_mutex_unlock(&iscsilun->mutex); if (iTask.status != SCSI_STATUS_GOOD) { - return iTask.err_code; + error_report("iSCSI READ10/16 failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); + r = iTask.err_code; } - return 0; + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; } static int coroutine_fn iscsi_co_flush(BlockDriverState *bs) { IscsiLun *iscsilun = bs->opaque; struct IscsiTask iTask; + int r = 0; iscsi_co_init_iscsitask(iscsilun, &iTask); qemu_mutex_lock(&iscsilun->mutex); @@ -892,13 +905,15 @@ retry: iTask.complete = 0; goto retry; } - qemu_mutex_unlock(&iscsilun->mutex); if (iTask.status != SCSI_STATUS_GOOD) { - return iTask.err_code; + error_report("iSCSI SYNCHRONIZECACHE10 failed: %s", iTask.err_str); + r = iTask.err_code; } - return 0; + qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); + return r; } #ifdef __linux__ @@ -1139,12 +1154,15 @@ retry: } if (iTask.status != SCSI_STATUS_GOOD) { + error_report("iSCSI UNMAP failed at lba %" PRIu64 ": %s", + list.lba, iTask.err_str); r = iTask.err_code; goto out_unlock; } out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } @@ -1241,6 +1259,8 @@ retry: if (iTask.status != SCSI_STATUS_GOOD) { iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS, bytes >> BDRV_SECTOR_BITS); + error_report("iSCSI WRITESAME10/16 failed at lba %" PRIu64 ": %s", + lba, iTask.err_str); r = iTask.err_code; goto out_unlock; } @@ -1255,6 +1275,7 @@ retry: out_unlock: qemu_mutex_unlock(&iscsilun->mutex); + g_free(iTask.err_str); return r; } From 8af36743c26372789b1c92606dd181b2a6d2ad53 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:52:28 +0000 Subject: [PATCH 324/546] exec: Don't reuse unassigned_mem_ops for io_mem_rom We set up the io_mem_rom special memory region using the unassigned_mem_ops structure; this is then used when a guest tries to write to ROM. This is incorrect, because the behaviour of unassigned memory may be different from that of ROM for writes. In particular, on some architectures writing to unassigned memory generates a guest exception, whereas writing to ROM is generally ignored. Use a special readonly_mem_ops for this purpose instead, so writes to ROM are ignored for all guest CPUs. Signed-off-by: Peter Maydell Message-Id: <1513187549-2435-2-git-send-email-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- exec.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 6b5828ee6e..4722e521d4 100644 --- a/exec.c +++ b/exec.c @@ -2725,6 +2725,37 @@ static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr) return phys_section_add(map, §ion); } +static void readonly_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + /* Ignore any write to ROM. */ +} + +static bool readonly_mem_accepts(void *opaque, hwaddr addr, + unsigned size, bool is_write) +{ + return is_write; +} + +/* This will only be used for writes, because reads are special cased + * to directly access the underlying host ram. + */ +static const MemoryRegionOps readonly_mem_ops = { + .write = readonly_mem_write, + .valid.accepts = readonly_mem_accepts, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + .unaligned = false, + }, +}; + MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index, MemTxAttrs attrs) { int asidx = cpu_asidx_from_attrs(cpu, attrs); @@ -2737,7 +2768,8 @@ MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index, MemTxAttrs attrs) static void io_mem_init(void) { - memory_region_init_io(&io_mem_rom, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX); + memory_region_init_io(&io_mem_rom, NULL, &readonly_mem_ops, + NULL, NULL, UINT64_MAX); memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL, NULL, UINT64_MAX); From 5fb3d632884cbc113d9d13b1c8b0c5f2a8c7bc0d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 13 Dec 2017 17:52:29 +0000 Subject: [PATCH 325/546] hw/mips/boston: Remove workaround for writes to ROM aborting Now that the memory system correctly handles writes to ROM for guest CPUs that may generate exceptions for decode errors, we can remove the workaround from the boston board. Signed-off-by: Peter Maydell Message-Id: <1513187549-2435-3-git-send-email-peter.maydell@linaro.org> Signed-off-by: Paolo Bonzini --- hw/mips/boston.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/hw/mips/boston.c b/hw/mips/boston.c index 1cb4b6aca2..fb23161b33 100644 --- a/hw/mips/boston.c +++ b/hw/mips/boston.c @@ -248,16 +248,6 @@ static const MemoryRegionOps boston_platreg_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void boston_flash_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ -} - -static const MemoryRegionOps boston_flash_ops = { - .write = boston_flash_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - static const TypeInfo boston_device = { .name = TYPE_MIPS_BOSTON, .parent = TYPE_SYS_BUS_DEVICE, @@ -481,8 +471,8 @@ static void boston_mach_init(MachineState *machine) sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s->cps), 0, 0, 1); flash = g_new(MemoryRegion, 1); - memory_region_init_rom_device_nomigrate(flash, NULL, &boston_flash_ops, s, - "boston.flash", 128 * M_BYTE, &err); + memory_region_init_rom_nomigrate(flash, NULL, + "boston.flash", 128 * M_BYTE, &err); memory_region_add_subregion_overlap(sys_mem, 0x18000000, flash, 0); ddr = g_new(MemoryRegion, 1); From 7299e1a411de99761a4260e44b4f1cf2e4e126ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 15 Dec 2017 00:43:55 -0300 Subject: [PATCH 326/546] hw/i386/vmport: replace fprintf() by trace events or LOG_UNIMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20171215034356.4449-2-f4bug@amsat.org> [Replace unknown command tracepoint with LOG_UNIMP, add generic tracepoint for vmport commands. - Paolo] Signed-off-by: Paolo Bonzini --- hw/i386/trace-events | 4 ++++ hw/i386/vmport.c | 14 +++++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/i386/trace-events b/hw/i386/trace-events index d43b4b6cd3..22d44648af 100644 --- a/hw/i386/trace-events +++ b/hw/i386/trace-events @@ -113,3 +113,7 @@ amdvi_mode_invalid(uint8_t level, uint64_t addr)"error: translation level 0x%"PR amdvi_page_fault(uint64_t addr) "error: page fault accessing guest physical address 0x%"PRIx64 amdvi_iotlb_hit(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "hit iotlb devid %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 amdvi_translation_result(uint8_t bus, uint8_t slot, uint8_t func, uint64_t addr, uint64_t txaddr) "devid: %02x:%02x.%x gpa 0x%"PRIx64" hpa 0x%"PRIx64 + +# hw/i386/vmport.c +vmport_register(unsigned char command, void *func, void *opaque) "command: 0x%02x func: %p opaque: %p" +vmport_command(unsigned char command) "command: 0x%02x" diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index eb880c6def..9b8c68806e 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -27,8 +27,7 @@ #include "hw/i386/pc.h" #include "sysemu/hw_accel.h" #include "hw/qdev.h" - -/* #define VMPORT_DEBUG */ +#include "trace.h" #define VMPORT_CMD_GETVERSION 0x0a #define VMPORT_CMD_GETRAMSIZE 0x14 @@ -54,6 +53,7 @@ void vmport_register(unsigned char command, VMPortReadFunc *func, void *opaque) return; } + trace_vmport_register(command, func, opaque); port_state->func[command] = func; port_state->opaque[command] = opaque; } @@ -76,13 +76,9 @@ static uint64_t vmport_ioport_read(void *opaque, hwaddr addr, } command = env->regs[R_ECX]; - if (command >= VMPORT_ENTRIES) { - return eax; - } - if (!s->func[command]) { -#ifdef VMPORT_DEBUG - fprintf(stderr, "vmport: unknown command %x\n", command); -#endif + trace_vmport_command(command); + if (command >= VMPORT_ENTRIES || !s->func[command]) { + qemu_log_mask(LOG_UNIMP, "vmport: unknown command %x\n", command); return eax; } From f68d98b21fa74155dc7c1fd212474379ac3c7531 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 27 Nov 2017 13:27:41 +0100 Subject: [PATCH 327/546] scsi: provide general-purpose functions to manage sense data Extract the common parts of scsi_sense_buf_to_errno, scsi_convert_sense and scsi_target_send_command's REQUEST SENSE handling into two new functions scsi_parse_sense_buf and scsi_build_sense_buf. Fix a bug in scsi_target_send_command along the way; the length was written in buf[10] rather than buf[7]. Reported-by: Dr. David Alan Gilbert Reviewed-by: Dr. David Alan Gilbert Fixes: b07fbce634 ("scsi-bus: correct responses for INQUIRY and REQUEST SENSE") Signed-off-by: Paolo Bonzini --- hw/scsi/scsi-bus.c | 16 +---- include/scsi/utils.h | 3 + scsi/utils.c | 139 +++++++++++++++++++++---------------------- 3 files changed, 72 insertions(+), 86 deletions(-) diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 977f7bce1f..965becf31f 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -540,20 +540,8 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf) if (req->lun != 0) { const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED); - if (fixed_sense) { - r->buf[0] = 0x70; - r->buf[2] = sense.key; - r->buf[10] = 10; - r->buf[12] = sense.asc; - r->buf[13] = sense.ascq; - r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN); - } else { - r->buf[0] = 0x72; - r->buf[1] = sense.key; - r->buf[2] = sense.asc; - r->buf[3] = sense.ascq; - r->len = 8; - } + r->len = scsi_build_sense_buf(r->buf, req->cmd.xfer, + sense, fixed_sense); } else { r->len = scsi_device_get_sense(r->req.dev, r->buf, MIN(req->cmd.xfer, r->buf_len), diff --git a/include/scsi/utils.h b/include/scsi/utils.h index eb07e474ee..4b705f5e0f 100644 --- a/include/scsi/utils.h +++ b/include/scsi/utils.h @@ -31,6 +31,9 @@ typedef struct SCSISense { } SCSISense; int scsi_build_sense(uint8_t *buf, SCSISense sense); +SCSISense scsi_parse_sense_buf(const uint8_t *in_buf, int in_len); +int scsi_build_sense_buf(uint8_t *buf, size_t max_size, SCSISense sense, + bool fixed_sense); /* * Predefined sense codes diff --git a/scsi/utils.c b/scsi/utils.c index e4182a9b09..61bc1a8e2b 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -96,15 +96,60 @@ int scsi_cdb_length(uint8_t *buf) return cdb_len; } +SCSISense scsi_parse_sense_buf(const uint8_t *in_buf, int in_len) +{ + bool fixed_in; + SCSISense sense; + + assert(in_len > 0); + fixed_in = (in_buf[0] & 2) == 0; + if (fixed_in) { + if (in_len < 14) { + return SENSE_CODE(IO_ERROR); + } + sense.key = in_buf[2]; + sense.asc = in_buf[12]; + sense.ascq = in_buf[13]; + } else { + if (in_len < 4) { + return SENSE_CODE(IO_ERROR); + } + sense.key = in_buf[1]; + sense.asc = in_buf[2]; + sense.ascq = in_buf[3]; + } + + return sense; +} + +int scsi_build_sense_buf(uint8_t *out_buf, size_t size, SCSISense sense, + bool fixed_sense) +{ + int len; + uint8_t buf[SCSI_SENSE_LEN] = { 0 }; + + if (fixed_sense) { + buf[0] = 0x70; + buf[2] = sense.key; + buf[7] = 10; + buf[12] = sense.asc; + buf[13] = sense.ascq; + len = 18; + } else { + buf[0] = 0x72; + buf[1] = sense.key; + buf[2] = sense.asc; + buf[3] = sense.ascq; + len = 8; + } + len = MIN(len, size); + memcpy(out_buf, buf, len); + return len; +} + int scsi_build_sense(uint8_t *buf, SCSISense sense) { - memset(buf, 0, 18); - buf[0] = 0x70; - buf[2] = sense.key; - buf[7] = 10; - buf[12] = sense.asc; - buf[13] = sense.ascq; - return 18; + return scsi_build_sense_buf(buf, SCSI_SENSE_LEN, sense, true); } /* @@ -274,52 +319,21 @@ const struct SCSISense sense_code_SPACE_ALLOC_FAILED = { int scsi_convert_sense(uint8_t *in_buf, int in_len, uint8_t *buf, int len, bool fixed) { - bool fixed_in; SCSISense sense; - if (!fixed && len < 8) { - return 0; + bool fixed_in; + + fixed_in = (in_buf[0] & 2) == 0; + if (in_len && fixed == fixed_in) { + memcpy(buf, in_buf, MIN(len, in_len)); + return MIN(len, in_len); } if (in_len == 0) { - sense.key = NO_SENSE; - sense.asc = 0; - sense.ascq = 0; + sense = SENSE_CODE(NO_SENSE); } else { - fixed_in = (in_buf[0] & 2) == 0; - - if (fixed == fixed_in) { - memcpy(buf, in_buf, MIN(len, in_len)); - return MIN(len, in_len); - } - - if (fixed_in) { - sense.key = in_buf[2]; - sense.asc = in_buf[12]; - sense.ascq = in_buf[13]; - } else { - sense.key = in_buf[1]; - sense.asc = in_buf[2]; - sense.ascq = in_buf[3]; - } - } - - memset(buf, 0, len); - if (fixed) { - /* Return fixed format sense buffer */ - buf[0] = 0x70; - buf[2] = sense.key; - buf[7] = 10; - buf[12] = sense.asc; - buf[13] = sense.ascq; - return MIN(len, SCSI_SENSE_LEN); - } else { - /* Return descriptor format sense buffer */ - buf[0] = 0x72; - buf[1] = sense.key; - buf[2] = sense.asc; - buf[3] = sense.ascq; - return 8; + sense = scsi_parse_sense_buf(in_buf, in_len); } + return scsi_build_sense_buf(buf, len, sense, fixed); } int scsi_sense_to_errno(int key, int asc, int ascq) @@ -366,34 +380,15 @@ int scsi_sense_to_errno(int key, int asc, int ascq) } } -int scsi_sense_buf_to_errno(const uint8_t *sense, size_t sense_size) +int scsi_sense_buf_to_errno(const uint8_t *in_buf, size_t in_len) { - int key, asc, ascq; - if (sense_size < 1) { + SCSISense sense; + if (in_len < 1) { return EIO; } - switch (sense[0]) { - case 0x70: /* Fixed format sense data. */ - if (sense_size < 14) { - return EIO; - } - key = sense[2] & 0xF; - asc = sense[12]; - ascq = sense[13]; - break; - case 0x72: /* Descriptor format sense data. */ - if (sense_size < 4) { - return EIO; - } - key = sense[1] & 0xF; - asc = sense[2]; - ascq = sense[3]; - break; - default: - return EIO; - break; - } - return scsi_sense_to_errno(key, asc, ascq); + + sense = scsi_parse_sense_buf(in_buf, in_len); + return scsi_sense_to_errno(sense.key, sense.asc, sense.ascq); } const char *scsi_command_name(uint8_t cmd) From 9661e208f8cc94f66176db6f069a0f8adef9478d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 27 Nov 2017 13:45:59 +0100 Subject: [PATCH 328/546] scsi: replace hex constants with #defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sense keys have nice #defines in scsi/constants.h, use them. Reported-by: Dr. David Alan Gilbert Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- scsi/utils.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scsi/utils.c b/scsi/utils.c index 61bc1a8e2b..ddae650a99 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -339,16 +339,16 @@ int scsi_convert_sense(uint8_t *in_buf, int in_len, int scsi_sense_to_errno(int key, int asc, int ascq) { switch (key) { - case 0x00: /* NO SENSE */ - case 0x01: /* RECOVERED ERROR */ - case 0x06: /* UNIT ATTENTION */ + case NO_SENSE: + case RECOVERED_ERROR: + case UNIT_ATTENTION: /* These sense keys are not errors */ return 0; - case 0x0b: /* COMMAND ABORTED */ + case ABORTED_COMMAND: /* COMMAND ABORTED */ return ECANCELED; - case 0x02: /* NOT READY */ - case 0x05: /* ILLEGAL REQUEST */ - case 0x07: /* DATA PROTECTION */ + case NOT_READY: + case ILLEGAL_REQUEST: + case DATA_PROTECT: /* Parse ASCQ */ break; default: From ed57c757961d4518717502f908373331cb48f261 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 Dec 2017 18:44:25 +0100 Subject: [PATCH 329/546] Remove legacy -no-kvm-pit option It's only printing a warning since QEMU v1.3.0, so nobody should use this anymore today. Let's get rid of this now. Signed-off-by: Thomas Huth Message-Id: <1513619065-31722-1-git-send-email-thuth@redhat.com> Signed-off-by: Paolo Bonzini --- qemu-doc.texi | 5 ----- qemu-options.hx | 3 --- vl.c | 4 ---- 3 files changed, 12 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 69e2953dc6..90bea7331d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2612,11 +2612,6 @@ synonym for setting ``-global kvm-pit.lost_tick_policy=discard''. The ``-no-kvm-irqchip'' argument is now a synonym for setting ``-machine kernel_irqchip=off''. -@subsection -no-kvm-pit (since 1.3.0) - -The ``-no-kvm-pit'' argument is ignored. It is no longer -possible to disable the KVM PIT directly. - @subsection -no-kvm (since 1.3.0) The ``-no-kvm'' argument is now a synonym for setting diff --git a/qemu-options.hx b/qemu-options.hx index b1e5781908..94647e21e3 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3927,9 +3927,6 @@ HXCOMM Deprecated by kvm-pit driver properties DEF("no-kvm-pit-reinjection", 0, QEMU_OPTION_no_kvm_pit_reinjection, "", QEMU_ARCH_I386) -HXCOMM Deprecated (ignored) -DEF("no-kvm-pit", 0, QEMU_OPTION_no_kvm_pit, "", QEMU_ARCH_I386) - HXCOMM Deprecated by -machine kernel_irqchip=on|off property DEF("no-kvm-irqchip", 0, QEMU_OPTION_no_kvm_irqchip, "", QEMU_ARCH_I386) diff --git a/vl.c b/vl.c index e9012bb009..d3a5c5d021 100644 --- a/vl.c +++ b/vl.c @@ -3817,10 +3817,6 @@ int main(int argc, char **argv, char **envp) olist = qemu_find_opts("machine"); qemu_opts_parse_noisily(olist, "accel=tcg", false); break; - case QEMU_OPTION_no_kvm_pit: { - warn_report("ignoring deprecated option"); - break; - } case QEMU_OPTION_no_kvm_pit_reinjection: { static GlobalProperty kvm_pit_lost_tick_policy = { .driver = "kvm-pit", From 0880a873007b51c06ab008366cbd5e510be15bad Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Sun, 10 Dec 2017 14:38:15 +0800 Subject: [PATCH 330/546] i8259: convert DPRINTFs into trace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One thing to mention is that in pic_set_irq() I need to uncomment a few lines in the macros to make sure IRQ value calculation is correct. Signed-off-by: Peter Xu Message-Id: <20171210063819.14892-2-peterx@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/intc/i8259.c | 26 +++++++++++--------------- hw/intc/trace-events | 7 +++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index fe9ecd6bd4..f12e0b27f1 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -30,17 +30,11 @@ #include "qemu/log.h" #include "hw/isa/i8259_internal.h" #include "hw/intc/intc.h" +#include "trace.h" /* debug PIC */ //#define DEBUG_PIC -#ifdef DEBUG_PIC -#define DPRINTF(fmt, ...) \ - do { printf("pic: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) -#endif - //#define DEBUG_IRQ_LATENCY //#define DEBUG_IRQ_COUNT @@ -122,8 +116,7 @@ static void pic_update_irq(PICCommonState *s) irq = pic_get_irq(s); if (irq >= 0) { - DPRINTF("pic%d: imr=%x irr=%x padd=%d\n", - s->master ? 0 : 1, s->imr, s->irr, s->priority_add); + trace_pic_update_irq(s->master, s->imr, s->irr, s->priority_add); qemu_irq_raise(s->int_out[0]); } else { qemu_irq_lower(s->int_out[0]); @@ -140,9 +133,11 @@ static void pic_set_irq(void *opaque, int irq, int level) defined(DEBUG_IRQ_LATENCY) int irq_index = s->master ? irq : irq + 8; #endif + + trace_pic_set_irq(s->master, irq, level); + #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq_index]) { - DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level); irq_level[irq_index] = level; #ifdef DEBUG_IRQ_COUNT if (level == 1) { @@ -223,18 +218,18 @@ int pic_read_irq(DeviceState *d) intno = s->irq_base + irq; } -#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY) if (irq == 2) { irq = irq2 + 8; } -#endif + #ifdef DEBUG_IRQ_LATENCY printf("IRQ%d latency=%0.3fus\n", irq, (double)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - irq_time[irq]) * 1000000.0 / NANOSECONDS_PER_SECOND); #endif - DPRINTF("pic_interrupt: irq=%d\n", irq); + + trace_pic_interrupt(irq, intno); return intno; } @@ -289,7 +284,8 @@ static void pic_ioport_write(void *opaque, hwaddr addr64, uint32_t val = val64; int priority, cmd, irq; - DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val); + trace_pic_ioport_write(s->master, addr, val); + if (addr == 0) { if (val & 0x10) { pic_init_reset(s); @@ -402,7 +398,7 @@ static uint64_t pic_ioport_read(void *opaque, hwaddr addr, ret = s->imr; } } - DPRINTF("read: addr=0x%02" HWADDR_PRIx " val=0x%02x\n", addr, ret); + trace_pic_ioport_read(s->master, addr, ret); return ret; } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 7077aaaee6..be769186fc 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -1,5 +1,12 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/intc/i8259.c +pic_update_irq(bool master, uint8_t imr, uint8_t irr, uint8_t padd) "master %d imr %"PRIu8" irr %"PRIu8" padd %"PRIu8 +pic_set_irq(bool master, int irq, int level) "master %d irq %d level %d" +pic_interrupt(int irq, int intno) "irq %d intno %d" +pic_ioport_write(bool master, uint64_t addr, uint64_t val) "master %d addr 0x%"PRIx64" val 0x%"PRIx64 +pic_ioport_read(bool master, uint64_t addr, int val) "master %d addr 0x%"PRIx64" val 0x%x" + # hw/intc/apic_common.c cpu_set_apic_base(uint64_t val) "0x%016"PRIx64 cpu_get_apic_base(uint64_t val) "0x%016"PRIx64 From f260f7361ca6caf7bb672195c50db99eff26b856 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Sun, 10 Dec 2017 14:38:16 +0800 Subject: [PATCH 331/546] i8259: use DEBUG_IRQ_COUNT always MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not really scary to even enable it forever. After all it's i8259, and it's even not the kernel one. Then we can remove quite a few of lines to make it cleaner. And "info irq" will always work for it. Signed-off-by: Peter Xu Message-Id: <20171210063819.14892-3-peterx@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/intc/i8259.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index f12e0b27f1..20c9d0a58b 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -36,7 +36,6 @@ //#define DEBUG_PIC //#define DEBUG_IRQ_LATENCY -//#define DEBUG_IRQ_COUNT #define TYPE_I8259 "isa-i8259" #define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259) @@ -52,12 +51,8 @@ typedef struct PICClass { DeviceRealize parent_realize; } PICClass; -#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) static int irq_level[16]; -#endif -#ifdef DEBUG_IRQ_COUNT static uint64_t irq_count[16]; -#endif #ifdef DEBUG_IRQ_LATENCY static int64_t irq_time[16]; #endif @@ -128,24 +123,17 @@ static void pic_set_irq(void *opaque, int irq, int level) { PICCommonState *s = opaque; int mask = 1 << irq; - -#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \ - defined(DEBUG_IRQ_LATENCY) int irq_index = s->master ? irq : irq + 8; -#endif trace_pic_set_irq(s->master, irq, level); -#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) if (level != irq_level[irq_index]) { irq_level[irq_index] = level; -#ifdef DEBUG_IRQ_COUNT if (level == 1) { irq_count[irq_index]++; } -#endif } -#endif + #ifdef DEBUG_IRQ_LATENCY if (level) { irq_time[irq_index] = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -253,12 +241,8 @@ static bool pic_get_statistics(InterruptStatsProvider *obj, PICCommonState *s = PIC_COMMON(obj); if (s->master) { -#ifdef DEBUG_IRQ_COUNT *irq_counts = irq_count; *nb_irqs = ARRAY_SIZE(irq_count); -#else - return false; -#endif } else { *irq_counts = NULL; *nb_irqs = 0; From 1b23190aba72a974c9a08496bf6d45e14b60087a Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Sun, 10 Dec 2017 14:38:17 +0800 Subject: [PATCH 332/546] i8259: generalize statistics into common code It was only for userspace i8259. Move it to general code so that kvm-i8259 can also use it in the future. Signed-off-by: Peter Xu Message-Id: <20171210063819.14892-4-peterx@redhat.com> Signed-off-by: Paolo Bonzini --- hw/intc/i8259.c | 37 +---------------------------- hw/intc/i8259_common.c | 41 +++++++++++++++++++++++++++++++++ include/hw/isa/i8259_internal.h | 7 ++++-- 3 files changed, 47 insertions(+), 38 deletions(-) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 20c9d0a58b..d9b9666aff 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -25,11 +25,9 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/isa/isa.h" -#include "monitor/monitor.h" #include "qemu/timer.h" #include "qemu/log.h" #include "hw/isa/i8259_internal.h" -#include "hw/intc/intc.h" #include "trace.h" /* debug PIC */ @@ -51,8 +49,6 @@ typedef struct PICClass { DeviceRealize parent_realize; } PICClass; -static int irq_level[16]; -static uint64_t irq_count[16]; #ifdef DEBUG_IRQ_LATENCY static int64_t irq_time[16]; #endif @@ -126,13 +122,7 @@ static void pic_set_irq(void *opaque, int irq, int level) int irq_index = s->master ? irq : irq + 8; trace_pic_set_irq(s->master, irq, level); - - if (level != irq_level[irq_index]) { - irq_level[irq_index] = level; - if (level == 1) { - irq_count[irq_index]++; - } - } + pic_stat_update_irq(irq_index, level); #ifdef DEBUG_IRQ_LATENCY if (level) { @@ -235,31 +225,6 @@ static void pic_reset(DeviceState *dev) pic_init_reset(s); } -static bool pic_get_statistics(InterruptStatsProvider *obj, - uint64_t **irq_counts, unsigned int *nb_irqs) -{ - PICCommonState *s = PIC_COMMON(obj); - - if (s->master) { - *irq_counts = irq_count; - *nb_irqs = ARRAY_SIZE(irq_count); - } else { - *irq_counts = NULL; - *nb_irqs = 0; - } - return true; -} - -static void pic_print_info(InterruptStatsProvider *obj, Monitor *mon) -{ - PICCommonState *s = PIC_COMMON(obj); - monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " - "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", - s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr, - s->special_fully_nested_mode); -} - static void pic_ioport_write(void *opaque, hwaddr addr64, uint64_t val64, unsigned size) { diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 18427b459a..a3caddeefb 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -25,6 +25,10 @@ #include "qemu/osdep.h" #include "hw/i386/pc.h" #include "hw/isa/i8259_internal.h" +#include "monitor/monitor.h" + +static int irq_level[16]; +static uint64_t irq_count[16]; void pic_reset_common(PICCommonState *s) { @@ -98,6 +102,43 @@ ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master) return isadev; } +void pic_stat_update_irq(int irq, int level) +{ + if (level != irq_level[irq]) { + irq_level[irq] = level; + if (level == 1) { + irq_count[irq]++; + } + } +} + +bool pic_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + PICCommonState *s = PIC_COMMON(obj); + + if (s->master) { + *irq_counts = irq_count; + *nb_irqs = ARRAY_SIZE(irq_count); + } else { + *irq_counts = NULL; + *nb_irqs = 0; + } + + return true; +} + +void pic_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + PICCommonState *s = PIC_COMMON(obj); + + monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " + "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", + s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add, + s->irq_base, s->read_reg_select, s->elcr, + s->special_fully_nested_mode); +} + static const VMStateDescription vmstate_pic_common = { .name = "i8259", .version_id = 1, diff --git a/include/hw/isa/i8259_internal.h b/include/hw/isa/i8259_internal.h index 6954b6ec5f..f742c2a726 100644 --- a/include/hw/isa/i8259_internal.h +++ b/include/hw/isa/i8259_internal.h @@ -28,6 +28,7 @@ #include "hw/hw.h" #include "hw/i386/pc.h" #include "hw/isa/isa.h" +#include "hw/intc/intc.h" typedef struct PICCommonState PICCommonState; @@ -76,8 +77,10 @@ struct PICCommonState { }; void pic_reset_common(PICCommonState *s); - ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master); - +void pic_stat_update_irq(int irq, int level); +bool pic_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs); +void pic_print_info(InterruptStatsProvider *obj, Monitor *mon); #endif /* QEMU_I8259_INTERNAL_H */ From e267d16496e3998f271767a80ff9b0cc43be8a35 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Sun, 10 Dec 2017 14:38:18 +0800 Subject: [PATCH 333/546] kvm-i8259: support "info pic" and "info irq" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's leverage the i8259 common code for kvm-i8259 too. I think it's still possible that stats can lost when i8259 is in kernel and meanwhile when irqfd is used, e.g., by vfio or vhost devices. However that should be rare IMHO since they should be using MSIs mostly if they really want performance (that's why people use vhost and device assignment), and no old INTx should be used. As long as the INTx users are emulated in QEMU the stats will be correct. For "info pic", it should be always accurate since we fetch kvm regs before dump. More importantly, it's just too simple to do this now - it's only 10+ LOC to gain this feature. Signed-off-by: Peter Xu Message-Id: <20171210063819.14892-5-peterx@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/i386/kvm/i8259.c | 8 ++++++++ hw/intc/i8259_common.c | 1 + 2 files changed, 9 insertions(+) diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index 11d1b726b6..57abe091b0 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -111,6 +111,7 @@ static void kvm_pic_set_irq(void *opaque, int irq, int level) { int delivered; + pic_stat_update_irq(irq, level); delivered = kvm_set_irq(kvm_state, irq, level); apic_report_irq_delivered(delivered); } @@ -139,12 +140,15 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) KVMPICClass *kpc = KVM_PIC_CLASS(klass); PICCommonClass *k = PIC_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = kvm_pic_reset; kpc->parent_realize = dc->realize; dc->realize = kvm_pic_realize; k->pre_save = kvm_pic_get; k->post_load = kvm_pic_put; + ic->get_statistics = pic_get_statistics; + ic->print_info = pic_print_info; } static const TypeInfo kvm_i8259_info = { @@ -153,6 +157,10 @@ static const TypeInfo kvm_i8259_info = { .instance_size = sizeof(PICCommonState), .class_init = kvm_i8259_class_init, .class_size = sizeof(KVMPICClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void kvm_pic_register_types(void) diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index a3caddeefb..7efd2e8012 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -132,6 +132,7 @@ void pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { PICCommonState *s = PIC_COMMON(obj); + pic_dispatch_pre_save(s); monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d " "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", s->master ? 0 : 1, s->irr, s->imr, s->isr, s->priority_add, From b8c7723440324a7822acdb0b6f35c7ccb791862a Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Sun, 10 Dec 2017 14:38:19 +0800 Subject: [PATCH 334/546] i8259: move TYPE_INTERRUPT_STATS_PROVIDER upper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now both classes (i8259, i8259-kvm) support this. Move this upper to the common class code. Signed-off-by: Peter Xu Message-Id: <20171210063819.14892-6-peterx@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- hw/i386/kvm/i8259.c | 7 ------- hw/intc/i8259.c | 7 ------- hw/intc/i8259_common.c | 7 +++++++ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index 57abe091b0..b91e98074e 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -140,15 +140,12 @@ static void kvm_i8259_class_init(ObjectClass *klass, void *data) KVMPICClass *kpc = KVM_PIC_CLASS(klass); PICCommonClass *k = PIC_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->reset = kvm_pic_reset; kpc->parent_realize = dc->realize; dc->realize = kvm_pic_realize; k->pre_save = kvm_pic_get; k->post_load = kvm_pic_put; - ic->get_statistics = pic_get_statistics; - ic->print_info = pic_print_info; } static const TypeInfo kvm_i8259_info = { @@ -157,10 +154,6 @@ static const TypeInfo kvm_i8259_info = { .instance_size = sizeof(PICCommonState), .class_init = kvm_i8259_class_init, .class_size = sizeof(KVMPICClass), - .interfaces = (InterfaceInfo[]) { - { TYPE_INTERRUPT_STATS_PROVIDER }, - { } - }, }; static void kvm_pic_register_types(void) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index d9b9666aff..1602255a87 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -442,13 +442,10 @@ static void i8259_class_init(ObjectClass *klass, void *data) { PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); - InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); k->parent_realize = dc->realize; dc->realize = pic_realize; dc->reset = pic_reset; - ic->get_statistics = pic_get_statistics; - ic->print_info = pic_print_info; } static const TypeInfo i8259_info = { @@ -457,10 +454,6 @@ static const TypeInfo i8259_info = { .parent = TYPE_PIC_COMMON, .class_init = i8259_class_init, .class_size = sizeof(PICClass), - .interfaces = (InterfaceInfo[]) { - { TYPE_INTERRUPT_STATS_PROVIDER }, - { } - }, }; static void pic_register_types(void) diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 7efd2e8012..c75c880157 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -178,6 +178,7 @@ static Property pic_properties_common[] = { static void pic_common_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); dc->vmsd = &vmstate_pic_common; dc->props = pic_properties_common; @@ -189,6 +190,8 @@ static void pic_common_class_init(ObjectClass *klass, void *data) * code. */ dc->user_creatable = false; + ic->get_statistics = pic_get_statistics; + ic->print_info = pic_print_info; } static const TypeInfo pic_common_type = { @@ -198,6 +201,10 @@ static const TypeInfo pic_common_type = { .class_size = sizeof(PICCommonClass), .class_init = pic_common_class_init, .abstract = true, + .interfaces = (InterfaceInfo[]) { + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, }; static void pic_common_register_types(void) From 6b012d2311e5ba0a952c2dcfe4327a73353c9fdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 15 Dec 2017 19:18:10 +0100 Subject: [PATCH 335/546] checkpatch: volatile with a comment or sig_atomic_t is okay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This assumes that the comment gives some justification; "volatile sig_atomic_t" is also self-explanatory and usually correct. Discussed in: '[Qemu-devel] [PATCH] dump-guest-memory.py: fix "You can't do that without a process to debug"' Suggested-by: Fam Zheng Signed-off-by: Marc-André Lureau Message-Id: <20171215181810.4122-1-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- scripts/checkpatch.pl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 34df753571..3dc27d9656 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2475,8 +2475,11 @@ sub process { # no volatiles please my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; - if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { - ERROR("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/ && + $line !~ /sig_atomic_t/ && + !ctx_has_comment($first_line, $linenr)) { + my $msg = "Use of volatile is usually wrong, please add a comment\n" . $herecurr; + ERROR($msg); } # warn about #if 0 From 5a22ab71623c0fb709d49df353bdf2ec7c445c4c Mon Sep 17 00:00:00 2001 From: Yang Zhong Date: Wed, 20 Dec 2017 21:16:46 +0800 Subject: [PATCH 336/546] rcu: reduce more than 7MB heap memory by malloc_trim() Since there are some issues in memory alloc/free machenism in glibc for little chunk memory, if Qemu frequently alloc/free little chunk memory, the glibc doesn't alloc little chunk memory from free list of glibc and still allocate from OS, which make the heap size bigger and bigger. This patch introduce malloc_trim(), which will free heap memory when there is no rcu call during rcu thread loop. malloc_trim() can be enabled/disabled by --enable-malloc-trim/ --disable-malloc-trim in the Qemu configure command. The default malloc_trim() is enabled for libc. Below are test results from smaps file. (1)without patch 55f0783e1000-55f07992a000 rw-p 00000000 00:00 0 [heap] Size: 21796 kB Rss: 14260 kB Pss: 14260 kB (2)with patch 55cc5fadf000-55cc61008000 rw-p 00000000 00:00 0 [heap] Size: 21668 kB Rss: 6940 kB Pss: 6940 kB Signed-off-by: Yang Zhong Message-Id: <1513775806-19779-1-git-send-email-yang.zhong@intel.com> Signed-off-by: Paolo Bonzini --- configure | 35 +++++++++++++++++++++++++++++++++++ util/rcu.c | 6 ++++++ 2 files changed, 41 insertions(+) diff --git a/configure b/configure index 99ccc1725a..100309c33f 100755 --- a/configure +++ b/configure @@ -426,6 +426,7 @@ vxhs="" supported_cpu="no" supported_os="no" bogus_os="no" +malloc_trim="" # parse CC options first for opt do @@ -1047,6 +1048,10 @@ for opt do ;; --enable-tcg) tcg="yes" ;; + --disable-malloc-trim) malloc_trim="no" + ;; + --enable-malloc-trim) malloc_trim="yes" + ;; --disable-spice) spice="no" ;; --enable-spice) spice="yes" @@ -1466,6 +1471,7 @@ Advanced options (experts only): Default:trace- --disable-slirp disable SLIRP userspace network connectivity --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI) + --enable-malloc-trim enable libc malloc_trim() for memory optimization --oss-lib path to OSS library --cpu=CPU Build for host CPU [$cpu] --with-coroutine=BACKEND coroutine backend. Supported options: @@ -3860,6 +3866,30 @@ if test "$tcmalloc" = "yes" && test "$jemalloc" = "yes" ; then exit 1 fi +# Even if malloc_trim() is available, these non-libc memory allocators +# do not support it. +if test "$tcmalloc" = "yes" || test "$jemalloc" = "yes" ; then + if test "$malloc_trim" = "yes" ; then + echo "Disabling malloc_trim with non-libc memory allocator" + fi + malloc_trim="no" +fi + +####################################### +# malloc_trim + +if test "$malloc_trim" != "no" ; then + cat > $TMPC << EOF +#include +int main(void) { malloc_trim(0); return 0; } +EOF + if compile_prog "" "" ; then + malloc_trim="yes" + else + malloc_trim="no" + fi +fi + ########################################## # tcmalloc probe @@ -5505,6 +5535,7 @@ if test "$tcg" = "yes" ; then echo "TCG debug enabled $debug_tcg" echo "TCG interpreter $tcg_interpreter" fi +echo "malloc trim support $malloc_trim" echo "RDMA support $rdma" echo "fdt support $fdt" echo "preadv support $preadv" @@ -6015,6 +6046,10 @@ if test "$opengl" = "yes" ; then fi fi +if test "$malloc_trim" = "yes" ; then + echo "CONFIG_MALLOC_TRIM=y" >> $config_host_mak +fi + if test "$avx2_opt" = "yes" ; then echo "CONFIG_AVX2_OPT=y" >> $config_host_mak fi diff --git a/util/rcu.c b/util/rcu.c index ca5a63e36a..f4d09c8304 100644 --- a/util/rcu.c +++ b/util/rcu.c @@ -32,6 +32,9 @@ #include "qemu/atomic.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#if defined(CONFIG_MALLOC_TRIM) +#include +#endif /* * Global grace period counter. Bit 0 is always one in rcu_gp_ctr. @@ -246,6 +249,9 @@ static void *call_rcu_thread(void *opaque) qemu_event_reset(&rcu_call_ready_event); n = atomic_read(&rcu_call_count); if (n == 0) { +#if defined(CONFIG_MALLOC_TRIM) + malloc_trim(4 * 1024 * 1024); +#endif qemu_event_wait(&rcu_call_ready_event); } } From d09c4a47874f30820b08c39ad39bcca9b8cde084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 3 Nov 2017 16:28:23 +0100 Subject: [PATCH 337/546] chardev: fix backend events regression with mux chardev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kirill noticied that on recent versions on QEMU he was not able to trigger SysRq to invoke debug capabilites of Linux Kernel. He tracked it down to qemu_chr_be_event() ignoring CHR_EVENT_BREAK due s->be being NULL. The bug was introduced in 2.8, commit a4afa548fc6d ("char: move front end handlers in CharBackend"). Since the commit, the qemu_chr_be_event() failed to deliver CHR_EVENT_BREAK due to qemu_chr_fe_init() does not set s->be in case of mux. Let's fix this by teaching mux to send an event to the frontend with the focus. Reported-by: Kirill A. Shutemov Signed-off-by: Marc-André Lureau Fixes: a4afa548fc6d ("char: move front end handlers in CharBackend") Message-Id: <20171103152824.21948-2-marcandre.lureau@redhat.com> Tested-by: Kirill A. Shutemov Signed-off-by: Paolo Bonzini --- chardev/char-mux.c | 10 ++++++++++ chardev/char.c | 18 ++++++++++++------ include/chardev/char.h | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/chardev/char-mux.c b/chardev/char-mux.c index 4cda5e7458..567bf965cd 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -123,6 +123,15 @@ static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event) } } +static void mux_chr_be_event(Chardev *chr, int event) +{ + MuxChardev *d = MUX_CHARDEV(chr); + + if (d->focus != -1) { + mux_chr_send_event(d, d->focus, event); + } +} + static int mux_proc_byte(Chardev *chr, MuxChardev *d, int ch) { if (d->term_got_escape) { @@ -346,6 +355,7 @@ static void char_mux_class_init(ObjectClass *oc, void *data) cc->chr_write = mux_chr_write; cc->chr_accept_input = mux_chr_accept_input; cc->chr_add_watch = mux_chr_add_watch; + cc->chr_be_event = mux_chr_be_event; } static const TypeInfo char_mux_type_info = { diff --git a/chardev/char.c b/chardev/char.c index 2ae4f465ec..8c3765ee99 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -43,10 +43,19 @@ static Object *get_chardevs_root(void) return container_get(object_get_root(), "/chardevs"); } -void qemu_chr_be_event(Chardev *s, int event) +static void chr_be_event(Chardev *s, int event) { CharBackend *be = s->be; + if (!be || !be->chr_event) { + return; + } + + be->chr_event(be->opaque, event); +} + +void qemu_chr_be_event(Chardev *s, int event) +{ /* Keep track if the char device is open */ switch (event) { case CHR_EVENT_OPENED: @@ -57,11 +66,7 @@ void qemu_chr_be_event(Chardev *s, int event) break; } - if (!be || !be->chr_event) { - return; - } - - be->chr_event(be->opaque, event); + CHARDEV_GET_CLASS(s)->chr_be_event(s, event); } /* Not reporting errors from writing to logfile, as logs are @@ -244,6 +249,7 @@ static void char_class_init(ObjectClass *oc, void *data) ChardevClass *cc = CHARDEV_CLASS(oc); cc->chr_write = null_chr_write; + cc->chr_be_event = chr_be_event; } static void char_finalize(Object *obj) diff --git a/include/chardev/char.h b/include/chardev/char.h index 43aabccef5..778d610295 100644 --- a/include/chardev/char.h +++ b/include/chardev/char.h @@ -248,6 +248,7 @@ typedef struct ChardevClass { void (*chr_accept_input)(Chardev *chr); void (*chr_set_echo)(Chardev *chr, bool echo); void (*chr_set_fe_open)(Chardev *chr, int fe_open); + void (*chr_be_event)(Chardev *s, int event); } ChardevClass; Chardev *qemu_chardev_new(const char *id, const char *typename, From d45f80ba82f281a35168011125cf6664cd217c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 3 Nov 2017 16:28:24 +0100 Subject: [PATCH 338/546] test: add some chardev mux event tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the expected behaviour of qemu_chr_be_event() on a mux chardev. For some reason, sending the event on the base chardev broadcast to all frontends, while sending it on the mux chardev itself should trigger the event on the currently focused chardev frontend. Signed-off-by: Marc-André Lureau Message-Id: <20171103152824.21948-3-marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini --- tests/test-char.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test-char.c b/tests/test-char.c index 7ac25ff73f..911e3f6e8d 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -5,6 +5,7 @@ #include "qemu/config-file.h" #include "qemu/sockets.h" #include "chardev/char-fe.h" +#include "chardev/char-mux.h" #include "sysemu/sysemu.h" #include "qapi/error.h" #include "qom/qom-qobject.h" @@ -164,6 +165,7 @@ static void char_mux_test(void) FeHandler h1 = { 0, }, h2 = { 0, }; CharBackend chr_be1, chr_be2; + muxes_realized = true; /* done after machine init */ opts = qemu_opts_create(qemu_find_opts("chardev"), "mux-label", 1, &error_abort); qemu_opt_set(opts, "backend", "ringbuf", &error_abort); @@ -201,8 +203,23 @@ static void char_mux_test(void) g_assert_cmpstr(h2.read_buf, ==, "hello"); h2.read_count = 0; + g_assert_cmpint(h1.last_event, !=, 42); /* should be MUX_OUT or OPENED */ + g_assert_cmpint(h2.last_event, !=, 42); /* should be MUX_IN or OPENED */ + /* sending event on the base broadcast to all fe, historical reasons? */ + qemu_chr_be_event(base, 42); + g_assert_cmpint(h1.last_event, ==, 42); + g_assert_cmpint(h2.last_event, ==, 42); + qemu_chr_be_event(chr, -1); + g_assert_cmpint(h1.last_event, ==, 42); + g_assert_cmpint(h2.last_event, ==, -1); + /* switch focus */ qemu_chr_be_write(base, (void *)"\1c", 2); + g_assert_cmpint(h1.last_event, ==, CHR_EVENT_MUX_IN); + g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); + qemu_chr_be_event(chr, -1); + g_assert_cmpint(h1.last_event, ==, -1); + g_assert_cmpint(h2.last_event, ==, CHR_EVENT_MUX_OUT); qemu_chr_be_write(base, (void *)"hello", 6); g_assert_cmpint(h2.read_count, ==, 0); From 862172f45c38fb6c446cc8db8c9a3f5a9be1dee7 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 18 Dec 2017 10:16:42 +0000 Subject: [PATCH 339/546] blockdev: convert internal NBD server to QIONetListener Instead of creating a QIOChannelSocket directly for the NBD server socket, use a QIONetListener. This provides the ability to listen on multiple sockets at the same time, so enables full support for IPv4/IPv6 dual stack. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-Id: <20171218101643.20360-2-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- blockdev-nbd.c | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index 28f551a7b0..9e3c22109c 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -18,10 +18,10 @@ #include "qmp-commands.h" #include "block/nbd.h" #include "io/channel-socket.h" +#include "io/net-listener.h" typedef struct NBDServerData { - QIOChannelSocket *listen_ioc; - int watch; + QIONetListener *listener; QCryptoTLSCreds *tlscreds; } NBDServerData; @@ -32,27 +32,13 @@ static void nbd_blockdev_client_closed(NBDClient *client, bool ignored) nbd_client_put(client); } -static gboolean nbd_accept(QIOChannel *ioc, GIOCondition condition, - gpointer opaque) +static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + gpointer opaque) { - QIOChannelSocket *cioc; - - if (!nbd_server) { - return FALSE; - } - - cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), - NULL); - if (!cioc) { - return TRUE; - } - qio_channel_set_name(QIO_CHANNEL(cioc), "nbd-server"); nbd_client_new(NULL, cioc, nbd_server->tlscreds, NULL, nbd_blockdev_client_closed); - object_unref(OBJECT(cioc)); - return TRUE; } @@ -62,10 +48,8 @@ static void nbd_server_free(NBDServerData *server) return; } - if (server->watch != -1) { - g_source_remove(server->watch); - } - object_unref(OBJECT(server->listen_ioc)); + qio_net_listener_disconnect(server->listener); + object_unref(OBJECT(server->listener)); if (server->tlscreds) { object_unref(OBJECT(server->tlscreds)); } @@ -112,12 +96,12 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, } nbd_server = g_new0(NBDServerData, 1); - nbd_server->watch = -1; - nbd_server->listen_ioc = qio_channel_socket_new(); - qio_channel_set_name(QIO_CHANNEL(nbd_server->listen_ioc), - "nbd-listener"); - if (qio_channel_socket_listen_sync( - nbd_server->listen_ioc, addr, errp) < 0) { + nbd_server->listener = qio_net_listener_new(); + + qio_net_listener_set_name(nbd_server->listener, + "nbd-listener"); + + if (qio_net_listener_open_sync(nbd_server->listener, addr, errp) < 0) { goto error; } @@ -134,12 +118,10 @@ void nbd_server_start(SocketAddress *addr, const char *tls_creds, } } - nbd_server->watch = qio_channel_add_watch( - QIO_CHANNEL(nbd_server->listen_ioc), - G_IO_IN, - nbd_accept, - NULL, - NULL); + qio_net_listener_set_client_func(nbd_server->listener, + nbd_accept, + NULL, + NULL); return; From e4849c1d7cd4472ff4e747a6bcc1994a6e370307 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 18 Dec 2017 10:16:43 +0000 Subject: [PATCH 340/546] blockdev: convert qemu-nbd server to QIONetListener Instead of creating a QIOChannelSocket directly for the NBD server socket, use a QIONetListener. This provides the ability to listen on multiple sockets at the same time, so enables full support for IPv4/IPv6 dual stack. This also means we can honour multiple FDs received during socket activation. Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange Message-Id: <20171218101643.20360-3-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- qemu-nbd.c | 61 +++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/qemu-nbd.c b/qemu-nbd.c index d75ca51482..3723493be1 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -37,6 +37,7 @@ #include "qapi/qmp/qstring.h" #include "qom/object_interfaces.h" #include "io/channel-socket.h" +#include "io/net-listener.h" #include "crypto/init.h" #include "trace/control.h" #include "qemu-version.h" @@ -62,8 +63,7 @@ static int persistent = 0; static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state; static int shared = 1; static int nb_fds; -static QIOChannelSocket *server_ioc; -static int server_watch = -1; +static QIONetListener *server; static QCryptoTLSCreds *tlscreds; static void usage(const char *name) @@ -344,44 +344,25 @@ static void nbd_client_closed(NBDClient *client, bool negotiated) nbd_client_put(client); } -static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque) +static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc, + gpointer opaque) { - QIOChannelSocket *cioc; - - cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), - NULL); - if (!cioc) { - return TRUE; - } - if (state >= TERMINATE) { - object_unref(OBJECT(cioc)); - return TRUE; + return; } nb_fds++; nbd_update_server_watch(); nbd_client_new(newproto ? NULL : exp, cioc, tlscreds, NULL, nbd_client_closed); - object_unref(OBJECT(cioc)); - - return TRUE; } static void nbd_update_server_watch(void) { if (nbd_can_accept()) { - if (server_watch == -1) { - server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc), - G_IO_IN, - nbd_accept, - NULL, NULL); - } + qio_net_listener_set_client_func(server, nbd_accept, NULL, NULL); } else { - if (server_watch != -1) { - g_source_remove(server_watch); - server_watch = -1; - } + qio_net_listener_set_client_func(server, NULL, NULL, NULL); } } @@ -915,23 +896,29 @@ int main(int argc, char **argv) snprintf(sockpath, 128, SOCKET_PATH, basename(device)); } + server = qio_net_listener_new(); if (socket_activation == 0) { - server_ioc = qio_channel_socket_new(); saddr = nbd_build_socket_address(sockpath, bindto, port); - if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) { - object_unref(OBJECT(server_ioc)); + if (qio_net_listener_open_sync(server, saddr, &local_err) < 0) { + object_unref(OBJECT(server)); error_report_err(local_err); - return 1; + exit(EXIT_FAILURE); } } else { + size_t i; /* See comment in check_socket_activation above. */ - assert(socket_activation == 1); - server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, - &local_err); - if (server_ioc == NULL) { - error_report("Failed to use socket activation: %s", - error_get_pretty(local_err)); - exit(EXIT_FAILURE); + for (i = 0; i < socket_activation; i++) { + QIOChannelSocket *sioc; + sioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD + i, + &local_err); + if (sioc == NULL) { + object_unref(OBJECT(server)); + error_report("Failed to use socket activation: %s", + error_get_pretty(local_err)); + exit(EXIT_FAILURE); + } + qio_net_listener_add(server, sioc); + object_unref(OBJECT(sioc)); } } From 194b7f0d448361dd58d2f7f189147cf075988255 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Mon, 18 Dec 2017 13:54:17 +0000 Subject: [PATCH 341/546] chardev: convert the socket server to QIONetListener Instead of creating a QIOChannelSocket directly for the chardev server socket, use a QIONetListener. This provides the ability to listen on multiple sockets at the same time, so enables full support for IPv4/IPv6 dual stack. Signed-off-by: Daniel P. Berrange Message-Id: <20171218135417.28301-2-berrange@redhat.com> Signed-off-by: Paolo Bonzini --- chardev/char-socket.c | 73 ++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 43 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 53eda8ef00..630a7f2995 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -25,6 +25,7 @@ #include "chardev/char.h" #include "io/channel-socket.h" #include "io/channel-tls.h" +#include "io/net-listener.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "qapi/clone-visitor.h" @@ -40,8 +41,7 @@ typedef struct { Chardev parent; QIOChannel *ioc; /* Client I/O channel */ QIOChannelSocket *sioc; /* Client master channel */ - QIOChannelSocket *listen_ioc; - guint listen_tag; + QIONetListener *listener; QCryptoTLSCreds *tls_creds; int connected; int max_size; @@ -93,9 +93,9 @@ static void check_report_connect_error(Chardev *chr, qemu_chr_socket_restart_timer(chr); } -static gboolean tcp_chr_accept(QIOChannel *chan, - GIOCondition cond, - void *opaque); +static void tcp_chr_accept(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque); static int tcp_chr_read_poll(void *opaque); static void tcp_chr_disconnect(Chardev *chr); @@ -401,9 +401,9 @@ static void tcp_chr_disconnect(Chardev *chr) tcp_chr_free_connection(chr); - if (s->listen_ioc && s->listen_tag == 0) { - s->listen_tag = qio_channel_add_watch( - QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL); + if (s->listener) { + qio_net_listener_set_client_func(s->listener, tcp_chr_accept, + chr, NULL); } update_disconnected_filename(s); if (emit_close) { @@ -702,9 +702,8 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc) if (s->do_nodelay) { qio_channel_set_delay(s->ioc, false); } - if (s->listen_tag) { - g_source_remove(s->listen_tag); - s->listen_tag = 0; + if (s->listener) { + qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); } if (s->tls_creds) { @@ -736,24 +735,14 @@ static int tcp_chr_add_client(Chardev *chr, int fd) return ret; } -static gboolean tcp_chr_accept(QIOChannel *channel, - GIOCondition cond, - void *opaque) +static void tcp_chr_accept(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque) { Chardev *chr = CHARDEV(opaque); - QIOChannelSocket *sioc; - sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(channel), - NULL); - if (!sioc) { - return TRUE; - } - - tcp_chr_new_client(chr, sioc); - - object_unref(OBJECT(sioc)); - - return TRUE; + tcp_chr_set_client_ioc_name(chr, cioc); + tcp_chr_new_client(chr, cioc); } static int tcp_chr_wait_connected(Chardev *chr, Error **errp) @@ -767,9 +756,10 @@ static int tcp_chr_wait_connected(Chardev *chr, Error **errp) if (s->is_listen) { info_report("QEMU waiting for connection on: %s", chr->filename); - qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL); - tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr); - qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL); + sioc = qio_net_listener_wait_client(s->listener); + tcp_chr_set_client_ioc_name(chr, sioc); + tcp_chr_new_client(chr, sioc); + object_unref(OBJECT(sioc)); } else { sioc = qio_channel_socket_new(); tcp_chr_set_client_ioc_name(chr, sioc); @@ -797,12 +787,9 @@ static void char_socket_finalize(Object *obj) s->reconnect_timer = 0; } qapi_free_SocketAddress(s->addr); - if (s->listen_tag) { - g_source_remove(s->listen_tag); - s->listen_tag = 0; - } - if (s->listen_ioc) { - object_unref(OBJECT(s->listen_ioc)); + if (s->listener) { + qio_net_listener_set_client_func(s->listener, NULL, NULL, NULL); + object_unref(OBJECT(s->listener)); } if (s->tls_creds) { object_unref(OBJECT(s->tls_creds)); @@ -935,29 +922,29 @@ static void qmp_chardev_open_socket(Chardev *chr, } else { if (s->is_listen) { char *name; - sioc = qio_channel_socket_new(); + s->listener = qio_net_listener_new(); name = g_strdup_printf("chardev-tcp-listener-%s", chr->label); - qio_channel_set_name(QIO_CHANNEL(sioc), name); + qio_net_listener_set_name(s->listener, name); g_free(name); - if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) { + if (qio_net_listener_open_sync(s->listener, s->addr, errp) < 0) { + object_unref(OBJECT(s->listener)); + s->listener = NULL; goto error; } qapi_free_SocketAddress(s->addr); - s->addr = socket_local_address(sioc->fd, errp); + s->addr = socket_local_address(s->listener->sioc[0]->fd, errp); update_disconnected_filename(s); - s->listen_ioc = sioc; if (is_waitconnect && qemu_chr_wait_connected(chr, errp) < 0) { return; } if (!s->ioc) { - s->listen_tag = qio_channel_add_watch( - QIO_CHANNEL(s->listen_ioc), G_IO_IN, - tcp_chr_accept, chr, NULL); + qio_net_listener_set_client_func(s->listener, tcp_chr_accept, + chr, NULL); } } else if (qemu_chr_wait_connected(chr, errp) < 0) { goto error; From 77cb0f5aafc8e6d0c6d3c339f381c9b7921648e0 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 20 Dec 2017 13:14:06 +0100 Subject: [PATCH 342/546] Split adb.c into adb.c, adb-mouse.c and adb-kbd.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It makes the code clearer to separate the bus implementation from the devices one. Replace ADB_DPRINTF() with trace events (and adding new ones in adb-kbd.c). Some minor changes to make checkpatch.pl happy. Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20171220121406.24056-1-laurent@vivier.eu> --- hw/input/Makefile.objs | 2 +- hw/input/adb-internal.h | 49 ++++ hw/input/adb-kbd.c | 400 ++++++++++++++++++++++++++ hw/input/adb-mouse.c | 254 ++++++++++++++++ hw/input/adb.c | 622 +--------------------------------------- hw/input/trace-events | 8 + 6 files changed, 714 insertions(+), 621 deletions(-) create mode 100644 hw/input/adb-internal.h create mode 100644 hw/input/adb-kbd.c create mode 100644 hw/input/adb-mouse.c diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs index 636f794b6b..77e53e6883 100644 --- a/hw/input/Makefile.objs +++ b/hw/input/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-$(CONFIG_ADB) += adb.o +common-obj-$(CONFIG_ADB) += adb.o adb-mouse.o adb-kbd.o common-obj-y += hid.o common-obj-$(CONFIG_LM832X) += lm832x.o common-obj-$(CONFIG_PCKBD) += pckbd.o diff --git a/hw/input/adb-internal.h b/hw/input/adb-internal.h new file mode 100644 index 0000000000..2a779b8a0a --- /dev/null +++ b/hw/input/adb-internal.h @@ -0,0 +1,49 @@ +/* + * QEMU ADB support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* ADB commands */ + +#define ADB_BUSRESET 0x00 +#define ADB_FLUSH 0x01 +#define ADB_WRITEREG 0x08 +#define ADB_READREG 0x0c + +/* ADB device commands */ + +#define ADB_CMD_SELF_TEST 0xff +#define ADB_CMD_CHANGE_ID 0xfe +#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd +#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 + +/* ADB default device IDs (upper 4 bits of ADB command byte) */ + +#define ADB_DEVID_DONGLE 1 +#define ADB_DEVID_KEYBOARD 2 +#define ADB_DEVID_MOUSE 3 +#define ADB_DEVID_TABLET 4 +#define ADB_DEVID_MODEM 5 +#define ADB_DEVID_MISC 7 + +extern const VMStateDescription vmstate_adb_device; + diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c new file mode 100644 index 0000000000..354f56e41e --- /dev/null +++ b/hw/input/adb-kbd.c @@ -0,0 +1,400 @@ +/* + * QEMU ADB keyboard support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "hw/input/adb.h" +#include "ui/input.h" +#include "hw/input/adb-keys.h" +#include "sysemu/sysemu.h" +#include "adb-internal.h" +#include "trace.h" + +#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD) + +typedef struct KBDState { + /*< private >*/ + ADBDevice parent_obj; + /*< public >*/ + + uint8_t data[128]; + int rptr, wptr, count; +} KBDState; + +#define ADB_KEYBOARD_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD) +#define ADB_KEYBOARD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD) + +typedef struct ADBKeyboardClass { + /*< private >*/ + ADBDeviceClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; +} ADBKeyboardClass; + +/* The adb keyboard doesn't have every key imaginable */ +#define NO_KEY 0xff + +int qcode_to_adb_keycode[] = { + /* Make sure future additions are automatically set to NO_KEY */ + [0 ... 0xff] = NO_KEY, + + [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT, + [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, + [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION, + [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION, + [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL, + [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL, + [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND, + [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND, + [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR, + + [Q_KEY_CODE_ESC] = ADB_KEY_ESC, + [Q_KEY_CODE_1] = ADB_KEY_1, + [Q_KEY_CODE_2] = ADB_KEY_2, + [Q_KEY_CODE_3] = ADB_KEY_3, + [Q_KEY_CODE_4] = ADB_KEY_4, + [Q_KEY_CODE_5] = ADB_KEY_5, + [Q_KEY_CODE_6] = ADB_KEY_6, + [Q_KEY_CODE_7] = ADB_KEY_7, + [Q_KEY_CODE_8] = ADB_KEY_8, + [Q_KEY_CODE_9] = ADB_KEY_9, + [Q_KEY_CODE_0] = ADB_KEY_0, + [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS, + [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL, + [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE, + [Q_KEY_CODE_TAB] = ADB_KEY_TAB, + [Q_KEY_CODE_Q] = ADB_KEY_Q, + [Q_KEY_CODE_W] = ADB_KEY_W, + [Q_KEY_CODE_E] = ADB_KEY_E, + [Q_KEY_CODE_R] = ADB_KEY_R, + [Q_KEY_CODE_T] = ADB_KEY_T, + [Q_KEY_CODE_Y] = ADB_KEY_Y, + [Q_KEY_CODE_U] = ADB_KEY_U, + [Q_KEY_CODE_I] = ADB_KEY_I, + [Q_KEY_CODE_O] = ADB_KEY_O, + [Q_KEY_CODE_P] = ADB_KEY_P, + [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET, + [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET, + [Q_KEY_CODE_RET] = ADB_KEY_RETURN, + [Q_KEY_CODE_A] = ADB_KEY_A, + [Q_KEY_CODE_S] = ADB_KEY_S, + [Q_KEY_CODE_D] = ADB_KEY_D, + [Q_KEY_CODE_F] = ADB_KEY_F, + [Q_KEY_CODE_G] = ADB_KEY_G, + [Q_KEY_CODE_H] = ADB_KEY_H, + [Q_KEY_CODE_J] = ADB_KEY_J, + [Q_KEY_CODE_K] = ADB_KEY_K, + [Q_KEY_CODE_L] = ADB_KEY_L, + [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON, + [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE, + [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT, + [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH, + [Q_KEY_CODE_Z] = ADB_KEY_Z, + [Q_KEY_CODE_X] = ADB_KEY_X, + [Q_KEY_CODE_C] = ADB_KEY_C, + [Q_KEY_CODE_V] = ADB_KEY_V, + [Q_KEY_CODE_B] = ADB_KEY_B, + [Q_KEY_CODE_N] = ADB_KEY_N, + [Q_KEY_CODE_M] = ADB_KEY_M, + [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA, + [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD, + [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH, + [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK, + + [Q_KEY_CODE_F1] = ADB_KEY_F1, + [Q_KEY_CODE_F2] = ADB_KEY_F2, + [Q_KEY_CODE_F3] = ADB_KEY_F3, + [Q_KEY_CODE_F4] = ADB_KEY_F4, + [Q_KEY_CODE_F5] = ADB_KEY_F5, + [Q_KEY_CODE_F6] = ADB_KEY_F6, + [Q_KEY_CODE_F7] = ADB_KEY_F7, + [Q_KEY_CODE_F8] = ADB_KEY_F8, + [Q_KEY_CODE_F9] = ADB_KEY_F9, + [Q_KEY_CODE_F10] = ADB_KEY_F10, + [Q_KEY_CODE_F11] = ADB_KEY_F11, + [Q_KEY_CODE_F12] = ADB_KEY_F12, + [Q_KEY_CODE_PRINT] = ADB_KEY_F13, + [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13, + [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14, + [Q_KEY_CODE_PAUSE] = ADB_KEY_F15, + + [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR, + [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL, + [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE, + [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY, + [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT, + [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS, + [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER, + [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD, + [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0, + [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1, + [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2, + [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3, + [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4, + [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5, + [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6, + [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7, + [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8, + [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9, + + [Q_KEY_CODE_UP] = ADB_KEY_UP, + [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN, + [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT, + [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT, + + [Q_KEY_CODE_HELP] = ADB_KEY_HELP, + [Q_KEY_CODE_INSERT] = ADB_KEY_HELP, + [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE, + [Q_KEY_CODE_HOME] = ADB_KEY_HOME, + [Q_KEY_CODE_END] = ADB_KEY_END, + [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP, + [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN, + + [Q_KEY_CODE_POWER] = ADB_KEY_POWER +}; + +static void adb_kbd_put_keycode(void *opaque, int keycode) +{ + KBDState *s = opaque; + + if (s->count < sizeof(s->data)) { + s->data[s->wptr] = keycode; + if (++s->wptr == sizeof(s->data)) { + s->wptr = 0; + } + s->count++; + } +} + +static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) +{ + KBDState *s = ADB_KEYBOARD(d); + int keycode; + int olen; + + olen = 0; + if (s->count == 0) { + return 0; + } + keycode = s->data[s->rptr]; + s->rptr++; + if (s->rptr == sizeof(s->data)) { + s->rptr = 0; + } + s->count--; + /* + * The power key is the only two byte value key, so it is a special case. + * Since 0x7f is not a used keycode for ADB we overload it to indicate the + * power button when we're storing keycodes in our internal buffer, and + * expand it out to two bytes when we send to the guest. + */ + if (keycode == 0x7f) { + obuf[0] = 0x7f; + obuf[1] = 0x7f; + olen = 2; + } else { + obuf[0] = keycode; + /* NOTE: the power key key-up is the two byte sequence 0xff 0xff; + * otherwise we could in theory send a second keycode in the second + * byte, but choose not to bother. + */ + obuf[1] = 0xff; + olen = 2; + } + + return olen; +} + +static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, + const uint8_t *buf, int len) +{ + KBDState *s = ADB_KEYBOARD(d); + int cmd, reg, olen; + + if ((buf[0] & 0x0f) == ADB_FLUSH) { + /* flush keyboard fifo */ + s->wptr = s->rptr = s->count = 0; + return 0; + } + + cmd = buf[0] & 0xc; + reg = buf[0] & 0x3; + olen = 0; + switch (cmd) { + case ADB_WRITEREG: + trace_adb_kbd_writereg(reg, buf[1]); + switch (reg) { + case 2: + /* LED status */ + break; + case 3: + switch (buf[2]) { + case ADB_CMD_SELF_TEST: + break; + case ADB_CMD_CHANGE_ID: + case ADB_CMD_CHANGE_ID_AND_ACT: + case ADB_CMD_CHANGE_ID_AND_ENABLE: + d->devaddr = buf[1] & 0xf; + break; + default: + d->devaddr = buf[1] & 0xf; + /* we support handlers: + * 1: Apple Standard Keyboard + * 2: Apple Extended Keyboard (LShift = RShift) + * 3: Apple Extended Keyboard (LShift != RShift) + */ + if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) { + d->handler = buf[2]; + } + break; + } + } + break; + case ADB_READREG: + switch (reg) { + case 0: + olen = adb_kbd_poll(d, obuf); + break; + case 1: + break; + case 2: + obuf[0] = 0x00; /* XXX: check this */ + obuf[1] = 0x07; /* led status */ + olen = 2; + break; + case 3: + obuf[0] = d->handler; + obuf[1] = d->devaddr; + olen = 2; + break; + } + trace_adb_kbd_readreg(reg, obuf[0], obuf[1]); + break; + } + return olen; +} + +/* This is where keyboard events enter this file */ +static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + KBDState *s = (KBDState *)dev; + int qcode, keycode; + + qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); + if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) { + return; + } + /* FIXME: take handler into account when translating qcode */ + keycode = qcode_to_adb_keycode[qcode]; + if (keycode == NO_KEY) { /* We don't want to send this to the guest */ + trace_adb_kbd_no_key(); + return; + } + if (evt->u.key.data->down == false) { /* if key release event */ + keycode = keycode | 0x80; /* create keyboard break code */ + } + + adb_kbd_put_keycode(s, keycode); +} + +static const VMStateDescription vmstate_adb_kbd = { + .name = "adb_kbd", + .version_id = 2, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice), + VMSTATE_BUFFER(data, KBDState), + VMSTATE_INT32(rptr, KBDState), + VMSTATE_INT32(wptr, KBDState), + VMSTATE_INT32(count, KBDState), + VMSTATE_END_OF_LIST() + } +}; + +static void adb_kbd_reset(DeviceState *dev) +{ + ADBDevice *d = ADB_DEVICE(dev); + KBDState *s = ADB_KEYBOARD(dev); + + d->handler = 1; + d->devaddr = ADB_DEVID_KEYBOARD; + memset(s->data, 0, sizeof(s->data)); + s->rptr = 0; + s->wptr = 0; + s->count = 0; +} + +static QemuInputHandler adb_keyboard_handler = { + .name = "QEMU ADB Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = adb_keyboard_event, +}; + +static void adb_kbd_realizefn(DeviceState *dev, Error **errp) +{ + ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); + akc->parent_realize(dev, errp); + qemu_input_handler_register(dev, &adb_keyboard_handler); +} + +static void adb_kbd_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_KEYBOARD; +} + +static void adb_kbd_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); + + akc->parent_realize = dc->realize; + dc->realize = adb_kbd_realizefn; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + adc->devreq = adb_kbd_request; + dc->reset = adb_kbd_reset; + dc->vmsd = &vmstate_adb_kbd; +} + +static const TypeInfo adb_kbd_type_info = { + .name = TYPE_ADB_KEYBOARD, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(KBDState), + .instance_init = adb_kbd_initfn, + .class_init = adb_kbd_class_init, + .class_size = sizeof(ADBKeyboardClass), +}; + +static void adb_kbd_register_types(void) +{ + type_register_static(&adb_kbd_type_info); +} + +type_init(adb_kbd_register_types) diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c new file mode 100644 index 0000000000..c9004233b8 --- /dev/null +++ b/hw/input/adb-mouse.c @@ -0,0 +1,254 @@ +/* + * QEMU ADB mouse support + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu/osdep.h" +#include "ui/console.h" +#include "hw/input/adb.h" +#include "adb-internal.h" +#include "trace.h" + +#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) + +typedef struct MouseState { + /*< public >*/ + ADBDevice parent_obj; + /*< private >*/ + + int buttons_state, last_buttons_state; + int dx, dy, dz; +} MouseState; + +#define ADB_MOUSE_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) +#define ADB_MOUSE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) + +typedef struct ADBMouseClass { + /*< public >*/ + ADBDeviceClass parent_class; + /*< private >*/ + + DeviceRealize parent_realize; +} ADBMouseClass; + +static void adb_mouse_event(void *opaque, + int dx1, int dy1, int dz1, int buttons_state) +{ + MouseState *s = opaque; + + s->dx += dx1; + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; +} + + +static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) +{ + MouseState *s = ADB_MOUSE(d); + int dx, dy; + + if (s->last_buttons_state == s->buttons_state && + s->dx == 0 && s->dy == 0) { + return 0; + } + + dx = s->dx; + if (dx < -63) { + dx = -63; + } else if (dx > 63) { + dx = 63; + } + + dy = s->dy; + if (dy < -63) { + dy = -63; + } else if (dy > 63) { + dy = 63; + } + + s->dx -= dx; + s->dy -= dy; + s->last_buttons_state = s->buttons_state; + + dx &= 0x7f; + dy &= 0x7f; + + if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) { + dy |= 0x80; + } + if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) { + dx |= 0x80; + } + + obuf[0] = dy; + obuf[1] = dx; + return 2; +} + +static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, + const uint8_t *buf, int len) +{ + MouseState *s = ADB_MOUSE(d); + int cmd, reg, olen; + + if ((buf[0] & 0x0f) == ADB_FLUSH) { + /* flush mouse fifo */ + s->buttons_state = s->last_buttons_state; + s->dx = 0; + s->dy = 0; + s->dz = 0; + return 0; + } + + cmd = buf[0] & 0xc; + reg = buf[0] & 0x3; + olen = 0; + switch (cmd) { + case ADB_WRITEREG: + trace_adb_mouse_writereg(reg, buf[1]); + switch (reg) { + case 2: + break; + case 3: + switch (buf[2]) { + case ADB_CMD_SELF_TEST: + break; + case ADB_CMD_CHANGE_ID: + case ADB_CMD_CHANGE_ID_AND_ACT: + case ADB_CMD_CHANGE_ID_AND_ENABLE: + d->devaddr = buf[1] & 0xf; + break; + default: + d->devaddr = buf[1] & 0xf; + /* we support handlers: + * 0x01: Classic Apple Mouse Protocol / 100 cpi operations + * 0x02: Classic Apple Mouse Protocol / 200 cpi operations + * we don't support handlers (at least): + * 0x03: Mouse systems A3 trackball + * 0x04: Extended Apple Mouse Protocol + * 0x2f: Microspeed mouse + * 0x42: Macally + * 0x5f: Microspeed mouse + * 0x66: Microspeed mouse + */ + if (buf[2] == 1 || buf[2] == 2) { + d->handler = buf[2]; + } + break; + } + } + break; + case ADB_READREG: + switch (reg) { + case 0: + olen = adb_mouse_poll(d, obuf); + break; + case 1: + break; + case 3: + obuf[0] = d->handler; + obuf[1] = d->devaddr; + olen = 2; + break; + } + trace_adb_mouse_readreg(reg, obuf[0], obuf[1]); + break; + } + return olen; +} + +static void adb_mouse_reset(DeviceState *dev) +{ + ADBDevice *d = ADB_DEVICE(dev); + MouseState *s = ADB_MOUSE(dev); + + d->handler = 2; + d->devaddr = ADB_DEVID_MOUSE; + s->last_buttons_state = s->buttons_state = 0; + s->dx = s->dy = s->dz = 0; +} + +static const VMStateDescription vmstate_adb_mouse = { + .name = "adb_mouse", + .version_id = 2, + .minimum_version_id = 2, + .fields = (VMStateField[]) { + VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device, + ADBDevice), + VMSTATE_INT32(buttons_state, MouseState), + VMSTATE_INT32(last_buttons_state, MouseState), + VMSTATE_INT32(dx, MouseState), + VMSTATE_INT32(dy, MouseState), + VMSTATE_INT32(dz, MouseState), + VMSTATE_END_OF_LIST() + } +}; + +static void adb_mouse_realizefn(DeviceState *dev, Error **errp) +{ + MouseState *s = ADB_MOUSE(dev); + ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); + + amc->parent_realize(dev, errp); + + qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); +} + +static void adb_mouse_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_MOUSE; +} + +static void adb_mouse_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); + + amc->parent_realize = dc->realize; + dc->realize = adb_mouse_realizefn; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); + + adc->devreq = adb_mouse_request; + dc->reset = adb_mouse_reset; + dc->vmsd = &vmstate_adb_mouse; +} + +static const TypeInfo adb_mouse_type_info = { + .name = TYPE_ADB_MOUSE, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(MouseState), + .instance_init = adb_mouse_initfn, + .class_init = adb_mouse_class_init, + .class_size = sizeof(ADBMouseClass), +}; + +static void adb_mouse_register_types(void) +{ + type_register_static(&adb_mouse_type_info); +} + +type_init(adb_mouse_register_types) diff --git a/hw/input/adb.c b/hw/input/adb.c index 924a3f9fd5..23ae6f0d75 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -22,49 +22,12 @@ * THE SOFTWARE. */ #include "qemu/osdep.h" -#include "hw/hw.h" #include "hw/input/adb.h" -#include "hw/input/adb-keys.h" -#include "ui/console.h" -#include "ui/input.h" -#include "sysemu/sysemu.h" - -/* debug ADB */ -//#define DEBUG_ADB - -#ifdef DEBUG_ADB -#define ADB_DPRINTF(fmt, ...) \ -do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) -#else -#define ADB_DPRINTF(fmt, ...) -#endif - -/* ADB commands */ -#define ADB_BUSRESET 0x00 -#define ADB_FLUSH 0x01 -#define ADB_WRITEREG 0x08 -#define ADB_READREG 0x0c - -/* ADB device commands */ -#define ADB_CMD_SELF_TEST 0xff -#define ADB_CMD_CHANGE_ID 0xfe -#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd -#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 - -/* ADB default device IDs (upper 4 bits of ADB command byte) */ -#define ADB_DEVID_DONGLE 1 -#define ADB_DEVID_KEYBOARD 2 -#define ADB_DEVID_MOUSE 3 -#define ADB_DEVID_TABLET 4 -#define ADB_DEVID_MODEM 5 -#define ADB_DEVID_MISC 7 +#include "adb-internal.h" /* error codes */ #define ADB_RET_NOTPRESENT (-2) -/* The adb keyboard doesn't have every key imaginable */ -#define NO_KEY 0xff - static void adb_device_reset(ADBDevice *d) { qdev_reset_all(DEVICE(d)); @@ -127,7 +90,7 @@ static const TypeInfo adb_bus_type_info = { .instance_size = sizeof(ADBBusState), }; -static const VMStateDescription vmstate_adb_device = { +const VMStateDescription vmstate_adb_device = { .name = "adb_device", .version_id = 0, .minimum_version_id = 0, @@ -166,591 +129,10 @@ static const TypeInfo adb_device_type_info = { .class_init = adb_device_class_init, }; -/***************************************************************/ -/* Keyboard ADB device */ - -#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD) - -typedef struct KBDState { - /*< private >*/ - ADBDevice parent_obj; - /*< public >*/ - - uint8_t data[128]; - int rptr, wptr, count; -} KBDState; - -#define ADB_KEYBOARD_CLASS(class) \ - OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD) -#define ADB_KEYBOARD_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD) - -typedef struct ADBKeyboardClass { - /*< private >*/ - ADBDeviceClass parent_class; - /*< public >*/ - - DeviceRealize parent_realize; -} ADBKeyboardClass; - -int qcode_to_adb_keycode[] = { - /* Make sure future additions are automatically set to NO_KEY */ - [0 ... 0xff] = NO_KEY, - - [Q_KEY_CODE_SHIFT] = ADB_KEY_LEFT_SHIFT, - [Q_KEY_CODE_SHIFT_R] = ADB_KEY_RIGHT_SHIFT, - [Q_KEY_CODE_ALT] = ADB_KEY_LEFT_OPTION, - [Q_KEY_CODE_ALT_R] = ADB_KEY_RIGHT_OPTION, - [Q_KEY_CODE_CTRL] = ADB_KEY_LEFT_CONTROL, - [Q_KEY_CODE_CTRL_R] = ADB_KEY_RIGHT_CONTROL, - [Q_KEY_CODE_META_L] = ADB_KEY_COMMAND, - [Q_KEY_CODE_META_R] = ADB_KEY_COMMAND, - [Q_KEY_CODE_SPC] = ADB_KEY_SPACEBAR, - - [Q_KEY_CODE_ESC] = ADB_KEY_ESC, - [Q_KEY_CODE_1] = ADB_KEY_1, - [Q_KEY_CODE_2] = ADB_KEY_2, - [Q_KEY_CODE_3] = ADB_KEY_3, - [Q_KEY_CODE_4] = ADB_KEY_4, - [Q_KEY_CODE_5] = ADB_KEY_5, - [Q_KEY_CODE_6] = ADB_KEY_6, - [Q_KEY_CODE_7] = ADB_KEY_7, - [Q_KEY_CODE_8] = ADB_KEY_8, - [Q_KEY_CODE_9] = ADB_KEY_9, - [Q_KEY_CODE_0] = ADB_KEY_0, - [Q_KEY_CODE_MINUS] = ADB_KEY_MINUS, - [Q_KEY_CODE_EQUAL] = ADB_KEY_EQUAL, - [Q_KEY_CODE_BACKSPACE] = ADB_KEY_DELETE, - [Q_KEY_CODE_TAB] = ADB_KEY_TAB, - [Q_KEY_CODE_Q] = ADB_KEY_Q, - [Q_KEY_CODE_W] = ADB_KEY_W, - [Q_KEY_CODE_E] = ADB_KEY_E, - [Q_KEY_CODE_R] = ADB_KEY_R, - [Q_KEY_CODE_T] = ADB_KEY_T, - [Q_KEY_CODE_Y] = ADB_KEY_Y, - [Q_KEY_CODE_U] = ADB_KEY_U, - [Q_KEY_CODE_I] = ADB_KEY_I, - [Q_KEY_CODE_O] = ADB_KEY_O, - [Q_KEY_CODE_P] = ADB_KEY_P, - [Q_KEY_CODE_BRACKET_LEFT] = ADB_KEY_LEFT_BRACKET, - [Q_KEY_CODE_BRACKET_RIGHT] = ADB_KEY_RIGHT_BRACKET, - [Q_KEY_CODE_RET] = ADB_KEY_RETURN, - [Q_KEY_CODE_A] = ADB_KEY_A, - [Q_KEY_CODE_S] = ADB_KEY_S, - [Q_KEY_CODE_D] = ADB_KEY_D, - [Q_KEY_CODE_F] = ADB_KEY_F, - [Q_KEY_CODE_G] = ADB_KEY_G, - [Q_KEY_CODE_H] = ADB_KEY_H, - [Q_KEY_CODE_J] = ADB_KEY_J, - [Q_KEY_CODE_K] = ADB_KEY_K, - [Q_KEY_CODE_L] = ADB_KEY_L, - [Q_KEY_CODE_SEMICOLON] = ADB_KEY_SEMICOLON, - [Q_KEY_CODE_APOSTROPHE] = ADB_KEY_APOSTROPHE, - [Q_KEY_CODE_GRAVE_ACCENT] = ADB_KEY_GRAVE_ACCENT, - [Q_KEY_CODE_BACKSLASH] = ADB_KEY_BACKSLASH, - [Q_KEY_CODE_Z] = ADB_KEY_Z, - [Q_KEY_CODE_X] = ADB_KEY_X, - [Q_KEY_CODE_C] = ADB_KEY_C, - [Q_KEY_CODE_V] = ADB_KEY_V, - [Q_KEY_CODE_B] = ADB_KEY_B, - [Q_KEY_CODE_N] = ADB_KEY_N, - [Q_KEY_CODE_M] = ADB_KEY_M, - [Q_KEY_CODE_COMMA] = ADB_KEY_COMMA, - [Q_KEY_CODE_DOT] = ADB_KEY_PERIOD, - [Q_KEY_CODE_SLASH] = ADB_KEY_FORWARD_SLASH, - [Q_KEY_CODE_ASTERISK] = ADB_KEY_KP_MULTIPLY, - [Q_KEY_CODE_CAPS_LOCK] = ADB_KEY_CAPS_LOCK, - - [Q_KEY_CODE_F1] = ADB_KEY_F1, - [Q_KEY_CODE_F2] = ADB_KEY_F2, - [Q_KEY_CODE_F3] = ADB_KEY_F3, - [Q_KEY_CODE_F4] = ADB_KEY_F4, - [Q_KEY_CODE_F5] = ADB_KEY_F5, - [Q_KEY_CODE_F6] = ADB_KEY_F6, - [Q_KEY_CODE_F7] = ADB_KEY_F7, - [Q_KEY_CODE_F8] = ADB_KEY_F8, - [Q_KEY_CODE_F9] = ADB_KEY_F9, - [Q_KEY_CODE_F10] = ADB_KEY_F10, - [Q_KEY_CODE_F11] = ADB_KEY_F11, - [Q_KEY_CODE_F12] = ADB_KEY_F12, - [Q_KEY_CODE_PRINT] = ADB_KEY_F13, - [Q_KEY_CODE_SYSRQ] = ADB_KEY_F13, - [Q_KEY_CODE_SCROLL_LOCK] = ADB_KEY_F14, - [Q_KEY_CODE_PAUSE] = ADB_KEY_F15, - - [Q_KEY_CODE_NUM_LOCK] = ADB_KEY_KP_CLEAR, - [Q_KEY_CODE_KP_EQUALS] = ADB_KEY_KP_EQUAL, - [Q_KEY_CODE_KP_DIVIDE] = ADB_KEY_KP_DIVIDE, - [Q_KEY_CODE_KP_MULTIPLY] = ADB_KEY_KP_MULTIPLY, - [Q_KEY_CODE_KP_SUBTRACT] = ADB_KEY_KP_SUBTRACT, - [Q_KEY_CODE_KP_ADD] = ADB_KEY_KP_PLUS, - [Q_KEY_CODE_KP_ENTER] = ADB_KEY_KP_ENTER, - [Q_KEY_CODE_KP_DECIMAL] = ADB_KEY_KP_PERIOD, - [Q_KEY_CODE_KP_0] = ADB_KEY_KP_0, - [Q_KEY_CODE_KP_1] = ADB_KEY_KP_1, - [Q_KEY_CODE_KP_2] = ADB_KEY_KP_2, - [Q_KEY_CODE_KP_3] = ADB_KEY_KP_3, - [Q_KEY_CODE_KP_4] = ADB_KEY_KP_4, - [Q_KEY_CODE_KP_5] = ADB_KEY_KP_5, - [Q_KEY_CODE_KP_6] = ADB_KEY_KP_6, - [Q_KEY_CODE_KP_7] = ADB_KEY_KP_7, - [Q_KEY_CODE_KP_8] = ADB_KEY_KP_8, - [Q_KEY_CODE_KP_9] = ADB_KEY_KP_9, - - [Q_KEY_CODE_UP] = ADB_KEY_UP, - [Q_KEY_CODE_DOWN] = ADB_KEY_DOWN, - [Q_KEY_CODE_LEFT] = ADB_KEY_LEFT, - [Q_KEY_CODE_RIGHT] = ADB_KEY_RIGHT, - - [Q_KEY_CODE_HELP] = ADB_KEY_HELP, - [Q_KEY_CODE_INSERT] = ADB_KEY_HELP, - [Q_KEY_CODE_DELETE] = ADB_KEY_FORWARD_DELETE, - [Q_KEY_CODE_HOME] = ADB_KEY_HOME, - [Q_KEY_CODE_END] = ADB_KEY_END, - [Q_KEY_CODE_PGUP] = ADB_KEY_PAGE_UP, - [Q_KEY_CODE_PGDN] = ADB_KEY_PAGE_DOWN, - - [Q_KEY_CODE_POWER] = ADB_KEY_POWER -}; - -static void adb_kbd_put_keycode(void *opaque, int keycode) -{ - KBDState *s = opaque; - - if (s->count < sizeof(s->data)) { - s->data[s->wptr] = keycode; - if (++s->wptr == sizeof(s->data)) - s->wptr = 0; - s->count++; - } -} - -static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) -{ - KBDState *s = ADB_KEYBOARD(d); - int keycode; - int olen; - - olen = 0; - if (s->count == 0) { - return 0; - } - keycode = s->data[s->rptr]; - s->rptr++; - if (s->rptr == sizeof(s->data)) { - s->rptr = 0; - } - s->count--; - /* - * The power key is the only two byte value key, so it is a special case. - * Since 0x7f is not a used keycode for ADB we overload it to indicate the - * power button when we're storing keycodes in our internal buffer, and - * expand it out to two bytes when we send to the guest. - */ - if (keycode == 0x7f) { - obuf[0] = 0x7f; - obuf[1] = 0x7f; - olen = 2; - } else { - obuf[0] = keycode; - /* NOTE: the power key key-up is the two byte sequence 0xff 0xff; - * otherwise we could in theory send a second keycode in the second - * byte, but choose not to bother. - */ - obuf[1] = 0xff; - olen = 2; - } - - return olen; -} - -static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - KBDState *s = ADB_KEYBOARD(d); - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush keyboard fifo */ - s->wptr = s->rptr = s->count = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - switch(reg) { - case 2: - /* LED status */ - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - d->devaddr = buf[1] & 0xf; - /* we support handlers: - * 1: Apple Standard Keyboard - * 2: Apple Extended Keyboard (LShift = RShift) - * 3: Apple Extended Keyboard (LShift != RShift) - */ - if (buf[2] == 1 || buf[2] == 2 || buf[2] == 3) { - d->handler = buf[2]; - } - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_kbd_poll(d, obuf); - break; - case 1: - break; - case 2: - obuf[0] = 0x00; /* XXX: check this */ - obuf[1] = 0x07; /* led status */ - olen = 2; - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - break; - } - return olen; -} - -/* This is where keyboard events enter this file */ -static void adb_keyboard_event(DeviceState *dev, QemuConsole *src, - InputEvent *evt) -{ - KBDState *s = (KBDState *)dev; - int qcode, keycode; - - qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); - if (qcode >= ARRAY_SIZE(qcode_to_adb_keycode)) { - return; - } - /* FIXME: take handler into account when translating qcode */ - keycode = qcode_to_adb_keycode[qcode]; - if (keycode == NO_KEY) { /* We don't want to send this to the guest */ - ADB_DPRINTF("Ignoring NO_KEY\n"); - return; - } - if (evt->u.key.data->down == false) { /* if key release event */ - keycode = keycode | 0x80; /* create keyboard break code */ - } - - adb_kbd_put_keycode(s, keycode); -} - -static const VMStateDescription vmstate_adb_kbd = { - .name = "adb_kbd", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(parent_obj, KBDState, 0, vmstate_adb_device, ADBDevice), - VMSTATE_BUFFER(data, KBDState), - VMSTATE_INT32(rptr, KBDState), - VMSTATE_INT32(wptr, KBDState), - VMSTATE_INT32(count, KBDState), - VMSTATE_END_OF_LIST() - } -}; - -static void adb_kbd_reset(DeviceState *dev) -{ - ADBDevice *d = ADB_DEVICE(dev); - KBDState *s = ADB_KEYBOARD(dev); - - d->handler = 1; - d->devaddr = ADB_DEVID_KEYBOARD; - memset(s->data, 0, sizeof(s->data)); - s->rptr = 0; - s->wptr = 0; - s->count = 0; -} - -static QemuInputHandler adb_keyboard_handler = { - .name = "QEMU ADB Keyboard", - .mask = INPUT_EVENT_MASK_KEY, - .event = adb_keyboard_event, -}; - -static void adb_kbd_realizefn(DeviceState *dev, Error **errp) -{ - ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); - akc->parent_realize(dev, errp); - qemu_input_handler_register(dev, &adb_keyboard_handler); -} - -static void adb_kbd_initfn(Object *obj) -{ - ADBDevice *d = ADB_DEVICE(obj); - - d->devaddr = ADB_DEVID_KEYBOARD; -} - -static void adb_kbd_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); - ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); - - akc->parent_realize = dc->realize; - dc->realize = adb_kbd_realizefn; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - adc->devreq = adb_kbd_request; - dc->reset = adb_kbd_reset; - dc->vmsd = &vmstate_adb_kbd; -} - -static const TypeInfo adb_kbd_type_info = { - .name = TYPE_ADB_KEYBOARD, - .parent = TYPE_ADB_DEVICE, - .instance_size = sizeof(KBDState), - .instance_init = adb_kbd_initfn, - .class_init = adb_kbd_class_init, - .class_size = sizeof(ADBKeyboardClass), -}; - -/***************************************************************/ -/* Mouse ADB device */ - -#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) - -typedef struct MouseState { - /*< public >*/ - ADBDevice parent_obj; - /*< private >*/ - - int buttons_state, last_buttons_state; - int dx, dy, dz; -} MouseState; - -#define ADB_MOUSE_CLASS(class) \ - OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) -#define ADB_MOUSE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) - -typedef struct ADBMouseClass { - /*< public >*/ - ADBDeviceClass parent_class; - /*< private >*/ - - DeviceRealize parent_realize; -} ADBMouseClass; - -static void adb_mouse_event(void *opaque, - int dx1, int dy1, int dz1, int buttons_state) -{ - MouseState *s = opaque; - - s->dx += dx1; - s->dy += dy1; - s->dz += dz1; - s->buttons_state = buttons_state; -} - - -static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) -{ - MouseState *s = ADB_MOUSE(d); - int dx, dy; - - if (s->last_buttons_state == s->buttons_state && - s->dx == 0 && s->dy == 0) - return 0; - - dx = s->dx; - if (dx < -63) - dx = -63; - else if (dx > 63) - dx = 63; - - dy = s->dy; - if (dy < -63) - dy = -63; - else if (dy > 63) - dy = 63; - - s->dx -= dx; - s->dy -= dy; - s->last_buttons_state = s->buttons_state; - - dx &= 0x7f; - dy &= 0x7f; - - if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) - dy |= 0x80; - if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) - dx |= 0x80; - - obuf[0] = dy; - obuf[1] = dx; - return 2; -} - -static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - MouseState *s = ADB_MOUSE(d); - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush mouse fifo */ - s->buttons_state = s->last_buttons_state; - s->dx = 0; - s->dy = 0; - s->dz = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]); - switch(reg) { - case 2: - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - d->devaddr = buf[1] & 0xf; - /* we support handlers: - * 0x01: Classic Apple Mouse Protocol / 100 cpi operations - * 0x02: Classic Apple Mouse Protocol / 200 cpi operations - * we don't support handlers (at least): - * 0x03: Mouse systems A3 trackball - * 0x04: Extended Apple Mouse Protocol - * 0x2f: Microspeed mouse - * 0x42: Macally - * 0x5f: Microspeed mouse - * 0x66: Microspeed mouse - */ - if (buf[2] == 1 || buf[2] == 2) { - d->handler = buf[2]; - } - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_mouse_poll(d, obuf); - break; - case 1: - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg, - obuf[0], obuf[1]); - break; - } - return olen; -} - -static void adb_mouse_reset(DeviceState *dev) -{ - ADBDevice *d = ADB_DEVICE(dev); - MouseState *s = ADB_MOUSE(dev); - - d->handler = 2; - d->devaddr = ADB_DEVID_MOUSE; - s->last_buttons_state = s->buttons_state = 0; - s->dx = s->dy = s->dz = 0; -} - -static const VMStateDescription vmstate_adb_mouse = { - .name = "adb_mouse", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(parent_obj, MouseState, 0, vmstate_adb_device, - ADBDevice), - VMSTATE_INT32(buttons_state, MouseState), - VMSTATE_INT32(last_buttons_state, MouseState), - VMSTATE_INT32(dx, MouseState), - VMSTATE_INT32(dy, MouseState), - VMSTATE_INT32(dz, MouseState), - VMSTATE_END_OF_LIST() - } -}; - -static void adb_mouse_realizefn(DeviceState *dev, Error **errp) -{ - MouseState *s = ADB_MOUSE(dev); - ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); - - amc->parent_realize(dev, errp); - - qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); -} - -static void adb_mouse_initfn(Object *obj) -{ - ADBDevice *d = ADB_DEVICE(obj); - - d->devaddr = ADB_DEVID_MOUSE; -} - -static void adb_mouse_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); - ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); - - amc->parent_realize = dc->realize; - dc->realize = adb_mouse_realizefn; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - - adc->devreq = adb_mouse_request; - dc->reset = adb_mouse_reset; - dc->vmsd = &vmstate_adb_mouse; -} - -static const TypeInfo adb_mouse_type_info = { - .name = TYPE_ADB_MOUSE, - .parent = TYPE_ADB_DEVICE, - .instance_size = sizeof(MouseState), - .instance_init = adb_mouse_initfn, - .class_init = adb_mouse_class_init, - .class_size = sizeof(ADBMouseClass), -}; - - static void adb_register_types(void) { type_register_static(&adb_bus_type_info); type_register_static(&adb_device_type_info); - type_register_static(&adb_kbd_type_info); - type_register_static(&adb_mouse_type_info); } type_init(adb_register_types) diff --git a/hw/input/trace-events b/hw/input/trace-events index 88150ef7a6..a8d46cb766 100644 --- a/hw/input/trace-events +++ b/hw/input/trace-events @@ -1,5 +1,13 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/input/adb-kbd.c +adb_kbd_no_key(void) "Ignoring NO_KEY" +adb_kbd_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" +adb_kbd_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" +# hw/input/adb-mouse.c +adb_mouse_writereg(int reg, uint8_t val) "reg %d val 0x%2.2x" +adb_mouse_readreg(int reg, uint8_t val0, uint8_t val1) "reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x" + # hw/input/ps2.c ps2_put_keycode(void *opaque, int keycode) "%p keycode 0x%02x" ps2_keyboard_event(void *opaque, int qcode, int down, unsigned int modifier, unsigned int modifiers) "%p qcode %d down %d modifier 0x%x modifiers 0x%x" From 5f63f6ab50b7c70bb8af8e0bd515ea14129c7aaa Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 20 Dec 2017 14:08:15 +0100 Subject: [PATCH 343/546] target/m68k: remove unused variable gen_throws_exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It has been introduced by e6e5906b6e ("ColdFire target."), but the content is never used. Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-Id: <20171220130815.20708-1-laurent@vivier.eu> --- target/m68k/translate.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index b60909222c..dfb2d5dad2 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -181,11 +181,6 @@ static void do_writebacks(DisasContext *s) #define IS_USER(s) s->user #endif -/* XXX: move that elsewhere */ -/* ??? Fix exceptions. */ -static void *gen_throws_exception; -#define gen_last_qop NULL - typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); #ifdef DEBUG_DISPATCH @@ -310,7 +305,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign) default: g_assert_not_reached(); } - gen_throws_exception = gen_last_qop; return tmp; } @@ -331,7 +325,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val) default: g_assert_not_reached(); } - gen_throws_exception = gen_last_qop; } typedef enum { @@ -1001,7 +994,6 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp) } tcg_temp_free(tmp); tcg_temp_free_i64(t64); - gen_throws_exception = gen_last_qop; } static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp) @@ -1056,7 +1048,6 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp) } tcg_temp_free(tmp); tcg_temp_free_i64(t64); - gen_throws_exception = gen_last_qop; } static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr, @@ -5561,7 +5552,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) gen_tb_start(tb); do { pc_offset = dc->pc - pc_start; - gen_throws_exception = NULL; tcg_gen_insn_start(dc->pc, dc->cc_op); num_insns++; From cea066821c75a533536bcbc6d79db07f2e0432f4 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 21 Dec 2017 09:30:57 +0100 Subject: [PATCH 344/546] target/m68k: add monitor.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to use registers content in the monitor. Example: BEFORE: (qemu) print $d0 unknown register AFTER: (qemu) print $d0 0 (qemu) print $sr 0x2000 (qemu) x/10i $pc 0x40010a2a: movew %sr,%d0 0x40010a2c: oril #1792,%d0 0x40010a32: movew %d0,%sr 0x40010a34: movel %a0@,%d0 0x40010a36: btst #3,%d0 0x40010a3a: beqs 0x40010a26 0x40010a3c: movew %sr,%d0 0x40010a3e: andil #63743,%d0 0x40010a44: movew %d0,%sr 0x40010a46: rts Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Thomas Huth Message-Id: <20171221083057.17942-1-laurent@vivier.eu> --- target/m68k/Makefile.objs | 1 + target/m68k/monitor.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 target/m68k/monitor.c diff --git a/target/m68k/Makefile.objs b/target/m68k/Makefile.objs index 39141ab93d..d143f20270 100644 --- a/target/m68k/Makefile.objs +++ b/target/m68k/Makefile.objs @@ -1,3 +1,4 @@ obj-y += m68k-semi.o obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o obj-y += gdbstub.o +obj-$(CONFIG_SOFTMMU) += monitor.o diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c new file mode 100644 index 0000000000..5605323a81 --- /dev/null +++ b/target/m68k/monitor.c @@ -0,0 +1,39 @@ +/* + * QEMU monitor for m68k + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "monitor/hmp-target.h" + +static const MonitorDef monitor_defs[] = { + { "d0", offsetof(CPUM68KState, dregs[0]) }, + { "d1", offsetof(CPUM68KState, dregs[1]) }, + { "d2", offsetof(CPUM68KState, dregs[2]) }, + { "d3", offsetof(CPUM68KState, dregs[3]) }, + { "d4", offsetof(CPUM68KState, dregs[4]) }, + { "d5", offsetof(CPUM68KState, dregs[5]) }, + { "d6", offsetof(CPUM68KState, dregs[6]) }, + { "d7", offsetof(CPUM68KState, dregs[7]) }, + { "a0", offsetof(CPUM68KState, aregs[0]) }, + { "a1", offsetof(CPUM68KState, aregs[1]) }, + { "a2", offsetof(CPUM68KState, aregs[2]) }, + { "a3", offsetof(CPUM68KState, aregs[3]) }, + { "a4", offsetof(CPUM68KState, aregs[4]) }, + { "a5", offsetof(CPUM68KState, aregs[5]) }, + { "a6", offsetof(CPUM68KState, aregs[6]) }, + { "a7", offsetof(CPUM68KState, aregs[7]) }, + { "pc", offsetof(CPUM68KState, pc) }, + { "sr", offsetof(CPUM68KState, sr) }, + { "ssp", offsetof(CPUM68KState, sp[0]) }, + { "usp", offsetof(CPUM68KState, sp[1]) }, + { NULL }, +}; + +const MonitorDef *target_monitor_defs(void) +{ + return monitor_defs; +} From 7deddf96e94f3e1eb3677db0ea7b53e61751b544 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 21 Dec 2017 17:05:58 +0100 Subject: [PATCH 345/546] target/m68k: fix set_cc_op() The first call of set_cc_op() in a new translation sequence is done with old_op set to CC_OP_DYNAMIC (-1). This will do an out of bound access to the array cc_op_live[]. We fix that by adding an entry in cc_op_live[] for CC_OP_DYNAMIC. Reported-by: Thomas Huth Signed-off-by: Laurent Vivier Reviewed-by: Paolo Bonzini Reviewed-by: Richard Henderson Message-Id: <20171221160558.14151-1-laurent@vivier.eu> --- target/m68k/cpu.h | 2 +- target/m68k/translate.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index afae5f68ac..5d03764eab 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -182,7 +182,7 @@ void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); */ typedef enum { /* Translator only -- use env->cc_op. */ - CC_OP_DYNAMIC = -1, + CC_OP_DYNAMIC, /* Each flag bit computed into cc_[xcnvz]. */ CC_OP_FLAGS, diff --git a/target/m68k/translate.c b/target/m68k/translate.c index dfb2d5dad2..bbda7399ec 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -202,6 +202,7 @@ typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); #endif static const uint8_t cc_op_live[CC_OP_NB] = { + [CC_OP_DYNAMIC] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X, [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X, [CC_OP_ADDB ... CC_OP_ADDL] = CCF_X | CCF_N | CCF_V, [CC_OP_SUBB ... CC_OP_SUBL] = CCF_X | CCF_N | CCF_V, From 598a29f3606c4c7042a1ca3f1116663d0a60867c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 30 Nov 2017 09:53:04 +0100 Subject: [PATCH 346/546] tests/boot-serial-test: Add support for the mcf5208evb board We can output a character quite easily here with some few lines of assembly that we provide as a mini-kernel for this board. Signed-off-by: Thomas Huth Message-Id: <1512031988-32490-4-git-send-email-thuth@redhat.com> [lv: add boot-serial-test in check-qtest-m68k] Signed-off-by: Laurent Vivier --- tests/Makefile.include | 2 ++ tests/boot-serial-test.c | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/tests/Makefile.include b/tests/Makefile.include index f8e20d9f5d..77f8183117 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -297,6 +297,8 @@ gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y) check-qtest-alpha-y = tests/boot-serial-test$(EXESUF) +check-qtest-m68k-y = tests/boot-serial-test$(EXESUF) + check-qtest-mips-y = tests/endianness-test$(EXESUF) check-qtest-mips64-y = tests/endianness-test$(EXESUF) diff --git a/tests/boot-serial-test.c b/tests/boot-serial-test.c index d99726919e..dd3828c49b 100644 --- a/tests/boot-serial-test.c +++ b/tests/boot-serial-test.c @@ -16,6 +16,14 @@ #include "qemu/osdep.h" #include "libqtest.h" +static const uint8_t kernel_mcf5208[] = { + 0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00, /* lea 0xfc060000,%a0 */ + 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */ + 0x11, 0x7c, 0x00, 0x04, 0x00, 0x08, /* move.b #4,8(%a0) Enable TX */ + 0x11, 0x40, 0x00, 0x0c, /* move.b %d0,12(%a0) Print 'T' */ + 0x60, 0xfa /* bra.s loop */ +}; + typedef struct testdef { const char *arch; /* Target architecture */ const char *machine; /* Name of the machine */ @@ -41,6 +49,8 @@ static testdef_t tests[] = { { "x86_64", "q35", "-device sga", "SGABIOS" }, { "s390x", "s390-ccw-virtio", "-nodefaults -device sclpconsole,chardev=serial0", "virtio device" }, + { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 }, + { NULL } }; From 43ab9a5376c95c61ae898a222c4d04bdf60e239b Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 21 Dec 2017 22:11:03 +0100 Subject: [PATCH 347/546] hw/i386/vmport: fix missing definitions with non-log trace backends When compiled with anything other than the 'log' trace backend, we have: error: implicit declaration of function 'qemu_log_mask' error: 'LOG_UNIMP' undeclared (first use in this function) This patch adds the missing include. Fixes: 7299e1a411 ("hw/i386/vmport: replace fprintf() by trace events or LOG_UNIMP") Signed-off-by: Laurent Vivier Message-id: 20171221211103.30311-1-laurent@vivier.eu [PMM: fixed commit message description of when problem occurs] Signed-off-by: Peter Maydell --- hw/i386/vmport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 9b8c68806e..116aa09819 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -27,6 +27,7 @@ #include "hw/i386/pc.h" #include "sysemu/hw_accel.h" #include "hw/qdev.h" +#include "qemu/log.h" #include "trace.h" #define VMPORT_CMD_GETVERSION 0x0a From 7d08c73e7bdc39b10e5f2f5acdce700f17ffe962 Mon Sep 17 00:00:00 2001 From: Ed Swierk via Qemu-devel Date: Tue, 14 Nov 2017 15:23:33 -0800 Subject: [PATCH 348/546] e1000, e1000e: Move per-packet TX offload flags out of context state sum_needed and cptse flags are received from the guest within each transmit data descriptor. They are not part of the offload context; instead, they determine how to apply a previously received context to the packet being transmitted: - If cptse is set, perform both segmentation and checksum offload using the parameters in the TSO context; otherwise just do checksum offload. (Currently the e1000 device incorrectly stores only one context, which will be fixed in a subsequent patch.) - Depending on the bits set in sum_needed, possibly perform L4 checksum offload and/or IP checksum offload, using the parameters in the appropriate context. Move these flags out of struct e1000x_txd_props, which is otherwise dedicated to storing values from a context descriptor, and into the per-packet TX struct. Signed-off-by: Ed Swierk Signed-off-by: Jason Wang --- hw/net/e1000.c | 30 ++++++++++++++++-------------- hw/net/e1000e.c | 4 ++-- hw/net/e1000e_core.c | 16 ++++++++-------- hw/net/e1000e_core.h | 2 ++ hw/net/e1000x_common.h | 2 -- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 05a00cba31..30aef93dad 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -98,6 +98,8 @@ typedef struct E1000State_st { unsigned char data[0x10000]; uint16_t size; unsigned char vlan_needed; + unsigned char sum_needed; + bool cptse; e1000x_txd_props props; uint16_t tso_frames; } tx; @@ -540,7 +542,7 @@ xmit_seg(E1000State *s) unsigned int frames = s->tx.tso_frames, css, sofar; struct e1000_tx *tp = &s->tx; - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { css = tp->props.ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); @@ -564,7 +566,7 @@ xmit_seg(E1000State *s) } } else /* UDP */ stw_be_p(tp->data+css+4, len); - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation void *sp = tp->data + tp->props.tucso; @@ -576,11 +578,11 @@ xmit_seg(E1000State *s) tp->tso_frames++; } - if (tp->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { putsum(tp->data, tp->size, tp->props.tucso, tp->props.tucss, tp->props.tucse); } - if (tp->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { putsum(tp->data, tp->size, tp->props.ipcso, tp->props.ipcss, tp->props.ipcse); } @@ -624,17 +626,17 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { // data descriptor if (tp->size == 0) { - tp->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8; } - tp->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tp->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; } else { // legacy descriptor - tp->props.cptse = 0; + tp->cptse = 0; } if (e1000x_vlan_enabled(s->mac_reg) && e1000x_is_vlan_txd(txd_lower) && - (tp->props.cptse || txd_lower & E1000_TXD_CMD_EOP)) { + (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) { tp->vlan_needed = 1; stw_be_p(tp->vlan_header, le16_to_cpu(s->mac_reg[VET])); @@ -643,7 +645,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } addr = le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->props.cptse) { + if (tp->props.tse && tp->cptse) { msh = tp->props.hdr_len + tp->props.mss; do { bytes = split_size; @@ -665,7 +667,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } split_size -= bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->props.cptse) { + } else if (!tp->props.tse && tp->cptse) { // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentation error\n"); } else { @@ -676,14 +678,14 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->props.cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { xmit_seg(s); } tp->tso_frames = 0; - tp->props.sum_needed = 0; + tp->sum_needed = 0; tp->vlan_needed = 0; tp->size = 0; - tp->props.cptse = 0; + tp->cptse = 0; } static uint32_t @@ -1461,7 +1463,7 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT16(tx.props.mss, E1000State), VMSTATE_UINT16(tx.size, E1000State), VMSTATE_UINT16(tx.tso_frames, E1000State), - VMSTATE_UINT8(tx.props.sum_needed, E1000State), + VMSTATE_UINT8(tx.sum_needed, E1000State), VMSTATE_INT8(tx.props.ip, E1000State), VMSTATE_INT8(tx.props.tcp, E1000State), VMSTATE_BUFFER(tx.header, E1000State), diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index f1af279e8d..191398a3d5 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -556,7 +556,7 @@ static const VMStateDescription e1000e_vmstate_tx = { .version_id = 1, .minimum_version_id = 1, .fields = (VMStateField[]) { - VMSTATE_UINT8(props.sum_needed, struct e1000e_tx), + VMSTATE_UINT8(sum_needed, struct e1000e_tx), VMSTATE_UINT8(props.ipcss, struct e1000e_tx), VMSTATE_UINT8(props.ipcso, struct e1000e_tx), VMSTATE_UINT16(props.ipcse, struct e1000e_tx), @@ -569,7 +569,7 @@ static const VMStateDescription e1000e_vmstate_tx = { VMSTATE_INT8(props.ip, struct e1000e_tx), VMSTATE_INT8(props.tcp, struct e1000e_tx), VMSTATE_BOOL(props.tse, struct e1000e_tx), - VMSTATE_BOOL(props.cptse, struct e1000e_tx), + VMSTATE_BOOL(cptse, struct e1000e_tx), VMSTATE_BOOL(skip_cp, struct e1000e_tx), VMSTATE_END_OF_LIST() } diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index 43a8d89955..c93c4661ed 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -632,18 +632,18 @@ e1000e_rss_parse_packet(E1000ECore *core, static void e1000e_setup_tx_offloads(E1000ECore *core, struct e1000e_tx *tx) { - if (tx->props.tse && tx->props.cptse) { + if (tx->props.tse && tx->cptse) { net_tx_pkt_build_vheader(tx->tx_pkt, true, true, tx->props.mss); net_tx_pkt_update_ip_checksums(tx->tx_pkt); e1000x_inc_reg_if_not_full(core->mac, TSCTC); return; } - if (tx->props.sum_needed & E1000_TXD_POPTS_TXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_TXSM) { net_tx_pkt_build_vheader(tx->tx_pkt, false, true, 0); } - if (tx->props.sum_needed & E1000_TXD_POPTS_IXSM) { + if (tx->sum_needed & E1000_TXD_POPTS_IXSM) { net_tx_pkt_update_ip_hdr_checksum(tx->tx_pkt); } } @@ -715,13 +715,13 @@ e1000e_process_tx_desc(E1000ECore *core, return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { /* data descriptor */ - tx->props.sum_needed = le32_to_cpu(dp->upper.data) >> 8; - tx->props.cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; + tx->sum_needed = le32_to_cpu(dp->upper.data) >> 8; + tx->cptse = (txd_lower & E1000_TXD_CMD_TSE) ? 1 : 0; e1000e_process_ts_option(core, dp); } else { /* legacy descriptor */ e1000e_process_ts_option(core, dp); - tx->props.cptse = 0; + tx->cptse = 0; } addr = le64_to_cpu(dp->buffer_addr); @@ -747,8 +747,8 @@ e1000e_process_tx_desc(E1000ECore *core, tx->skip_cp = false; net_tx_pkt_reset(tx->tx_pkt); - tx->props.sum_needed = 0; - tx->props.cptse = 0; + tx->sum_needed = 0; + tx->cptse = 0; } } diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h index 1ff6978ca1..7d8ff41890 100644 --- a/hw/net/e1000e_core.h +++ b/hw/net/e1000e_core.h @@ -71,6 +71,8 @@ struct E1000Core { e1000x_txd_props props; bool skip_cp; + unsigned char sum_needed; + bool cptse; struct NetTxPkt *tx_pkt; } tx[E1000E_NUM_QUEUES]; diff --git a/hw/net/e1000x_common.h b/hw/net/e1000x_common.h index 3072ce9d50..0268884e72 100644 --- a/hw/net/e1000x_common.h +++ b/hw/net/e1000x_common.h @@ -193,7 +193,6 @@ void e1000x_update_regs_on_autoneg_done(uint32_t *mac, uint16_t *phy); void e1000x_increase_size_stats(uint32_t *mac, const int *size_regs, int size); typedef struct e1000x_txd_props { - unsigned char sum_needed; uint8_t ipcss; uint8_t ipcso; uint16_t ipcse; @@ -206,7 +205,6 @@ typedef struct e1000x_txd_props { int8_t ip; int8_t tcp; bool tse; - bool cptse; } e1000x_txd_props; void e1000x_read_tx_ctx_descr(struct e1000_context_desc *d, From d62644b46a86bce2c069af7122501e3ffd349d3c Mon Sep 17 00:00:00 2001 From: Ed Swierk via Qemu-devel Date: Tue, 14 Nov 2017 15:23:34 -0800 Subject: [PATCH 349/546] e1000: Separate TSO and non-TSO contexts, fixing UDP TX corruption The device is supposed to maintain two distinct contexts for transmit offloads: one has parameters for both segmentation and checksum offload, the other only for checksum offload. The guest driver can send two context descriptors, one for each context (the TSE flag specifies which). Then the guest can refer to one or the other context in subsequent transmit data descriptors, depending on what offloads it wants applied to each packet. Currently the e1000 device stores just one context, and misinterprets the TSE flags in the context and data descriptors. This is often okay: Linux happens to send a fresh context descriptor before every data descriptor, so forgetting the other context doesn't matter. Windows does rely on separate contexts for TSO vs. non-TSO packets, but for mostly-TCP traffic the two contexts have identical TCP-specific offload parameters so confusing them doesn't matter. One case where this confusion matters is when a Windows guest sets up a TSO context for TCP and a non-TSO context for UDP, and then transmits both TCP and UDP traffic in parallel. The e1000 device sometimes ends up using TCP-specific parameters while doing checksum offload on a UDP datagram: it writes the checksum to offset 16 (the correct location for a TCP checksum), stomping on two bytes of UDP data, and leaving the wrong value in the actual UDP checksum field at offset 6. (Even worse, the host network stack may then recompute the UDP checksum, "correcting" it to match the corrupt data before sending it out a physical interface.) Correct this by tracking the TSO context independently of the non-TSO context, and selecting the appropriate context based on the TSE flag in each transmit data descriptor. Signed-off-by: Ed Swierk Signed-off-by: Jason Wang --- hw/net/e1000.c | 70 ++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 30aef93dad..804ec08721 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -101,6 +101,7 @@ typedef struct E1000State_st { unsigned char sum_needed; bool cptse; e1000x_txd_props props; + e1000x_txd_props tso_props; uint16_t tso_frames; } tx; @@ -541,35 +542,37 @@ xmit_seg(E1000State *s) uint16_t len; unsigned int frames = s->tx.tso_frames, css, sofar; struct e1000_tx *tp = &s->tx; + struct e1000x_txd_props *props = tp->cptse ? &tp->tso_props : &tp->props; - if (tp->props.tse && tp->cptse) { - css = tp->props.ipcss; + if (tp->cptse) { + css = props->ipcss; DBGOUT(TXSUM, "frames %d size %d ipcss %d\n", frames, tp->size, css); - if (tp->props.ip) { /* IPv4 */ + if (props->ip) { /* IPv4 */ stw_be_p(tp->data+css+2, tp->size - css); stw_be_p(tp->data+css+4, lduw_be_p(tp->data + css + 4) + frames); } else { /* IPv6 */ stw_be_p(tp->data+css+4, tp->size - css); } - css = tp->props.tucss; + css = props->tucss; len = tp->size - css; - DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->props.tcp, css, len); - if (tp->props.tcp) { - sofar = frames * tp->props.mss; + DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", props->tcp, css, len); + if (props->tcp) { + sofar = frames * props->mss; stl_be_p(tp->data+css+4, ldl_be_p(tp->data+css+4)+sofar); /* seq */ - if (tp->props.paylen - sofar > tp->props.mss) { + if (props->paylen - sofar > props->mss) { tp->data[css + 13] &= ~9; /* PSH, FIN */ } else if (frames) { e1000x_inc_reg_if_not_full(s->mac_reg, TSCTC); } - } else /* UDP */ + } else { /* UDP */ stw_be_p(tp->data+css+4, len); + } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { unsigned int phsum; // add pseudo-header length before checksum calculation - void *sp = tp->data + tp->props.tucso; + void *sp = tp->data + props->tucso; phsum = lduw_be_p(sp) + len; phsum = (phsum >> 16) + (phsum & 0xffff); @@ -579,12 +582,10 @@ xmit_seg(E1000State *s) } if (tp->sum_needed & E1000_TXD_POPTS_TXSM) { - putsum(tp->data, tp->size, tp->props.tucso, - tp->props.tucss, tp->props.tucse); + putsum(tp->data, tp->size, props->tucso, props->tucss, props->tucse); } if (tp->sum_needed & E1000_TXD_POPTS_IXSM) { - putsum(tp->data, tp->size, tp->props.ipcso, - tp->props.ipcss, tp->props.ipcse); + putsum(tp->data, tp->size, props->ipcso, props->ipcss, props->ipcse); } if (tp->vlan_needed) { memmove(tp->vlan, tp->data, 4); @@ -616,11 +617,11 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) s->mit_ide |= (txd_lower & E1000_TXD_CMD_IDE); if (dtype == E1000_TXD_CMD_DEXT) { /* context descriptor */ - e1000x_read_tx_ctx_descr(xp, &tp->props); - tp->tso_frames = 0; - if (tp->props.tucso == 0) { /* this is probably wrong */ - DBGOUT(TXSUM, "TCP/UDP: cso 0!\n"); - tp->props.tucso = tp->props.tucss + (tp->props.tcp ? 16 : 6); + if (le32_to_cpu(xp->cmd_and_length) & E1000_TXD_CMD_TSE) { + e1000x_read_tx_ctx_descr(xp, &tp->tso_props); + tp->tso_frames = 0; + } else { + e1000x_read_tx_ctx_descr(xp, &tp->props); } return; } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) { @@ -645,8 +646,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) } addr = le64_to_cpu(dp->buffer_addr); - if (tp->props.tse && tp->cptse) { - msh = tp->props.hdr_len + tp->props.mss; + if (tp->cptse) { + msh = tp->tso_props.hdr_len + tp->tso_props.mss; do { bytes = split_size; if (tp->size + bytes > msh) @@ -655,21 +656,19 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(d, addr, tp->data + tp->size, bytes); sz = tp->size + bytes; - if (sz >= tp->props.hdr_len && tp->size < tp->props.hdr_len) { - memmove(tp->header, tp->data, tp->props.hdr_len); + if (sz >= tp->tso_props.hdr_len + && tp->size < tp->tso_props.hdr_len) { + memmove(tp->header, tp->data, tp->tso_props.hdr_len); } tp->size = sz; addr += bytes; if (sz == msh) { xmit_seg(s); - memmove(tp->data, tp->header, tp->props.hdr_len); - tp->size = tp->props.hdr_len; + memmove(tp->data, tp->header, tp->tso_props.hdr_len); + tp->size = tp->tso_props.hdr_len; } split_size -= bytes; } while (bytes && split_size); - } else if (!tp->props.tse && tp->cptse) { - // context descriptor TSE is not set, while data descriptor TSE is set - DBGOUT(TXERR, "TCP segmentation error\n"); } else { split_size = MIN(sizeof(tp->data) - tp->size, split_size); pci_dma_read(d, addr, tp->data + tp->size, split_size); @@ -678,7 +677,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) if (!(txd_lower & E1000_TXD_CMD_EOP)) return; - if (!(tp->props.tse && tp->cptse && tp->size < tp->props.hdr_len)) { + if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { xmit_seg(s); } tp->tso_frames = 0; @@ -1437,7 +1436,7 @@ static const VMStateDescription vmstate_e1000_full_mac_state = { static const VMStateDescription vmstate_e1000 = { .name = "e1000", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .pre_save = e1000_pre_save, .post_load = e1000_post_load, @@ -1510,6 +1509,17 @@ static const VMStateDescription vmstate_e1000 = { VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128), VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128), + VMSTATE_UINT8_V(tx.tso_props.ipcss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.ipcso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.ipcse, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucss, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.tucso, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.tucse, E1000State, 3), + VMSTATE_UINT32_V(tx.tso_props.paylen, E1000State, 3), + VMSTATE_UINT8_V(tx.tso_props.hdr_len, E1000State, 3), + VMSTATE_UINT16_V(tx.tso_props.mss, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.ip, E1000State, 3), + VMSTATE_INT8_V(tx.tso_props.tcp, E1000State, 3), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription*[]) { From eaba8f34f0dac5e9296df9c2046d9601264c46a4 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:43 +0000 Subject: [PATCH 350/546] net: move CRC32 calculation from compute_mcast_idx() into its own net_crc32() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate out the standard ethernet CRC32 calculation into a new net_crc32() function, renaming the constant POLYNOMIAL to POLYNOMIAL_BE to make it clear that this is a big-endian CRC32 calculation. As part of the constant rename, remove the duplicate definition of POLYNOMIAL from eepro100.c and use the new POLYNOMIAL_BE constant instead. Once this is complete remove the existing CRC32 implementation from compute_mcast_idx() and call the new net_crc32() function in its place. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/eepro100.c | 4 +--- include/net/net.h | 3 ++- net/net.c | 16 +++++++++++----- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 1c0def555b..71cddfece4 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -323,8 +323,6 @@ static const uint16_t eepro100_mdi_mask[] = { 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; -#define POLYNOMIAL 0x04c11db6 - static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); /* From FreeBSD (locally modified). */ @@ -342,7 +340,7 @@ static unsigned e100_compute_mcast_idx(const uint8_t *ep) crc <<= 1; b >>= 1; if (carry) { - crc = ((crc ^ POLYNOMIAL) | carry); + crc = ((crc ^ POLYNOMIAL_BE) | carry); } } } diff --git a/include/net/net.h b/include/net/net.h index 1c55a93588..586098cb94 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -227,7 +227,8 @@ NetClientState *net_hub_port_find(int hub_id); void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd); -#define POLYNOMIAL 0x04c11db6 +#define POLYNOMIAL_BE 0x04c11db6 +uint32_t net_crc32(const uint8_t *p, int len); unsigned compute_mcast_idx(const uint8_t *ep); #define vmstate_offset_macaddr(_state, _field) \ diff --git a/net/net.c b/net/net.c index 39ef546708..a14dc9910c 100644 --- a/net/net.c +++ b/net/net.c @@ -1581,25 +1581,31 @@ int net_client_parse(QemuOptsList *opts_list, const char *optarg) /* From FreeBSD */ /* XXX: optimize */ -unsigned compute_mcast_idx(const uint8_t *ep) +uint32_t net_crc32(const uint8_t *p, int len) { uint32_t crc; int carry, i, j; uint8_t b; crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; + for (i = 0; i < len; i++) { + b = *p++; for (j = 0; j < 8; j++) { carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); crc <<= 1; b >>= 1; if (carry) { - crc = ((crc ^ POLYNOMIAL) | carry); + crc = ((crc ^ POLYNOMIAL_BE) | carry); } } } - return crc >> 26; + + return crc; +} + +unsigned compute_mcast_idx(const uint8_t *ep) +{ + return net_crc32(ep, ETH_ALEN) >> 26; } QemuOptsList qemu_netdev_opts = { From f1a7deb900f4d87ca7ff602454e35aa65ff81567 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:44 +0000 Subject: [PATCH 351/546] net: introduce net_crc32_le() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This provides a standard ethernet CRC32 little-endian implementation. Signed-off-by: Mark Cave-Ayland Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- include/net/net.h | 2 ++ net/net.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/net/net.h b/include/net/net.h index 586098cb94..4afac1a9dd 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -228,7 +228,9 @@ NetClientState *net_hub_port_find(int hub_id); void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd); #define POLYNOMIAL_BE 0x04c11db6 +#define POLYNOMIAL_LE 0xedb88320 uint32_t net_crc32(const uint8_t *p, int len); +uint32_t net_crc32_le(const uint8_t *p, int len); unsigned compute_mcast_idx(const uint8_t *ep); #define vmstate_offset_macaddr(_state, _field) \ diff --git a/net/net.c b/net/net.c index a14dc9910c..4ecaf80bd1 100644 --- a/net/net.c +++ b/net/net.c @@ -1603,6 +1603,28 @@ uint32_t net_crc32(const uint8_t *p, int len) return crc; } +uint32_t net_crc32_le(const uint8_t *p, int len) +{ + uint32_t crc; + int carry, i, j; + uint8_t b; + + crc = 0xffffffff; + for (i = 0; i < len; i++) { + b = *p++; + for (j = 0; j < 8; j++) { + carry = (crc & 0x1) ^ (b & 0x01); + crc >>= 1; + b >>= 1; + if (carry) { + crc ^= POLYNOMIAL_LE; + } + } + } + + return crc; +} + unsigned compute_mcast_idx(const uint8_t *ep) { return net_crc32(ep, ETH_ALEN) >> 26; From cbbeca91819c8e08f4b85777f8dd1671314db586 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:45 +0000 Subject: [PATCH 352/546] pcnet: switch pcnet over to use net_crc32_le() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of lnc_mchash() using its own implementation, we can simply call net_crc32_le() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/pcnet.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c index 654455355f..39d5d93525 100644 --- a/hw/net/pcnet.c +++ b/hw/net/pcnet.c @@ -38,6 +38,7 @@ #include "qemu/osdep.h" #include "hw/qdev.h" #include "net/net.h" +#include "net/eth.h" #include "qemu/timer.h" #include "qemu/sockets.h" #include "sysemu/sysemu.h" @@ -522,25 +523,6 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, be16_to_cpu(hdr->ether_type)); \ } while (0) -#define MULTICAST_FILTER_LEN 8 - -static inline uint32_t lnc_mchash(const uint8_t *ether_addr) -{ -#define LNC_POLYNOMIAL 0xEDB88320UL - uint32_t crc = 0xFFFFFFFF; - int idx, bit; - uint8_t data; - - for (idx = 0; idx < 6; idx++) { - for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { - crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); - data >>= 1; - } - } - return crc; -#undef LNC_POLYNOMIAL -} - #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) /* generated using the AUTODIN II polynomial @@ -656,7 +638,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) s->csr[10] & 0xff, s->csr[10] >> 8, s->csr[11] & 0xff, s->csr[11] >> 8 }; - int index = lnc_mchash(hdr->ether_dhost) >> 26; + int index = net_crc32_le(hdr->ether_dhost, ETH_ALEN) >> 26; return !!(ladr[index >> 3] & (1 << (index & 7))); } return 0; From 7c0348bd633aff5ff27d5c393008495175ca416b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:46 +0000 Subject: [PATCH 353/546] eepro100: switch eepro100 e100_compute_mcast_idx() over to use net_crc32() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of e100_compute_mcast_idx() using its own implementation, we can simply call net_crc32() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Stefan Weil Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/eepro100.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 71cddfece4..e30fed830b 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -44,6 +44,7 @@ #include "hw/hw.h" #include "hw/pci/pci.h" #include "net/net.h" +#include "net/eth.h" #include "hw/nvram/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" @@ -325,28 +326,6 @@ static const uint16_t eepro100_mdi_mask[] = { static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s); -/* From FreeBSD (locally modified). */ -static unsigned e100_compute_mcast_idx(const uint8_t *ep) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) { - crc = ((crc ^ POLYNOMIAL_BE) | carry); - } - } - } - return (crc & BITS(7, 2)) >> 2; -} - /* Read a 16 bit control/status (CSR) register. */ static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr) { @@ -843,7 +822,8 @@ static void set_multicast_list(EEPRO100State *s) uint8_t multicast_addr[6]; pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6); TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6))); - unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr); + unsigned mcast_idx = (net_crc32(multicast_addr, ETH_ALEN) & + BITS(7, 2)) >> 2; assert(mcast_idx < 64); s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7)); } @@ -1679,7 +1659,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) if (s->configuration[21] & BIT(3)) { /* Multicast all bit is set, receive all multicast frames. */ } else { - unsigned mcast_idx = e100_compute_mcast_idx(buf); + unsigned mcast_idx = (net_crc32(buf, ETH_ALEN) & BITS(7, 2)) >> 2; assert(mcast_idx < 64); if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) { /* Multicast frame is allowed in hash table. */ From a89a6b052abff87871800406bd3c598fcf406426 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:47 +0000 Subject: [PATCH 354/546] sunhme: switch sunhme over to use net_crc32_le() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of sunhme_crc32_le() using its own implementation, we can simply call net_crc32_le() directly and apply the bit shift inline. Signed-off-by: Mark Cave-Ayland Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/sunhme.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index b1efa1b88d..7558fca8f9 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -698,29 +698,6 @@ static inline void sunhme_set_rx_ring_nr(SunHMEState *s, int i) s->erxregs[HME_ERXI_RING >> 2] = ring; } -#define POLYNOMIAL_LE 0xedb88320 -static uint32_t sunhme_crc32_le(const uint8_t *p, int len) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < len; i++) { - b = *p++; - for (j = 0; j < 8; j++) { - carry = (crc & 0x1) ^ (b & 0x01); - crc >>= 1; - b >>= 1; - if (carry) { - crc = crc ^ POLYNOMIAL_LE; - } - } - } - - return crc; -} - #define MIN_BUF_SIZE 60 static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf, @@ -761,7 +738,7 @@ static ssize_t sunhme_receive(NetClientState *nc, const uint8_t *buf, trace_sunhme_rx_filter_bcast_match(); } else if (s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_HENABLE) { /* Didn't match local address, check hash filter */ - int mcast_idx = sunhme_crc32_le(buf, 6) >> 26; + int mcast_idx = net_crc32_le(buf, ETH_ALEN) >> 26; if (!(s->macregs[(HME_MACI_HASHTAB0 >> 2) - (mcast_idx >> 4)] & (1 << (mcast_idx & 0xf)))) { /* Didn't match hash filter */ From 8f90bc2f8fbba3c98116e80afd537fb0ca90be2e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:48 +0000 Subject: [PATCH 355/546] sungem: fix multicast filter CRC calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the Linux sungem driver, we know that the multicast filter CRC is implemented using ether_crc_le() which isn't the same as calling zlib's crc32() function (the zlib implementation requires a complemented initial value and also returns the complemented result). Fix the multicast filter by simply using the new net_crc32_le() function. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Jason Wang --- hw/net/sungem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 6aa8d1117b..60f1e479f3 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -11,12 +11,11 @@ #include "hw/pci/pci.h" #include "qemu/log.h" #include "net/net.h" +#include "net/eth.h" #include "net/checksum.h" #include "hw/net/mii.h" #include "sysemu/sysemu.h" #include "trace.h" -/* For crc32 */ -#include #define TYPE_SUNGEM "sungem" @@ -595,7 +594,7 @@ static ssize_t sungem_receive(NetClientState *nc, const uint8_t *buf, } /* Get MAC crc */ - mac_crc = crc32(~0, buf, 6); + mac_crc = net_crc32_le(buf, ETH_ALEN); /* Packet isn't for me ? */ rx_cond = sungem_check_rx_mac(s, buf, mac_crc); From d00d6d005424dd2447f8b0394e945909852a4282 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:49 +0000 Subject: [PATCH 356/546] eepro100: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/eepro100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index e30fed830b..a07a63247e 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -1679,7 +1679,7 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) rfd_status |= 0x0004; } else if (s->configuration[20] & BIT(6)) { /* Multiple IA bit set. */ - unsigned mcast_idx = compute_mcast_idx(buf); + unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; assert(mcast_idx < 64); if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) { TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s)); From 308913bb431104f34f5c2e35eaaf297ff3e8ec7b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:50 +0000 Subject: [PATCH 357/546] opencores_eth: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/opencores_eth.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 268d6a7892..d42b79c08c 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -36,6 +36,7 @@ #include "hw/net/mii.h" #include "hw/sysbus.h" #include "net/net.h" +#include "net/eth.h" #include "sysemu/sysemu.h" #include "trace.h" @@ -373,7 +374,7 @@ static ssize_t open_eth_receive(NetClientState *nc, if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) { miss = GET_REGBIT(s, MODER, BRO); } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) { - unsigned mcast_idx = compute_mcast_idx(buf); + unsigned mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; miss = !(s->regs[HASH0 + mcast_idx / 32] & (1 << (mcast_idx % 32))); trace_open_eth_receive_mcast( From eedeaee73ac47341efca4c06e3ccb0029ee9332f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:51 +0000 Subject: [PATCH 358/546] lan9118: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/lan9118.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index 3db8937cac..b9032dac59 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "net/net.h" +#include "net/eth.h" #include "hw/devices.h" #include "sysemu/sysemu.h" #include "hw/ptimer.h" @@ -504,7 +505,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) } } else { /* Hash matching */ - hash = compute_mcast_idx(addr); + hash = net_crc32(addr, ETH_ALEN) >> 26; if (hash & 0x20) { return (s->mac_hashh >> (hash & 0x1f)) & 1; } else { From 4227be63f081e939ae7313b1921d8f60a5d8d714 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:52 +0000 Subject: [PATCH 359/546] ftgmac100: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/ftgmac100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 3c36ab9cec..704f452067 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -762,7 +762,7 @@ static int ftgmac100_filter(FTGMAC100State *s, const uint8_t *buf, size_t len) } /* TODO: this does not seem to work for ftgmac100 */ - mcast_idx = compute_mcast_idx(buf); + mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->math[mcast_idx / 32] & (1 << (mcast_idx % 32)))) { return 0; } From 084e2b111bb9c809fd53563e3b5ef1ea3bef08ad Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:53 +0000 Subject: [PATCH 360/546] ne2000: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/ne2000.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 6874c8c6b9..687ef84aac 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -23,6 +23,8 @@ */ #include "qemu/osdep.h" #include "hw/pci/pci.h" +#include "net/net.h" +#include "net/eth.h" #include "ne2000.h" #include "hw/loader.h" #include "sysemu/sysemu.h" @@ -199,7 +201,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_) /* multicast */ if (!(s->rxcr & 0x08)) return size; - mcast_idx = compute_mcast_idx(buf); + mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) return size; } else if (s->mem[0] == buf[0] && From e7a58fc71ca039ae46590e9395467cea283d259c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:54 +0000 Subject: [PATCH 361/546] rtl8139: use inline net_crc32() and bitshift instead of compute_mcast_idx() This makes it much easier to compare the multicast CRC calculation endian and bitshift against the Linux driver implementation. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- hw/net/rtl8139.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index a6b2a9f7a4..1cc95b8cba 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -882,7 +882,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t return size; } - int mcast_idx = compute_mcast_idx(buf); + int mcast_idx = net_crc32(buf, ETH_ALEN) >> 26; if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { From d9caeb09b107e91122d10ba4a08a4af2b59c69cf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 15 Dec 2017 18:41:55 +0000 Subject: [PATCH 362/546] net: remove unused compute_mcast_idx() function Now that all of the callers have been converted to compute the multicast index inline using new net CRC functions, this function can now be dropped. Signed-off-by: Mark Cave-Ayland Signed-off-by: Jason Wang --- net/net.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/net.c b/net/net.c index 4ecaf80bd1..5bc0a343ae 100644 --- a/net/net.c +++ b/net/net.c @@ -1625,11 +1625,6 @@ uint32_t net_crc32_le(const uint8_t *p, int len) return crc; } -unsigned compute_mcast_idx(const uint8_t *ep) -{ - return net_crc32(ep, ETH_ALEN) >> 26; -} - QemuOptsList qemu_netdev_opts = { .name = "netdev", .implied_opt_name = "type", From 3a22ee27340aee063b442daa37ae684e9a114a91 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 19 Dec 2017 16:28:54 +0100 Subject: [PATCH 363/546] net: Remove the legacy "-net channel" parameter It has never been documented, so hardly anybody knows about this parameter, and it is marked as deprecated since QEMU v2.6. Time to let it go now. Reviewed-by: Samuel Thibault Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- include/net/slirp.h | 2 -- net/net.c | 7 ------- net/slirp.c | 34 ---------------------------------- qemu-doc.texi | 5 ----- 4 files changed, 48 deletions(-) diff --git a/include/net/slirp.h b/include/net/slirp.h index 64b795cda9..0c98e463db 100644 --- a/include/net/slirp.h +++ b/include/net/slirp.h @@ -36,8 +36,6 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict); int net_slirp_redir(const char *redir_str); -int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret); - int net_slirp_smb(const char *exported_dir); void hmp_info_usernet(Monitor *mon, const QDict *qdict); diff --git a/net/net.c b/net/net.c index 5bc0a343ae..2b81c93193 100644 --- a/net/net.c +++ b/net/net.c @@ -1565,13 +1565,6 @@ int net_init_clients(void) int net_client_parse(QemuOptsList *opts_list, const char *optarg) { -#if defined(CONFIG_SLIRP) - int ret; - if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { - return ret; - } -#endif - if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { return -1; } diff --git a/net/slirp.c b/net/slirp.c index 318a26e892..cb8ca2312f 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -956,37 +956,3 @@ int net_init_slirp(const Netdev *netdev, const char *name, return ret; } - -int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) -{ - if (strcmp(opts_list->name, "net") != 0 || - strncmp(optarg, "channel,", strlen("channel,")) != 0) { - return 0; - } - - error_report("The '-net channel' option is deprecated. " - "Please use '-netdev user,guestfwd=...' instead."); - - /* handle legacy -net channel,port:chr */ - optarg += strlen("channel,"); - - if (QTAILQ_EMPTY(&slirp_stacks)) { - struct slirp_config_str *config; - - config = g_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), optarg); - config->flags = SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - *ret = 0; - } else { - Error *err = NULL; - *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1, &err); - if (*ret < 0) { - error_report_err(err); - } - } - - return 1; -} - diff --git a/qemu-doc.texi b/qemu-doc.texi index 90bea7331d..140659a14b 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2670,11 +2670,6 @@ The ``-smb /some/dir'' argument is now a synonym for setting the ``-netdev user,smb=/some/dir'' argument instead. The new syntax allows different settings to be provided per NIC. -@subsection -net channel (since 2.6.0) - -The ``--net channel,ARGS'' argument is now a synonym for setting -the ``-netdev user,guestfwd=ARGS'' argument instead. - @subsection -net vlan (since 2.9.0) The ``-net vlan=NN'' argument is partially replaced with the From 0e60a82d9b15be9531c2567cf9f0b509006f174f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 19 Dec 2017 16:28:55 +0100 Subject: [PATCH 364/546] qemu-doc: The "-net nic" option can be used with "netdev=...", too Looks like we missed to document that it is also possible to specify a netdev with "-net nic" - which is very useful if you want to configure your on-board NIC to use a backend that has been specified with "-netdev". Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- qemu-options.hx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 94647e21e3..9f4dd3a2c1 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2035,9 +2035,10 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "-netdev hubport,id=str,hubid=n\n" " configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL) DEF("net", HAS_ARG, QEMU_OPTION_net, - "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n" - " old way to create a new NIC and connect it to VLAN 'n'\n" - " (use the '-device devtype,netdev=str' option if possible instead)\n" + "-net nic[,vlan=n][,netdev=nd][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n" + " configure or create an on-board (or machine default) NIC and\n" + " connect it either to VLAN 'n' or the netdev 'nd' (for pluggable\n" + " NICs please use '-device devtype,netdev=nd' instead)\n" "-net dump[,vlan=n][,file=f][,len=n]\n" " dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n" "-net none use it alone to have zero network devices. If no -net option\n" @@ -2058,10 +2059,11 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, " old way to initialize a host network interface\n" " (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL) STEXI -@item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}] +@item -net nic[,vlan=@var{n}][,netdev=@var{nd}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}] @findex -net -Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n} -= 0 is the default). The NIC is an e1000 by default on the PC +Configure or create an on-board (or machine default) Network Interface Card +(NIC) and connect it either to VLAN @var{n} (@var{n} = 0 is the default), or +to the netdev @var{nd}. The NIC is an e1000 by default on the PC target. Optionally, the MAC address can be changed to @var{mac}, the device address set to @var{addr} (PCI cards only), and a @var{name} can be assigned for use in monitor commands. From 0065e915192cdf83c2700bb377e5323c2649476e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 19 Dec 2017 16:28:56 +0100 Subject: [PATCH 365/546] qemu-doc: Update the deprecation information of -tftp, -bootp, -redir and -smb The information how to update the deprecated parameters was too scarce, so that some people did not update to the new syntax yet. Provide some more information to make sure that it is clear how to update from the old syntax to the new one. Signed-off-by: Thomas Huth Signed-off-by: Jason Wang --- qemu-doc.texi | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index 140659a14b..ae90f7199e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2648,27 +2648,36 @@ combined with ``-vnc tls-creds=tls0' @subsection -tftp (since 2.6.0) -The ``-tftp /some/dir'' argument is now a synonym for setting -the ``-netdev user,tftp=/some/dir' argument. The new syntax -allows different settings to be provided per NIC. +The ``-tftp /some/dir'' argument is replaced by +``-netdev user,id=x,tftp=/some/dir'', either accompanied with +``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +(for embedded NICs). The new syntax allows different settings to be +provided per NIC. @subsection -bootp (since 2.6.0) -The ``-bootp /some/file'' argument is now a synonym for setting -the ``-netdev user,bootp=/some/file' argument. The new syntax -allows different settings to be provided per NIC. +The ``-bootp /some/file'' argument is replaced by +``-netdev user,id=x,bootp=/some/file'', either accompanied with +``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +(for embedded NICs). The new syntax allows different settings to be +provided per NIC. @subsection -redir (since 2.6.0) -The ``-redir ARGS'' argument is now a synonym for setting -the ``-netdev user,hostfwd=ARGS'' argument instead. The new -syntax allows different settings to be provided per NIC. +The ``-redir [tcp|udp]:hostport:[guestaddr]:guestport'' argument is +replaced by ``-netdev +user,id=x,hostfwd=[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport'', +either accompanied with ``-device ...,netdev=x'' (for pluggable NICs) or +``-net nic,netdev=x'' (for embedded NICs). The new syntax allows different +settings to be provided per NIC. @subsection -smb (since 2.6.0) -The ``-smb /some/dir'' argument is now a synonym for setting -the ``-netdev user,smb=/some/dir'' argument instead. The new -syntax allows different settings to be provided per NIC. +The ``-smb /some/dir'' argument is replaced by +``-netdev user,id=x,smb=/some/dir'', either accompanied with +``-device ...,netdev=x'' (for pluggable NICs) or ``-net nic,netdev=x'' +(for embedded NICs). The new syntax allows different settings to be +provided per NIC. @subsection -net vlan (since 2.9.0) From 0b4c7c65f882fac328f2c97398f06f16fe6d3f12 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 8 Nov 2017 15:30:18 -0500 Subject: [PATCH 366/546] tpm_emulator: Add a caching layer for the TPM Established flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a caching layer for the TPM established flag so that we don't need to go to the emulator every time the flag is read by accessing the REG_ACCESS register. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_emulator.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 38b6f175a1..35c78de5a9 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -72,6 +72,9 @@ typedef struct TPMEmulator { Error *migration_blocker; QemuMutex mutex; + + unsigned int established_flag:1; + unsigned int established_flag_cached:1; } TPMEmulator; @@ -349,16 +352,22 @@ static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb) TPMEmulator *tpm_emu = TPM_EMULATOR(tb); ptm_est est; - DPRINTF("%s", __func__); + if (tpm_emu->established_flag_cached) { + return tpm_emu->established_flag; + } + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_GET_TPMESTABLISHED, &est, 0, sizeof(est)) < 0) { error_report("tpm-emulator: Could not get the TPM established flag: %s", strerror(errno)); return false; } - DPRINTF("established flag: %0x", est.u.resp.bit); + DPRINTF("got established flag: %0x", est.u.resp.bit); - return (est.u.resp.bit != 0); + tpm_emu->established_flag_cached = 1; + tpm_emu->established_flag = (est.u.resp.bit != 0); + + return tpm_emu->established_flag; } static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, @@ -389,6 +398,8 @@ static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb, return -1; } + tpm_emu->established_flag_cached = 0; + return 0; } From 8a2306c7ed30bfc88cf7e3aced8c2867525f8d4b Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 9 Nov 2017 20:32:06 -0500 Subject: [PATCH 367/546] tpm_tis: convert uint32_t to size_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index b8e811b086..ac5f51f108 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -974,7 +974,7 @@ static const MemoryRegionOps tpm_tis_memory_ops = { }, }; -static int tpm_tis_do_startup_tpm(TPMState *s, uint32_t buffersize) +static int tpm_tis_do_startup_tpm(TPMState *s, size_t buffersize) { return tpm_backend_startup_tpm(s->be_driver, buffersize); } From 1af3d63ea3b0d18a6f17e4587f48529cd4fb26f0 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 9 Nov 2017 19:24:02 -0500 Subject: [PATCH 368/546] tpm_tis: limit size of buffer from backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a preparatory patch for the subsequent ones where we get rid of the flexibility of supporting any kind of buffer size that the backend may support. We keep the size at 4096, which is also the size the external emulator supports. So, limit the size of the buffer we can support and pass it back to the backend. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index ac5f51f108..a6e2f6eb6c 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -1012,7 +1012,8 @@ static void tpm_tis_reset(DeviceState *dev) int c; s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); - s->be_buffer_size = tpm_backend_get_buffer_size(s->be_driver); + s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), + TPM_TIS_BUFFER_MAX); tpm_backend_reset(s->be_driver); @@ -1044,7 +1045,7 @@ static void tpm_tis_reset(DeviceState *dev) tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size); } - tpm_tis_do_startup_tpm(s, 0); + tpm_tis_do_startup_tpm(s, s->be_buffer_size); } static const VMStateDescription vmstate_tpm_tis = { From e6b703f6c7a88f84c62d9b8335ee8f451caa9bda Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 9 Nov 2017 19:30:05 -0500 Subject: [PATCH 369/546] tpm_tis: remove TPMSizeBuffer usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove usage of TPMSizeBuffer. The size of the buffers is limited now by s->be_buffer_size, which is the size of the buffer the TIS has negotiated with the backend. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 68 +++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index a6e2f6eb6c..624c269189 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -64,8 +64,8 @@ typedef struct TPMLocality { uint16_t w_offset; uint16_t r_offset; - TPMSizedBuffer w_buffer; - TPMSizedBuffer r_buffer; + unsigned char w_buffer[TPM_TIS_BUFFER_MAX]; + unsigned char r_buffer[TPM_TIS_BUFFER_MAX]; } TPMLocality; typedef struct TPMState { @@ -215,23 +215,19 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); } -static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb) -{ - return tpm_cmd_get_size(sb->buffer); -} - -static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) +static void tpm_tis_show_buffer(const unsigned char *buffer, + size_t buffer_size, const char *string) { #ifdef DEBUG_TIS uint32_t len, i; - len = tpm_tis_get_size_from_buffer(sb); + len = MIN(tpm_cmd_get_size(buffer), buffer_size); DPRINTF("tpm_tis: %s length = %d\n", string, len); for (i = 0; i < len; i++) { if (i && !(i % 16)) { DPRINTF("\n"); } - DPRINTF("%.2X ", sb->buffer[i]); + DPRINTF("%.2X ", buffer[i]); } DPRINTF("\n"); #endif @@ -263,7 +259,8 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { TPMLocality *locty_data = &s->loc[locty]; - tpm_tis_show_buffer(&s->loc[locty].w_buffer, "tpm_tis: To TPM"); + tpm_tis_show_buffer(s->loc[locty].w_buffer, s->be_buffer_size, + "tpm_tis: To TPM"); /* * w_offset serves as length indicator for length of data; @@ -273,10 +270,10 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) s->cmd = (TPMBackendCmd) { .locty = locty, - .in = locty_data->w_buffer.buffer, + .in = locty_data->w_buffer, .in_len = locty_data->w_offset, - .out = locty_data->r_buffer.buffer, - .out_len = locty_data->r_buffer.size + .out = locty_data->r_buffer, + .out_len = s->be_buffer_size, }; tpm_backend_deliver_request(s->be_driver, &s->cmd); @@ -427,7 +424,8 @@ static void tpm_tis_request_completed(TPMIf *ti) s->loc[locty].r_offset = 0; s->loc[locty].w_offset = 0; - tpm_tis_show_buffer(&s->loc[locty].r_buffer, "tpm_tis: From TPM"); + tpm_tis_show_buffer(s->loc[locty].r_buffer, s->be_buffer_size, + "tpm_tis: From TPM"); if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { tpm_tis_abort(s, locty); @@ -446,9 +444,10 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) uint16_t len; if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { - len = tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer); + len = MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), + s->be_buffer_size); - ret = s->loc[locty].r_buffer.buffer[s->loc[locty].r_offset++]; + ret = s->loc[locty].r_buffer[s->loc[locty].r_offset++]; if (s->loc[locty].r_offset >= len) { /* got last byte */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); @@ -494,11 +493,12 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: result buffer : ", s->loc[locty].r_offset); for (idx = 0; - idx < tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer); + idx < MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), + s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].r_offset == idx ? '>' : ' ', - s->loc[locty].r_buffer.buffer[idx], + s->loc[locty].r_buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n" @@ -506,11 +506,12 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: request buffer: ", s->loc[locty].w_offset); for (idx = 0; - idx < tpm_tis_get_size_from_buffer(&s->loc[locty].w_buffer); + idx < MIN(tpm_cmd_get_size(s->loc[locty].w_buffer), + s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].w_offset == idx ? '>' : ' ', - s->loc[locty].w_buffer.buffer[idx], + s->loc[locty].w_buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n"); @@ -572,11 +573,11 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, if (s->active_locty == locty) { if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { val = TPM_TIS_BURST_COUNT( - tpm_tis_get_size_from_buffer(&s->loc[locty].r_buffer) + MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), + s->be_buffer_size) - s->loc[locty].r_offset) | s->loc[locty].sts; } else { - avail = s->loc[locty].w_buffer.size - - s->loc[locty].w_offset; + avail = s->be_buffer_size - s->loc[locty].w_offset; /* * byte-sized reads should not return 0x00 for 0x100 * available bytes. @@ -924,9 +925,9 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { - if (s->loc[locty].w_offset < s->loc[locty].w_buffer.size) { - s->loc[locty].w_buffer. - buffer[s->loc[locty].w_offset++] = (uint8_t)val; + if (s->loc[locty].w_offset < s->be_buffer_size) { + s->loc[locty].w_buffer[s->loc[locty].w_offset++] = + (uint8_t)val; val >>= 8; size--; } else { @@ -940,7 +941,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, /* we have a packet length - see if we have all of it */ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); - len = tpm_tis_get_size_from_buffer(&s->loc[locty].w_buffer); + len = tpm_cmd_get_size(&s->loc[locty].w_buffer); if (len > s->loc[locty].w_offset) { tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); @@ -979,15 +980,6 @@ static int tpm_tis_do_startup_tpm(TPMState *s, size_t buffersize) return tpm_backend_startup_tpm(s->be_driver, buffersize); } -static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb, - size_t wanted_size) -{ - if (sb->size != wanted_size) { - sb->buffer = g_realloc(sb->buffer, wanted_size); - sb->size = wanted_size; - } -} - /* * Get the TPMVersion of the backend device being used */ @@ -1040,9 +1032,7 @@ static void tpm_tis_reset(DeviceState *dev) s->loc[c].state = TPM_TIS_STATE_IDLE; s->loc[c].w_offset = 0; - tpm_tis_realloc_buffer(&s->loc[c].w_buffer, s->be_buffer_size); s->loc[c].r_offset = 0; - tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size); } tpm_tis_do_startup_tpm(s, s->be_buffer_size); From 0804084230eaff79b4e00cf1c1bcfeb30e7bb9b4 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 9 Nov 2017 20:01:46 -0500 Subject: [PATCH 370/546] tpm_tis: move buffers from localities into common location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One read buffer and one write buffer is sufficient for all localities. The localities cannot all be active at the same time, and only the active locality can use the r/w buffers. Inactive localities will require the COMMAND_READY flag to be set on the STS register to move to the READY state, which then enables access to using the buffer for writing of a command, while all other localities are inactive. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 624c269189..34bfc86143 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -64,16 +64,14 @@ typedef struct TPMLocality { uint16_t w_offset; uint16_t r_offset; - unsigned char w_buffer[TPM_TIS_BUFFER_MAX]; - unsigned char r_buffer[TPM_TIS_BUFFER_MAX]; } TPMLocality; typedef struct TPMState { ISADevice busdev; MemoryRegion mmio; - uint32_t offset; - uint8_t buf[TPM_TIS_BUFFER_MAX]; + unsigned char w_buffer[TPM_TIS_BUFFER_MAX]; + unsigned char r_buffer[TPM_TIS_BUFFER_MAX]; uint8_t active_locty; uint8_t aborting_locty; @@ -259,7 +257,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { TPMLocality *locty_data = &s->loc[locty]; - tpm_tis_show_buffer(s->loc[locty].w_buffer, s->be_buffer_size, + tpm_tis_show_buffer(s->w_buffer, s->be_buffer_size, "tpm_tis: To TPM"); /* @@ -270,9 +268,9 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) s->cmd = (TPMBackendCmd) { .locty = locty, - .in = locty_data->w_buffer, + .in = s->w_buffer, .in_len = locty_data->w_offset, - .out = locty_data->r_buffer, + .out = s->r_buffer, .out_len = s->be_buffer_size, }; @@ -424,7 +422,7 @@ static void tpm_tis_request_completed(TPMIf *ti) s->loc[locty].r_offset = 0; s->loc[locty].w_offset = 0; - tpm_tis_show_buffer(s->loc[locty].r_buffer, s->be_buffer_size, + tpm_tis_show_buffer(s->r_buffer, s->be_buffer_size, "tpm_tis: From TPM"); if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { @@ -444,10 +442,10 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) uint16_t len; if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { - len = MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), + len = MIN(tpm_cmd_get_size(&s->r_buffer), s->be_buffer_size); - ret = s->loc[locty].r_buffer[s->loc[locty].r_offset++]; + ret = s->r_buffer[s->loc[locty].r_offset++]; if (s->loc[locty].r_offset >= len) { /* got last byte */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); @@ -493,12 +491,11 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: result buffer : ", s->loc[locty].r_offset); for (idx = 0; - idx < MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), - s->be_buffer_size); + idx < MIN(tpm_cmd_get_size(&s->r_buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].r_offset == idx ? '>' : ' ', - s->loc[locty].r_buffer[idx], + s->r_buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n" @@ -506,12 +503,11 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: request buffer: ", s->loc[locty].w_offset); for (idx = 0; - idx < MIN(tpm_cmd_get_size(s->loc[locty].w_buffer), - s->be_buffer_size); + idx < MIN(tpm_cmd_get_size(s->w_buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].w_offset == idx ? '>' : ' ', - s->loc[locty].w_buffer[idx], + s->w_buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n"); @@ -573,7 +569,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, if (s->active_locty == locty) { if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { val = TPM_TIS_BURST_COUNT( - MIN(tpm_cmd_get_size(&s->loc[locty].r_buffer), + MIN(tpm_cmd_get_size(&s->r_buffer), s->be_buffer_size) - s->loc[locty].r_offset) | s->loc[locty].sts; } else { @@ -926,7 +922,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { if (s->loc[locty].w_offset < s->be_buffer_size) { - s->loc[locty].w_buffer[s->loc[locty].w_offset++] = + s->w_buffer[s->loc[locty].w_offset++] = (uint8_t)val; val >>= 8; size--; @@ -941,7 +937,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, /* we have a packet length - see if we have all of it */ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); - len = tpm_cmd_get_size(&s->loc[locty].w_buffer); + len = tpm_cmd_get_size(&s->w_buffer); if (len > s->loc[locty].w_offset) { tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); From c5496b9797d8dfde3ef491da67b7a1d191820ef2 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 9 Nov 2017 20:12:39 -0500 Subject: [PATCH 371/546] tpm_tis: merge read and write buffer into single buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we can only be in read or write mode, we can merge the buffers into a single buffer. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 34bfc86143..ad3634789f 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -70,8 +70,7 @@ typedef struct TPMState { ISADevice busdev; MemoryRegion mmio; - unsigned char w_buffer[TPM_TIS_BUFFER_MAX]; - unsigned char r_buffer[TPM_TIS_BUFFER_MAX]; + unsigned char buffer[TPM_TIS_BUFFER_MAX]; uint8_t active_locty; uint8_t aborting_locty; @@ -257,7 +256,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { TPMLocality *locty_data = &s->loc[locty]; - tpm_tis_show_buffer(s->w_buffer, s->be_buffer_size, + tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "tpm_tis: To TPM"); /* @@ -268,9 +267,9 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) s->cmd = (TPMBackendCmd) { .locty = locty, - .in = s->w_buffer, + .in = s->buffer, .in_len = locty_data->w_offset, - .out = s->r_buffer, + .out = s->buffer, .out_len = s->be_buffer_size, }; @@ -422,7 +421,7 @@ static void tpm_tis_request_completed(TPMIf *ti) s->loc[locty].r_offset = 0; s->loc[locty].w_offset = 0; - tpm_tis_show_buffer(s->r_buffer, s->be_buffer_size, + tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "tpm_tis: From TPM"); if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { @@ -442,10 +441,10 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) uint16_t len; if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { - len = MIN(tpm_cmd_get_size(&s->r_buffer), + len = MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); - ret = s->r_buffer[s->loc[locty].r_offset++]; + ret = s->buffer[s->loc[locty].r_offset++]; if (s->loc[locty].r_offset >= len) { /* got last byte */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); @@ -491,11 +490,11 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: result buffer : ", s->loc[locty].r_offset); for (idx = 0; - idx < MIN(tpm_cmd_get_size(&s->r_buffer), s->be_buffer_size); + idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].r_offset == idx ? '>' : ' ', - s->r_buffer[idx], + s->buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n" @@ -503,11 +502,11 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) "tpm_tis: request buffer: ", s->loc[locty].w_offset); for (idx = 0; - idx < MIN(tpm_cmd_get_size(s->w_buffer), s->be_buffer_size); + idx < MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", s->loc[locty].w_offset == idx ? '>' : ' ', - s->w_buffer[idx], + s->buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n"); @@ -569,7 +568,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, if (s->active_locty == locty) { if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { val = TPM_TIS_BURST_COUNT( - MIN(tpm_cmd_get_size(&s->r_buffer), + MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size) - s->loc[locty].r_offset) | s->loc[locty].sts; } else { @@ -922,7 +921,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { if (s->loc[locty].w_offset < s->be_buffer_size) { - s->w_buffer[s->loc[locty].w_offset++] = + s->buffer[s->loc[locty].w_offset++] = (uint8_t)val; val >>= 8; size--; @@ -937,7 +936,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, /* we have a packet length - see if we have all of it */ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); - len = tpm_cmd_get_size(&s->w_buffer); + len = tpm_cmd_get_size(&s->buffer); if (len > s->loc[locty].w_offset) { tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); From e6b30c71f4b56784638eed475e7bdd6dc8c7764e Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 10 Nov 2017 07:37:27 -0500 Subject: [PATCH 372/546] tpm_tis: move r/w_offsets to TPMState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we have a single buffer, we also only need a single set of read/write offsets into that buffer. This works since only one locality can be active. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 57 +++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index ad3634789f..45d7b8cf62 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -61,9 +61,6 @@ typedef struct TPMLocality { uint32_t iface_id; uint32_t inte; uint32_t ints; - - uint16_t w_offset; - uint16_t r_offset; } TPMLocality; typedef struct TPMState { @@ -71,6 +68,8 @@ typedef struct TPMState { MemoryRegion mmio; unsigned char buffer[TPM_TIS_BUFFER_MAX]; + uint16_t w_offset; + uint16_t r_offset; uint8_t active_locty; uint8_t aborting_locty; @@ -254,8 +253,6 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) */ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) { - TPMLocality *locty_data = &s->loc[locty]; - tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "tpm_tis: To TPM"); @@ -268,7 +265,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) s->cmd = (TPMBackendCmd) { .locty = locty, .in = s->buffer, - .in_len = locty_data->w_offset, + .in_len = s->w_offset, .out = s->buffer, .out_len = s->be_buffer_size, }; @@ -350,8 +347,8 @@ static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) /* abort -- this function switches the locality */ static void tpm_tis_abort(TPMState *s, uint8_t locty) { - s->loc[locty].r_offset = 0; - s->loc[locty].w_offset = 0; + s->r_offset = 0; + s->w_offset = 0; DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", s->next_locty); @@ -418,8 +415,8 @@ static void tpm_tis_request_completed(TPMIf *ti) tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); s->loc[locty].state = TPM_TIS_STATE_COMPLETION; - s->loc[locty].r_offset = 0; - s->loc[locty].w_offset = 0; + s->r_offset = 0; + s->w_offset = 0; tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "tpm_tis: From TPM"); @@ -444,14 +441,14 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) len = MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); - ret = s->buffer[s->loc[locty].r_offset++]; - if (s->loc[locty].r_offset >= len) { + ret = s->buffer[s->r_offset++]; + if (s->r_offset >= len) { /* got last byte */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); } DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n", - ret, s->loc[locty].r_offset - 1); + ret, s->r_offset - 1); } return ret; @@ -488,24 +485,24 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) DPRINTF("tpm_tis: read offset : %d\n" "tpm_tis: result buffer : ", - s->loc[locty].r_offset); + s->r_offset); for (idx = 0; idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", - s->loc[locty].r_offset == idx ? '>' : ' ', + s->r_offset == idx ? '>' : ' ', s->buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } DPRINTF("\n" "tpm_tis: write offset : %d\n" "tpm_tis: request buffer: ", - s->loc[locty].w_offset); + s->w_offset); for (idx = 0; idx < MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", - s->loc[locty].w_offset == idx ? '>' : ' ', + s->w_offset == idx ? '>' : ' ', s->buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } @@ -570,9 +567,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, val = TPM_TIS_BURST_COUNT( MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size) - - s->loc[locty].r_offset) | s->loc[locty].sts; + - s->r_offset) | s->loc[locty].sts; } else { - avail = s->be_buffer_size - s->loc[locty].w_offset; + avail = s->be_buffer_size - s->w_offset; /* * byte-sized reads should not return 0x00 for 0x100 * available bytes. @@ -836,8 +833,8 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, switch (s->loc[locty].state) { case TPM_TIS_STATE_READY: - s->loc[locty].w_offset = 0; - s->loc[locty].r_offset = 0; + s->w_offset = 0; + s->r_offset = 0; break; case TPM_TIS_STATE_IDLE: @@ -855,8 +852,8 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, break; case TPM_TIS_STATE_COMPLETION: - s->loc[locty].w_offset = 0; - s->loc[locty].r_offset = 0; + s->w_offset = 0; + s->r_offset = 0; /* shortcut to ready state with C/R set */ s->loc[locty].state = TPM_TIS_STATE_READY; if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { @@ -882,7 +879,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { switch (s->loc[locty].state) { case TPM_TIS_STATE_COMPLETION: - s->loc[locty].r_offset = 0; + s->r_offset = 0; tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID| TPM_TIS_STS_DATA_AVAILABLE); @@ -920,8 +917,8 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { - if (s->loc[locty].w_offset < s->be_buffer_size) { - s->buffer[s->loc[locty].w_offset++] = + if (s->w_offset < s->be_buffer_size) { + s->buffer[s->w_offset++] = (uint8_t)val; val >>= 8; size--; @@ -931,13 +928,13 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } /* check for complete packet */ - if (s->loc[locty].w_offset > 5 && + if (s->w_offset > 5 && (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { /* we have a packet length - see if we have all of it */ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); len = tpm_cmd_get_size(&s->buffer); - if (len > s->loc[locty].w_offset) { + if (len > s->w_offset) { tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); } else { @@ -1026,8 +1023,8 @@ static void tpm_tis_reset(DeviceState *dev) s->loc[c].ints = 0; s->loc[c].state = TPM_TIS_STATE_IDLE; - s->loc[c].w_offset = 0; - s->loc[c].r_offset = 0; + s->w_offset = 0; + s->r_offset = 0; } tpm_tis_do_startup_tpm(s, s->be_buffer_size); From f999d81bc7d9ff3dd2b699d0091824e6b9071d83 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Fri, 10 Nov 2017 07:45:33 -0500 Subject: [PATCH 373/546] tpm_tis: merge r/w_offset into rw_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can now merge the r_offset and w_offset into a single rw_offset. This is possible since when the offset is used for writing in RECEPTION state then reads are ignore. Conversely, when the offset is used for reading when in COMPLETION state, then writes are ignored. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 60 +++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index 45d7b8cf62..ac5d5c61be 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -68,8 +68,7 @@ typedef struct TPMState { MemoryRegion mmio; unsigned char buffer[TPM_TIS_BUFFER_MAX]; - uint16_t w_offset; - uint16_t r_offset; + uint16_t rw_offset; uint8_t active_locty; uint8_t aborting_locty; @@ -257,7 +256,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) "tpm_tis: To TPM"); /* - * w_offset serves as length indicator for length of data; + * rw_offset serves as length indicator for length of data; * it's reset when the response comes back */ s->loc[locty].state = TPM_TIS_STATE_EXECUTION; @@ -265,7 +264,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) s->cmd = (TPMBackendCmd) { .locty = locty, .in = s->buffer, - .in_len = s->w_offset, + .in_len = s->rw_offset, .out = s->buffer, .out_len = s->be_buffer_size, }; @@ -347,8 +346,7 @@ static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) /* abort -- this function switches the locality */ static void tpm_tis_abort(TPMState *s, uint8_t locty) { - s->r_offset = 0; - s->w_offset = 0; + s->rw_offset = 0; DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", s->next_locty); @@ -415,8 +413,7 @@ static void tpm_tis_request_completed(TPMIf *ti) tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); s->loc[locty].state = TPM_TIS_STATE_COMPLETION; - s->r_offset = 0; - s->w_offset = 0; + s->rw_offset = 0; tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "tpm_tis: From TPM"); @@ -441,14 +438,14 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) len = MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); - ret = s->buffer[s->r_offset++]; - if (s->r_offset >= len) { + ret = s->buffer[s->rw_offset++]; + if (s->rw_offset >= len) { /* got last byte */ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); } DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n", - ret, s->r_offset - 1); + ret, s->rw_offset - 1); } return ret; @@ -483,26 +480,14 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); } - DPRINTF("tpm_tis: read offset : %d\n" + DPRINTF("tpm_tis: r/w offset : %d\n" "tpm_tis: result buffer : ", - s->r_offset); + s->rw_offset); for (idx = 0; idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); idx++) { DPRINTF("%c%02x%s", - s->r_offset == idx ? '>' : ' ', - s->buffer[idx], - ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); - } - DPRINTF("\n" - "tpm_tis: write offset : %d\n" - "tpm_tis: request buffer: ", - s->w_offset); - for (idx = 0; - idx < MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); - idx++) { - DPRINTF("%c%02x%s", - s->w_offset == idx ? '>' : ' ', + s->rw_offset == idx ? '>' : ' ', s->buffer[idx], ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); } @@ -567,9 +552,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, val = TPM_TIS_BURST_COUNT( MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size) - - s->r_offset) | s->loc[locty].sts; + - s->rw_offset) | s->loc[locty].sts; } else { - avail = s->be_buffer_size - s->w_offset; + avail = s->be_buffer_size - s->rw_offset; /* * byte-sized reads should not return 0x00 for 0x100 * available bytes. @@ -833,8 +818,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, switch (s->loc[locty].state) { case TPM_TIS_STATE_READY: - s->w_offset = 0; - s->r_offset = 0; + s->rw_offset = 0; break; case TPM_TIS_STATE_IDLE: @@ -852,8 +836,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, break; case TPM_TIS_STATE_COMPLETION: - s->w_offset = 0; - s->r_offset = 0; + s->rw_offset = 0; /* shortcut to ready state with C/R set */ s->loc[locty].state = TPM_TIS_STATE_READY; if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { @@ -879,7 +862,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { switch (s->loc[locty].state) { case TPM_TIS_STATE_COMPLETION: - s->r_offset = 0; + s->rw_offset = 0; tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID| TPM_TIS_STS_DATA_AVAILABLE); @@ -917,8 +900,8 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { - if (s->w_offset < s->be_buffer_size) { - s->buffer[s->w_offset++] = + if (s->rw_offset < s->be_buffer_size) { + s->buffer[s->rw_offset++] = (uint8_t)val; val >>= 8; size--; @@ -928,13 +911,13 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr, } /* check for complete packet */ - if (s->w_offset > 5 && + if (s->rw_offset > 5 && (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { /* we have a packet length - see if we have all of it */ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); len = tpm_cmd_get_size(&s->buffer); - if (len > s->w_offset) { + if (len > s->rw_offset) { tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); } else { @@ -1023,8 +1006,7 @@ static void tpm_tis_reset(DeviceState *dev) s->loc[c].ints = 0; s->loc[c].state = TPM_TIS_STATE_IDLE; - s->w_offset = 0; - s->r_offset = 0; + s->rw_offset = 0; } tpm_tis_do_startup_tpm(s, s->be_buffer_size); From b86da7ddeda904b5fb1da03781328e7039536025 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 11 Oct 2017 10:36:53 -0400 Subject: [PATCH 374/546] tpm: Implement tpm_sized_buffer_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the definition of TPMSizedBuffer out of tpm_tis.c into tpm_util.h and implement tpm_sized_buffer_reset() for the following patches to use. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/tpm/tpm_tis.c | 5 ----- hw/tpm/tpm_util.c | 7 +++++++ hw/tpm/tpm_util.h | 7 +++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c index ac5d5c61be..561384cd86 100644 --- a/hw/tpm/tpm_tis.c +++ b/hw/tpm/tpm_tis.c @@ -48,11 +48,6 @@ typedef enum { TPM_TIS_STATE_RECEPTION, } TPMTISState; -typedef struct TPMSizedBuffer { - uint32_t size; - uint8_t *buffer; -} TPMSizedBuffer; - /* locality data -- all fields are persisted */ typedef struct TPMLocality { TPMTISState state; diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c index 17cafbe6b3..747075e244 100644 --- a/hw/tpm/tpm_util.c +++ b/hw/tpm/tpm_util.c @@ -355,3 +355,10 @@ int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, return 0; } + +void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) +{ + g_free(tsb->buffer); + tsb->buffer = NULL; + tsb->size = 0; +} diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h index 2393b6bc0e..19b28474ae 100644 --- a/hw/tpm/tpm_util.h +++ b/hw/tpm/tpm_util.h @@ -42,4 +42,11 @@ int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, #define DEFINE_PROP_TPMBE(_n, _s, _f) \ DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) +typedef struct TPMSizedBuffer { + uint32_t size; + uint8_t *buffer; +} TPMSizedBuffer; + +void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); + #endif /* TPM_TPM_UTIL_H */ From 2cb9f06e3d2c8649166a95e01b05433fa9d14384 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:15 -0500 Subject: [PATCH 375/546] apic: add function to apic that will be used by hvf This patch adds the function apic_get_highest_priority_irr to apic.c and exports it through the interface in apic.h for use by hvf. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-8-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- hw/intc/apic.c | 12 ++++++++++++ include/hw/i386/apic.h | 1 + 2 files changed, 13 insertions(+) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index fe15fb6024..6fda52b86c 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -305,6 +305,18 @@ static void apic_set_tpr(APICCommonState *s, uint8_t val) } } +int apic_get_highest_priority_irr(DeviceState *dev) +{ + APICCommonState *s; + + if (!dev) { + /* no interrupts */ + return -1; + } + s = APIC_COMMON(dev); + return get_highest_priority_int(s->irr); +} + static uint8_t apic_get_tpr(APICCommonState *s) { apic_sync_vapic(s, SYNC_FROM_VAPIC); diff --git a/include/hw/i386/apic.h b/include/hw/i386/apic.h index ea48ea9389..a9f6c0aa33 100644 --- a/include/hw/i386/apic.h +++ b/include/hw/i386/apic.h @@ -20,6 +20,7 @@ void apic_init_reset(DeviceState *s); void apic_sipi(DeviceState *s); void apic_poll_irq(DeviceState *d); void apic_designate_bsp(DeviceState *d, bool bsp); +int apic_get_highest_priority_irr(DeviceState *dev); /* pc.c */ DeviceState *cpu_get_current_apic(void); From c97d6d2cdf97edb4aebe832fdba65d701ad7bcb6 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:09 -0500 Subject: [PATCH 376/546] i386: hvf: add code base from Google's QEMU repository This file begins tracking the files that will be the code base for HVF support in QEMU. This code base is part of Google's QEMU version of their Android emulator, and can be found at https://android.googlesource.com/platform/external/qemu/+/emu-master-dev This code is based on Veertu Inc's vdhh (Veertu Desktop Hosted Hypervisor), found at https://github.com/veertuinc/vdhh. Everything is appropriately licensed under GPL v2-or-later, except for the code inside x86_task.c and x86_task.h, which, deriving from KVM (the Linux kernel), is licensed GPL v2-only. This code base already implements a very great deal of functionality, although Google's version removed from Vertuu's the support for APIC page and hyperv-related stuff. According to the Android Emulator Release Notes, Revision 26.1.3 (August 2017), "Hypervisor.framework is now enabled by default on macOS for 32-bit x86 images to improve performance and macOS compatibility", although we better use with caution for, as the same Revision warns us, "If you experience issues with it specifically, please file a bug report...". The code hasn't seen much update in the last 5 months, so I think that we can further develop the code with occasional visiting Google's repository to see if there has been any update. On top of Google's code, the following changes were made: - add code to the configure script to support the --enable-hvf argument. If the OS is Darwin, it checks for presence of HVF in the system. The patch also adds strings related to HVF in the file qemu-options.hx. QEMU will only support the modern syntax style '-M accel=hvf' no enable hvf; the legacy '-enable-hvf' will not be supported. - fix styling issues - add glue code to cpus.c - move HVFX86EmulatorState field to CPUX86State, changing the the emulation functions to have a parameter with signature 'CPUX86State *' instead of 'CPUState *' so we don't have to get the 'env'. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-2-Sergio.G.DelReal@gmail.com> Message-Id: <20170913090522.4022-3-Sergio.G.DelReal@gmail.com> Message-Id: <20170913090522.4022-5-Sergio.G.DelReal@gmail.com> Message-Id: <20170913090522.4022-6-Sergio.G.DelReal@gmail.com> Message-Id: <20170905035457.3753-7-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- accel/stubs/Makefile.objs | 1 + accel/stubs/hvf-stub.c | 31 + configure | 38 + cpus.c | 86 ++ include/qemu/typedefs.h | 1 + include/qom/cpu.h | 2 + include/sysemu/hvf.h | 102 ++ qemu-options.hx | 10 +- target/i386/Makefile.objs | 1 + target/i386/cpu.h | 39 +- target/i386/hvf-all.c | 1006 ++++++++++++ target/i386/hvf-i386.h | 48 + target/i386/hvf-utils/Makefile.objs | 1 + target/i386/hvf-utils/README.md | 7 + target/i386/hvf-utils/vmcs.h | 371 +++++ target/i386/hvf-utils/vmx.h | 214 +++ target/i386/hvf-utils/x86.c | 184 +++ target/i386/hvf-utils/x86.h | 476 ++++++ target/i386/hvf-utils/x86_decode.c | 2186 +++++++++++++++++++++++++++ target/i386/hvf-utils/x86_decode.h | 325 ++++ target/i386/hvf-utils/x86_descr.c | 124 ++ target/i386/hvf-utils/x86_descr.h | 55 + target/i386/hvf-utils/x86_emu.c | 1537 +++++++++++++++++++ target/i386/hvf-utils/x86_emu.h | 49 + target/i386/hvf-utils/x86_flags.c | 333 ++++ target/i386/hvf-utils/x86_flags.h | 243 +++ target/i386/hvf-utils/x86_gen.h | 53 + target/i386/hvf-utils/x86_mmu.c | 273 ++++ target/i386/hvf-utils/x86_mmu.h | 45 + target/i386/hvf-utils/x86hvf.c | 513 +++++++ target/i386/hvf-utils/x86hvf.h | 39 + 31 files changed, 8382 insertions(+), 11 deletions(-) create mode 100644 accel/stubs/hvf-stub.c create mode 100644 include/sysemu/hvf.h create mode 100644 target/i386/hvf-all.c create mode 100644 target/i386/hvf-i386.h create mode 100644 target/i386/hvf-utils/Makefile.objs create mode 100644 target/i386/hvf-utils/README.md create mode 100644 target/i386/hvf-utils/vmcs.h create mode 100644 target/i386/hvf-utils/vmx.h create mode 100644 target/i386/hvf-utils/x86.c create mode 100644 target/i386/hvf-utils/x86.h create mode 100644 target/i386/hvf-utils/x86_decode.c create mode 100644 target/i386/hvf-utils/x86_decode.h create mode 100644 target/i386/hvf-utils/x86_descr.c create mode 100644 target/i386/hvf-utils/x86_descr.h create mode 100644 target/i386/hvf-utils/x86_emu.c create mode 100644 target/i386/hvf-utils/x86_emu.h create mode 100644 target/i386/hvf-utils/x86_flags.c create mode 100644 target/i386/hvf-utils/x86_flags.h create mode 100644 target/i386/hvf-utils/x86_gen.h create mode 100644 target/i386/hvf-utils/x86_mmu.c create mode 100644 target/i386/hvf-utils/x86_mmu.h create mode 100644 target/i386/hvf-utils/x86hvf.c create mode 100644 target/i386/hvf-utils/x86hvf.h diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index c071abaf4e..779343b0c0 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -1,3 +1,4 @@ obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o +obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o diff --git a/accel/stubs/hvf-stub.c b/accel/stubs/hvf-stub.c new file mode 100644 index 0000000000..a79f9fc36f --- /dev/null +++ b/accel/stubs/hvf-stub.c @@ -0,0 +1,31 @@ +/* + * QEMU HVF support + * + * Copyright 2017 Red Hat, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2 or later, as published by the Free Software Foundation, + * and may be copied, distributed, and modified under those terms. + * + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "sysemu/hvf.h" + +int hvf_init_vcpu(CPUState *cpu) +{ + return -ENOSYS; +} + +int hvf_vcpu_exec(CPUState *cpu) +{ + return -ENOSYS; +} + +void hvf_vcpu_destroy(CPUState *cpu) +{ +} diff --git a/configure b/configure index 100309c33f..56f9716609 100755 --- a/configure +++ b/configure @@ -211,6 +211,17 @@ supported_xen_target() { return 1 } +supported_hvf_target() { + test "$hvf" = "yes" || return 1 + glob "$1" "*-softmmu" || return 1 + case "${1%-softmmu}" in + x86_64) + return 0 + ;; + esac + return 1 +} + supported_target() { case "$1" in *-softmmu) @@ -236,6 +247,7 @@ supported_target() { supported_kvm_target "$1" && return 0 supported_xen_target "$1" && return 0 supported_hax_target "$1" && return 0 + supported_hvf_target "$1" && return 0 print_error "TCG disabled, but hardware accelerator not available for '$target'" return 1 } @@ -325,6 +337,7 @@ vhost_vsock="no" vhost_user="" kvm="no" hax="no" +hvf="no" rdma="" gprof="no" debug_tcg="no" @@ -741,6 +754,7 @@ Darwin) bsd="yes" darwin="yes" hax="yes" + hvf="yes" LDFLAGS_SHARED="-bundle -undefined dynamic_lookup" if [ "$cpu" = "x86_64" ] ; then QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS" @@ -1036,6 +1050,10 @@ for opt do ;; --enable-hax) hax="yes" ;; + --disable-hvf) hvf="no" + ;; + --enable-hvf) hvf="yes" + ;; --disable-tcg-interpreter) tcg_interpreter="no" ;; --enable-tcg-interpreter) tcg_interpreter="yes" @@ -1529,6 +1547,7 @@ disabled with --disable-FEATURE, default is enabled if available: bluez bluez stack connectivity kvm KVM acceleration support hax HAX acceleration support + hvf Hypervisor.framework acceleration support rdma RDMA-based migration support vde support for vde network netmap support for netmap network @@ -5055,6 +5074,21 @@ then fi +################################################# +# Check to see if we have the Hypervisor framework +if [ "$darwin" == "yes" ] ; then + cat > $TMPC << EOF +#include +int main() { return 0;} +EOF + if ! compile_object ""; then + hvf='no' + else + hvf='yes' + LDFLAGS="-framework Hypervisor $LDFLAGS" + fi +fi + ################################################# # Sparc implicitly links with --relax, which is # incompatible with -r, so --no-relax should be @@ -5530,6 +5564,7 @@ echo "ATTR/XATTR support $attr" echo "Install blobs $blobs" echo "KVM support $kvm" echo "HAX support $hax" +echo "HVF support $hvf" echo "TCG support $tcg" if test "$tcg" = "yes" ; then echo "TCG debug enabled $debug_tcg" @@ -6602,6 +6637,9 @@ fi if supported_hax_target $target; then echo "CONFIG_HAX=y" >> $config_target_mak fi +if supported_hvf_target $target; then + echo "CONFIG_HVF=y" >> $config_target_mak +fi if test "$target_bigendian" = "yes" ; then echo "TARGET_WORDS_BIGENDIAN=y" >> $config_target_mak fi diff --git a/cpus.c b/cpus.c index 83700c1716..e8139de534 100644 --- a/cpus.c +++ b/cpus.c @@ -37,6 +37,7 @@ #include "sysemu/hw_accel.h" #include "sysemu/kvm.h" #include "sysemu/hax.h" +#include "sysemu/hvf.h" #include "qmp-commands.h" #include "exec/exec-all.h" @@ -900,6 +901,10 @@ void cpu_synchronize_all_states(void) CPU_FOREACH(cpu) { cpu_synchronize_state(cpu); + /* TODO: move to cpu_synchronize_state() */ + if (hvf_enabled()) { + hvf_cpu_synchronize_state(cpu); + } } } @@ -909,6 +914,10 @@ void cpu_synchronize_all_post_reset(void) CPU_FOREACH(cpu) { cpu_synchronize_post_reset(cpu); + /* TODO: move to cpu_synchronize_post_reset() */ + if (hvf_enabled()) { + hvf_cpu_synchronize_post_reset(cpu); + } } } @@ -918,6 +927,10 @@ void cpu_synchronize_all_post_init(void) CPU_FOREACH(cpu) { cpu_synchronize_post_init(cpu); + /* TODO: move to cpu_synchronize_post_init() */ + if (hvf_enabled()) { + hvf_cpu_synchronize_post_init(cpu); + } } } @@ -1107,6 +1120,14 @@ static void qemu_kvm_wait_io_event(CPUState *cpu) qemu_wait_io_event_common(cpu); } +static void qemu_hvf_wait_io_event(CPUState *cpu) +{ + while (cpu_thread_is_idle(cpu)) { + qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex); + } + qemu_wait_io_event_common(cpu); +} + static void *qemu_kvm_cpu_thread_fn(void *arg) { CPUState *cpu = arg; @@ -1444,6 +1465,48 @@ static void *qemu_hax_cpu_thread_fn(void *arg) return NULL; } +/* The HVF-specific vCPU thread function. This one should only run when the host + * CPU supports the VMX "unrestricted guest" feature. */ +static void *qemu_hvf_cpu_thread_fn(void *arg) +{ + CPUState *cpu = arg; + + int r; + + assert(hvf_enabled()); + + rcu_register_thread(); + + qemu_mutex_lock_iothread(); + qemu_thread_get_self(cpu->thread); + + cpu->thread_id = qemu_get_thread_id(); + cpu->can_do_io = 1; + current_cpu = cpu; + + hvf_init_vcpu(cpu); + + /* signal CPU creation */ + cpu->created = true; + qemu_cond_signal(&qemu_cpu_cond); + + do { + if (cpu_can_run(cpu)) { + r = hvf_vcpu_exec(cpu); + if (r == EXCP_DEBUG) { + cpu_handle_guest_debug(cpu); + } + } + qemu_hvf_wait_io_event(cpu); + } while (!cpu->unplug || cpu_can_run(cpu)); + + hvf_vcpu_destroy(cpu); + cpu->created = false; + qemu_cond_signal(&qemu_cpu_cond); + qemu_mutex_unlock_iothread(); + return NULL; +} + #ifdef _WIN32 static void CALLBACK dummy_apc_func(ULONG_PTR unused) { @@ -1761,6 +1824,27 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) } } +static void qemu_hvf_start_vcpu(CPUState *cpu) +{ + char thread_name[VCPU_THREAD_NAME_SIZE]; + + /* HVF currently does not support TCG, and only runs in + * unrestricted-guest mode. */ + assert(hvf_enabled()); + + cpu->thread = g_malloc0(sizeof(QemuThread)); + cpu->halt_cond = g_malloc0(sizeof(QemuCond)); + qemu_cond_init(cpu->halt_cond); + + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, qemu_hvf_cpu_thread_fn, + cpu, QEMU_THREAD_JOINABLE); + while (!cpu->created) { + qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); + } +} + static void qemu_dummy_start_vcpu(CPUState *cpu) { char thread_name[VCPU_THREAD_NAME_SIZE]; @@ -1795,6 +1879,8 @@ void qemu_init_vcpu(CPUState *cpu) qemu_kvm_start_vcpu(cpu); } else if (hax_enabled()) { qemu_hax_start_vcpu(cpu); + } else if (hvf_enabled()) { + qemu_hvf_start_vcpu(cpu); } else if (tcg_enabled()) { qemu_tcg_init_vcpu(cpu); } else { diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 3dbc69b1e9..9bd7a834ba 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -36,6 +36,7 @@ typedef struct FWCfgIoState FWCfgIoState; typedef struct FWCfgMemState FWCfgMemState; typedef struct FWCfgState FWCfgState; typedef struct HCIInfo HCIInfo; +typedef struct HVFX86EmulatorState HVFX86EmulatorState; typedef struct I2CBus I2CBus; typedef struct I2SCodec I2SCodec; typedef struct ISABus ISABus; diff --git a/include/qom/cpu.h b/include/qom/cpu.h index c2fa151228..93bd546879 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -423,6 +423,8 @@ struct CPUState { * unnecessary flushes. */ uint16_t pending_tlb_flush; + + int hvf_fd; }; QTAILQ_HEAD(CPUTailQ, CPUState); diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h new file mode 100644 index 0000000000..614a2d203b --- /dev/null +++ b/include/sysemu/hvf.h @@ -0,0 +1,102 @@ +/* + * QEMU Hypervisor.framework (HVF) support + * + * Copyright Google Inc., 2017 + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +/* header to be included in non-HVF-specific code */ +#ifndef _HVF_H +#define _HVF_H + +#include "config-host.h" +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/bitops.h" +#include "exec/memory.h" +#include "sysemu/accel.h" + +extern int hvf_disabled; +#ifdef CONFIG_HVF +#include +#include +#include +#include "target/i386/cpu.h" +#include "hw/hw.h" +uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, + int reg); +#define hvf_enabled() !hvf_disabled +#else +#define hvf_enabled() 0 +#define hvf_get_supported_cpuid(func, idx, reg) 0 +#endif + +typedef struct hvf_slot { + uint64_t start; + uint64_t size; + uint8_t *mem; + int slot_id; +} hvf_slot; + +typedef struct hvf_vcpu_caps { + uint64_t vmx_cap_pinbased; + uint64_t vmx_cap_procbased; + uint64_t vmx_cap_procbased2; + uint64_t vmx_cap_entry; + uint64_t vmx_cap_exit; + uint64_t vmx_cap_preemption_timer; +} hvf_vcpu_caps; + +typedef struct HVFState { + AccelState parent; + hvf_slot slots[32]; + int num_slots; + + hvf_vcpu_caps *hvf_caps; +} HVFState; +extern HVFState *hvf_state; + +void hvf_set_phys_mem(MemoryRegionSection *, bool); +void hvf_handle_io(CPUArchState *, uint16_t, void *, + int, int, int); +hvf_slot *hvf_find_overlap_slot(uint64_t, uint64_t); + +/* Disable HVF if |disable| is 1, otherwise, enable it iff it is supported by + * the host CPU. Use hvf_enabled() after this to get the result. */ +void hvf_disable(int disable); + +/* Returns non-0 if the host CPU supports the VMX "unrestricted guest" feature + * which allows the virtual CPU to directly run in "real mode". If true, this + * allows QEMU to run several vCPU threads in parallel (see cpus.c). Otherwise, + * only a a single TCG thread can run, and it will call HVF to run the current + * instructions, except in case of "real mode" (paging disabled, typically at + * boot time), or MMIO operations. */ + +int hvf_sync_vcpus(void); + +int hvf_init_vcpu(CPUState *); +int hvf_vcpu_exec(CPUState *); +int hvf_smp_cpu_exec(CPUState *); +void hvf_cpu_synchronize_state(CPUState *); +void hvf_cpu_synchronize_post_reset(CPUState *); +void hvf_cpu_synchronize_post_init(CPUState *); +void _hvf_cpu_synchronize_post_init(CPUState *, run_on_cpu_data); + +void hvf_vcpu_destroy(CPUState *); +void hvf_raise_event(CPUState *); +/* void hvf_reset_vcpu_state(void *opaque); */ +void hvf_reset_vcpu(CPUState *); +void vmx_update_tpr(CPUState *); +void update_apic_tpr(CPUState *); +int hvf_put_registers(CPUState *); +void vmx_clear_int_window_exiting(CPUState *cpu); + +#define TYPE_HVF_ACCEL ACCEL_CLASS_NAME("hvf") + +#define HVF_STATE(obj) \ + OBJECT_CHECK(HVFState, (obj), TYPE_HVF_ACCEL) + +#endif diff --git a/qemu-options.hx b/qemu-options.hx index 94647e21e3..d398d19907 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -31,7 +31,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" " selects emulated machine ('-machine help' for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" - " supported accelerators are kvm, xen, hax or tcg (default: tcg)\n" + " supported accelerators are kvm, xen, hax, hvf or tcg (default: tcg)\n" " kernel_irqchip=on|off|split controls accelerated irqchip support (default=off)\n" " vmport=on|off|auto controls emulation of vmport (default: auto)\n" " kvm_shadow_mem=size of KVM shadow MMU in bytes\n" @@ -66,7 +66,7 @@ Supported machine properties are: @table @option @item accel=@var{accels1}[:@var{accels2}[:...]] This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, hax or tcg can be available. By default, tcg is used. If there is +kvm, xen, hax, hvf or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize. @item kernel_irqchip=on|off @@ -126,13 +126,13 @@ ETEXI DEF("accel", HAS_ARG, QEMU_OPTION_accel, "-accel [accel=]accelerator[,thread=single|multi]\n" - " select accelerator (kvm, xen, hax or tcg; use 'help' for a list)\n" - " thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL) + " select accelerator (kvm, xen, hax, hvf or tcg; use 'help' for a list)\n" + " thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL) STEXI @item -accel @var{name}[,prop=@var{value}[,...]] @findex -accel This is used to enable an accelerator. Depending on the target architecture, -kvm, xen, hax or tcg can be available. By default, tcg is used. If there is +kvm, xen, hax, hvf or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize. @table @option diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 6a26e9d9f0..0bef89c099 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -12,4 +12,5 @@ obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o endif ifdef CONFIG_DARWIN obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-darwin.o +obj-$(CONFIG_HVF) += hvf-utils/ hvf-all.o endif diff --git a/target/i386/cpu.h b/target/i386/cpu.h index d605cc6ccb..de9d74acaf 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -30,6 +30,8 @@ #define TARGET_LONG_BITS 32 #endif +#include "exec/cpu-defs.h" + /* The x86 has a strong memory model with some store-after-load re-ordering */ #define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) @@ -50,8 +52,6 @@ #define CPUArchState struct CPUX86State -#include "exec/cpu-defs.h" - #ifdef CONFIG_TCG #include "fpu/softfloat.h" #endif @@ -82,16 +82,20 @@ #define R_GS 5 /* segment descriptor fields */ -#define DESC_G_MASK (1 << 23) +#define DESC_G_SHIFT 23 +#define DESC_G_MASK (1 << DESC_G_SHIFT) #define DESC_B_SHIFT 22 #define DESC_B_MASK (1 << DESC_B_SHIFT) #define DESC_L_SHIFT 21 /* x86_64 only : 64 bit code segment */ #define DESC_L_MASK (1 << DESC_L_SHIFT) -#define DESC_AVL_MASK (1 << 20) -#define DESC_P_MASK (1 << 15) +#define DESC_AVL_SHIFT 20 +#define DESC_AVL_MASK (1 << DESC_AVL_SHIFT) +#define DESC_P_SHIFT 15 +#define DESC_P_MASK (1 << DESC_P_SHIFT) #define DESC_DPL_SHIFT 13 #define DESC_DPL_MASK (3 << DESC_DPL_SHIFT) -#define DESC_S_MASK (1 << 12) +#define DESC_S_SHIFT 12 +#define DESC_S_MASK (1 << DESC_S_SHIFT) #define DESC_TYPE_SHIFT 8 #define DESC_TYPE_MASK (15 << DESC_TYPE_SHIFT) #define DESC_A_MASK (1 << 8) @@ -631,6 +635,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS]; #define CPUID_7_0_EBX_AVX512BW (1U << 30) /* AVX-512 Byte and Word Instructions */ #define CPUID_7_0_EBX_AVX512VL (1U << 31) /* AVX-512 Vector Length Extensions */ +#define CPUID_7_0_ECX_AVX512BMI (1U << 1) #define CPUID_7_0_ECX_VBMI (1U << 1) /* AVX-512 Vector Byte Manipulation Instrs */ #define CPUID_7_0_ECX_UMIP (1U << 2) #define CPUID_7_0_ECX_PKU (1U << 3) @@ -812,6 +817,20 @@ typedef struct SegmentCache { float64 _d_##n[(bits)/64]; \ } +typedef union { + uint8_t _b[16]; + uint16_t _w[8]; + uint32_t _l[4]; + uint64_t _q[2]; +} XMMReg; + +typedef union { + uint8_t _b[32]; + uint16_t _w[16]; + uint32_t _l[8]; + uint64_t _q[4]; +} YMMReg; + typedef MMREG_UNION(ZMMReg, 512) ZMMReg; typedef MMREG_UNION(MMXReg, 64) MMXReg; @@ -1047,7 +1066,11 @@ typedef struct CPUX86State { ZMMReg xmm_t0; MMXReg mmx_t0; + XMMReg ymmh_regs[CPU_NB_REGS]; + uint64_t opmask_regs[NB_OPMASK_REGS]; + YMMReg zmmh_regs[CPU_NB_REGS]; + ZMMReg hi16_zmm_regs[CPU_NB_REGS]; /* sysenter registers */ uint32_t sysenter_cs; @@ -1172,11 +1195,15 @@ typedef struct CPUX86State { int32_t interrupt_injected; uint8_t soft_interrupt; uint8_t has_error_code; + uint32_t ins_len; uint32_t sipi_vector; bool tsc_valid; int64_t tsc_khz; int64_t user_tsc_khz; /* for sanity check only */ void *kvm_xsave_buf; +#if defined(CONFIG_HVF) + HVFX86EmulatorState *hvf_emul; +#endif uint64_t mcg_cap; uint64_t mcg_ctl; diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c new file mode 100644 index 0000000000..b0c87ebd9f --- /dev/null +++ b/target/i386/hvf-all.c @@ -0,0 +1,1006 @@ +/* Copyright 2008 IBM Corporation + * 2008 Red Hat, Inc. + * Copyright 2011 Intel Corporation + * Copyright 2016 Veertu, Inc. + * Copyright 2017 The Android Open Source Project + * + * QEMU Hypervisor.framework support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/error-report.h" + +#include "sysemu/hvf.h" +#include "hvf-i386.h" +#include "hvf-utils/vmcs.h" +#include "hvf-utils/vmx.h" +#include "hvf-utils/x86.h" +#include "hvf-utils/x86_descr.h" +#include "hvf-utils/x86_mmu.h" +#include "hvf-utils/x86_decode.h" +#include "hvf-utils/x86_emu.h" +#include "hvf-utils/x86hvf.h" + +#include +#include + +#include "exec/address-spaces.h" +#include "exec/exec-all.h" +#include "exec/ioport.h" +#include "hw/i386/apic_internal.h" +#include "hw/boards.h" +#include "qemu/main-loop.h" +#include "strings.h" +#include "trace.h" +#include "sysemu/accel.h" +#include "sysemu/sysemu.h" +#include "target/i386/cpu.h" + +pthread_rwlock_t mem_lock = PTHREAD_RWLOCK_INITIALIZER; +HVFState *hvf_state; +int hvf_disabled = 1; + +static void assert_hvf_ok(hv_return_t ret) +{ + if (ret == HV_SUCCESS) { + return; + } + + switch (ret) { + case HV_ERROR: + error_report("Error: HV_ERROR\n"); + break; + case HV_BUSY: + error_report("Error: HV_BUSY\n"); + break; + case HV_BAD_ARGUMENT: + error_report("Error: HV_BAD_ARGUMENT\n"); + break; + case HV_NO_RESOURCES: + error_report("Error: HV_NO_RESOURCES\n"); + break; + case HV_NO_DEVICE: + error_report("Error: HV_NO_DEVICE\n"); + break; + case HV_UNSUPPORTED: + error_report("Error: HV_UNSUPPORTED\n"); + break; + default: + error_report("Unknown Error\n"); + } + + abort(); +} + +/* Memory slots */ +hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t end) +{ + hvf_slot *slot; + int x; + for (x = 0; x < hvf_state->num_slots; ++x) { + slot = &hvf_state->slots[x]; + if (slot->size && start < (slot->start + slot->size) && + end > slot->start) { + return slot; + } + } + return NULL; +} + +struct mac_slot { + int present; + uint64_t size; + uint64_t gpa_start; + uint64_t gva; +}; + +struct mac_slot mac_slots[32]; +#define ALIGN(x, y) (((x) + (y) - 1) & ~((y) - 1)) + +static int do_hvf_set_memory(hvf_slot *slot) +{ + struct mac_slot *macslot; + hv_memory_flags_t flags; + hv_return_t ret; + + macslot = &mac_slots[slot->slot_id]; + + if (macslot->present) { + if (macslot->size != slot->size) { + macslot->present = 0; + ret = hv_vm_unmap(macslot->gpa_start, macslot->size); + assert_hvf_ok(ret); + } + } + + if (!slot->size) { + return 0; + } + + flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC; + + macslot->present = 1; + macslot->gpa_start = slot->start; + macslot->size = slot->size; + ret = hv_vm_map((hv_uvaddr_t)slot->mem, slot->start, slot->size, flags); + assert_hvf_ok(ret); + return 0; +} + +void hvf_set_phys_mem(MemoryRegionSection *section, bool add) +{ + hvf_slot *mem; + MemoryRegion *area = section->mr; + + if (!memory_region_is_ram(area)) { + return; + } + + mem = hvf_find_overlap_slot( + section->offset_within_address_space, + section->offset_within_address_space + int128_get64(section->size)); + + if (mem && add) { + if (mem->size == int128_get64(section->size) && + mem->start == section->offset_within_address_space && + mem->mem == (memory_region_get_ram_ptr(area) + + section->offset_within_region)) { + return; /* Same region was attempted to register, go away. */ + } + } + + /* Region needs to be reset. set the size to 0 and remap it. */ + if (mem) { + mem->size = 0; + if (do_hvf_set_memory(mem)) { + error_report("Failed to reset overlapping slot\n"); + abort(); + } + } + + if (!add) { + return; + } + + /* Now make a new slot. */ + int x; + + for (x = 0; x < hvf_state->num_slots; ++x) { + mem = &hvf_state->slots[x]; + if (!mem->size) { + break; + } + } + + if (x == hvf_state->num_slots) { + error_report("No free slots\n"); + abort(); + } + + mem->size = int128_get64(section->size); + mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region; + mem->start = section->offset_within_address_space; + + if (do_hvf_set_memory(mem)) { + error_report("Error registering new memory slot\n"); + abort(); + } +} + +void vmx_update_tpr(CPUState *cpu) +{ + /* TODO: need integrate APIC handling */ + X86CPU *x86_cpu = X86_CPU(cpu); + int tpr = cpu_get_apic_tpr(x86_cpu->apic_state) << 4; + int irr = apic_get_highest_priority_irr(x86_cpu->apic_state); + + wreg(cpu->hvf_fd, HV_X86_TPR, tpr); + if (irr == -1) { + wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, 0); + } else { + wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, (irr > tpr) ? tpr >> 4 : + irr >> 4); + } +} + +void update_apic_tpr(CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + int tpr = rreg(cpu->hvf_fd, HV_X86_TPR) >> 4; + cpu_set_apic_tpr(x86_cpu->apic_state, tpr); +} + +#define VECTORING_INFO_VECTOR_MASK 0xff + +// TODO: taskswitch handling +static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) +{ + /* CR3 and ldt selector are not saved intentionally */ + tss->eip = EIP(cpu); + tss->eflags = EFLAGS(cpu); + tss->eax = EAX(cpu); + tss->ecx = ECX(cpu); + tss->edx = EDX(cpu); + tss->ebx = EBX(cpu); + tss->esp = ESP(cpu); + tss->ebp = EBP(cpu); + tss->esi = ESI(cpu); + tss->edi = EDI(cpu); + + tss->es = vmx_read_segment_selector(cpu, REG_SEG_ES).sel; + tss->cs = vmx_read_segment_selector(cpu, REG_SEG_CS).sel; + tss->ss = vmx_read_segment_selector(cpu, REG_SEG_SS).sel; + tss->ds = vmx_read_segment_selector(cpu, REG_SEG_DS).sel; + tss->fs = vmx_read_segment_selector(cpu, REG_SEG_FS).sel; + tss->gs = vmx_read_segment_selector(cpu, REG_SEG_GS).sel; +} + +static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) +{ + wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); + + RIP(cpu) = tss->eip; + EFLAGS(cpu) = tss->eflags | 2; + + /* General purpose registers */ + RAX(cpu) = tss->eax; + RCX(cpu) = tss->ecx; + RDX(cpu) = tss->edx; + RBX(cpu) = tss->ebx; + RSP(cpu) = tss->esp; + RBP(cpu) = tss->ebp; + RSI(cpu) = tss->esi; + RDI(cpu) = tss->edi; + + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, REG_SEG_LDTR); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, REG_SEG_ES); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, REG_SEG_CS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, REG_SEG_SS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, REG_SEG_DS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, REG_SEG_FS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, REG_SEG_GS); + +#if 0 + load_segment(cpu, REG_SEG_LDTR, tss->ldt); + load_segment(cpu, REG_SEG_ES, tss->es); + load_segment(cpu, REG_SEG_CS, tss->cs); + load_segment(cpu, REG_SEG_SS, tss->ss); + load_segment(cpu, REG_SEG_DS, tss->ds); + load_segment(cpu, REG_SEG_FS, tss->fs); + load_segment(cpu, REG_SEG_GS, tss->gs); +#endif +} + +static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segment_selector old_tss_sel, + uint64_t old_tss_base, struct x86_segment_descriptor *new_desc) +{ + struct x86_tss_segment32 tss_seg; + uint32_t new_tss_base = x86_segment_base(new_desc); + uint32_t eip_offset = offsetof(struct x86_tss_segment32, eip); + uint32_t ldt_sel_offset = offsetof(struct x86_tss_segment32, ldt); + + vmx_read_mem(cpu, &tss_seg, old_tss_base, sizeof(tss_seg)); + save_state_to_tss32(cpu, &tss_seg); + + vmx_write_mem(cpu, old_tss_base + eip_offset, &tss_seg.eip, ldt_sel_offset - eip_offset); + vmx_read_mem(cpu, &tss_seg, new_tss_base, sizeof(tss_seg)); + + if (old_tss_sel.sel != 0xffff) { + tss_seg.prev_tss = old_tss_sel.sel; + + vmx_write_mem(cpu, new_tss_base, &tss_seg.prev_tss, sizeof(tss_seg.prev_tss)); + } + load_state_from_tss32(cpu, &tss_seg); + return 0; +} + +static void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type) +{ + uint64_t rip = rreg(cpu->hvf_fd, HV_X86_RIP); + if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION && + gate_type != VMCS_INTR_T_HWINTR && + gate_type != VMCS_INTR_T_NMI)) { + int ins_len = rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); + macvm_set_rip(cpu, rip + ins_len); + return; + } + + load_regs(cpu); + + struct x86_segment_descriptor curr_tss_desc, next_tss_desc; + int ret; + x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, REG_SEG_TR); + uint64_t old_tss_base = vmx_read_segment_base(cpu, REG_SEG_TR); + uint32_t desc_limit; + struct x86_call_gate task_gate_desc; + struct vmx_segment vmx_seg; + + x86_read_segment_descriptor(cpu, &next_tss_desc, tss_sel); + x86_read_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); + + if (reason == TSR_IDT_GATE && gate_valid) { + int dpl; + + ret = x86_read_call_gate(cpu, &task_gate_desc, gate); + + dpl = task_gate_desc.dpl; + x68_segment_selector cs = vmx_read_segment_selector(cpu, REG_SEG_CS); + if (tss_sel.rpl > dpl || cs.rpl > dpl) + ;//DPRINTF("emulate_gp"); + } + + desc_limit = x86_segment_limit(&next_tss_desc); + if (!next_tss_desc.p || ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || desc_limit < 0x2b)) { + VM_PANIC("emulate_ts"); + } + + if (reason == TSR_IRET || reason == TSR_JMP) { + curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ + x86_write_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); + } + + if (reason == TSR_IRET) + EFLAGS(cpu) &= ~RFLAGS_NT; + + if (reason != TSR_CALL && reason != TSR_IDT_GATE) + old_tss_sel.sel = 0xffff; + + if (reason != TSR_IRET) { + next_tss_desc.type |= (1 << 1); /* set busy flag */ + x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); + } + + if (next_tss_desc.type & 8) + ret = task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); + else + //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); + VM_PANIC("task_switch_16"); + + macvm_set_cr0(cpu->hvf_fd, rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0) | CR0_TS); + x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); + vmx_write_segment_descriptor(cpu, &vmx_seg, REG_SEG_TR); + + store_regs(cpu); + + hv_vcpu_invalidate_tlb(cpu->hvf_fd); + hv_vcpu_flush(cpu->hvf_fd); +} + +static void hvf_handle_interrupt(CPUState * cpu, int mask) +{ + cpu->interrupt_request |= mask; + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } +} + +void hvf_handle_io(CPUArchState *env, uint16_t port, void *buffer, + int direction, int size, int count) +{ + int i; + uint8_t *ptr = buffer; + + for (i = 0; i < count; i++) { + address_space_rw(&address_space_io, port, MEMTXATTRS_UNSPECIFIED, + ptr, size, + direction); + ptr += size; + } +} + +/* TODO: synchronize vcpu state */ +static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) +{ + CPUState *cpu_state = cpu; + if (cpu_state->vcpu_dirty == 0) { + hvf_get_registers(cpu_state); + } + + cpu_state->vcpu_dirty = 1; +} + +void hvf_cpu_synchronize_state(CPUState *cpu_state) +{ + if (cpu_state->vcpu_dirty == 0) { + run_on_cpu(cpu_state, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL); + } +} + +static void do_hvf_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) +{ + CPUState *cpu_state = cpu; + hvf_put_registers(cpu_state); + cpu_state->vcpu_dirty = false; +} + +void hvf_cpu_synchronize_post_reset(CPUState *cpu_state) +{ + run_on_cpu(cpu_state, do_hvf_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); +} + +void _hvf_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) +{ + CPUState *cpu_state = cpu; + hvf_put_registers(cpu_state); + cpu_state->vcpu_dirty = false; +} + +void hvf_cpu_synchronize_post_init(CPUState *cpu_state) +{ + run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); +} + +/* TODO: ept fault handlig */ +static bool ept_emulation_fault(uint64_t ept_qual) +{ + int read, write; + + /* EPT fault on an instruction fetch doesn't make sense here */ + if (ept_qual & EPT_VIOLATION_INST_FETCH) { + return false; + } + + /* EPT fault must be a read fault or a write fault */ + read = ept_qual & EPT_VIOLATION_DATA_READ ? 1 : 0; + write = ept_qual & EPT_VIOLATION_DATA_WRITE ? 1 : 0; + if ((read | write) == 0) { + return false; + } + + /* + * The EPT violation must have been caused by accessing a + * guest-physical address that is a translation of a guest-linear + * address. + */ + if ((ept_qual & EPT_VIOLATION_GLA_VALID) == 0 || + (ept_qual & EPT_VIOLATION_XLAT_VALID) == 0) { + return false; + } + + return true; +} + +static void hvf_region_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + hvf_set_phys_mem(section, true); +} + +static void hvf_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + hvf_set_phys_mem(section, false); +} + +static MemoryListener hvf_memory_listener = { + .priority = 10, + .region_add = hvf_region_add, + .region_del = hvf_region_del, +}; + +void hvf_reset_vcpu(CPUState *cpu) { + + /* TODO: this shouldn't be needed; there is already a call to + * cpu_synchronize_all_post_reset in vl.c + */ + wvmcs(cpu->hvf_fd, VMCS_ENTRY_CTLS, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, 0); + macvm_set_cr0(cpu->hvf_fd, 0x60000010); + + wvmcs(cpu->hvf_fd, VMCS_CR4_MASK, CR4_VMXE_MASK); + wvmcs(cpu->hvf_fd, VMCS_CR4_SHADOW, 0x0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_CR4, CR4_VMXE_MASK); + + /* set VMCS guest state fields */ + wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_SELECTOR, 0xf000); + wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_ACCESS_RIGHTS, 0x9b); + wvmcs(cpu->hvf_fd, VMCS_GUEST_CS_BASE, 0xffff0000); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_ACCESS_RIGHTS, 0x93); + wvmcs(cpu->hvf_fd, VMCS_GUEST_DS_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_ACCESS_RIGHTS, 0x93); + wvmcs(cpu->hvf_fd, VMCS_GUEST_ES_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_ACCESS_RIGHTS, 0x93); + wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_ACCESS_RIGHTS, 0x93); + wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_LIMIT, 0xffff); + wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_ACCESS_RIGHTS, 0x93); + wvmcs(cpu->hvf_fd, VMCS_GUEST_SS_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_ACCESS_RIGHTS, 0x10000); + wvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_SELECTOR, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_LIMIT, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_ACCESS_RIGHTS, 0x83); + wvmcs(cpu->hvf_fd, VMCS_GUEST_TR_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE, 0); + + wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT, 0); + wvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE, 0); + + /*wvmcs(cpu->hvf_fd, VMCS_GUEST_CR2, 0x0);*/ + wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, 0x0); + + wreg(cpu->hvf_fd, HV_X86_RIP, 0xfff0); + wreg(cpu->hvf_fd, HV_X86_RDX, 0x623); + wreg(cpu->hvf_fd, HV_X86_RFLAGS, 0x2); + wreg(cpu->hvf_fd, HV_X86_RSP, 0x0); + wreg(cpu->hvf_fd, HV_X86_RAX, 0x0); + wreg(cpu->hvf_fd, HV_X86_RBX, 0x0); + wreg(cpu->hvf_fd, HV_X86_RCX, 0x0); + wreg(cpu->hvf_fd, HV_X86_RSI, 0x0); + wreg(cpu->hvf_fd, HV_X86_RDI, 0x0); + wreg(cpu->hvf_fd, HV_X86_RBP, 0x0); + + for (int i = 0; i < 8; i++) { + wreg(cpu->hvf_fd, HV_X86_R8 + i, 0x0); + } + + hv_vm_sync_tsc(0); + cpu->halted = 0; + hv_vcpu_invalidate_tlb(cpu->hvf_fd); + hv_vcpu_flush(cpu->hvf_fd); +} + +void hvf_vcpu_destroy(CPUState *cpu) +{ + hv_return_t ret = hv_vcpu_destroy((hv_vcpuid_t)cpu->hvf_fd); + assert_hvf_ok(ret); +} + +static void dummy_signal(int sig) +{ +} + +int hvf_init_vcpu(CPUState *cpu) +{ + + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + int r; + + /* init cpu signals */ + sigset_t set; + struct sigaction sigact; + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = dummy_signal; + sigaction(SIG_IPI, &sigact, NULL); + + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + + init_emu(); + init_decoder(); + + hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1); + env->hvf_emul = g_new0(HVFX86EmulatorState, 1); + + r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf_fd, HV_VCPU_DEFAULT); + cpu->vcpu_dirty = 1; + assert_hvf_ok(r); + + if (hv_vmx_read_capability(HV_VMX_CAP_PINBASED, + &hvf_state->hvf_caps->vmx_cap_pinbased)) { + abort(); + } + if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, + &hvf_state->hvf_caps->vmx_cap_procbased)) { + abort(); + } + if (hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, + &hvf_state->hvf_caps->vmx_cap_procbased2)) { + abort(); + } + if (hv_vmx_read_capability(HV_VMX_CAP_ENTRY, + &hvf_state->hvf_caps->vmx_cap_entry)) { + abort(); + } + + /* set VMCS control fields */ + wvmcs(cpu->hvf_fd, VMCS_PIN_BASED_CTLS, + cap2ctrl(hvf_state->hvf_caps->vmx_cap_pinbased, + VMCS_PIN_BASED_CTLS_EXTINT | + VMCS_PIN_BASED_CTLS_NMI | + VMCS_PIN_BASED_CTLS_VNMI)); + wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, + cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased, + VMCS_PRI_PROC_BASED_CTLS_HLT | + VMCS_PRI_PROC_BASED_CTLS_MWAIT | + VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET | + VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW) | + VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL); + wvmcs(cpu->hvf_fd, VMCS_SEC_PROC_BASED_CTLS, + cap2ctrl(hvf_state->hvf_caps->vmx_cap_procbased2, + VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES)); + + wvmcs(cpu->hvf_fd, VMCS_ENTRY_CTLS, cap2ctrl(hvf_state->hvf_caps->vmx_cap_entry, + 0)); + wvmcs(cpu->hvf_fd, VMCS_EXCEPTION_BITMAP, 0); /* Double fault */ + + wvmcs(cpu->hvf_fd, VMCS_TPR_THRESHOLD, 0); + + hvf_reset_vcpu(cpu); + + x86cpu = X86_CPU(cpu); + x86cpu->env.kvm_xsave_buf = qemu_memalign(4096, + sizeof(struct hvf_xsave_buf)); + + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_STAR, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_LSTAR, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_CSTAR, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FMASK, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_FSBASE, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_GSBASE, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_KERNELGSBASE, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_TSC_AUX, 1); + /*hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_TSC, 1);*/ + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_CS, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_EIP, 1); + hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_IA32_SYSENTER_ESP, 1); + + return 0; +} + +void hvf_disable(int shouldDisable) +{ + hvf_disabled = shouldDisable; +} + +int hvf_vcpu_exec(CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + int ret = 0; + uint64_t rip = 0; + + cpu->halted = 0; + + if (hvf_process_events(cpu)) { + return EXCP_HLT; + } + + do { + if (cpu->vcpu_dirty) { + hvf_put_registers(cpu); + cpu->vcpu_dirty = false; + } + + env->hvf_emul->interruptable = + !(rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & + (VMCS_INTERRUPTIBILITY_STI_BLOCKING | + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)); + + hvf_inject_interrupts(cpu); + vmx_update_tpr(cpu); + + qemu_mutex_unlock_iothread(); + if (!cpu_is_bsp(X86_CPU(cpu)) && cpu->halted) { + qemu_mutex_lock_iothread(); + return EXCP_HLT; + } + + hv_return_t r = hv_vcpu_run(cpu->hvf_fd); + assert_hvf_ok(r); + + /* handle VMEXIT */ + uint64_t exit_reason = rvmcs(cpu->hvf_fd, VMCS_EXIT_REASON); + uint64_t exit_qual = rvmcs(cpu->hvf_fd, VMCS_EXIT_QUALIFICATION); + uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf_fd, + VMCS_EXIT_INSTRUCTION_LENGTH); + uint64_t idtvec_info = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO); + rip = rreg(cpu->hvf_fd, HV_X86_RIP); + RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); + env->eflags = RFLAGS(env); + + qemu_mutex_lock_iothread(); + + update_apic_tpr(cpu); + current_cpu = cpu; + + ret = 0; + switch (exit_reason) { + case EXIT_REASON_HLT: { + macvm_set_rip(cpu, rip + ins_len); + if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && + (EFLAGS(env) & IF_MASK)) + && !(cpu->interrupt_request & CPU_INTERRUPT_NMI) && + !(idtvec_info & VMCS_IDT_VEC_VALID)) { + cpu->halted = 1; + ret = EXCP_HLT; + } + ret = EXCP_INTERRUPT; + break; + } + case EXIT_REASON_MWAIT: { + ret = EXCP_INTERRUPT; + break; + } + /* Need to check if MMIO or unmmaped fault */ + case EXIT_REASON_EPT_FAULT: + { + hvf_slot *slot; + addr_t gpa = rvmcs(cpu->hvf_fd, VMCS_GUEST_PHYSICAL_ADDRESS); + + if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) && + ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) { + vmx_set_nmi_blocking(cpu); + } + + slot = hvf_find_overlap_slot(gpa, gpa); + /* mmio */ + if (ept_emulation_fault(exit_qual) && !slot) { + struct x86_decode decode; + + load_regs(cpu); + env->hvf_emul->fetch_rip = rip; + + decode_instruction(env, &decode); + exec_instruction(env, &decode); + store_regs(cpu); + break; + } +#ifdef DIRTY_VGA_TRACKING + /* TODO: handle dirty page tracking */ +#endif + break; + } + case EXIT_REASON_INOUT: + { + uint32_t in = (exit_qual & 8) != 0; + uint32_t size = (exit_qual & 7) + 1; + uint32_t string = (exit_qual & 16) != 0; + uint32_t port = exit_qual >> 16; + /*uint32_t rep = (exit_qual & 0x20) != 0;*/ + +#if 1 + if (!string && in) { + uint64_t val = 0; + load_regs(cpu); + hvf_handle_io(env, port, &val, 0, size, 1); + if (size == 1) { + AL(env) = val; + } else if (size == 2) { + AX(env) = val; + } else if (size == 4) { + RAX(env) = (uint32_t)val; + } else { + VM_PANIC("size"); + } + RIP(env) += ins_len; + store_regs(cpu); + break; + } else if (!string && !in) { + RAX(env) = rreg(cpu->hvf_fd, HV_X86_RAX); + hvf_handle_io(env, port, &RAX(env), 1, size, 1); + macvm_set_rip(cpu, rip + ins_len); + break; + } +#endif + struct x86_decode decode; + + load_regs(cpu); + env->hvf_emul->fetch_rip = rip; + + decode_instruction(env, &decode); + VM_PANIC_ON(ins_len != decode.len); + exec_instruction(env, &decode); + store_regs(cpu); + + break; + } + case EXIT_REASON_CPUID: { + uint32_t rax = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RAX); + uint32_t rbx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RBX); + uint32_t rcx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RCX); + uint32_t rdx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RDX); + + cpu_x86_cpuid(env, rax, rcx, &rax, &rbx, &rcx, &rdx); + + wreg(cpu->hvf_fd, HV_X86_RAX, rax); + wreg(cpu->hvf_fd, HV_X86_RBX, rbx); + wreg(cpu->hvf_fd, HV_X86_RCX, rcx); + wreg(cpu->hvf_fd, HV_X86_RDX, rdx); + + macvm_set_rip(cpu, rip + ins_len); + break; + } + case EXIT_REASON_XSETBV: { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + uint32_t eax = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RAX); + uint32_t ecx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RCX); + uint32_t edx = (uint32_t)rreg(cpu->hvf_fd, HV_X86_RDX); + + if (ecx) { + macvm_set_rip(cpu, rip + ins_len); + break; + } + env->xcr0 = ((uint64_t)edx << 32) | eax; + wreg(cpu->hvf_fd, HV_X86_XCR0, env->xcr0 | 1); + macvm_set_rip(cpu, rip + ins_len); + break; + } + case EXIT_REASON_INTR_WINDOW: + vmx_clear_int_window_exiting(cpu); + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_NMI_WINDOW: + vmx_clear_nmi_window_exiting(cpu); + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_EXT_INTR: + /* force exit and allow io handling */ + ret = EXCP_INTERRUPT; + break; + case EXIT_REASON_RDMSR: + case EXIT_REASON_WRMSR: + { + load_regs(cpu); + if (exit_reason == EXIT_REASON_RDMSR) { + simulate_rdmsr(cpu); + } else { + simulate_wrmsr(cpu); + } + RIP(env) += rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); + store_regs(cpu); + break; + } + case EXIT_REASON_CR_ACCESS: { + int cr; + int reg; + + load_regs(cpu); + cr = exit_qual & 15; + reg = (exit_qual >> 8) & 15; + + switch (cr) { + case 0x0: { + macvm_set_cr0(cpu->hvf_fd, RRX(env, reg)); + break; + } + case 4: { + macvm_set_cr4(cpu->hvf_fd, RRX(env, reg)); + break; + } + case 8: { + X86CPU *x86_cpu = X86_CPU(cpu); + if (exit_qual & 0x10) { + RRX(env, reg) = cpu_get_apic_tpr(x86_cpu->apic_state); + } else { + int tpr = RRX(env, reg); + cpu_set_apic_tpr(x86_cpu->apic_state, tpr); + ret = EXCP_INTERRUPT; + } + break; + } + default: + error_report("Unrecognized CR %d\n", cr); + abort(); + } + RIP(env) += ins_len; + store_regs(cpu); + break; + } + case EXIT_REASON_APIC_ACCESS: { /* TODO */ + struct x86_decode decode; + + load_regs(cpu); + env->hvf_emul->fetch_rip = rip; + + decode_instruction(env, &decode); + exec_instruction(env, &decode); + store_regs(cpu); + break; + } + case EXIT_REASON_TPR: { + ret = 1; + break; + } + case EXIT_REASON_TASK_SWITCH: { + uint64_t vinfo = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO); + x68_segment_selector sel = {.sel = exit_qual & 0xffff}; + vmx_handle_task_switch(cpu, sel, (exit_qual >> 30) & 0x3, + vinfo & VMCS_INTR_VALID, vinfo & VECTORING_INFO_VECTOR_MASK, vinfo + & VMCS_INTR_T_MASK); + break; + } + case EXIT_REASON_TRIPLE_FAULT: { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + ret = EXCP_INTERRUPT; + break; + } + case EXIT_REASON_RDPMC: + wreg(cpu->hvf_fd, HV_X86_RAX, 0); + wreg(cpu->hvf_fd, HV_X86_RDX, 0); + macvm_set_rip(cpu, rip + ins_len); + break; + case VMX_REASON_VMCALL: + /* TODO: inject #GP fault */ + break; + default: + error_report("%llx: unhandled exit %llx\n", rip, exit_reason); + } + } while (ret == 0); + + return ret; +} + +static bool hvf_allowed; + +static int hvf_accel_init(MachineState *ms) +{ + int x; + hv_return_t ret; + HVFState *s; + + hvf_disable(0); + ret = hv_vm_create(HV_VM_DEFAULT); + assert_hvf_ok(ret); + + s = g_new0(HVFState, 1); + + s->num_slots = 32; + for (x = 0; x < s->num_slots; ++x) { + s->slots[x].size = 0; + s->slots[x].slot_id = x; + } + + hvf_state = s; + cpu_interrupt_handler = hvf_handle_interrupt; + memory_listener_register(&hvf_memory_listener, &address_space_memory); + return 0; +} + +static void hvf_accel_class_init(ObjectClass *oc, void *data) +{ + AccelClass *ac = ACCEL_CLASS(oc); + ac->name = "HVF"; + ac->init_machine = hvf_accel_init; + ac->allowed = &hvf_allowed; +} + +static const TypeInfo hvf_accel_type = { + .name = TYPE_HVF_ACCEL, + .parent = TYPE_ACCEL, + .class_init = hvf_accel_class_init, +}; + +static void hvf_type_init(void) +{ + type_register_static(&hvf_accel_type); +} + +type_init(hvf_type_init); diff --git a/target/i386/hvf-i386.h b/target/i386/hvf-i386.h new file mode 100644 index 0000000000..797718ce34 --- /dev/null +++ b/target/i386/hvf-i386.h @@ -0,0 +1,48 @@ +/* + * QEMU Hypervisor.framework (HVF) support + * + * Copyright 2017 Google Inc + * + * Adapted from target-i386/hax-i386.h: + * Copyright (c) 2011 Intel Corporation + * Written by: + * Jiang Yunhong + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef _HVF_I386_H +#define _HVF_I386_H + +#include "sysemu/hvf.h" +#include "cpu.h" +#include "hvf-utils/x86.h" + +#define HVF_MAX_VCPU 0x10 +#define MAX_VM_ID 0x40 +#define MAX_VCPU_ID 0x40 + +extern struct hvf_state hvf_global; + +struct hvf_vm { + int id; + struct hvf_vcpu_state *vcpus[HVF_MAX_VCPU]; +}; + +struct hvf_state { + uint32_t version; + struct hvf_vm *vm; + uint64_t mem_quota; +}; + +#ifdef NEED_CPU_H +/* Functions exported to host specific mode */ + +/* Host specific functions */ +int hvf_inject_interrupt(CPUArchState *env, int vector); +int hvf_vcpu_run(struct hvf_vcpu_state *vcpu); +#endif + +#endif diff --git a/target/i386/hvf-utils/Makefile.objs b/target/i386/hvf-utils/Makefile.objs new file mode 100644 index 0000000000..7df219ad9c --- /dev/null +++ b/target/i386/hvf-utils/Makefile.objs @@ -0,0 +1 @@ +obj-y += x86.o x86_cpuid.o x86_decode.o x86_descr.o x86_emu.o x86_flags.o x86_mmu.o x86hvf.o diff --git a/target/i386/hvf-utils/README.md b/target/i386/hvf-utils/README.md new file mode 100644 index 0000000000..0d27a0d52b --- /dev/null +++ b/target/i386/hvf-utils/README.md @@ -0,0 +1,7 @@ +# OS X Hypervisor.framework support in QEMU + +These sources (and ../hvf-all.c) are adapted from Veertu Inc's vdhh (Veertu Desktop Hosted Hypervisor) (last known location: https://github.com/veertuinc/vdhh) with some minor changes, the most significant of which were: + +1. Adapt to our current QEMU's `CPUState` structure and `address_space_rw` API; many struct members have been moved around (emulated x86 state, kvm_xsave_buf) due to historical differences + QEMU needing to handle more emulation targets. +2. Removal of `apic_page` and hyperv-related functionality. +3. More relaxed use of `qemu_mutex_lock_iothread`. diff --git a/target/i386/hvf-utils/vmcs.h b/target/i386/hvf-utils/vmcs.h new file mode 100644 index 0000000000..cd3a19fe38 --- /dev/null +++ b/target/i386/hvf-utils/vmcs.h @@ -0,0 +1,371 @@ +/*- + * Copyright (c) 2011 NetApp, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VMCS_H_ +#define _VMCS_H_ + +#include +#include + +#define VMCS_INITIAL 0xffffffffffffffff + +#define VMCS_IDENT(encoding) ((encoding) | 0x80000000) +/* + * VMCS field encodings from Appendix H, Intel Architecture Manual Vol3B. + */ +#define VMCS_INVALID_ENCODING 0xffffffff + +/* 16-bit control fields */ +#define VMCS_VPID 0x00000000 +#define VMCS_PIR_VECTOR 0x00000002 + +/* 16-bit guest-state fields */ +#define VMCS_GUEST_ES_SELECTOR 0x00000800 +#define VMCS_GUEST_CS_SELECTOR 0x00000802 +#define VMCS_GUEST_SS_SELECTOR 0x00000804 +#define VMCS_GUEST_DS_SELECTOR 0x00000806 +#define VMCS_GUEST_FS_SELECTOR 0x00000808 +#define VMCS_GUEST_GS_SELECTOR 0x0000080A +#define VMCS_GUEST_LDTR_SELECTOR 0x0000080C +#define VMCS_GUEST_TR_SELECTOR 0x0000080E +#define VMCS_GUEST_INTR_STATUS 0x00000810 + +/* 16-bit host-state fields */ +#define VMCS_HOST_ES_SELECTOR 0x00000C00 +#define VMCS_HOST_CS_SELECTOR 0x00000C02 +#define VMCS_HOST_SS_SELECTOR 0x00000C04 +#define VMCS_HOST_DS_SELECTOR 0x00000C06 +#define VMCS_HOST_FS_SELECTOR 0x00000C08 +#define VMCS_HOST_GS_SELECTOR 0x00000C0A +#define VMCS_HOST_TR_SELECTOR 0x00000C0C + +/* 64-bit control fields */ +#define VMCS_IO_BITMAP_A 0x00002000 +#define VMCS_IO_BITMAP_B 0x00002002 +#define VMCS_MSR_BITMAP 0x00002004 +#define VMCS_EXIT_MSR_STORE 0x00002006 +#define VMCS_EXIT_MSR_LOAD 0x00002008 +#define VMCS_ENTRY_MSR_LOAD 0x0000200A +#define VMCS_EXECUTIVE_VMCS 0x0000200C +#define VMCS_TSC_OFFSET 0x00002010 +#define VMCS_VIRTUAL_APIC 0x00002012 +#define VMCS_APIC_ACCESS 0x00002014 +#define VMCS_PIR_DESC 0x00002016 +#define VMCS_EPTP 0x0000201A +#define VMCS_EOI_EXIT0 0x0000201C +#define VMCS_EOI_EXIT1 0x0000201E +#define VMCS_EOI_EXIT2 0x00002020 +#define VMCS_EOI_EXIT3 0x00002022 +#define VMCS_EOI_EXIT(vector) (VMCS_EOI_EXIT0 + ((vector) / 64) * 2) + +/* 64-bit read-only fields */ +#define VMCS_GUEST_PHYSICAL_ADDRESS 0x00002400 + +/* 64-bit guest-state fields */ +#define VMCS_LINK_POINTER 0x00002800 +#define VMCS_GUEST_IA32_DEBUGCTL 0x00002802 +#define VMCS_GUEST_IA32_PAT 0x00002804 +#define VMCS_GUEST_IA32_EFER 0x00002806 +#define VMCS_GUEST_IA32_PERF_GLOBAL_CTRL 0x00002808 +#define VMCS_GUEST_PDPTE0 0x0000280A +#define VMCS_GUEST_PDPTE1 0x0000280C +#define VMCS_GUEST_PDPTE2 0x0000280E +#define VMCS_GUEST_PDPTE3 0x00002810 + +/* 64-bit host-state fields */ +#define VMCS_HOST_IA32_PAT 0x00002C00 +#define VMCS_HOST_IA32_EFER 0x00002C02 +#define VMCS_HOST_IA32_PERF_GLOBAL_CTRL 0x00002C04 + +/* 32-bit control fields */ +#define VMCS_PIN_BASED_CTLS 0x00004000 +#define VMCS_PRI_PROC_BASED_CTLS 0x00004002 +#define VMCS_EXCEPTION_BITMAP 0x00004004 +#define VMCS_PF_ERROR_MASK 0x00004006 +#define VMCS_PF_ERROR_MATCH 0x00004008 +#define VMCS_CR3_TARGET_COUNT 0x0000400A +#define VMCS_EXIT_CTLS 0x0000400C +#define VMCS_EXIT_MSR_STORE_COUNT 0x0000400E +#define VMCS_EXIT_MSR_LOAD_COUNT 0x00004010 +#define VMCS_ENTRY_CTLS 0x00004012 +#define VMCS_ENTRY_MSR_LOAD_COUNT 0x00004014 +#define VMCS_ENTRY_INTR_INFO 0x00004016 +#define VMCS_ENTRY_EXCEPTION_ERROR 0x00004018 +#define VMCS_ENTRY_INST_LENGTH 0x0000401A +#define VMCS_TPR_THRESHOLD 0x0000401C +#define VMCS_SEC_PROC_BASED_CTLS 0x0000401E +#define VMCS_PLE_GAP 0x00004020 +#define VMCS_PLE_WINDOW 0x00004022 + +/* 32-bit read-only data fields */ +#define VMCS_INSTRUCTION_ERROR 0x00004400 +#define VMCS_EXIT_REASON 0x00004402 +#define VMCS_EXIT_INTR_INFO 0x00004404 +#define VMCS_EXIT_INTR_ERRCODE 0x00004406 +#define VMCS_IDT_VECTORING_INFO 0x00004408 +#define VMCS_IDT_VECTORING_ERROR 0x0000440A +#define VMCS_EXIT_INSTRUCTION_LENGTH 0x0000440C +#define VMCS_EXIT_INSTRUCTION_INFO 0x0000440E + +/* 32-bit guest-state fields */ +#define VMCS_GUEST_ES_LIMIT 0x00004800 +#define VMCS_GUEST_CS_LIMIT 0x00004802 +#define VMCS_GUEST_SS_LIMIT 0x00004804 +#define VMCS_GUEST_DS_LIMIT 0x00004806 +#define VMCS_GUEST_FS_LIMIT 0x00004808 +#define VMCS_GUEST_GS_LIMIT 0x0000480A +#define VMCS_GUEST_LDTR_LIMIT 0x0000480C +#define VMCS_GUEST_TR_LIMIT 0x0000480E +#define VMCS_GUEST_GDTR_LIMIT 0x00004810 +#define VMCS_GUEST_IDTR_LIMIT 0x00004812 +#define VMCS_GUEST_ES_ACCESS_RIGHTS 0x00004814 +#define VMCS_GUEST_CS_ACCESS_RIGHTS 0x00004816 +#define VMCS_GUEST_SS_ACCESS_RIGHTS 0x00004818 +#define VMCS_GUEST_DS_ACCESS_RIGHTS 0x0000481A +#define VMCS_GUEST_FS_ACCESS_RIGHTS 0x0000481C +#define VMCS_GUEST_GS_ACCESS_RIGHTS 0x0000481E +#define VMCS_GUEST_LDTR_ACCESS_RIGHTS 0x00004820 +#define VMCS_GUEST_TR_ACCESS_RIGHTS 0x00004822 +#define VMCS_GUEST_INTERRUPTIBILITY 0x00004824 +#define VMCS_GUEST_ACTIVITY 0x00004826 +#define VMCS_GUEST_SMBASE 0x00004828 +#define VMCS_GUEST_IA32_SYSENTER_CS 0x0000482A +#define VMCS_PREEMPTION_TIMER_VALUE 0x0000482E + +/* 32-bit host state fields */ +#define VMCS_HOST_IA32_SYSENTER_CS 0x00004C00 + +/* Natural Width control fields */ +#define VMCS_CR0_MASK 0x00006000 +#define VMCS_CR4_MASK 0x00006002 +#define VMCS_CR0_SHADOW 0x00006004 +#define VMCS_CR4_SHADOW 0x00006006 +#define VMCS_CR3_TARGET0 0x00006008 +#define VMCS_CR3_TARGET1 0x0000600A +#define VMCS_CR3_TARGET2 0x0000600C +#define VMCS_CR3_TARGET3 0x0000600E + +/* Natural Width read-only fields */ +#define VMCS_EXIT_QUALIFICATION 0x00006400 +#define VMCS_IO_RCX 0x00006402 +#define VMCS_IO_RSI 0x00006404 +#define VMCS_IO_RDI 0x00006406 +#define VMCS_IO_RIP 0x00006408 +#define VMCS_GUEST_LINEAR_ADDRESS 0x0000640A + +/* Natural Width guest-state fields */ +#define VMCS_GUEST_CR0 0x00006800 +#define VMCS_GUEST_CR3 0x00006802 +#define VMCS_GUEST_CR4 0x00006804 +#define VMCS_GUEST_ES_BASE 0x00006806 +#define VMCS_GUEST_CS_BASE 0x00006808 +#define VMCS_GUEST_SS_BASE 0x0000680A +#define VMCS_GUEST_DS_BASE 0x0000680C +#define VMCS_GUEST_FS_BASE 0x0000680E +#define VMCS_GUEST_GS_BASE 0x00006810 +#define VMCS_GUEST_LDTR_BASE 0x00006812 +#define VMCS_GUEST_TR_BASE 0x00006814 +#define VMCS_GUEST_GDTR_BASE 0x00006816 +#define VMCS_GUEST_IDTR_BASE 0x00006818 +#define VMCS_GUEST_DR7 0x0000681A +#define VMCS_GUEST_RSP 0x0000681C +#define VMCS_GUEST_RIP 0x0000681E +#define VMCS_GUEST_RFLAGS 0x00006820 +#define VMCS_GUEST_PENDING_DBG_EXCEPTIONS 0x00006822 +#define VMCS_GUEST_IA32_SYSENTER_ESP 0x00006824 +#define VMCS_GUEST_IA32_SYSENTER_EIP 0x00006826 + +/* Natural Width host-state fields */ +#define VMCS_HOST_CR0 0x00006C00 +#define VMCS_HOST_CR3 0x00006C02 +#define VMCS_HOST_CR4 0x00006C04 +#define VMCS_HOST_FS_BASE 0x00006C06 +#define VMCS_HOST_GS_BASE 0x00006C08 +#define VMCS_HOST_TR_BASE 0x00006C0A +#define VMCS_HOST_GDTR_BASE 0x00006C0C +#define VMCS_HOST_IDTR_BASE 0x00006C0E +#define VMCS_HOST_IA32_SYSENTER_ESP 0x00006C10 +#define VMCS_HOST_IA32_SYSENTER_EIP 0x00006C12 +#define VMCS_HOST_RSP 0x00006C14 +#define VMCS_HOST_RIP 0x00006c16 + +/* + * VM instruction error numbers + */ +#define VMRESUME_WITH_NON_LAUNCHED_VMCS 5 + +/* + * VMCS exit reasons + */ +#define EXIT_REASON_EXCEPTION 0 +#define EXIT_REASON_EXT_INTR 1 +#define EXIT_REASON_TRIPLE_FAULT 2 +#define EXIT_REASON_INIT 3 +#define EXIT_REASON_SIPI 4 +#define EXIT_REASON_IO_SMI 5 +#define EXIT_REASON_SMI 6 +#define EXIT_REASON_INTR_WINDOW 7 +#define EXIT_REASON_NMI_WINDOW 8 +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_GETSEC 11 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVD 13 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_RSM 17 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMXOFF 26 +#define EXIT_REASON_VMXON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_INOUT 30 +#define EXIT_REASON_RDMSR 31 +#define EXIT_REASON_WRMSR 32 +#define EXIT_REASON_INVAL_VMCS 33 +#define EXIT_REASON_INVAL_MSR 34 +#define EXIT_REASON_MWAIT 36 +#define EXIT_REASON_MTF 37 +#define EXIT_REASON_MONITOR 39 +#define EXIT_REASON_PAUSE 40 +#define EXIT_REASON_MCE_DURING_ENTR 41 +#define EXIT_REASON_TPR 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_VIRTUALIZED_EOI 45 +#define EXIT_REASON_GDTR_IDTR 46 +#define EXIT_REASON_LDTR_TR 47 +#define EXIT_REASON_EPT_FAULT 48 +#define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_INVEPT 50 +#define EXIT_REASON_RDTSCP 51 +#define EXIT_REASON_VMX_PREEMPT 52 +#define EXIT_REASON_INVVPID 53 +#define EXIT_REASON_WBINVD 54 +#define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_APIC_WRITE 56 + +/* + * NMI unblocking due to IRET. + * + * Applies to VM-exits due to hardware exception or EPT fault. + */ +#define EXIT_QUAL_NMIUDTI (1 << 12) +/* + * VMCS interrupt information fields + */ +#define VMCS_INTR_VALID (1U << 31) +#define VMCS_INTR_T_MASK 0x700 /* Interruption-info type */ +#define VMCS_INTR_T_HWINTR (0 << 8) +#define VMCS_INTR_T_NMI (2 << 8) +#define VMCS_INTR_T_HWEXCEPTION (3 << 8) +#define VMCS_INTR_T_SWINTR (4 << 8) +#define VMCS_INTR_T_PRIV_SWEXCEPTION (5 << 8) +#define VMCS_INTR_T_SWEXCEPTION (6 << 8) +#define VMCS_INTR_DEL_ERRCODE (1 << 11) + +/* + * VMCS IDT-Vectoring information fields + */ +#define VMCS_IDT_VEC_VALID (1U << 31) +#define VMCS_IDT_VEC_TYPE 0x700 +#define VMCS_IDT_VEC_ERRCODE_VALID (1U << 11) +#define VMCS_IDT_VEC_HWINTR (0 << 8) +#define VMCS_IDT_VEC_NMI (2 << 8) +#define VMCS_IDT_VEC_HWEXCEPTION (3 << 8) +#define VMCS_IDT_VEC_SWINTR (4 << 8) + +/* + * VMCS Guest interruptibility field + */ +#define VMCS_INTERRUPTIBILITY_STI_BLOCKING (1 << 0) +#define VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING (1 << 1) +#define VMCS_INTERRUPTIBILITY_SMI_BLOCKING (1 << 2) +#define VMCS_INTERRUPTIBILITY_NMI_BLOCKING (1 << 3) + +/* + * Exit qualification for EXIT_REASON_INVAL_VMCS + */ +#define EXIT_QUAL_NMI_WHILE_STI_BLOCKING 3 + +/* + * Exit qualification for EPT violation + */ +#define EPT_VIOLATION_DATA_READ (1UL << 0) +#define EPT_VIOLATION_DATA_WRITE (1UL << 1) +#define EPT_VIOLATION_INST_FETCH (1UL << 2) +#define EPT_VIOLATION_GPA_READABLE (1UL << 3) +#define EPT_VIOLATION_GPA_WRITEABLE (1UL << 4) +#define EPT_VIOLATION_GPA_EXECUTABLE (1UL << 5) +#define EPT_VIOLATION_GLA_VALID (1UL << 7) +#define EPT_VIOLATION_XLAT_VALID (1UL << 8) + +/* + * Exit qualification for APIC-access VM exit + */ +#define APIC_ACCESS_OFFSET(qual) ((qual) & 0xFFF) +#define APIC_ACCESS_TYPE(qual) (((qual) >> 12) & 0xF) + +/* + * Exit qualification for APIC-write VM exit + */ +#define APIC_WRITE_OFFSET(qual) ((qual) & 0xFFF) + +#define VMCS_PIN_BASED_CTLS_EXTINT (1 << 0) +#define VMCS_PIN_BASED_CTLS_NMI (1 << 3) +#define VMCS_PIN_BASED_CTLS_VNMI (1 << 5) + +#define VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING (1 << 2) +#define VMCS_PRI_PROC_BASED_CTLS_TSC_OFFSET (1 << 3) +#define VMCS_PRI_PROC_BASED_CTLS_HLT (1 << 7) +#define VMCS_PRI_PROC_BASED_CTLS_MWAIT (1 << 10) +#define VMCS_PRI_PROC_BASED_CTLS_TSC (1 << 12) +#define VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD (1 << 19) +#define VMCS_PRI_PROC_BASED_CTLS_CR8_STORE (1 << 20) +#define VMCS_PRI_PROC_BASED_CTLS_TPR_SHADOW (1 << 21) +#define VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING (1 << 22) +#define VMCS_PRI_PROC_BASED_CTLS_SEC_CONTROL (1 << 31) + +#define VMCS_PRI_PROC_BASED2_CTLS_APIC_ACCESSES (1 << 0) +#define VMCS_PRI_PROC_BASED2_CTLS_X2APIC (1 << 4) + +enum task_switch_reason { + TSR_CALL, + TSR_IRET, + TSR_JMP, + TSR_IDT_GATE, /* task gate in IDT */ +}; + +#endif diff --git a/target/i386/hvf-utils/vmx.h b/target/i386/hvf-utils/vmx.h new file mode 100644 index 0000000000..d086c8d253 --- /dev/null +++ b/target/i386/hvf-utils/vmx.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * Based on Veertu vddh/vmm/vmx.h + * + * Interfaces to Hypervisor.framework to read/write X86 registers and VMCS. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef VMX_H +#define VMX_H + +#include +#include +#include +#include "vmcs.h" +#include "cpu.h" +#include "x86.h" + +#include "exec/address-spaces.h" + +static inline uint64_t rreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg) +{ + uint64_t v; + + if (hv_vcpu_read_register(vcpu, reg, &v)) { + abort(); + } + + return v; +} + +/* write GPR */ +static inline void wreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t v) +{ + if (hv_vcpu_write_register(vcpu, reg, v)) { + abort(); + } +} + +/* read VMCS field */ +static inline uint64_t rvmcs(hv_vcpuid_t vcpu, uint32_t field) +{ + uint64_t v; + + hv_vmx_vcpu_read_vmcs(vcpu, field, &v); + + return v; +} + +/* write VMCS field */ +static inline void wvmcs(hv_vcpuid_t vcpu, uint32_t field, uint64_t v) +{ + hv_vmx_vcpu_write_vmcs(vcpu, field, v); +} + +/* desired control word constrained by hardware/hypervisor capabilities */ +static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl) +{ + return (ctrl | (cap & 0xffffffff)) & (cap >> 32); +} + +#define VM_ENTRY_GUEST_LMA (1LL << 9) + +#define AR_TYPE_ACCESSES_MASK 1 +#define AR_TYPE_READABLE_MASK (1 << 1) +#define AR_TYPE_WRITEABLE_MASK (1 << 2) +#define AR_TYPE_CODE_MASK (1 << 3) +#define AR_TYPE_MASK 0x0f +#define AR_TYPE_BUSY_64_TSS 11 +#define AR_TYPE_BUSY_32_TSS 11 +#define AR_TYPE_BUSY_16_TSS 3 +#define AR_TYPE_LDT 2 + +static void enter_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer) +{ + uint64_t entry_ctls; + + efer |= EFER_LMA; + wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer); + entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); + wvmcs(vcpu, VMCS_ENTRY_CTLS, rvmcs(vcpu, VMCS_ENTRY_CTLS) | + VM_ENTRY_GUEST_LMA); + + uint64_t guest_tr_ar = rvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS); + if ((efer & EFER_LME) && + (guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { + wvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS, + (guest_tr_ar & ~AR_TYPE_MASK) | AR_TYPE_BUSY_64_TSS); + } +} + +static void exit_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer) +{ + uint64_t entry_ctls; + + entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); + wvmcs(vcpu, VMCS_ENTRY_CTLS, entry_ctls & ~VM_ENTRY_GUEST_LMA); + + efer &= ~EFER_LMA; + wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer); +} + +static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) +{ + int i; + uint64_t pdpte[4] = {0, 0, 0, 0}; + uint64_t efer = rvmcs(vcpu, VMCS_GUEST_IA32_EFER); + uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); + + if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && + !(efer & EFER_LME)) { + address_space_rw(&address_space_memory, + rvmcs(vcpu, VMCS_GUEST_CR3) & ~0x1f, + MEMTXATTRS_UNSPECIFIED, + (uint8_t *)pdpte, 32, 0); + } + + for (i = 0; i < 4; i++) { + wvmcs(vcpu, VMCS_GUEST_PDPTE0 + i * 2, pdpte[i]); + } + + wvmcs(vcpu, VMCS_CR0_MASK, CR0_CD | CR0_NE | CR0_PG); + wvmcs(vcpu, VMCS_CR0_SHADOW, cr0); + + cr0 &= ~CR0_CD; + wvmcs(vcpu, VMCS_GUEST_CR0, cr0 | CR0_NE | CR0_ET); + + if (efer & EFER_LME) { + if (!(old_cr0 & CR0_PG) && (cr0 & CR0_PG)) { + enter_long_mode(vcpu, cr0, efer); + } + if (/*(old_cr0 & CR0_PG) &&*/ !(cr0 & CR0_PG)) { + exit_long_mode(vcpu, cr0, efer); + } + } + + hv_vcpu_invalidate_tlb(vcpu); + hv_vcpu_flush(vcpu); +} + +static inline void macvm_set_cr4(hv_vcpuid_t vcpu, uint64_t cr4) +{ + uint64_t guest_cr4 = cr4 | CR4_VMXE; + + wvmcs(vcpu, VMCS_GUEST_CR4, guest_cr4); + wvmcs(vcpu, VMCS_CR4_SHADOW, cr4); + + hv_vcpu_invalidate_tlb(vcpu); + hv_vcpu_flush(vcpu); +} + +static inline void macvm_set_rip(CPUState *cpu, uint64_t rip) +{ + uint64_t val; + + /* BUG, should take considering overlap.. */ + wreg(cpu->hvf_fd, HV_X86_RIP, rip); + + /* after moving forward in rip, we need to clean INTERRUPTABILITY */ + val = rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); + if (val & (VMCS_INTERRUPTIBILITY_STI_BLOCKING | + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) { + wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, + val & ~(VMCS_INTERRUPTIBILITY_STI_BLOCKING | + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)); + } +} + +static inline void vmx_clear_nmi_blocking(CPUState *cpu) +{ + uint32_t gi = (uint32_t) rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); + gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi); +} + +static inline void vmx_set_nmi_blocking(CPUState *cpu) +{ + uint32_t gi = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); + gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING; + wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi); +} + +static inline void vmx_set_nmi_window_exiting(CPUState *cpu) +{ + uint64_t val; + val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); + wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val | + VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING); + +} + +static inline void vmx_clear_nmi_window_exiting(CPUState *cpu) +{ + + uint64_t val; + val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); + wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val & + ~VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING); +} + +#endif diff --git a/target/i386/hvf-utils/x86.c b/target/i386/hvf-utils/x86.c new file mode 100644 index 0000000000..587efd54fd --- /dev/null +++ b/target/i386/hvf-utils/x86.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "x86_decode.h" +#include "x86_emu.h" +#include "vmcs.h" +#include "vmx.h" +#include "x86_mmu.h" +#include "x86_descr.h" + +/* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var) +{ + uint32_t ar; + + if (!var->p) { + ar = 1 << 16; + return ar; + } + + ar = var->type & 15; + ar |= (var->s & 1) << 4; + ar |= (var->dpl & 3) << 5; + ar |= (var->p & 1) << 7; + ar |= (var->avl & 1) << 12; + ar |= (var->l & 1) << 13; + ar |= (var->db & 1) << 14; + ar |= (var->g & 1) << 15; + return ar; +}*/ + +bool x86_read_segment_descriptor(struct CPUState *cpu, + struct x86_segment_descriptor *desc, + x68_segment_selector sel) +{ + addr_t base; + uint32_t limit; + + ZERO_INIT(*desc); + /* valid gdt descriptors start from index 1 */ + if (!sel.index && GDT_SEL == sel.ti) { + return false; + } + + if (GDT_SEL == sel.ti) { + base = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE); + limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT); + } else { + base = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE); + limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT); + } + + if (sel.index * 8 >= limit) { + return false; + } + + vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc)); + return true; +} + +bool x86_write_segment_descriptor(struct CPUState *cpu, + struct x86_segment_descriptor *desc, + x68_segment_selector sel) +{ + addr_t base; + uint32_t limit; + + if (GDT_SEL == sel.ti) { + base = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_BASE); + limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_GDTR_LIMIT); + } else { + base = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_BASE); + limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_LDTR_LIMIT); + } + + if (sel.index * 8 >= limit) { + printf("%s: gdt limit\n", __func__); + return false; + } + vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc)); + return true; +} + +bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc, + int gate) +{ + addr_t base = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE); + uint32_t limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT); + + ZERO_INIT(*idt_desc); + if (gate * 8 >= limit) { + printf("%s: idt limit\n", __func__); + return false; + } + + vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc)); + return true; +} + +bool x86_is_protected(struct CPUState *cpu) +{ + uint64_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0); + return cr0 & CR0_PE; +} + +bool x86_is_real(struct CPUState *cpu) +{ + return !x86_is_protected(cpu); +} + +bool x86_is_v8086(struct CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + return x86_is_protected(cpu) && (RFLAGS(env) & RFLAGS_VM); +} + +bool x86_is_long_mode(struct CPUState *cpu) +{ + return rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER) & EFER_LMA; +} + +bool x86_is_long64_mode(struct CPUState *cpu) +{ + struct vmx_segment desc; + vmx_read_segment_descriptor(cpu, &desc, REG_SEG_CS); + + return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1); +} + +bool x86_is_paging_mode(struct CPUState *cpu) +{ + uint64_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0); + return cr0 & CR0_PG; +} + +bool x86_is_pae_enabled(struct CPUState *cpu) +{ + uint64_t cr4 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR4); + return cr4 & CR4_PAE; +} + +addr_t linear_addr(struct CPUState *cpu, addr_t addr, x86_reg_segment seg) +{ + return vmx_read_segment_base(cpu, seg) + addr; +} + +addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, + x86_reg_segment seg) +{ + switch (size) { + case 2: + addr = (uint16_t)addr; + break; + case 4: + addr = (uint32_t)addr; + break; + default: + break; + } + return linear_addr(cpu, addr, seg); +} + +addr_t linear_rip(struct CPUState *cpu, addr_t rip) +{ + return linear_addr(cpu, rip, REG_SEG_CS); +} diff --git a/target/i386/hvf-utils/x86.h b/target/i386/hvf-utils/x86.h new file mode 100644 index 0000000000..d32e13d648 --- /dev/null +++ b/target/i386/hvf-utils/x86.h @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Veertu Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include "qemu-common.h" +#include "x86_gen.h" + +/* exceptions */ +typedef enum x86_exception { + EXCEPTION_DE, /* divide error */ + EXCEPTION_DB, /* debug fault */ + EXCEPTION_NMI, /* non-maskable interrupt */ + EXCEPTION_BP, /* breakpoint trap */ + EXCEPTION_OF, /* overflow trap */ + EXCEPTION_BR, /* boundary range exceeded fault */ + EXCEPTION_UD, /* undefined opcode */ + EXCEPTION_NM, /* device not available */ + EXCEPTION_DF, /* double fault */ + EXCEPTION_RSVD, /* not defined */ + EXCEPTION_TS, /* invalid TSS fault */ + EXCEPTION_NP, /* not present fault */ + EXCEPTION_GP, /* general protection fault */ + EXCEPTION_PF, /* page fault */ + EXCEPTION_RSVD2, /* not defined */ +} x86_exception; + +/* general purpose regs */ +typedef enum x86_reg_name { + REG_RAX = 0, + REG_RCX = 1, + REG_RDX = 2, + REG_RBX = 3, + REG_RSP = 4, + REG_RBP = 5, + REG_RSI = 6, + REG_RDI = 7, + REG_R8 = 8, + REG_R9 = 9, + REG_R10 = 10, + REG_R11 = 11, + REG_R12 = 12, + REG_R13 = 13, + REG_R14 = 14, + REG_R15 = 15, +} x86_reg_name; + +/* segment regs */ +typedef enum x86_reg_segment { + REG_SEG_ES = 0, + REG_SEG_CS = 1, + REG_SEG_SS = 2, + REG_SEG_DS = 3, + REG_SEG_FS = 4, + REG_SEG_GS = 5, + REG_SEG_LDTR = 6, + REG_SEG_TR = 7, +} x86_reg_segment; + +typedef struct x86_register { + union { + struct { + uint64_t rrx; /* full 64 bit */ + }; + struct { + uint32_t erx; /* low 32 bit part */ + uint32_t hi32_unused1; + }; + struct { + uint16_t rx; /* low 16 bit part */ + uint16_t hi16_unused1; + uint32_t hi32_unused2; + }; + struct { + uint8_t lx; /* low 8 bit part */ + uint8_t hx; /* high 8 bit */ + uint16_t hi16_unused2; + uint32_t hi32_unused3; + }; + }; +} __attribute__ ((__packed__)) x86_register; + +typedef enum x86_rflags { + RFLAGS_CF = (1L << 0), + RFLAGS_PF = (1L << 2), + RFLAGS_AF = (1L << 4), + RFLAGS_ZF = (1L << 6), + RFLAGS_SF = (1L << 7), + RFLAGS_TF = (1L << 8), + RFLAGS_IF = (1L << 9), + RFLAGS_DF = (1L << 10), + RFLAGS_OF = (1L << 11), + RFLAGS_IOPL = (3L << 12), + RFLAGS_NT = (1L << 14), + RFLAGS_RF = (1L << 16), + RFLAGS_VM = (1L << 17), + RFLAGS_AC = (1L << 18), + RFLAGS_VIF = (1L << 19), + RFLAGS_VIP = (1L << 20), + RFLAGS_ID = (1L << 21), +} x86_rflags; + +/* rflags register */ +typedef struct x86_reg_flags { + union { + struct { + uint64_t rflags; + }; + struct { + uint32_t eflags; + uint32_t hi32_unused1; + }; + struct { + uint32_t cf:1; + uint32_t unused1:1; + uint32_t pf:1; + uint32_t unused2:1; + uint32_t af:1; + uint32_t unused3:1; + uint32_t zf:1; + uint32_t sf:1; + uint32_t tf:1; + uint32_t ief:1; + uint32_t df:1; + uint32_t of:1; + uint32_t iopl:2; + uint32_t nt:1; + uint32_t unused4:1; + uint32_t rf:1; + uint32_t vm:1; + uint32_t ac:1; + uint32_t vif:1; + uint32_t vip:1; + uint32_t id:1; + uint32_t unused5:10; + uint32_t hi32_unused2; + }; + }; +} __attribute__ ((__packed__)) x86_reg_flags; + +typedef enum x86_reg_efer { + EFER_SCE = (1L << 0), + EFER_LME = (1L << 8), + EFER_LMA = (1L << 10), + EFER_NXE = (1L << 11), + EFER_SVME = (1L << 12), + EFER_FXSR = (1L << 14), +} x86_reg_efer; + +typedef struct x86_efer { + uint64_t efer; +} __attribute__ ((__packed__)) x86_efer; + +typedef enum x86_reg_cr0 { + CR0_PE = (1L << 0), + CR0_MP = (1L << 1), + CR0_EM = (1L << 2), + CR0_TS = (1L << 3), + CR0_ET = (1L << 4), + CR0_NE = (1L << 5), + CR0_WP = (1L << 16), + CR0_AM = (1L << 18), + CR0_NW = (1L << 29), + CR0_CD = (1L << 30), + CR0_PG = (1L << 31), +} x86_reg_cr0; + +typedef enum x86_reg_cr4 { + CR4_VME = (1L << 0), + CR4_PVI = (1L << 1), + CR4_TSD = (1L << 2), + CR4_DE = (1L << 3), + CR4_PSE = (1L << 4), + CR4_PAE = (1L << 5), + CR4_MSE = (1L << 6), + CR4_PGE = (1L << 7), + CR4_PCE = (1L << 8), + CR4_OSFXSR = (1L << 9), + CR4_OSXMMEXCPT = (1L << 10), + CR4_VMXE = (1L << 13), + CR4_SMXE = (1L << 14), + CR4_FSGSBASE = (1L << 16), + CR4_PCIDE = (1L << 17), + CR4_OSXSAVE = (1L << 18), + CR4_SMEP = (1L << 20), +} x86_reg_cr4; + +/* 16 bit Task State Segment */ +typedef struct x86_tss_segment16 { + uint16_t link; + uint16_t sp0; + uint16_t ss0; + uint32_t sp1; + uint16_t ss1; + uint32_t sp2; + uint16_t ss2; + uint16_t ip; + uint16_t flags; + uint16_t ax; + uint16_t cx; + uint16_t dx; + uint16_t bx; + uint16_t sp; + uint16_t bp; + uint16_t si; + uint16_t di; + uint16_t es; + uint16_t cs; + uint16_t ss; + uint16_t ds; + uint16_t ldtr; +} __attribute__((packed)) x86_tss_segment16; + +/* 32 bit Task State Segment */ +typedef struct x86_tss_segment32 { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} __attribute__ ((__packed__)) x86_tss_segment32; + +/* 64 bit Task State Segment */ +typedef struct x86_tss_segment64 { + uint32_t unused; + uint64_t rsp0; + uint64_t rsp1; + uint64_t rsp2; + uint64_t unused1; + uint64_t ist1; + uint64_t ist2; + uint64_t ist3; + uint64_t ist4; + uint64_t ist5; + uint64_t ist6; + uint64_t ist7; + uint64_t unused2; + uint16_t unused3; + uint16_t iomap_base; +} __attribute__ ((__packed__)) x86_tss_segment64; + +/* segment descriptors */ +typedef struct x86_segment_descriptor { + uint64_t limit0:16; + uint64_t base0:16; + uint64_t base1:8; + uint64_t type:4; + uint64_t s:1; + uint64_t dpl:2; + uint64_t p:1; + uint64_t limit1:4; + uint64_t avl:1; + uint64_t l:1; + uint64_t db:1; + uint64_t g:1; + uint64_t base2:8; +} __attribute__ ((__packed__)) x86_segment_descriptor; + +static inline uint32_t x86_segment_base(x86_segment_descriptor *desc) +{ + return (uint32_t)((desc->base2 << 24) | (desc->base1 << 16) | desc->base0); +} + +static inline void x86_set_segment_base(x86_segment_descriptor *desc, + uint32_t base) +{ + desc->base2 = base >> 24; + desc->base1 = (base >> 16) & 0xff; + desc->base0 = base & 0xffff; +} + +static inline uint32_t x86_segment_limit(x86_segment_descriptor *desc) +{ + uint32_t limit = (uint32_t)((desc->limit1 << 16) | desc->limit0); + if (desc->g) { + return (limit << 12) | 0xfff; + } + return limit; +} + +static inline void x86_set_segment_limit(x86_segment_descriptor *desc, + uint32_t limit) +{ + desc->limit0 = limit & 0xffff; + desc->limit1 = limit >> 16; +} + +typedef struct x86_call_gate { + uint64_t offset0:16; + uint64_t selector:16; + uint64_t param_count:4; + uint64_t reserved:3; + uint64_t type:4; + uint64_t dpl:1; + uint64_t p:1; + uint64_t offset1:16; +} __attribute__ ((__packed__)) x86_call_gate; + +static inline uint32_t x86_call_gate_offset(x86_call_gate *gate) +{ + return (uint32_t)((gate->offset1 << 16) | gate->offset0); +} + +#define LDT_SEL 0 +#define GDT_SEL 1 + +typedef struct x68_segment_selector { + union { + uint16_t sel; + struct { + uint16_t rpl:3; + uint16_t ti:1; + uint16_t index:12; + }; + }; +} __attribute__ ((__packed__)) x68_segment_selector; + +typedef struct lazy_flags { + addr_t result; + addr_t auxbits; +} lazy_flags; + +/* Definition of hvf_x86_state is here */ +struct HVFX86EmulatorState { + int interruptable; + uint64_t fetch_rip; + uint64_t rip; + struct x86_register regs[16]; + struct x86_reg_flags rflags; + struct lazy_flags lflags; + struct x86_efer efer; + uint8_t mmio_buf[4096]; +}; + +/* +* hvf xsave area +*/ +struct hvf_xsave_buf { + uint32_t data[1024]; +}; + +/* useful register access macros */ +#define RIP(cpu) (cpu->hvf_emul->rip) +#define EIP(cpu) ((uint32_t)cpu->hvf_emul->rip) +#define RFLAGS(cpu) (cpu->hvf_emul->rflags.rflags) +#define EFLAGS(cpu) (cpu->hvf_emul->rflags.eflags) + +#define RRX(cpu, reg) (cpu->hvf_emul->regs[reg].rrx) +#define RAX(cpu) RRX(cpu, REG_RAX) +#define RCX(cpu) RRX(cpu, REG_RCX) +#define RDX(cpu) RRX(cpu, REG_RDX) +#define RBX(cpu) RRX(cpu, REG_RBX) +#define RSP(cpu) RRX(cpu, REG_RSP) +#define RBP(cpu) RRX(cpu, REG_RBP) +#define RSI(cpu) RRX(cpu, REG_RSI) +#define RDI(cpu) RRX(cpu, REG_RDI) +#define R8(cpu) RRX(cpu, REG_R8) +#define R9(cpu) RRX(cpu, REG_R9) +#define R10(cpu) RRX(cpu, REG_R10) +#define R11(cpu) RRX(cpu, REG_R11) +#define R12(cpu) RRX(cpu, REG_R12) +#define R13(cpu) RRX(cpu, REG_R13) +#define R14(cpu) RRX(cpu, REG_R14) +#define R15(cpu) RRX(cpu, REG_R15) + +#define ERX(cpu, reg) (cpu->hvf_emul->regs[reg].erx) +#define EAX(cpu) ERX(cpu, REG_RAX) +#define ECX(cpu) ERX(cpu, REG_RCX) +#define EDX(cpu) ERX(cpu, REG_RDX) +#define EBX(cpu) ERX(cpu, REG_RBX) +#define ESP(cpu) ERX(cpu, REG_RSP) +#define EBP(cpu) ERX(cpu, REG_RBP) +#define ESI(cpu) ERX(cpu, REG_RSI) +#define EDI(cpu) ERX(cpu, REG_RDI) + +#define RX(cpu, reg) (cpu->hvf_emul->regs[reg].rx) +#define AX(cpu) RX(cpu, REG_RAX) +#define CX(cpu) RX(cpu, REG_RCX) +#define DX(cpu) RX(cpu, REG_RDX) +#define BP(cpu) RX(cpu, REG_RBP) +#define SP(cpu) RX(cpu, REG_RSP) +#define BX(cpu) RX(cpu, REG_RBX) +#define SI(cpu) RX(cpu, REG_RSI) +#define DI(cpu) RX(cpu, REG_RDI) + +#define RL(cpu, reg) (cpu->hvf_emul->regs[reg].lx) +#define AL(cpu) RL(cpu, REG_RAX) +#define CL(cpu) RL(cpu, REG_RCX) +#define DL(cpu) RL(cpu, REG_RDX) +#define BL(cpu) RL(cpu, REG_RBX) + +#define RH(cpu, reg) (cpu->hvf_emul->regs[reg].hx) +#define AH(cpu) RH(cpu, REG_RAX) +#define CH(cpu) RH(cpu, REG_RCX) +#define DH(cpu) RH(cpu, REG_RDX) +#define BH(cpu) RH(cpu, REG_RBX) + +/* deal with GDT/LDT descriptors in memory */ +bool x86_read_segment_descriptor(struct CPUState *cpu, + struct x86_segment_descriptor *desc, + x68_segment_selector sel); +bool x86_write_segment_descriptor(struct CPUState *cpu, + struct x86_segment_descriptor *desc, + x68_segment_selector sel); + +bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc, + int gate); + +/* helpers */ +bool x86_is_protected(struct CPUState *cpu); +bool x86_is_real(struct CPUState *cpu); +bool x86_is_v8086(struct CPUState *cpu); +bool x86_is_long_mode(struct CPUState *cpu); +bool x86_is_long64_mode(struct CPUState *cpu); +bool x86_is_paging_mode(struct CPUState *cpu); +bool x86_is_pae_enabled(struct CPUState *cpu); + +addr_t linear_addr(struct CPUState *cpu, addr_t addr, x86_reg_segment seg); +addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, + x86_reg_segment seg); +addr_t linear_rip(struct CPUState *cpu, addr_t rip); + +static inline uint64_t rdtscp(void) +{ + uint64_t tsc; + __asm__ __volatile__("rdtscp; " /* serializing read of tsc */ + "shl $32,%%rdx; " /* shift higher 32 bits stored in rdx up */ + "or %%rdx,%%rax" /* and or onto rax */ + : "=a"(tsc) /* output to tsc variable */ + : + : "%rcx", "%rdx"); /* rcx and rdx are clobbered */ + + return tsc; +} + diff --git a/target/i386/hvf-utils/x86_decode.c b/target/i386/hvf-utils/x86_decode.c new file mode 100644 index 0000000000..13022f2851 --- /dev/null +++ b/target/i386/hvf-utils/x86_decode.c @@ -0,0 +1,2186 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" + +#include "x86_decode.h" +#include "string.h" +#include "vmx.h" +#include "x86_gen.h" +#include "x86_mmu.h" +#include "x86_descr.h" + +#define OPCODE_ESCAPE 0xf + +static void decode_invalid(CPUX86State *env, struct x86_decode *decode) +{ + printf("%llx: failed to decode instruction ", env->hvf_emul->fetch_rip - + decode->len); + for (int i = 0; i < decode->opcode_len; i++) { + printf("%x ", decode->opcode[i]); + } + printf("\n"); + VM_PANIC("decoder failed\n"); +} + +uint64_t sign(uint64_t val, int size) +{ + switch (size) { + case 1: + val = (int8_t)val; + break; + case 2: + val = (int16_t)val; + break; + case 4: + val = (int32_t)val; + break; + case 8: + val = (int64_t)val; + break; + default: + VM_PANIC_EX("%s invalid size %d\n", __func__, size); + break; + } + return val; +} + +static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, + int size) +{ + addr_t val = 0; + + switch (size) { + case 1: + case 2: + case 4: + case 8: + break; + default: + VM_PANIC_EX("%s invalid size %d\n", __func__, size); + break; + } + addr_t va = linear_rip(ENV_GET_CPU(env), RIP(env)) + decode->len; + vmx_read_mem(ENV_GET_CPU(env), &val, va, size); + decode->len += size; + + return val; +} + +static inline uint8_t decode_byte(CPUX86State *env, struct x86_decode *decode) +{ + return (uint8_t)decode_bytes(env, decode, 1); +} + +static inline uint16_t decode_word(CPUX86State *env, struct x86_decode *decode) +{ + return (uint16_t)decode_bytes(env, decode, 2); +} + +static inline uint32_t decode_dword(CPUX86State *env, struct x86_decode *decode) +{ + return (uint32_t)decode_bytes(env, decode, 4); +} + +static inline uint64_t decode_qword(CPUX86State *env, struct x86_decode *decode) +{ + return decode_bytes(env, decode, 8); +} + +static void decode_modrm_rm(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_RM; +} + +static void decode_modrm_reg(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_REG; + op->reg = decode->modrm.reg; + op->ptr = get_reg_ref(env, op->reg, decode->rex.r, decode->operand_size); +} + +static void decode_rax(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_REG; + op->reg = REG_RAX; + op->ptr = get_reg_ref(env, op->reg, 0, decode->operand_size); +} + +static inline void decode_immediate(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *var, int size) +{ + var->type = X86_VAR_IMMEDIATE; + var->size = size; + switch (size) { + case 1: + var->val = decode_byte(env, decode); + break; + case 2: + var->val = decode_word(env, decode); + break; + case 4: + var->val = decode_dword(env, decode); + break; + case 8: + var->val = decode_qword(env, decode); + break; + default: + VM_PANIC_EX("bad size %d\n", size); + } +} + +static void decode_imm8(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + decode_immediate(env, decode, op, 1); + op->type = X86_VAR_IMMEDIATE; +} + +static void decode_imm8_signed(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + decode_immediate(env, decode, op, 1); + op->val = sign(op->val, 1); + op->type = X86_VAR_IMMEDIATE; +} + +static void decode_imm16(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + decode_immediate(env, decode, op, 2); + op->type = X86_VAR_IMMEDIATE; +} + + +static void decode_imm(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + if (8 == decode->operand_size) { + decode_immediate(env, decode, op, 4); + op->val = sign(op->val, decode->operand_size); + } else { + decode_immediate(env, decode, op, decode->operand_size); + } + op->type = X86_VAR_IMMEDIATE; +} + +static void decode_imm_signed(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + decode_immediate(env, decode, op, decode->operand_size); + op->val = sign(op->val, decode->operand_size); + op->type = X86_VAR_IMMEDIATE; +} + +static void decode_imm_1(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_IMMEDIATE; + op->val = 1; +} + +static void decode_imm_0(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_IMMEDIATE; + op->val = 0; +} + + +static void decode_pushseg(CPUX86State *env, struct x86_decode *decode) +{ + uint8_t op = (decode->opcode_len > 1) ? decode->opcode[1] : decode->opcode[0]; + + decode->op[0].type = X86_VAR_REG; + switch (op) { + case 0xe: + decode->op[0].reg = REG_SEG_CS; + break; + case 0x16: + decode->op[0].reg = REG_SEG_SS; + break; + case 0x1e: + decode->op[0].reg = REG_SEG_DS; + break; + case 0x06: + decode->op[0].reg = REG_SEG_ES; + break; + case 0xa0: + decode->op[0].reg = REG_SEG_FS; + break; + case 0xa8: + decode->op[0].reg = REG_SEG_GS; + break; + } +} + +static void decode_popseg(CPUX86State *env, struct x86_decode *decode) +{ + uint8_t op = (decode->opcode_len > 1) ? decode->opcode[1] : decode->opcode[0]; + + decode->op[0].type = X86_VAR_REG; + switch (op) { + case 0xf: + decode->op[0].reg = REG_SEG_CS; + break; + case 0x17: + decode->op[0].reg = REG_SEG_SS; + break; + case 0x1f: + decode->op[0].reg = REG_SEG_DS; + break; + case 0x07: + decode->op[0].reg = REG_SEG_ES; + break; + case 0xa1: + decode->op[0].reg = REG_SEG_FS; + break; + case 0xa9: + decode->op[0].reg = REG_SEG_GS; + break; + } +} + +static void decode_incgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0x40; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_decgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0x48; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_incgroup2(CPUX86State *env, struct x86_decode *decode) +{ + if (!decode->modrm.reg) { + decode->cmd = X86_DECODE_CMD_INC; + } else if (1 == decode->modrm.reg) { + decode->cmd = X86_DECODE_CMD_DEC; + } +} + +static void decode_pushgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0x50; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_popgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0x58; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_jxx(CPUX86State *env, struct x86_decode *decode) +{ + decode->displacement = decode_bytes(env, decode, decode->operand_size); + decode->displacement_size = decode->operand_size; +} + +static void decode_farjmp(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_IMMEDIATE; + decode->op[0].val = decode_bytes(env, decode, decode->operand_size); + decode->displacement = decode_word(env, decode); +} + +static void decode_addgroup(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_ADD, + X86_DECODE_CMD_OR, + X86_DECODE_CMD_ADC, + X86_DECODE_CMD_SBB, + X86_DECODE_CMD_AND, + X86_DECODE_CMD_SUB, + X86_DECODE_CMD_XOR, + X86_DECODE_CMD_CMP + }; + decode->cmd = group[decode->modrm.reg]; +} + +static void decode_rotgroup(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_ROL, + X86_DECODE_CMD_ROR, + X86_DECODE_CMD_RCL, + X86_DECODE_CMD_RCR, + X86_DECODE_CMD_SHL, + X86_DECODE_CMD_SHR, + X86_DECODE_CMD_SHL, + X86_DECODE_CMD_SAR + }; + decode->cmd = group[decode->modrm.reg]; +} + +static void decode_f7group(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_TST, + X86_DECODE_CMD_TST, + X86_DECODE_CMD_NOT, + X86_DECODE_CMD_NEG, + X86_DECODE_CMD_MUL, + X86_DECODE_CMD_IMUL_1, + X86_DECODE_CMD_DIV, + X86_DECODE_CMD_IDIV + }; + decode->cmd = group[decode->modrm.reg]; + decode_modrm_rm(env, decode, &decode->op[0]); + + switch (decode->modrm.reg) { + case 0: + case 1: + decode_imm(env, decode, &decode->op[1]); + break; + case 2: + break; + case 3: + decode->op[1].type = X86_VAR_IMMEDIATE; + decode->op[1].val = 0; + break; + default: + break; + } +} + +static void decode_xchgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0x90; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_movgroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0xb8; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); + decode_immediate(env, decode, &decode->op[1], decode->operand_size); +} + +static void fetch_moffs(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_OFFSET; + op->ptr = decode_bytes(env, decode, decode->addressing_size); +} + +static void decode_movgroup8(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[0] - 0xb0; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); + decode_immediate(env, decode, &decode->op[1], decode->operand_size); +} + +static void decode_rcx(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X86_VAR_REG; + op->reg = REG_RCX; + op->ptr = get_reg_ref(env, op->reg, decode->rex.b, decode->operand_size); +} + +struct decode_tbl { + uint8_t opcode; + enum x86_decode_cmd cmd; + uint8_t operand_size; + bool is_modrm; + void (*decode_op1)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op1); + void (*decode_op2)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op2); + void (*decode_op3)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op3); + void (*decode_op4)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op4); + void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); + addr_t flags_mask; +}; + +struct decode_x87_tbl { + uint8_t opcode; + uint8_t modrm_reg; + uint8_t modrm_mod; + enum x86_decode_cmd cmd; + uint8_t operand_size; + bool rev; + bool pop; + void (*decode_op1)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op1); + void (*decode_op2)(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op2); + void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); + addr_t flags_mask; +}; + +struct decode_tbl invl_inst = {0x0, 0, 0, false, NULL, NULL, NULL, NULL, + decode_invalid}; + +struct decode_tbl _decode_tbl1[255]; +struct decode_tbl _decode_tbl2[255]; +struct decode_x87_tbl _decode_tbl3[255]; + +static void decode_x87_ins(CPUX86State *env, struct x86_decode *decode) +{ + struct decode_x87_tbl *decoder; + + decode->is_fpu = true; + int mode = decode->modrm.mod == 3 ? 1 : 0; + int index = ((decode->opcode[0] & 0xf) << 4) | (mode << 3) | + decode->modrm.reg; + + decoder = &_decode_tbl3[index]; + + decode->cmd = decoder->cmd; + if (decoder->operand_size) { + decode->operand_size = decoder->operand_size; + } + decode->flags_mask = decoder->flags_mask; + decode->fpop_stack = decoder->pop; + decode->frev = decoder->rev; + + if (decoder->decode_op1) { + decoder->decode_op1(env, decode, &decode->op[0]); + } + if (decoder->decode_op2) { + decoder->decode_op2(env, decode, &decode->op[1]); + } + if (decoder->decode_postfix) { + decoder->decode_postfix(env, decode); + } + + VM_PANIC_ON_EX(!decode->cmd, "x87 opcode %x %x (%x %x) not decoded\n", + decode->opcode[0], decode->modrm.modrm, decoder->modrm_reg, + decoder->modrm_mod); +} + +static void decode_ffgroup(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_INC, + X86_DECODE_CMD_DEC, + X86_DECODE_CMD_CALL_NEAR_ABS_INDIRECT, + X86_DECODE_CMD_CALL_FAR_ABS_INDIRECT, + X86_DECODE_CMD_JMP_NEAR_ABS_INDIRECT, + X86_DECODE_CMD_JMP_FAR_ABS_INDIRECT, + X86_DECODE_CMD_PUSH, + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_INVL + }; + decode->cmd = group[decode->modrm.reg]; + if (decode->modrm.reg > 2) { + decode->flags_mask = 0; + } +} + +static void decode_sldtgroup(CPUX86State *env, struct x86_decode *decode) +{ + + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_SLDT, + X86_DECODE_CMD_STR, + X86_DECODE_CMD_LLDT, + X86_DECODE_CMD_LTR, + X86_DECODE_CMD_VERR, + X86_DECODE_CMD_VERW, + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_INVL + }; + decode->cmd = group[decode->modrm.reg]; + printf("%llx: decode_sldtgroup: %d\n", env->hvf_emul->fetch_rip, + decode->modrm.reg); +} + +static void decode_lidtgroup(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_SGDT, + X86_DECODE_CMD_SIDT, + X86_DECODE_CMD_LGDT, + X86_DECODE_CMD_LIDT, + X86_DECODE_CMD_SMSW, + X86_DECODE_CMD_LMSW, + X86_DECODE_CMD_LMSW, + X86_DECODE_CMD_INVLPG + }; + decode->cmd = group[decode->modrm.reg]; + if (0xf9 == decode->modrm.modrm) { + decode->opcode[decode->len++] = decode->modrm.modrm; + decode->cmd = X86_DECODE_CMD_RDTSCP; + } +} + +static void decode_btgroup(CPUX86State *env, struct x86_decode *decode) +{ + enum x86_decode_cmd group[] = { + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_INVL, + X86_DECODE_CMD_BT, + X86_DECODE_CMD_BTS, + X86_DECODE_CMD_BTR, + X86_DECODE_CMD_BTC + }; + decode->cmd = group[decode->modrm.reg]; +} + +static void decode_x87_general(CPUX86State *env, struct x86_decode *decode) +{ + decode->is_fpu = true; +} + +static void decode_x87_modrm_floatp(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X87_VAR_FLOATP; +} + +static void decode_x87_modrm_intp(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X87_VAR_INTP; +} + +static void decode_x87_modrm_bytep(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X87_VAR_BYTEP; +} + +static void decode_x87_modrm_st0(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X87_VAR_REG; + op->reg = 0; +} + +static void decode_decode_x87_modrm_st0(CPUX86State *env, + struct x86_decode *decode, + struct x86_decode_op *op) +{ + op->type = X87_VAR_REG; + op->reg = decode->modrm.modrm & 7; +} + + +static void decode_aegroup(CPUX86State *env, struct x86_decode *decode) +{ + decode->is_fpu = true; + switch (decode->modrm.reg) { + case 0: + decode->cmd = X86_DECODE_CMD_FXSAVE; + decode_x87_modrm_bytep(env, decode, &decode->op[0]); + break; + case 1: + decode_x87_modrm_bytep(env, decode, &decode->op[0]); + decode->cmd = X86_DECODE_CMD_FXRSTOR; + break; + case 5: + if (decode->modrm.modrm == 0xe8) { + decode->cmd = X86_DECODE_CMD_LFENCE; + } else { + VM_PANIC("xrstor"); + } + break; + case 6: + VM_PANIC_ON(decode->modrm.modrm != 0xf0); + decode->cmd = X86_DECODE_CMD_MFENCE; + break; + case 7: + if (decode->modrm.modrm == 0xf8) { + decode->cmd = X86_DECODE_CMD_SFENCE; + } else { + decode->cmd = X86_DECODE_CMD_CLFLUSH; + } + break; + default: + VM_PANIC_ON_EX(1, "0xae: reg %d\n", decode->modrm.reg); + break; + } +} + +static void decode_bswap(CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = decode->opcode[1] - 0xc8; + decode->op[0].ptr = get_reg_ref(env, decode->op[0].reg, decode->rex.b, + decode->operand_size); +} + +static void decode_d9_4(CPUX86State *env, struct x86_decode *decode) +{ + switch (decode->modrm.modrm) { + case 0xe0: + /* FCHS */ + decode->cmd = X86_DECODE_CMD_FCHS; + break; + case 0xe1: + decode->cmd = X86_DECODE_CMD_FABS; + break; + case 0xe4: + VM_PANIC_ON_EX(1, "FTST"); + break; + case 0xe5: + /* FXAM */ + decode->cmd = X86_DECODE_CMD_FXAM; + break; + default: + VM_PANIC_ON_EX(1, "FLDENV"); + break; + } +} + +static void decode_db_4(CPUX86State *env, struct x86_decode *decode) +{ + switch (decode->modrm.modrm) { + case 0xe0: + VM_PANIC_ON_EX(1, "unhandled FNENI: %x %x\n", decode->opcode[0], + decode->modrm.modrm); + break; + case 0xe1: + VM_PANIC_ON_EX(1, "unhandled FNDISI: %x %x\n", decode->opcode[0], + decode->modrm.modrm); + break; + case 0xe2: + VM_PANIC_ON_EX(1, "unhandled FCLEX: %x %x\n", decode->opcode[0], + decode->modrm.modrm); + break; + case 0xe3: + decode->cmd = X86_DECODE_CMD_FNINIT; + break; + case 0xe4: + decode->cmd = X86_DECODE_CMD_FNSETPM; + break; + default: + VM_PANIC_ON_EX(1, "unhandled fpu opcode: %x %x\n", decode->opcode[0], + decode->modrm.modrm); + break; + } +} + + +#define RFLAGS_MASK_NONE 0 +#define RFLAGS_MASK_OSZAPC (RFLAGS_OF | RFLAGS_SF | RFLAGS_ZF | RFLAGS_AF | \ + RFLAGS_PF | RFLAGS_CF) +#define RFLAGS_MASK_LAHF (RFLAGS_SF | RFLAGS_ZF | RFLAGS_AF | RFLAGS_PF | \ + RFLAGS_CF) +#define RFLAGS_MASK_CF (RFLAGS_CF) +#define RFLAGS_MASK_IF (RFLAGS_IF) +#define RFLAGS_MASK_TF (RFLAGS_TF) +#define RFLAGS_MASK_DF (RFLAGS_DF) +#define RFLAGS_MASK_ZF (RFLAGS_ZF) + +struct decode_tbl _1op_inst[] = { + {0x0, X86_DECODE_CMD_ADD, 1, true, decode_modrm_rm, decode_modrm_reg, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x1, X86_DECODE_CMD_ADD, 0, true, decode_modrm_rm, decode_modrm_reg, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2, X86_DECODE_CMD_ADD, 1, true, decode_modrm_reg, decode_modrm_rm, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x3, X86_DECODE_CMD_ADD, 0, true, decode_modrm_reg, decode_modrm_rm, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x4, X86_DECODE_CMD_ADD, 1, false, decode_rax, decode_imm8, NULL, NULL, + NULL, RFLAGS_MASK_OSZAPC}, + {0x5, X86_DECODE_CMD_ADD, 0, false, decode_rax, decode_imm, NULL, NULL, + NULL, RFLAGS_MASK_OSZAPC}, + {0x6, X86_DECODE_CMD_PUSH_SEG, 0, false, false, NULL, NULL, NULL, + decode_pushseg, RFLAGS_MASK_NONE}, + {0x7, X86_DECODE_CMD_POP_SEG, 0, false, false, NULL, NULL, NULL, + decode_popseg, RFLAGS_MASK_NONE}, + {0x8, X86_DECODE_CMD_OR, 1, true, decode_modrm_rm, decode_modrm_reg, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x9, X86_DECODE_CMD_OR, 0, true, decode_modrm_rm, decode_modrm_reg, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xa, X86_DECODE_CMD_OR, 1, true, decode_modrm_reg, decode_modrm_rm, NULL, + NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xb, X86_DECODE_CMD_OR, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xc, X86_DECODE_CMD_OR, 1, false, decode_rax, decode_imm8, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xd, X86_DECODE_CMD_OR, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xe, X86_DECODE_CMD_PUSH_SEG, 0, false, false, + NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + {0xf, X86_DECODE_CMD_POP_SEG, 0, false, false, + NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + + {0x10, X86_DECODE_CMD_ADC, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x11, X86_DECODE_CMD_ADC, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x12, X86_DECODE_CMD_ADC, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x13, X86_DECODE_CMD_ADC, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x14, X86_DECODE_CMD_ADC, 1, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x15, X86_DECODE_CMD_ADC, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x16, X86_DECODE_CMD_PUSH_SEG, 0, false, false, + NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + {0x17, X86_DECODE_CMD_POP_SEG, 0, false, false, + NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + + {0x18, X86_DECODE_CMD_SBB, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x19, X86_DECODE_CMD_SBB, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x1a, X86_DECODE_CMD_SBB, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x1b, X86_DECODE_CMD_SBB, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x1c, X86_DECODE_CMD_SBB, 1, false, decode_rax, decode_imm8, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x1d, X86_DECODE_CMD_SBB, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x1e, X86_DECODE_CMD_PUSH_SEG, 0, false, false, + NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + {0x1f, X86_DECODE_CMD_POP_SEG, 0, false, false, + NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + + {0x20, X86_DECODE_CMD_AND, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x21, X86_DECODE_CMD_AND, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x22, X86_DECODE_CMD_AND, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x23, X86_DECODE_CMD_AND, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x24, X86_DECODE_CMD_AND, 1, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x25, X86_DECODE_CMD_AND, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x28, X86_DECODE_CMD_SUB, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x29, X86_DECODE_CMD_SUB, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2a, X86_DECODE_CMD_SUB, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2b, X86_DECODE_CMD_SUB, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2c, X86_DECODE_CMD_SUB, 1, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2d, X86_DECODE_CMD_SUB, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x2f, X86_DECODE_CMD_DAS, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x30, X86_DECODE_CMD_XOR, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x31, X86_DECODE_CMD_XOR, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x32, X86_DECODE_CMD_XOR, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x33, X86_DECODE_CMD_XOR, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x34, X86_DECODE_CMD_XOR, 1, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x35, X86_DECODE_CMD_XOR, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x38, X86_DECODE_CMD_CMP, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x39, X86_DECODE_CMD_CMP, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x3a, X86_DECODE_CMD_CMP, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x3b, X86_DECODE_CMD_CMP, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x3c, X86_DECODE_CMD_CMP, 1, false, decode_rax, decode_imm8, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x3d, X86_DECODE_CMD_CMP, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x3f, X86_DECODE_CMD_AAS, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x40, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x41, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x42, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x43, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x44, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x45, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x46, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + {0x47, X86_DECODE_CMD_INC, 0, false, + NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + + {0x48, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x49, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4a, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4b, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4c, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4d, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4e, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + {0x4f, X86_DECODE_CMD_DEC, 0, false, + NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + + {0x50, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x51, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x52, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x53, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x54, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x55, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x56, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + {0x57, X86_DECODE_CMD_PUSH, 0, false, + NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + + {0x58, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x59, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5a, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5b, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5c, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5d, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5e, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + {0x5f, X86_DECODE_CMD_POP, 0, false, + NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + + {0x60, X86_DECODE_CMD_PUSHA, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x61, X86_DECODE_CMD_POPA, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0x68, X86_DECODE_CMD_PUSH, 0, false, decode_imm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x6a, X86_DECODE_CMD_PUSH, 0, false, decode_imm8_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x69, X86_DECODE_CMD_IMUL_3, 0, true, decode_modrm_reg, + decode_modrm_rm, decode_imm, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x6b, X86_DECODE_CMD_IMUL_3, 0, true, decode_modrm_reg, decode_modrm_rm, + decode_imm8_signed, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0x6c, X86_DECODE_CMD_INS, 1, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x6d, X86_DECODE_CMD_INS, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x6e, X86_DECODE_CMD_OUTS, 1, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x6f, X86_DECODE_CMD_OUTS, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0x70, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x71, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x72, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x73, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x74, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x75, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x76, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x77, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x78, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x79, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7a, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7b, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7c, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7d, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7e, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x7f, X86_DECODE_CMD_JXX, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + + {0x80, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, + NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + {0x81, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm, + NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + {0x82, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, + NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + {0x83, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8_signed, + NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + {0x84, X86_DECODE_CMD_TST, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x85, X86_DECODE_CMD_TST, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0x86, X86_DECODE_CMD_XCHG, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x87, X86_DECODE_CMD_XCHG, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x88, X86_DECODE_CMD_MOV, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x89, X86_DECODE_CMD_MOV, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8a, X86_DECODE_CMD_MOV, 1, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8b, X86_DECODE_CMD_MOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8c, X86_DECODE_CMD_MOV_FROM_SEG, 0, true, decode_modrm_rm, + decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8d, X86_DECODE_CMD_LEA, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8e, X86_DECODE_CMD_MOV_TO_SEG, 0, true, decode_modrm_reg, + decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x8f, X86_DECODE_CMD_POP, 0, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0x90, X86_DECODE_CMD_NOP, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x91, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x92, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x93, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x94, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x95, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x96, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + {0x97, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, + NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + + {0x98, X86_DECODE_CMD_CBW, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x99, X86_DECODE_CMD_CWD, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0x9a, X86_DECODE_CMD_CALL_FAR, 0, false, NULL, + NULL, NULL, NULL, decode_farjmp, RFLAGS_MASK_NONE}, + + {0x9c, X86_DECODE_CMD_PUSHF, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + /*{0x9d, X86_DECODE_CMD_POPF, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_POPF},*/ + {0x9e, X86_DECODE_CMD_SAHF, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9f, X86_DECODE_CMD_LAHF, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_LAHF}, + + {0xa0, X86_DECODE_CMD_MOV, 1, false, decode_rax, fetch_moffs, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa1, X86_DECODE_CMD_MOV, 0, false, decode_rax, fetch_moffs, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa2, X86_DECODE_CMD_MOV, 1, false, fetch_moffs, decode_rax, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa3, X86_DECODE_CMD_MOV, 0, false, fetch_moffs, decode_rax, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xa4, X86_DECODE_CMD_MOVS, 1, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa5, X86_DECODE_CMD_MOVS, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa6, X86_DECODE_CMD_CMPS, 1, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xa7, X86_DECODE_CMD_CMPS, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xaa, X86_DECODE_CMD_STOS, 1, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xab, X86_DECODE_CMD_STOS, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xac, X86_DECODE_CMD_LODS, 1, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xad, X86_DECODE_CMD_LODS, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xae, X86_DECODE_CMD_SCAS, 1, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xaf, X86_DECODE_CMD_SCAS, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xa8, X86_DECODE_CMD_TST, 1, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xa9, X86_DECODE_CMD_TST, 0, false, decode_rax, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xb0, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb1, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb2, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb3, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb4, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb5, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb6, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + {0xb7, X86_DECODE_CMD_MOV, 1, false, NULL, + NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + + {0xb8, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xb9, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xba, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xbb, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xbc, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xbd, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xbe, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + {0xbf, X86_DECODE_CMD_MOV, 0, false, NULL, + NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + + {0xc0, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + {0xc1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + + {0xc2, X86_DECODE_RET_NEAR, 0, false, decode_imm16, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xc3, X86_DECODE_RET_NEAR, 0, false, NULL, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xc4, X86_DECODE_CMD_LES, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xc5, X86_DECODE_CMD_LDS, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xc6, X86_DECODE_CMD_MOV, 1, true, decode_modrm_rm, decode_imm8, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xc7, X86_DECODE_CMD_MOV, 0, true, decode_modrm_rm, decode_imm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xc8, X86_DECODE_CMD_ENTER, 0, false, decode_imm16, decode_imm8, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xc9, X86_DECODE_CMD_LEAVE, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xca, X86_DECODE_RET_FAR, 0, false, decode_imm16, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xcb, X86_DECODE_RET_FAR, 0, false, decode_imm_0, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xcd, X86_DECODE_CMD_INT, 0, false, decode_imm8, NULL, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + /*{0xcf, X86_DECODE_CMD_IRET, 0, false, NULL, NULL, + NULL, NULL, NULL, RFLAGS_MASK_IRET},*/ + + {0xd0, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm_1, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + {0xd1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm_1, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + {0xd2, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_rcx, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + {0xd3, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_rcx, + NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + + {0xd4, X86_DECODE_CMD_AAM, 0, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xd5, X86_DECODE_CMD_AAD, 0, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xd7, X86_DECODE_CMD_XLAT, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xd8, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xd9, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xda, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xdb, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xdc, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xdd, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xde, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + {0xdf, X86_DECODE_CMD_INVL, 0, true, NULL, + NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + + {0xe0, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe1, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe2, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xe3, X86_DECODE_CMD_JCXZ, 1, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + + {0xe4, X86_DECODE_CMD_IN, 1, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe5, X86_DECODE_CMD_IN, 0, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe6, X86_DECODE_CMD_OUT, 1, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe7, X86_DECODE_CMD_OUT, 0, false, decode_imm8, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe8, X86_DECODE_CMD_CALL_NEAR, 0, false, decode_imm_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xe9, X86_DECODE_CMD_JMP_NEAR, 0, false, decode_imm_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xea, X86_DECODE_CMD_JMP_FAR, 0, false, + NULL, NULL, NULL, NULL, decode_farjmp, RFLAGS_MASK_NONE}, + {0xeb, X86_DECODE_CMD_JMP_NEAR, 1, false, decode_imm8_signed, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xec, X86_DECODE_CMD_IN, 1, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xed, X86_DECODE_CMD_IN, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xee, X86_DECODE_CMD_OUT, 1, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xef, X86_DECODE_CMD_OUT, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xf4, X86_DECODE_CMD_HLT, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xf5, X86_DECODE_CMD_CMC, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + + {0xf6, X86_DECODE_CMD_INVL, 1, true, + NULL, NULL, NULL, NULL, decode_f7group, RFLAGS_MASK_OSZAPC}, + {0xf7, X86_DECODE_CMD_INVL, 0, true, + NULL, NULL, NULL, NULL, decode_f7group, RFLAGS_MASK_OSZAPC}, + + {0xf8, X86_DECODE_CMD_CLC, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + {0xf9, X86_DECODE_CMD_STC, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + + {0xfa, X86_DECODE_CMD_CLI, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_IF}, + {0xfb, X86_DECODE_CMD_STI, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_IF}, + {0xfc, X86_DECODE_CMD_CLD, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_DF}, + {0xfd, X86_DECODE_CMD_STD, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_DF}, + {0xfe, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, + NULL, NULL, NULL, decode_incgroup2, RFLAGS_MASK_OSZAPC}, + {0xff, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, + NULL, NULL, NULL, decode_ffgroup, RFLAGS_MASK_OSZAPC}, +}; + +struct decode_tbl _2op_inst[] = { + {0x0, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, + NULL, NULL, NULL, decode_sldtgroup, RFLAGS_MASK_NONE}, + {0x1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, + NULL, NULL, NULL, decode_lidtgroup, RFLAGS_MASK_NONE}, + {0x6, X86_DECODE_CMD_CLTS, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_TF}, + {0x9, X86_DECODE_CMD_WBINVD, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x18, X86_DECODE_CMD_PREFETCH, 0, true, + NULL, NULL, NULL, NULL, decode_x87_general, RFLAGS_MASK_NONE}, + {0x1f, X86_DECODE_CMD_NOP, 0, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x20, X86_DECODE_CMD_MOV_FROM_CR, 0, true, decode_modrm_rm, + decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x21, X86_DECODE_CMD_MOV_FROM_DR, 0, true, decode_modrm_rm, + decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x22, X86_DECODE_CMD_MOV_TO_CR, 0, true, decode_modrm_reg, + decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x23, X86_DECODE_CMD_MOV_TO_DR, 0, true, decode_modrm_reg, + decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x30, X86_DECODE_CMD_WRMSR, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x31, X86_DECODE_CMD_RDTSC, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x32, X86_DECODE_CMD_RDMSR, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x40, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x41, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x42, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x43, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x44, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x45, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x46, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x47, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x48, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x49, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4a, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4b, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4c, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4d, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4e, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x4f, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x77, X86_DECODE_CMD_EMMS, 0, false, + NULL, NULL, NULL, NULL, decode_x87_general, RFLAGS_MASK_NONE}, + {0x82, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x83, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x84, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x85, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x86, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x87, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x88, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x89, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8a, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8b, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8c, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8d, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8e, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x8f, X86_DECODE_CMD_JXX, 0, false, + NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + {0x90, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x91, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x92, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x93, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x94, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x95, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x96, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x97, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x98, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x99, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9a, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9b, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9c, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9d, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9e, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0x9f, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xb0, X86_DECODE_CMD_CMPXCHG, 1, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xb1, X86_DECODE_CMD_CMPXCHG, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xb6, X86_DECODE_CMD_MOVZX, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xb7, X86_DECODE_CMD_MOVZX, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xb8, X86_DECODE_CMD_POPCNT, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xbe, X86_DECODE_CMD_MOVSX, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xbf, X86_DECODE_CMD_MOVSX, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa0, X86_DECODE_CMD_PUSH_SEG, 0, false, false, + NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + {0xa1, X86_DECODE_CMD_POP_SEG, 0, false, false, + NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + {0xa2, X86_DECODE_CMD_CPUID, 0, false, + NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xa3, X86_DECODE_CMD_BT, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_CF}, + {0xa4, X86_DECODE_CMD_SHLD, 0, true, decode_modrm_rm, decode_modrm_reg, + decode_imm8, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xa5, X86_DECODE_CMD_SHLD, 0, true, decode_modrm_rm, decode_modrm_reg, + decode_rcx, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xa8, X86_DECODE_CMD_PUSH_SEG, 0, false, false, + NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + {0xa9, X86_DECODE_CMD_POP_SEG, 0, false, false, + NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + {0xab, X86_DECODE_CMD_BTS, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_CF}, + {0xac, X86_DECODE_CMD_SHRD, 0, true, decode_modrm_rm, decode_modrm_reg, + decode_imm8, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xad, X86_DECODE_CMD_SHRD, 0, true, decode_modrm_rm, decode_modrm_reg, + decode_rcx, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xae, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, + NULL, NULL, NULL, decode_aegroup, RFLAGS_MASK_NONE}, + + {0xaf, X86_DECODE_CMD_IMUL_2, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xb2, X86_DECODE_CMD_LSS, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_NONE}, + {0xb3, X86_DECODE_CMD_BTR, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xba, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8, + NULL, NULL, decode_btgroup, RFLAGS_MASK_OSZAPC}, + {0xbb, X86_DECODE_CMD_BTC, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xbc, X86_DECODE_CMD_BSF, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + {0xbd, X86_DECODE_CMD_BSR, 0, true, decode_modrm_reg, decode_modrm_rm, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xc1, X86_DECODE_CMD_XADD, 0, true, decode_modrm_rm, decode_modrm_reg, + NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + + {0xc7, X86_DECODE_CMD_CMPXCHG8B, 0, true, decode_modrm_rm, + NULL, NULL, NULL, NULL, RFLAGS_MASK_ZF}, + + {0xc8, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xc9, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xca, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xcb, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xcc, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xcd, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xce, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + {0xcf, X86_DECODE_CMD_BSWAP, 0, false, + NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, +}; + +struct decode_x87_tbl invl_inst_x87 = {0x0, 0, 0, 0, 0, false, false, NULL, + NULL, decode_invalid, 0}; + +struct decode_x87_tbl _x87_inst[] = { + {0xd8, 0, 3, X86_DECODE_CMD_FADD, 10, false, false, + decode_x87_modrm_st0, decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 0, 0, X86_DECODE_CMD_FADD, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xd8, 1, 3, X86_DECODE_CMD_FMUL, 10, false, false, decode_x87_modrm_st0, + decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 1, 0, X86_DECODE_CMD_FMUL, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xd8, 4, 3, X86_DECODE_CMD_FSUB, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 4, 0, X86_DECODE_CMD_FSUB, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xd8, 5, 3, X86_DECODE_CMD_FSUB, 10, true, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 5, 0, X86_DECODE_CMD_FSUB, 4, true, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xd8, 6, 3, X86_DECODE_CMD_FDIV, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 6, 0, X86_DECODE_CMD_FDIV, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xd8, 7, 3, X86_DECODE_CMD_FDIV, 10, true, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd8, 7, 0, X86_DECODE_CMD_FDIV, 4, true, false, decode_x87_modrm_st0, + decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + + {0xd9, 0, 3, X86_DECODE_CMD_FLD, 10, false, false, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 0, 0, X86_DECODE_CMD_FLD, 4, false, false, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xd9, 1, 0, X86_DECODE_CMD_INVL, 10, false, false, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 2, 3, X86_DECODE_CMD_INVL, 10, false, false, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 2, 0, X86_DECODE_CMD_FST, 4, false, false, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 3, 3, X86_DECODE_CMD_INVL, 10, false, false, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 3, 0, X86_DECODE_CMD_FST, 4, false, true, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, + decode_x87_modrm_st0, NULL, decode_d9_4, RFLAGS_MASK_NONE}, + {0xd9, 4, 0, X86_DECODE_CMD_INVL, 4, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 5, 3, X86_DECODE_CMD_FLDxx, 10, false, false, NULL, NULL, NULL, + RFLAGS_MASK_NONE}, + {0xd9, 5, 0, X86_DECODE_CMD_FLDCW, 2, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xd9, 7, 3, X86_DECODE_CMD_FNSTCW, 2, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + {0xd9, 7, 0, X86_DECODE_CMD_FNSTCW, 2, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xda, 0, 3, X86_DECODE_CMD_FCMOV, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xda, 0, 0, X86_DECODE_CMD_FADD, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xda, 1, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, + decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xda, 1, 0, X86_DECODE_CMD_FMUL, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xda, 2, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xda, 3, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xda, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, + RFLAGS_MASK_NONE}, + {0xda, 4, 0, X86_DECODE_CMD_FSUB, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xda, 5, 3, X86_DECODE_CMD_FUCOM, 10, false, true, decode_x87_modrm_st0, + decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xda, 5, 0, X86_DECODE_CMD_FSUB, 4, true, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xda, 6, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, + RFLAGS_MASK_NONE}, + {0xda, 6, 0, X86_DECODE_CMD_FDIV, 4, false, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xda, 7, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, + RFLAGS_MASK_NONE}, + {0xda, 7, 0, X86_DECODE_CMD_FDIV, 4, true, false, decode_x87_modrm_st0, + decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + + {0xdb, 0, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, + decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdb, 0, 0, X86_DECODE_CMD_FLD, 4, false, false, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdb, 1, 3, X86_DECODE_CMD_FCMOV, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdb, 2, 3, X86_DECODE_CMD_FCMOV, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdb, 2, 0, X86_DECODE_CMD_FST, 4, false, false, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdb, 3, 3, X86_DECODE_CMD_FCMOV, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdb, 3, 0, X86_DECODE_CMD_FST, 4, false, true, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdb, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, + decode_db_4, RFLAGS_MASK_NONE}, + {0xdb, 4, 0, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, + RFLAGS_MASK_NONE}, + {0xdb, 5, 3, X86_DECODE_CMD_FUCOMI, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdb, 5, 0, X86_DECODE_CMD_FLD, 10, false, false, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdb, 7, 0, X86_DECODE_CMD_FST, 10, false, true, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xdc, 0, 3, X86_DECODE_CMD_FADD, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 0, 0, X86_DECODE_CMD_FADD, 8, false, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xdc, 1, 3, X86_DECODE_CMD_FMUL, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 1, 0, X86_DECODE_CMD_FMUL, 8, false, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xdc, 4, 3, X86_DECODE_CMD_FSUB, 10, true, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 4, 0, X86_DECODE_CMD_FSUB, 8, false, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xdc, 5, 3, X86_DECODE_CMD_FSUB, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 5, 0, X86_DECODE_CMD_FSUB, 8, true, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xdc, 6, 3, X86_DECODE_CMD_FDIV, 10, true, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 6, 0, X86_DECODE_CMD_FDIV, 8, false, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + {0xdc, 7, 3, X86_DECODE_CMD_FDIV, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdc, 7, 0, X86_DECODE_CMD_FDIV, 8, true, false, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + + {0xdd, 0, 0, X86_DECODE_CMD_FLD, 8, false, false, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdd, 2, 3, X86_DECODE_CMD_FST, 10, false, false, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 2, 0, X86_DECODE_CMD_FST, 8, false, false, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 3, 3, X86_DECODE_CMD_FST, 10, false, true, + decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 3, 0, X86_DECODE_CMD_FST, 8, false, true, + decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 4, 3, X86_DECODE_CMD_FUCOM, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdd, 4, 0, X86_DECODE_CMD_FRSTOR, 8, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 5, 3, X86_DECODE_CMD_FUCOM, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdd, 7, 0, X86_DECODE_CMD_FNSTSW, 0, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdd, 7, 3, X86_DECODE_CMD_FNSTSW, 0, false, false, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + + {0xde, 0, 3, X86_DECODE_CMD_FADD, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 0, 0, X86_DECODE_CMD_FADD, 2, false, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xde, 1, 3, X86_DECODE_CMD_FMUL, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 1, 0, X86_DECODE_CMD_FMUL, 2, false, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xde, 4, 3, X86_DECODE_CMD_FSUB, 10, true, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 4, 0, X86_DECODE_CMD_FSUB, 2, false, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xde, 5, 3, X86_DECODE_CMD_FSUB, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 5, 0, X86_DECODE_CMD_FSUB, 2, true, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xde, 6, 3, X86_DECODE_CMD_FDIV, 10, true, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 6, 0, X86_DECODE_CMD_FDIV, 2, false, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + {0xde, 7, 3, X86_DECODE_CMD_FDIV, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xde, 7, 0, X86_DECODE_CMD_FDIV, 2, true, false, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + + {0xdf, 0, 0, X86_DECODE_CMD_FLD, 2, false, false, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdf, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdf, 2, 3, X86_DECODE_CMD_FST, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdf, 2, 0, X86_DECODE_CMD_FST, 2, false, false, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdf, 3, 3, X86_DECODE_CMD_FST, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdf, 3, 0, X86_DECODE_CMD_FST, 2, false, true, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdf, 4, 3, X86_DECODE_CMD_FNSTSW, 2, false, true, + decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdf, 5, 3, X86_DECODE_CMD_FUCOMI, 10, false, true, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + {0xdf, 5, 0, X86_DECODE_CMD_FLD, 8, false, false, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + {0xdf, 7, 0, X86_DECODE_CMD_FST, 8, false, true, + decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, +}; + +void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + addr_t ptr = 0; + x86_reg_segment seg = REG_SEG_DS; + + if (!decode->modrm.mod && 6 == decode->modrm.rm) { + op->ptr = (uint16_t)decode->displacement; + goto calc_addr; + } + + if (decode->displacement_size) { + ptr = sign(decode->displacement, decode->displacement_size); + } + + switch (decode->modrm.rm) { + case 0: + ptr += BX(env) + SI(env); + break; + case 1: + ptr += BX(env) + DI(env); + break; + case 2: + ptr += BP(env) + SI(env); + seg = REG_SEG_SS; + break; + case 3: + ptr += BP(env) + DI(env); + seg = REG_SEG_SS; + break; + case 4: + ptr += SI(env); + break; + case 5: + ptr += DI(env); + break; + case 6: + ptr += BP(env); + seg = REG_SEG_SS; + break; + case 7: + ptr += BX(env); + break; + } +calc_addr: + if (X86_DECODE_CMD_LEA == decode->cmd) { + op->ptr = (uint16_t)ptr; + } else { + op->ptr = decode_linear_addr(env, decode, (uint16_t)ptr, seg); + } +} + +addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size) +{ + addr_t ptr = 0; + int which = 0; + + if (is_extended) { + reg |= REG_R8; + } + + + switch (size) { + case 1: + if (is_extended || reg < 4) { + which = 1; + ptr = (addr_t)&RL(env, reg); + } else { + which = 2; + ptr = (addr_t)&RH(env, reg - 4); + } + break; + default: + which = 3; + ptr = (addr_t)&RRX(env, reg); + break; + } + return ptr; +} + +addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size) +{ + addr_t val = 0; + memcpy(&val, (void *)get_reg_ref(env, reg, is_extended, size), size); + return val; +} + +static addr_t get_sib_val(CPUX86State *env, struct x86_decode *decode, + x86_reg_segment *sel) +{ + addr_t base = 0; + addr_t scaled_index = 0; + int addr_size = decode->addressing_size; + int base_reg = decode->sib.base; + int index_reg = decode->sib.index; + + *sel = REG_SEG_DS; + + if (decode->modrm.mod || base_reg != REG_RBP) { + if (decode->rex.b) { + base_reg |= REG_R8; + } + if (REG_RSP == base_reg || REG_RBP == base_reg) { + *sel = REG_SEG_SS; + } + base = get_reg_val(env, decode->sib.base, decode->rex.b, addr_size); + } + + if (decode->rex.x) { + index_reg |= REG_R8; + } + + if (index_reg != REG_RSP) { + scaled_index = get_reg_val(env, index_reg, decode->rex.x, addr_size) << + decode->sib.scale; + } + return base + scaled_index; +} + +void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + x86_reg_segment seg = REG_SEG_DS; + addr_t ptr = 0; + int addr_size = decode->addressing_size; + + if (decode->displacement_size) { + ptr = sign(decode->displacement, decode->displacement_size); + } + + if (4 == decode->modrm.rm) { + ptr += get_sib_val(env, decode, &seg); + } else if (!decode->modrm.mod && 5 == decode->modrm.rm) { + if (x86_is_long_mode(ENV_GET_CPU(env))) { + ptr += RIP(env) + decode->len; + } else { + ptr = decode->displacement; + } + } else { + if (REG_RBP == decode->modrm.rm || REG_RSP == decode->modrm.rm) { + seg = REG_SEG_SS; + } + ptr += get_reg_val(env, decode->modrm.rm, decode->rex.b, addr_size); + } + + if (X86_DECODE_CMD_LEA == decode->cmd) { + op->ptr = (uint32_t)ptr; + } else { + op->ptr = decode_linear_addr(env, decode, (uint32_t)ptr, seg); + } +} + +void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + x86_reg_segment seg = REG_SEG_DS; + int32_t offset = 0; + int mod = decode->modrm.mod; + int rm = decode->modrm.rm; + addr_t ptr; + int src = decode->modrm.rm; + + if (decode->displacement_size) { + offset = sign(decode->displacement, decode->displacement_size); + } + + if (4 == rm) { + ptr = get_sib_val(env, decode, &seg) + offset; + } else if (0 == mod && 5 == rm) { + ptr = RIP(env) + decode->len + (int32_t) offset; + } else { + ptr = get_reg_val(env, src, decode->rex.b, 8) + (int64_t) offset; + } + + if (X86_DECODE_CMD_LEA == decode->cmd) { + op->ptr = ptr; + } else { + op->ptr = decode_linear_addr(env, decode, ptr, seg); + } +} + + +void calc_modrm_operand(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op) +{ + if (3 == decode->modrm.mod) { + op->reg = decode->modrm.reg; + op->type = X86_VAR_REG; + op->ptr = get_reg_ref(env, decode->modrm.rm, decode->rex.b, + decode->operand_size); + return; + } + + switch (decode->addressing_size) { + case 2: + calc_modrm_operand16(env, decode, op); + break; + case 4: + calc_modrm_operand32(env, decode, op); + break; + case 8: + calc_modrm_operand64(env, decode, op); + break; + default: + VM_PANIC_EX("unsupported address size %d\n", decode->addressing_size); + break; + } +} + +static void decode_prefix(CPUX86State *env, struct x86_decode *decode) +{ + while (1) { + uint8_t byte = decode_byte(env, decode); + switch (byte) { + case PREFIX_LOCK: + decode->lock = byte; + break; + case PREFIX_REPN: + case PREFIX_REP: + decode->rep = byte; + break; + case PREFIX_CS_SEG_OVEERIDE: + case PREFIX_SS_SEG_OVEERIDE: + case PREFIX_DS_SEG_OVEERIDE: + case PREFIX_ES_SEG_OVEERIDE: + case PREFIX_FS_SEG_OVEERIDE: + case PREFIX_GS_SEG_OVEERIDE: + decode->segment_override = byte; + break; + case PREFIX_OP_SIZE_OVERRIDE: + decode->op_size_override = byte; + break; + case PREFIX_ADDR_SIZE_OVERRIDE: + decode->addr_size_override = byte; + break; + case PREFIX_REX ... (PREFIX_REX + 0xf): + if (x86_is_long_mode(ENV_GET_CPU(env))) { + decode->rex.rex = byte; + break; + } + /* fall through when not in long mode */ + default: + decode->len--; + return; + } + } +} + +void set_addressing_size(CPUX86State *env, struct x86_decode *decode) +{ + decode->addressing_size = -1; + if (x86_is_real(ENV_GET_CPU(env)) || x86_is_v8086(ENV_GET_CPU(env))) { + if (decode->addr_size_override) { + decode->addressing_size = 4; + } else { + decode->addressing_size = 2; + } + } else if (!x86_is_long_mode(ENV_GET_CPU(env))) { + /* protected */ + struct vmx_segment cs; + vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, REG_SEG_CS); + /* check db */ + if ((cs.ar >> 14) & 1) { + if (decode->addr_size_override) { + decode->addressing_size = 2; + } else { + decode->addressing_size = 4; + } + } else { + if (decode->addr_size_override) { + decode->addressing_size = 4; + } else { + decode->addressing_size = 2; + } + } + } else { + /* long */ + if (decode->addr_size_override) { + decode->addressing_size = 4; + } else { + decode->addressing_size = 8; + } + } +} + +void set_operand_size(CPUX86State *env, struct x86_decode *decode) +{ + decode->operand_size = -1; + if (x86_is_real(ENV_GET_CPU(env)) || x86_is_v8086(ENV_GET_CPU(env))) { + if (decode->op_size_override) { + decode->operand_size = 4; + } else { + decode->operand_size = 2; + } + } else if (!x86_is_long_mode(ENV_GET_CPU(env))) { + /* protected */ + struct vmx_segment cs; + vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, REG_SEG_CS); + /* check db */ + if ((cs.ar >> 14) & 1) { + if (decode->op_size_override) { + decode->operand_size = 2; + } else{ + decode->operand_size = 4; + } + } else { + if (decode->op_size_override) { + decode->operand_size = 4; + } else { + decode->operand_size = 2; + } + } + } else { + /* long */ + if (decode->op_size_override) { + decode->operand_size = 2; + } else { + decode->operand_size = 4; + } + + if (decode->rex.w) { + decode->operand_size = 8; + } + } +} + +static void decode_sib(CPUX86State *env, struct x86_decode *decode) +{ + if ((decode->modrm.mod != 3) && (4 == decode->modrm.rm) && + (decode->addressing_size != 2)) { + decode->sib.sib = decode_byte(env, decode); + decode->sib_present = true; + } +} + +/* 16 bit modrm */ +int disp16_tbl[4][8] = { + {0, 0, 0, 0, 0, 0, 2, 0}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {2, 2, 2, 2, 2, 2, 2, 2}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +/* 32/64-bit modrm */ +int disp32_tbl[4][8] = { + {0, 0, 0, 0, -1, 4, 0, 0}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {4, 4, 4, 4, 4, 4, 4, 4}, + {0, 0, 0, 0, 0, 0, 0, 0} +}; + +static inline void decode_displacement(CPUX86State *env, struct x86_decode *decode) +{ + int addressing_size = decode->addressing_size; + int mod = decode->modrm.mod; + int rm = decode->modrm.rm; + + decode->displacement_size = 0; + switch (addressing_size) { + case 2: + decode->displacement_size = disp16_tbl[mod][rm]; + if (decode->displacement_size) { + decode->displacement = (uint16_t)decode_bytes(env, decode, + decode->displacement_size); + } + break; + case 4: + case 8: + if (-1 == disp32_tbl[mod][rm]) { + if (5 == decode->sib.base) { + decode->displacement_size = 4; + } + } else { + decode->displacement_size = disp32_tbl[mod][rm]; + } + + if (decode->displacement_size) { + decode->displacement = (uint32_t)decode_bytes(env, decode, + decode->displacement_size); + } + break; + } +} + +static inline void decode_modrm(CPUX86State *env, struct x86_decode *decode) +{ + decode->modrm.modrm = decode_byte(env, decode); + decode->is_modrm = true; + + decode_sib(env, decode); + decode_displacement(env, decode); +} + +static inline void decode_opcode_general(CPUX86State *env, + struct x86_decode *decode, + uint8_t opcode, + struct decode_tbl *inst_decoder) +{ + decode->cmd = inst_decoder->cmd; + if (inst_decoder->operand_size) { + decode->operand_size = inst_decoder->operand_size; + } + decode->flags_mask = inst_decoder->flags_mask; + + if (inst_decoder->is_modrm) { + decode_modrm(env, decode); + } + if (inst_decoder->decode_op1) { + inst_decoder->decode_op1(env, decode, &decode->op[0]); + } + if (inst_decoder->decode_op2) { + inst_decoder->decode_op2(env, decode, &decode->op[1]); + } + if (inst_decoder->decode_op3) { + inst_decoder->decode_op3(env, decode, &decode->op[2]); + } + if (inst_decoder->decode_op4) { + inst_decoder->decode_op4(env, decode, &decode->op[3]); + } + if (inst_decoder->decode_postfix) { + inst_decoder->decode_postfix(env, decode); + } +} + +static inline void decode_opcode_1(CPUX86State *env, struct x86_decode *decode, + uint8_t opcode) +{ + struct decode_tbl *inst_decoder = &_decode_tbl1[opcode]; + decode_opcode_general(env, decode, opcode, inst_decoder); +} + + +static inline void decode_opcode_2(CPUX86State *env, struct x86_decode *decode, + uint8_t opcode) +{ + struct decode_tbl *inst_decoder = &_decode_tbl2[opcode]; + decode_opcode_general(env, decode, opcode, inst_decoder); +} + +static void decode_opcodes(CPUX86State *env, struct x86_decode *decode) +{ + uint8_t opcode; + + opcode = decode_byte(env, decode); + decode->opcode[decode->opcode_len++] = opcode; + if (opcode != OPCODE_ESCAPE) { + decode_opcode_1(env, decode, opcode); + } else { + opcode = decode_byte(env, decode); + decode->opcode[decode->opcode_len++] = opcode; + decode_opcode_2(env, decode, opcode); + } +} + +uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode) +{ + ZERO_INIT(*decode); + + decode_prefix(env, decode); + set_addressing_size(env, decode); + set_operand_size(env, decode); + + decode_opcodes(env, decode); + + return decode->len; +} + +void init_decoder() +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_decode_tbl2); i++) { + memcpy(_decode_tbl1, &invl_inst, sizeof(invl_inst)); + } + for (i = 0; i < ARRAY_SIZE(_decode_tbl2); i++) { + memcpy(_decode_tbl2, &invl_inst, sizeof(invl_inst)); + } + for (i = 0; i < ARRAY_SIZE(_decode_tbl3); i++) { + memcpy(_decode_tbl3, &invl_inst, sizeof(invl_inst_x87)); + + } + for (i = 0; i < ARRAY_SIZE(_1op_inst); i++) { + _decode_tbl1[_1op_inst[i].opcode] = _1op_inst[i]; + } + for (i = 0; i < ARRAY_SIZE(_2op_inst); i++) { + _decode_tbl2[_2op_inst[i].opcode] = _2op_inst[i]; + } + for (i = 0; i < ARRAY_SIZE(_x87_inst); i++) { + int index = ((_x87_inst[i].opcode & 0xf) << 4) | + ((_x87_inst[i].modrm_mod & 1) << 3) | + _x87_inst[i].modrm_reg; + _decode_tbl3[index] = _x87_inst[i]; + } +} + + +const char *decode_cmd_to_string(enum x86_decode_cmd cmd) +{ + static const char *cmds[] = {"INVL", "PUSH", "PUSH_SEG", "POP", "POP_SEG", + "MOV", "MOVSX", "MOVZX", "CALL_NEAR", "CALL_NEAR_ABS_INDIRECT", + "CALL_FAR_ABS_INDIRECT", "CMD_CALL_FAR", "RET_NEAR", "RET_FAR", "ADD", + "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP", "INC", "DEC", "TST", + "NOT", "NEG", "JMP_NEAR", "JMP_NEAR_ABS_INDIRECT", "JMP_FAR", + "JMP_FAR_ABS_INDIRECT", "LEA", "JXX", "JCXZ", "SETXX", "MOV_TO_SEG", + "MOV_FROM_SEG", "CLI", "STI", "CLD", "STD", "STC", "CLC", "OUT", "IN", + "INS", "OUTS", "LIDT", "SIDT", "LGDT", "SGDT", "SMSW", "LMSW", + "RDTSCP", "INVLPG", "MOV_TO_CR", "MOV_FROM_CR", "MOV_TO_DR", + "MOV_FROM_DR", "PUSHF", "POPF", "CPUID", "ROL", "ROR", "RCL", "RCR", + "SHL", "SAL", "SHR", "SHRD", "SHLD", "SAR", "DIV", "IDIV", "MUL", + "IMUL_3", "IMUL_2", "IMUL_1", "MOVS", "CMPS", "SCAS", "LODS", "STOS", + "BSWAP", "XCHG", "RDTSC", "RDMSR", "WRMSR", "ENTER", "LEAVE", "BT", + "BTS", "BTC", "BTR", "BSF", "BSR", "IRET", "INT", "POPA", "PUSHA", + "CWD", "CBW", "DAS", "AAD", "AAM", "AAS", "LOOP", "SLDT", "STR", "LLDT", + "LTR", "VERR", "VERW", "SAHF", "LAHF", "WBINVD", "LDS", "LSS", "LES", + "LGS", "LFS", "CMC", "XLAT", "NOP", "CMOV", "CLTS", "XADD", "HLT", + "CMPXCHG8B", "CMPXCHG", "POPCNT", "FNINIT", "FLD", "FLDxx", "FNSTCW", + "FNSTSW", "FNSETPM", "FSAVE", "FRSTOR", "FXSAVE", "FXRSTOR", "FDIV", + "FMUL", "FSUB", "FADD", "EMMS", "MFENCE", "SFENCE", "LFENCE", + "PREFETCH", "FST", "FABS", "FUCOM", "FUCOMI", "FLDCW", + "FXCH", "FCHS", "FCMOV", "FRNDINT", "FXAM", "LAST"}; + return cmds[cmd]; +} + +addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, + addr_t addr, x86_reg_segment seg) +{ + switch (decode->segment_override) { + case PREFIX_CS_SEG_OVEERIDE: + seg = REG_SEG_CS; + break; + case PREFIX_SS_SEG_OVEERIDE: + seg = REG_SEG_SS; + break; + case PREFIX_DS_SEG_OVEERIDE: + seg = REG_SEG_DS; + break; + case PREFIX_ES_SEG_OVEERIDE: + seg = REG_SEG_ES; + break; + case PREFIX_FS_SEG_OVEERIDE: + seg = REG_SEG_FS; + break; + case PREFIX_GS_SEG_OVEERIDE: + seg = REG_SEG_GS; + break; + default: + break; + } + return linear_addr_size(ENV_GET_CPU(env), addr, decode->addressing_size, seg); +} diff --git a/target/i386/hvf-utils/x86_decode.h b/target/i386/hvf-utils/x86_decode.h new file mode 100644 index 0000000000..540e95d17d --- /dev/null +++ b/target/i386/hvf-utils/x86_decode.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include "qemu-common.h" +#include "x86.h" +#include "cpu.h" + +typedef enum x86_prefix { + /* group 1 */ + PREFIX_LOCK = 0xf0, + PREFIX_REPN = 0xf2, + PREFIX_REP = 0xf3, + /* group 2 */ + PREFIX_CS_SEG_OVEERIDE = 0x2e, + PREFIX_SS_SEG_OVEERIDE = 0x36, + PREFIX_DS_SEG_OVEERIDE = 0x3e, + PREFIX_ES_SEG_OVEERIDE = 0x26, + PREFIX_FS_SEG_OVEERIDE = 0x64, + PREFIX_GS_SEG_OVEERIDE = 0x65, + /* group 3 */ + PREFIX_OP_SIZE_OVERRIDE = 0x66, + /* group 4 */ + PREFIX_ADDR_SIZE_OVERRIDE = 0x67, + + PREFIX_REX = 0x40, +} x86_prefix; + +enum x86_decode_cmd { + X86_DECODE_CMD_INVL = 0, + + X86_DECODE_CMD_PUSH, + X86_DECODE_CMD_PUSH_SEG, + X86_DECODE_CMD_POP, + X86_DECODE_CMD_POP_SEG, + X86_DECODE_CMD_MOV, + X86_DECODE_CMD_MOVSX, + X86_DECODE_CMD_MOVZX, + X86_DECODE_CMD_CALL_NEAR, + X86_DECODE_CMD_CALL_NEAR_ABS_INDIRECT, + X86_DECODE_CMD_CALL_FAR_ABS_INDIRECT, + X86_DECODE_CMD_CALL_FAR, + X86_DECODE_RET_NEAR, + X86_DECODE_RET_FAR, + X86_DECODE_CMD_ADD, + X86_DECODE_CMD_OR, + X86_DECODE_CMD_ADC, + X86_DECODE_CMD_SBB, + X86_DECODE_CMD_AND, + X86_DECODE_CMD_SUB, + X86_DECODE_CMD_XOR, + X86_DECODE_CMD_CMP, + X86_DECODE_CMD_INC, + X86_DECODE_CMD_DEC, + X86_DECODE_CMD_TST, + X86_DECODE_CMD_NOT, + X86_DECODE_CMD_NEG, + X86_DECODE_CMD_JMP_NEAR, + X86_DECODE_CMD_JMP_NEAR_ABS_INDIRECT, + X86_DECODE_CMD_JMP_FAR, + X86_DECODE_CMD_JMP_FAR_ABS_INDIRECT, + X86_DECODE_CMD_LEA, + X86_DECODE_CMD_JXX, + X86_DECODE_CMD_JCXZ, + X86_DECODE_CMD_SETXX, + X86_DECODE_CMD_MOV_TO_SEG, + X86_DECODE_CMD_MOV_FROM_SEG, + X86_DECODE_CMD_CLI, + X86_DECODE_CMD_STI, + X86_DECODE_CMD_CLD, + X86_DECODE_CMD_STD, + X86_DECODE_CMD_STC, + X86_DECODE_CMD_CLC, + X86_DECODE_CMD_OUT, + X86_DECODE_CMD_IN, + X86_DECODE_CMD_INS, + X86_DECODE_CMD_OUTS, + X86_DECODE_CMD_LIDT, + X86_DECODE_CMD_SIDT, + X86_DECODE_CMD_LGDT, + X86_DECODE_CMD_SGDT, + X86_DECODE_CMD_SMSW, + X86_DECODE_CMD_LMSW, + X86_DECODE_CMD_RDTSCP, + X86_DECODE_CMD_INVLPG, + X86_DECODE_CMD_MOV_TO_CR, + X86_DECODE_CMD_MOV_FROM_CR, + X86_DECODE_CMD_MOV_TO_DR, + X86_DECODE_CMD_MOV_FROM_DR, + X86_DECODE_CMD_PUSHF, + X86_DECODE_CMD_POPF, + X86_DECODE_CMD_CPUID, + X86_DECODE_CMD_ROL, + X86_DECODE_CMD_ROR, + X86_DECODE_CMD_RCL, + X86_DECODE_CMD_RCR, + X86_DECODE_CMD_SHL, + X86_DECODE_CMD_SAL, + X86_DECODE_CMD_SHR, + X86_DECODE_CMD_SHRD, + X86_DECODE_CMD_SHLD, + X86_DECODE_CMD_SAR, + X86_DECODE_CMD_DIV, + X86_DECODE_CMD_IDIV, + X86_DECODE_CMD_MUL, + X86_DECODE_CMD_IMUL_3, + X86_DECODE_CMD_IMUL_2, + X86_DECODE_CMD_IMUL_1, + X86_DECODE_CMD_MOVS, + X86_DECODE_CMD_CMPS, + X86_DECODE_CMD_SCAS, + X86_DECODE_CMD_LODS, + X86_DECODE_CMD_STOS, + X86_DECODE_CMD_BSWAP, + X86_DECODE_CMD_XCHG, + X86_DECODE_CMD_RDTSC, + X86_DECODE_CMD_RDMSR, + X86_DECODE_CMD_WRMSR, + X86_DECODE_CMD_ENTER, + X86_DECODE_CMD_LEAVE, + X86_DECODE_CMD_BT, + X86_DECODE_CMD_BTS, + X86_DECODE_CMD_BTC, + X86_DECODE_CMD_BTR, + X86_DECODE_CMD_BSF, + X86_DECODE_CMD_BSR, + X86_DECODE_CMD_IRET, + X86_DECODE_CMD_INT, + X86_DECODE_CMD_POPA, + X86_DECODE_CMD_PUSHA, + X86_DECODE_CMD_CWD, + X86_DECODE_CMD_CBW, + X86_DECODE_CMD_DAS, + X86_DECODE_CMD_AAD, + X86_DECODE_CMD_AAM, + X86_DECODE_CMD_AAS, + X86_DECODE_CMD_LOOP, + X86_DECODE_CMD_SLDT, + X86_DECODE_CMD_STR, + X86_DECODE_CMD_LLDT, + X86_DECODE_CMD_LTR, + X86_DECODE_CMD_VERR, + X86_DECODE_CMD_VERW, + X86_DECODE_CMD_SAHF, + X86_DECODE_CMD_LAHF, + X86_DECODE_CMD_WBINVD, + X86_DECODE_CMD_LDS, + X86_DECODE_CMD_LSS, + X86_DECODE_CMD_LES, + X86_DECODE_XMD_LGS, + X86_DECODE_CMD_LFS, + X86_DECODE_CMD_CMC, + X86_DECODE_CMD_XLAT, + X86_DECODE_CMD_NOP, + X86_DECODE_CMD_CMOV, + X86_DECODE_CMD_CLTS, + X86_DECODE_CMD_XADD, + X86_DECODE_CMD_HLT, + X86_DECODE_CMD_CMPXCHG8B, + X86_DECODE_CMD_CMPXCHG, + X86_DECODE_CMD_POPCNT, + + X86_DECODE_CMD_FNINIT, + X86_DECODE_CMD_FLD, + X86_DECODE_CMD_FLDxx, + X86_DECODE_CMD_FNSTCW, + X86_DECODE_CMD_FNSTSW, + X86_DECODE_CMD_FNSETPM, + X86_DECODE_CMD_FSAVE, + X86_DECODE_CMD_FRSTOR, + X86_DECODE_CMD_FXSAVE, + X86_DECODE_CMD_FXRSTOR, + X86_DECODE_CMD_FDIV, + X86_DECODE_CMD_FMUL, + X86_DECODE_CMD_FSUB, + X86_DECODE_CMD_FADD, + X86_DECODE_CMD_EMMS, + X86_DECODE_CMD_MFENCE, + X86_DECODE_CMD_SFENCE, + X86_DECODE_CMD_LFENCE, + X86_DECODE_CMD_PREFETCH, + X86_DECODE_CMD_CLFLUSH, + X86_DECODE_CMD_FST, + X86_DECODE_CMD_FABS, + X86_DECODE_CMD_FUCOM, + X86_DECODE_CMD_FUCOMI, + X86_DECODE_CMD_FLDCW, + X86_DECODE_CMD_FXCH, + X86_DECODE_CMD_FCHS, + X86_DECODE_CMD_FCMOV, + X86_DECODE_CMD_FRNDINT, + X86_DECODE_CMD_FXAM, + + X86_DECODE_CMD_LAST, +}; + +const char *decode_cmd_to_string(enum x86_decode_cmd cmd); + +typedef struct x86_modrm { + union { + uint8_t modrm; + struct { + uint8_t rm:3; + uint8_t reg:3; + uint8_t mod:2; + }; + }; +} __attribute__ ((__packed__)) x86_modrm; + +typedef struct x86_sib { + union { + uint8_t sib; + struct { + uint8_t base:3; + uint8_t index:3; + uint8_t scale:2; + }; + }; +} __attribute__ ((__packed__)) x86_sib; + +typedef struct x86_rex { + union { + uint8_t rex; + struct { + uint8_t b:1; + uint8_t x:1; + uint8_t r:1; + uint8_t w:1; + uint8_t unused:4; + }; + }; +} __attribute__ ((__packed__)) x86_rex; + +typedef enum x86_var_type { + X86_VAR_IMMEDIATE, + X86_VAR_OFFSET, + X86_VAR_REG, + X86_VAR_RM, + + /* for floating point computations */ + X87_VAR_REG, + X87_VAR_FLOATP, + X87_VAR_INTP, + X87_VAR_BYTEP, +} x86_var_type; + +typedef struct x86_decode_op { + enum x86_var_type type; + int size; + + int reg; + addr_t val; + + addr_t ptr; +} x86_decode_op; + +typedef struct x86_decode { + int len; + uint8_t opcode[4]; + uint8_t opcode_len; + enum x86_decode_cmd cmd; + int addressing_size; + int operand_size; + int lock; + int rep; + int op_size_override; + int addr_size_override; + int segment_override; + int control_change_inst; + bool fwait; + bool fpop_stack; + bool frev; + + uint32_t displacement; + uint8_t displacement_size; + struct x86_rex rex; + bool is_modrm; + bool sib_present; + struct x86_sib sib; + struct x86_modrm modrm; + struct x86_decode_op op[4]; + bool is_fpu; + addr_t flags_mask; + +} x86_decode; + +uint64_t sign(uint64_t val, int size); + +uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode); + +addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size); +addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size); +void calc_modrm_operand(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op); +addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, + addr_t addr, x86_reg_segment seg); + +void init_decoder(void); +void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op); +void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op); +void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, + struct x86_decode_op *op); +void set_addressing_size(CPUX86State *env, struct x86_decode *decode); +void set_operand_size(CPUX86State *env, struct x86_decode *decode); diff --git a/target/i386/hvf-utils/x86_descr.c b/target/i386/hvf-utils/x86_descr.c new file mode 100644 index 0000000000..c3b089aaa8 --- /dev/null +++ b/target/i386/hvf-utils/x86_descr.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" + +#include "vmx.h" +#include "x86_descr.h" + +#define VMX_SEGMENT_FIELD(seg) \ + [REG_SEG_##seg] = { \ + .selector = VMCS_GUEST_##seg##_SELECTOR, \ + .base = VMCS_GUEST_##seg##_BASE, \ + .limit = VMCS_GUEST_##seg##_LIMIT, \ + .ar_bytes = VMCS_GUEST_##seg##_ACCESS_RIGHTS, \ +} + +static const struct vmx_segment_field { + int selector; + int base; + int limit; + int ar_bytes; +} vmx_segment_fields[] = { + VMX_SEGMENT_FIELD(ES), + VMX_SEGMENT_FIELD(CS), + VMX_SEGMENT_FIELD(SS), + VMX_SEGMENT_FIELD(DS), + VMX_SEGMENT_FIELD(FS), + VMX_SEGMENT_FIELD(GS), + VMX_SEGMENT_FIELD(LDTR), + VMX_SEGMENT_FIELD(TR), +}; + +uint32_t vmx_read_segment_limit(CPUState *cpu, x86_reg_segment seg) +{ + return (uint32_t)rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].limit); +} + +uint32_t vmx_read_segment_ar(CPUState *cpu, x86_reg_segment seg) +{ + return (uint32_t)rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].ar_bytes); +} + +uint64_t vmx_read_segment_base(CPUState *cpu, x86_reg_segment seg) +{ + return rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].base); +} + +x68_segment_selector vmx_read_segment_selector(CPUState *cpu, x86_reg_segment seg) +{ + x68_segment_selector sel; + sel.sel = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector); + return sel; +} + +void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, x86_reg_segment seg) +{ + wvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector, selector.sel); +} + +void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, x86_reg_segment seg) +{ + desc->sel = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector); + desc->base = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].base); + desc->limit = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].limit); + desc->ar = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].ar_bytes); +} + +void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, x86_reg_segment seg) +{ + const struct vmx_segment_field *sf = &vmx_segment_fields[seg]; + + wvmcs(cpu->hvf_fd, sf->base, desc->base); + wvmcs(cpu->hvf_fd, sf->limit, desc->limit); + wvmcs(cpu->hvf_fd, sf->selector, desc->sel); + wvmcs(cpu->hvf_fd, sf->ar_bytes, desc->ar); +} + +void x86_segment_descriptor_to_vmx(struct CPUState *cpu, x68_segment_selector selector, struct x86_segment_descriptor *desc, struct vmx_segment *vmx_desc) +{ + vmx_desc->sel = selector.sel; + vmx_desc->base = x86_segment_base(desc); + vmx_desc->limit = x86_segment_limit(desc); + + vmx_desc->ar = (selector.sel ? 0 : 1) << 16 | + desc->g << 15 | + desc->db << 14 | + desc->l << 13 | + desc->avl << 12 | + desc->p << 7 | + desc->dpl << 5 | + desc->s << 4 | + desc->type; +} + +void vmx_segment_to_x86_descriptor(struct CPUState *cpu, struct vmx_segment *vmx_desc, struct x86_segment_descriptor *desc) +{ + x86_set_segment_limit(desc, vmx_desc->limit); + x86_set_segment_base(desc, vmx_desc->base); + + desc->type = vmx_desc->ar & 15; + desc->s = (vmx_desc->ar >> 4) & 1; + desc->dpl = (vmx_desc->ar >> 5) & 3; + desc->p = (vmx_desc->ar >> 7) & 1; + desc->avl = (vmx_desc->ar >> 12) & 1; + desc->l = (vmx_desc->ar >> 13) & 1; + desc->db = (vmx_desc->ar >> 14) & 1; + desc->g = (vmx_desc->ar >> 15) & 1; +} + diff --git a/target/i386/hvf-utils/x86_descr.h b/target/i386/hvf-utils/x86_descr.h new file mode 100644 index 0000000000..f5e247782b --- /dev/null +++ b/target/i386/hvf-utils/x86_descr.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#pragma once + +#include "x86.h" + +typedef struct vmx_segment { + uint16_t sel; + uint64_t base; + uint64_t limit; + uint64_t ar; +} vmx_segment; + +/* deal with vmstate descriptors */ +void vmx_read_segment_descriptor(struct CPUState *cpu, + struct vmx_segment *desc, x86_reg_segment seg); +void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, + x86_reg_segment seg); + +x68_segment_selector vmx_read_segment_selector(struct CPUState *cpu, + x86_reg_segment seg); +void vmx_write_segment_selector(struct CPUState *cpu, + x68_segment_selector selector, + x86_reg_segment seg); + +uint64_t vmx_read_segment_base(struct CPUState *cpu, x86_reg_segment seg); +void vmx_write_segment_base(struct CPUState *cpu, x86_reg_segment seg, + uint64_t base); + +void x86_segment_descriptor_to_vmx(struct CPUState *cpu, + x68_segment_selector selector, + struct x86_segment_descriptor *desc, + struct vmx_segment *vmx_desc); + +uint32_t vmx_read_segment_limit(CPUState *cpu, x86_reg_segment seg); +uint32_t vmx_read_segment_ar(CPUState *cpu, x86_reg_segment seg); +void vmx_segment_to_x86_descriptor(struct CPUState *cpu, + struct vmx_segment *vmx_desc, + struct x86_segment_descriptor *desc); diff --git a/target/i386/hvf-utils/x86_emu.c b/target/i386/hvf-utils/x86_emu.c new file mode 100644 index 0000000000..eb09e38a77 --- /dev/null +++ b/target/i386/hvf-utils/x86_emu.c @@ -0,0 +1,1537 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2012 The Bochs Project +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA +///////////////////////////////////////////////////////////////////////// + +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "x86_decode.h" +#include "x86.h" +#include "x86_emu.h" +#include "x86_mmu.h" +#include "x86_flags.h" +#include "vmcs.h" +#include "vmx.h" + +void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, + int direction, int size, uint32_t count); + +#define EXEC_2OP_LOGIC_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ +{ \ + fetch_operands(env, decode, 2, true, true, false); \ + switch (decode->operand_size) { \ + case 1: \ + { \ + uint8_t v1 = (uint8_t)decode->op[0].val; \ + uint8_t v2 = (uint8_t)decode->op[1].val; \ + uint8_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 1); \ + } \ + FLAGS_FUNC##_8(diff); \ + break; \ + } \ + case 2: \ + { \ + uint16_t v1 = (uint16_t)decode->op[0].val; \ + uint16_t v2 = (uint16_t)decode->op[1].val; \ + uint16_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 2); \ + } \ + FLAGS_FUNC##_16(diff); \ + break; \ + } \ + case 4: \ + { \ + uint32_t v1 = (uint32_t)decode->op[0].val; \ + uint32_t v2 = (uint32_t)decode->op[1].val; \ + uint32_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 4); \ + } \ + FLAGS_FUNC##_32(diff); \ + break; \ + } \ + default: \ + VM_PANIC("bad size\n"); \ + } \ +} \ + + +#define EXEC_2OP_ARITH_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ +{ \ + fetch_operands(env, decode, 2, true, true, false); \ + switch (decode->operand_size) { \ + case 1: \ + { \ + uint8_t v1 = (uint8_t)decode->op[0].val; \ + uint8_t v2 = (uint8_t)decode->op[1].val; \ + uint8_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 1); \ + } \ + FLAGS_FUNC##_8(v1, v2, diff); \ + break; \ + } \ + case 2: \ + { \ + uint16_t v1 = (uint16_t)decode->op[0].val; \ + uint16_t v2 = (uint16_t)decode->op[1].val; \ + uint16_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 2); \ + } \ + FLAGS_FUNC##_16(v1, v2, diff); \ + break; \ + } \ + case 4: \ + { \ + uint32_t v1 = (uint32_t)decode->op[0].val; \ + uint32_t v2 = (uint32_t)decode->op[1].val; \ + uint32_t diff = v1 cmd v2; \ + if (save_res) { \ + write_val_ext(env, decode->op[0].ptr, diff, 4); \ + } \ + FLAGS_FUNC##_32(v1, v2, diff); \ + break; \ + } \ + default: \ + VM_PANIC("bad size\n"); \ + } \ +} + +addr_t read_reg(CPUX86State *env, int reg, int size) +{ + switch (size) { + case 1: + return env->hvf_emul->regs[reg].lx; + case 2: + return env->hvf_emul->regs[reg].rx; + case 4: + return env->hvf_emul->regs[reg].erx; + case 8: + return env->hvf_emul->regs[reg].rrx; + default: + VM_PANIC_ON("read_reg size"); + } + return 0; +} + +void write_reg(CPUX86State *env, int reg, addr_t val, int size) +{ + switch (size) { + case 1: + env->hvf_emul->regs[reg].lx = val; + break; + case 2: + env->hvf_emul->regs[reg].rx = val; + break; + case 4: + env->hvf_emul->regs[reg].rrx = (uint32_t)val; + break; + case 8: + env->hvf_emul->regs[reg].rrx = val; + break; + default: + VM_PANIC_ON("write_reg size"); + } +} + +addr_t read_val_from_reg(addr_t reg_ptr, int size) +{ + addr_t val; + + switch (size) { + case 1: + val = *(uint8_t *)reg_ptr; + break; + case 2: + val = *(uint16_t *)reg_ptr; + break; + case 4: + val = *(uint32_t *)reg_ptr; + break; + case 8: + val = *(uint64_t *)reg_ptr; + break; + default: + VM_PANIC_ON_EX(1, "read_val: Unknown size %d\n", size); + break; + } + return val; +} + +void write_val_to_reg(addr_t reg_ptr, addr_t val, int size) +{ + switch (size) { + case 1: + *(uint8_t *)reg_ptr = val; + break; + case 2: + *(uint16_t *)reg_ptr = val; + break; + case 4: + *(uint64_t *)reg_ptr = (uint32_t)val; + break; + case 8: + *(uint64_t *)reg_ptr = val; + break; + default: + VM_PANIC("write_val: Unknown size\n"); + break; + } +} + +static bool is_host_reg(struct CPUX86State *env, addr_t ptr) +{ + return (ptr - (addr_t)&env->hvf_emul->regs[0]) < sizeof(env->hvf_emul->regs); +} + +void write_val_ext(struct CPUX86State *env, addr_t ptr, addr_t val, int size) +{ + if (is_host_reg(env, ptr)) { + write_val_to_reg(ptr, val, size); + return; + } + vmx_write_mem(ENV_GET_CPU(env), ptr, &val, size); +} + +uint8_t *read_mmio(struct CPUX86State *env, addr_t ptr, int bytes) +{ + vmx_read_mem(ENV_GET_CPU(env), env->hvf_emul->mmio_buf, ptr, bytes); + return env->hvf_emul->mmio_buf; +} + + +addr_t read_val_ext(struct CPUX86State *env, addr_t ptr, int size) +{ + addr_t val; + uint8_t *mmio_ptr; + + if (is_host_reg(env, ptr)) { + return read_val_from_reg(ptr, size); + } + + mmio_ptr = read_mmio(env, ptr, size); + switch (size) { + case 1: + val = *(uint8_t *)mmio_ptr; + break; + case 2: + val = *(uint16_t *)mmio_ptr; + break; + case 4: + val = *(uint32_t *)mmio_ptr; + break; + case 8: + val = *(uint64_t *)mmio_ptr; + break; + default: + VM_PANIC("bad size\n"); + break; + } + return val; +} + +static void fetch_operands(struct CPUX86State *env, struct x86_decode *decode, + int n, bool val_op0, bool val_op1, bool val_op2) +{ + int i; + bool calc_val[3] = {val_op0, val_op1, val_op2}; + + for (i = 0; i < n; i++) { + switch (decode->op[i].type) { + case X86_VAR_IMMEDIATE: + break; + case X86_VAR_REG: + VM_PANIC_ON(!decode->op[i].ptr); + if (calc_val[i]) { + decode->op[i].val = read_val_from_reg(decode->op[i].ptr, + decode->operand_size); + } + break; + case X86_VAR_RM: + calc_modrm_operand(env, decode, &decode->op[i]); + if (calc_val[i]) { + decode->op[i].val = read_val_ext(env, decode->op[i].ptr, + decode->operand_size); + } + break; + case X86_VAR_OFFSET: + decode->op[i].ptr = decode_linear_addr(env, decode, + decode->op[i].ptr, + REG_SEG_DS); + if (calc_val[i]) { + decode->op[i].val = read_val_ext(env, decode->op[i].ptr, + decode->operand_size); + } + break; + default: + break; + } + } +} + +static void exec_mov(struct CPUX86State *env, struct x86_decode *decode) +{ + fetch_operands(env, decode, 2, false, true, false); + write_val_ext(env, decode->op[0].ptr, decode->op[1].val, + decode->operand_size); + + RIP(env) += decode->len; +} + +static void exec_add(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); + RIP(env) += decode->len; +} + +static void exec_or(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_LOGIC_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); + RIP(env) += decode->len; +} + +static void exec_adc(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); + RIP(env) += decode->len; +} + +static void exec_sbb(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); + RIP(env) += decode->len; +} + +static void exec_and(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_LOGIC_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); + RIP(env) += decode->len; +} + +static void exec_sub(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); + RIP(env) += decode->len; +} + +static void exec_xor(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_LOGIC_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); + RIP(env) += decode->len; +} + +static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) +{ + /*EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ + int32_t val; + fetch_operands(env, decode, 2, true, true, false); + + val = 0 - sign(decode->op[1].val, decode->operand_size); + write_val_ext(env, decode->op[1].ptr, val, decode->operand_size); + + if (4 == decode->operand_size) { + SET_FLAGS_OSZAPC_SUB_32(0, 0 - val, val); + } else if (2 == decode->operand_size) { + SET_FLAGS_OSZAPC_SUB_16(0, 0 - val, val); + } else if (1 == decode->operand_size) { + SET_FLAGS_OSZAPC_SUB_8(0, 0 - val, val); + } else { + VM_PANIC("bad op size\n"); + } + + /*lflags_to_rflags(env);*/ + RIP(env) += decode->len; +} + +static void exec_cmp(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + RIP(env) += decode->len; +} + +static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) +{ + decode->op[1].type = X86_VAR_IMMEDIATE; + decode->op[1].val = 0; + + EXEC_2OP_ARITH_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); + + RIP(env) += decode->len; +} + +static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) +{ + decode->op[1].type = X86_VAR_IMMEDIATE; + decode->op[1].val = 0; + + EXEC_2OP_ARITH_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); + RIP(env) += decode->len; +} + +static void exec_tst(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_LOGIC_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); + RIP(env) += decode->len; +} + +static void exec_not(struct CPUX86State *env, struct x86_decode *decode) +{ + fetch_operands(env, decode, 1, true, false, false); + + write_val_ext(env, decode->op[0].ptr, ~decode->op[0].val, + decode->operand_size); + RIP(env) += decode->len; +} + +void exec_movzx(struct CPUX86State *env, struct x86_decode *decode) +{ + int src_op_size; + int op_size = decode->operand_size; + + fetch_operands(env, decode, 1, false, false, false); + + if (0xb6 == decode->opcode[1]) { + src_op_size = 1; + } else { + src_op_size = 2; + } + decode->operand_size = src_op_size; + calc_modrm_operand(env, decode, &decode->op[1]); + decode->op[1].val = read_val_ext(env, decode->op[1].ptr, src_op_size); + write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); + + RIP(env) += decode->len; +} + +static void exec_out(struct CPUX86State *env, struct x86_decode *decode) +{ + switch (decode->opcode[0]) { + case 0xe6: + hvf_handle_io(ENV_GET_CPU(env), decode->op[0].val, &AL(env), 1, 1, 1); + break; + case 0xe7: + hvf_handle_io(ENV_GET_CPU(env), decode->op[0].val, &RAX(env), 1, + decode->operand_size, 1); + break; + case 0xee: + hvf_handle_io(ENV_GET_CPU(env), DX(env), &AL(env), 1, 1, 1); + break; + case 0xef: + hvf_handle_io(ENV_GET_CPU(env), DX(env), &RAX(env), 1, decode->operand_size, 1); + break; + default: + VM_PANIC("Bad out opcode\n"); + break; + } + RIP(env) += decode->len; +} + +static void exec_in(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t val = 0; + switch (decode->opcode[0]) { + case 0xe4: + hvf_handle_io(ENV_GET_CPU(env), decode->op[0].val, &AL(env), 0, 1, 1); + break; + case 0xe5: + hvf_handle_io(ENV_GET_CPU(env), decode->op[0].val, &val, 0, decode->operand_size, 1); + if (decode->operand_size == 2) { + AX(env) = val; + } else { + RAX(env) = (uint32_t)val; + } + break; + case 0xec: + hvf_handle_io(ENV_GET_CPU(env), DX(env), &AL(env), 0, 1, 1); + break; + case 0xed: + hvf_handle_io(ENV_GET_CPU(env), DX(env), &val, 0, decode->operand_size, 1); + if (decode->operand_size == 2) { + AX(env) = val; + } else { + RAX(env) = (uint32_t)val; + } + + break; + default: + VM_PANIC("Bad in opcode\n"); + break; + } + + RIP(env) += decode->len; +} + +static inline void string_increment_reg(struct CPUX86State *env, int reg, + struct x86_decode *decode) +{ + addr_t val = read_reg(env, reg, decode->addressing_size); + if (env->hvf_emul->rflags.df) { + val -= decode->operand_size; + } else { + val += decode->operand_size; + } + write_reg(env, reg, val, decode->addressing_size); +} + +static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode, + void (*func)(struct CPUX86State *env, + struct x86_decode *ins), int rep) +{ + addr_t rcx = read_reg(env, REG_RCX, decode->addressing_size); + while (rcx--) { + func(env, decode); + write_reg(env, REG_RCX, rcx, decode->addressing_size); + if ((PREFIX_REP == rep) && !get_ZF(env)) { + break; + } + if ((PREFIX_REPN == rep) && get_ZF(env)) { + break; + } + } +} + +static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, + REG_SEG_ES); + + hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 0, + decode->operand_size, 1); + vmx_write_mem(ENV_GET_CPU(env), addr, env->hvf_emul->mmio_buf, decode->operand_size); + + string_increment_reg(env, REG_RDI, decode); +} + +static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_ins_single, 0); + } else { + exec_ins_single(env, decode); + } + + RIP(env) += decode->len; +} + +static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + + vmx_read_mem(ENV_GET_CPU(env), env->hvf_emul->mmio_buf, addr, decode->operand_size); + hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 1, + decode->operand_size, 1); + + string_increment_reg(env, REG_RSI, decode); +} + +static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_outs_single, 0); + } else { + exec_outs_single(env, decode); + } + + RIP(env) += decode->len; +} + +static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t src_addr; + addr_t dst_addr; + addr_t val; + + src_addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, + REG_SEG_ES); + + val = read_val_ext(env, src_addr, decode->operand_size); + write_val_ext(env, dst_addr, val, decode->operand_size); + + string_increment_reg(env, REG_RSI, decode); + string_increment_reg(env, REG_RDI, decode); +} + +static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_movs_single, 0); + } else { + exec_movs_single(env, decode); + } + + RIP(env) += decode->len; +} + +static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t src_addr; + addr_t dst_addr; + + src_addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, + REG_SEG_ES); + + decode->op[0].type = X86_VAR_IMMEDIATE; + decode->op[0].val = read_val_ext(env, src_addr, decode->operand_size); + decode->op[1].type = X86_VAR_IMMEDIATE; + decode->op[1].val = read_val_ext(env, dst_addr, decode->operand_size); + + EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + + string_increment_reg(env, REG_RSI, decode); + string_increment_reg(env, REG_RDI, decode); +} + +static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_cmps_single, decode->rep); + } else { + exec_cmps_single(env, decode); + } + RIP(env) += decode->len; +} + + +static void exec_stos_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t addr; + addr_t val; + + addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, REG_SEG_ES); + val = read_reg(env, REG_RAX, decode->operand_size); + vmx_write_mem(ENV_GET_CPU(env), addr, &val, decode->operand_size); + + string_increment_reg(env, REG_RDI, decode); +} + + +static void exec_stos(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_stos_single, 0); + } else { + exec_stos_single(env, decode); + } + + RIP(env) += decode->len; +} + +static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t addr; + + addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, REG_SEG_ES); + decode->op[1].type = X86_VAR_IMMEDIATE; + vmx_read_mem(ENV_GET_CPU(env), &decode->op[1].val, addr, decode->operand_size); + + EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + string_increment_reg(env, REG_RDI, decode); +} + +static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) +{ + decode->op[0].type = X86_VAR_REG; + decode->op[0].reg = REG_RAX; + if (decode->rep) { + string_rep(env, decode, exec_scas_single, decode->rep); + } else { + exec_scas_single(env, decode); + } + + RIP(env) += decode->len; +} + +static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) +{ + addr_t addr; + addr_t val = 0; + + addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + vmx_read_mem(ENV_GET_CPU(env), &val, addr, decode->operand_size); + write_reg(env, REG_RAX, val, decode->operand_size); + + string_increment_reg(env, REG_RSI, decode); +} + +static void exec_lods(struct CPUX86State *env, struct x86_decode *decode) +{ + if (decode->rep) { + string_rep(env, decode, exec_lods_single, 0); + } else { + exec_lods_single(env, decode); + } + + RIP(env) += decode->len; +} + +#define MSR_IA32_UCODE_REV 0x00000017 + +void simulate_rdmsr(struct CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + uint32_t msr = ECX(env); + uint64_t val = 0; + + switch (msr) { + case MSR_IA32_TSC: + val = rdtscp() + rvmcs(cpu->hvf_fd, VMCS_TSC_OFFSET); + break; + case MSR_IA32_APICBASE: + val = cpu_get_apic_base(X86_CPU(cpu)->apic_state); + break; + case MSR_IA32_UCODE_REV: + val = (0x100000000ULL << 32) | 0x100000000ULL; + break; + case MSR_EFER: + val = rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER); + break; + case MSR_FSBASE: + val = rvmcs(cpu->hvf_fd, VMCS_GUEST_FS_BASE); + break; + case MSR_GSBASE: + val = rvmcs(cpu->hvf_fd, VMCS_GUEST_GS_BASE); + break; + case MSR_KERNELGSBASE: + val = rvmcs(cpu->hvf_fd, VMCS_HOST_FS_BASE); + break; + case MSR_STAR: + abort(); + break; + case MSR_LSTAR: + abort(); + break; + case MSR_CSTAR: + abort(); + break; + case MSR_IA32_MISC_ENABLE: + val = env->msr_ia32_misc_enable; + break; + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + val = env->mtrr_var[(ECX(env) - MSR_MTRRphysBase(0)) / 2].base; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + val = env->mtrr_var[(ECX(env) - MSR_MTRRphysMask(0)) / 2].mask; + break; + case MSR_MTRRfix64K_00000: + val = env->mtrr_fixed[0]; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + val = env->mtrr_fixed[ECX(env) - MSR_MTRRfix16K_80000 + 1]; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + val = env->mtrr_fixed[ECX(env) - MSR_MTRRfix4K_C0000 + 3]; + break; + case MSR_MTRRdefType: + val = env->mtrr_deftype; + break; + default: + /* fprintf(stderr, "%s: unknown msr 0x%x\n", __func__, msr); */ + val = 0; + break; + } + + RAX(env) = (uint32_t)val; + RDX(env) = (uint32_t)(val >> 32); +} + +static void exec_rdmsr(struct CPUX86State *env, struct x86_decode *decode) +{ + simulate_rdmsr(ENV_GET_CPU(env)); + RIP(env) += decode->len; +} + +void simulate_wrmsr(struct CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + uint32_t msr = ECX(env); + uint64_t data = ((uint64_t)EDX(env) << 32) | EAX(env); + + switch (msr) { + case MSR_IA32_TSC: + /* if (!osx_is_sierra()) + wvmcs(cpu->hvf_fd, VMCS_TSC_OFFSET, data - rdtscp()); + hv_vm_sync_tsc(data);*/ + break; + case MSR_IA32_APICBASE: + cpu_set_apic_base(X86_CPU(cpu)->apic_state, data); + break; + case MSR_FSBASE: + wvmcs(cpu->hvf_fd, VMCS_GUEST_FS_BASE, data); + break; + case MSR_GSBASE: + wvmcs(cpu->hvf_fd, VMCS_GUEST_GS_BASE, data); + break; + case MSR_KERNELGSBASE: + wvmcs(cpu->hvf_fd, VMCS_HOST_FS_BASE, data); + break; + case MSR_STAR: + abort(); + break; + case MSR_LSTAR: + abort(); + break; + case MSR_CSTAR: + abort(); + break; + case MSR_EFER: + env->hvf_emul->efer.efer = data; + /*printf("new efer %llx\n", EFER(cpu));*/ + wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, data); + if (data & EFER_NXE) { + hv_vcpu_invalidate_tlb(cpu->hvf_fd); + } + break; + case MSR_MTRRphysBase(0): + case MSR_MTRRphysBase(1): + case MSR_MTRRphysBase(2): + case MSR_MTRRphysBase(3): + case MSR_MTRRphysBase(4): + case MSR_MTRRphysBase(5): + case MSR_MTRRphysBase(6): + case MSR_MTRRphysBase(7): + env->mtrr_var[(ECX(env) - MSR_MTRRphysBase(0)) / 2].base = data; + break; + case MSR_MTRRphysMask(0): + case MSR_MTRRphysMask(1): + case MSR_MTRRphysMask(2): + case MSR_MTRRphysMask(3): + case MSR_MTRRphysMask(4): + case MSR_MTRRphysMask(5): + case MSR_MTRRphysMask(6): + case MSR_MTRRphysMask(7): + env->mtrr_var[(ECX(env) - MSR_MTRRphysMask(0)) / 2].mask = data; + break; + case MSR_MTRRfix64K_00000: + env->mtrr_fixed[ECX(env) - MSR_MTRRfix64K_00000] = data; + break; + case MSR_MTRRfix16K_80000: + case MSR_MTRRfix16K_A0000: + env->mtrr_fixed[ECX(env) - MSR_MTRRfix16K_80000 + 1] = data; + break; + case MSR_MTRRfix4K_C0000: + case MSR_MTRRfix4K_C8000: + case MSR_MTRRfix4K_D0000: + case MSR_MTRRfix4K_D8000: + case MSR_MTRRfix4K_E0000: + case MSR_MTRRfix4K_E8000: + case MSR_MTRRfix4K_F0000: + case MSR_MTRRfix4K_F8000: + env->mtrr_fixed[ECX(env) - MSR_MTRRfix4K_C0000 + 3] = data; + break; + case MSR_MTRRdefType: + env->mtrr_deftype = data; + break; + default: + break; + } + + /* Related to support known hypervisor interface */ + /* if (g_hypervisor_iface) + g_hypervisor_iface->wrmsr_handler(cpu, msr, data); + + printf("write msr %llx\n", RCX(cpu));*/ +} + +static void exec_wrmsr(struct CPUX86State *env, struct x86_decode *decode) +{ + simulate_wrmsr(ENV_GET_CPU(env)); + RIP(env) += decode->len; +} + +/* + * flag: + * 0 - bt, 1 - btc, 2 - bts, 3 - btr + */ +static void do_bt(struct CPUX86State *env, struct x86_decode *decode, int flag) +{ + int32_t displacement; + uint8_t index; + bool cf; + int mask = (4 == decode->operand_size) ? 0x1f : 0xf; + + VM_PANIC_ON(decode->rex.rex); + + fetch_operands(env, decode, 2, false, true, false); + index = decode->op[1].val & mask; + + if (decode->op[0].type != X86_VAR_REG) { + if (4 == decode->operand_size) { + displacement = ((int32_t) (decode->op[1].val & 0xffffffe0)) / 32; + decode->op[0].ptr += 4 * displacement; + } else if (2 == decode->operand_size) { + displacement = ((int16_t) (decode->op[1].val & 0xfff0)) / 16; + decode->op[0].ptr += 2 * displacement; + } else { + VM_PANIC("bt 64bit\n"); + } + } + decode->op[0].val = read_val_ext(env, decode->op[0].ptr, + decode->operand_size); + cf = (decode->op[0].val >> index) & 0x01; + + switch (flag) { + case 0: + set_CF(env, cf); + return; + case 1: + decode->op[0].val ^= (1u << index); + break; + case 2: + decode->op[0].val |= (1u << index); + break; + case 3: + decode->op[0].val &= ~(1u << index); + break; + } + write_val_ext(env, decode->op[0].ptr, decode->op[0].val, + decode->operand_size); + set_CF(env, cf); +} + +static void exec_bt(struct CPUX86State *env, struct x86_decode *decode) +{ + do_bt(env, decode, 0); + RIP(env) += decode->len; +} + +static void exec_btc(struct CPUX86State *env, struct x86_decode *decode) +{ + do_bt(env, decode, 1); + RIP(env) += decode->len; +} + +static void exec_btr(struct CPUX86State *env, struct x86_decode *decode) +{ + do_bt(env, decode, 3); + RIP(env) += decode->len; +} + +static void exec_bts(struct CPUX86State *env, struct x86_decode *decode) +{ + do_bt(env, decode, 2); + RIP(env) += decode->len; +} + +void exec_shl(struct CPUX86State *env, struct x86_decode *decode) +{ + uint8_t count; + int of = 0, cf = 0; + + fetch_operands(env, decode, 2, true, true, false); + + count = decode->op[1].val; + count &= 0x1f; /* count is masked to 5 bits*/ + if (!count) { + goto exit; + } + + switch (decode->operand_size) { + case 1: + { + uint8_t res = 0; + if (count <= 8) { + res = (decode->op[0].val << count); + cf = (decode->op[0].val >> (8 - count)) & 0x1; + of = cf ^ (res >> 7); + } + + write_val_ext(env, decode->op[0].ptr, res, 1); + SET_FLAGS_OSZAPC_LOGIC_8(res); + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 2: + { + uint16_t res = 0; + + /* from bochs */ + if (count <= 16) { + res = (decode->op[0].val << count); + cf = (decode->op[0].val >> (16 - count)) & 0x1; + of = cf ^ (res >> 15); /* of = cf ^ result15 */ + } + + write_val_ext(env, decode->op[0].ptr, res, 2); + SET_FLAGS_OSZAPC_LOGIC_16(res); + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 4: + { + uint32_t res = decode->op[0].val << count; + + write_val_ext(env, decode->op[0].ptr, res, 4); + SET_FLAGS_OSZAPC_LOGIC_32(res); + cf = (decode->op[0].val >> (32 - count)) & 0x1; + of = cf ^ (res >> 31); /* of = cf ^ result31 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + default: + abort(); + } + +exit: + /* lflags_to_rflags(env); */ + RIP(env) += decode->len; +} + +void exec_movsx(CPUX86State *env, struct x86_decode *decode) +{ + int src_op_size; + int op_size = decode->operand_size; + + fetch_operands(env, decode, 2, false, false, false); + + if (0xbe == decode->opcode[1]) { + src_op_size = 1; + } else { + src_op_size = 2; + } + + decode->operand_size = src_op_size; + calc_modrm_operand(env, decode, &decode->op[1]); + decode->op[1].val = sign(read_val_ext(env, decode->op[1].ptr, src_op_size), + src_op_size); + + write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); + + RIP(env) += decode->len; +} + +void exec_ror(struct CPUX86State *env, struct x86_decode *decode) +{ + uint8_t count; + + fetch_operands(env, decode, 2, true, true, false); + count = decode->op[1].val; + + switch (decode->operand_size) { + case 1: + { + uint32_t bit6, bit7; + uint8_t res; + + if ((count & 0x07) == 0) { + if (count & 0x18) { + bit6 = ((uint8_t)decode->op[0].val >> 6) & 1; + bit7 = ((uint8_t)decode->op[0].val >> 7) & 1; + SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); + } + } else { + count &= 0x7; /* use only bottom 3 bits */ + res = ((uint8_t)decode->op[0].val >> count) | + ((uint8_t)decode->op[0].val << (8 - count)); + write_val_ext(env, decode->op[0].ptr, res, 1); + bit6 = (res >> 6) & 1; + bit7 = (res >> 7) & 1; + /* set eflags: ROR count affects the following flags: C, O */ + SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); + } + break; + } + case 2: + { + uint32_t bit14, bit15; + uint16_t res; + + if ((count & 0x0f) == 0) { + if (count & 0x10) { + bit14 = ((uint16_t)decode->op[0].val >> 14) & 1; + bit15 = ((uint16_t)decode->op[0].val >> 15) & 1; + /* of = result14 ^ result15 */ + SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); + } + } else { + count &= 0x0f; /* use only 4 LSB's */ + res = ((uint16_t)decode->op[0].val >> count) | + ((uint16_t)decode->op[0].val << (16 - count)); + write_val_ext(env, decode->op[0].ptr, res, 2); + + bit14 = (res >> 14) & 1; + bit15 = (res >> 15) & 1; + /* of = result14 ^ result15 */ + SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); + } + break; + } + case 4: + { + uint32_t bit31, bit30; + uint32_t res; + + count &= 0x1f; + if (count) { + res = ((uint32_t)decode->op[0].val >> count) | + ((uint32_t)decode->op[0].val << (32 - count)); + write_val_ext(env, decode->op[0].ptr, res, 4); + + bit31 = (res >> 31) & 1; + bit30 = (res >> 30) & 1; + /* of = result30 ^ result31 */ + SET_FLAGS_OxxxxC(env, bit30 ^ bit31, bit31); + } + break; + } + } + RIP(env) += decode->len; +} + +void exec_rol(struct CPUX86State *env, struct x86_decode *decode) +{ + uint8_t count; + + fetch_operands(env, decode, 2, true, true, false); + count = decode->op[1].val; + + switch (decode->operand_size) { + case 1: + { + uint32_t bit0, bit7; + uint8_t res; + + if ((count & 0x07) == 0) { + if (count & 0x18) { + bit0 = ((uint8_t)decode->op[0].val & 1); + bit7 = ((uint8_t)decode->op[0].val >> 7); + SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); + } + } else { + count &= 0x7; /* use only lowest 3 bits */ + res = ((uint8_t)decode->op[0].val << count) | + ((uint8_t)decode->op[0].val >> (8 - count)); + + write_val_ext(env, decode->op[0].ptr, res, 1); + /* set eflags: + * ROL count affects the following flags: C, O + */ + bit0 = (res & 1); + bit7 = (res >> 7); + SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); + } + break; + } + case 2: + { + uint32_t bit0, bit15; + uint16_t res; + + if ((count & 0x0f) == 0) { + if (count & 0x10) { + bit0 = ((uint16_t)decode->op[0].val & 0x1); + bit15 = ((uint16_t)decode->op[0].val >> 15); + /* of = cf ^ result15 */ + SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); + } + } else { + count &= 0x0f; /* only use bottom 4 bits */ + res = ((uint16_t)decode->op[0].val << count) | + ((uint16_t)decode->op[0].val >> (16 - count)); + + write_val_ext(env, decode->op[0].ptr, res, 2); + bit0 = (res & 0x1); + bit15 = (res >> 15); + /* of = cf ^ result15 */ + SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); + } + break; + } + case 4: + { + uint32_t bit0, bit31; + uint32_t res; + + count &= 0x1f; + if (count) { + res = ((uint32_t)decode->op[0].val << count) | + ((uint32_t)decode->op[0].val >> (32 - count)); + + write_val_ext(env, decode->op[0].ptr, res, 4); + bit0 = (res & 0x1); + bit31 = (res >> 31); + /* of = cf ^ result31 */ + SET_FLAGS_OxxxxC(env, bit0 ^ bit31, bit0); + } + break; + } + } + RIP(env) += decode->len; +} + + +void exec_rcl(struct CPUX86State *env, struct x86_decode *decode) +{ + uint8_t count; + int of = 0, cf = 0; + + fetch_operands(env, decode, 2, true, true, false); + count = decode->op[1].val & 0x1f; + + switch (decode->operand_size) { + case 1: + { + uint8_t op1_8 = decode->op[0].val; + uint8_t res; + count %= 9; + if (!count) { + break; + } + + if (1 == count) { + res = (op1_8 << 1) | get_CF(env); + } else { + res = (op1_8 << count) | (get_CF(env) << (count - 1)) | + (op1_8 >> (9 - count)); + } + + write_val_ext(env, decode->op[0].ptr, res, 1); + + cf = (op1_8 >> (8 - count)) & 0x01; + of = cf ^ (res >> 7); /* of = cf ^ result7 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 2: + { + uint16_t res; + uint16_t op1_16 = decode->op[0].val; + + count %= 17; + if (!count) { + break; + } + + if (1 == count) { + res = (op1_16 << 1) | get_CF(env); + } else if (count == 16) { + res = (get_CF(env) << 15) | (op1_16 >> 1); + } else { /* 2..15 */ + res = (op1_16 << count) | (get_CF(env) << (count - 1)) | + (op1_16 >> (17 - count)); + } + + write_val_ext(env, decode->op[0].ptr, res, 2); + + cf = (op1_16 >> (16 - count)) & 0x1; + of = cf ^ (res >> 15); /* of = cf ^ result15 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 4: + { + uint32_t res; + uint32_t op1_32 = decode->op[0].val; + + if (!count) { + break; + } + + if (1 == count) { + res = (op1_32 << 1) | get_CF(env); + } else { + res = (op1_32 << count) | (get_CF(env) << (count - 1)) | + (op1_32 >> (33 - count)); + } + + write_val_ext(env, decode->op[0].ptr, res, 4); + + cf = (op1_32 >> (32 - count)) & 0x1; + of = cf ^ (res >> 31); /* of = cf ^ result31 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + } + RIP(env) += decode->len; +} + +void exec_rcr(struct CPUX86State *env, struct x86_decode *decode) +{ + uint8_t count; + int of = 0, cf = 0; + + fetch_operands(env, decode, 2, true, true, false); + count = decode->op[1].val & 0x1f; + + switch (decode->operand_size) { + case 1: + { + uint8_t op1_8 = decode->op[0].val; + uint8_t res; + + count %= 9; + if (!count) { + break; + } + res = (op1_8 >> count) | (get_CF(env) << (8 - count)) | + (op1_8 << (9 - count)); + + write_val_ext(env, decode->op[0].ptr, res, 1); + + cf = (op1_8 >> (count - 1)) & 0x1; + of = (((res << 1) ^ res) >> 7) & 0x1; /* of = result6 ^ result7 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 2: + { + uint16_t op1_16 = decode->op[0].val; + uint16_t res; + + count %= 17; + if (!count) { + break; + } + res = (op1_16 >> count) | (get_CF(env) << (16 - count)) | + (op1_16 << (17 - count)); + + write_val_ext(env, decode->op[0].ptr, res, 2); + + cf = (op1_16 >> (count - 1)) & 0x1; + of = ((uint16_t)((res << 1) ^ res) >> 15) & 0x1; /* of = result15 ^ + result14 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + case 4: + { + uint32_t res; + uint32_t op1_32 = decode->op[0].val; + + if (!count) { + break; + } + + if (1 == count) { + res = (op1_32 >> 1) | (get_CF(env) << 31); + } else { + res = (op1_32 >> count) | (get_CF(env) << (32 - count)) | + (op1_32 << (33 - count)); + } + + write_val_ext(env, decode->op[0].ptr, res, 4); + + cf = (op1_32 >> (count - 1)) & 0x1; + of = ((res << 1) ^ res) >> 31; /* of = result30 ^ result31 */ + SET_FLAGS_OxxxxC(env, of, cf); + break; + } + } + RIP(env) += decode->len; +} + +static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) +{ + fetch_operands(env, decode, 2, true, true, false); + + write_val_ext(env, decode->op[0].ptr, decode->op[1].val, + decode->operand_size); + write_val_ext(env, decode->op[1].ptr, decode->op[0].val, + decode->operand_size); + + RIP(env) += decode->len; +} + +static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) +{ + EXEC_2OP_ARITH_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); + write_val_ext(env, decode->op[1].ptr, decode->op[0].val, + decode->operand_size); + + RIP(env) += decode->len; +} + +static struct cmd_handler { + enum x86_decode_cmd cmd; + void (*handler)(struct CPUX86State *env, struct x86_decode *ins); +} handlers[] = { + {X86_DECODE_CMD_INVL, NULL,}, + {X86_DECODE_CMD_MOV, exec_mov}, + {X86_DECODE_CMD_ADD, exec_add}, + {X86_DECODE_CMD_OR, exec_or}, + {X86_DECODE_CMD_ADC, exec_adc}, + {X86_DECODE_CMD_SBB, exec_sbb}, + {X86_DECODE_CMD_AND, exec_and}, + {X86_DECODE_CMD_SUB, exec_sub}, + {X86_DECODE_CMD_NEG, exec_neg}, + {X86_DECODE_CMD_XOR, exec_xor}, + {X86_DECODE_CMD_CMP, exec_cmp}, + {X86_DECODE_CMD_INC, exec_inc}, + {X86_DECODE_CMD_DEC, exec_dec}, + {X86_DECODE_CMD_TST, exec_tst}, + {X86_DECODE_CMD_NOT, exec_not}, + {X86_DECODE_CMD_MOVZX, exec_movzx}, + {X86_DECODE_CMD_OUT, exec_out}, + {X86_DECODE_CMD_IN, exec_in}, + {X86_DECODE_CMD_INS, exec_ins}, + {X86_DECODE_CMD_OUTS, exec_outs}, + {X86_DECODE_CMD_RDMSR, exec_rdmsr}, + {X86_DECODE_CMD_WRMSR, exec_wrmsr}, + {X86_DECODE_CMD_BT, exec_bt}, + {X86_DECODE_CMD_BTR, exec_btr}, + {X86_DECODE_CMD_BTC, exec_btc}, + {X86_DECODE_CMD_BTS, exec_bts}, + {X86_DECODE_CMD_SHL, exec_shl}, + {X86_DECODE_CMD_ROL, exec_rol}, + {X86_DECODE_CMD_ROR, exec_ror}, + {X86_DECODE_CMD_RCR, exec_rcr}, + {X86_DECODE_CMD_RCL, exec_rcl}, + /*{X86_DECODE_CMD_CPUID, exec_cpuid},*/ + {X86_DECODE_CMD_MOVS, exec_movs}, + {X86_DECODE_CMD_CMPS, exec_cmps}, + {X86_DECODE_CMD_STOS, exec_stos}, + {X86_DECODE_CMD_SCAS, exec_scas}, + {X86_DECODE_CMD_LODS, exec_lods}, + {X86_DECODE_CMD_MOVSX, exec_movsx}, + {X86_DECODE_CMD_XCHG, exec_xchg}, + {X86_DECODE_CMD_XADD, exec_xadd}, +}; + +static struct cmd_handler _cmd_handler[X86_DECODE_CMD_LAST]; + +static void init_cmd_handler() +{ + int i; + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + _cmd_handler[handlers[i].cmd] = handlers[i]; + } +} + +void load_regs(struct CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + int i = 0; + RRX(env, REG_RAX) = rreg(cpu->hvf_fd, HV_X86_RAX); + RRX(env, REG_RBX) = rreg(cpu->hvf_fd, HV_X86_RBX); + RRX(env, REG_RCX) = rreg(cpu->hvf_fd, HV_X86_RCX); + RRX(env, REG_RDX) = rreg(cpu->hvf_fd, HV_X86_RDX); + RRX(env, REG_RSI) = rreg(cpu->hvf_fd, HV_X86_RSI); + RRX(env, REG_RDI) = rreg(cpu->hvf_fd, HV_X86_RDI); + RRX(env, REG_RSP) = rreg(cpu->hvf_fd, HV_X86_RSP); + RRX(env, REG_RBP) = rreg(cpu->hvf_fd, HV_X86_RBP); + for (i = 8; i < 16; i++) { + RRX(env, i) = rreg(cpu->hvf_fd, HV_X86_RAX + i); + } + + RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); + rflags_to_lflags(env); + RIP(env) = rreg(cpu->hvf_fd, HV_X86_RIP); +} + +void store_regs(struct CPUState *cpu) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + int i = 0; + wreg(cpu->hvf_fd, HV_X86_RAX, RAX(env)); + wreg(cpu->hvf_fd, HV_X86_RBX, RBX(env)); + wreg(cpu->hvf_fd, HV_X86_RCX, RCX(env)); + wreg(cpu->hvf_fd, HV_X86_RDX, RDX(env)); + wreg(cpu->hvf_fd, HV_X86_RSI, RSI(env)); + wreg(cpu->hvf_fd, HV_X86_RDI, RDI(env)); + wreg(cpu->hvf_fd, HV_X86_RBP, RBP(env)); + wreg(cpu->hvf_fd, HV_X86_RSP, RSP(env)); + for (i = 8; i < 16; i++) { + wreg(cpu->hvf_fd, HV_X86_RAX + i, RRX(env, i)); + } + + lflags_to_rflags(env); + wreg(cpu->hvf_fd, HV_X86_RFLAGS, RFLAGS(env)); + macvm_set_rip(cpu, RIP(env)); +} + +bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins) +{ + /*if (hvf_vcpu_id(cpu)) + printf("%d, %llx: exec_instruction %s\n", hvf_vcpu_id(cpu), RIP(cpu), + decode_cmd_to_string(ins->cmd));*/ + + if (0 && ins->is_fpu) { + VM_PANIC("emulate fpu\n"); + } else { + if (!_cmd_handler[ins->cmd].handler) { + printf("Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), + ins->cmd, ins->opcode[0], + ins->opcode_len > 1 ? ins->opcode[1] : 0); + RIP(env) += ins->len; + return true; + } + + VM_PANIC_ON_EX(!_cmd_handler[ins->cmd].handler, + "Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), + ins->cmd, ins->opcode[0], + ins->opcode_len > 1 ? ins->opcode[1] : 0); + _cmd_handler[ins->cmd].handler(env, ins); + } + return true; +} + +void init_emu() +{ + init_cmd_handler(); +} diff --git a/target/i386/hvf-utils/x86_emu.h b/target/i386/hvf-utils/x86_emu.h new file mode 100644 index 0000000000..e1491a0935 --- /dev/null +++ b/target/i386/hvf-utils/x86_emu.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef __X86_EMU_H__ +#define __X86_EMU_H__ + +#include "x86.h" +#include "x86_decode.h" +#include "cpu.h" + +void init_emu(void); +bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins); + +void load_regs(struct CPUState *cpu); +void store_regs(struct CPUState *cpu); + +void simulate_rdmsr(struct CPUState *cpu); +void simulate_wrmsr(struct CPUState *cpu); + +addr_t read_reg(CPUX86State *env, int reg, int size); +void write_reg(CPUX86State *env, int reg, addr_t val, int size); +addr_t read_val_from_reg(addr_t reg_ptr, int size); +void write_val_to_reg(addr_t reg_ptr, addr_t val, int size); +void write_val_ext(struct CPUX86State *env, addr_t ptr, addr_t val, int size); +uint8_t *read_mmio(struct CPUX86State *env, addr_t ptr, int bytes); +addr_t read_val_ext(struct CPUX86State *env, addr_t ptr, int size); + +void exec_movzx(struct CPUX86State *env, struct x86_decode *decode); +void exec_shl(struct CPUX86State *env, struct x86_decode *decode); +void exec_movsx(struct CPUX86State *env, struct x86_decode *decode); +void exec_ror(struct CPUX86State *env, struct x86_decode *decode); +void exec_rol(struct CPUX86State *env, struct x86_decode *decode); +void exec_rcl(struct CPUX86State *env, struct x86_decode *decode); +void exec_rcr(struct CPUX86State *env, struct x86_decode *decode); +#endif diff --git a/target/i386/hvf-utils/x86_flags.c b/target/i386/hvf-utils/x86_flags.c new file mode 100644 index 0000000000..c833774485 --- /dev/null +++ b/target/i386/hvf-utils/x86_flags.c @@ -0,0 +1,333 @@ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2012 The Bochs Project +// Copyright (C) 2017 Google Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA +///////////////////////////////////////////////////////////////////////// +/* + * flags functions + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "cpu.h" +#include "x86_flags.h" +#include "x86.h" + +void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf) +{ + uint32_t temp_po = new_of ^ new_cf; + env->hvf_emul->lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF); + env->hvf_emul->lflags.auxbits |= (temp_po << LF_BIT_PO) | + (new_cf << LF_BIT_CF); +} + +void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff) +{ + SET_FLAGS_OSZAPC_SUB_32(v1, v2, diff); +} + +void SET_FLAGS_OSZAPC_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff) +{ + SET_FLAGS_OSZAPC_SUB_16(v1, v2, diff); +} + +void SET_FLAGS_OSZAPC_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff) +{ + SET_FLAGS_OSZAPC_SUB_8(v1, v2, diff); +} + +void SET_FLAGS_OSZAPC_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff) +{ + SET_FLAGS_OSZAPC_ADD_32(v1, v2, diff); +} + +void SET_FLAGS_OSZAPC_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff) +{ + SET_FLAGS_OSZAPC_ADD_16(v1, v2, diff); +} + +void SET_FLAGS_OSZAPC_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff) +{ + SET_FLAGS_OSZAPC_ADD_8(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff) +{ + SET_FLAGS_OSZAP_SUB_32(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff) +{ + SET_FLAGS_OSZAP_SUB_16(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff) +{ + SET_FLAGS_OSZAP_SUB_8(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff) +{ + SET_FLAGS_OSZAP_ADD_32(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff) +{ + SET_FLAGS_OSZAP_ADD_16(v1, v2, diff); +} + +void SET_FLAGS_OSZAP_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff) +{ + SET_FLAGS_OSZAP_ADD_8(v1, v2, diff); +} + + +void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t diff) +{ + SET_FLAGS_OSZAPC_LOGIC_32(diff); +} + +void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t diff) +{ + SET_FLAGS_OSZAPC_LOGIC_16(diff); +} + +void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t diff) +{ + SET_FLAGS_OSZAPC_LOGIC_8(diff); +} + +void SET_FLAGS_SHR32(CPUX86State *env, uint32_t v, int count, uint32_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + int of = (((res << 1) ^ res) >> 31); + + SET_FLAGS_OSZAPC_LOGIC_32(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +void SET_FLAGS_SHR16(CPUX86State *env, uint16_t v, int count, uint16_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + int of = (((res << 1) ^ res) >> 15); + + SET_FLAGS_OSZAPC_LOGIC_16(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +void SET_FLAGS_SHR8(CPUX86State *env, uint8_t v, int count, uint8_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + int of = (((res << 1) ^ res) >> 7); + + SET_FLAGS_OSZAPC_LOGIC_8(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +void SET_FLAGS_SAR32(CPUX86State *env, int32_t v, int count, uint32_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + + SET_FLAGS_OSZAPC_LOGIC_32(res); + SET_FLAGS_OxxxxC(env, 0, cf); +} + +void SET_FLAGS_SAR16(CPUX86State *env, int16_t v, int count, uint16_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + + SET_FLAGS_OSZAPC_LOGIC_16(res); + SET_FLAGS_OxxxxC(env, 0, cf); +} + +void SET_FLAGS_SAR8(CPUX86State *env, int8_t v, int count, uint8_t res) +{ + int cf = (v >> (count - 1)) & 0x1; + + SET_FLAGS_OSZAPC_LOGIC_8(res); + SET_FLAGS_OxxxxC(env, 0, cf); +} + + +void SET_FLAGS_SHL32(CPUX86State *env, uint32_t v, int count, uint32_t res) +{ + int of, cf; + + cf = (v >> (32 - count)) & 0x1; + of = cf ^ (res >> 31); + + SET_FLAGS_OSZAPC_LOGIC_32(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +void SET_FLAGS_SHL16(CPUX86State *env, uint16_t v, int count, uint16_t res) +{ + int of = 0, cf = 0; + + if (count <= 16) { + cf = (v >> (16 - count)) & 0x1; + of = cf ^ (res >> 15); + } + + SET_FLAGS_OSZAPC_LOGIC_16(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +void SET_FLAGS_SHL8(CPUX86State *env, uint8_t v, int count, uint8_t res) +{ + int of = 0, cf = 0; + + if (count <= 8) { + cf = (v >> (8 - count)) & 0x1; + of = cf ^ (res >> 7); + } + + SET_FLAGS_OSZAPC_LOGIC_8(res); + SET_FLAGS_OxxxxC(env, of, cf); +} + +bool get_PF(CPUX86State *env) +{ + uint32_t temp = (255 & env->hvf_emul->lflags.result); + temp = temp ^ (255 & (env->hvf_emul->lflags.auxbits >> LF_BIT_PDB)); + temp = (temp ^ (temp >> 4)) & 0x0F; + return (0x9669U >> temp) & 1; +} + +void set_PF(CPUX86State *env, bool val) +{ + uint32_t temp = (255 & env->hvf_emul->lflags.result) ^ (!val); + env->hvf_emul->lflags.auxbits &= ~(LF_MASK_PDB); + env->hvf_emul->lflags.auxbits |= (temp << LF_BIT_PDB); +} + +bool _get_OF(CPUX86State *env) +{ + return ((env->hvf_emul->lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; +} + +bool get_OF(CPUX86State *env) +{ + return _get_OF(env); +} + +bool _get_CF(CPUX86State *env) +{ + return (env->hvf_emul->lflags.auxbits >> LF_BIT_CF) & 1; +} + +bool get_CF(CPUX86State *env) +{ + return _get_CF(env); +} + +void set_OF(CPUX86State *env, bool val) +{ + SET_FLAGS_OxxxxC(env, val, _get_CF(env)); +} + +void set_CF(CPUX86State *env, bool val) +{ + SET_FLAGS_OxxxxC(env, _get_OF(env), (val)); +} + +bool get_AF(CPUX86State *env) +{ + return (env->hvf_emul->lflags.auxbits >> LF_BIT_AF) & 1; +} + +void set_AF(CPUX86State *env, bool val) +{ + env->hvf_emul->lflags.auxbits &= ~(LF_MASK_AF); + env->hvf_emul->lflags.auxbits |= (val) << LF_BIT_AF; +} + +bool get_ZF(CPUX86State *env) +{ + return !env->hvf_emul->lflags.result; +} + +void set_ZF(CPUX86State *env, bool val) +{ + if (val) { + env->hvf_emul->lflags.auxbits ^= + (((env->hvf_emul->lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD); + /* merge the parity bits into the Parity Delta Byte */ + uint32_t temp_pdb = (255 & env->hvf_emul->lflags.result); + env->hvf_emul->lflags.auxbits ^= (temp_pdb << LF_BIT_PDB); + /* now zero the .result value */ + env->hvf_emul->lflags.result = 0; + } else { + env->hvf_emul->lflags.result |= (1 << 8); + } +} + +bool get_SF(CPUX86State *env) +{ + return ((env->hvf_emul->lflags.result >> LF_SIGN_BIT) ^ + (env->hvf_emul->lflags.auxbits >> LF_BIT_SD)) & 1; +} + +void set_SF(CPUX86State *env, bool val) +{ + bool temp_sf = get_SF(env); + env->hvf_emul->lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; +} + +void set_OSZAPC(CPUX86State *env, uint32_t flags32) +{ + set_OF(env, env->hvf_emul->rflags.of); + set_SF(env, env->hvf_emul->rflags.sf); + set_ZF(env, env->hvf_emul->rflags.zf); + set_AF(env, env->hvf_emul->rflags.af); + set_PF(env, env->hvf_emul->rflags.pf); + set_CF(env, env->hvf_emul->rflags.cf); +} + +void lflags_to_rflags(CPUX86State *env) +{ + env->hvf_emul->rflags.cf = get_CF(env); + env->hvf_emul->rflags.pf = get_PF(env); + env->hvf_emul->rflags.af = get_AF(env); + env->hvf_emul->rflags.zf = get_ZF(env); + env->hvf_emul->rflags.sf = get_SF(env); + env->hvf_emul->rflags.of = get_OF(env); +} + +void rflags_to_lflags(CPUX86State *env) +{ + env->hvf_emul->lflags.auxbits = env->hvf_emul->lflags.result = 0; + set_OF(env, env->hvf_emul->rflags.of); + set_SF(env, env->hvf_emul->rflags.sf); + set_ZF(env, env->hvf_emul->rflags.zf); + set_AF(env, env->hvf_emul->rflags.af); + set_PF(env, env->hvf_emul->rflags.pf); + set_CF(env, env->hvf_emul->rflags.cf); +} diff --git a/target/i386/hvf-utils/x86_flags.h b/target/i386/hvf-utils/x86_flags.h new file mode 100644 index 0000000000..57a524240c --- /dev/null +++ b/target/i386/hvf-utils/x86_flags.h @@ -0,0 +1,243 @@ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2001-2012 The Bochs Project +// Copyright (C) 2017 Google Inc. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA +///////////////////////////////////////////////////////////////////////// +/* + * x86 eflags functions + */ +#ifndef __X86_FLAGS_H__ +#define __X86_FLAGS_H__ + +#include "x86_gen.h" +#include "cpu.h" + +/* this is basically bocsh code */ + +#define LF_SIGN_BIT 31 + +#define LF_BIT_SD (0) /* lazy Sign Flag Delta */ +#define LF_BIT_AF (3) /* lazy Adjust flag */ +#define LF_BIT_PDB (8) /* lazy Parity Delta Byte (8 bits) */ +#define LF_BIT_CF (31) /* lazy Carry Flag */ +#define LF_BIT_PO (30) /* lazy Partial Overflow = CF ^ OF */ + +#define LF_MASK_SD (0x01 << LF_BIT_SD) +#define LF_MASK_AF (0x01 << LF_BIT_AF) +#define LF_MASK_PDB (0xFF << LF_BIT_PDB) +#define LF_MASK_CF (0x01 << LF_BIT_CF) +#define LF_MASK_PO (0x01 << LF_BIT_PO) + +#define ADD_COUT_VEC(op1, op2, result) \ + (((op1) & (op2)) | (((op1) | (op2)) & (~(result)))) + +#define SUB_COUT_VEC(op1, op2, result) \ + (((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result))) + +#define GET_ADD_OVERFLOW(op1, op2, result, mask) \ + ((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) + +/* ******************* */ +/* OSZAPC */ +/* ******************* */ + +/* size, carries, result */ +#define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ + addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ + env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ + if ((size) == 32) { \ + temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ + } else if ((size) == 16) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ + } else if ((size) == 8) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ + } else { \ + VM_PANIC("unimplemented"); \ + } \ + env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)temp; \ +} + +/* carries, result */ +#define SET_FLAGS_OSZAPC_8(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(8, carries, result) +#define SET_FLAGS_OSZAPC_16(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(16, carries, result) +#define SET_FLAGS_OSZAPC_32(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(32, carries, result) + +/* result */ +#define SET_FLAGS_OSZAPC_LOGIC_8(result_8) \ + SET_FLAGS_OSZAPC_8(0, (result_8)) +#define SET_FLAGS_OSZAPC_LOGIC_16(result_16) \ + SET_FLAGS_OSZAPC_16(0, (result_16)) +#define SET_FLAGS_OSZAPC_LOGIC_32(result_32) \ + SET_FLAGS_OSZAPC_32(0, (result_32)) +#define SET_FLAGS_OSZAPC_LOGIC_SIZE(size, result) { \ + if (32 == size) { \ + SET_FLAGS_OSZAPC_LOGIC_32(result); \ + } else if (16 == size) { \ + SET_FLAGS_OSZAPC_LOGIC_16(result); \ + } else if (8 == size) { \ + SET_FLAGS_OSZAPC_LOGIC_8(result); \ + } else { \ + VM_PANIC("unimplemented"); \ + } \ +} + +/* op1, op2, result */ +#define SET_FLAGS_OSZAPC_ADD_8(op1_8, op2_8, sum_8) \ + SET_FLAGS_OSZAPC_8(ADD_COUT_VEC((op1_8), (op2_8), (sum_8)), (sum_8)) +#define SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16) \ + SET_FLAGS_OSZAPC_16(ADD_COUT_VEC((op1_16), (op2_16), (sum_16)), (sum_16)) +#define SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32) \ + SET_FLAGS_OSZAPC_32(ADD_COUT_VEC((op1_32), (op2_32), (sum_32)), (sum_32)) + +/* op1, op2, result */ +#define SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8) \ + SET_FLAGS_OSZAPC_8(SUB_COUT_VEC((op1_8), (op2_8), (diff_8)), (diff_8)) +#define SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16) \ + SET_FLAGS_OSZAPC_16(SUB_COUT_VEC((op1_16), (op2_16), (diff_16)), (diff_16)) +#define SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32) \ + SET_FLAGS_OSZAPC_32(SUB_COUT_VEC((op1_32), (op2_32), (diff_32)), (diff_32)) + +/* ******************* */ +/* OSZAP */ +/* ******************* */ +/* size, carries, result */ +#define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \ + addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ + if ((size) == 32) { \ + temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ + } else if ((size) == 16) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ + } else if ((size) == 8) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ + } else { \ + VM_PANIC("unimplemented"); \ + } \ + env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ + addr_t delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ + delta_c ^= (delta_c >> 1); \ + env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)(temp ^ delta_c); \ +} + +/* carries, result */ +#define SET_FLAGS_OSZAP_8(carries, result) \ + SET_FLAGS_OSZAP_SIZE(8, carries, result) +#define SET_FLAGS_OSZAP_16(carries, result) \ + SET_FLAGS_OSZAP_SIZE(16, carries, result) +#define SET_FLAGS_OSZAP_32(carries, result) \ + SET_FLAGS_OSZAP_SIZE(32, carries, result) + +/* op1, op2, result */ +#define SET_FLAGS_OSZAP_ADD_8(op1_8, op2_8, sum_8) \ + SET_FLAGS_OSZAP_8(ADD_COUT_VEC((op1_8), (op2_8), (sum_8)), (sum_8)) +#define SET_FLAGS_OSZAP_ADD_16(op1_16, op2_16, sum_16) \ + SET_FLAGS_OSZAP_16(ADD_COUT_VEC((op1_16), (op2_16), (sum_16)), (sum_16)) +#define SET_FLAGS_OSZAP_ADD_32(op1_32, op2_32, sum_32) \ + SET_FLAGS_OSZAP_32(ADD_COUT_VEC((op1_32), (op2_32), (sum_32)), (sum_32)) + +/* op1, op2, result */ +#define SET_FLAGS_OSZAP_SUB_8(op1_8, op2_8, diff_8) \ + SET_FLAGS_OSZAP_8(SUB_COUT_VEC((op1_8), (op2_8), (diff_8)), (diff_8)) +#define SET_FLAGS_OSZAP_SUB_16(op1_16, op2_16, diff_16) \ + SET_FLAGS_OSZAP_16(SUB_COUT_VEC((op1_16), (op2_16), (diff_16)), (diff_16)) +#define SET_FLAGS_OSZAP_SUB_32(op1_32, op2_32, diff_32) \ + SET_FLAGS_OSZAP_32(SUB_COUT_VEC((op1_32), (op2_32), (diff_32)), (diff_32)) + +/* ******************* */ +/* OSZAxC */ +/* ******************* */ +/* size, carries, result */ +#define SET_FLAGS_OSZAxC_LOGIC_SIZE(size, lf_result) { \ + bool saved_PF = getB_PF(); \ + SET_FLAGS_OSZAPC_SIZE(size, (int##size##_t)(0), lf_result); \ + set_PF(saved_PF); \ +} + +/* result */ +#define SET_FLAGS_OSZAxC_LOGIC_32(result_32) \ + SET_FLAGS_OSZAxC_LOGIC_SIZE(32, (result_32)) + +void lflags_to_rflags(CPUX86State *env); +void rflags_to_lflags(CPUX86State *env); + +bool get_PF(CPUX86State *env); +void set_PF(CPUX86State *env, bool val); +bool get_CF(CPUX86State *env); +void set_CF(CPUX86State *env, bool val); +bool get_AF(CPUX86State *env); +void set_AF(CPUX86State *env, bool val); +bool get_ZF(CPUX86State *env); +void set_ZF(CPUX86State *env, bool val); +bool get_SF(CPUX86State *env); +void set_SF(CPUX86State *env, bool val); +bool get_OF(CPUX86State *env); +void set_OF(CPUX86State *env, bool val); +void set_OSZAPC(CPUX86State *env, uint32_t flags32); + +void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf); + +void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff); +void SET_FLAGS_OSZAPC_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff); +void SET_FLAGS_OSZAPC_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff); + +void SET_FLAGS_OSZAPC_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff); +void SET_FLAGS_OSZAPC_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff); +void SET_FLAGS_OSZAPC_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff); + +void SET_FLAGS_OSZAP_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff); +void SET_FLAGS_OSZAP_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff); +void SET_FLAGS_OSZAP_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff); + +void SET_FLAGS_OSZAP_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff); +void SET_FLAGS_OSZAP_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff); +void SET_FLAGS_OSZAP_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff); + +void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t diff); +void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t diff); +void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t diff); + +void SET_FLAGS_SHR32(CPUX86State *env, uint32_t v, int count, uint32_t res); +void SET_FLAGS_SHR16(CPUX86State *env, uint16_t v, int count, uint16_t res); +void SET_FLAGS_SHR8(CPUX86State *env, uint8_t v, int count, uint8_t res); + +void SET_FLAGS_SAR32(CPUX86State *env, int32_t v, int count, uint32_t res); +void SET_FLAGS_SAR16(CPUX86State *env, int16_t v, int count, uint16_t res); +void SET_FLAGS_SAR8(CPUX86State *env, int8_t v, int count, uint8_t res); + +void SET_FLAGS_SHL32(CPUX86State *env, uint32_t v, int count, uint32_t res); +void SET_FLAGS_SHL16(CPUX86State *env, uint16_t v, int count, uint16_t res); +void SET_FLAGS_SHL8(CPUX86State *env, uint8_t v, int count, uint8_t res); + +bool _get_OF(CPUX86State *env); +bool _get_CF(CPUX86State *env); +#endif /* __X86_FLAGS_H__ */ diff --git a/target/i386/hvf-utils/x86_gen.h b/target/i386/hvf-utils/x86_gen.h new file mode 100644 index 0000000000..e4340fa244 --- /dev/null +++ b/target/i386/hvf-utils/x86_gen.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef __X86_GEN_H__ +#define __X86_GEN_H__ + +#include +#include +#include "qemu-common.h" + +typedef uint64_t addr_t; + +#define VM_PANIC(x) {\ + printf("%s\n", x); \ + abort(); \ +} + +#define VM_PANIC_ON(x) {\ + if (x) { \ + printf("%s\n", #x); \ + abort(); \ + } \ +} + +#define VM_PANIC_EX(...) {\ + printf(__VA_ARGS__); \ + abort(); \ +} + +#define VM_PANIC_ON_EX(x, ...) {\ + if (x) { \ + printf(__VA_ARGS__); \ + abort(); \ + } \ +} + +#define ZERO_INIT(obj) memset((void *) &obj, 0, sizeof(obj)) + +#endif diff --git a/target/i386/hvf-utils/x86_mmu.c b/target/i386/hvf-utils/x86_mmu.c new file mode 100644 index 0000000000..4bb1664104 --- /dev/null +++ b/target/i386/hvf-utils/x86_mmu.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#include "qemu/osdep.h" + +#include "qemu-common.h" +#include "x86.h" +#include "x86_mmu.h" +#include "string.h" +#include "vmcs.h" +#include "vmx.h" + +#include "memory.h" +#include "exec/address-spaces.h" + +#define pte_present(pte) (pte & PT_PRESENT) +#define pte_write_access(pte) (pte & PT_WRITE) +#define pte_user_access(pte) (pte & PT_USER) +#define pte_exec_access(pte) (!(pte & PT_NX)) + +#define pte_large_page(pte) (pte & PT_PS) +#define pte_global_access(pte) (pte & PT_GLOBAL) + +#define PAE_CR3_MASK (~0x1fllu) +#define LEGACY_CR3_MASK (0xffffffff) + +#define LEGACY_PTE_PAGE_MASK (0xffffffffllu << 12) +#define PAE_PTE_PAGE_MASK ((-1llu << 12) & ((1llu << 52) - 1)) +#define PAE_PTE_LARGE_PAGE_MASK ((-1llu << (21)) & ((1llu << 52) - 1)) + +struct gpt_translation { + addr_t gva; + addr_t gpa; + int err_code; + uint64_t pte[5]; + bool write_access; + bool user_access; + bool exec_access; +}; + +static int gpt_top_level(struct CPUState *cpu, bool pae) +{ + if (!pae) { + return 2; + } + if (x86_is_long_mode(cpu)) { + return 4; + } + + return 3; +} + +static inline int gpt_entry(addr_t addr, int level, bool pae) +{ + int level_shift = pae ? 9 : 10; + return (addr >> (level_shift * (level - 1) + 12)) & ((1 << level_shift) - 1); +} + +static inline int pte_size(bool pae) +{ + return pae ? 8 : 4; +} + + +static bool get_pt_entry(struct CPUState *cpu, struct gpt_translation *pt, + int level, bool pae) +{ + int index; + uint64_t pte = 0; + addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; + addr_t gpa = pt->pte[level] & page_mask; + + if (level == 3 && !x86_is_long_mode(cpu)) { + gpa = pt->pte[level]; + } + + index = gpt_entry(pt->gva, level, pae); + address_space_rw(&address_space_memory, gpa + index * pte_size(pae), + MEMTXATTRS_UNSPECIFIED, (uint8_t *)&pte, pte_size(pae), 0); + + pt->pte[level - 1] = pte; + + return true; +} + +/* test page table entry */ +static bool test_pt_entry(struct CPUState *cpu, struct gpt_translation *pt, + int level, bool *is_large, bool pae) +{ + uint64_t pte = pt->pte[level]; + + if (pt->write_access) { + pt->err_code |= MMU_PAGE_WT; + } + if (pt->user_access) { + pt->err_code |= MMU_PAGE_US; + } + if (pt->exec_access) { + pt->err_code |= MMU_PAGE_NX; + } + + if (!pte_present(pte)) { + /* addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; */ + return false; + } + + if (pae && !x86_is_long_mode(cpu) && 2 == level) { + goto exit; + } + + if (1 == level && pte_large_page(pte)) { + pt->err_code |= MMU_PAGE_PT; + *is_large = true; + } + if (!level) { + pt->err_code |= MMU_PAGE_PT; + } + + addr_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0); + /* check protection */ + if (cr0 & CR0_WP) { + if (pt->write_access && !pte_write_access(pte)) { + return false; + } + } + + if (pt->user_access && !pte_user_access(pte)) { + return false; + } + + if (pae && pt->exec_access && !pte_exec_access(pte)) { + return false; + } + +exit: + /* TODO: check reserved bits */ + return true; +} + +static inline uint64_t pse_pte_to_page(uint64_t pte) +{ + return ((pte & 0x1fe000) << 19) | (pte & 0xffc00000); +} + +static inline uint64_t large_page_gpa(struct gpt_translation *pt, bool pae) +{ + VM_PANIC_ON(!pte_large_page(pt->pte[1])) + /* 2Mb large page */ + if (pae) { + return (pt->pte[1] & PAE_PTE_LARGE_PAGE_MASK) | (pt->gva & 0x1fffff); + } + + /* 4Mb large page */ + return pse_pte_to_page(pt->pte[1]) | (pt->gva & 0x3fffff); +} + + + +static bool walk_gpt(struct CPUState *cpu, addr_t addr, int err_code, + struct gpt_translation *pt, bool pae) +{ + int top_level, level; + bool is_large = false; + addr_t cr3 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR3); + addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; + + memset(pt, 0, sizeof(*pt)); + top_level = gpt_top_level(cpu, pae); + + pt->pte[top_level] = pae ? (cr3 & PAE_CR3_MASK) : (cr3 & LEGACY_CR3_MASK); + pt->gva = addr; + pt->user_access = (err_code & MMU_PAGE_US); + pt->write_access = (err_code & MMU_PAGE_WT); + pt->exec_access = (err_code & MMU_PAGE_NX); + + for (level = top_level; level > 0; level--) { + get_pt_entry(cpu, pt, level, pae); + + if (!test_pt_entry(cpu, pt, level - 1, &is_large, pae)) { + return false; + } + + if (is_large) { + break; + } + } + + if (!is_large) { + pt->gpa = (pt->pte[0] & page_mask) | (pt->gva & 0xfff); + } else { + pt->gpa = large_page_gpa(pt, pae); + } + + return true; +} + + +bool mmu_gva_to_gpa(struct CPUState *cpu, addr_t gva, addr_t *gpa) +{ + bool res; + struct gpt_translation pt; + int err_code = 0; + + if (!x86_is_paging_mode(cpu)) { + *gpa = gva; + return true; + } + + res = walk_gpt(cpu, gva, err_code, &pt, x86_is_pae_enabled(cpu)); + if (res) { + *gpa = pt.gpa; + return true; + } + + return false; +} + +void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes) +{ + addr_t gpa; + + while (bytes > 0) { + /* copy page */ + int copy = MIN(bytes, 0x1000 - (gva & 0xfff)); + + if (!mmu_gva_to_gpa(cpu, gva, &gpa)) { + VM_PANIC_ON_EX(1, "%s: mmu_gva_to_gpa %llx failed\n", __func__, + gva); + } else { + address_space_rw(&address_space_memory, gpa, MEMTXATTRS_UNSPECIFIED, + data, copy, 1); + } + + bytes -= copy; + gva += copy; + data += copy; + } +} + +void vmx_read_mem(struct CPUState *cpu, void *data, addr_t gva, int bytes) +{ + addr_t gpa; + + while (bytes > 0) { + /* copy page */ + int copy = MIN(bytes, 0x1000 - (gva & 0xfff)); + + if (!mmu_gva_to_gpa(cpu, gva, &gpa)) { + VM_PANIC_ON_EX(1, "%s: mmu_gva_to_gpa %llx failed\n", __func__, + gva); + } + address_space_rw(&address_space_memory, gpa, MEMTXATTRS_UNSPECIFIED, + data, copy, 0); + + bytes -= copy; + gva += copy; + data += copy; + } +} diff --git a/target/i386/hvf-utils/x86_mmu.h b/target/i386/hvf-utils/x86_mmu.h new file mode 100644 index 0000000000..4fce48c18f --- /dev/null +++ b/target/i386/hvf-utils/x86_mmu.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef __X86_MMU_H__ +#define __X86_MMU_H__ + +#include "x86_gen.h" + +#define PT_PRESENT (1 << 0) +#define PT_WRITE (1 << 1) +#define PT_USER (1 << 2) +#define PT_WT (1 << 3) +#define PT_CD (1 << 4) +#define PT_ACCESSED (1 << 5) +#define PT_DIRTY (1 << 6) +#define PT_PS (1 << 7) +#define PT_GLOBAL (1 << 8) +#define PT_NX (1llu << 63) + +/* error codes */ +#define MMU_PAGE_PT (1 << 0) +#define MMU_PAGE_WT (1 << 1) +#define MMU_PAGE_US (1 << 2) +#define MMU_PAGE_NX (1 << 3) + +bool mmu_gva_to_gpa(struct CPUState *cpu, addr_t gva, addr_t *gpa); + +void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes); +void vmx_read_mem(struct CPUState *cpu, void *data, addr_t gva, int bytes); + +#endif /* __X86_MMU_H__ */ diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf-utils/x86hvf.c new file mode 100644 index 0000000000..1d9ab08cbe --- /dev/null +++ b/target/i386/hvf-utils/x86hvf.c @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" + +#include "x86hvf.h" +#include "vmx.h" +#include "vmcs.h" +#include "cpu.h" +#include "x86_descr.h" +#include "x86_decode.h" + +#include "hw/i386/apic_internal.h" + +#include +#include +#include +#include +#include + +void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg, + SegmentCache *qseg, bool is_tr) +{ + vmx_seg->sel = qseg->selector; + vmx_seg->base = qseg->base; + vmx_seg->limit = qseg->limit; + + if (!qseg->selector && !x86_is_real(cpu) && !is_tr) { + /* the TR register is usable after processor reset despite + * having a null selector */ + vmx_seg->ar = 1 << 16; + return; + } + vmx_seg->ar = (qseg->flags >> DESC_TYPE_SHIFT) & 0xf; + vmx_seg->ar |= ((qseg->flags >> DESC_G_SHIFT) & 1) << 15; + vmx_seg->ar |= ((qseg->flags >> DESC_B_SHIFT) & 1) << 14; + vmx_seg->ar |= ((qseg->flags >> DESC_L_SHIFT) & 1) << 13; + vmx_seg->ar |= ((qseg->flags >> DESC_AVL_SHIFT) & 1) << 12; + vmx_seg->ar |= ((qseg->flags >> DESC_P_SHIFT) & 1) << 7; + vmx_seg->ar |= ((qseg->flags >> DESC_DPL_SHIFT) & 3) << 5; + vmx_seg->ar |= ((qseg->flags >> DESC_S_SHIFT) & 1) << 4; +} + +void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg) +{ + qseg->limit = vmx_seg->limit; + qseg->base = vmx_seg->base; + qseg->selector = vmx_seg->sel; + qseg->flags = ((vmx_seg->ar & 0xf) << DESC_TYPE_SHIFT) | + (((vmx_seg->ar >> 4) & 1) << DESC_S_SHIFT) | + (((vmx_seg->ar >> 5) & 3) << DESC_DPL_SHIFT) | + (((vmx_seg->ar >> 7) & 1) << DESC_P_SHIFT) | + (((vmx_seg->ar >> 12) & 1) << DESC_AVL_SHIFT) | + (((vmx_seg->ar >> 13) & 1) << DESC_L_SHIFT) | + (((vmx_seg->ar >> 14) & 1) << DESC_B_SHIFT) | + (((vmx_seg->ar >> 15) & 1) << DESC_G_SHIFT); +} + +void hvf_put_xsave(CPUState *cpu_state) +{ + + int x; + struct hvf_xsave_buf *xsave; + + xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; + memset(xsave, 0, sizeof(*xsave)); + + memcpy(&xsave->data[4], &X86_CPU(cpu_state)->env.fpdp, sizeof(X86_CPU(cpu_state)->env.fpdp)); + memcpy(&xsave->data[2], &X86_CPU(cpu_state)->env.fpip, sizeof(X86_CPU(cpu_state)->env.fpip)); + memcpy(&xsave->data[8], &X86_CPU(cpu_state)->env.fpregs, sizeof(X86_CPU(cpu_state)->env.fpregs)); + memcpy(&xsave->data[144], &X86_CPU(cpu_state)->env.ymmh_regs, sizeof(X86_CPU(cpu_state)->env.ymmh_regs)); + memcpy(&xsave->data[288], &X86_CPU(cpu_state)->env.zmmh_regs, sizeof(X86_CPU(cpu_state)->env.zmmh_regs)); + memcpy(&xsave->data[272], &X86_CPU(cpu_state)->env.opmask_regs, sizeof(X86_CPU(cpu_state)->env.opmask_regs)); + memcpy(&xsave->data[240], &X86_CPU(cpu_state)->env.bnd_regs, sizeof(X86_CPU(cpu_state)->env.bnd_regs)); + memcpy(&xsave->data[256], &X86_CPU(cpu_state)->env.bndcs_regs, sizeof(X86_CPU(cpu_state)->env.bndcs_regs)); + memcpy(&xsave->data[416], &X86_CPU(cpu_state)->env.hi16_zmm_regs, sizeof(X86_CPU(cpu_state)->env.hi16_zmm_regs)); + + xsave->data[0] = (uint16_t)X86_CPU(cpu_state)->env.fpuc; + xsave->data[0] |= (X86_CPU(cpu_state)->env.fpus << 16); + xsave->data[0] |= (X86_CPU(cpu_state)->env.fpstt & 7) << 11; + + for (x = 0; x < 8; ++x) + xsave->data[1] |= ((!X86_CPU(cpu_state)->env.fptags[x]) << x); + xsave->data[1] |= (uint32_t)(X86_CPU(cpu_state)->env.fpop << 16); + + memcpy(&xsave->data[40], &X86_CPU(cpu_state)->env.xmm_regs, sizeof(X86_CPU(cpu_state)->env.xmm_regs)); + + xsave->data[6] = X86_CPU(cpu_state)->env.mxcsr; + *(uint64_t *)&xsave->data[128] = X86_CPU(cpu_state)->env.xstate_bv; + + if (hv_vcpu_write_fpstate(cpu_state->hvf_fd, xsave->data, 4096)){ + abort(); + } +} + +void hvf_put_segments(CPUState *cpu_state) +{ + CPUX86State *env = &X86_CPU(cpu_state)->env; + struct vmx_segment seg; + + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_LIMIT, env->idt.limit); + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_BASE, env->idt.base); + + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_LIMIT, env->gdt.limit); + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_BASE, env->gdt.base); + + /* wvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR2, env->cr[2]); */ + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR3, env->cr[3]); + vmx_update_tpr(cpu_state); + wvmcs(cpu_state->hvf_fd, VMCS_GUEST_IA32_EFER, env->efer); + + macvm_set_cr4(cpu_state->hvf_fd, env->cr[4]); + macvm_set_cr0(cpu_state->hvf_fd, env->cr[0]); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_CS], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_CS); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_DS], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_DS); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_ES], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_ES); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_SS], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_SS); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_FS], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_FS); + + hvf_set_segment(cpu_state, &seg, &env->segs[R_GS], false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_GS); + + hvf_set_segment(cpu_state, &seg, &env->tr, true); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_TR); + + hvf_set_segment(cpu_state, &seg, &env->ldt, false); + vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); + + hv_vcpu_flush(cpu_state->hvf_fd); +} + +void hvf_put_msrs(CPUState *cpu_state) +{ + CPUX86State *env = &X86_CPU(cpu_state)->env; + + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_CS, + env->sysenter_cs); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_ESP, + env->sysenter_esp); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_EIP, + env->sysenter_eip); + + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_STAR, env->star); + +#ifdef TARGET_X86_64 + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_CSTAR, env->cstar); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_KERNELGSBASE, env->kernelgsbase); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_FMASK, env->fmask); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_LSTAR, env->lstar); +#endif + + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_GSBASE, env->segs[R_GS].base); + hv_vcpu_write_msr(cpu_state->hvf_fd, MSR_FSBASE, env->segs[R_FS].base); + + /* if (!osx_is_sierra()) + wvmcs(cpu_state->hvf_fd, VMCS_TSC_OFFSET, env->tsc - rdtscp());*/ + hv_vm_sync_tsc(env->tsc); +} + + +void hvf_get_xsave(CPUState *cpu_state) +{ + int x; + struct hvf_xsave_buf *xsave; + + xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; + + if (hv_vcpu_read_fpstate(cpu_state->hvf_fd, xsave->data, 4096)) { + abort(); + } + + memcpy(&X86_CPU(cpu_state)->env.fpdp, &xsave->data[4], sizeof(X86_CPU(cpu_state)->env.fpdp)); + memcpy(&X86_CPU(cpu_state)->env.fpip, &xsave->data[2], sizeof(X86_CPU(cpu_state)->env.fpip)); + memcpy(&X86_CPU(cpu_state)->env.fpregs, &xsave->data[8], sizeof(X86_CPU(cpu_state)->env.fpregs)); + memcpy(&X86_CPU(cpu_state)->env.ymmh_regs, &xsave->data[144], sizeof(X86_CPU(cpu_state)->env.ymmh_regs)); + memcpy(&X86_CPU(cpu_state)->env.zmmh_regs, &xsave->data[288], sizeof(X86_CPU(cpu_state)->env.zmmh_regs)); + memcpy(&X86_CPU(cpu_state)->env.opmask_regs, &xsave->data[272], sizeof(X86_CPU(cpu_state)->env.opmask_regs)); + memcpy(&X86_CPU(cpu_state)->env.bnd_regs, &xsave->data[240], sizeof(X86_CPU(cpu_state)->env.bnd_regs)); + memcpy(&X86_CPU(cpu_state)->env.bndcs_regs, &xsave->data[256], sizeof(X86_CPU(cpu_state)->env.bndcs_regs)); + memcpy(&X86_CPU(cpu_state)->env.hi16_zmm_regs, &xsave->data[416], sizeof(X86_CPU(cpu_state)->env.hi16_zmm_regs)); + + + X86_CPU(cpu_state)->env.fpuc = (uint16_t)xsave->data[0]; + X86_CPU(cpu_state)->env.fpus = (uint16_t)(xsave->data[0] >> 16); + X86_CPU(cpu_state)->env.fpstt = (X86_CPU(cpu_state)->env.fpus >> 11) & 7; + X86_CPU(cpu_state)->env.fpop = (uint16_t)(xsave->data[1] >> 16); + + for (x = 0; x < 8; ++x) + X86_CPU(cpu_state)->env.fptags[x] = + ((((uint16_t)xsave->data[1] >> x) & 1) == 0); + + memcpy(&X86_CPU(cpu_state)->env.xmm_regs, &xsave->data[40], sizeof(X86_CPU(cpu_state)->env.xmm_regs)); + + X86_CPU(cpu_state)->env.mxcsr = xsave->data[6]; + X86_CPU(cpu_state)->env.xstate_bv = *(uint64_t *)&xsave->data[128]; +} + +void hvf_get_segments(CPUState *cpu_state) +{ + CPUX86State *env = &X86_CPU(cpu_state)->env; + + struct vmx_segment seg; + + env->interrupt_injected = -1; + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_CS); + hvf_get_segment(&env->segs[R_CS], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_DS); + hvf_get_segment(&env->segs[R_DS], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_ES); + hvf_get_segment(&env->segs[R_ES], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_FS); + hvf_get_segment(&env->segs[R_FS], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_GS); + hvf_get_segment(&env->segs[R_GS], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_SS); + hvf_get_segment(&env->segs[R_SS], &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_TR); + hvf_get_segment(&env->tr, &seg); + + vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); + hvf_get_segment(&env->ldt, &seg); + + env->idt.limit = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_LIMIT); + env->idt.base = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_BASE); + env->gdt.limit = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_LIMIT); + env->gdt.base = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_GDTR_BASE); + + env->cr[0] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR0); + env->cr[2] = 0; + env->cr[3] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR3); + env->cr[4] = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_CR4); + + env->efer = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IA32_EFER); +} + +void hvf_get_msrs(CPUState *cpu_state) +{ + CPUX86State *env = &X86_CPU(cpu_state)->env; + uint64_t tmp; + + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_CS, &tmp); + env->sysenter_cs = tmp; + + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_ESP, &tmp); + env->sysenter_esp = tmp; + + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_SYSENTER_EIP, &tmp); + env->sysenter_eip = tmp; + + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_STAR, &env->star); + +#ifdef TARGET_X86_64 + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_CSTAR, &env->cstar); + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_KERNELGSBASE, &env->kernelgsbase); + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_FMASK, &env->fmask); + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_LSTAR, &env->lstar); +#endif + + hv_vcpu_read_msr(cpu_state->hvf_fd, MSR_IA32_APICBASE, &tmp); + + env->tsc = rdtscp() + rvmcs(cpu_state->hvf_fd, VMCS_TSC_OFFSET); +} + +int hvf_put_registers(CPUState *cpu_state) +{ + X86CPU *x86cpu = X86_CPU(cpu_state); + CPUX86State *env = &x86cpu->env; + + wreg(cpu_state->hvf_fd, HV_X86_RAX, env->regs[R_EAX]); + wreg(cpu_state->hvf_fd, HV_X86_RBX, env->regs[R_EBX]); + wreg(cpu_state->hvf_fd, HV_X86_RCX, env->regs[R_ECX]); + wreg(cpu_state->hvf_fd, HV_X86_RDX, env->regs[R_EDX]); + wreg(cpu_state->hvf_fd, HV_X86_RBP, env->regs[R_EBP]); + wreg(cpu_state->hvf_fd, HV_X86_RSP, env->regs[R_ESP]); + wreg(cpu_state->hvf_fd, HV_X86_RSI, env->regs[R_ESI]); + wreg(cpu_state->hvf_fd, HV_X86_RDI, env->regs[R_EDI]); + wreg(cpu_state->hvf_fd, HV_X86_R8, env->regs[8]); + wreg(cpu_state->hvf_fd, HV_X86_R9, env->regs[9]); + wreg(cpu_state->hvf_fd, HV_X86_R10, env->regs[10]); + wreg(cpu_state->hvf_fd, HV_X86_R11, env->regs[11]); + wreg(cpu_state->hvf_fd, HV_X86_R12, env->regs[12]); + wreg(cpu_state->hvf_fd, HV_X86_R13, env->regs[13]); + wreg(cpu_state->hvf_fd, HV_X86_R14, env->regs[14]); + wreg(cpu_state->hvf_fd, HV_X86_R15, env->regs[15]); + wreg(cpu_state->hvf_fd, HV_X86_RFLAGS, env->eflags); + wreg(cpu_state->hvf_fd, HV_X86_RIP, env->eip); + + wreg(cpu_state->hvf_fd, HV_X86_XCR0, env->xcr0); + + hvf_put_xsave(cpu_state); + + hvf_put_segments(cpu_state); + + hvf_put_msrs(cpu_state); + + wreg(cpu_state->hvf_fd, HV_X86_DR0, env->dr[0]); + wreg(cpu_state->hvf_fd, HV_X86_DR1, env->dr[1]); + wreg(cpu_state->hvf_fd, HV_X86_DR2, env->dr[2]); + wreg(cpu_state->hvf_fd, HV_X86_DR3, env->dr[3]); + wreg(cpu_state->hvf_fd, HV_X86_DR4, env->dr[4]); + wreg(cpu_state->hvf_fd, HV_X86_DR5, env->dr[5]); + wreg(cpu_state->hvf_fd, HV_X86_DR6, env->dr[6]); + wreg(cpu_state->hvf_fd, HV_X86_DR7, env->dr[7]); + + return 0; +} + +int hvf_get_registers(CPUState *cpu_state) +{ + X86CPU *x86cpu = X86_CPU(cpu_state); + CPUX86State *env = &x86cpu->env; + + + env->regs[R_EAX] = rreg(cpu_state->hvf_fd, HV_X86_RAX); + env->regs[R_EBX] = rreg(cpu_state->hvf_fd, HV_X86_RBX); + env->regs[R_ECX] = rreg(cpu_state->hvf_fd, HV_X86_RCX); + env->regs[R_EDX] = rreg(cpu_state->hvf_fd, HV_X86_RDX); + env->regs[R_EBP] = rreg(cpu_state->hvf_fd, HV_X86_RBP); + env->regs[R_ESP] = rreg(cpu_state->hvf_fd, HV_X86_RSP); + env->regs[R_ESI] = rreg(cpu_state->hvf_fd, HV_X86_RSI); + env->regs[R_EDI] = rreg(cpu_state->hvf_fd, HV_X86_RDI); + env->regs[8] = rreg(cpu_state->hvf_fd, HV_X86_R8); + env->regs[9] = rreg(cpu_state->hvf_fd, HV_X86_R9); + env->regs[10] = rreg(cpu_state->hvf_fd, HV_X86_R10); + env->regs[11] = rreg(cpu_state->hvf_fd, HV_X86_R11); + env->regs[12] = rreg(cpu_state->hvf_fd, HV_X86_R12); + env->regs[13] = rreg(cpu_state->hvf_fd, HV_X86_R13); + env->regs[14] = rreg(cpu_state->hvf_fd, HV_X86_R14); + env->regs[15] = rreg(cpu_state->hvf_fd, HV_X86_R15); + + env->eflags = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); + env->eip = rreg(cpu_state->hvf_fd, HV_X86_RIP); + + hvf_get_xsave(cpu_state); + env->xcr0 = rreg(cpu_state->hvf_fd, HV_X86_XCR0); + + hvf_get_segments(cpu_state); + hvf_get_msrs(cpu_state); + + env->dr[0] = rreg(cpu_state->hvf_fd, HV_X86_DR0); + env->dr[1] = rreg(cpu_state->hvf_fd, HV_X86_DR1); + env->dr[2] = rreg(cpu_state->hvf_fd, HV_X86_DR2); + env->dr[3] = rreg(cpu_state->hvf_fd, HV_X86_DR3); + env->dr[4] = rreg(cpu_state->hvf_fd, HV_X86_DR4); + env->dr[5] = rreg(cpu_state->hvf_fd, HV_X86_DR5); + env->dr[6] = rreg(cpu_state->hvf_fd, HV_X86_DR6); + env->dr[7] = rreg(cpu_state->hvf_fd, HV_X86_DR7); + + return 0; +} + +static void vmx_set_int_window_exiting(CPUState *cpu) +{ + uint64_t val; + val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); + wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val | + VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING); +} + +void vmx_clear_int_window_exiting(CPUState *cpu) +{ + uint64_t val; + val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS); + wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val & + ~VMCS_PRI_PROC_BASED_CTLS_INT_WINDOW_EXITING); +} + +#define NMI_VEC 2 + +bool hvf_inject_interrupts(CPUState *cpu_state) +{ + int allow_nmi = !(rvmcs(cpu_state->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & + VMCS_INTERRUPTIBILITY_NMI_BLOCKING); + X86CPU *x86cpu = X86_CPU(cpu_state); + CPUX86State *env = &x86cpu->env; + + uint64_t idt_info = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_INFO); + uint64_t info = 0; + + if (idt_info & VMCS_IDT_VEC_VALID) { + uint8_t vector = idt_info & 0xff; + uint64_t intr_type = idt_info & VMCS_INTR_T_MASK; + info = idt_info; + + uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON); + if (intr_type == VMCS_INTR_T_NMI && reason != EXIT_REASON_TASK_SWITCH) { + allow_nmi = 1; + vmx_clear_nmi_blocking(cpu_state); + } + + if ((allow_nmi || intr_type != VMCS_INTR_T_NMI)) { + info &= ~(1 << 12); /* clear undefined bit */ + if (intr_type == VMCS_INTR_T_SWINTR || + intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION || + intr_type == VMCS_INTR_T_SWEXCEPTION) { + uint64_t ins_len = rvmcs(cpu_state->hvf_fd, + VMCS_EXIT_INSTRUCTION_LENGTH); + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); + } + if (vector == EXCEPTION_BP || vector == EXCEPTION_OF) { + /* + * VT-x requires #BP and #OF to be injected as software + * exceptions. + */ + info &= ~VMCS_INTR_T_MASK; + info |= VMCS_INTR_T_SWEXCEPTION; + uint64_t ins_len = rvmcs(cpu_state->hvf_fd, + VMCS_EXIT_INSTRUCTION_LENGTH); + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); + } + + uint64_t err = 0; + if (idt_info & VMCS_INTR_DEL_ERRCODE) { + err = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_ERROR); + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, err); + } + /*printf("reinject %lx err %d\n", info, err);*/ + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); + }; + } + + if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) { + if (allow_nmi && !(info & VMCS_INTR_VALID)) { + cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI; + info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC; + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); + } else { + vmx_set_nmi_window_exiting(cpu_state); + } + } + + if (env->hvf_emul->interruptable && + (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && + (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) { + int line = cpu_get_pic_interrupt(&x86cpu->env); + cpu_state->interrupt_request &= ~CPU_INTERRUPT_HARD; + if (line >= 0) { + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, line | + VMCS_INTR_VALID | VMCS_INTR_T_HWINTR); + } + } + if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) { + vmx_set_int_window_exiting(cpu_state); + } +} + +int hvf_process_events(CPUState *cpu_state) +{ + X86CPU *cpu = X86_CPU(cpu_state); + CPUX86State *env = &cpu->env; + + EFLAGS(env) = rreg(cpu_state->hvf_fd, HV_X86_RFLAGS); + + if (cpu_state->interrupt_request & CPU_INTERRUPT_INIT) { + hvf_cpu_synchronize_state(cpu_state); + do_cpu_init(cpu); + } + + if (cpu_state->interrupt_request & CPU_INTERRUPT_POLL) { + cpu_state->interrupt_request &= ~CPU_INTERRUPT_POLL; + apic_poll_irq(cpu->apic_state); + } + if (((cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && + (EFLAGS(env) & IF_MASK)) || + (cpu_state->interrupt_request & CPU_INTERRUPT_NMI)) { + cpu_state->halted = 0; + } + if (cpu_state->interrupt_request & CPU_INTERRUPT_SIPI) { + hvf_cpu_synchronize_state(cpu_state); + do_cpu_sipi(cpu); + } + if (cpu_state->interrupt_request & CPU_INTERRUPT_TPR) { + cpu_state->interrupt_request &= ~CPU_INTERRUPT_TPR; + hvf_cpu_synchronize_state(cpu_state); + apic_handle_tpr_access_report(cpu->apic_state, env->eip, + env->tpr_access_type); + } + return cpu_state->halted; +} diff --git a/target/i386/hvf-utils/x86hvf.h b/target/i386/hvf-utils/x86hvf.h new file mode 100644 index 0000000000..daa0b75273 --- /dev/null +++ b/target/i386/hvf-utils/x86hvf.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef X86HVF_H +#define X86HVF_H +#include "cpu.h" +#include "x86_descr.h" + +int hvf_process_events(CPUState *); +int hvf_put_registers(CPUState *); +int hvf_get_registers(CPUState *); +bool hvf_inject_interrupts(CPUState *); +void hvf_set_segment(struct CPUState *cpu, struct vmx_segment *vmx_seg, + SegmentCache *qseg, bool is_tr); +void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg); +void hvf_put_xsave(CPUState *cpu_state); +void hvf_put_segments(CPUState *cpu_state); +void hvf_put_msrs(CPUState *cpu_state); +void hvf_get_xsave(CPUState *cpu_state); +void hvf_get_msrs(CPUState *cpu_state); +void vmx_clear_int_window_exiting(CPUState *cpu); +void hvf_get_segments(CPUState *cpu_state); +void vmx_update_tpr(CPUState *cpu); +void hvf_cpu_synchronize_state(CPUState *cpu_state); +#endif From 996feed462fa7f249f03ffb0520c2ef0c5bc3312 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:11 -0500 Subject: [PATCH 377/546] i386: hvf: fix licensing issues; isolate task handling code (GPL v2-only) This patch replaces the license header for those files that were either GPL v2-or-v3, or GPL v2-only; the replacing license is GPL v2-or-later. The code for task switching/handling, which is derived from KVM and hence is GPL v2-only, is isolated in the new files (with this license) x86_task.c/.h, and the corresponding compilation rule is added to target/i386/hvf-utils/Makefile.objs. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-4-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf-all.c | 155 +-------------------- target/i386/hvf-utils/Makefile.objs | 2 +- target/i386/hvf-utils/vmx.h | 14 +- target/i386/hvf-utils/x86.c | 14 +- target/i386/hvf-utils/x86.h | 14 +- target/i386/hvf-utils/x86_decode.c | 14 +- target/i386/hvf-utils/x86_decode.h | 14 +- target/i386/hvf-utils/x86_descr.c | 14 +- target/i386/hvf-utils/x86_descr.h | 14 +- target/i386/hvf-utils/x86_emu.c | 14 +- target/i386/hvf-utils/x86_emu.h | 14 +- target/i386/hvf-utils/x86_gen.h | 14 +- target/i386/hvf-utils/x86_mmu.c | 14 +- target/i386/hvf-utils/x86_mmu.h | 14 +- target/i386/hvf-utils/x86_task.c | 200 ++++++++++++++++++++++++++++ target/i386/hvf-utils/x86_task.h | 18 +++ target/i386/hvf-utils/x86hvf.c | 14 +- target/i386/hvf-utils/x86hvf.h | 14 +- 18 files changed, 318 insertions(+), 253 deletions(-) create mode 100644 target/i386/hvf-utils/x86_task.c create mode 100644 target/i386/hvf-utils/x86_task.h diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c index b0c87ebd9f..c098949577 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf-all.c @@ -31,6 +31,7 @@ #include "hvf-utils/x86_mmu.h" #include "hvf-utils/x86_decode.h" #include "hvf-utils/x86_emu.h" +#include "hvf-utils/x86_task.h" #include "hvf-utils/x86hvf.h" #include @@ -224,160 +225,6 @@ void update_apic_tpr(CPUState *cpu) #define VECTORING_INFO_VECTOR_MASK 0xff -// TODO: taskswitch handling -static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) -{ - /* CR3 and ldt selector are not saved intentionally */ - tss->eip = EIP(cpu); - tss->eflags = EFLAGS(cpu); - tss->eax = EAX(cpu); - tss->ecx = ECX(cpu); - tss->edx = EDX(cpu); - tss->ebx = EBX(cpu); - tss->esp = ESP(cpu); - tss->ebp = EBP(cpu); - tss->esi = ESI(cpu); - tss->edi = EDI(cpu); - - tss->es = vmx_read_segment_selector(cpu, REG_SEG_ES).sel; - tss->cs = vmx_read_segment_selector(cpu, REG_SEG_CS).sel; - tss->ss = vmx_read_segment_selector(cpu, REG_SEG_SS).sel; - tss->ds = vmx_read_segment_selector(cpu, REG_SEG_DS).sel; - tss->fs = vmx_read_segment_selector(cpu, REG_SEG_FS).sel; - tss->gs = vmx_read_segment_selector(cpu, REG_SEG_GS).sel; -} - -static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) -{ - wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); - - RIP(cpu) = tss->eip; - EFLAGS(cpu) = tss->eflags | 2; - - /* General purpose registers */ - RAX(cpu) = tss->eax; - RCX(cpu) = tss->ecx; - RDX(cpu) = tss->edx; - RBX(cpu) = tss->ebx; - RSP(cpu) = tss->esp; - RBP(cpu) = tss->ebp; - RSI(cpu) = tss->esi; - RDI(cpu) = tss->edi; - - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, REG_SEG_LDTR); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, REG_SEG_ES); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, REG_SEG_CS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, REG_SEG_SS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, REG_SEG_DS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, REG_SEG_FS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, REG_SEG_GS); - -#if 0 - load_segment(cpu, REG_SEG_LDTR, tss->ldt); - load_segment(cpu, REG_SEG_ES, tss->es); - load_segment(cpu, REG_SEG_CS, tss->cs); - load_segment(cpu, REG_SEG_SS, tss->ss); - load_segment(cpu, REG_SEG_DS, tss->ds); - load_segment(cpu, REG_SEG_FS, tss->fs); - load_segment(cpu, REG_SEG_GS, tss->gs); -#endif -} - -static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segment_selector old_tss_sel, - uint64_t old_tss_base, struct x86_segment_descriptor *new_desc) -{ - struct x86_tss_segment32 tss_seg; - uint32_t new_tss_base = x86_segment_base(new_desc); - uint32_t eip_offset = offsetof(struct x86_tss_segment32, eip); - uint32_t ldt_sel_offset = offsetof(struct x86_tss_segment32, ldt); - - vmx_read_mem(cpu, &tss_seg, old_tss_base, sizeof(tss_seg)); - save_state_to_tss32(cpu, &tss_seg); - - vmx_write_mem(cpu, old_tss_base + eip_offset, &tss_seg.eip, ldt_sel_offset - eip_offset); - vmx_read_mem(cpu, &tss_seg, new_tss_base, sizeof(tss_seg)); - - if (old_tss_sel.sel != 0xffff) { - tss_seg.prev_tss = old_tss_sel.sel; - - vmx_write_mem(cpu, new_tss_base, &tss_seg.prev_tss, sizeof(tss_seg.prev_tss)); - } - load_state_from_tss32(cpu, &tss_seg); - return 0; -} - -static void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type) -{ - uint64_t rip = rreg(cpu->hvf_fd, HV_X86_RIP); - if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION && - gate_type != VMCS_INTR_T_HWINTR && - gate_type != VMCS_INTR_T_NMI)) { - int ins_len = rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); - macvm_set_rip(cpu, rip + ins_len); - return; - } - - load_regs(cpu); - - struct x86_segment_descriptor curr_tss_desc, next_tss_desc; - int ret; - x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, REG_SEG_TR); - uint64_t old_tss_base = vmx_read_segment_base(cpu, REG_SEG_TR); - uint32_t desc_limit; - struct x86_call_gate task_gate_desc; - struct vmx_segment vmx_seg; - - x86_read_segment_descriptor(cpu, &next_tss_desc, tss_sel); - x86_read_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); - - if (reason == TSR_IDT_GATE && gate_valid) { - int dpl; - - ret = x86_read_call_gate(cpu, &task_gate_desc, gate); - - dpl = task_gate_desc.dpl; - x68_segment_selector cs = vmx_read_segment_selector(cpu, REG_SEG_CS); - if (tss_sel.rpl > dpl || cs.rpl > dpl) - ;//DPRINTF("emulate_gp"); - } - - desc_limit = x86_segment_limit(&next_tss_desc); - if (!next_tss_desc.p || ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || desc_limit < 0x2b)) { - VM_PANIC("emulate_ts"); - } - - if (reason == TSR_IRET || reason == TSR_JMP) { - curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ - x86_write_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); - } - - if (reason == TSR_IRET) - EFLAGS(cpu) &= ~RFLAGS_NT; - - if (reason != TSR_CALL && reason != TSR_IDT_GATE) - old_tss_sel.sel = 0xffff; - - if (reason != TSR_IRET) { - next_tss_desc.type |= (1 << 1); /* set busy flag */ - x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); - } - - if (next_tss_desc.type & 8) - ret = task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); - else - //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); - VM_PANIC("task_switch_16"); - - macvm_set_cr0(cpu->hvf_fd, rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0) | CR0_TS); - x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); - vmx_write_segment_descriptor(cpu, &vmx_seg, REG_SEG_TR); - - store_regs(cpu); - - hv_vcpu_invalidate_tlb(cpu->hvf_fd); - hv_vcpu_flush(cpu->hvf_fd); -} - static void hvf_handle_interrupt(CPUState * cpu, int mask) { cpu->interrupt_request |= mask; diff --git a/target/i386/hvf-utils/Makefile.objs b/target/i386/hvf-utils/Makefile.objs index 7df219ad9c..79d8969ca8 100644 --- a/target/i386/hvf-utils/Makefile.objs +++ b/target/i386/hvf-utils/Makefile.objs @@ -1 +1 @@ -obj-y += x86.o x86_cpuid.o x86_decode.o x86_descr.o x86_emu.o x86_flags.o x86_mmu.o x86hvf.o +obj-y += x86.o x86_cpuid.o x86_decode.o x86_descr.o x86_emu.o x86_flags.o x86_mmu.o x86hvf.o x86_task.o diff --git a/target/i386/hvf-utils/vmx.h b/target/i386/hvf-utils/vmx.h index d086c8d253..44a5c6d554 100644 --- a/target/i386/hvf-utils/vmx.h +++ b/target/i386/hvf-utils/vmx.h @@ -6,17 +6,17 @@ * Interfaces to Hypervisor.framework to read/write X86 registers and VMCS. * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #ifndef VMX_H diff --git a/target/i386/hvf-utils/x86.c b/target/i386/hvf-utils/x86.c index 587efd54fd..625ea6cac0 100644 --- a/target/i386/hvf-utils/x86.c +++ b/target/i386/hvf-utils/x86.c @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #include "qemu/osdep.h" diff --git a/target/i386/hvf-utils/x86.h b/target/i386/hvf-utils/x86.h index d32e13d648..ca39d829d1 100644 --- a/target/i386/hvf-utils/x86.h +++ b/target/i386/hvf-utils/x86.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Veertu Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #pragma once diff --git a/target/i386/hvf-utils/x86_decode.c b/target/i386/hvf-utils/x86_decode.c index 13022f2851..623c051339 100644 --- a/target/i386/hvf-utils/x86_decode.c +++ b/target/i386/hvf-utils/x86_decode.c @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #include "qemu/osdep.h" diff --git a/target/i386/hvf-utils/x86_decode.h b/target/i386/hvf-utils/x86_decode.h index 540e95d17d..329131360f 100644 --- a/target/i386/hvf-utils/x86_decode.h +++ b/target/i386/hvf-utils/x86_decode.h @@ -2,17 +2,17 @@ * Copyright (C) 2016 Veertu Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #pragma once diff --git a/target/i386/hvf-utils/x86_descr.c b/target/i386/hvf-utils/x86_descr.c index c3b089aaa8..0b9562818f 100644 --- a/target/i386/hvf-utils/x86_descr.c +++ b/target/i386/hvf-utils/x86_descr.c @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #include "qemu/osdep.h" diff --git a/target/i386/hvf-utils/x86_descr.h b/target/i386/hvf-utils/x86_descr.h index f5e247782b..1285dd3897 100644 --- a/target/i386/hvf-utils/x86_descr.h +++ b/target/i386/hvf-utils/x86_descr.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #pragma once diff --git a/target/i386/hvf-utils/x86_emu.c b/target/i386/hvf-utils/x86_emu.c index eb09e38a77..f0f68f1c30 100644 --- a/target/i386/hvf-utils/x86_emu.c +++ b/target/i386/hvf-utils/x86_emu.c @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ ///////////////////////////////////////////////////////////////////////// diff --git a/target/i386/hvf-utils/x86_emu.h b/target/i386/hvf-utils/x86_emu.h index e1491a0935..cd4acb0030 100644 --- a/target/i386/hvf-utils/x86_emu.h +++ b/target/i386/hvf-utils/x86_emu.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #ifndef __X86_EMU_H__ #define __X86_EMU_H__ diff --git a/target/i386/hvf-utils/x86_gen.h b/target/i386/hvf-utils/x86_gen.h index e4340fa244..2045b0e69d 100644 --- a/target/i386/hvf-utils/x86_gen.h +++ b/target/i386/hvf-utils/x86_gen.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #ifndef __X86_GEN_H__ #define __X86_GEN_H__ diff --git a/target/i386/hvf-utils/x86_mmu.c b/target/i386/hvf-utils/x86_mmu.c index 4bb1664104..26e9e95b0b 100644 --- a/target/i386/hvf-utils/x86_mmu.c +++ b/target/i386/hvf-utils/x86_mmu.c @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #include "qemu/osdep.h" diff --git a/target/i386/hvf-utils/x86_mmu.h b/target/i386/hvf-utils/x86_mmu.h index 4fce48c18f..b786af280b 100644 --- a/target/i386/hvf-utils/x86_mmu.h +++ b/target/i386/hvf-utils/x86_mmu.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #ifndef __X86_MMU_H__ #define __X86_MMU_H__ diff --git a/target/i386/hvf-utils/x86_task.c b/target/i386/hvf-utils/x86_task.c new file mode 100644 index 0000000000..2806814f90 --- /dev/null +++ b/target/i386/hvf-utils/x86_task.c @@ -0,0 +1,200 @@ +// This software is licensed under the terms of the GNU General Public +// License version 2, as published by the Free Software Foundation, and +// may be copied, distributed, and modified under those terms. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/error-report.h" + +#include "sysemu/hvf.h" +#include "hvf-i386.h" +#include "hvf-utils/vmcs.h" +#include "hvf-utils/vmx.h" +#include "hvf-utils/x86.h" +#include "hvf-utils/x86_descr.h" +#include "hvf-utils/x86_mmu.h" +#include "hvf-utils/x86_decode.h" +#include "hvf-utils/x86_emu.h" +#include "hvf-utils/x86_task.h" +#include "hvf-utils/x86hvf.h" + +#include +#include + +#include "exec/address-spaces.h" +#include "exec/exec-all.h" +#include "exec/ioport.h" +#include "hw/i386/apic_internal.h" +#include "hw/boards.h" +#include "qemu/main-loop.h" +#include "strings.h" +#include "sysemu/accel.h" +#include "sysemu/sysemu.h" +#include "target/i386/cpu.h" + +// TODO: taskswitch handling +static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + /* CR3 and ldt selector are not saved intentionally */ + tss->eip = EIP(env); + tss->eflags = EFLAGS(env); + tss->eax = EAX(env); + tss->ecx = ECX(env); + tss->edx = EDX(env); + tss->ebx = EBX(env); + tss->esp = ESP(env); + tss->ebp = EBP(env); + tss->esi = ESI(env); + tss->edi = EDI(env); + + tss->es = vmx_read_segment_selector(cpu, REG_SEG_ES).sel; + tss->cs = vmx_read_segment_selector(cpu, REG_SEG_CS).sel; + tss->ss = vmx_read_segment_selector(cpu, REG_SEG_SS).sel; + tss->ds = vmx_read_segment_selector(cpu, REG_SEG_DS).sel; + tss->fs = vmx_read_segment_selector(cpu, REG_SEG_FS).sel; + tss->gs = vmx_read_segment_selector(cpu, REG_SEG_GS).sel; +} + +static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + wvmcs(cpu->hvf_fd, VMCS_GUEST_CR3, tss->cr3); + + RIP(env) = tss->eip; + EFLAGS(env) = tss->eflags | 2; + + /* General purpose registers */ + RAX(env) = tss->eax; + RCX(env) = tss->ecx; + RDX(env) = tss->edx; + RBX(env) = tss->ebx; + RSP(env) = tss->esp; + RBP(env) = tss->ebp; + RSI(env) = tss->esi; + RDI(env) = tss->edi; + + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, REG_SEG_LDTR); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, REG_SEG_ES); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, REG_SEG_CS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, REG_SEG_SS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, REG_SEG_DS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, REG_SEG_FS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, REG_SEG_GS); + +#if 0 + load_segment(cpu, REG_SEG_LDTR, tss->ldt); + load_segment(cpu, REG_SEG_ES, tss->es); + load_segment(cpu, REG_SEG_CS, tss->cs); + load_segment(cpu, REG_SEG_SS, tss->ss); + load_segment(cpu, REG_SEG_DS, tss->ds); + load_segment(cpu, REG_SEG_FS, tss->fs); + load_segment(cpu, REG_SEG_GS, tss->gs); +#endif +} + +static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segment_selector old_tss_sel, + uint64_t old_tss_base, struct x86_segment_descriptor *new_desc) +{ + struct x86_tss_segment32 tss_seg; + uint32_t new_tss_base = x86_segment_base(new_desc); + uint32_t eip_offset = offsetof(struct x86_tss_segment32, eip); + uint32_t ldt_sel_offset = offsetof(struct x86_tss_segment32, ldt); + + vmx_read_mem(cpu, &tss_seg, old_tss_base, sizeof(tss_seg)); + save_state_to_tss32(cpu, &tss_seg); + + vmx_write_mem(cpu, old_tss_base + eip_offset, &tss_seg.eip, ldt_sel_offset - eip_offset); + vmx_read_mem(cpu, &tss_seg, new_tss_base, sizeof(tss_seg)); + + if (old_tss_sel.sel != 0xffff) { + tss_seg.prev_tss = old_tss_sel.sel; + + vmx_write_mem(cpu, new_tss_base, &tss_seg.prev_tss, sizeof(tss_seg.prev_tss)); + } + load_state_from_tss32(cpu, &tss_seg); + return 0; +} + +void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int reason, bool gate_valid, uint8_t gate, uint64_t gate_type) +{ + uint64_t rip = rreg(cpu->hvf_fd, HV_X86_RIP); + if (!gate_valid || (gate_type != VMCS_INTR_T_HWEXCEPTION && + gate_type != VMCS_INTR_T_HWINTR && + gate_type != VMCS_INTR_T_NMI)) { + int ins_len = rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); + macvm_set_rip(cpu, rip + ins_len); + return; + } + + load_regs(cpu); + + struct x86_segment_descriptor curr_tss_desc, next_tss_desc; + int ret; + x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, REG_SEG_TR); + uint64_t old_tss_base = vmx_read_segment_base(cpu, REG_SEG_TR); + uint32_t desc_limit; + struct x86_call_gate task_gate_desc; + struct vmx_segment vmx_seg; + + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + x86_read_segment_descriptor(cpu, &next_tss_desc, tss_sel); + x86_read_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); + + if (reason == TSR_IDT_GATE && gate_valid) { + int dpl; + + ret = x86_read_call_gate(cpu, &task_gate_desc, gate); + + dpl = task_gate_desc.dpl; + x68_segment_selector cs = vmx_read_segment_selector(cpu, REG_SEG_CS); + if (tss_sel.rpl > dpl || cs.rpl > dpl) + ;//DPRINTF("emulate_gp"); + } + + desc_limit = x86_segment_limit(&next_tss_desc); + if (!next_tss_desc.p || ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || desc_limit < 0x2b)) { + VM_PANIC("emulate_ts"); + } + + if (reason == TSR_IRET || reason == TSR_JMP) { + curr_tss_desc.type &= ~(1 << 1); /* clear busy flag */ + x86_write_segment_descriptor(cpu, &curr_tss_desc, old_tss_sel); + } + + if (reason == TSR_IRET) + EFLAGS(env) &= ~RFLAGS_NT; + + if (reason != TSR_CALL && reason != TSR_IDT_GATE) + old_tss_sel.sel = 0xffff; + + if (reason != TSR_IRET) { + next_tss_desc.type |= (1 << 1); /* set busy flag */ + x86_write_segment_descriptor(cpu, &next_tss_desc, tss_sel); + } + + if (next_tss_desc.type & 8) + ret = task_switch_32(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); + else + //ret = task_switch_16(cpu, tss_sel, old_tss_sel, old_tss_base, &next_tss_desc); + VM_PANIC("task_switch_16"); + + macvm_set_cr0(cpu->hvf_fd, rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0) | CR0_TS); + x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); + vmx_write_segment_descriptor(cpu, &vmx_seg, REG_SEG_TR); + + store_regs(cpu); + + hv_vcpu_invalidate_tlb(cpu->hvf_fd); + hv_vcpu_flush(cpu->hvf_fd); +} diff --git a/target/i386/hvf-utils/x86_task.h b/target/i386/hvf-utils/x86_task.h new file mode 100644 index 0000000000..4f1b188d2e --- /dev/null +++ b/target/i386/hvf-utils/x86_task.h @@ -0,0 +1,18 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef HVF_TASK +#define HVF_TASK +void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, + int reason, bool gate_valid, uint8_t gate, uint64_t gate_type); +#endif diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf-utils/x86hvf.c index 1d9ab08cbe..55da8298f9 100644 --- a/target/i386/hvf-utils/x86hvf.c +++ b/target/i386/hvf-utils/x86hvf.c @@ -4,17 +4,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #include "qemu/osdep.h" diff --git a/target/i386/hvf-utils/x86hvf.h b/target/i386/hvf-utils/x86hvf.h index daa0b75273..79539f7282 100644 --- a/target/i386/hvf-utils/x86hvf.h +++ b/target/i386/hvf-utils/x86hvf.h @@ -3,17 +3,17 @@ * Copyright (C) 2017 Google Inc, * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . */ #ifndef X86HVF_H #define X86HVF_H From f585195ec07fd2a6af5fc04c92caf1b71f34e16c Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:17 -0500 Subject: [PATCH 378/546] i386: hvf: use new helper functions for put/get xsave This patch makes use of the helper functions for handling xsave in xsave_helper.c, which are shared with kvm. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-10-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf-all.c | 3 +- target/i386/hvf-utils/x86.h | 7 ---- target/i386/hvf-utils/x86hvf.c | 69 ++++++---------------------------- 3 files changed, 12 insertions(+), 67 deletions(-) diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c index c098949577..ddeadac176 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf-all.c @@ -502,8 +502,7 @@ int hvf_init_vcpu(CPUState *cpu) hvf_reset_vcpu(cpu); x86cpu = X86_CPU(cpu); - x86cpu->env.kvm_xsave_buf = qemu_memalign(4096, - sizeof(struct hvf_xsave_buf)); + x86cpu->env.kvm_xsave_buf = qemu_memalign(4096, 4096); hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_STAR, 1); hv_vcpu_enable_native_msr(cpu->hvf_fd, MSR_LSTAR, 1); diff --git a/target/i386/hvf-utils/x86.h b/target/i386/hvf-utils/x86.h index ca39d829d1..250364b448 100644 --- a/target/i386/hvf-utils/x86.h +++ b/target/i386/hvf-utils/x86.h @@ -373,13 +373,6 @@ struct HVFX86EmulatorState { uint8_t mmio_buf[4096]; }; -/* -* hvf xsave area -*/ -struct hvf_xsave_buf { - uint32_t data[1024]; -}; - /* useful register access macros */ #define RIP(cpu) (cpu->hvf_emul->rip) #define EIP(cpu) ((uint32_t)cpu->hvf_emul->rip) diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf-utils/x86hvf.c index 55da8298f9..c7dbe5810f 100644 --- a/target/i386/hvf-utils/x86hvf.c +++ b/target/i386/hvf-utils/x86hvf.c @@ -76,36 +76,13 @@ void hvf_get_segment(SegmentCache *qseg, struct vmx_segment *vmx_seg) void hvf_put_xsave(CPUState *cpu_state) { - int x; - struct hvf_xsave_buf *xsave; - + struct X86XSaveArea *xsave; + xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; - memset(xsave, 0, sizeof(*xsave)); - - memcpy(&xsave->data[4], &X86_CPU(cpu_state)->env.fpdp, sizeof(X86_CPU(cpu_state)->env.fpdp)); - memcpy(&xsave->data[2], &X86_CPU(cpu_state)->env.fpip, sizeof(X86_CPU(cpu_state)->env.fpip)); - memcpy(&xsave->data[8], &X86_CPU(cpu_state)->env.fpregs, sizeof(X86_CPU(cpu_state)->env.fpregs)); - memcpy(&xsave->data[144], &X86_CPU(cpu_state)->env.ymmh_regs, sizeof(X86_CPU(cpu_state)->env.ymmh_regs)); - memcpy(&xsave->data[288], &X86_CPU(cpu_state)->env.zmmh_regs, sizeof(X86_CPU(cpu_state)->env.zmmh_regs)); - memcpy(&xsave->data[272], &X86_CPU(cpu_state)->env.opmask_regs, sizeof(X86_CPU(cpu_state)->env.opmask_regs)); - memcpy(&xsave->data[240], &X86_CPU(cpu_state)->env.bnd_regs, sizeof(X86_CPU(cpu_state)->env.bnd_regs)); - memcpy(&xsave->data[256], &X86_CPU(cpu_state)->env.bndcs_regs, sizeof(X86_CPU(cpu_state)->env.bndcs_regs)); - memcpy(&xsave->data[416], &X86_CPU(cpu_state)->env.hi16_zmm_regs, sizeof(X86_CPU(cpu_state)->env.hi16_zmm_regs)); - - xsave->data[0] = (uint16_t)X86_CPU(cpu_state)->env.fpuc; - xsave->data[0] |= (X86_CPU(cpu_state)->env.fpus << 16); - xsave->data[0] |= (X86_CPU(cpu_state)->env.fpstt & 7) << 11; - - for (x = 0; x < 8; ++x) - xsave->data[1] |= ((!X86_CPU(cpu_state)->env.fptags[x]) << x); - xsave->data[1] |= (uint32_t)(X86_CPU(cpu_state)->env.fpop << 16); - - memcpy(&xsave->data[40], &X86_CPU(cpu_state)->env.xmm_regs, sizeof(X86_CPU(cpu_state)->env.xmm_regs)); - - xsave->data[6] = X86_CPU(cpu_state)->env.mxcsr; - *(uint64_t *)&xsave->data[128] = X86_CPU(cpu_state)->env.xstate_bv; - - if (hv_vcpu_write_fpstate(cpu_state->hvf_fd, xsave->data, 4096)){ + + x86_cpu_xsave_all_areas(X86_CPU(cpu_state), xsave); + + if (hv_vcpu_write_fpstate(cpu_state->hvf_fd, (void*)xsave, 4096)) { abort(); } } @@ -187,39 +164,15 @@ void hvf_put_msrs(CPUState *cpu_state) void hvf_get_xsave(CPUState *cpu_state) { - int x; - struct hvf_xsave_buf *xsave; - + struct X86XSaveArea *xsave; + xsave = X86_CPU(cpu_state)->env.kvm_xsave_buf; - - if (hv_vcpu_read_fpstate(cpu_state->hvf_fd, xsave->data, 4096)) { + + if (hv_vcpu_read_fpstate(cpu_state->hvf_fd, (void*)xsave, 4096)) { abort(); } - memcpy(&X86_CPU(cpu_state)->env.fpdp, &xsave->data[4], sizeof(X86_CPU(cpu_state)->env.fpdp)); - memcpy(&X86_CPU(cpu_state)->env.fpip, &xsave->data[2], sizeof(X86_CPU(cpu_state)->env.fpip)); - memcpy(&X86_CPU(cpu_state)->env.fpregs, &xsave->data[8], sizeof(X86_CPU(cpu_state)->env.fpregs)); - memcpy(&X86_CPU(cpu_state)->env.ymmh_regs, &xsave->data[144], sizeof(X86_CPU(cpu_state)->env.ymmh_regs)); - memcpy(&X86_CPU(cpu_state)->env.zmmh_regs, &xsave->data[288], sizeof(X86_CPU(cpu_state)->env.zmmh_regs)); - memcpy(&X86_CPU(cpu_state)->env.opmask_regs, &xsave->data[272], sizeof(X86_CPU(cpu_state)->env.opmask_regs)); - memcpy(&X86_CPU(cpu_state)->env.bnd_regs, &xsave->data[240], sizeof(X86_CPU(cpu_state)->env.bnd_regs)); - memcpy(&X86_CPU(cpu_state)->env.bndcs_regs, &xsave->data[256], sizeof(X86_CPU(cpu_state)->env.bndcs_regs)); - memcpy(&X86_CPU(cpu_state)->env.hi16_zmm_regs, &xsave->data[416], sizeof(X86_CPU(cpu_state)->env.hi16_zmm_regs)); - - - X86_CPU(cpu_state)->env.fpuc = (uint16_t)xsave->data[0]; - X86_CPU(cpu_state)->env.fpus = (uint16_t)(xsave->data[0] >> 16); - X86_CPU(cpu_state)->env.fpstt = (X86_CPU(cpu_state)->env.fpus >> 11) & 7; - X86_CPU(cpu_state)->env.fpop = (uint16_t)(xsave->data[1] >> 16); - - for (x = 0; x < 8; ++x) - X86_CPU(cpu_state)->env.fptags[x] = - ((((uint16_t)xsave->data[1] >> x) & 1) == 0); - - memcpy(&X86_CPU(cpu_state)->env.xmm_regs, &xsave->data[40], sizeof(X86_CPU(cpu_state)->env.xmm_regs)); - - X86_CPU(cpu_state)->env.mxcsr = xsave->data[6]; - X86_CPU(cpu_state)->env.xstate_bv = *(uint64_t *)&xsave->data[128]; + x86_cpu_xrstor_all_areas(X86_CPU(cpu_state), xsave); } void hvf_get_segments(CPUState *cpu_state) From db5cb9a0320d74b817d3e58f54206cea36529572 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:18 -0500 Subject: [PATCH 379/546] i386: hvf: implement hvf_get_supported_cpuid This patch implements hvf_get_supported_cpuid, which returns the set of features supported by both the host processor and the hypervisor. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-11-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf-utils/x86_cpuid.c | 164 ++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 target/i386/hvf-utils/x86_cpuid.c diff --git a/target/i386/hvf-utils/x86_cpuid.c b/target/i386/hvf-utils/x86_cpuid.c new file mode 100644 index 0000000000..103223a85d --- /dev/null +++ b/target/i386/hvf-utils/x86_cpuid.c @@ -0,0 +1,164 @@ +/* + * i386 CPUID helper functions + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2017 Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + * + * cpuid + */ + +#include "qemu/osdep.h" +#include "x86.h" +#include "vmx.h" +#include "sysemu/hvf.h" + +static uint64_t xgetbv(uint32_t xcr) +{ + uint32_t eax, edx; + + __asm__ volatile ("xgetbv" + : "=a" (eax), "=d" (edx) + : "c" (xcr)); + + return (((uint64_t)edx) << 32) | eax; +} + +static bool vmx_mpx_supported() +{ + uint64_t cap_exit, cap_entry; + + hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &cap_entry); + hv_vmx_read_capability(HV_VMX_CAP_EXIT, &cap_exit); + + return ((cap_exit & (1 << 23)) && (cap_entry & (1 << 16))); +} + +uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, + int reg) +{ + uint64_t cap; + uint32_t eax, ebx, ecx, edx; + + host_cpuid(func, idx, &eax, &ebx, &ecx, &edx); + + switch (func) { + case 0: + eax = eax < (uint32_t)0xd ? eax : (uint32_t)0xd; + break; + case 1: + edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | + CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | + CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | + CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | + CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS; + ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | + CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | + CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE | + CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE | + CPUID_EXT_AVX | CPUID_EXT_F16C | CPUID_EXT_RDRAND; + ecx |= CPUID_EXT_HYPERVISOR; + break; + case 6: + eax = CPUID_6_EAX_ARAT; + ebx = 0; + ecx = 0; + edx = 0; + break; + case 7: + if (idx == 0) { + ebx &= CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | + CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | + CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | + CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_RTM | + CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | + CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA | + CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512PF | + CPUID_7_0_EBX_AVX512ER | CPUID_7_0_EBX_AVX512CD | + CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | + CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_SHA_NI | + CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL | + CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_MPX; + + if (!vmx_mpx_supported()) { + ebx &= ~CPUID_7_0_EBX_MPX; + } + hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); + if (!(cap & CPU_BASED2_INVPCID)) { + ebx &= ~CPUID_7_0_EBX_INVPCID; + } + + ecx &= CPUID_7_0_ECX_AVX512BMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ; + edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS; + } else { + ebx = 0; + ecx = 0; + edx = 0; + } + eax = 0; + break; + case 0xD: + if (idx == 0) { + uint64_t host_xcr0 = xgetbv(0); + uint64_t supp_xcr0 = host_xcr0 & (XSTATE_FP_MASK | XSTATE_SSE_MASK | + XSTATE_YMM_MASK | XSTATE_BNDREGS_MASK | + XSTATE_BNDCSR_MASK | XSTATE_OPMASK_MASK | + XSTATE_ZMM_Hi256_MASK | XSTATE_Hi16_ZMM_MASK); + eax &= supp_xcr0; + if (!vmx_mpx_supported()) { + eax &= ~(XSTATE_BNDREGS_MASK | XSTATE_BNDCSR_MASK); + } + } else if (idx == 1) { + hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &cap); + eax &= CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XGETBV1; + if (!(cap & CPU_BASED2_XSAVES_XRSTORS)) { + eax &= ~CPUID_XSAVE_XSAVES; + } + } + break; + case 0x80000001: + /* LM only if HVF in 64-bit mode */ + edx &= CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | + CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | + CPUID_EXT2_SYSCALL | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | + CPUID_PAT | CPUID_PSE36 | CPUID_EXT2_MMXEXT | CPUID_MMX | + CPUID_FXSR | CPUID_EXT2_FXSR | CPUID_EXT2_PDPE1GB | CPUID_EXT2_3DNOWEXT | + CPUID_EXT2_3DNOW | CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX; + hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &cap); + if (!(cap & CPU_BASED_TSC_OFFSET)) { + edx &= ~CPUID_EXT2_RDTSCP; + } + ecx &= CPUID_EXT3_LAHF_LM | CPUID_EXT3_CMP_LEG | CPUID_EXT3_CR8LEG | + CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | CPUID_EXT3_MISALIGNSSE | + CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_OSVW | CPUID_EXT3_XOP | + CPUID_EXT3_FMA4 | CPUID_EXT3_TBM; + break; + default: + return 0; + } + + switch (reg) { + case R_EAX: + return eax; + case R_EBX: + return ebx; + case R_ECX: + return ecx; + case R_EDX: + return edx; + default: + return 0; + } +} From d6dcc5583e7a3f04a76de72424ee63c760dffd0f Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:19 -0500 Subject: [PATCH 380/546] i386: refactor KVM cpuid code so that it applies to hvf as well This patch generalizes some code in cpu.c for hypervisor-based accelerators, calling the new hvf_get_supported_cpuid where KVM used kvm_get_supported_cpuid. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-12-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu-qom.h | 4 +-- target/i386/cpu.c | 77 ++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/target/i386/cpu-qom.h b/target/i386/cpu-qom.h index c2205e6077..22f95eb3a4 100644 --- a/target/i386/cpu-qom.h +++ b/target/i386/cpu-qom.h @@ -47,7 +47,7 @@ typedef struct X86CPUDefinition X86CPUDefinition; /** * X86CPUClass: * @cpu_def: CPU model definition - * @kvm_required: Whether CPU model requires KVM to be enabled. + * @host_cpuid_required: Whether CPU model requires cpuid from host. * @ordering: Ordering on the "-cpu help" CPU model list. * @migration_safe: See CpuDefinitionInfo::migration_safe * @static_model: See CpuDefinitionInfo::static @@ -66,7 +66,7 @@ typedef struct X86CPUClass { */ X86CPUDefinition *cpu_def; - bool kvm_required; + bool host_cpuid_required; int ordering; bool migration_safe; bool static_model; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index b069eafcc6..fcda7609c8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "sysemu/kvm.h" +#include "sysemu/hvf.h" #include "sysemu/cpus.h" #include "kvm_i386.h" @@ -615,6 +616,11 @@ static uint32_t xsave_area_size(uint64_t mask) return ret; } +static inline bool accel_uses_host_cpuid(void) +{ + return kvm_enabled() || hvf_enabled(); +} + static inline uint64_t x86_cpu_xsave_components(X86CPU *cpu) { return ((uint64_t)cpu->env.features[FEAT_XSAVE_COMP_HI]) << 32 | @@ -1686,10 +1692,15 @@ static void max_x86_cpu_initfn(Object *obj) */ cpu->max_features = true; - if (kvm_enabled()) { + if (accel_uses_host_cpuid()) { char vendor[CPUID_VENDOR_SZ + 1] = { 0 }; char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 }; int family, model, stepping; + X86CPUDefinition host_cpudef = { }; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; + + host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); + x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx); host_vendor_fms(vendor, &family, &model, &stepping); @@ -1703,12 +1714,21 @@ static void max_x86_cpu_initfn(Object *obj) object_property_set_str(OBJECT(cpu), model_id, "model-id", &error_abort); - env->cpuid_min_level = - kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); - env->cpuid_min_xlevel = - kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); - env->cpuid_min_xlevel2 = - kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); + if (kvm_enabled()) { + env->cpuid_min_level = + kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX); + env->cpuid_min_xlevel = + kvm_arch_get_supported_cpuid(s, 0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); + } else { + env->cpuid_min_level = + hvf_get_supported_cpuid(0x0, 0, R_EAX); + env->cpuid_min_xlevel = + hvf_get_supported_cpuid(0x80000000, 0, R_EAX); + env->cpuid_min_xlevel2 = + hvf_get_supported_cpuid(0xC0000000, 0, R_EAX); + } if (lmce_supported()) { object_property_set_bool(OBJECT(cpu), true, "lmce", &error_abort); @@ -1734,18 +1754,21 @@ static const TypeInfo max_x86_cpu_type_info = { .class_init = max_x86_cpu_class_init, }; -#ifdef CONFIG_KVM - +#if defined(CONFIG_KVM) || defined(CONFIG_HVF) static void host_x86_cpu_class_init(ObjectClass *oc, void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); - xcc->kvm_required = true; + xcc->host_cpuid_required = true; xcc->ordering = 8; - xcc->model_description = - "KVM processor with all supported host features " - "(only available in KVM mode)"; + if (kvm_enabled()) { + xcc->model_description = + "KVM processor with all supported host features "; + } else if (hvf_enabled()) { + xcc->model_description = + "HVF processor with all supported host features "; + } } static const TypeInfo host_x86_cpu_type_info = { @@ -1767,7 +1790,7 @@ static void report_unavailable_features(FeatureWord w, uint32_t mask) assert(reg); warn_report("%s doesn't support requested feature: " "CPUID.%02XH:%s%s%s [bit %d]", - kvm_enabled() ? "host" : "TCG", + accel_uses_host_cpuid() ? "host" : "TCG", f->cpuid_eax, reg, f->feat_names[i] ? "." : "", f->feat_names[i] ? f->feat_names[i] : "", i); @@ -2218,7 +2241,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc, Error *err = NULL; strList **next = missing_feats; - if (xcc->kvm_required && !kvm_enabled()) { + if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { strList *new = g_new0(strList, 1); new->value = g_strdup("kvm"); *missing_feats = new; @@ -2380,6 +2403,10 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, r = kvm_arch_get_supported_cpuid(kvm_state, wi->cpuid_eax, wi->cpuid_ecx, wi->cpuid_reg); + } else if (hvf_enabled()) { + r = hvf_get_supported_cpuid(wi->cpuid_eax, + wi->cpuid_ecx, + wi->cpuid_reg); } else if (tcg_enabled()) { r = wi->tcg_features; } else { @@ -2439,6 +2466,7 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) } /* Special cases not set in the X86CPUDefinition structs: */ + /* TODO: in-kernel irqchip for hvf */ if (kvm_enabled()) { if (!kvm_irqchip_in_kernel()) { x86_cpu_change_kvm_default("x2apic", "off"); @@ -2459,7 +2487,7 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp) * when doing cross vendor migration */ vendor = def->vendor; - if (kvm_enabled()) { + if (accel_uses_host_cpuid()) { uint32_t ebx = 0, ecx = 0, edx = 0; host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); x86_cpu_vendor_words2str(host_vendor, ebx, edx, ecx); @@ -2910,6 +2938,11 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); + } else if (hvf_enabled() && cpu->enable_pmu) { + *eax = hvf_get_supported_cpuid(0xA, count, R_EAX); + *ebx = hvf_get_supported_cpuid(0xA, count, R_EBX); + *ecx = hvf_get_supported_cpuid(0xA, count, R_ECX); + *edx = hvf_get_supported_cpuid(0xA, count, R_EDX); } else { *eax = 0; *ebx = 0; @@ -3261,6 +3294,9 @@ static void x86_cpu_reset(CPUState *s) if (kvm_enabled()) { kvm_arch_reset_vcpu(cpu); } + else if (hvf_enabled()) { + hvf_reset_vcpu(s); + } #endif } @@ -3300,6 +3336,7 @@ APICCommonClass *apic_get_class(void) { const char *apic_type = "apic"; + /* TODO: in-kernel irqchip for hvf */ if (kvm_apic_in_kernel()) { apic_type = "kvm-apic"; } else if (xen_enabled()) { @@ -3613,7 +3650,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) Error *local_err = NULL; static bool ht_warned; - if (xcc->kvm_required && !kvm_enabled()) { + if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { char *name = x86_cpu_class_get_model_name(xcc); error_setg(&local_err, "CPU model '%s' requires KVM", name); g_free(name); @@ -3635,7 +3672,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) x86_cpu_report_filtered_features(cpu); if (cpu->enforce_cpuid) { error_setg(&local_err, - kvm_enabled() ? + accel_uses_host_cpuid() ? "Host doesn't support requested features" : "TCG doesn't support requested features"); goto out; @@ -3658,7 +3695,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) * consumer AMD devices but nothing else. */ if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) { - if (kvm_enabled()) { + if (accel_uses_host_cpuid()) { uint32_t host_phys_bits = x86_host_phys_bits(); static bool warned; @@ -4272,7 +4309,7 @@ static void x86_cpu_register_types(void) } type_register_static(&max_x86_cpu_type_info); type_register_static(&x86_base_cpu_type_info); -#ifdef CONFIG_KVM +#if defined(CONFIG_KVM) || defined(CONFIG_HVF) type_register_static(&host_x86_cpu_type_info); #endif } From babfa20ca4721e950d8096f32b1dc091763a8837 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:20 -0500 Subject: [PATCH 381/546] i386: hvf: implement vga dirty page tracking This patch implements setting the tracking of dirty vga pages, using hvf's interface to protect guest memory. It uses the MemoryListener callback mechanism through .log_start/stop/sync Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-13-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- include/sysemu/hvf.h | 5 +++ target/i386/hvf-all.c | 73 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h index 614a2d203b..e4e43f6468 100644 --- a/include/sysemu/hvf.h +++ b/include/sysemu/hvf.h @@ -34,11 +34,16 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, #define hvf_get_supported_cpuid(func, idx, reg) 0 #endif +/* hvf_slot flags */ +#define HVF_SLOT_LOG (1 << 0) + typedef struct hvf_slot { uint64_t start; uint64_t size; uint8_t *mem; int slot_id; + uint32_t flags; + MemoryRegion *region; } hvf_slot; typedef struct hvf_vcpu_caps { diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c index ddeadac176..b63dd5599e 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf-all.c @@ -193,6 +193,7 @@ void hvf_set_phys_mem(MemoryRegionSection *section, bool add) mem->size = int128_get64(section->size); mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region; mem->start = section->offset_within_address_space; + mem->region = area; if (do_hvf_set_memory(mem)) { error_report("Error registering new memory slot\n"); @@ -289,8 +290,7 @@ void hvf_cpu_synchronize_post_init(CPUState *cpu_state) run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } -/* TODO: ept fault handlig */ -static bool ept_emulation_fault(uint64_t ept_qual) +static bool ept_emulation_fault(hvf_slot *slot, addr_t gpa, uint64_t ept_qual) { int read, write; @@ -306,6 +306,14 @@ static bool ept_emulation_fault(uint64_t ept_qual) return false; } + if (write && slot) { + if (slot->flags & HVF_SLOT_LOG) { + memory_region_set_dirty(slot->region, gpa - slot->start, 1); + hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size, + HV_MEMORY_READ | HV_MEMORY_WRITE); + } + } + /* * The EPT violation must have been caused by accessing a * guest-physical address that is a translation of a guest-linear @@ -316,7 +324,58 @@ static bool ept_emulation_fault(uint64_t ept_qual) return false; } - return true; + return !slot; +} + +static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on) +{ + hvf_slot *slot; + + slot = hvf_find_overlap_slot( + section->offset_within_address_space, + section->offset_within_address_space + int128_get64(section->size)); + + /* protect region against writes; begin tracking it */ + if (on) { + slot->flags |= HVF_SLOT_LOG; + hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size, + HV_MEMORY_READ); + /* stop tracking region*/ + } else { + slot->flags &= ~HVF_SLOT_LOG; + hv_vm_protect((hv_gpaddr_t)slot->start, (size_t)slot->size, + HV_MEMORY_READ | HV_MEMORY_WRITE); + } +} + +static void hvf_log_start(MemoryListener *listener, + MemoryRegionSection *section, int old, int new) +{ + if (old != 0) { + return; + } + + hvf_set_dirty_tracking(section, 1); +} + +static void hvf_log_stop(MemoryListener *listener, + MemoryRegionSection *section, int old, int new) +{ + if (new != 0) { + return; + } + + hvf_set_dirty_tracking(section, 0); +} + +static void hvf_log_sync(MemoryListener *listener, + MemoryRegionSection *section) +{ + /* + * sync of dirty pages is handled elsewhere; just make sure we keep + * tracking the region. + */ + hvf_set_dirty_tracking(section, 1); } static void hvf_region_add(MemoryListener *listener, @@ -335,6 +394,9 @@ static MemoryListener hvf_memory_listener = { .priority = 10, .region_add = hvf_region_add, .region_del = hvf_region_del, + .log_start = hvf_log_start, + .log_stop = hvf_log_stop, + .log_sync = hvf_log_sync, }; void hvf_reset_vcpu(CPUState *cpu) { @@ -607,7 +669,7 @@ int hvf_vcpu_exec(CPUState *cpu) slot = hvf_find_overlap_slot(gpa, gpa); /* mmio */ - if (ept_emulation_fault(exit_qual) && !slot) { + if (ept_emulation_fault(slot, gpa, exit_qual)) { struct x86_decode decode; load_regs(cpu); @@ -618,9 +680,6 @@ int hvf_vcpu_exec(CPUState *cpu) store_regs(cpu); break; } -#ifdef DIRTY_VGA_TRACKING - /* TODO: handle dirty page tracking */ -#endif break; } case EXIT_REASON_INOUT: From b7394c8394d38cb38b6db14eb431cac7a91e7140 Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:21 -0500 Subject: [PATCH 382/546] i386: hvf: refactor event injection code for hvf This patch refactors the event-injection code for hvf by using the appropriate fields already provided by CPUX86State. At vmexit, it fills these fields so that hvf_inject_interrupts can just retrieve them without calling into hvf. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-14-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 3 ++ target/i386/hvf-all.c | 61 ++++++++++++++++++++++++++++--- target/i386/hvf-utils/vmcs.h | 3 ++ target/i386/hvf-utils/vmx.h | 8 ++++ target/i386/hvf-utils/x86hvf.c | 67 +++++++++++++++++----------------- target/i386/kvm.c | 2 - 6 files changed, 102 insertions(+), 42 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fcda7609c8..3818d72831 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3285,6 +3285,9 @@ static void x86_cpu_reset(CPUState *s) memset(env->mtrr_var, 0, sizeof(env->mtrr_var)); memset(env->mtrr_fixed, 0, sizeof(env->mtrr_fixed)); + env->interrupt_injected = -1; + env->exception_injected = -1; + env->nmi_injected = false; #if !defined(CONFIG_USER_ONLY) /* We hard-wire the BSP to the first CPU. */ apic_designate_bsp(cpu->apic_state, s->cpu_index == 0); diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c index b63dd5599e..1df13fbc19 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf-all.c @@ -587,6 +587,55 @@ void hvf_disable(int shouldDisable) hvf_disabled = shouldDisable; } +static void hvf_store_events(CPUState *cpu, uint32_t ins_len, uint64_t idtvec_info) +{ + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + env->exception_injected = -1; + env->interrupt_injected = -1; + env->nmi_injected = false; + if (idtvec_info & VMCS_IDT_VEC_VALID) { + switch (idtvec_info & VMCS_IDT_VEC_TYPE) { + case VMCS_IDT_VEC_HWINTR: + case VMCS_IDT_VEC_SWINTR: + env->interrupt_injected = idtvec_info & VMCS_IDT_VEC_VECNUM; + break; + case VMCS_IDT_VEC_NMI: + env->nmi_injected = true; + break; + case VMCS_IDT_VEC_HWEXCEPTION: + case VMCS_IDT_VEC_SWEXCEPTION: + env->exception_injected = idtvec_info & VMCS_IDT_VEC_VECNUM; + break; + case VMCS_IDT_VEC_PRIV_SWEXCEPTION: + default: + abort(); + } + if ((idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWEXCEPTION || + (idtvec_info & VMCS_IDT_VEC_TYPE) == VMCS_IDT_VEC_SWINTR) { + env->ins_len = ins_len; + } + if (idtvec_info & VMCS_INTR_DEL_ERRCODE) { + env->has_error_code = true; + env->error_code = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_ERROR); + } + } + if ((rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & + VMCS_INTERRUPTIBILITY_NMI_BLOCKING)) { + env->hflags2 |= HF2_NMI_MASK; + } else { + env->hflags2 &= ~HF2_NMI_MASK; + } + if (rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & + (VMCS_INTERRUPTIBILITY_STI_BLOCKING | + VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) { + env->hflags |= HF_INHIBIT_IRQ_MASK; + } else { + env->hflags &= ~HF_INHIBIT_IRQ_MASK; + } +} + int hvf_vcpu_exec(CPUState *cpu) { X86CPU *x86_cpu = X86_CPU(cpu); @@ -606,12 +655,9 @@ int hvf_vcpu_exec(CPUState *cpu) cpu->vcpu_dirty = false; } - env->hvf_emul->interruptable = - !(rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & - (VMCS_INTERRUPTIBILITY_STI_BLOCKING | - VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)); - - hvf_inject_interrupts(cpu); + if (hvf_inject_interrupts(cpu)) { + return EXCP_INTERRUPT; + } vmx_update_tpr(cpu); qemu_mutex_unlock_iothread(); @@ -628,7 +674,10 @@ int hvf_vcpu_exec(CPUState *cpu) uint64_t exit_qual = rvmcs(cpu->hvf_fd, VMCS_EXIT_QUALIFICATION); uint32_t ins_len = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_EXIT_INSTRUCTION_LENGTH); + uint64_t idtvec_info = rvmcs(cpu->hvf_fd, VMCS_IDT_VECTORING_INFO); + + hvf_store_events(cpu, ins_len, idtvec_info); rip = rreg(cpu->hvf_fd, HV_X86_RIP); RFLAGS(env) = rreg(cpu->hvf_fd, HV_X86_RFLAGS); env->eflags = RFLAGS(env); diff --git a/target/i386/hvf-utils/vmcs.h b/target/i386/hvf-utils/vmcs.h index cd3a19fe38..2a8c0424a5 100644 --- a/target/i386/hvf-utils/vmcs.h +++ b/target/i386/hvf-utils/vmcs.h @@ -299,6 +299,7 @@ /* * VMCS IDT-Vectoring information fields */ +#define VMCS_IDT_VEC_VECNUM 0xFF #define VMCS_IDT_VEC_VALID (1U << 31) #define VMCS_IDT_VEC_TYPE 0x700 #define VMCS_IDT_VEC_ERRCODE_VALID (1U << 11) @@ -306,6 +307,8 @@ #define VMCS_IDT_VEC_NMI (2 << 8) #define VMCS_IDT_VEC_HWEXCEPTION (3 << 8) #define VMCS_IDT_VEC_SWINTR (4 << 8) +#define VMCS_IDT_VEC_PRIV_SWEXCEPTION (5 << 8) +#define VMCS_IDT_VEC_SWEXCEPTION (6 << 8) /* * VMCS Guest interruptibility field diff --git a/target/i386/hvf-utils/vmx.h b/target/i386/hvf-utils/vmx.h index 44a5c6d554..102075d0d4 100644 --- a/target/i386/hvf-utils/vmx.h +++ b/target/i386/hvf-utils/vmx.h @@ -181,6 +181,10 @@ static inline void macvm_set_rip(CPUState *cpu, uint64_t rip) static inline void vmx_clear_nmi_blocking(CPUState *cpu) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + env->hflags2 &= ~HF2_NMI_MASK; uint32_t gi = (uint32_t) rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING; wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi); @@ -188,6 +192,10 @@ static inline void vmx_clear_nmi_blocking(CPUState *cpu) static inline void vmx_set_nmi_blocking(CPUState *cpu) { + X86CPU *x86_cpu = X86_CPU(cpu); + CPUX86State *env = &x86_cpu->env; + + env->hflags2 |= HF2_NMI_MASK; uint32_t gi = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY); gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING; wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi); diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf-utils/x86hvf.c index c7dbe5810f..c7a72d1890 100644 --- a/target/i386/hvf-utils/x86hvf.c +++ b/target/i386/hvf-utils/x86hvf.c @@ -356,50 +356,47 @@ void vmx_clear_int_window_exiting(CPUState *cpu) bool hvf_inject_interrupts(CPUState *cpu_state) { - int allow_nmi = !(rvmcs(cpu_state->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY) & - VMCS_INTERRUPTIBILITY_NMI_BLOCKING); X86CPU *x86cpu = X86_CPU(cpu_state); CPUX86State *env = &x86cpu->env; - uint64_t idt_info = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_INFO); + uint8_t vector; + uint64_t intr_type; + bool have_event = true; + if (env->interrupt_injected != -1) { + vector = env->interrupt_injected; + intr_type = VMCS_INTR_T_SWINTR; + } else if (env->exception_injected != -1) { + vector = env->exception_injected; + if (vector == EXCP03_INT3 || vector == EXCP04_INTO) { + intr_type = VMCS_INTR_T_SWEXCEPTION; + } else { + intr_type = VMCS_INTR_T_HWEXCEPTION; + } + } else if (env->nmi_injected) { + vector = NMI_VEC; + intr_type = VMCS_INTR_T_NMI; + } else { + have_event = false; + } + uint64_t info = 0; - - if (idt_info & VMCS_IDT_VEC_VALID) { - uint8_t vector = idt_info & 0xff; - uint64_t intr_type = idt_info & VMCS_INTR_T_MASK; - info = idt_info; - + if (have_event) { + info = vector | intr_type | VMCS_INTR_VALID; uint64_t reason = rvmcs(cpu_state->hvf_fd, VMCS_EXIT_REASON); - if (intr_type == VMCS_INTR_T_NMI && reason != EXIT_REASON_TASK_SWITCH) { - allow_nmi = 1; + if (env->nmi_injected && reason != EXIT_REASON_TASK_SWITCH) { vmx_clear_nmi_blocking(cpu_state); } - - if ((allow_nmi || intr_type != VMCS_INTR_T_NMI)) { + + if (!(env->hflags2 & HF2_NMI_MASK) || intr_type != VMCS_INTR_T_NMI) { info &= ~(1 << 12); /* clear undefined bit */ if (intr_type == VMCS_INTR_T_SWINTR || - intr_type == VMCS_INTR_T_PRIV_SWEXCEPTION || intr_type == VMCS_INTR_T_SWEXCEPTION) { - uint64_t ins_len = rvmcs(cpu_state->hvf_fd, - VMCS_EXIT_INSTRUCTION_LENGTH); - wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); - } - if (vector == EXCEPTION_BP || vector == EXCEPTION_OF) { - /* - * VT-x requires #BP and #OF to be injected as software - * exceptions. - */ - info &= ~VMCS_INTR_T_MASK; - info |= VMCS_INTR_T_SWEXCEPTION; - uint64_t ins_len = rvmcs(cpu_state->hvf_fd, - VMCS_EXIT_INSTRUCTION_LENGTH); - wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, ins_len); + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INST_LENGTH, env->ins_len); } - uint64_t err = 0; - if (idt_info & VMCS_INTR_DEL_ERRCODE) { - err = rvmcs(cpu_state->hvf_fd, VMCS_IDT_VECTORING_ERROR); - wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, err); + if (env->has_error_code) { + wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_EXCEPTION_ERROR, + env->error_code); } /*printf("reinject %lx err %d\n", info, err);*/ wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); @@ -407,7 +404,7 @@ bool hvf_inject_interrupts(CPUState *cpu_state) } if (cpu_state->interrupt_request & CPU_INTERRUPT_NMI) { - if (allow_nmi && !(info & VMCS_INTR_VALID)) { + if (!(env->hflags2 & HF2_NMI_MASK) && !(info & VMCS_INTR_VALID)) { cpu_state->interrupt_request &= ~CPU_INTERRUPT_NMI; info = VMCS_INTR_VALID | VMCS_INTR_T_NMI | NMI_VEC; wvmcs(cpu_state->hvf_fd, VMCS_ENTRY_INTR_INFO, info); @@ -416,7 +413,7 @@ bool hvf_inject_interrupts(CPUState *cpu_state) } } - if (env->hvf_emul->interruptable && + if (!(env->hflags & HF_INHIBIT_IRQ_MASK) && (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) && (EFLAGS(env) & IF_MASK) && !(info & VMCS_INTR_VALID)) { int line = cpu_get_pic_interrupt(&x86cpu->env); @@ -429,6 +426,8 @@ bool hvf_inject_interrupts(CPUState *cpu_state) if (cpu_state->interrupt_request & CPU_INTERRUPT_HARD) { vmx_set_int_window_exiting(cpu_state); } + return (cpu_state->interrupt_request + & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)); } int hvf_process_events(CPUState *cpu_state) diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 351b64f77c..6f69e2fcfd 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -1038,8 +1038,6 @@ void kvm_arch_reset_vcpu(X86CPU *cpu) { CPUX86State *env = &cpu->env; - env->exception_injected = -1; - env->interrupt_injected = -1; env->xcr0 = 1; if (kvm_irqchip_in_kernel()) { env->mp_state = cpu_is_bsp(cpu) ? KVM_MP_STATE_RUNNABLE : From 3010460fb99776bdf0a8b170555f2ab076382f9c Mon Sep 17 00:00:00 2001 From: Sergio Andres Gomez Del Real Date: Wed, 13 Sep 2017 04:05:22 -0500 Subject: [PATCH 383/546] i386: hvf: inject General Protection Fault when vmexit through vmcall This patch injects a GP fault when the guest vmexit's by executing a vmcall instruction. Signed-off-by: Sergio Andres Gomez Del Real Message-Id: <20170913090522.4022-15-Sergio.G.DelReal@gmail.com> Signed-off-by: Paolo Bonzini --- target/i386/hvf-all.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/i386/hvf-all.c b/target/i386/hvf-all.c index 1df13fbc19..126344f5be 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf-all.c @@ -902,7 +902,9 @@ int hvf_vcpu_exec(CPUState *cpu) macvm_set_rip(cpu, rip + ins_len); break; case VMX_REASON_VMCALL: - /* TODO: inject #GP fault */ + env->exception_injected = EXCP0D_GPF; + env->has_error_code = true; + env->error_code = 0; break; default: error_report("%llx: unhandled exit %llx\n", rip, exit_reason); From 69e0a03c3f28f5bd35f54a47cd4996cc14e135ba Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:33:29 +0200 Subject: [PATCH 384/546] i386: hvf: move all hvf files in the same directory Just call it hvf/, no need for the "utils" suffix. Signed-off-by: Paolo Bonzini --- target/i386/Makefile.objs | 2 +- target/i386/{hvf-utils => hvf}/Makefile.objs | 1 + target/i386/{hvf-utils => hvf}/README.md | 0 target/i386/{ => hvf}/hvf-i386.h | 2 +- target/i386/{hvf-all.c => hvf/hvf.c} | 19 +++++++++---------- target/i386/{hvf-utils => hvf}/vmcs.h | 0 target/i386/{hvf-utils => hvf}/vmx.h | 0 target/i386/{hvf-utils => hvf}/x86.c | 0 target/i386/{hvf-utils => hvf}/x86.h | 0 target/i386/{hvf-utils => hvf}/x86_cpuid.c | 0 target/i386/{hvf-utils => hvf}/x86_decode.c | 0 target/i386/{hvf-utils => hvf}/x86_decode.h | 0 target/i386/{hvf-utils => hvf}/x86_descr.c | 0 target/i386/{hvf-utils => hvf}/x86_descr.h | 0 target/i386/{hvf-utils => hvf}/x86_emu.c | 0 target/i386/{hvf-utils => hvf}/x86_emu.h | 0 target/i386/{hvf-utils => hvf}/x86_flags.c | 0 target/i386/{hvf-utils => hvf}/x86_flags.h | 0 target/i386/{hvf-utils => hvf}/x86_gen.h | 0 target/i386/{hvf-utils => hvf}/x86_mmu.c | 0 target/i386/{hvf-utils => hvf}/x86_mmu.h | 0 target/i386/{hvf-utils => hvf}/x86_task.c | 18 +++++++++--------- target/i386/{hvf-utils => hvf}/x86_task.h | 0 target/i386/{hvf-utils => hvf}/x86hvf.c | 0 target/i386/{hvf-utils => hvf}/x86hvf.h | 0 25 files changed, 21 insertions(+), 21 deletions(-) rename target/i386/{hvf-utils => hvf}/Makefile.objs (87%) rename target/i386/{hvf-utils => hvf}/README.md (100%) rename target/i386/{ => hvf}/hvf-i386.h (97%) rename target/i386/{hvf-all.c => hvf/hvf.c} (98%) rename target/i386/{hvf-utils => hvf}/vmcs.h (100%) rename target/i386/{hvf-utils => hvf}/vmx.h (100%) rename target/i386/{hvf-utils => hvf}/x86.c (100%) rename target/i386/{hvf-utils => hvf}/x86.h (100%) rename target/i386/{hvf-utils => hvf}/x86_cpuid.c (100%) rename target/i386/{hvf-utils => hvf}/x86_decode.c (100%) rename target/i386/{hvf-utils => hvf}/x86_decode.h (100%) rename target/i386/{hvf-utils => hvf}/x86_descr.c (100%) rename target/i386/{hvf-utils => hvf}/x86_descr.h (100%) rename target/i386/{hvf-utils => hvf}/x86_emu.c (100%) rename target/i386/{hvf-utils => hvf}/x86_emu.h (100%) rename target/i386/{hvf-utils => hvf}/x86_flags.c (100%) rename target/i386/{hvf-utils => hvf}/x86_flags.h (100%) rename target/i386/{hvf-utils => hvf}/x86_gen.h (100%) rename target/i386/{hvf-utils => hvf}/x86_mmu.c (100%) rename target/i386/{hvf-utils => hvf}/x86_mmu.h (100%) rename target/i386/{hvf-utils => hvf}/x86_task.c (96%) rename target/i386/{hvf-utils => hvf}/x86_task.h (100%) rename target/i386/{hvf-utils => hvf}/x86hvf.c (100%) rename target/i386/{hvf-utils => hvf}/x86hvf.h (100%) diff --git a/target/i386/Makefile.objs b/target/i386/Makefile.objs index 0bef89c099..44103a693b 100644 --- a/target/i386/Makefile.objs +++ b/target/i386/Makefile.objs @@ -12,5 +12,5 @@ obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-windows.o endif ifdef CONFIG_DARWIN obj-$(CONFIG_HAX) += hax-all.o hax-mem.o hax-darwin.o -obj-$(CONFIG_HVF) += hvf-utils/ hvf-all.o +obj-$(CONFIG_HVF) += hvf/ endif diff --git a/target/i386/hvf-utils/Makefile.objs b/target/i386/hvf/Makefile.objs similarity index 87% rename from target/i386/hvf-utils/Makefile.objs rename to target/i386/hvf/Makefile.objs index 79d8969ca8..927b86bc67 100644 --- a/target/i386/hvf-utils/Makefile.objs +++ b/target/i386/hvf/Makefile.objs @@ -1 +1,2 @@ +obj-y += hvf.o obj-y += x86.o x86_cpuid.o x86_decode.o x86_descr.o x86_emu.o x86_flags.o x86_mmu.o x86hvf.o x86_task.o diff --git a/target/i386/hvf-utils/README.md b/target/i386/hvf/README.md similarity index 100% rename from target/i386/hvf-utils/README.md rename to target/i386/hvf/README.md diff --git a/target/i386/hvf-i386.h b/target/i386/hvf/hvf-i386.h similarity index 97% rename from target/i386/hvf-i386.h rename to target/i386/hvf/hvf-i386.h index 797718ce34..2232501552 100644 --- a/target/i386/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -18,7 +18,7 @@ #include "sysemu/hvf.h" #include "cpu.h" -#include "hvf-utils/x86.h" +#include "x86.h" #define HVF_MAX_VCPU 0x10 #define MAX_VM_ID 0x40 diff --git a/target/i386/hvf-all.c b/target/i386/hvf/hvf.c similarity index 98% rename from target/i386/hvf-all.c rename to target/i386/hvf/hvf.c index 126344f5be..445082c2cb 100644 --- a/target/i386/hvf-all.c +++ b/target/i386/hvf/hvf.c @@ -24,15 +24,15 @@ #include "sysemu/hvf.h" #include "hvf-i386.h" -#include "hvf-utils/vmcs.h" -#include "hvf-utils/vmx.h" -#include "hvf-utils/x86.h" -#include "hvf-utils/x86_descr.h" -#include "hvf-utils/x86_mmu.h" -#include "hvf-utils/x86_decode.h" -#include "hvf-utils/x86_emu.h" -#include "hvf-utils/x86_task.h" -#include "hvf-utils/x86hvf.h" +#include "vmcs.h" +#include "vmx.h" +#include "x86.h" +#include "x86_descr.h" +#include "x86_mmu.h" +#include "x86_decode.h" +#include "x86_emu.h" +#include "x86_task.h" +#include "x86hvf.h" #include #include @@ -44,7 +44,6 @@ #include "hw/boards.h" #include "qemu/main-loop.h" #include "strings.h" -#include "trace.h" #include "sysemu/accel.h" #include "sysemu/sysemu.h" #include "target/i386/cpu.h" diff --git a/target/i386/hvf-utils/vmcs.h b/target/i386/hvf/vmcs.h similarity index 100% rename from target/i386/hvf-utils/vmcs.h rename to target/i386/hvf/vmcs.h diff --git a/target/i386/hvf-utils/vmx.h b/target/i386/hvf/vmx.h similarity index 100% rename from target/i386/hvf-utils/vmx.h rename to target/i386/hvf/vmx.h diff --git a/target/i386/hvf-utils/x86.c b/target/i386/hvf/x86.c similarity index 100% rename from target/i386/hvf-utils/x86.c rename to target/i386/hvf/x86.c diff --git a/target/i386/hvf-utils/x86.h b/target/i386/hvf/x86.h similarity index 100% rename from target/i386/hvf-utils/x86.h rename to target/i386/hvf/x86.h diff --git a/target/i386/hvf-utils/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c similarity index 100% rename from target/i386/hvf-utils/x86_cpuid.c rename to target/i386/hvf/x86_cpuid.c diff --git a/target/i386/hvf-utils/x86_decode.c b/target/i386/hvf/x86_decode.c similarity index 100% rename from target/i386/hvf-utils/x86_decode.c rename to target/i386/hvf/x86_decode.c diff --git a/target/i386/hvf-utils/x86_decode.h b/target/i386/hvf/x86_decode.h similarity index 100% rename from target/i386/hvf-utils/x86_decode.h rename to target/i386/hvf/x86_decode.h diff --git a/target/i386/hvf-utils/x86_descr.c b/target/i386/hvf/x86_descr.c similarity index 100% rename from target/i386/hvf-utils/x86_descr.c rename to target/i386/hvf/x86_descr.c diff --git a/target/i386/hvf-utils/x86_descr.h b/target/i386/hvf/x86_descr.h similarity index 100% rename from target/i386/hvf-utils/x86_descr.h rename to target/i386/hvf/x86_descr.h diff --git a/target/i386/hvf-utils/x86_emu.c b/target/i386/hvf/x86_emu.c similarity index 100% rename from target/i386/hvf-utils/x86_emu.c rename to target/i386/hvf/x86_emu.c diff --git a/target/i386/hvf-utils/x86_emu.h b/target/i386/hvf/x86_emu.h similarity index 100% rename from target/i386/hvf-utils/x86_emu.h rename to target/i386/hvf/x86_emu.h diff --git a/target/i386/hvf-utils/x86_flags.c b/target/i386/hvf/x86_flags.c similarity index 100% rename from target/i386/hvf-utils/x86_flags.c rename to target/i386/hvf/x86_flags.c diff --git a/target/i386/hvf-utils/x86_flags.h b/target/i386/hvf/x86_flags.h similarity index 100% rename from target/i386/hvf-utils/x86_flags.h rename to target/i386/hvf/x86_flags.h diff --git a/target/i386/hvf-utils/x86_gen.h b/target/i386/hvf/x86_gen.h similarity index 100% rename from target/i386/hvf-utils/x86_gen.h rename to target/i386/hvf/x86_gen.h diff --git a/target/i386/hvf-utils/x86_mmu.c b/target/i386/hvf/x86_mmu.c similarity index 100% rename from target/i386/hvf-utils/x86_mmu.c rename to target/i386/hvf/x86_mmu.c diff --git a/target/i386/hvf-utils/x86_mmu.h b/target/i386/hvf/x86_mmu.h similarity index 100% rename from target/i386/hvf-utils/x86_mmu.h rename to target/i386/hvf/x86_mmu.h diff --git a/target/i386/hvf-utils/x86_task.c b/target/i386/hvf/x86_task.c similarity index 96% rename from target/i386/hvf-utils/x86_task.c rename to target/i386/hvf/x86_task.c index 2806814f90..c8cb16d3fa 100644 --- a/target/i386/hvf-utils/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -12,15 +12,15 @@ #include "sysemu/hvf.h" #include "hvf-i386.h" -#include "hvf-utils/vmcs.h" -#include "hvf-utils/vmx.h" -#include "hvf-utils/x86.h" -#include "hvf-utils/x86_descr.h" -#include "hvf-utils/x86_mmu.h" -#include "hvf-utils/x86_decode.h" -#include "hvf-utils/x86_emu.h" -#include "hvf-utils/x86_task.h" -#include "hvf-utils/x86hvf.h" +#include "vmcs.h" +#include "vmx.h" +#include "x86.h" +#include "x86_descr.h" +#include "x86_mmu.h" +#include "x86_decode.h" +#include "x86_emu.h" +#include "x86_task.h" +#include "x86hvf.h" #include #include diff --git a/target/i386/hvf-utils/x86_task.h b/target/i386/hvf/x86_task.h similarity index 100% rename from target/i386/hvf-utils/x86_task.h rename to target/i386/hvf/x86_task.h diff --git a/target/i386/hvf-utils/x86hvf.c b/target/i386/hvf/x86hvf.c similarity index 100% rename from target/i386/hvf-utils/x86hvf.c rename to target/i386/hvf/x86hvf.c diff --git a/target/i386/hvf-utils/x86hvf.h b/target/i386/hvf/x86hvf.h similarity index 100% rename from target/i386/hvf-utils/x86hvf.h rename to target/i386/hvf/x86hvf.h From f9fea777405b43dd4143548d573d3799b9fb728f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:36:05 +0200 Subject: [PATCH 385/546] i386: hvf: header cleanup Remove inclusions of system headers and avoid "pragma once". Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86.h | 9 +++------ target/i386/hvf/x86_cpuid.c | 1 + target/i386/hvf/x86_decode.c | 1 + target/i386/hvf/x86_decode.h | 12 +++++------- target/i386/hvf/x86_descr.c | 1 + target/i386/hvf/x86_descr.h | 5 ++++- target/i386/hvf/x86_flags.c | 2 +- target/i386/hvf/x86_gen.h | 4 ---- target/i386/hvf/x86hvf.c | 2 +- 9 files changed, 17 insertions(+), 20 deletions(-) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 250364b448..2dc55477a5 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -16,13 +16,9 @@ * License along with this program; if not, see . */ -#pragma once +#ifndef HVF_X86_H +#define HVF_X86_H 1 -#include -#include -#include -#include -#include "qemu-common.h" #include "x86_gen.h" /* exceptions */ @@ -467,3 +463,4 @@ static inline uint64_t rdtscp(void) return tsc; } +#endif diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index 103223a85d..bcb9705a71 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -21,6 +21,7 @@ */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "x86.h" #include "vmx.h" #include "sysemu/hvf.h" diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 623c051339..2a42a67130 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" +#include "qemu-common.h" #include "x86_decode.h" #include "string.h" #include "vmx.h" diff --git a/target/i386/hvf/x86_decode.h b/target/i386/hvf/x86_decode.h index 329131360f..3e1eca0cdb 100644 --- a/target/i386/hvf/x86_decode.h +++ b/target/i386/hvf/x86_decode.h @@ -15,15 +15,11 @@ * License along with this program; if not, see . */ -#pragma once +#ifndef HVF_X86_DECODE_H +#define HVF_X86_DECODE_H 1 -#include -#include -#include -#include -#include "qemu-common.h" -#include "x86.h" #include "cpu.h" +#include "x86.h" typedef enum x86_prefix { /* group 1 */ @@ -323,3 +319,5 @@ void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op); void set_addressing_size(CPUX86State *env, struct x86_decode *decode); void set_operand_size(CPUX86State *env, struct x86_decode *decode); + +#endif diff --git a/target/i386/hvf/x86_descr.c b/target/i386/hvf/x86_descr.c index 0b9562818f..b4a7cdd2a7 100644 --- a/target/i386/hvf/x86_descr.c +++ b/target/i386/hvf/x86_descr.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" +#include "qemu-common.h" #include "vmx.h" #include "x86_descr.h" diff --git a/target/i386/hvf/x86_descr.h b/target/i386/hvf/x86_descr.h index 1285dd3897..034d8e95c5 100644 --- a/target/i386/hvf/x86_descr.h +++ b/target/i386/hvf/x86_descr.h @@ -16,7 +16,8 @@ * License along with this program; if not, see . */ -#pragma once +#ifndef HVF_X86_DESCR_H +#define HVF_X86_DESCR_H 1 #include "x86.h" @@ -53,3 +54,5 @@ uint32_t vmx_read_segment_ar(CPUState *cpu, x86_reg_segment seg); void vmx_segment_to_x86_descriptor(struct CPUState *cpu, struct vmx_segment *vmx_desc, struct x86_segment_descriptor *desc); + +#endif diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index c833774485..d2693f21f4 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -22,8 +22,8 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu-common.h" #include "cpu.h" #include "x86_flags.h" #include "x86.h" diff --git a/target/i386/hvf/x86_gen.h b/target/i386/hvf/x86_gen.h index 2045b0e69d..69edeffb19 100644 --- a/target/i386/hvf/x86_gen.h +++ b/target/i386/hvf/x86_gen.h @@ -18,10 +18,6 @@ #ifndef __X86_GEN_H__ #define __X86_GEN_H__ -#include -#include -#include "qemu-common.h" - typedef uint64_t addr_t; #define VM_PANIC(x) {\ diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index c7a72d1890..371a4b3f4d 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -18,8 +18,8 @@ */ #include "qemu/osdep.h" -#include "qemu-common.h" +#include "qemu-common.h" #include "x86hvf.h" #include "vmx.h" #include "vmcs.h" From 6701d81d74b3fbc7afd73a18d1c82602a811e409 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 13:59:15 +0200 Subject: [PATCH 386/546] i386: hvf: unify register enums between HVF and the rest Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 58 ++++++++------ target/i386/hvf/vmx.h | 10 +-- target/i386/hvf/x86.c | 10 +-- target/i386/hvf/x86.h | 145 +++++++++++------------------------ target/i386/hvf/x86_decode.c | 80 +++++++++---------- target/i386/hvf/x86_decode.h | 2 +- target/i386/hvf/x86_descr.c | 26 +++---- target/i386/hvf/x86_descr.h | 16 ++-- target/i386/hvf/x86_emu.c | 66 ++++++++-------- target/i386/hvf/x86_task.c | 48 ++++++------ target/i386/hvf/x86hvf.c | 32 ++++---- 11 files changed, 224 insertions(+), 269 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index de9d74acaf..62c4742703 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -56,30 +56,44 @@ #include "fpu/softfloat.h" #endif -#define R_EAX 0 -#define R_ECX 1 -#define R_EDX 2 -#define R_EBX 3 -#define R_ESP 4 -#define R_EBP 5 -#define R_ESI 6 -#define R_EDI 7 +enum { + R_EAX = 0, + R_ECX = 1, + R_EDX = 2, + R_EBX = 3, + R_ESP = 4, + R_EBP = 5, + R_ESI = 6, + R_EDI = 7, + R_R8 = 8, + R_R9 = 9, + R_R10 = 10, + R_R11 = 11, + R_R12 = 12, + R_R13 = 13, + R_R14 = 14, + R_R15 = 15, -#define R_AL 0 -#define R_CL 1 -#define R_DL 2 -#define R_BL 3 -#define R_AH 4 -#define R_CH 5 -#define R_DH 6 -#define R_BH 7 + R_AL = 0, + R_CL = 1, + R_DL = 2, + R_BL = 3, + R_AH = 4, + R_CH = 5, + R_DH = 6, + R_BH = 7, +}; -#define R_ES 0 -#define R_CS 1 -#define R_SS 2 -#define R_DS 3 -#define R_FS 4 -#define R_GS 5 +typedef enum X86Seg { + R_ES = 0, + R_CS = 1, + R_SS = 2, + R_DS = 3, + R_FS = 4, + R_GS = 5, + R_LDTR = 6, + R_TR = 7, +} X86Seg; /* segment descriptor fields */ #define DESC_G_SHIFT 23 diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 102075d0d4..9dfcd2f2eb 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -88,14 +88,14 @@ static void enter_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer) { uint64_t entry_ctls; - efer |= EFER_LMA; + efer |= MSR_EFER_LMA; wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer); entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); wvmcs(vcpu, VMCS_ENTRY_CTLS, rvmcs(vcpu, VMCS_ENTRY_CTLS) | VM_ENTRY_GUEST_LMA); uint64_t guest_tr_ar = rvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS); - if ((efer & EFER_LME) && + if ((efer & MSR_EFER_LME) && (guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { wvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS, (guest_tr_ar & ~AR_TYPE_MASK) | AR_TYPE_BUSY_64_TSS); @@ -109,7 +109,7 @@ static void exit_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer) entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS); wvmcs(vcpu, VMCS_ENTRY_CTLS, entry_ctls & ~VM_ENTRY_GUEST_LMA); - efer &= ~EFER_LMA; + efer &= ~MSR_EFER_LMA; wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer); } @@ -121,7 +121,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0); if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) && - !(efer & EFER_LME)) { + !(efer & MSR_EFER_LME)) { address_space_rw(&address_space_memory, rvmcs(vcpu, VMCS_GUEST_CR3) & ~0x1f, MEMTXATTRS_UNSPECIFIED, @@ -138,7 +138,7 @@ static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0) cr0 &= ~CR0_CD; wvmcs(vcpu, VMCS_GUEST_CR0, cr0 | CR0_NE | CR0_ET); - if (efer & EFER_LME) { + if (efer & MSR_EFER_LME) { if (!(old_cr0 & CR0_PG) && (cr0 & CR0_PG)) { enter_long_mode(vcpu, cr0, efer); } diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index 625ea6cac0..ca0ec2968a 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -134,13 +134,13 @@ bool x86_is_v8086(struct CPUState *cpu) bool x86_is_long_mode(struct CPUState *cpu) { - return rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER) & EFER_LMA; + return rvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA; } bool x86_is_long64_mode(struct CPUState *cpu) { struct vmx_segment desc; - vmx_read_segment_descriptor(cpu, &desc, REG_SEG_CS); + vmx_read_segment_descriptor(cpu, &desc, R_CS); return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1); } @@ -157,13 +157,13 @@ bool x86_is_pae_enabled(struct CPUState *cpu) return cr4 & CR4_PAE; } -addr_t linear_addr(struct CPUState *cpu, addr_t addr, x86_reg_segment seg) +addr_t linear_addr(struct CPUState *cpu, addr_t addr, X86Seg seg) { return vmx_read_segment_base(cpu, seg) + addr; } addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, - x86_reg_segment seg) + X86Seg seg) { switch (size) { case 2: @@ -180,5 +180,5 @@ addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, addr_t linear_rip(struct CPUState *cpu, addr_t rip) { - return linear_addr(cpu, rip, REG_SEG_CS); + return linear_addr(cpu, rip, R_CS); } diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 2dc55477a5..92a8ee1be8 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -21,57 +21,6 @@ #include "x86_gen.h" -/* exceptions */ -typedef enum x86_exception { - EXCEPTION_DE, /* divide error */ - EXCEPTION_DB, /* debug fault */ - EXCEPTION_NMI, /* non-maskable interrupt */ - EXCEPTION_BP, /* breakpoint trap */ - EXCEPTION_OF, /* overflow trap */ - EXCEPTION_BR, /* boundary range exceeded fault */ - EXCEPTION_UD, /* undefined opcode */ - EXCEPTION_NM, /* device not available */ - EXCEPTION_DF, /* double fault */ - EXCEPTION_RSVD, /* not defined */ - EXCEPTION_TS, /* invalid TSS fault */ - EXCEPTION_NP, /* not present fault */ - EXCEPTION_GP, /* general protection fault */ - EXCEPTION_PF, /* page fault */ - EXCEPTION_RSVD2, /* not defined */ -} x86_exception; - -/* general purpose regs */ -typedef enum x86_reg_name { - REG_RAX = 0, - REG_RCX = 1, - REG_RDX = 2, - REG_RBX = 3, - REG_RSP = 4, - REG_RBP = 5, - REG_RSI = 6, - REG_RDI = 7, - REG_R8 = 8, - REG_R9 = 9, - REG_R10 = 10, - REG_R11 = 11, - REG_R12 = 12, - REG_R13 = 13, - REG_R14 = 14, - REG_R15 = 15, -} x86_reg_name; - -/* segment regs */ -typedef enum x86_reg_segment { - REG_SEG_ES = 0, - REG_SEG_CS = 1, - REG_SEG_SS = 2, - REG_SEG_DS = 3, - REG_SEG_FS = 4, - REG_SEG_GS = 5, - REG_SEG_LDTR = 6, - REG_SEG_TR = 7, -} x86_reg_segment; - typedef struct x86_register { union { struct { @@ -153,15 +102,6 @@ typedef struct x86_reg_flags { }; } __attribute__ ((__packed__)) x86_reg_flags; -typedef enum x86_reg_efer { - EFER_SCE = (1L << 0), - EFER_LME = (1L << 8), - EFER_LMA = (1L << 10), - EFER_NXE = (1L << 11), - EFER_SVME = (1L << 12), - EFER_FXSR = (1L << 14), -} x86_reg_efer; - typedef struct x86_efer { uint64_t efer; } __attribute__ ((__packed__)) x86_efer; @@ -376,54 +316,54 @@ struct HVFX86EmulatorState { #define EFLAGS(cpu) (cpu->hvf_emul->rflags.eflags) #define RRX(cpu, reg) (cpu->hvf_emul->regs[reg].rrx) -#define RAX(cpu) RRX(cpu, REG_RAX) -#define RCX(cpu) RRX(cpu, REG_RCX) -#define RDX(cpu) RRX(cpu, REG_RDX) -#define RBX(cpu) RRX(cpu, REG_RBX) -#define RSP(cpu) RRX(cpu, REG_RSP) -#define RBP(cpu) RRX(cpu, REG_RBP) -#define RSI(cpu) RRX(cpu, REG_RSI) -#define RDI(cpu) RRX(cpu, REG_RDI) -#define R8(cpu) RRX(cpu, REG_R8) -#define R9(cpu) RRX(cpu, REG_R9) -#define R10(cpu) RRX(cpu, REG_R10) -#define R11(cpu) RRX(cpu, REG_R11) -#define R12(cpu) RRX(cpu, REG_R12) -#define R13(cpu) RRX(cpu, REG_R13) -#define R14(cpu) RRX(cpu, REG_R14) -#define R15(cpu) RRX(cpu, REG_R15) +#define RAX(cpu) RRX(cpu, R_EAX) +#define RCX(cpu) RRX(cpu, R_ECX) +#define RDX(cpu) RRX(cpu, R_EDX) +#define RBX(cpu) RRX(cpu, R_EBX) +#define RSP(cpu) RRX(cpu, R_ESP) +#define RBP(cpu) RRX(cpu, R_EBP) +#define RSI(cpu) RRX(cpu, R_ESI) +#define RDI(cpu) RRX(cpu, R_EDI) +#define R8(cpu) RRX(cpu, R_R8) +#define R9(cpu) RRX(cpu, R_R9) +#define R10(cpu) RRX(cpu, R_R10) +#define R11(cpu) RRX(cpu, R_R11) +#define R12(cpu) RRX(cpu, R_R12) +#define R13(cpu) RRX(cpu, R_R13) +#define R14(cpu) RRX(cpu, R_R14) +#define R15(cpu) RRX(cpu, R_R15) #define ERX(cpu, reg) (cpu->hvf_emul->regs[reg].erx) -#define EAX(cpu) ERX(cpu, REG_RAX) -#define ECX(cpu) ERX(cpu, REG_RCX) -#define EDX(cpu) ERX(cpu, REG_RDX) -#define EBX(cpu) ERX(cpu, REG_RBX) -#define ESP(cpu) ERX(cpu, REG_RSP) -#define EBP(cpu) ERX(cpu, REG_RBP) -#define ESI(cpu) ERX(cpu, REG_RSI) -#define EDI(cpu) ERX(cpu, REG_RDI) +#define EAX(cpu) ERX(cpu, R_EAX) +#define ECX(cpu) ERX(cpu, R_ECX) +#define EDX(cpu) ERX(cpu, R_EDX) +#define EBX(cpu) ERX(cpu, R_EBX) +#define ESP(cpu) ERX(cpu, R_ESP) +#define EBP(cpu) ERX(cpu, R_EBP) +#define ESI(cpu) ERX(cpu, R_ESI) +#define EDI(cpu) ERX(cpu, R_EDI) #define RX(cpu, reg) (cpu->hvf_emul->regs[reg].rx) -#define AX(cpu) RX(cpu, REG_RAX) -#define CX(cpu) RX(cpu, REG_RCX) -#define DX(cpu) RX(cpu, REG_RDX) -#define BP(cpu) RX(cpu, REG_RBP) -#define SP(cpu) RX(cpu, REG_RSP) -#define BX(cpu) RX(cpu, REG_RBX) -#define SI(cpu) RX(cpu, REG_RSI) -#define DI(cpu) RX(cpu, REG_RDI) +#define AX(cpu) RX(cpu, R_EAX) +#define CX(cpu) RX(cpu, R_ECX) +#define DX(cpu) RX(cpu, R_EDX) +#define BP(cpu) RX(cpu, R_EBP) +#define SP(cpu) RX(cpu, R_ESP) +#define BX(cpu) RX(cpu, R_EBX) +#define SI(cpu) RX(cpu, R_ESI) +#define DI(cpu) RX(cpu, R_EDI) #define RL(cpu, reg) (cpu->hvf_emul->regs[reg].lx) -#define AL(cpu) RL(cpu, REG_RAX) -#define CL(cpu) RL(cpu, REG_RCX) -#define DL(cpu) RL(cpu, REG_RDX) -#define BL(cpu) RL(cpu, REG_RBX) +#define AL(cpu) RL(cpu, R_EAX) +#define CL(cpu) RL(cpu, R_ECX) +#define DL(cpu) RL(cpu, R_EDX) +#define BL(cpu) RL(cpu, R_EBX) #define RH(cpu, reg) (cpu->hvf_emul->regs[reg].hx) -#define AH(cpu) RH(cpu, REG_RAX) -#define CH(cpu) RH(cpu, REG_RCX) -#define DH(cpu) RH(cpu, REG_RDX) -#define BH(cpu) RH(cpu, REG_RBX) +#define AH(cpu) RH(cpu, R_EAX) +#define CH(cpu) RH(cpu, R_ECX) +#define DH(cpu) RH(cpu, R_EDX) +#define BH(cpu) RH(cpu, R_EBX) /* deal with GDT/LDT descriptors in memory */ bool x86_read_segment_descriptor(struct CPUState *cpu, @@ -445,9 +385,10 @@ bool x86_is_long64_mode(struct CPUState *cpu); bool x86_is_paging_mode(struct CPUState *cpu); bool x86_is_pae_enabled(struct CPUState *cpu); -addr_t linear_addr(struct CPUState *cpu, addr_t addr, x86_reg_segment seg); +enum X86Seg; +addr_t linear_addr(struct CPUState *cpu, addr_t addr, enum X86Seg seg); addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, - x86_reg_segment seg); + enum X86Seg seg); addr_t linear_rip(struct CPUState *cpu, addr_t rip); static inline uint64_t rdtscp(void) diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 2a42a67130..6488bf72d1 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -121,7 +121,7 @@ static void decode_rax(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { op->type = X86_VAR_REG; - op->reg = REG_RAX; + op->reg = R_EAX; op->ptr = get_reg_ref(env, op->reg, 0, decode->operand_size); } @@ -213,22 +213,22 @@ static void decode_pushseg(CPUX86State *env, struct x86_decode *decode) decode->op[0].type = X86_VAR_REG; switch (op) { case 0xe: - decode->op[0].reg = REG_SEG_CS; + decode->op[0].reg = R_CS; break; case 0x16: - decode->op[0].reg = REG_SEG_SS; + decode->op[0].reg = R_SS; break; case 0x1e: - decode->op[0].reg = REG_SEG_DS; + decode->op[0].reg = R_DS; break; case 0x06: - decode->op[0].reg = REG_SEG_ES; + decode->op[0].reg = R_ES; break; case 0xa0: - decode->op[0].reg = REG_SEG_FS; + decode->op[0].reg = R_FS; break; case 0xa8: - decode->op[0].reg = REG_SEG_GS; + decode->op[0].reg = R_GS; break; } } @@ -240,22 +240,22 @@ static void decode_popseg(CPUX86State *env, struct x86_decode *decode) decode->op[0].type = X86_VAR_REG; switch (op) { case 0xf: - decode->op[0].reg = REG_SEG_CS; + decode->op[0].reg = R_CS; break; case 0x17: - decode->op[0].reg = REG_SEG_SS; + decode->op[0].reg = R_SS; break; case 0x1f: - decode->op[0].reg = REG_SEG_DS; + decode->op[0].reg = R_DS; break; case 0x07: - decode->op[0].reg = REG_SEG_ES; + decode->op[0].reg = R_ES; break; case 0xa1: - decode->op[0].reg = REG_SEG_FS; + decode->op[0].reg = R_FS; break; case 0xa9: - decode->op[0].reg = REG_SEG_GS; + decode->op[0].reg = R_GS; break; } } @@ -412,7 +412,7 @@ static void decode_rcx(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { op->type = X86_VAR_REG; - op->reg = REG_RCX; + op->reg = R_ECX; op->ptr = get_reg_ref(env, op->reg, decode->rex.b, decode->operand_size); } @@ -1639,7 +1639,7 @@ void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { addr_t ptr = 0; - x86_reg_segment seg = REG_SEG_DS; + X86Seg seg = R_DS; if (!decode->modrm.mod && 6 == decode->modrm.rm) { op->ptr = (uint16_t)decode->displacement; @@ -1659,11 +1659,11 @@ void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, break; case 2: ptr += BP(env) + SI(env); - seg = REG_SEG_SS; + seg = R_SS; break; case 3: ptr += BP(env) + DI(env); - seg = REG_SEG_SS; + seg = R_SS; break; case 4: ptr += SI(env); @@ -1673,7 +1673,7 @@ void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, break; case 6: ptr += BP(env); - seg = REG_SEG_SS; + seg = R_SS; break; case 7: ptr += BX(env); @@ -1693,7 +1693,7 @@ addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size) int which = 0; if (is_extended) { - reg |= REG_R8; + reg |= R_R8; } @@ -1723,7 +1723,7 @@ addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size) } static addr_t get_sib_val(CPUX86State *env, struct x86_decode *decode, - x86_reg_segment *sel) + X86Seg *sel) { addr_t base = 0; addr_t scaled_index = 0; @@ -1731,23 +1731,23 @@ static addr_t get_sib_val(CPUX86State *env, struct x86_decode *decode, int base_reg = decode->sib.base; int index_reg = decode->sib.index; - *sel = REG_SEG_DS; + *sel = R_DS; - if (decode->modrm.mod || base_reg != REG_RBP) { + if (decode->modrm.mod || base_reg != R_EBP) { if (decode->rex.b) { - base_reg |= REG_R8; + base_reg |= R_R8; } - if (REG_RSP == base_reg || REG_RBP == base_reg) { - *sel = REG_SEG_SS; + if (base_reg == R_ESP || base_reg == R_EBP) { + *sel = R_SS; } base = get_reg_val(env, decode->sib.base, decode->rex.b, addr_size); } if (decode->rex.x) { - index_reg |= REG_R8; + index_reg |= R_R8; } - if (index_reg != REG_RSP) { + if (index_reg != R_ESP) { scaled_index = get_reg_val(env, index_reg, decode->rex.x, addr_size) << decode->sib.scale; } @@ -1757,7 +1757,7 @@ static addr_t get_sib_val(CPUX86State *env, struct x86_decode *decode, void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { - x86_reg_segment seg = REG_SEG_DS; + X86Seg seg = R_DS; addr_t ptr = 0; int addr_size = decode->addressing_size; @@ -1774,8 +1774,8 @@ void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, ptr = decode->displacement; } } else { - if (REG_RBP == decode->modrm.rm || REG_RSP == decode->modrm.rm) { - seg = REG_SEG_SS; + if (decode->modrm.rm == R_EBP || decode->modrm.rm == R_ESP) { + seg = R_SS; } ptr += get_reg_val(env, decode->modrm.rm, decode->rex.b, addr_size); } @@ -1790,7 +1790,7 @@ void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { - x86_reg_segment seg = REG_SEG_DS; + X86Seg seg = R_DS; int32_t offset = 0; int mod = decode->modrm.mod; int rm = decode->modrm.rm; @@ -1895,7 +1895,7 @@ void set_addressing_size(CPUX86State *env, struct x86_decode *decode) } else if (!x86_is_long_mode(ENV_GET_CPU(env))) { /* protected */ struct vmx_segment cs; - vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, REG_SEG_CS); + vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, R_CS); /* check db */ if ((cs.ar >> 14) & 1) { if (decode->addr_size_override) { @@ -1932,7 +1932,7 @@ void set_operand_size(CPUX86State *env, struct x86_decode *decode) } else if (!x86_is_long_mode(ENV_GET_CPU(env))) { /* protected */ struct vmx_segment cs; - vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, REG_SEG_CS); + vmx_read_segment_descriptor(ENV_GET_CPU(env), &cs, R_CS); /* check db */ if ((cs.ar >> 14) & 1) { if (decode->op_size_override) { @@ -2159,26 +2159,26 @@ const char *decode_cmd_to_string(enum x86_decode_cmd cmd) } addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, - addr_t addr, x86_reg_segment seg) + addr_t addr, X86Seg seg) { switch (decode->segment_override) { case PREFIX_CS_SEG_OVEERIDE: - seg = REG_SEG_CS; + seg = R_CS; break; case PREFIX_SS_SEG_OVEERIDE: - seg = REG_SEG_SS; + seg = R_SS; break; case PREFIX_DS_SEG_OVEERIDE: - seg = REG_SEG_DS; + seg = R_DS; break; case PREFIX_ES_SEG_OVEERIDE: - seg = REG_SEG_ES; + seg = R_ES; break; case PREFIX_FS_SEG_OVEERIDE: - seg = REG_SEG_FS; + seg = R_FS; break; case PREFIX_GS_SEG_OVEERIDE: - seg = REG_SEG_GS; + seg = R_GS; break; default: break; diff --git a/target/i386/hvf/x86_decode.h b/target/i386/hvf/x86_decode.h index 3e1eca0cdb..b3dc88e167 100644 --- a/target/i386/hvf/x86_decode.h +++ b/target/i386/hvf/x86_decode.h @@ -308,7 +308,7 @@ addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size); void calc_modrm_operand(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op); addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, - addr_t addr, x86_reg_segment seg); + addr_t addr, enum X86Seg seg); void init_decoder(void); void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, diff --git a/target/i386/hvf/x86_descr.c b/target/i386/hvf/x86_descr.c index b4a7cdd2a7..8c05c34f33 100644 --- a/target/i386/hvf/x86_descr.c +++ b/target/i386/hvf/x86_descr.c @@ -22,12 +22,12 @@ #include "vmx.h" #include "x86_descr.h" -#define VMX_SEGMENT_FIELD(seg) \ - [REG_SEG_##seg] = { \ - .selector = VMCS_GUEST_##seg##_SELECTOR, \ - .base = VMCS_GUEST_##seg##_BASE, \ - .limit = VMCS_GUEST_##seg##_LIMIT, \ - .ar_bytes = VMCS_GUEST_##seg##_ACCESS_RIGHTS, \ +#define VMX_SEGMENT_FIELD(seg) \ + [R_##seg] = { \ + .selector = VMCS_GUEST_##seg##_SELECTOR, \ + .base = VMCS_GUEST_##seg##_BASE, \ + .limit = VMCS_GUEST_##seg##_LIMIT, \ + .ar_bytes = VMCS_GUEST_##seg##_ACCESS_RIGHTS, \ } static const struct vmx_segment_field { @@ -46,34 +46,34 @@ static const struct vmx_segment_field { VMX_SEGMENT_FIELD(TR), }; -uint32_t vmx_read_segment_limit(CPUState *cpu, x86_reg_segment seg) +uint32_t vmx_read_segment_limit(CPUState *cpu, X86Seg seg) { return (uint32_t)rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].limit); } -uint32_t vmx_read_segment_ar(CPUState *cpu, x86_reg_segment seg) +uint32_t vmx_read_segment_ar(CPUState *cpu, X86Seg seg) { return (uint32_t)rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].ar_bytes); } -uint64_t vmx_read_segment_base(CPUState *cpu, x86_reg_segment seg) +uint64_t vmx_read_segment_base(CPUState *cpu, X86Seg seg) { return rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].base); } -x68_segment_selector vmx_read_segment_selector(CPUState *cpu, x86_reg_segment seg) +x68_segment_selector vmx_read_segment_selector(CPUState *cpu, X86Seg seg) { x68_segment_selector sel; sel.sel = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector); return sel; } -void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, x86_reg_segment seg) +void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, X86Seg seg) { wvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector, selector.sel); } -void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, x86_reg_segment seg) +void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, X86Seg seg) { desc->sel = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].selector); desc->base = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].base); @@ -81,7 +81,7 @@ void vmx_read_segment_descriptor(struct CPUState *cpu, struct vmx_segment *desc, desc->ar = rvmcs(cpu->hvf_fd, vmx_segment_fields[seg].ar_bytes); } -void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, x86_reg_segment seg) +void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, X86Seg seg) { const struct vmx_segment_field *sf = &vmx_segment_fields[seg]; diff --git a/target/i386/hvf/x86_descr.h b/target/i386/hvf/x86_descr.h index 034d8e95c5..25a2b1731c 100644 --- a/target/i386/hvf/x86_descr.h +++ b/target/i386/hvf/x86_descr.h @@ -30,18 +30,18 @@ typedef struct vmx_segment { /* deal with vmstate descriptors */ void vmx_read_segment_descriptor(struct CPUState *cpu, - struct vmx_segment *desc, x86_reg_segment seg); + struct vmx_segment *desc, enum X86Seg seg); void vmx_write_segment_descriptor(CPUState *cpu, struct vmx_segment *desc, - x86_reg_segment seg); + enum X86Seg seg); x68_segment_selector vmx_read_segment_selector(struct CPUState *cpu, - x86_reg_segment seg); + enum X86Seg seg); void vmx_write_segment_selector(struct CPUState *cpu, x68_segment_selector selector, - x86_reg_segment seg); + enum X86Seg seg); -uint64_t vmx_read_segment_base(struct CPUState *cpu, x86_reg_segment seg); -void vmx_write_segment_base(struct CPUState *cpu, x86_reg_segment seg, +uint64_t vmx_read_segment_base(struct CPUState *cpu, enum X86Seg seg); +void vmx_write_segment_base(struct CPUState *cpu, enum X86Seg seg, uint64_t base); void x86_segment_descriptor_to_vmx(struct CPUState *cpu, @@ -49,8 +49,8 @@ void x86_segment_descriptor_to_vmx(struct CPUState *cpu, struct x86_segment_descriptor *desc, struct vmx_segment *vmx_desc); -uint32_t vmx_read_segment_limit(CPUState *cpu, x86_reg_segment seg); -uint32_t vmx_read_segment_ar(CPUState *cpu, x86_reg_segment seg); +uint32_t vmx_read_segment_limit(CPUState *cpu, enum X86Seg seg); +uint32_t vmx_read_segment_ar(CPUState *cpu, enum X86Seg seg); void vmx_segment_to_x86_descriptor(struct CPUState *cpu, struct vmx_segment *vmx_desc, struct x86_segment_descriptor *desc); diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index f0f68f1c30..e063d01221 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -294,7 +294,7 @@ static void fetch_operands(struct CPUX86State *env, struct x86_decode *decode, case X86_VAR_OFFSET: decode->op[i].ptr = decode_linear_addr(env, decode, decode->op[i].ptr, - REG_SEG_DS); + R_DS); if (calc_val[i]) { decode->op[i].val = read_val_ext(env, decode->op[i].ptr, decode->operand_size); @@ -514,10 +514,10 @@ static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode void (*func)(struct CPUX86State *env, struct x86_decode *ins), int rep) { - addr_t rcx = read_reg(env, REG_RCX, decode->addressing_size); + addr_t rcx = read_reg(env, R_ECX, decode->addressing_size); while (rcx--) { func(env, decode); - write_reg(env, REG_RCX, rcx, decode->addressing_size); + write_reg(env, R_ECX, rcx, decode->addressing_size); if ((PREFIX_REP == rep) && !get_ZF(env)) { break; } @@ -530,13 +530,13 @@ static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) { addr_t addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, - REG_SEG_ES); + R_ES); hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 0, decode->operand_size, 1); vmx_write_mem(ENV_GET_CPU(env), addr, env->hvf_emul->mmio_buf, decode->operand_size); - string_increment_reg(env, REG_RDI, decode); + string_increment_reg(env, R_EDI, decode); } static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) @@ -552,13 +552,13 @@ static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + addr_t addr = decode_linear_addr(env, decode, RSI(env), R_DS); vmx_read_mem(ENV_GET_CPU(env), env->hvf_emul->mmio_buf, addr, decode->operand_size); hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 1, decode->operand_size, 1); - string_increment_reg(env, REG_RSI, decode); + string_increment_reg(env, R_ESI, decode); } static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) @@ -578,15 +578,15 @@ static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) addr_t dst_addr; addr_t val; - src_addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, - REG_SEG_ES); + R_ES); val = read_val_ext(env, src_addr, decode->operand_size); write_val_ext(env, dst_addr, val, decode->operand_size); - string_increment_reg(env, REG_RSI, decode); - string_increment_reg(env, REG_RDI, decode); + string_increment_reg(env, R_ESI, decode); + string_increment_reg(env, R_EDI, decode); } static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) @@ -605,9 +605,9 @@ static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) addr_t src_addr; addr_t dst_addr; - src_addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, - REG_SEG_ES); + R_ES); decode->op[0].type = X86_VAR_IMMEDIATE; decode->op[0].val = read_val_ext(env, src_addr, decode->operand_size); @@ -616,8 +616,8 @@ static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); - string_increment_reg(env, REG_RSI, decode); - string_increment_reg(env, REG_RDI, decode); + string_increment_reg(env, R_ESI, decode); + string_increment_reg(env, R_EDI, decode); } static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) @@ -636,11 +636,11 @@ static void exec_stos_single(struct CPUX86State *env, struct x86_decode *decode) addr_t addr; addr_t val; - addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, REG_SEG_ES); - val = read_reg(env, REG_RAX, decode->operand_size); + addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, R_ES); + val = read_reg(env, R_EAX, decode->operand_size); vmx_write_mem(ENV_GET_CPU(env), addr, &val, decode->operand_size); - string_increment_reg(env, REG_RDI, decode); + string_increment_reg(env, R_EDI, decode); } @@ -659,18 +659,18 @@ static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) { addr_t addr; - addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, REG_SEG_ES); + addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, R_ES); decode->op[1].type = X86_VAR_IMMEDIATE; vmx_read_mem(ENV_GET_CPU(env), &decode->op[1].val, addr, decode->operand_size); EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); - string_increment_reg(env, REG_RDI, decode); + string_increment_reg(env, R_EDI, decode); } static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) { decode->op[0].type = X86_VAR_REG; - decode->op[0].reg = REG_RAX; + decode->op[0].reg = R_EAX; if (decode->rep) { string_rep(env, decode, exec_scas_single, decode->rep); } else { @@ -685,11 +685,11 @@ static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) addr_t addr; addr_t val = 0; - addr = decode_linear_addr(env, decode, RSI(env), REG_SEG_DS); + addr = decode_linear_addr(env, decode, RSI(env), R_DS); vmx_read_mem(ENV_GET_CPU(env), &val, addr, decode->operand_size); - write_reg(env, REG_RAX, val, decode->operand_size); + write_reg(env, R_EAX, val, decode->operand_size); - string_increment_reg(env, REG_RSI, decode); + string_increment_reg(env, R_ESI, decode); } static void exec_lods(struct CPUX86State *env, struct x86_decode *decode) @@ -840,7 +840,7 @@ void simulate_wrmsr(struct CPUState *cpu) env->hvf_emul->efer.efer = data; /*printf("new efer %llx\n", EFER(cpu));*/ wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, data); - if (data & EFER_NXE) { + if (data & MSR_EFER_NXE) { hv_vcpu_invalidate_tlb(cpu->hvf_fd); } break; @@ -1465,14 +1465,14 @@ void load_regs(struct CPUState *cpu) CPUX86State *env = &x86_cpu->env; int i = 0; - RRX(env, REG_RAX) = rreg(cpu->hvf_fd, HV_X86_RAX); - RRX(env, REG_RBX) = rreg(cpu->hvf_fd, HV_X86_RBX); - RRX(env, REG_RCX) = rreg(cpu->hvf_fd, HV_X86_RCX); - RRX(env, REG_RDX) = rreg(cpu->hvf_fd, HV_X86_RDX); - RRX(env, REG_RSI) = rreg(cpu->hvf_fd, HV_X86_RSI); - RRX(env, REG_RDI) = rreg(cpu->hvf_fd, HV_X86_RDI); - RRX(env, REG_RSP) = rreg(cpu->hvf_fd, HV_X86_RSP); - RRX(env, REG_RBP) = rreg(cpu->hvf_fd, HV_X86_RBP); + RRX(env, R_EAX) = rreg(cpu->hvf_fd, HV_X86_RAX); + RRX(env, R_EBX) = rreg(cpu->hvf_fd, HV_X86_RBX); + RRX(env, R_ECX) = rreg(cpu->hvf_fd, HV_X86_RCX); + RRX(env, R_EDX) = rreg(cpu->hvf_fd, HV_X86_RDX); + RRX(env, R_ESI) = rreg(cpu->hvf_fd, HV_X86_RSI); + RRX(env, R_EDI) = rreg(cpu->hvf_fd, HV_X86_RDI); + RRX(env, R_ESP) = rreg(cpu->hvf_fd, HV_X86_RSP); + RRX(env, R_EBP) = rreg(cpu->hvf_fd, HV_X86_RBP); for (i = 8; i < 16; i++) { RRX(env, i) = rreg(cpu->hvf_fd, HV_X86_RAX + i); } diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index c8cb16d3fa..a9e1008663 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -54,12 +54,12 @@ static void save_state_to_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) tss->esi = ESI(env); tss->edi = EDI(env); - tss->es = vmx_read_segment_selector(cpu, REG_SEG_ES).sel; - tss->cs = vmx_read_segment_selector(cpu, REG_SEG_CS).sel; - tss->ss = vmx_read_segment_selector(cpu, REG_SEG_SS).sel; - tss->ds = vmx_read_segment_selector(cpu, REG_SEG_DS).sel; - tss->fs = vmx_read_segment_selector(cpu, REG_SEG_FS).sel; - tss->gs = vmx_read_segment_selector(cpu, REG_SEG_GS).sel; + tss->es = vmx_read_segment_selector(cpu, R_ES).sel; + tss->cs = vmx_read_segment_selector(cpu, R_CS).sel; + tss->ss = vmx_read_segment_selector(cpu, R_SS).sel; + tss->ds = vmx_read_segment_selector(cpu, R_DS).sel; + tss->fs = vmx_read_segment_selector(cpu, R_FS).sel; + tss->gs = vmx_read_segment_selector(cpu, R_GS).sel; } static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) @@ -82,22 +82,22 @@ static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) RSI(env) = tss->esi; RDI(env) = tss->edi; - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, REG_SEG_LDTR); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, REG_SEG_ES); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, REG_SEG_CS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, REG_SEG_SS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, REG_SEG_DS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, REG_SEG_FS); - vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, REG_SEG_GS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ldt}}, R_LDTR); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->es}}, R_ES); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->cs}}, R_CS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ss}}, R_SS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, R_DS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, R_FS); + vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, R_GS); #if 0 - load_segment(cpu, REG_SEG_LDTR, tss->ldt); - load_segment(cpu, REG_SEG_ES, tss->es); - load_segment(cpu, REG_SEG_CS, tss->cs); - load_segment(cpu, REG_SEG_SS, tss->ss); - load_segment(cpu, REG_SEG_DS, tss->ds); - load_segment(cpu, REG_SEG_FS, tss->fs); - load_segment(cpu, REG_SEG_GS, tss->gs); + load_segment(cpu, R_LDTR, tss->ldt); + load_segment(cpu, R_ES, tss->es); + load_segment(cpu, R_CS, tss->cs); + load_segment(cpu, R_SS, tss->ss); + load_segment(cpu, R_DS, tss->ds); + load_segment(cpu, R_FS, tss->fs); + load_segment(cpu, R_GS, tss->gs); #endif } @@ -139,8 +139,8 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea struct x86_segment_descriptor curr_tss_desc, next_tss_desc; int ret; - x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, REG_SEG_TR); - uint64_t old_tss_base = vmx_read_segment_base(cpu, REG_SEG_TR); + x68_segment_selector old_tss_sel = vmx_read_segment_selector(cpu, R_TR); + uint64_t old_tss_base = vmx_read_segment_base(cpu, R_TR); uint32_t desc_limit; struct x86_call_gate task_gate_desc; struct vmx_segment vmx_seg; @@ -157,7 +157,7 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea ret = x86_read_call_gate(cpu, &task_gate_desc, gate); dpl = task_gate_desc.dpl; - x68_segment_selector cs = vmx_read_segment_selector(cpu, REG_SEG_CS); + x68_segment_selector cs = vmx_read_segment_selector(cpu, R_CS); if (tss_sel.rpl > dpl || cs.rpl > dpl) ;//DPRINTF("emulate_gp"); } @@ -191,7 +191,7 @@ void vmx_handle_task_switch(CPUState *cpu, x68_segment_selector tss_sel, int rea macvm_set_cr0(cpu->hvf_fd, rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0) | CR0_TS); x86_segment_descriptor_to_vmx(cpu, tss_sel, &next_tss_desc, &vmx_seg); - vmx_write_segment_descriptor(cpu, &vmx_seg, REG_SEG_TR); + vmx_write_segment_descriptor(cpu, &vmx_seg, R_TR); store_regs(cpu); diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index 371a4b3f4d..71c0515073 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -107,28 +107,28 @@ void hvf_put_segments(CPUState *cpu_state) macvm_set_cr0(cpu_state->hvf_fd, env->cr[0]); hvf_set_segment(cpu_state, &seg, &env->segs[R_CS], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_CS); + vmx_write_segment_descriptor(cpu_state, &seg, R_CS); hvf_set_segment(cpu_state, &seg, &env->segs[R_DS], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_DS); + vmx_write_segment_descriptor(cpu_state, &seg, R_DS); hvf_set_segment(cpu_state, &seg, &env->segs[R_ES], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_ES); + vmx_write_segment_descriptor(cpu_state, &seg, R_ES); hvf_set_segment(cpu_state, &seg, &env->segs[R_SS], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_SS); + vmx_write_segment_descriptor(cpu_state, &seg, R_SS); hvf_set_segment(cpu_state, &seg, &env->segs[R_FS], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_FS); + vmx_write_segment_descriptor(cpu_state, &seg, R_FS); hvf_set_segment(cpu_state, &seg, &env->segs[R_GS], false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_GS); + vmx_write_segment_descriptor(cpu_state, &seg, R_GS); hvf_set_segment(cpu_state, &seg, &env->tr, true); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_TR); + vmx_write_segment_descriptor(cpu_state, &seg, R_TR); hvf_set_segment(cpu_state, &seg, &env->ldt, false); - vmx_write_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); + vmx_write_segment_descriptor(cpu_state, &seg, R_LDTR); hv_vcpu_flush(cpu_state->hvf_fd); } @@ -183,28 +183,28 @@ void hvf_get_segments(CPUState *cpu_state) env->interrupt_injected = -1; - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_CS); + vmx_read_segment_descriptor(cpu_state, &seg, R_CS); hvf_get_segment(&env->segs[R_CS], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_DS); + vmx_read_segment_descriptor(cpu_state, &seg, R_DS); hvf_get_segment(&env->segs[R_DS], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_ES); + vmx_read_segment_descriptor(cpu_state, &seg, R_ES); hvf_get_segment(&env->segs[R_ES], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_FS); + vmx_read_segment_descriptor(cpu_state, &seg, R_FS); hvf_get_segment(&env->segs[R_FS], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_GS); + vmx_read_segment_descriptor(cpu_state, &seg, R_GS); hvf_get_segment(&env->segs[R_GS], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_SS); + vmx_read_segment_descriptor(cpu_state, &seg, R_SS); hvf_get_segment(&env->segs[R_SS], &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_TR); + vmx_read_segment_descriptor(cpu_state, &seg, R_TR); hvf_get_segment(&env->tr, &seg); - vmx_read_segment_descriptor(cpu_state, &seg, REG_SEG_LDTR); + vmx_read_segment_descriptor(cpu_state, &seg, R_LDTR); hvf_get_segment(&env->ldt, &seg); env->idt.limit = rvmcs(cpu_state->hvf_fd, VMCS_GUEST_IDTR_LIMIT); From 746827825db4f695c0897f103cd13f1e916e5081 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 14:10:15 +0200 Subject: [PATCH 387/546] i386: hvf: remove more dead emulator code Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 2 -- target/i386/hvf/x86.h | 5 ----- target/i386/hvf/x86_decode.c | 22 +++++++++++----------- target/i386/hvf/x86_emu.c | 25 ++++++++----------------- target/i386/hvf/x86_flags.c | 10 ---------- target/i386/hvf/x86_flags.h | 1 - target/i386/hvf/x86_mmu.c | 6 ++---- target/i386/hvf/x86_task.c | 10 ---------- 8 files changed, 21 insertions(+), 60 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 445082c2cb..3e5e9f9472 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -738,7 +738,6 @@ int hvf_vcpu_exec(CPUState *cpu) uint32_t port = exit_qual >> 16; /*uint32_t rep = (exit_qual & 0x20) != 0;*/ -#if 1 if (!string && in) { uint64_t val = 0; load_regs(cpu); @@ -761,7 +760,6 @@ int hvf_vcpu_exec(CPUState *cpu) macvm_set_rip(cpu, rip + ins_len); break; } -#endif struct x86_decode decode; load_regs(cpu); diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 92a8ee1be8..cfcb9c95cc 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -102,10 +102,6 @@ typedef struct x86_reg_flags { }; } __attribute__ ((__packed__)) x86_reg_flags; -typedef struct x86_efer { - uint64_t efer; -} __attribute__ ((__packed__)) x86_efer; - typedef enum x86_reg_cr0 { CR0_PE = (1L << 0), CR0_MP = (1L << 1), @@ -305,7 +301,6 @@ struct HVFX86EmulatorState { struct x86_register regs[16]; struct x86_reg_flags rflags; struct lazy_flags lflags; - struct x86_efer efer; uint8_t mmio_buf[4096]; }; diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 6488bf72d1..759aa38ee0 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -631,7 +631,7 @@ static void decode_aegroup(CPUX86State *env, struct x86_decode *decode) } break; default: - VM_PANIC_ON_EX(1, "0xae: reg %d\n", decode->modrm.reg); + VM_PANIC_EX("0xae: reg %d\n", decode->modrm.reg); break; } } @@ -655,14 +655,14 @@ static void decode_d9_4(CPUX86State *env, struct x86_decode *decode) decode->cmd = X86_DECODE_CMD_FABS; break; case 0xe4: - VM_PANIC_ON_EX(1, "FTST"); + VM_PANIC("FTST"); break; case 0xe5: /* FXAM */ decode->cmd = X86_DECODE_CMD_FXAM; break; default: - VM_PANIC_ON_EX(1, "FLDENV"); + VM_PANIC("FLDENV"); break; } } @@ -671,16 +671,16 @@ static void decode_db_4(CPUX86State *env, struct x86_decode *decode) { switch (decode->modrm.modrm) { case 0xe0: - VM_PANIC_ON_EX(1, "unhandled FNENI: %x %x\n", decode->opcode[0], - decode->modrm.modrm); + VM_PANIC_EX("unhandled FNENI: %x %x\n", decode->opcode[0], + decode->modrm.modrm); break; case 0xe1: - VM_PANIC_ON_EX(1, "unhandled FNDISI: %x %x\n", decode->opcode[0], - decode->modrm.modrm); + VM_PANIC_EX("unhandled FNDISI: %x %x\n", decode->opcode[0], + decode->modrm.modrm); break; case 0xe2: - VM_PANIC_ON_EX(1, "unhandled FCLEX: %x %x\n", decode->opcode[0], - decode->modrm.modrm); + VM_PANIC_EX("unhandled FCLEX: %x %x\n", decode->opcode[0], + decode->modrm.modrm); break; case 0xe3: decode->cmd = X86_DECODE_CMD_FNINIT; @@ -689,8 +689,8 @@ static void decode_db_4(CPUX86State *env, struct x86_decode *decode) decode->cmd = X86_DECODE_CMD_FNSETPM; break; default: - VM_PANIC_ON_EX(1, "unhandled fpu opcode: %x %x\n", decode->opcode[0], - decode->modrm.modrm); + VM_PANIC_EX("unhandled fpu opcode: %x %x\n", decode->opcode[0], + decode->modrm.modrm); break; } } diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index e063d01221..ff146fa81b 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -837,7 +837,6 @@ void simulate_wrmsr(struct CPUState *cpu) abort(); break; case MSR_EFER: - env->hvf_emul->efer.efer = data; /*printf("new efer %llx\n", EFER(cpu));*/ wvmcs(cpu->hvf_fd, VMCS_GUEST_IA32_EFER, data); if (data & MSR_EFER_NXE) { @@ -1511,23 +1510,15 @@ bool exec_instruction(struct CPUX86State *env, struct x86_decode *ins) printf("%d, %llx: exec_instruction %s\n", hvf_vcpu_id(cpu), RIP(cpu), decode_cmd_to_string(ins->cmd));*/ - if (0 && ins->is_fpu) { - VM_PANIC("emulate fpu\n"); - } else { - if (!_cmd_handler[ins->cmd].handler) { - printf("Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), - ins->cmd, ins->opcode[0], - ins->opcode_len > 1 ? ins->opcode[1] : 0); - RIP(env) += ins->len; - return true; - } - - VM_PANIC_ON_EX(!_cmd_handler[ins->cmd].handler, - "Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), - ins->cmd, ins->opcode[0], - ins->opcode_len > 1 ? ins->opcode[1] : 0); - _cmd_handler[ins->cmd].handler(env, ins); + if (!_cmd_handler[ins->cmd].handler) { + printf("Unimplemented handler (%llx) for %d (%x %x) \n", RIP(env), + ins->cmd, ins->opcode[0], + ins->opcode_len > 1 ? ins->opcode[1] : 0); + RIP(env) += ins->len; + return true; } + + _cmd_handler[ins->cmd].handler(env, ins); return true; } diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index d2693f21f4..ea25a3b26f 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -301,16 +301,6 @@ void set_SF(CPUX86State *env, bool val) env->hvf_emul->lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; } -void set_OSZAPC(CPUX86State *env, uint32_t flags32) -{ - set_OF(env, env->hvf_emul->rflags.of); - set_SF(env, env->hvf_emul->rflags.sf); - set_ZF(env, env->hvf_emul->rflags.zf); - set_AF(env, env->hvf_emul->rflags.af); - set_PF(env, env->hvf_emul->rflags.pf); - set_CF(env, env->hvf_emul->rflags.cf); -} - void lflags_to_rflags(CPUX86State *env) { env->hvf_emul->rflags.cf = get_CF(env); diff --git a/target/i386/hvf/x86_flags.h b/target/i386/hvf/x86_flags.h index 57a524240c..3e487535ea 100644 --- a/target/i386/hvf/x86_flags.h +++ b/target/i386/hvf/x86_flags.h @@ -190,7 +190,6 @@ bool get_SF(CPUX86State *env); void set_SF(CPUX86State *env, bool val); bool get_OF(CPUX86State *env); void set_OF(CPUX86State *env, bool val); -void set_OSZAPC(CPUX86State *env, uint32_t flags32); void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf); diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index 26e9e95b0b..1084670c1d 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -238,8 +238,7 @@ void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes) int copy = MIN(bytes, 0x1000 - (gva & 0xfff)); if (!mmu_gva_to_gpa(cpu, gva, &gpa)) { - VM_PANIC_ON_EX(1, "%s: mmu_gva_to_gpa %llx failed\n", __func__, - gva); + VM_PANIC_EX("%s: mmu_gva_to_gpa %llx failed\n", __func__, gva); } else { address_space_rw(&address_space_memory, gpa, MEMTXATTRS_UNSPECIFIED, data, copy, 1); @@ -260,8 +259,7 @@ void vmx_read_mem(struct CPUState *cpu, void *data, addr_t gva, int bytes) int copy = MIN(bytes, 0x1000 - (gva & 0xfff)); if (!mmu_gva_to_gpa(cpu, gva, &gpa)) { - VM_PANIC_ON_EX(1, "%s: mmu_gva_to_gpa %llx failed\n", __func__, - gva); + VM_PANIC_EX("%s: mmu_gva_to_gpa %llx failed\n", __func__, gva); } address_space_rw(&address_space_memory, gpa, MEMTXATTRS_UNSPECIFIED, data, copy, 0); diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index a9e1008663..bb3c3457eb 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -89,16 +89,6 @@ static void load_state_from_tss32(CPUState *cpu, struct x86_tss_segment32 *tss) vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->ds}}, R_DS); vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->fs}}, R_FS); vmx_write_segment_selector(cpu, (x68_segment_selector){{tss->gs}}, R_GS); - -#if 0 - load_segment(cpu, R_LDTR, tss->ldt); - load_segment(cpu, R_ES, tss->es); - load_segment(cpu, R_CS, tss->cs); - load_segment(cpu, R_SS, tss->ss); - load_segment(cpu, R_DS, tss->ds); - load_segment(cpu, R_FS, tss->fs); - load_segment(cpu, R_GS, tss->gs); -#endif } static int task_switch_32(CPUState *cpu, x68_segment_selector tss_sel, x68_segment_selector old_tss_sel, From 715f396dfb6d35cf88392770bbc2ed89a6636b8d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 14:55:22 +0200 Subject: [PATCH 388/546] i386: hvf: remove ZERO_INIT macro Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86.c | 5 +++-- target/i386/hvf/x86_decode.c | 3 +-- target/i386/hvf/x86_gen.h | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index ca0ec2968a..efb28c373c 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -53,7 +53,8 @@ bool x86_read_segment_descriptor(struct CPUState *cpu, addr_t base; uint32_t limit; - ZERO_INIT(*desc); + memset(desc, 0, sizeof(*desc)); + /* valid gdt descriptors start from index 1 */ if (!sel.index && GDT_SEL == sel.ti) { return false; @@ -104,7 +105,7 @@ bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc, addr_t base = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE); uint32_t limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT); - ZERO_INIT(*idt_desc); + memset(idt_desc, 0, sizeof(*idt_desc)); if (gate * 8 >= limit) { printf("%s: idt limit\n", __func__); return false; diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 759aa38ee0..4bfd85f2df 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -2091,8 +2091,7 @@ static void decode_opcodes(CPUX86State *env, struct x86_decode *decode) uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode) { - ZERO_INIT(*decode); - + memset(decode, 0, sizeof(*decode)); decode_prefix(env, decode); set_addressing_size(env, decode); set_operand_size(env, decode); diff --git a/target/i386/hvf/x86_gen.h b/target/i386/hvf/x86_gen.h index 69edeffb19..e5739f1de5 100644 --- a/target/i386/hvf/x86_gen.h +++ b/target/i386/hvf/x86_gen.h @@ -44,6 +44,4 @@ typedef uint64_t addr_t; } \ } -#define ZERO_INIT(obj) memset((void *) &obj, 0, sizeof(obj)) - #endif From e62963bf48269f8942fe2f3c0c0f3e6778552207 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:00:47 +0200 Subject: [PATCH 389/546] i386: hvf: abort on decoding error Rather than unsupported situations, some VM_PANIC calls actually are caused by internal errors. Convert them to just abort. Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 2 +- target/i386/hvf/x86_emu.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 3e5e9f9472..8ceba73a5c 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -766,7 +766,7 @@ int hvf_vcpu_exec(CPUState *cpu) env->hvf_emul->fetch_rip = rip; decode_instruction(env, &decode); - VM_PANIC_ON(ins_len != decode.len); + assert(ins_len == decode.len); exec_instruction(env, &decode); store_regs(cpu); diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index ff146fa81b..5ecabc4230 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -146,7 +146,7 @@ addr_t read_reg(CPUX86State *env, int reg, int size) case 8: return env->hvf_emul->regs[reg].rrx; default: - VM_PANIC_ON("read_reg size"); + abort(); } return 0; } @@ -167,7 +167,7 @@ void write_reg(CPUX86State *env, int reg, addr_t val, int size) env->hvf_emul->regs[reg].rrx = val; break; default: - VM_PANIC_ON("write_reg size"); + abort(); } } @@ -189,8 +189,7 @@ addr_t read_val_from_reg(addr_t reg_ptr, int size) val = *(uint64_t *)reg_ptr; break; default: - VM_PANIC_ON_EX(1, "read_val: Unknown size %d\n", size); - break; + abort(); } return val; } @@ -211,8 +210,7 @@ void write_val_to_reg(addr_t reg_ptr, addr_t val, int size) *(uint64_t *)reg_ptr = val; break; default: - VM_PANIC("write_val: Unknown size\n"); - break; + abort(); } } From e8a632579dbf327679c6d2e47ca4285d6e97ec2c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 14:41:27 +0200 Subject: [PATCH 390/546] i386: hvf: simplify flag handling Remove much indirection and duplicate code, and provide a cleaner interface out of x86_flags.c. Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_emu.c | 93 ++++---------- target/i386/hvf/x86_flags.c | 235 +++++++++++++++++------------------- target/i386/hvf/x86_flags.h | 173 +------------------------- 3 files changed, 144 insertions(+), 357 deletions(-) diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 5ecabc4230..31b0807add 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -49,7 +49,7 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, int direction, int size, uint32_t count); -#define EXEC_2OP_LOGIC_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ +#define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ { \ fetch_operands(env, decode, 2, true, true, false); \ switch (decode->operand_size) { \ @@ -61,7 +61,7 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, if (save_res) { \ write_val_ext(env, decode->op[0].ptr, diff, 1); \ } \ - FLAGS_FUNC##_8(diff); \ + FLAGS_FUNC##8(env, v1, v2, diff); \ break; \ } \ case 2: \ @@ -72,7 +72,7 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, if (save_res) { \ write_val_ext(env, decode->op[0].ptr, diff, 2); \ } \ - FLAGS_FUNC##_16(diff); \ + FLAGS_FUNC##16(env, v1, v2, diff); \ break; \ } \ case 4: \ @@ -83,7 +83,7 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, if (save_res) { \ write_val_ext(env, decode->op[0].ptr, diff, 4); \ } \ - FLAGS_FUNC##_32(diff); \ + FLAGS_FUNC##32(env, v1, v2, diff); \ break; \ } \ default: \ @@ -91,49 +91,6 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, } \ } \ - -#define EXEC_2OP_ARITH_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ -{ \ - fetch_operands(env, decode, 2, true, true, false); \ - switch (decode->operand_size) { \ - case 1: \ - { \ - uint8_t v1 = (uint8_t)decode->op[0].val; \ - uint8_t v2 = (uint8_t)decode->op[1].val; \ - uint8_t diff = v1 cmd v2; \ - if (save_res) { \ - write_val_ext(env, decode->op[0].ptr, diff, 1); \ - } \ - FLAGS_FUNC##_8(v1, v2, diff); \ - break; \ - } \ - case 2: \ - { \ - uint16_t v1 = (uint16_t)decode->op[0].val; \ - uint16_t v2 = (uint16_t)decode->op[1].val; \ - uint16_t diff = v1 cmd v2; \ - if (save_res) { \ - write_val_ext(env, decode->op[0].ptr, diff, 2); \ - } \ - FLAGS_FUNC##_16(v1, v2, diff); \ - break; \ - } \ - case 4: \ - { \ - uint32_t v1 = (uint32_t)decode->op[0].val; \ - uint32_t v2 = (uint32_t)decode->op[1].val; \ - uint32_t diff = v1 cmd v2; \ - if (save_res) { \ - write_val_ext(env, decode->op[0].ptr, diff, 4); \ - } \ - FLAGS_FUNC##_32(v1, v2, diff); \ - break; \ - } \ - default: \ - VM_PANIC("bad size\n"); \ - } \ -} - addr_t read_reg(CPUX86State *env, int reg, int size) { switch (size) { @@ -315,49 +272,49 @@ static void exec_mov(struct CPUX86State *env, struct x86_decode *decode) static void exec_add(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); + EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); RIP(env) += decode->len; } static void exec_or(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_LOGIC_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); + EXEC_2OP_FLAGS_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); RIP(env) += decode->len; } static void exec_adc(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); + EXEC_2OP_FLAGS_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); RIP(env) += decode->len; } static void exec_sbb(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); + EXEC_2OP_FLAGS_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); RIP(env) += decode->len; } static void exec_and(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_LOGIC_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); + EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); RIP(env) += decode->len; } static void exec_sub(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); + EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); RIP(env) += decode->len; } static void exec_xor(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_LOGIC_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); + EXEC_2OP_FLAGS_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); RIP(env) += decode->len; } static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) { - /*EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ + /*EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ int32_t val; fetch_operands(env, decode, 2, true, true, false); @@ -365,11 +322,11 @@ static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) write_val_ext(env, decode->op[1].ptr, val, decode->operand_size); if (4 == decode->operand_size) { - SET_FLAGS_OSZAPC_SUB_32(0, 0 - val, val); + SET_FLAGS_OSZAPC_SUB32(env, 0, 0 - val, val); } else if (2 == decode->operand_size) { - SET_FLAGS_OSZAPC_SUB_16(0, 0 - val, val); + SET_FLAGS_OSZAPC_SUB16(env, 0, 0 - val, val); } else if (1 == decode->operand_size) { - SET_FLAGS_OSZAPC_SUB_8(0, 0 - val, val); + SET_FLAGS_OSZAPC_SUB8(env, 0, 0 - val, val); } else { VM_PANIC("bad op size\n"); } @@ -380,7 +337,7 @@ static void exec_neg(struct CPUX86State *env, struct x86_decode *decode) static void exec_cmp(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); RIP(env) += decode->len; } @@ -389,7 +346,7 @@ static void exec_inc(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].type = X86_VAR_IMMEDIATE; decode->op[1].val = 0; - EXEC_2OP_ARITH_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); + EXEC_2OP_FLAGS_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); RIP(env) += decode->len; } @@ -399,13 +356,13 @@ static void exec_dec(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].type = X86_VAR_IMMEDIATE; decode->op[1].val = 0; - EXEC_2OP_ARITH_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); + EXEC_2OP_FLAGS_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); RIP(env) += decode->len; } static void exec_tst(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_LOGIC_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); + EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); RIP(env) += decode->len; } @@ -612,7 +569,7 @@ static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].type = X86_VAR_IMMEDIATE; decode->op[1].val = read_val_ext(env, dst_addr, decode->operand_size); - EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); string_increment_reg(env, R_ESI, decode); string_increment_reg(env, R_EDI, decode); @@ -661,7 +618,7 @@ static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) decode->op[1].type = X86_VAR_IMMEDIATE; vmx_read_mem(ENV_GET_CPU(env), &decode->op[1].val, addr, decode->operand_size); - EXEC_2OP_ARITH_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); + EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); string_increment_reg(env, R_EDI, decode); } @@ -996,7 +953,7 @@ void exec_shl(struct CPUX86State *env, struct x86_decode *decode) } write_val_ext(env, decode->op[0].ptr, res, 1); - SET_FLAGS_OSZAPC_LOGIC_8(res); + SET_FLAGS_OSZAPC_LOGIC8(env, 0, 0, res); SET_FLAGS_OxxxxC(env, of, cf); break; } @@ -1012,7 +969,7 @@ void exec_shl(struct CPUX86State *env, struct x86_decode *decode) } write_val_ext(env, decode->op[0].ptr, res, 2); - SET_FLAGS_OSZAPC_LOGIC_16(res); + SET_FLAGS_OSZAPC_LOGIC16(env, 0, 0, res); SET_FLAGS_OxxxxC(env, of, cf); break; } @@ -1021,7 +978,7 @@ void exec_shl(struct CPUX86State *env, struct x86_decode *decode) uint32_t res = decode->op[0].val << count; write_val_ext(env, decode->op[0].ptr, res, 4); - SET_FLAGS_OSZAPC_LOGIC_32(res); + SET_FLAGS_OSZAPC_LOGIC32(env, 0, 0, res); cf = (decode->op[0].val >> (32 - count)) & 0x1; of = cf ^ (res >> 31); /* of = cf ^ result31 */ SET_FLAGS_OxxxxC(env, of, cf); @@ -1393,7 +1350,7 @@ static void exec_xchg(struct CPUX86State *env, struct x86_decode *decode) static void exec_xadd(struct CPUX86State *env, struct x86_decode *decode) { - EXEC_2OP_ARITH_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); + EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); write_val_ext(env, decode->op[1].ptr, decode->op[0].val, decode->operand_size); diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index ea25a3b26f..b0686c7962 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -28,6 +28,91 @@ #include "x86_flags.h" #include "x86.h" + +/* this is basically bocsh code */ + +#define LF_SIGN_BIT 31 + +#define LF_BIT_SD (0) /* lazy Sign Flag Delta */ +#define LF_BIT_AF (3) /* lazy Adjust flag */ +#define LF_BIT_PDB (8) /* lazy Parity Delta Byte (8 bits) */ +#define LF_BIT_CF (31) /* lazy Carry Flag */ +#define LF_BIT_PO (30) /* lazy Partial Overflow = CF ^ OF */ + +#define LF_MASK_SD (0x01 << LF_BIT_SD) +#define LF_MASK_AF (0x01 << LF_BIT_AF) +#define LF_MASK_PDB (0xFF << LF_BIT_PDB) +#define LF_MASK_CF (0x01 << LF_BIT_CF) +#define LF_MASK_PO (0x01 << LF_BIT_PO) + +#define ADD_COUT_VEC(op1, op2, result) \ + (((op1) & (op2)) | (((op1) | (op2)) & (~(result)))) + +#define SUB_COUT_VEC(op1, op2, result) \ + (((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result))) + +#define GET_ADD_OVERFLOW(op1, op2, result, mask) \ + ((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) + +/* ******************* */ +/* OSZAPC */ +/* ******************* */ + +/* size, carries, result */ +#define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ + addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ + env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ + if ((size) == 32) { \ + temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ + } else if ((size) == 16) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ + } else if ((size) == 8) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ + } else { \ + VM_PANIC("unimplemented"); \ + } \ + env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)temp; \ +} + +/* carries, result */ +#define SET_FLAGS_OSZAPC_8(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(8, carries, result) +#define SET_FLAGS_OSZAPC_16(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(16, carries, result) +#define SET_FLAGS_OSZAPC_32(carries, result) \ + SET_FLAGS_OSZAPC_SIZE(32, carries, result) + +/* ******************* */ +/* OSZAP */ +/* ******************* */ +/* size, carries, result */ +#define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \ + addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ + if ((size) == 32) { \ + temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ + } else if ((size) == 16) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ + } else if ((size) == 8) { \ + temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ + } else { \ + VM_PANIC("unimplemented"); \ + } \ + env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ + addr_t delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ + delta_c ^= (delta_c >> 1); \ + env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)(temp ^ delta_c); \ +} + +/* carries, result */ +#define SET_FLAGS_OSZAP_8(carries, result) \ + SET_FLAGS_OSZAP_SIZE(8, carries, result) +#define SET_FLAGS_OSZAP_16(carries, result) \ + SET_FLAGS_OSZAP_SIZE(16, carries, result) +#define SET_FLAGS_OSZAP_32(carries, result) \ + SET_FLAGS_OSZAP_SIZE(32, carries, result) + void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf) { uint32_t temp_po = new_of ^ new_cf; @@ -39,178 +124,92 @@ void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf) void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, uint32_t diff) { - SET_FLAGS_OSZAPC_SUB_32(v1, v2, diff); + SET_FLAGS_OSZAPC_32(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAPC_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, uint16_t diff) { - SET_FLAGS_OSZAPC_SUB_16(v1, v2, diff); + SET_FLAGS_OSZAPC_16(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAPC_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff) { - SET_FLAGS_OSZAPC_SUB_8(v1, v2, diff); + SET_FLAGS_OSZAPC_8(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAPC_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, uint32_t diff) { - SET_FLAGS_OSZAPC_ADD_32(v1, v2, diff); + SET_FLAGS_OSZAPC_32(ADD_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAPC_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, uint16_t diff) { - SET_FLAGS_OSZAPC_ADD_16(v1, v2, diff); + SET_FLAGS_OSZAPC_16(ADD_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAPC_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff) { - SET_FLAGS_OSZAPC_ADD_8(v1, v2, diff); + SET_FLAGS_OSZAPC_8(ADD_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, uint32_t diff) { - SET_FLAGS_OSZAP_SUB_32(v1, v2, diff); + SET_FLAGS_OSZAP_32(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_SUB16(CPUX86State *env, uint16_t v1, uint16_t v2, uint16_t diff) { - SET_FLAGS_OSZAP_SUB_16(v1, v2, diff); + SET_FLAGS_OSZAP_16(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_SUB8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff) { - SET_FLAGS_OSZAP_SUB_8(v1, v2, diff); + SET_FLAGS_OSZAP_8(SUB_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_ADD32(CPUX86State *env, uint32_t v1, uint32_t v2, uint32_t diff) { - SET_FLAGS_OSZAP_ADD_32(v1, v2, diff); + SET_FLAGS_OSZAP_32(ADD_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, uint16_t diff) { - SET_FLAGS_OSZAP_ADD_16(v1, v2, diff); + SET_FLAGS_OSZAP_16(ADD_COUT_VEC(v1, v2, diff), diff); } void SET_FLAGS_OSZAP_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff) { - SET_FLAGS_OSZAP_ADD_8(v1, v2, diff); + SET_FLAGS_OSZAP_8(ADD_COUT_VEC(v1, v2, diff), diff); } -void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t diff) +void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff) { - SET_FLAGS_OSZAPC_LOGIC_32(diff); + SET_FLAGS_OSZAPC_32(0, diff); } -void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t diff) +void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff) { - SET_FLAGS_OSZAPC_LOGIC_16(diff); + SET_FLAGS_OSZAPC_16(0, diff); } -void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t diff) +void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff) { - SET_FLAGS_OSZAPC_LOGIC_8(diff); -} - -void SET_FLAGS_SHR32(CPUX86State *env, uint32_t v, int count, uint32_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - int of = (((res << 1) ^ res) >> 31); - - SET_FLAGS_OSZAPC_LOGIC_32(res); - SET_FLAGS_OxxxxC(env, of, cf); -} - -void SET_FLAGS_SHR16(CPUX86State *env, uint16_t v, int count, uint16_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - int of = (((res << 1) ^ res) >> 15); - - SET_FLAGS_OSZAPC_LOGIC_16(res); - SET_FLAGS_OxxxxC(env, of, cf); -} - -void SET_FLAGS_SHR8(CPUX86State *env, uint8_t v, int count, uint8_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - int of = (((res << 1) ^ res) >> 7); - - SET_FLAGS_OSZAPC_LOGIC_8(res); - SET_FLAGS_OxxxxC(env, of, cf); -} - -void SET_FLAGS_SAR32(CPUX86State *env, int32_t v, int count, uint32_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - - SET_FLAGS_OSZAPC_LOGIC_32(res); - SET_FLAGS_OxxxxC(env, 0, cf); -} - -void SET_FLAGS_SAR16(CPUX86State *env, int16_t v, int count, uint16_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - - SET_FLAGS_OSZAPC_LOGIC_16(res); - SET_FLAGS_OxxxxC(env, 0, cf); -} - -void SET_FLAGS_SAR8(CPUX86State *env, int8_t v, int count, uint8_t res) -{ - int cf = (v >> (count - 1)) & 0x1; - - SET_FLAGS_OSZAPC_LOGIC_8(res); - SET_FLAGS_OxxxxC(env, 0, cf); -} - - -void SET_FLAGS_SHL32(CPUX86State *env, uint32_t v, int count, uint32_t res) -{ - int of, cf; - - cf = (v >> (32 - count)) & 0x1; - of = cf ^ (res >> 31); - - SET_FLAGS_OSZAPC_LOGIC_32(res); - SET_FLAGS_OxxxxC(env, of, cf); -} - -void SET_FLAGS_SHL16(CPUX86State *env, uint16_t v, int count, uint16_t res) -{ - int of = 0, cf = 0; - - if (count <= 16) { - cf = (v >> (16 - count)) & 0x1; - of = cf ^ (res >> 15); - } - - SET_FLAGS_OSZAPC_LOGIC_16(res); - SET_FLAGS_OxxxxC(env, of, cf); -} - -void SET_FLAGS_SHL8(CPUX86State *env, uint8_t v, int count, uint8_t res) -{ - int of = 0, cf = 0; - - if (count <= 8) { - cf = (v >> (8 - count)) & 0x1; - of = cf ^ (res >> 7); - } - - SET_FLAGS_OSZAPC_LOGIC_8(res); - SET_FLAGS_OxxxxC(env, of, cf); + SET_FLAGS_OSZAPC_8(0, diff); } bool get_PF(CPUX86State *env) @@ -228,34 +227,26 @@ void set_PF(CPUX86State *env, bool val) env->hvf_emul->lflags.auxbits |= (temp << LF_BIT_PDB); } -bool _get_OF(CPUX86State *env) +bool get_OF(CPUX86State *env) { return ((env->hvf_emul->lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; } -bool get_OF(CPUX86State *env) -{ - return _get_OF(env); -} - -bool _get_CF(CPUX86State *env) +bool get_CF(CPUX86State *env) { return (env->hvf_emul->lflags.auxbits >> LF_BIT_CF) & 1; } -bool get_CF(CPUX86State *env) -{ - return _get_CF(env); -} - void set_OF(CPUX86State *env, bool val) { - SET_FLAGS_OxxxxC(env, val, _get_CF(env)); + bool old_cf = get_CF(env); + SET_FLAGS_OxxxxC(env, val, old_cf); } void set_CF(CPUX86State *env, bool val) { - SET_FLAGS_OxxxxC(env, _get_OF(env), (val)); + bool old_of = get_OF(env); + SET_FLAGS_OxxxxC(env, old_of, val); } bool get_AF(CPUX86State *env) @@ -266,7 +257,7 @@ bool get_AF(CPUX86State *env) void set_AF(CPUX86State *env, bool val) { env->hvf_emul->lflags.auxbits &= ~(LF_MASK_AF); - env->hvf_emul->lflags.auxbits |= (val) << LF_BIT_AF; + env->hvf_emul->lflags.auxbits |= val << LF_BIT_AF; } bool get_ZF(CPUX86State *env) diff --git a/target/i386/hvf/x86_flags.h b/target/i386/hvf/x86_flags.h index 3e487535ea..13e5d5bd1a 100644 --- a/target/i386/hvf/x86_flags.h +++ b/target/i386/hvf/x86_flags.h @@ -25,156 +25,6 @@ #include "x86_gen.h" #include "cpu.h" - -/* this is basically bocsh code */ - -#define LF_SIGN_BIT 31 - -#define LF_BIT_SD (0) /* lazy Sign Flag Delta */ -#define LF_BIT_AF (3) /* lazy Adjust flag */ -#define LF_BIT_PDB (8) /* lazy Parity Delta Byte (8 bits) */ -#define LF_BIT_CF (31) /* lazy Carry Flag */ -#define LF_BIT_PO (30) /* lazy Partial Overflow = CF ^ OF */ - -#define LF_MASK_SD (0x01 << LF_BIT_SD) -#define LF_MASK_AF (0x01 << LF_BIT_AF) -#define LF_MASK_PDB (0xFF << LF_BIT_PDB) -#define LF_MASK_CF (0x01 << LF_BIT_CF) -#define LF_MASK_PO (0x01 << LF_BIT_PO) - -#define ADD_COUT_VEC(op1, op2, result) \ - (((op1) & (op2)) | (((op1) | (op2)) & (~(result)))) - -#define SUB_COUT_VEC(op1, op2, result) \ - (((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result))) - -#define GET_ADD_OVERFLOW(op1, op2, result, mask) \ - ((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) - -/* ******************* */ -/* OSZAPC */ -/* ******************* */ - -/* size, carries, result */ -#define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ - addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ - (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ - env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ - if ((size) == 32) { \ - temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ - } else if ((size) == 16) { \ - temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ - } else if ((size) == 8) { \ - temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ - } else { \ - VM_PANIC("unimplemented"); \ - } \ - env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)temp; \ -} - -/* carries, result */ -#define SET_FLAGS_OSZAPC_8(carries, result) \ - SET_FLAGS_OSZAPC_SIZE(8, carries, result) -#define SET_FLAGS_OSZAPC_16(carries, result) \ - SET_FLAGS_OSZAPC_SIZE(16, carries, result) -#define SET_FLAGS_OSZAPC_32(carries, result) \ - SET_FLAGS_OSZAPC_SIZE(32, carries, result) - -/* result */ -#define SET_FLAGS_OSZAPC_LOGIC_8(result_8) \ - SET_FLAGS_OSZAPC_8(0, (result_8)) -#define SET_FLAGS_OSZAPC_LOGIC_16(result_16) \ - SET_FLAGS_OSZAPC_16(0, (result_16)) -#define SET_FLAGS_OSZAPC_LOGIC_32(result_32) \ - SET_FLAGS_OSZAPC_32(0, (result_32)) -#define SET_FLAGS_OSZAPC_LOGIC_SIZE(size, result) { \ - if (32 == size) { \ - SET_FLAGS_OSZAPC_LOGIC_32(result); \ - } else if (16 == size) { \ - SET_FLAGS_OSZAPC_LOGIC_16(result); \ - } else if (8 == size) { \ - SET_FLAGS_OSZAPC_LOGIC_8(result); \ - } else { \ - VM_PANIC("unimplemented"); \ - } \ -} - -/* op1, op2, result */ -#define SET_FLAGS_OSZAPC_ADD_8(op1_8, op2_8, sum_8) \ - SET_FLAGS_OSZAPC_8(ADD_COUT_VEC((op1_8), (op2_8), (sum_8)), (sum_8)) -#define SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16) \ - SET_FLAGS_OSZAPC_16(ADD_COUT_VEC((op1_16), (op2_16), (sum_16)), (sum_16)) -#define SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32) \ - SET_FLAGS_OSZAPC_32(ADD_COUT_VEC((op1_32), (op2_32), (sum_32)), (sum_32)) - -/* op1, op2, result */ -#define SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8) \ - SET_FLAGS_OSZAPC_8(SUB_COUT_VEC((op1_8), (op2_8), (diff_8)), (diff_8)) -#define SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16) \ - SET_FLAGS_OSZAPC_16(SUB_COUT_VEC((op1_16), (op2_16), (diff_16)), (diff_16)) -#define SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32) \ - SET_FLAGS_OSZAPC_32(SUB_COUT_VEC((op1_32), (op2_32), (diff_32)), (diff_32)) - -/* ******************* */ -/* OSZAP */ -/* ******************* */ -/* size, carries, result */ -#define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \ - addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ - (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ - if ((size) == 32) { \ - temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ - } else if ((size) == 16) { \ - temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 16); \ - } else if ((size) == 8) { \ - temp = ((lf_carries) & (LF_MASK_AF)) | ((lf_carries) << 24); \ - } else { \ - VM_PANIC("unimplemented"); \ - } \ - env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ - addr_t delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ - delta_c ^= (delta_c >> 1); \ - env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)(temp ^ delta_c); \ -} - -/* carries, result */ -#define SET_FLAGS_OSZAP_8(carries, result) \ - SET_FLAGS_OSZAP_SIZE(8, carries, result) -#define SET_FLAGS_OSZAP_16(carries, result) \ - SET_FLAGS_OSZAP_SIZE(16, carries, result) -#define SET_FLAGS_OSZAP_32(carries, result) \ - SET_FLAGS_OSZAP_SIZE(32, carries, result) - -/* op1, op2, result */ -#define SET_FLAGS_OSZAP_ADD_8(op1_8, op2_8, sum_8) \ - SET_FLAGS_OSZAP_8(ADD_COUT_VEC((op1_8), (op2_8), (sum_8)), (sum_8)) -#define SET_FLAGS_OSZAP_ADD_16(op1_16, op2_16, sum_16) \ - SET_FLAGS_OSZAP_16(ADD_COUT_VEC((op1_16), (op2_16), (sum_16)), (sum_16)) -#define SET_FLAGS_OSZAP_ADD_32(op1_32, op2_32, sum_32) \ - SET_FLAGS_OSZAP_32(ADD_COUT_VEC((op1_32), (op2_32), (sum_32)), (sum_32)) - -/* op1, op2, result */ -#define SET_FLAGS_OSZAP_SUB_8(op1_8, op2_8, diff_8) \ - SET_FLAGS_OSZAP_8(SUB_COUT_VEC((op1_8), (op2_8), (diff_8)), (diff_8)) -#define SET_FLAGS_OSZAP_SUB_16(op1_16, op2_16, diff_16) \ - SET_FLAGS_OSZAP_16(SUB_COUT_VEC((op1_16), (op2_16), (diff_16)), (diff_16)) -#define SET_FLAGS_OSZAP_SUB_32(op1_32, op2_32, diff_32) \ - SET_FLAGS_OSZAP_32(SUB_COUT_VEC((op1_32), (op2_32), (diff_32)), (diff_32)) - -/* ******************* */ -/* OSZAxC */ -/* ******************* */ -/* size, carries, result */ -#define SET_FLAGS_OSZAxC_LOGIC_SIZE(size, lf_result) { \ - bool saved_PF = getB_PF(); \ - SET_FLAGS_OSZAPC_SIZE(size, (int##size##_t)(0), lf_result); \ - set_PF(saved_PF); \ -} - -/* result */ -#define SET_FLAGS_OSZAxC_LOGIC_32(result_32) \ - SET_FLAGS_OSZAxC_LOGIC_SIZE(32, (result_32)) - void lflags_to_rflags(CPUX86State *env); void rflags_to_lflags(CPUX86State *env); @@ -221,22 +71,11 @@ void SET_FLAGS_OSZAP_ADD16(CPUX86State *env, uint16_t v1, uint16_t v2, void SET_FLAGS_OSZAP_ADD8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff); -void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t diff); -void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t diff); -void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t diff); +void SET_FLAGS_OSZAPC_LOGIC32(CPUX86State *env, uint32_t v1, uint32_t v2, + uint32_t diff); +void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t v1, uint16_t v2, + uint16_t diff); +void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, + uint8_t diff); -void SET_FLAGS_SHR32(CPUX86State *env, uint32_t v, int count, uint32_t res); -void SET_FLAGS_SHR16(CPUX86State *env, uint16_t v, int count, uint16_t res); -void SET_FLAGS_SHR8(CPUX86State *env, uint8_t v, int count, uint8_t res); - -void SET_FLAGS_SAR32(CPUX86State *env, int32_t v, int count, uint32_t res); -void SET_FLAGS_SAR16(CPUX86State *env, int16_t v, int count, uint16_t res); -void SET_FLAGS_SAR8(CPUX86State *env, int8_t v, int count, uint8_t res); - -void SET_FLAGS_SHL32(CPUX86State *env, uint32_t v, int count, uint32_t res); -void SET_FLAGS_SHL16(CPUX86State *env, uint16_t v, int count, uint16_t res); -void SET_FLAGS_SHL8(CPUX86State *env, uint8_t v, int count, uint8_t res); - -bool _get_OF(CPUX86State *env); -bool _get_CF(CPUX86State *env); #endif /* __X86_FLAGS_H__ */ From ff2de1668c9e5dfa7d4305451058234a029aa6ad Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:17:37 +0200 Subject: [PATCH 391/546] i386: hvf: remove addr_t Use target_ulong for virtual addresses and uint64_t for physical addresses. Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 4 +-- target/i386/hvf/x86.c | 15 ++++++----- target/i386/hvf/x86.h | 12 ++++----- target/i386/hvf/x86_cpuid.c | 1 + target/i386/hvf/x86_decode.c | 38 +++++++++++++------------- target/i386/hvf/x86_decode.h | 14 +++++----- target/i386/hvf/x86_emu.c | 52 ++++++++++++++++++------------------ target/i386/hvf/x86_emu.h | 14 +++++----- target/i386/hvf/x86_flags.c | 14 +++++----- target/i386/hvf/x86_gen.h | 2 -- target/i386/hvf/x86_mmu.c | 30 ++++++++++----------- target/i386/hvf/x86_mmu.h | 6 ++--- 12 files changed, 101 insertions(+), 101 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 8ceba73a5c..72cb45a5c9 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -289,7 +289,7 @@ void hvf_cpu_synchronize_post_init(CPUState *cpu_state) run_on_cpu(cpu_state, _hvf_cpu_synchronize_post_init, RUN_ON_CPU_NULL); } -static bool ept_emulation_fault(hvf_slot *slot, addr_t gpa, uint64_t ept_qual) +static bool ept_emulation_fault(hvf_slot *slot, uint64_t gpa, uint64_t ept_qual) { int read, write; @@ -708,7 +708,7 @@ int hvf_vcpu_exec(CPUState *cpu) case EXIT_REASON_EPT_FAULT: { hvf_slot *slot; - addr_t gpa = rvmcs(cpu->hvf_fd, VMCS_GUEST_PHYSICAL_ADDRESS); + uint64_t gpa = rvmcs(cpu->hvf_fd, VMCS_GUEST_PHYSICAL_ADDRESS); if (((idtvec_info & VMCS_IDT_VEC_VALID) == 0) && ((exit_qual & EXIT_QUAL_NMIUDTI) != 0)) { diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index efb28c373c..3afcedc7fc 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" +#include "cpu.h" #include "qemu-common.h" #include "x86_decode.h" #include "x86_emu.h" @@ -50,7 +51,7 @@ bool x86_read_segment_descriptor(struct CPUState *cpu, struct x86_segment_descriptor *desc, x68_segment_selector sel) { - addr_t base; + target_ulong base; uint32_t limit; memset(desc, 0, sizeof(*desc)); @@ -80,7 +81,7 @@ bool x86_write_segment_descriptor(struct CPUState *cpu, struct x86_segment_descriptor *desc, x68_segment_selector sel) { - addr_t base; + target_ulong base; uint32_t limit; if (GDT_SEL == sel.ti) { @@ -102,7 +103,7 @@ bool x86_write_segment_descriptor(struct CPUState *cpu, bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc, int gate) { - addr_t base = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE); + target_ulong base = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_BASE); uint32_t limit = rvmcs(cpu->hvf_fd, VMCS_GUEST_IDTR_LIMIT); memset(idt_desc, 0, sizeof(*idt_desc)); @@ -158,13 +159,13 @@ bool x86_is_pae_enabled(struct CPUState *cpu) return cr4 & CR4_PAE; } -addr_t linear_addr(struct CPUState *cpu, addr_t addr, X86Seg seg) +target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, X86Seg seg) { return vmx_read_segment_base(cpu, seg) + addr; } -addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, - X86Seg seg) +target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size, + X86Seg seg) { switch (size) { case 2: @@ -179,7 +180,7 @@ addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, return linear_addr(cpu, addr, seg); } -addr_t linear_rip(struct CPUState *cpu, addr_t rip) +target_ulong linear_rip(struct CPUState *cpu, target_ulong rip) { return linear_addr(cpu, rip, R_CS); } diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index cfcb9c95cc..ae877f0022 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -289,8 +289,8 @@ typedef struct x68_segment_selector { } __attribute__ ((__packed__)) x68_segment_selector; typedef struct lazy_flags { - addr_t result; - addr_t auxbits; + target_ulong result; + target_ulong auxbits; } lazy_flags; /* Definition of hvf_x86_state is here */ @@ -381,10 +381,10 @@ bool x86_is_paging_mode(struct CPUState *cpu); bool x86_is_pae_enabled(struct CPUState *cpu); enum X86Seg; -addr_t linear_addr(struct CPUState *cpu, addr_t addr, enum X86Seg seg); -addr_t linear_addr_size(struct CPUState *cpu, addr_t addr, int size, - enum X86Seg seg); -addr_t linear_rip(struct CPUState *cpu, addr_t rip); +target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, enum X86Seg seg); +target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size, + enum X86Seg seg); +target_ulong linear_rip(struct CPUState *cpu, target_ulong rip); static inline uint64_t rdtscp(void) { diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index bcb9705a71..9874a46e92 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "cpu.h" #include "x86.h" #include "vmx.h" #include "sysemu/hvf.h" diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 4bfd85f2df..71d0c3d115 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -64,7 +64,7 @@ uint64_t sign(uint64_t val, int size) static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, int size) { - addr_t val = 0; + target_ulong val = 0; switch (size) { case 1: @@ -76,7 +76,7 @@ static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, VM_PANIC_EX("%s invalid size %d\n", __func__, size); break; } - addr_t va = linear_rip(ENV_GET_CPU(env), RIP(env)) + decode->len; + target_ulong va = linear_rip(ENV_GET_CPU(env), RIP(env)) + decode->len; vmx_read_mem(ENV_GET_CPU(env), &val, va, size); decode->len += size; @@ -430,7 +430,7 @@ struct decode_tbl { void (*decode_op4)(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op4); void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); - addr_t flags_mask; + uint32_t flags_mask; }; struct decode_x87_tbl { @@ -446,7 +446,7 @@ struct decode_x87_tbl { void (*decode_op2)(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op2); void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); - addr_t flags_mask; + uint32_t flags_mask; }; struct decode_tbl invl_inst = {0x0, 0, 0, false, NULL, NULL, NULL, NULL, @@ -1638,7 +1638,7 @@ struct decode_x87_tbl _x87_inst[] = { void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { - addr_t ptr = 0; + target_ulong ptr = 0; X86Seg seg = R_DS; if (!decode->modrm.mod && 6 == decode->modrm.rm) { @@ -1687,9 +1687,9 @@ calc_addr: } } -addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size) +target_ulong get_reg_ref(CPUX86State *env, int reg, int is_extended, int size) { - addr_t ptr = 0; + target_ulong ptr = 0; int which = 0; if (is_extended) { @@ -1701,32 +1701,32 @@ addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size) case 1: if (is_extended || reg < 4) { which = 1; - ptr = (addr_t)&RL(env, reg); + ptr = (target_ulong)&RL(env, reg); } else { which = 2; - ptr = (addr_t)&RH(env, reg - 4); + ptr = (target_ulong)&RH(env, reg - 4); } break; default: which = 3; - ptr = (addr_t)&RRX(env, reg); + ptr = (target_ulong)&RRX(env, reg); break; } return ptr; } -addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size) +target_ulong get_reg_val(CPUX86State *env, int reg, int is_extended, int size) { - addr_t val = 0; + target_ulong val = 0; memcpy(&val, (void *)get_reg_ref(env, reg, is_extended, size), size); return val; } -static addr_t get_sib_val(CPUX86State *env, struct x86_decode *decode, +static target_ulong get_sib_val(CPUX86State *env, struct x86_decode *decode, X86Seg *sel) { - addr_t base = 0; - addr_t scaled_index = 0; + target_ulong base = 0; + target_ulong scaled_index = 0; int addr_size = decode->addressing_size; int base_reg = decode->sib.base; int index_reg = decode->sib.index; @@ -1758,7 +1758,7 @@ void calc_modrm_operand32(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op) { X86Seg seg = R_DS; - addr_t ptr = 0; + target_ulong ptr = 0; int addr_size = decode->addressing_size; if (decode->displacement_size) { @@ -1794,7 +1794,7 @@ void calc_modrm_operand64(CPUX86State *env, struct x86_decode *decode, int32_t offset = 0; int mod = decode->modrm.mod; int rm = decode->modrm.rm; - addr_t ptr; + target_ulong ptr; int src = decode->modrm.rm; if (decode->displacement_size) { @@ -2157,8 +2157,8 @@ const char *decode_cmd_to_string(enum x86_decode_cmd cmd) return cmds[cmd]; } -addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, - addr_t addr, X86Seg seg) +target_ulong decode_linear_addr(CPUX86State *env, struct x86_decode *decode, + target_ulong addr, X86Seg seg) { switch (decode->segment_override) { case PREFIX_CS_SEG_OVEERIDE: diff --git a/target/i386/hvf/x86_decode.h b/target/i386/hvf/x86_decode.h index b3dc88e167..5ab6f31fa5 100644 --- a/target/i386/hvf/x86_decode.h +++ b/target/i386/hvf/x86_decode.h @@ -264,9 +264,9 @@ typedef struct x86_decode_op { int size; int reg; - addr_t val; + target_ulong val; - addr_t ptr; + target_ulong ptr; } x86_decode_op; typedef struct x86_decode { @@ -295,7 +295,7 @@ typedef struct x86_decode { struct x86_modrm modrm; struct x86_decode_op op[4]; bool is_fpu; - addr_t flags_mask; + uint32_t flags_mask; } x86_decode; @@ -303,12 +303,12 @@ uint64_t sign(uint64_t val, int size); uint32_t decode_instruction(CPUX86State *env, struct x86_decode *decode); -addr_t get_reg_ref(CPUX86State *env, int reg, int is_extended, int size); -addr_t get_reg_val(CPUX86State *env, int reg, int is_extended, int size); +target_ulong get_reg_ref(CPUX86State *env, int reg, int is_extended, int size); +target_ulong get_reg_val(CPUX86State *env, int reg, int is_extended, int size); void calc_modrm_operand(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op); -addr_t decode_linear_addr(CPUX86State *env, struct x86_decode *decode, - addr_t addr, enum X86Seg seg); +target_ulong decode_linear_addr(CPUX86State *env, struct x86_decode *decode, + target_ulong addr, enum X86Seg seg); void init_decoder(void); void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 31b0807add..6abcea9d92 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -91,7 +91,7 @@ void hvf_handle_io(struct CPUState *cpu, uint16_t port, void *data, } \ } \ -addr_t read_reg(CPUX86State *env, int reg, int size) +target_ulong read_reg(CPUX86State *env, int reg, int size) { switch (size) { case 1: @@ -108,7 +108,7 @@ addr_t read_reg(CPUX86State *env, int reg, int size) return 0; } -void write_reg(CPUX86State *env, int reg, addr_t val, int size) +void write_reg(CPUX86State *env, int reg, target_ulong val, int size) { switch (size) { case 1: @@ -128,9 +128,9 @@ void write_reg(CPUX86State *env, int reg, addr_t val, int size) } } -addr_t read_val_from_reg(addr_t reg_ptr, int size) +target_ulong read_val_from_reg(target_ulong reg_ptr, int size) { - addr_t val; + target_ulong val; switch (size) { case 1: @@ -151,7 +151,7 @@ addr_t read_val_from_reg(addr_t reg_ptr, int size) return val; } -void write_val_to_reg(addr_t reg_ptr, addr_t val, int size) +void write_val_to_reg(target_ulong reg_ptr, target_ulong val, int size) { switch (size) { case 1: @@ -171,12 +171,12 @@ void write_val_to_reg(addr_t reg_ptr, addr_t val, int size) } } -static bool is_host_reg(struct CPUX86State *env, addr_t ptr) +static bool is_host_reg(struct CPUX86State *env, target_ulong ptr) { - return (ptr - (addr_t)&env->hvf_emul->regs[0]) < sizeof(env->hvf_emul->regs); + return (ptr - (target_ulong)&env->hvf_emul->regs[0]) < sizeof(env->hvf_emul->regs); } -void write_val_ext(struct CPUX86State *env, addr_t ptr, addr_t val, int size) +void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, int size) { if (is_host_reg(env, ptr)) { write_val_to_reg(ptr, val, size); @@ -185,16 +185,16 @@ void write_val_ext(struct CPUX86State *env, addr_t ptr, addr_t val, int size) vmx_write_mem(ENV_GET_CPU(env), ptr, &val, size); } -uint8_t *read_mmio(struct CPUX86State *env, addr_t ptr, int bytes) +uint8_t *read_mmio(struct CPUX86State *env, target_ulong ptr, int bytes) { vmx_read_mem(ENV_GET_CPU(env), env->hvf_emul->mmio_buf, ptr, bytes); return env->hvf_emul->mmio_buf; } -addr_t read_val_ext(struct CPUX86State *env, addr_t ptr, int size) +target_ulong read_val_ext(struct CPUX86State *env, target_ulong ptr, int size) { - addr_t val; + target_ulong val; uint8_t *mmio_ptr; if (is_host_reg(env, ptr)) { @@ -420,7 +420,7 @@ static void exec_out(struct CPUX86State *env, struct x86_decode *decode) static void exec_in(struct CPUX86State *env, struct x86_decode *decode) { - addr_t val = 0; + target_ulong val = 0; switch (decode->opcode[0]) { case 0xe4: hvf_handle_io(ENV_GET_CPU(env), decode->op[0].val, &AL(env), 0, 1, 1); @@ -456,7 +456,7 @@ static void exec_in(struct CPUX86State *env, struct x86_decode *decode) static inline void string_increment_reg(struct CPUX86State *env, int reg, struct x86_decode *decode) { - addr_t val = read_reg(env, reg, decode->addressing_size); + target_ulong val = read_reg(env, reg, decode->addressing_size); if (env->hvf_emul->rflags.df) { val -= decode->operand_size; } else { @@ -469,7 +469,7 @@ static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode void (*func)(struct CPUX86State *env, struct x86_decode *ins), int rep) { - addr_t rcx = read_reg(env, R_ECX, decode->addressing_size); + target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size); while (rcx--) { func(env, decode); write_reg(env, R_ECX, rcx, decode->addressing_size); @@ -484,7 +484,7 @@ static inline void string_rep(struct CPUX86State *env, struct x86_decode *decode static void exec_ins_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, + target_ulong addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, R_ES); hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 0, @@ -507,7 +507,7 @@ static void exec_ins(struct CPUX86State *env, struct x86_decode *decode) static void exec_outs_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr = decode_linear_addr(env, decode, RSI(env), R_DS); + target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); vmx_read_mem(ENV_GET_CPU(env), env->hvf_emul->mmio_buf, addr, decode->operand_size); hvf_handle_io(ENV_GET_CPU(env), DX(env), env->hvf_emul->mmio_buf, 1, @@ -529,9 +529,9 @@ static void exec_outs(struct CPUX86State *env, struct x86_decode *decode) static void exec_movs_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t src_addr; - addr_t dst_addr; - addr_t val; + target_ulong src_addr; + target_ulong dst_addr; + target_ulong val; src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, @@ -557,8 +557,8 @@ static void exec_movs(struct CPUX86State *env, struct x86_decode *decode) static void exec_cmps_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t src_addr; - addr_t dst_addr; + target_ulong src_addr; + target_ulong dst_addr; src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); dst_addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, @@ -588,8 +588,8 @@ static void exec_cmps(struct CPUX86State *env, struct x86_decode *decode) static void exec_stos_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr; - addr_t val; + target_ulong addr; + target_ulong val; addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, R_ES); val = read_reg(env, R_EAX, decode->operand_size); @@ -612,7 +612,7 @@ static void exec_stos(struct CPUX86State *env, struct x86_decode *decode) static void exec_scas_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr; + target_ulong addr; addr = linear_addr_size(ENV_GET_CPU(env), RDI(env), decode->addressing_size, R_ES); decode->op[1].type = X86_VAR_IMMEDIATE; @@ -637,8 +637,8 @@ static void exec_scas(struct CPUX86State *env, struct x86_decode *decode) static void exec_lods_single(struct CPUX86State *env, struct x86_decode *decode) { - addr_t addr; - addr_t val = 0; + target_ulong addr; + target_ulong val = 0; addr = decode_linear_addr(env, decode, RSI(env), R_DS); vmx_read_mem(ENV_GET_CPU(env), &val, addr, decode->operand_size); diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index cd4acb0030..fbb4832576 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -31,13 +31,13 @@ void store_regs(struct CPUState *cpu); void simulate_rdmsr(struct CPUState *cpu); void simulate_wrmsr(struct CPUState *cpu); -addr_t read_reg(CPUX86State *env, int reg, int size); -void write_reg(CPUX86State *env, int reg, addr_t val, int size); -addr_t read_val_from_reg(addr_t reg_ptr, int size); -void write_val_to_reg(addr_t reg_ptr, addr_t val, int size); -void write_val_ext(struct CPUX86State *env, addr_t ptr, addr_t val, int size); -uint8_t *read_mmio(struct CPUX86State *env, addr_t ptr, int bytes); -addr_t read_val_ext(struct CPUX86State *env, addr_t ptr, int size); +target_ulong read_reg(CPUX86State *env, int reg, int size); +void write_reg(CPUX86State *env, int reg, target_ulong val, int size); +target_ulong read_val_from_reg(target_ulong reg_ptr, int size); +void write_val_to_reg(target_ulong reg_ptr, target_ulong val, int size); +void write_val_ext(struct CPUX86State *env, target_ulong ptr, target_ulong val, int size); +uint8_t *read_mmio(struct CPUX86State *env, target_ulong ptr, int bytes); +target_ulong read_val_ext(struct CPUX86State *env, target_ulong ptr, int size); void exec_movzx(struct CPUX86State *env, struct x86_decode *decode); void exec_shl(struct CPUX86State *env, struct x86_decode *decode); diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index b0686c7962..28398ae680 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -60,9 +60,9 @@ /* size, carries, result */ #define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ - addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + target_ulong temp = ((lf_carries) & (LF_MASK_AF)) | \ (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ - env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ + env->hvf_emul->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ if ((size) == 32) { \ temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ } else if ((size) == 16) { \ @@ -72,7 +72,7 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)temp; \ + env->hvf_emul->lflags.auxbits = (target_ulong)(uint32_t)temp; \ } /* carries, result */ @@ -88,7 +88,7 @@ /* ******************* */ /* size, carries, result */ #define SET_FLAGS_OSZAP_SIZE(size, lf_carries, lf_result) { \ - addr_t temp = ((lf_carries) & (LF_MASK_AF)) | \ + target_ulong temp = ((lf_carries) & (LF_MASK_AF)) | \ (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ if ((size) == 32) { \ temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ @@ -99,10 +99,10 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_emul->lflags.result = (addr_t)(int##size##_t)(lf_result); \ - addr_t delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ + env->hvf_emul->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ + target_ulong delta_c = (env->hvf_emul->lflags.auxbits ^ temp) & LF_MASK_CF; \ delta_c ^= (delta_c >> 1); \ - env->hvf_emul->lflags.auxbits = (addr_t)(uint32_t)(temp ^ delta_c); \ + env->hvf_emul->lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \ } /* carries, result */ diff --git a/target/i386/hvf/x86_gen.h b/target/i386/hvf/x86_gen.h index e5739f1de5..96d6c5a811 100644 --- a/target/i386/hvf/x86_gen.h +++ b/target/i386/hvf/x86_gen.h @@ -18,8 +18,6 @@ #ifndef __X86_GEN_H__ #define __X86_GEN_H__ -typedef uint64_t addr_t; - #define VM_PANIC(x) {\ printf("%s\n", x); \ abort(); \ diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index 1084670c1d..cd8d122b45 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "cpu.h" #include "x86.h" #include "x86_mmu.h" #include "string.h" @@ -43,8 +44,8 @@ #define PAE_PTE_LARGE_PAGE_MASK ((-1llu << (21)) & ((1llu << 52) - 1)) struct gpt_translation { - addr_t gva; - addr_t gpa; + target_ulong gva; + uint64_t gpa; int err_code; uint64_t pte[5]; bool write_access; @@ -64,7 +65,7 @@ static int gpt_top_level(struct CPUState *cpu, bool pae) return 3; } -static inline int gpt_entry(addr_t addr, int level, bool pae) +static inline int gpt_entry(target_ulong addr, int level, bool pae) { int level_shift = pae ? 9 : 10; return (addr >> (level_shift * (level - 1) + 12)) & ((1 << level_shift) - 1); @@ -81,8 +82,8 @@ static bool get_pt_entry(struct CPUState *cpu, struct gpt_translation *pt, { int index; uint64_t pte = 0; - addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; - addr_t gpa = pt->pte[level] & page_mask; + uint64_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; + uint64_t gpa = pt->pte[level] & page_mask; if (level == 3 && !x86_is_long_mode(cpu)) { gpa = pt->pte[level]; @@ -114,7 +115,6 @@ static bool test_pt_entry(struct CPUState *cpu, struct gpt_translation *pt, } if (!pte_present(pte)) { - /* addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; */ return false; } @@ -130,7 +130,7 @@ static bool test_pt_entry(struct CPUState *cpu, struct gpt_translation *pt, pt->err_code |= MMU_PAGE_PT; } - addr_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0); + uint32_t cr0 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR0); /* check protection */ if (cr0 & CR0_WP) { if (pt->write_access && !pte_write_access(pte)) { @@ -170,13 +170,13 @@ static inline uint64_t large_page_gpa(struct gpt_translation *pt, bool pae) -static bool walk_gpt(struct CPUState *cpu, addr_t addr, int err_code, +static bool walk_gpt(struct CPUState *cpu, target_ulong addr, int err_code, struct gpt_translation *pt, bool pae) { int top_level, level; bool is_large = false; - addr_t cr3 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR3); - addr_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; + target_ulong cr3 = rvmcs(cpu->hvf_fd, VMCS_GUEST_CR3); + uint64_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK; memset(pt, 0, sizeof(*pt)); top_level = gpt_top_level(cpu, pae); @@ -209,7 +209,7 @@ static bool walk_gpt(struct CPUState *cpu, addr_t addr, int err_code, } -bool mmu_gva_to_gpa(struct CPUState *cpu, addr_t gva, addr_t *gpa) +bool mmu_gva_to_gpa(struct CPUState *cpu, target_ulong gva, uint64_t *gpa) { bool res; struct gpt_translation pt; @@ -229,9 +229,9 @@ bool mmu_gva_to_gpa(struct CPUState *cpu, addr_t gva, addr_t *gpa) return false; } -void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes) +void vmx_write_mem(struct CPUState *cpu, target_ulong gva, void *data, int bytes) { - addr_t gpa; + uint64_t gpa; while (bytes > 0) { /* copy page */ @@ -250,9 +250,9 @@ void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes) } } -void vmx_read_mem(struct CPUState *cpu, void *data, addr_t gva, int bytes) +void vmx_read_mem(struct CPUState *cpu, void *data, target_ulong gva, int bytes) { - addr_t gpa; + uint64_t gpa; while (bytes > 0) { /* copy page */ diff --git a/target/i386/hvf/x86_mmu.h b/target/i386/hvf/x86_mmu.h index b786af280b..ae02cb6916 100644 --- a/target/i386/hvf/x86_mmu.h +++ b/target/i386/hvf/x86_mmu.h @@ -37,9 +37,9 @@ #define MMU_PAGE_US (1 << 2) #define MMU_PAGE_NX (1 << 3) -bool mmu_gva_to_gpa(struct CPUState *cpu, addr_t gva, addr_t *gpa); +bool mmu_gva_to_gpa(struct CPUState *cpu, target_ulong gva, uint64_t *gpa); -void vmx_write_mem(struct CPUState *cpu, addr_t gva, void *data, int bytes); -void vmx_read_mem(struct CPUState *cpu, void *data, addr_t gva, int bytes); +void vmx_write_mem(struct CPUState *cpu, target_ulong gva, void *data, int bytes); +void vmx_read_mem(struct CPUState *cpu, void *data, target_ulong gva, int bytes); #endif /* __X86_MMU_H__ */ From da20f5cd0d9935205e607eaa843ed22fdea91b83 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:21:00 +0200 Subject: [PATCH 392/546] i386: hvf: remove VM_PANIC from "in" Just give the obvious meaning to a 64-bit port, even though it should not really happen. Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 72cb45a5c9..010866ed22 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -749,7 +749,7 @@ int hvf_vcpu_exec(CPUState *cpu) } else if (size == 4) { RAX(env) = (uint32_t)val; } else { - VM_PANIC("size"); + RAX(env) = (uint64_t)val; } RIP(env) += ins_len; store_regs(cpu); From 895f9fdf3ac5481ca5ad5763bf667cbf82aa52c4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 3 Oct 2017 15:22:35 +0200 Subject: [PATCH 393/546] i386: hvf: cleanup x86_gen.h This only includes VM_PANIC now. No need to include it from headers. Signed-off-by: Paolo Bonzini --- target/i386/hvf/{x86_gen.h => panic.h} | 4 ++-- target/i386/hvf/x86.h | 2 -- target/i386/hvf/x86_decode.c | 2 +- target/i386/hvf/x86_emu.c | 2 +- target/i386/hvf/x86_flags.c | 1 + target/i386/hvf/x86_flags.h | 1 - target/i386/hvf/x86_mmu.c | 1 + target/i386/hvf/x86_mmu.h | 2 -- target/i386/hvf/x86_task.c | 1 + 9 files changed, 7 insertions(+), 9 deletions(-) rename target/i386/hvf/{x86_gen.h => panic.h} (96%) diff --git a/target/i386/hvf/x86_gen.h b/target/i386/hvf/panic.h similarity index 96% rename from target/i386/hvf/x86_gen.h rename to target/i386/hvf/panic.h index 96d6c5a811..411ef43a5b 100644 --- a/target/i386/hvf/x86_gen.h +++ b/target/i386/hvf/panic.h @@ -15,8 +15,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, see . */ -#ifndef __X86_GEN_H__ -#define __X86_GEN_H__ +#ifndef HVF_PANIC_H +#define HVF_PANIC_H #define VM_PANIC(x) {\ printf("%s\n", x); \ diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index ae877f0022..103ec0976c 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -19,8 +19,6 @@ #ifndef HVF_X86_H #define HVF_X86_H 1 -#include "x86_gen.h" - typedef struct x86_register { union { struct { diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 71d0c3d115..bf93e8207d 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -19,10 +19,10 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "panic.h" #include "x86_decode.h" #include "string.h" #include "vmx.h" -#include "x86_gen.h" #include "x86_mmu.h" #include "x86_descr.h" diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 6abcea9d92..3ea18edc68 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -36,7 +36,7 @@ ///////////////////////////////////////////////////////////////////////// #include "qemu/osdep.h" - +#include "panic.h" #include "qemu-common.h" #include "x86_decode.h" #include "x86.h" diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index 28398ae680..ee6d33f861 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" +#include "panic.h" #include "cpu.h" #include "x86_flags.h" #include "x86.h" diff --git a/target/i386/hvf/x86_flags.h b/target/i386/hvf/x86_flags.h index 13e5d5bd1a..8942745988 100644 --- a/target/i386/hvf/x86_flags.h +++ b/target/i386/hvf/x86_flags.h @@ -23,7 +23,6 @@ #ifndef __X86_FLAGS_H__ #define __X86_FLAGS_H__ -#include "x86_gen.h" #include "cpu.h" void lflags_to_rflags(CPUX86State *env); void rflags_to_lflags(CPUX86State *env); diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index cd8d122b45..5c1f35acd0 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -16,6 +16,7 @@ * License along with this program; if not, see . */ #include "qemu/osdep.h" +#include "panic.h" #include "qemu-common.h" #include "cpu.h" diff --git a/target/i386/hvf/x86_mmu.h b/target/i386/hvf/x86_mmu.h index ae02cb6916..0bd1acc94f 100644 --- a/target/i386/hvf/x86_mmu.h +++ b/target/i386/hvf/x86_mmu.h @@ -18,8 +18,6 @@ #ifndef __X86_MMU_H__ #define __X86_MMU_H__ -#include "x86_gen.h" - #define PT_PRESENT (1 << 0) #define PT_WRITE (1 << 1) #define PT_USER (1 << 2) diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index bb3c3457eb..d7f665f8fa 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -7,6 +7,7 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. #include "qemu/osdep.h" +#include "panic.h" #include "qemu-common.h" #include "qemu/error-report.h" From 5fbfabd313b77e1cc7038ae8c4481c4b9f8b650a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 30 Nov 2017 17:38:43 +0100 Subject: [PATCH 394/546] block: Formats don't need CONSISTENT_READ with NO_IO Commit 1f4ad7d fixed 'qemu-img info' for raw images that are currently in use as a mirror target. It is not enough for image formats, though, as these still unconditionally request BLK_PERM_CONSISTENT_READ. As this permission is geared towards whether the guest-visible data is consistent, and has no impact on whether the metadata is sane, and 'qemu-img info' does not read guest-visible data (except for the raw format), it makes sense to not require BLK_PERM_CONSISTENT_READ if there is not going to be any guest I/O performed, regardless of image format. Signed-off-by: Kevin Wolf --- block.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 1c37ce4554..db0be7ef36 100644 --- a/block.c +++ b/block.c @@ -1924,6 +1924,8 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, assert(role == &child_backing || role == &child_file); if (!backing) { + int flags = bdrv_reopen_get_flags(reopen_queue, bs); + /* Apart from the modifications below, the same permissions are * forwarded and left alone as for filters */ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared, @@ -1936,7 +1938,9 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c, /* bs->file always needs to be consistent because of the metadata. We * can never allow other users to resize or write to it. */ - perm |= BLK_PERM_CONSISTENT_READ; + if (!(flags & BDRV_O_NO_IO)) { + perm |= BLK_PERM_CONSISTENT_READ; + } shared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE); } else { /* We want consistent read from backing files if the parent needs it. From bff5554843773d8ca644fddd37ffebcc952ce48f Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 4 Dec 2017 20:08:20 -0500 Subject: [PATCH 395/546] iotests: fix 197 for vpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VPC has some difficulty creating geometries of particular size. However, we can indeed force it to use a literal one, so let's do that for the sake of test 197, which is testing some specific offsets. Signed-off-by: John Snow Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf Reviewed-by: Lukáš Doktor --- tests/qemu-iotests/197 | 4 ++++ tests/qemu-iotests/common.filter | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 887eb4f496..5e869fe2b7 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -60,6 +60,10 @@ echo '=== Copy-on-read ===' echo # Prep the images +# VPC rounds image sizes to a specific geometry, force a specific size. +if [ "$IMGFMT" = "vpc" ]; then + IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size") +fi _make_test_img 4G $QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \ diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index d9237799e9..f08248bfd9 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -134,7 +134,8 @@ _filter_img_create() -e "s# log_size=[0-9]\\+##g" \ -e "s# refcount_bits=[0-9]\\+##g" \ -e "s# key-secret=[a-zA-Z0-9]\\+##g" \ - -e "s# iter-time=[0-9]\\+##g" + -e "s# iter-time=[0-9]\\+##g" \ + -e "s# force_size=\\(on\\|off\\)##g" } _filter_img_info() From db0289b9b26cb653d5662f5d6a2a52d70243cd56 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 5 Dec 2017 12:52:09 +0100 Subject: [PATCH 396/546] block: Make bdrv_drain_invoke() recursive This change separates bdrv_drain_invoke(), which calls the BlockDriver drain callbacks, from bdrv_drain_recurse(). Instead, the function performs its own recursion now. One reason for this is that bdrv_drain_recurse() can be called multiple times by bdrv_drain_all_begin(), but the callbacks may only be called once. The separation is necessary to fix this bug. The other reason is that we intend to go to a model where we call all driver callbacks first, and only then start polling. This is not fully achieved yet with this patch, as bdrv_drain_invoke() contains a BDRV_POLL_WHILE() loop for the block driver callbacks, which can still call callbacks for any unrelated event. It's a step in this direction anyway. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/io.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/block/io.c b/block/io.c index 6773926fc1..096468b761 100644 --- a/block/io.c +++ b/block/io.c @@ -175,8 +175,10 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) bdrv_wakeup(bs); } +/* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) { + BdrvChild *child, *tmp; BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; if (!bs->drv || (begin && !bs->drv->bdrv_co_drain_begin) || @@ -187,6 +189,10 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) data.co = qemu_coroutine_create(bdrv_drain_invoke_entry, &data); bdrv_coroutine_enter(bs, data.co); BDRV_POLL_WHILE(bs, !data.done); + + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { + bdrv_drain_invoke(child->bs, begin); + } } static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) @@ -194,9 +200,6 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) BdrvChild *child, *tmp; bool waited; - /* Ensure any pending metadata writes are submitted to bs->file. */ - bdrv_drain_invoke(bs, begin); - /* Wait for drained requests to finish */ waited = BDRV_POLL_WHILE(bs, atomic_read(&bs->in_flight) > 0); @@ -279,6 +282,7 @@ void bdrv_drained_begin(BlockDriverState *bs) bdrv_parent_drained_begin(bs); } + bdrv_drain_invoke(bs, true); bdrv_drain_recurse(bs, true); } @@ -294,6 +298,7 @@ void bdrv_drained_end(BlockDriverState *bs) } bdrv_parent_drained_end(bs); + bdrv_drain_invoke(bs, false); bdrv_drain_recurse(bs, false); aio_enable_external(bdrv_get_aio_context(bs)); } @@ -372,6 +377,8 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { if (aio_context == bdrv_get_aio_context(bs)) { + /* FIXME Calling this multiple times is wrong */ + bdrv_drain_invoke(bs, true); waited |= bdrv_drain_recurse(bs, true); } } @@ -393,6 +400,7 @@ void bdrv_drain_all_end(void) aio_context_acquire(aio_context); aio_enable_external(aio_context); bdrv_parent_drained_end(bs); + bdrv_drain_invoke(bs, false); bdrv_drain_recurse(bs, false); aio_context_release(aio_context); } From 2da9b7d456278bccc6ce889ae350f2867155d7e8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 5 Dec 2017 13:53:35 +0100 Subject: [PATCH 397/546] block: Call .drain_begin only once in bdrv_drain_all_begin() bdrv_drain_all_begin() used to call the .bdrv_co_drain_begin() driver callback inside its polling loop. This means that how many times it got called for each node depended on long it had to poll the event loop. This is obviously not right and results in nodes that stay drained even after bdrv_drain_all_end(), which calls .bdrv_co_drain_begin() once per node. Fix bdrv_drain_all_begin() to call the callback only once, too. Cc: qemu-stable@nongnu.org Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/block/io.c b/block/io.c index 096468b761..603f5b059e 100644 --- a/block/io.c +++ b/block/io.c @@ -355,6 +355,7 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); bdrv_parent_drained_begin(bs); aio_disable_external(aio_context); + bdrv_drain_invoke(bs, true); aio_context_release(aio_context); if (!g_slist_find(aio_ctxs, aio_context)) { @@ -377,8 +378,6 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { if (aio_context == bdrv_get_aio_context(bs)) { - /* FIXME Calling this multiple times is wrong */ - bdrv_drain_invoke(bs, true); waited |= bdrv_drain_recurse(bs, true); } } From 881cfd17c734634de0f4bc6725940cca4fd314c9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 5 Dec 2017 14:05:02 +0100 Subject: [PATCH 398/546] test-bdrv-drain: Test BlockDriver callbacks for drain This adds a test case that the BlockDriver callbacks for drain are called in bdrv_drained_all_begin/end(), and that both of them are called exactly once. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake --- tests/Makefile.include | 2 + tests/test-bdrv-drain.c | 137 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 tests/test-bdrv-drain.c diff --git a/tests/Makefile.include b/tests/Makefile.include index 77f8183117..39a4b5359d 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -80,6 +80,7 @@ gcov-files-test-thread-pool-y = thread-pool.c gcov-files-test-hbitmap-y = util/hbitmap.c check-unit-y += tests/test-hbitmap$(EXESUF) gcov-files-test-hbitmap-y = blockjob.c +check-unit-y += tests/test-bdrv-drain$(EXESUF) check-unit-y += tests/test-blockjob$(EXESUF) check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) @@ -595,6 +596,7 @@ tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y) tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y) tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y) +tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c new file mode 100644 index 0000000000..0e567e34ba --- /dev/null +++ b/tests/test-bdrv-drain.c @@ -0,0 +1,137 @@ +/* + * Block node draining tests + * + * Copyright (c) 2017 Kevin Wolf + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "block/block.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" + +typedef struct BDRVTestState { + int drain_count; +} BDRVTestState; + +static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) +{ + BDRVTestState *s = bs->opaque; + s->drain_count++; +} + +static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) +{ + BDRVTestState *s = bs->opaque; + s->drain_count--; +} + +static void bdrv_test_close(BlockDriverState *bs) +{ + BDRVTestState *s = bs->opaque; + g_assert_cmpint(s->drain_count, >, 0); +} + +static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) +{ + /* We want this request to stay until the polling loop in drain waits for + * it to complete. We need to sleep a while as bdrv_drain_invoke() comes + * first and polls its result, too, but it shouldn't accidentally complete + * this request yet. */ + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); + + return 0; +} + +static BlockDriver bdrv_test = { + .format_name = "test", + .instance_size = sizeof(BDRVTestState), + + .bdrv_close = bdrv_test_close, + .bdrv_co_preadv = bdrv_test_co_preadv, + + .bdrv_co_drain_begin = bdrv_test_co_drain_begin, + .bdrv_co_drain_end = bdrv_test_co_drain_end, +}; + +static void aio_ret_cb(void *opaque, int ret) +{ + int *aio_ret = opaque; + *aio_ret = ret; +} + +static void test_drv_cb_drain_all(void) +{ + BlockBackend *blk; + BlockDriverState *bs; + BDRVTestState *s; + BlockAIOCB *acb; + int aio_ret; + + QEMUIOVector qiov; + struct iovec iov = { + .iov_base = NULL, + .iov_len = 0, + }; + qemu_iovec_init_external(&qiov, &iov, 1); + + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, + &error_abort); + s = bs->opaque; + blk_insert_bs(blk, bs, &error_abort); + + /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ + g_assert_cmpint(s->drain_count, ==, 0); + bdrv_drain_all_begin(); + g_assert_cmpint(s->drain_count, ==, 1); + bdrv_drain_all_end(); + g_assert_cmpint(s->drain_count, ==, 0); + + /* Now do the same while a request is pending */ + aio_ret = -EINPROGRESS; + acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); + g_assert(acb != NULL); + g_assert_cmpint(aio_ret, ==, -EINPROGRESS); + + g_assert_cmpint(s->drain_count, ==, 0); + bdrv_drain_all_begin(); + g_assert_cmpint(aio_ret, ==, 0); + g_assert_cmpint(s->drain_count, ==, 1); + bdrv_drain_all_end(); + g_assert_cmpint(s->drain_count, ==, 0); + + bdrv_unref(bs); + blk_unref(blk); +} + +int main(int argc, char **argv) +{ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); + + return g_test_run(); +} From 99c05de9180ae100fcabd5ed02d32b392dc1528c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 5 Dec 2017 14:10:15 +0100 Subject: [PATCH 399/546] block: bdrv_drain_recurse(): Remove unused begin parameter Now that the bdrv_drain_invoke() calls are pulled up to the callers of bdrv_drain_recurse(), the 'begin' parameter isn't needed any more. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/io.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/block/io.c b/block/io.c index 603f5b059e..390d463c71 100644 --- a/block/io.c +++ b/block/io.c @@ -195,7 +195,7 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) } } -static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) +static bool bdrv_drain_recurse(BlockDriverState *bs) { BdrvChild *child, *tmp; bool waited; @@ -218,7 +218,7 @@ static bool bdrv_drain_recurse(BlockDriverState *bs, bool begin) */ bdrv_ref(bs); } - waited |= bdrv_drain_recurse(bs, begin); + waited |= bdrv_drain_recurse(bs); if (in_main_loop) { bdrv_unref(bs); } @@ -283,7 +283,7 @@ void bdrv_drained_begin(BlockDriverState *bs) } bdrv_drain_invoke(bs, true); - bdrv_drain_recurse(bs, true); + bdrv_drain_recurse(bs); } void bdrv_drained_end(BlockDriverState *bs) @@ -299,7 +299,7 @@ void bdrv_drained_end(BlockDriverState *bs) bdrv_parent_drained_end(bs); bdrv_drain_invoke(bs, false); - bdrv_drain_recurse(bs, false); + bdrv_drain_recurse(bs); aio_enable_external(bdrv_get_aio_context(bs)); } @@ -378,7 +378,7 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { if (aio_context == bdrv_get_aio_context(bs)) { - waited |= bdrv_drain_recurse(bs, true); + waited |= bdrv_drain_recurse(bs); } } aio_context_release(aio_context); @@ -400,7 +400,7 @@ void bdrv_drain_all_end(void) aio_enable_external(aio_context); bdrv_parent_drained_end(bs); bdrv_drain_invoke(bs, false); - bdrv_drain_recurse(bs, false); + bdrv_drain_recurse(bs); aio_context_release(aio_context); } From 5280aa32e140a262bbc6e8e06fd4abb137900016 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 10:45:27 +0100 Subject: [PATCH 400/546] block: Don't wait for requests in bdrv_drain*_end() The device is drained, so there is no point in waiting for requests at the end of the drained section. Remove the bdrv_drain_recurse() calls there. The bdrv_drain_recurse() calls were introduced in commit 481cad48e5e in order to call the .bdrv_co_drain_end() driver callback. This is now done by a separate bdrv_drain_invoke() call. Signed-off-by: Kevin Wolf Reviewed-by: Paolo Bonzini Reviewed-by: Stefan Hajnoczi --- block/io.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/block/io.c b/block/io.c index 390d463c71..5fdb92a15e 100644 --- a/block/io.c +++ b/block/io.c @@ -299,7 +299,6 @@ void bdrv_drained_end(BlockDriverState *bs) bdrv_parent_drained_end(bs); bdrv_drain_invoke(bs, false); - bdrv_drain_recurse(bs); aio_enable_external(bdrv_get_aio_context(bs)); } @@ -400,7 +399,6 @@ void bdrv_drain_all_end(void) aio_enable_external(aio_context); bdrv_parent_drained_end(bs); bdrv_drain_invoke(bs, false); - bdrv_drain_recurse(bs); aio_context_release(aio_context); } From 60369b86c427c6646c53b607b5a3e6b507ffe8d6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 11:00:59 +0100 Subject: [PATCH 401/546] block: Unify order in drain functions Drain requests are propagated to child nodes, parent nodes and directly to the AioContext. The order in which this happened was different between all combinations of drain/drain_all and begin/end. The correct order is to keep children only drained when their parents are also drained. This means that at the start of a drained section, the AioContext needs to be drained first, the parents second and only then the children. The correct order for the end of a drained section is the opposite. This patch changes the three other functions to follow the example of bdrv_drained_begin(), which is the only one that got it right. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- block/io.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/block/io.c b/block/io.c index 5fdb92a15e..1e92d2e5b2 100644 --- a/block/io.c +++ b/block/io.c @@ -277,6 +277,7 @@ void bdrv_drained_begin(BlockDriverState *bs) return; } + /* Stop things in parent-to-child order */ if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { aio_disable_external(bdrv_get_aio_context(bs)); bdrv_parent_drained_begin(bs); @@ -297,8 +298,9 @@ void bdrv_drained_end(BlockDriverState *bs) return; } - bdrv_parent_drained_end(bs); + /* Re-enable things in child-to-parent order */ bdrv_drain_invoke(bs, false); + bdrv_parent_drained_end(bs); aio_enable_external(bdrv_get_aio_context(bs)); } @@ -351,9 +353,10 @@ void bdrv_drain_all_begin(void) for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); + /* Stop things in parent-to-child order */ aio_context_acquire(aio_context); - bdrv_parent_drained_begin(bs); aio_disable_external(aio_context); + bdrv_parent_drained_begin(bs); bdrv_drain_invoke(bs, true); aio_context_release(aio_context); @@ -395,10 +398,11 @@ void bdrv_drain_all_end(void) for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); + /* Re-enable things in child-to-parent order */ aio_context_acquire(aio_context); - aio_enable_external(aio_context); - bdrv_parent_drained_end(bs); bdrv_drain_invoke(bs, false); + bdrv_parent_drained_end(bs); + aio_enable_external(aio_context); aio_context_release(aio_context); } From c200c4a470fc89d9a2b2d1884b140b03fd31981f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 11 Dec 2017 15:33:17 +0100 Subject: [PATCH 402/546] block: Don't acquire AioContext in hmp_qemu_io() Commit 15afd94a047 added code to acquire and release the AioContext in qemuio_command(). This means that the lock is taken twice now in the call path from hmp_qemu_io(). This causes BDRV_POLL_WHILE() to hang for any requests issued to nodes in a non-mainloop AioContext. Dropping the first locking from hmp_qemu_io() fixes the problem. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- hmp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hmp.c b/hmp.c index 35a7041824..2d72f94193 100644 --- a/hmp.c +++ b/hmp.c @@ -2318,7 +2318,6 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) { BlockBackend *blk; BlockBackend *local_blk = NULL; - AioContext *aio_context; const char* device = qdict_get_str(qdict, "device"); const char* command = qdict_get_str(qdict, "command"); Error *err = NULL; @@ -2338,9 +2337,6 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) } } - aio_context = blk_get_aio_context(blk); - aio_context_acquire(aio_context); - /* * Notably absent: Proper permission management. This is sad, but it seems * almost impossible to achieve without changing the semantics and thereby @@ -2368,8 +2364,6 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict) */ qemuio_command(blk, command); - aio_context_release(aio_context); - fail: blk_unref(local_blk); hmp_handle_error(mon, &err); From 546a7dc40e8b8b6440a052e2b5cdfe9aadcaccf6 Mon Sep 17 00:00:00 2001 From: Edgar Kaziakhmedov Date: Tue, 12 Dec 2017 17:40:54 +0300 Subject: [PATCH 403/546] qcow2: get rid of qcow2_backing_read1 routine Since bdrv_co_preadv does all neccessary checks including reading after the end of the backing file, avoid duplication of verification before bdrv_co_preadv call. Signed-off-by: Edgar Kaziakhmedov Reviewed-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2.c | 51 ++++++++------------------------------------------- block/qcow2.h | 3 --- 2 files changed, 8 insertions(+), 46 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 1914a940e5..4348b2c0c5 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1672,34 +1672,12 @@ static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, return status; } -/* handle reading after the end of the backing file */ -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t offset, int bytes) -{ - uint64_t bs_size = bs->total_sectors * BDRV_SECTOR_SIZE; - int n1; - - if ((offset + bytes) <= bs_size) { - return bytes; - } - - if (offset >= bs_size) { - n1 = 0; - } else { - n1 = bs_size - offset; - } - - qemu_iovec_memset(qiov, n1, 0, bytes - n1); - - return n1; -} - static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags) { BDRVQcow2State *s = bs->opaque; - int offset_in_cluster, n1; + int offset_in_cluster; int ret; unsigned int cur_bytes; /* number of bytes in current iteration */ uint64_t cluster_offset = 0; @@ -1734,26 +1712,13 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, case QCOW2_CLUSTER_UNALLOCATED: if (bs->backing) { - /* read from the base image */ - n1 = qcow2_backing_read1(bs->backing->bs, &hd_qiov, - offset, cur_bytes); - if (n1 > 0) { - QEMUIOVector local_qiov; - - qemu_iovec_init(&local_qiov, hd_qiov.niov); - qemu_iovec_concat(&local_qiov, &hd_qiov, 0, n1); - - BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); - qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_preadv(bs->backing, offset, n1, - &local_qiov, 0); - qemu_co_mutex_lock(&s->lock); - - qemu_iovec_destroy(&local_qiov); - - if (ret < 0) { - goto fail; - } + BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); + qemu_co_mutex_unlock(&s->lock); + ret = bdrv_co_preadv(bs->backing, offset, cur_bytes, + &hd_qiov, 0); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + goto fail; } } else { /* Note: in this case, no need to wait */ diff --git a/block/qcow2.h b/block/qcow2.h index 6f0ff15dd0..46c8cf44ec 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -528,9 +528,6 @@ uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset) } /* qcow2.c functions */ -int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, - int64_t sector_num, int nb_sectors); - int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size, int refcount_order, bool generous_increase, uint64_t *refblock_count); From 6b4738ce4d32d551b37afb387813a37a24b6de8f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Dec 2017 11:54:22 +0100 Subject: [PATCH 404/546] block: Document that x-blockdev-change breaks quorum children list Removing a quorum child node with x-blockdev-change results in a quorum driver state that cannot be recreated with create options because it would require a list with gaps. This causes trouble in at least .bdrv_refresh_filename(). Document this problem so that we won't accidentally mark the command stable without having addressed it. Signed-off-by: Kevin Wolf Reviewed-by: Alberto Garcia --- qapi/block-core.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qapi/block-core.json b/qapi/block-core.json index a8cdbc300b..e94a6881b2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3918,6 +3918,10 @@ # does not support all kinds of operations, all kinds of children, nor # all block drivers. # +# FIXME Removing children from a quorum node means introducing gaps in the +# child indices. This cannot be represented in the 'children' list of +# BlockdevOptionsQuorum, as returned by .bdrv_refresh_filename(). +# # Warning: The data in a new quorum child MUST be consistent with that of # the rest of the array. # From 1ee24514aed34760fb2863d98bea3a1b705d9c9f Mon Sep 17 00:00:00 2001 From: Doug Gale Date: Fri, 3 Nov 2017 09:37:53 -0400 Subject: [PATCH 405/546] nvme: Add tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add trace output for commands, errors, and undefined behavior. Add guest error log output for undefined behavior. Report invalid undefined accesses to MMIO. Annotate unlikely error checks with unlikely. Signed-off-by: Doug Gale Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- hw/block/nvme.c | 349 +++++++++++++++++++++++++++++++++++------- hw/block/trace-events | 93 +++++++++++ 2 files changed, 390 insertions(+), 52 deletions(-) diff --git a/hw/block/nvme.c b/hw/block/nvme.c index e529e88e4e..1ac356d3a5 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -34,8 +34,17 @@ #include "qapi/visitor.h" #include "sysemu/block-backend.h" +#include "qemu/log.h" +#include "trace.h" #include "nvme.h" +#define NVME_GUEST_ERR(trace, fmt, ...) \ + do { \ + (trace_##trace)(__VA_ARGS__); \ + qemu_log_mask(LOG_GUEST_ERROR, #trace \ + " in %s: " fmt "\n", __func__, ## __VA_ARGS__); \ + } while (0) + static void nvme_process_sq(void *opaque); static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size) @@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq) { if (cq->irq_enabled) { if (msix_enabled(&(n->parent_obj))) { + trace_nvme_irq_msix(cq->vector); msix_notify(&(n->parent_obj), cq->vector); } else { + trace_nvme_irq_pin(); pci_irq_pulse(&n->parent_obj); } + } else { + trace_nvme_irq_masked(); } } @@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, trans_len = MIN(len, trans_len); int num_prps = (len >> n->page_bits) + 1; - if (!prp1) { + if (unlikely(!prp1)) { + trace_nvme_err_invalid_prp(); return NVME_INVALID_FIELD | NVME_DNR; } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr && prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) { @@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, } len -= trans_len; if (len) { - if (!prp2) { + if (unlikely(!prp2)) { + trace_nvme_err_invalid_prp2_missing(); goto unmap; } if (len > n->page_size) { @@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, uint64_t prp_ent = le64_to_cpu(prp_list[i]); if (i == n->max_prp_ents - 1 && len > n->page_size) { - if (!prp_ent || prp_ent & (n->page_size - 1)) { + if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { + trace_nvme_err_invalid_prplist_ent(prp_ent); goto unmap; } @@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, prp_ent = le64_to_cpu(prp_list[i]); } - if (!prp_ent || prp_ent & (n->page_size - 1)) { + if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) { + trace_nvme_err_invalid_prplist_ent(prp_ent); goto unmap; } @@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector *iov, uint64_t prp1, i++; } } else { - if (prp2 & (n->page_size - 1)) { + if (unlikely(prp2 & (n->page_size - 1))) { + trace_nvme_err_invalid_prp2_align(prp2); goto unmap; } if (qsg->nsg) { @@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t *ptr, uint32_t len, QEMUIOVector iov; uint16_t status = NVME_SUCCESS; + trace_nvme_dma_read(prp1, prp2); + if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) { return NVME_INVALID_FIELD | NVME_DNR; } if (qsg.nsg > 0) { - if (dma_buf_read(ptr, len, &qsg)) { + if (unlikely(dma_buf_read(ptr, len, &qsg))) { + trace_nvme_err_invalid_dma(); status = NVME_INVALID_FIELD | NVME_DNR; } qemu_sglist_destroy(&qsg); } else { - if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) { + if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) { + trace_nvme_err_invalid_dma(); status = NVME_INVALID_FIELD | NVME_DNR; } qemu_iovec_destroy(&iov); @@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS); uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS); - if (slba + nlb > ns->id_ns.nsze) { + if (unlikely(slba + nlb > ns->id_ns.nsze)) { + trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -301,8 +324,11 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd, int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0; enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ; - if ((slba + nlb) > ns->id_ns.nsze) { + trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba); + + if (unlikely((slba + nlb) > ns->id_ns.nsze)) { block_acct_invalid(blk_get_stats(n->conf.blk), acct); + trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze); return NVME_LBA_RANGE | NVME_DNR; } @@ -336,7 +362,8 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) NvmeNamespace *ns; uint32_t nsid = le32_to_cpu(cmd->nsid); - if (nsid == 0 || nsid > n->num_namespaces) { + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); return NVME_INVALID_NSID | NVME_DNR; } @@ -350,6 +377,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_CMD_READ: return nvme_rw(n, ns, cmd, req); default: + trace_nvme_err_invalid_opc(cmd->opcode); return NVME_INVALID_OPCODE | NVME_DNR; } } @@ -373,10 +401,13 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd) NvmeCQueue *cq; uint16_t qid = le16_to_cpu(c->qid); - if (!qid || nvme_check_sqid(n, qid)) { + if (unlikely(!qid || nvme_check_sqid(n, qid))) { + trace_nvme_err_invalid_del_sq(qid); return NVME_INVALID_QID | NVME_DNR; } + trace_nvme_del_sq(qid); + sq = n->sq[qid]; while (!QTAILQ_EMPTY(&sq->out_req_list)) { req = QTAILQ_FIRST(&sq->out_req_list); @@ -439,19 +470,26 @@ static uint16_t nvme_create_sq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qflags = le16_to_cpu(c->sq_flags); uint64_t prp1 = le64_to_cpu(c->prp1); - if (!cqid || nvme_check_cqid(n, cqid)) { + trace_nvme_create_sq(prp1, sqid, cqid, qsize, qflags); + + if (unlikely(!cqid || nvme_check_cqid(n, cqid))) { + trace_nvme_err_invalid_create_sq_cqid(cqid); return NVME_INVALID_CQID | NVME_DNR; } - if (!sqid || !nvme_check_sqid(n, sqid)) { + if (unlikely(!sqid || !nvme_check_sqid(n, sqid))) { + trace_nvme_err_invalid_create_sq_sqid(sqid); return NVME_INVALID_QID | NVME_DNR; } - if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) { + if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { + trace_nvme_err_invalid_create_sq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } - if (!prp1 || prp1 & (n->page_size - 1)) { + if (unlikely(!prp1 || prp1 & (n->page_size - 1))) { + trace_nvme_err_invalid_create_sq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } - if (!(NVME_SQ_FLAGS_PC(qflags))) { + if (unlikely(!(NVME_SQ_FLAGS_PC(qflags)))) { + trace_nvme_err_invalid_create_sq_qflags(NVME_SQ_FLAGS_PC(qflags)); return NVME_INVALID_FIELD | NVME_DNR; } sq = g_malloc0(sizeof(*sq)); @@ -476,14 +514,17 @@ static uint16_t nvme_del_cq(NvmeCtrl *n, NvmeCmd *cmd) NvmeCQueue *cq; uint16_t qid = le16_to_cpu(c->qid); - if (!qid || nvme_check_cqid(n, qid)) { + if (unlikely(!qid || nvme_check_cqid(n, qid))) { + trace_nvme_err_invalid_del_cq_cqid(qid); return NVME_INVALID_CQID | NVME_DNR; } cq = n->cq[qid]; - if (!QTAILQ_EMPTY(&cq->sq_list)) { + if (unlikely(!QTAILQ_EMPTY(&cq->sq_list))) { + trace_nvme_err_invalid_del_cq_notempty(qid); return NVME_INVALID_QUEUE_DEL; } + trace_nvme_del_cq(qid); nvme_free_cq(cq, n); return NVME_SUCCESS; } @@ -516,19 +557,27 @@ static uint16_t nvme_create_cq(NvmeCtrl *n, NvmeCmd *cmd) uint16_t qflags = le16_to_cpu(c->cq_flags); uint64_t prp1 = le64_to_cpu(c->prp1); - if (!cqid || !nvme_check_cqid(n, cqid)) { + trace_nvme_create_cq(prp1, cqid, vector, qsize, qflags, + NVME_CQ_FLAGS_IEN(qflags) != 0); + + if (unlikely(!cqid || !nvme_check_cqid(n, cqid))) { + trace_nvme_err_invalid_create_cq_cqid(cqid); return NVME_INVALID_CQID | NVME_DNR; } - if (!qsize || qsize > NVME_CAP_MQES(n->bar.cap)) { + if (unlikely(!qsize || qsize > NVME_CAP_MQES(n->bar.cap))) { + trace_nvme_err_invalid_create_cq_size(qsize); return NVME_MAX_QSIZE_EXCEEDED | NVME_DNR; } - if (!prp1) { + if (unlikely(!prp1)) { + trace_nvme_err_invalid_create_cq_addr(prp1); return NVME_INVALID_FIELD | NVME_DNR; } - if (vector > n->num_queues) { + if (unlikely(vector > n->num_queues)) { + trace_nvme_err_invalid_create_cq_vector(vector); return NVME_INVALID_IRQ_VECTOR | NVME_DNR; } - if (!(NVME_CQ_FLAGS_PC(qflags))) { + if (unlikely(!(NVME_CQ_FLAGS_PC(qflags)))) { + trace_nvme_err_invalid_create_cq_qflags(NVME_CQ_FLAGS_PC(qflags)); return NVME_INVALID_FIELD | NVME_DNR; } @@ -543,6 +592,8 @@ static uint16_t nvme_identify_ctrl(NvmeCtrl *n, NvmeIdentify *c) uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); + trace_nvme_identify_ctrl(); + return nvme_dma_read_prp(n, (uint8_t *)&n->id_ctrl, sizeof(n->id_ctrl), prp1, prp2); } @@ -554,11 +605,15 @@ static uint16_t nvme_identify_ns(NvmeCtrl *n, NvmeIdentify *c) uint64_t prp1 = le64_to_cpu(c->prp1); uint64_t prp2 = le64_to_cpu(c->prp2); - if (nsid == 0 || nsid > n->num_namespaces) { + trace_nvme_identify_ns(nsid); + + if (unlikely(nsid == 0 || nsid > n->num_namespaces)) { + trace_nvme_err_invalid_ns(nsid, n->num_namespaces); return NVME_INVALID_NSID | NVME_DNR; } ns = &n->namespaces[nsid - 1]; + return nvme_dma_read_prp(n, (uint8_t *)&ns->id_ns, sizeof(ns->id_ns), prp1, prp2); } @@ -573,6 +628,8 @@ static uint16_t nvme_identify_nslist(NvmeCtrl *n, NvmeIdentify *c) uint16_t ret; int i, j = 0; + trace_nvme_identify_nslist(min_nsid); + list = g_malloc0(data_len); for (i = 0; i < n->num_namespaces; i++) { if (i < min_nsid) { @@ -601,6 +658,7 @@ static uint16_t nvme_identify(NvmeCtrl *n, NvmeCmd *cmd) case 0x02: return nvme_identify_nslist(n, c); default: + trace_nvme_err_invalid_identify_cns(le32_to_cpu(c->cns)); return NVME_INVALID_FIELD | NVME_DNR; } } @@ -613,11 +671,14 @@ static uint16_t nvme_get_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) switch (dw10) { case NVME_VOLATILE_WRITE_CACHE: result = blk_enable_write_cache(n->conf.blk); + trace_nvme_getfeat_vwcache(result ? "enabled" : "disabled"); break; case NVME_NUMBER_OF_QUEUES: result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); + trace_nvme_getfeat_numq(result); break; default: + trace_nvme_err_invalid_getfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; } @@ -635,10 +696,14 @@ static uint16_t nvme_set_feature(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) blk_set_enable_write_cache(n->conf.blk, dw11 & 1); break; case NVME_NUMBER_OF_QUEUES: + trace_nvme_setfeat_numq((dw11 & 0xFFFF) + 1, + ((dw11 >> 16) & 0xFFFF) + 1, + n->num_queues - 1, n->num_queues - 1); req->cqe.result = cpu_to_le32((n->num_queues - 2) | ((n->num_queues - 2) << 16)); break; default: + trace_nvme_err_invalid_setfeat(dw10); return NVME_INVALID_FIELD | NVME_DNR; } return NVME_SUCCESS; @@ -662,6 +727,7 @@ static uint16_t nvme_admin_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req) case NVME_ADM_CMD_GET_FEATURES: return nvme_get_feature(n, cmd, req); default: + trace_nvme_err_invalid_admin_opc(cmd->opcode); return NVME_INVALID_OPCODE | NVME_DNR; } } @@ -721,15 +787,78 @@ static int nvme_start_ctrl(NvmeCtrl *n) uint32_t page_bits = NVME_CC_MPS(n->bar.cc) + 12; uint32_t page_size = 1 << page_bits; - if (n->cq[0] || n->sq[0] || !n->bar.asq || !n->bar.acq || - n->bar.asq & (page_size - 1) || n->bar.acq & (page_size - 1) || - NVME_CC_MPS(n->bar.cc) < NVME_CAP_MPSMIN(n->bar.cap) || - NVME_CC_MPS(n->bar.cc) > NVME_CAP_MPSMAX(n->bar.cap) || - NVME_CC_IOCQES(n->bar.cc) < NVME_CTRL_CQES_MIN(n->id_ctrl.cqes) || - NVME_CC_IOCQES(n->bar.cc) > NVME_CTRL_CQES_MAX(n->id_ctrl.cqes) || - NVME_CC_IOSQES(n->bar.cc) < NVME_CTRL_SQES_MIN(n->id_ctrl.sqes) || - NVME_CC_IOSQES(n->bar.cc) > NVME_CTRL_SQES_MAX(n->id_ctrl.sqes) || - !NVME_AQA_ASQS(n->bar.aqa) || !NVME_AQA_ACQS(n->bar.aqa)) { + if (unlikely(n->cq[0])) { + trace_nvme_err_startfail_cq(); + return -1; + } + if (unlikely(n->sq[0])) { + trace_nvme_err_startfail_sq(); + return -1; + } + if (unlikely(!n->bar.asq)) { + trace_nvme_err_startfail_nbarasq(); + return -1; + } + if (unlikely(!n->bar.acq)) { + trace_nvme_err_startfail_nbaracq(); + return -1; + } + if (unlikely(n->bar.asq & (page_size - 1))) { + trace_nvme_err_startfail_asq_misaligned(n->bar.asq); + return -1; + } + if (unlikely(n->bar.acq & (page_size - 1))) { + trace_nvme_err_startfail_acq_misaligned(n->bar.acq); + return -1; + } + if (unlikely(NVME_CC_MPS(n->bar.cc) < + NVME_CAP_MPSMIN(n->bar.cap))) { + trace_nvme_err_startfail_page_too_small( + NVME_CC_MPS(n->bar.cc), + NVME_CAP_MPSMIN(n->bar.cap)); + return -1; + } + if (unlikely(NVME_CC_MPS(n->bar.cc) > + NVME_CAP_MPSMAX(n->bar.cap))) { + trace_nvme_err_startfail_page_too_large( + NVME_CC_MPS(n->bar.cc), + NVME_CAP_MPSMAX(n->bar.cap)); + return -1; + } + if (unlikely(NVME_CC_IOCQES(n->bar.cc) < + NVME_CTRL_CQES_MIN(n->id_ctrl.cqes))) { + trace_nvme_err_startfail_cqent_too_small( + NVME_CC_IOCQES(n->bar.cc), + NVME_CTRL_CQES_MIN(n->bar.cap)); + return -1; + } + if (unlikely(NVME_CC_IOCQES(n->bar.cc) > + NVME_CTRL_CQES_MAX(n->id_ctrl.cqes))) { + trace_nvme_err_startfail_cqent_too_large( + NVME_CC_IOCQES(n->bar.cc), + NVME_CTRL_CQES_MAX(n->bar.cap)); + return -1; + } + if (unlikely(NVME_CC_IOSQES(n->bar.cc) < + NVME_CTRL_SQES_MIN(n->id_ctrl.sqes))) { + trace_nvme_err_startfail_sqent_too_small( + NVME_CC_IOSQES(n->bar.cc), + NVME_CTRL_SQES_MIN(n->bar.cap)); + return -1; + } + if (unlikely(NVME_CC_IOSQES(n->bar.cc) > + NVME_CTRL_SQES_MAX(n->id_ctrl.sqes))) { + trace_nvme_err_startfail_sqent_too_large( + NVME_CC_IOSQES(n->bar.cc), + NVME_CTRL_SQES_MAX(n->bar.cap)); + return -1; + } + if (unlikely(!NVME_AQA_ASQS(n->bar.aqa))) { + trace_nvme_err_startfail_asqent_sz_zero(); + return -1; + } + if (unlikely(!NVME_AQA_ACQS(n->bar.aqa))) { + trace_nvme_err_startfail_acqent_sz_zero(); return -1; } @@ -749,16 +878,48 @@ static int nvme_start_ctrl(NvmeCtrl *n) static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, unsigned size) { + if (unlikely(offset & (sizeof(uint32_t) - 1))) { + NVME_GUEST_ERR(nvme_ub_mmiowr_misaligned32, + "MMIO write not 32-bit aligned," + " offset=0x%"PRIx64"", offset); + /* should be ignored, fall through for now */ + } + + if (unlikely(size < sizeof(uint32_t))) { + NVME_GUEST_ERR(nvme_ub_mmiowr_toosmall, + "MMIO write smaller than 32-bits," + " offset=0x%"PRIx64", size=%u", + offset, size); + /* should be ignored, fall through for now */ + } + switch (offset) { - case 0xc: + case 0xc: /* INTMS */ + if (unlikely(msix_enabled(&(n->parent_obj)))) { + NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, + "undefined access to interrupt mask set" + " when MSI-X is enabled"); + /* should be ignored, fall through for now */ + } n->bar.intms |= data & 0xffffffff; n->bar.intmc = n->bar.intms; + trace_nvme_mmio_intm_set(data & 0xffffffff, + n->bar.intmc); break; - case 0x10: + case 0x10: /* INTMC */ + if (unlikely(msix_enabled(&(n->parent_obj)))) { + NVME_GUEST_ERR(nvme_ub_mmiowr_intmask_with_msix, + "undefined access to interrupt mask clr" + " when MSI-X is enabled"); + /* should be ignored, fall through for now */ + } n->bar.intms &= ~(data & 0xffffffff); n->bar.intmc = n->bar.intms; + trace_nvme_mmio_intm_clr(data & 0xffffffff, + n->bar.intmc); break; - case 0x14: + case 0x14: /* CC */ + trace_nvme_mmio_cfg(data & 0xffffffff); /* Windows first sends data, then sends enable bit */ if (!NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc) && !NVME_CC_SHN(data) && !NVME_CC_SHN(n->bar.cc)) @@ -768,40 +929,82 @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data, if (NVME_CC_EN(data) && !NVME_CC_EN(n->bar.cc)) { n->bar.cc = data; - if (nvme_start_ctrl(n)) { + if (unlikely(nvme_start_ctrl(n))) { + trace_nvme_err_startfail(); n->bar.csts = NVME_CSTS_FAILED; } else { + trace_nvme_mmio_start_success(); n->bar.csts = NVME_CSTS_READY; } } else if (!NVME_CC_EN(data) && NVME_CC_EN(n->bar.cc)) { + trace_nvme_mmio_stopped(); nvme_clear_ctrl(n); n->bar.csts &= ~NVME_CSTS_READY; } if (NVME_CC_SHN(data) && !(NVME_CC_SHN(n->bar.cc))) { - nvme_clear_ctrl(n); - n->bar.cc = data; - n->bar.csts |= NVME_CSTS_SHST_COMPLETE; + trace_nvme_mmio_shutdown_set(); + nvme_clear_ctrl(n); + n->bar.cc = data; + n->bar.csts |= NVME_CSTS_SHST_COMPLETE; } else if (!NVME_CC_SHN(data) && NVME_CC_SHN(n->bar.cc)) { - n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; - n->bar.cc = data; + trace_nvme_mmio_shutdown_cleared(); + n->bar.csts &= ~NVME_CSTS_SHST_COMPLETE; + n->bar.cc = data; } break; - case 0x24: + case 0x1C: /* CSTS */ + if (data & (1 << 4)) { + NVME_GUEST_ERR(nvme_ub_mmiowr_ssreset_w1c_unsupported, + "attempted to W1C CSTS.NSSRO" + " but CAP.NSSRS is zero (not supported)"); + } else if (data != 0) { + NVME_GUEST_ERR(nvme_ub_mmiowr_ro_csts, + "attempted to set a read only bit" + " of controller status"); + } + break; + case 0x20: /* NSSR */ + if (data == 0x4E564D65) { + trace_nvme_ub_mmiowr_ssreset_unsupported(); + } else { + /* The spec says that writes of other values have no effect */ + return; + } + break; + case 0x24: /* AQA */ n->bar.aqa = data & 0xffffffff; + trace_nvme_mmio_aqattr(data & 0xffffffff); break; - case 0x28: + case 0x28: /* ASQ */ n->bar.asq = data; + trace_nvme_mmio_asqaddr(data); break; - case 0x2c: + case 0x2c: /* ASQ hi */ n->bar.asq |= data << 32; + trace_nvme_mmio_asqaddr_hi(data, n->bar.asq); break; - case 0x30: + case 0x30: /* ACQ */ + trace_nvme_mmio_acqaddr(data); n->bar.acq = data; break; - case 0x34: + case 0x34: /* ACQ hi */ n->bar.acq |= data << 32; + trace_nvme_mmio_acqaddr_hi(data, n->bar.acq); break; + case 0x38: /* CMBLOC */ + NVME_GUEST_ERR(nvme_ub_mmiowr_cmbloc_reserved, + "invalid write to reserved CMBLOC" + " when CMBSZ is zero, ignored"); + return; + case 0x3C: /* CMBSZ */ + NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly, + "invalid write to read only CMBSZ, ignored"); + return; default: + NVME_GUEST_ERR(nvme_ub_mmiowr_invalid, + "invalid MMIO write," + " offset=0x%"PRIx64", data=%"PRIx64"", + offset, data); break; } } @@ -812,9 +1015,26 @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size) uint8_t *ptr = (uint8_t *)&n->bar; uint64_t val = 0; + if (unlikely(addr & (sizeof(uint32_t) - 1))) { + NVME_GUEST_ERR(nvme_ub_mmiord_misaligned32, + "MMIO read not 32-bit aligned," + " offset=0x%"PRIx64"", addr); + /* should RAZ, fall through for now */ + } else if (unlikely(size < sizeof(uint32_t))) { + NVME_GUEST_ERR(nvme_ub_mmiord_toosmall, + "MMIO read smaller than 32-bits," + " offset=0x%"PRIx64"", addr); + /* should RAZ, fall through for now */ + } + if (addr < sizeof(n->bar)) { memcpy(&val, ptr + addr, size); + } else { + NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs, + "MMIO read beyond last register," + " offset=0x%"PRIx64", returning 0", addr); } + return val; } @@ -822,22 +1042,36 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) { uint32_t qid; - if (addr & ((1 << 2) - 1)) { + if (unlikely(addr & ((1 << 2) - 1))) { + NVME_GUEST_ERR(nvme_ub_db_wr_misaligned, + "doorbell write not 32-bit aligned," + " offset=0x%"PRIx64", ignoring", addr); return; } if (((addr - 0x1000) >> 2) & 1) { + /* Completion queue doorbell write */ + uint16_t new_head = val & 0xffff; int start_sqs; NvmeCQueue *cq; qid = (addr - (0x1000 + (1 << 2))) >> 3; - if (nvme_check_cqid(n, qid)) { + if (unlikely(nvme_check_cqid(n, qid))) { + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cq, + "completion queue doorbell write" + " for nonexistent queue," + " sqid=%"PRIu32", ignoring", qid); return; } cq = n->cq[qid]; - if (new_head >= cq->size) { + if (unlikely(new_head >= cq->size)) { + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_cqhead, + "completion queue doorbell write value" + " beyond queue size, sqid=%"PRIu32"," + " new_head=%"PRIu16", ignoring", + qid, new_head); return; } @@ -855,16 +1089,27 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int val) nvme_isr_notify(n, cq); } } else { + /* Submission queue doorbell write */ + uint16_t new_tail = val & 0xffff; NvmeSQueue *sq; qid = (addr - 0x1000) >> 3; - if (nvme_check_sqid(n, qid)) { + if (unlikely(nvme_check_sqid(n, qid))) { + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sq, + "submission queue doorbell write" + " for nonexistent queue," + " sqid=%"PRIu32", ignoring", qid); return; } sq = n->sq[qid]; - if (new_tail >= sq->size) { + if (unlikely(new_tail >= sq->size)) { + NVME_GUEST_ERR(nvme_ub_db_wr_invalid_sqtail, + "submission queue doorbell write value" + " beyond queue size, sqid=%"PRIu32"," + " new_tail=%"PRIu16", ignoring", + qid, new_tail); return; } diff --git a/hw/block/trace-events b/hw/block/trace-events index 962a3bfa24..5acd495207 100644 --- a/hw/block/trace-events +++ b/hw/block/trace-events @@ -11,6 +11,99 @@ virtio_blk_submit_multireq(void *vdev, void *mrb, int start, int num_reqs, uint6 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/nvme.c +# nvme traces for successful events +nvme_irq_msix(uint32_t vector) "raising MSI-X IRQ vector %u" +nvme_irq_pin(void) "pulsing IRQ pin" +nvme_irq_masked(void) "IRQ is masked" +nvme_dma_read(uint64_t prp1, uint64_t prp2) "DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64"" +nvme_rw(char const *verb, uint32_t blk_count, uint64_t byte_count, uint64_t lba) "%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64"" +nvme_create_sq(uint64_t addr, uint16_t sqid, uint16_t cqid, uint16_t qsize, uint16_t qflags) "create submission queue, addr=0x%"PRIx64", sqid=%"PRIu16", cqid=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16"" +nvme_create_cq(uint64_t addr, uint16_t cqid, uint16_t vector, uint16_t size, uint16_t qflags, int ien) "create completion queue, addr=0x%"PRIx64", cqid=%"PRIu16", vector=%"PRIu16", qsize=%"PRIu16", qflags=%"PRIu16", ien=%d" +nvme_del_sq(uint16_t qid) "deleting submission queue sqid=%"PRIu16"" +nvme_del_cq(uint16_t cqid) "deleted completion queue, sqid=%"PRIu16"" +nvme_identify_ctrl(void) "identify controller" +nvme_identify_ns(uint16_t ns) "identify namespace, nsid=%"PRIu16"" +nvme_identify_nslist(uint16_t ns) "identify namespace list, nsid=%"PRIu16"" +nvme_getfeat_vwcache(char const* result) "get feature volatile write cache, result=%s" +nvme_getfeat_numq(int result) "get feature number of queues, result=%d" +nvme_setfeat_numq(int reqcq, int reqsq, int gotcq, int gotsq) "requested cq_count=%d sq_count=%d, responding with cq_count=%d sq_count=%d" +nvme_mmio_intm_set(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask set, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +nvme_mmio_intm_clr(uint64_t data, uint64_t new_mask) "wrote MMIO, interrupt mask clr, data=0x%"PRIx64", new_mask=0x%"PRIx64"" +nvme_mmio_cfg(uint64_t data) "wrote MMIO, config controller config=0x%"PRIx64"" +nvme_mmio_aqattr(uint64_t data) "wrote MMIO, admin queue attributes=0x%"PRIx64"" +nvme_mmio_asqaddr(uint64_t data) "wrote MMIO, admin submission queue address=0x%"PRIx64"" +nvme_mmio_acqaddr(uint64_t data) "wrote MMIO, admin completion queue address=0x%"PRIx64"" +nvme_mmio_asqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin submission queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +nvme_mmio_acqaddr_hi(uint64_t data, uint64_t new_addr) "wrote MMIO, admin completion queue high half=0x%"PRIx64", new_address=0x%"PRIx64"" +nvme_mmio_start_success(void) "setting controller enable bit succeeded" +nvme_mmio_stopped(void) "cleared controller enable bit" +nvme_mmio_shutdown_set(void) "shutdown bit set" +nvme_mmio_shutdown_cleared(void) "shutdown bit cleared" + +# nvme traces for error conditions +nvme_err_invalid_dma(void) "PRP/SGL is too small for transfer size" +nvme_err_invalid_prplist_ent(uint64_t prplist) "PRP list entry is null or not page aligned: 0x%"PRIx64"" +nvme_err_invalid_prp2_align(uint64_t prp2) "PRP2 is not page aligned: 0x%"PRIx64"" +nvme_err_invalid_prp2_missing(void) "PRP2 is null and more data to be transferred" +nvme_err_invalid_field(void) "invalid field" +nvme_err_invalid_prp(void) "invalid PRP" +nvme_err_invalid_sgl(void) "invalid SGL" +nvme_err_invalid_ns(uint32_t ns, uint32_t limit) "invalid namespace %u not within 1-%u" +nvme_err_invalid_opc(uint8_t opc) "invalid opcode 0x%"PRIx8"" +nvme_err_invalid_admin_opc(uint8_t opc) "invalid admin opcode 0x%"PRIx8"" +nvme_err_invalid_lba_range(uint64_t start, uint64_t len, uint64_t limit) "Invalid LBA start=%"PRIu64" len=%"PRIu64" limit=%"PRIu64"" +nvme_err_invalid_del_sq(uint16_t qid) "invalid submission queue deletion, sid=%"PRIu16"" +nvme_err_invalid_create_sq_cqid(uint16_t cqid) "failed creating submission queue, invalid cqid=%"PRIu16"" +nvme_err_invalid_create_sq_sqid(uint16_t sqid) "failed creating submission queue, invalid sqid=%"PRIu16"" +nvme_err_invalid_create_sq_size(uint16_t qsize) "failed creating submission queue, invalid qsize=%"PRIu16"" +nvme_err_invalid_create_sq_addr(uint64_t addr) "failed creating submission queue, addr=0x%"PRIx64"" +nvme_err_invalid_create_sq_qflags(uint16_t qflags) "failed creating submission queue, qflags=%"PRIu16"" +nvme_err_invalid_del_cq_cqid(uint16_t cqid) "failed deleting completion queue, cqid=%"PRIu16"" +nvme_err_invalid_del_cq_notempty(uint16_t cqid) "failed deleting completion queue, it is not empty, cqid=%"PRIu16"" +nvme_err_invalid_create_cq_cqid(uint16_t cqid) "failed creating completion queue, cqid=%"PRIu16"" +nvme_err_invalid_create_cq_size(uint16_t size) "failed creating completion queue, size=%"PRIu16"" +nvme_err_invalid_create_cq_addr(uint64_t addr) "failed creating completion queue, addr=0x%"PRIx64"" +nvme_err_invalid_create_cq_vector(uint16_t vector) "failed creating completion queue, vector=%"PRIu16"" +nvme_err_invalid_create_cq_qflags(uint16_t qflags) "failed creating completion queue, qflags=%"PRIu16"" +nvme_err_invalid_identify_cns(uint16_t cns) "identify, invalid cns=0x%"PRIx16"" +nvme_err_invalid_getfeat(int dw10) "invalid get features, dw10=0x%"PRIx32"" +nvme_err_invalid_setfeat(uint32_t dw10) "invalid set features, dw10=0x%"PRIx32"" +nvme_err_startfail_cq(void) "nvme_start_ctrl failed because there are non-admin completion queues" +nvme_err_startfail_sq(void) "nvme_start_ctrl failed because there are non-admin submission queues" +nvme_err_startfail_nbarasq(void) "nvme_start_ctrl failed because the admin submission queue address is null" +nvme_err_startfail_nbaracq(void) "nvme_start_ctrl failed because the admin completion queue address is null" +nvme_err_startfail_asq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin submission queue address is misaligned: 0x%"PRIx64"" +nvme_err_startfail_acq_misaligned(uint64_t addr) "nvme_start_ctrl failed because the admin completion queue address is misaligned: 0x%"PRIx64"" +nvme_err_startfail_page_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too small: log2size=%u, min=%u" +nvme_err_startfail_page_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the page size is too large: log2size=%u, max=%u" +nvme_err_startfail_cqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too small: log2size=%u, min=%u" +nvme_err_startfail_cqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the completion queue entry size is too large: log2size=%u, max=%u" +nvme_err_startfail_sqent_too_small(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too small: log2size=%u, min=%u" +nvme_err_startfail_sqent_too_large(uint8_t log2ps, uint8_t maxlog2ps) "nvme_start_ctrl failed because the submission queue entry size is too large: log2size=%u, max=%u" +nvme_err_startfail_asqent_sz_zero(void) "nvme_start_ctrl failed because the admin submission queue size is zero" +nvme_err_startfail_acqent_sz_zero(void) "nvme_start_ctrl failed because the admin completion queue size is zero" +nvme_err_startfail(void) "setting controller enable bit failed" + +# Traces for undefined behavior +nvme_ub_mmiowr_misaligned32(uint64_t offset) "MMIO write not 32-bit aligned, offset=0x%"PRIx64"" +nvme_ub_mmiowr_toosmall(uint64_t offset, unsigned size) "MMIO write smaller than 32 bits, offset=0x%"PRIx64", size=%u" +nvme_ub_mmiowr_intmask_with_msix(void) "undefined access to interrupt mask set when MSI-X is enabled" +nvme_ub_mmiowr_ro_csts(void) "attempted to set a read only bit of controller status" +nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CAP.NSSRS is zero (not supported)" +nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)" +nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored" +nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored" +nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64"" +nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64"" +nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64"" +nvme_ub_mmiord_invalid_ofs(uint64_t offset) "MMIO read beyond last register, offset=0x%"PRIx64", returning 0" +nvme_ub_db_wr_misaligned(uint64_t offset) "doorbell write not 32-bit aligned, offset=0x%"PRIx64", ignoring" +nvme_ub_db_wr_invalid_cq(uint32_t qid) "completion queue doorbell write for nonexistent queue, cqid=%"PRIu32", ignoring" +nvme_ub_db_wr_invalid_cqhead(uint32_t qid, uint16_t new_head) "completion queue doorbell write value beyond queue size, cqid=%"PRIu32", new_head=%"PRIu16", ignoring" +nvme_ub_db_wr_invalid_sq(uint32_t qid) "submission queue doorbell write for nonexistent queue, sqid=%"PRIu32", ignoring" +nvme_ub_db_wr_invalid_sqtail(uint32_t qid, uint16_t new_tail) "submission queue doorbell write value beyond queue size, sqid=%"PRIu32", new_head=%"PRIu16", ignoring" + # hw/block/xen_disk.c xen_disk_alloc(char *name) "%s" xen_disk_init(char *name) "%s" From cc954f01e3c004aad081aa36736a17e842b80211 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 15 Dec 2017 16:04:45 +0800 Subject: [PATCH 406/546] block: Open backing image in force share mode for size probe Management tools create overlays of running guests with qemu-img: $ qemu-img create -b /image/in/use.qcow2 -f qcow2 /overlay/image.qcow2 but this doesn't work anymore due to image locking: qemu-img: /overlay/image.qcow2: Failed to get shared "write" lock Is another process using the image? Could not open backing image to determine size. Use the force share option to allow this use case again. Cc: qemu-stable@nongnu.org Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index db0be7ef36..dd90dca896 100644 --- a/block.c +++ b/block.c @@ -4605,10 +4605,11 @@ void bdrv_img_create(const char *filename, const char *fmt, back_flags = flags; back_flags &= ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); + backing_options = qdict_new(); if (backing_fmt) { - backing_options = qdict_new(); qdict_put_str(backing_options, "driver", backing_fmt); } + qdict_put_bool(backing_options, BDRV_OPT_FORCE_SHARE, true); bs = bdrv_open(full_backing, NULL, backing_options, back_flags, &local_err); From 0e153b04cccaeaa272a687194ea353167878b10f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 Dec 2017 18:14:31 +0100 Subject: [PATCH 407/546] block: Remove the obsolete -drive boot=on|off parameter It's not working anymore since QEMU v1.3.0 - time to remove it now. Signed-off-by: Thomas Huth Reviewed-by: John Snow Reviewed-by: Markus Armbruster Signed-off-by: Kevin Wolf --- blockdev.c | 11 ----------- qemu-doc.texi | 6 ------ 2 files changed, 17 deletions(-) diff --git a/blockdev.c b/blockdev.c index 9c3a430cfb..29d569a24e 100644 --- a/blockdev.c +++ b/blockdev.c @@ -734,10 +734,6 @@ QemuOptsList qemu_legacy_drive_opts = { .name = "trans", .type = QEMU_OPT_STRING, .help = "chs translation (auto, lba, none)", - },{ - .name = "boot", - .type = QEMU_OPT_BOOL, - .help = "(deprecated, ignored)", },{ .name = "addr", .type = QEMU_OPT_STRING, @@ -873,13 +869,6 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type) goto fail; } - /* Deprecated option boot=[on|off] */ - if (qemu_opt_get(legacy_opts, "boot") != NULL) { - fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be " - "ignored. Future versions will reject this parameter. Please " - "update your scripts.\n"); - } - /* Other deprecated options */ if (!qtest_enabled()) { for (i = 0; i < ARRAY_SIZE(deprecated); i++) { diff --git a/qemu-doc.texi b/qemu-doc.texi index 90bea7331d..ed55bd477d 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2589,12 +2589,6 @@ deprecated. @section System emulator command line arguments -@subsection -drive boot=on|off (since 1.3.0) - -The ``boot=on|off'' option to the ``-drive'' argument is -ignored. Applications should use the ``bootindex=N'' parameter -to set an absolute ordering between devices instead. - @subsection -tdf (since 1.3.0) The ``-tdf'' argument is ignored. The behaviour implemented From d1cdd92e5c67d14de6f8ea604715d24b6370b442 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 Dec 2017 18:14:32 +0100 Subject: [PATCH 408/546] block: Remove the deprecated -hdachs option It's been marked as deprecated since QEMU v2.10.0, and so far nobody complained that we should keep it, so let's remove this legacy option now to simplify the code quite a bit. Signed-off-by: Thomas Huth Reviewed-by: John Snow Reviewed-by: Markus Armbruster Signed-off-by: Kevin Wolf --- qemu-doc.texi | 8 ----- qemu-options.hx | 19 ++--------- vl.c | 86 ++----------------------------------------------- 3 files changed, 4 insertions(+), 109 deletions(-) diff --git a/qemu-doc.texi b/qemu-doc.texi index ed55bd477d..96fda9c56e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2686,14 +2686,6 @@ The ``--net dump'' argument is now replaced with the ``-object filter-dump'' argument which works in combination with the modern ``-netdev`` backends instead. -@subsection -hdachs (since 2.10.0) - -The ``-hdachs'' argument is now a synonym for setting -the ``cyls'', ``heads'', ``secs'', and ``trans'' properties -on the ``ide-hd'' device using the ``-device'' argument. -The new syntax allows different settings to be provided -per disk. - @subsection -usbdevice (since 2.10.0) The ``-usbdevice DEV'' argument is now a synonym for setting diff --git a/qemu-options.hx b/qemu-options.hx index 94647e21e3..2d39ba0b6d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -846,8 +846,8 @@ of available connectors of a given interface type. @item media=@var{media} This option defines the type of the media: disk or cdrom. @item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}] -These options have the same definition as they have in @option{-hdachs}. -These parameters are deprecated, use the corresponding parameters +Force disk physical geometry and the optional BIOS translation (trans=none or +lba). These parameters are deprecated, use the corresponding parameters of @code{-device} instead. @item snapshot=@var{snapshot} @var{snapshot} is "on" or "off" and controls snapshot mode for the given drive @@ -1027,21 +1027,6 @@ the raw disk image you use is not written back. You can however force the write back by pressing @key{C-a s} (@pxref{disk_images}). ETEXI -DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \ - "-hdachs c,h,s[,t]\n" \ - " force hard disk 0 physical geometry and the optional BIOS\n" \ - " translation (t=none or lba) (usually QEMU can guess them)\n", - QEMU_ARCH_ALL) -STEXI -@item -hdachs @var{c},@var{h},@var{s},[,@var{t}] -@findex -hdachs -Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <= -@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS -translation mode (@var{t}=none, lba or auto). Usually QEMU can guess -all those parameters. This option is deprecated, please use -@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead. -ETEXI - DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev, "-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n" " [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd][,fmode=fmode][,dmode=dmode]\n" diff --git a/vl.c b/vl.c index d3a5c5d021..444b7507da 100644 --- a/vl.c +++ b/vl.c @@ -3052,9 +3052,8 @@ int main(int argc, char **argv, char **envp) const char *boot_order = NULL; const char *boot_once = NULL; DisplayState *ds; - int cyls, heads, secs, translation; QemuOpts *opts, *machine_opts; - QemuOpts *hda_opts = NULL, *icount_opts = NULL, *accel_opts = NULL; + QemuOpts *icount_opts = NULL, *accel_opts = NULL; QemuOptsList *olist; int optind; const char *optarg; @@ -3146,8 +3145,6 @@ int main(int argc, char **argv, char **envp) cpu_model = NULL; snapshot = 0; - cyls = heads = secs = 0; - translation = BIOS_ATA_TRANSLATION_AUTO; nb_nics = 0; @@ -3186,7 +3183,7 @@ int main(int argc, char **argv, char **envp) if (optind >= argc) break; if (argv[optind][0] != '-') { - hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS); + drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS); } else { const QEMUOption *popt; @@ -3206,21 +3203,6 @@ int main(int argc, char **argv, char **envp) cpu_model = optarg; break; case QEMU_OPTION_hda: - { - char buf[256]; - if (cyls == 0) - snprintf(buf, sizeof(buf), "%s", HD_OPTS); - else - snprintf(buf, sizeof(buf), - "%s,cyls=%d,heads=%d,secs=%d%s", - HD_OPTS , cyls, heads, secs, - translation == BIOS_ATA_TRANSLATION_LBA ? - ",trans=lba" : - translation == BIOS_ATA_TRANSLATION_NONE ? - ",trans=none" : ""); - drive_add(IF_DEFAULT, 0, optarg, buf); - break; - } case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: case QEMU_OPTION_hdd: @@ -3271,70 +3253,6 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_snapshot: snapshot = 1; break; - case QEMU_OPTION_hdachs: - { - const char *p; - p = optarg; - cyls = strtol(p, (char **)&p, 0); - if (cyls < 1 || cyls > 16383) - goto chs_fail; - if (*p != ',') - goto chs_fail; - p++; - heads = strtol(p, (char **)&p, 0); - if (heads < 1 || heads > 16) - goto chs_fail; - if (*p != ',') - goto chs_fail; - p++; - secs = strtol(p, (char **)&p, 0); - if (secs < 1 || secs > 63) - goto chs_fail; - if (*p == ',') { - p++; - if (!strcmp(p, "large")) { - translation = BIOS_ATA_TRANSLATION_LARGE; - } else if (!strcmp(p, "rechs")) { - translation = BIOS_ATA_TRANSLATION_RECHS; - } else if (!strcmp(p, "none")) { - translation = BIOS_ATA_TRANSLATION_NONE; - } else if (!strcmp(p, "lba")) { - translation = BIOS_ATA_TRANSLATION_LBA; - } else if (!strcmp(p, "auto")) { - translation = BIOS_ATA_TRANSLATION_AUTO; - } else { - goto chs_fail; - } - } else if (*p != '\0') { - chs_fail: - error_report("invalid physical CHS format"); - exit(1); - } - if (hda_opts != NULL) { - qemu_opt_set_number(hda_opts, "cyls", cyls, - &error_abort); - qemu_opt_set_number(hda_opts, "heads", heads, - &error_abort); - qemu_opt_set_number(hda_opts, "secs", secs, - &error_abort); - if (translation == BIOS_ATA_TRANSLATION_LARGE) { - qemu_opt_set(hda_opts, "trans", "large", - &error_abort); - } else if (translation == BIOS_ATA_TRANSLATION_RECHS) { - qemu_opt_set(hda_opts, "trans", "rechs", - &error_abort); - } else if (translation == BIOS_ATA_TRANSLATION_LBA) { - qemu_opt_set(hda_opts, "trans", "lba", - &error_abort); - } else if (translation == BIOS_ATA_TRANSLATION_NONE) { - qemu_opt_set(hda_opts, "trans", "none", - &error_abort); - } - } - } - error_report("'-hdachs' is deprecated, please use '-device" - " ide-hd,cyls=c,heads=h,secs=s,...' instead"); - break; case QEMU_OPTION_numa: opts = qemu_opts_parse_noisily(qemu_find_opts("numa"), optarg, true); From c08d46a96f218e3f2c6f4d0e590d267a9fd77a3a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 18 Dec 2017 18:14:33 +0100 Subject: [PATCH 409/546] block: Mention -drive cyls/heads/secs/trans/serial/addr in deprecation chapter Looks like we forgot to announce the deprecation of these options in the corresponding chapter of the qemu-doc text, so let's do that now. Signed-off-by: Thomas Huth Reviewed-by: John Snow Reviewed-by: Markus Armbruster Signed-off-by: Kevin Wolf --- qemu-doc.texi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/qemu-doc.texi b/qemu-doc.texi index 96fda9c56e..2cc741e77e 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2680,6 +2680,21 @@ longer be directly supported in QEMU. The ``-drive if=scsi'' argument is replaced by the the ``-device BUS-TYPE'' argument combined with ``-drive if=none''. +@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0) + +The drive geometry arguments are replaced by the the geometry arguments +that can be specified with the ``-device'' parameter. + +@subsection -drive serial=... (since 2.10.0) + +The drive serial argument is replaced by the the serial argument +that can be specified with the ``-device'' parameter. + +@subsection -drive addr=... (since 2.10.0) + +The drive addr argument is replaced by the the addr argument +that can be specified with the ``-device'' parameter. + @subsection -net dump (since 2.10.0) The ``--net dump'' argument is now replaced with the From 8e77e0bceb4de0fe5cc912d5865b28a703f0f041 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 29 Nov 2017 22:49:48 +0800 Subject: [PATCH 410/546] block: Remove unused bdrv_requests_pending Signed-off-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/io.c | 18 ------------------ include/block/block_int.h | 1 - 2 files changed, 19 deletions(-) diff --git a/block/io.c b/block/io.c index 1e92d2e5b2..cf780c3cb0 100644 --- a/block/io.c +++ b/block/io.c @@ -134,24 +134,6 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs) assert(old >= 1); } -/* Check if any requests are in-flight (including throttled requests) */ -bool bdrv_requests_pending(BlockDriverState *bs) -{ - BdrvChild *child; - - if (atomic_read(&bs->in_flight)) { - return true; - } - - QLIST_FOREACH(child, &bs->children, next) { - if (bdrv_requests_pending(child->bs)) { - return true; - } - } - - return false; -} - typedef struct { Coroutine *co; BlockDriverState *bs; diff --git a/include/block/block_int.h b/include/block/block_int.h index a5482775ec..e107163594 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -1045,7 +1045,6 @@ bool blk_dev_is_tray_open(BlockBackend *blk); bool blk_dev_is_medium_locked(BlockBackend *blk); void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes); -bool bdrv_requests_pending(BlockDriverState *bs); void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out); void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in); From 9a7e86c8048cecededa665b1ca55c7f217ed358c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 15 Dec 2017 09:33:21 +0100 Subject: [PATCH 411/546] block: Assert drain_all is only called from main AioContext Signed-off-by: Kevin Wolf Reviewed-by: Fam Zheng --- block/io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/block/io.c b/block/io.c index cf780c3cb0..b94740b8ff 100644 --- a/block/io.c +++ b/block/io.c @@ -330,6 +330,12 @@ void bdrv_drain_all_begin(void) BdrvNextIterator it; GSList *aio_ctxs = NULL, *ctx; + /* BDRV_POLL_WHILE() for a node can only be called from its own I/O thread + * or the main loop AioContext. We potentially use BDRV_POLL_WHILE() on + * nodes in several different AioContexts, so make sure we're in the main + * context. */ + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); + block_job_pause_all(); for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { From 7b6a3d35536f945c41aa62627cc295482606aa2e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Dec 2017 12:20:10 +0100 Subject: [PATCH 412/546] block: Make bdrv_drain() driver callbacks non-recursive bdrv_drained_begin() doesn't increase bs->quiesce_counter recursively and also doesn't notify other parent nodes of children, which both means that the child nodes are not actually drained, and bdrv_drained_begin() is providing useful functionality only on a single node. To keep things consistent, we also shouldn't call the block driver callbacks recursively. A proper recursive drain version that provides an actually working drained section for child nodes will be introduced later. Signed-off-by: Kevin Wolf Reviewed-by: Fam Zheng --- block/io.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/block/io.c b/block/io.c index b94740b8ff..91a52e2d82 100644 --- a/block/io.c +++ b/block/io.c @@ -158,7 +158,7 @@ static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) } /* Recursively call BlockDriver.bdrv_co_drain_begin/end callbacks */ -static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) +static void bdrv_drain_invoke(BlockDriverState *bs, bool begin, bool recursive) { BdrvChild *child, *tmp; BdrvCoDrainData data = { .bs = bs, .done = false, .begin = begin}; @@ -172,8 +172,10 @@ static void bdrv_drain_invoke(BlockDriverState *bs, bool begin) bdrv_coroutine_enter(bs, data.co); BDRV_POLL_WHILE(bs, !data.done); - QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { - bdrv_drain_invoke(child->bs, begin); + if (recursive) { + QLIST_FOREACH_SAFE(child, &bs->children, next, tmp) { + bdrv_drain_invoke(child->bs, begin, true); + } } } @@ -265,7 +267,7 @@ void bdrv_drained_begin(BlockDriverState *bs) bdrv_parent_drained_begin(bs); } - bdrv_drain_invoke(bs, true); + bdrv_drain_invoke(bs, true, false); bdrv_drain_recurse(bs); } @@ -281,7 +283,7 @@ void bdrv_drained_end(BlockDriverState *bs) } /* Re-enable things in child-to-parent order */ - bdrv_drain_invoke(bs, false); + bdrv_drain_invoke(bs, false, false); bdrv_parent_drained_end(bs); aio_enable_external(bdrv_get_aio_context(bs)); } @@ -345,7 +347,7 @@ void bdrv_drain_all_begin(void) aio_context_acquire(aio_context); aio_disable_external(aio_context); bdrv_parent_drained_begin(bs); - bdrv_drain_invoke(bs, true); + bdrv_drain_invoke(bs, true, true); aio_context_release(aio_context); if (!g_slist_find(aio_ctxs, aio_context)) { @@ -388,7 +390,7 @@ void bdrv_drain_all_end(void) /* Re-enable things in child-to-parent order */ aio_context_acquire(aio_context); - bdrv_drain_invoke(bs, false); + bdrv_drain_invoke(bs, false, true); bdrv_parent_drained_end(bs); aio_enable_external(aio_context); aio_context_release(aio_context); From 86e1c840ec1173badfe9f195a448c88072b2ad2a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 18:13:53 +0100 Subject: [PATCH 413/546] test-bdrv-drain: Test callback for bdrv_drain The existing test is for bdrv_drain_all_begin/end() only. Generalise the test case so that it can be run for the other variants as well. At the moment this is only bdrv_drain_begin/end(), but in a while, we'll add another one. Also, add a backing file to the test node to test whether the operations work recursively. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 71 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 0e567e34ba..3a3eef0f87 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -71,6 +71,8 @@ static BlockDriver bdrv_test = { .bdrv_co_drain_begin = bdrv_test_co_drain_begin, .bdrv_co_drain_end = bdrv_test_co_drain_end, + + .bdrv_child_perm = bdrv_format_default_perms, }; static void aio_ret_cb(void *opaque, int ret) @@ -79,11 +81,34 @@ static void aio_ret_cb(void *opaque, int ret) *aio_ret = ret; } -static void test_drv_cb_drain_all(void) +enum drain_type { + BDRV_DRAIN_ALL, + BDRV_DRAIN, +}; + +static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) +{ + switch (drain_type) { + case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; + case BDRV_DRAIN: bdrv_drained_begin(bs); break; + default: g_assert_not_reached(); + } +} + +static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) +{ + switch (drain_type) { + case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; + case BDRV_DRAIN: bdrv_drained_end(bs); break; + default: g_assert_not_reached(); + } +} + +static void test_drv_cb_common(enum drain_type drain_type, bool recursive) { BlockBackend *blk; - BlockDriverState *bs; - BDRVTestState *s; + BlockDriverState *bs, *backing; + BDRVTestState *s, *backing_s; BlockAIOCB *acb; int aio_ret; @@ -100,12 +125,23 @@ static void test_drv_cb_drain_all(void) s = bs->opaque; blk_insert_bs(blk, bs, &error_abort); + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); + backing_s = backing->opaque; + bdrv_set_backing_hd(bs, backing, &error_abort); + /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ g_assert_cmpint(s->drain_count, ==, 0); - bdrv_drain_all_begin(); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + do_drain_begin(drain_type, bs); + g_assert_cmpint(s->drain_count, ==, 1); - bdrv_drain_all_end(); + g_assert_cmpint(backing_s->drain_count, ==, !!recursive); + + do_drain_end(drain_type, bs); + g_assert_cmpint(s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); /* Now do the same while a request is pending */ aio_ret = -EINPROGRESS; @@ -114,16 +150,34 @@ static void test_drv_cb_drain_all(void) g_assert_cmpint(aio_ret, ==, -EINPROGRESS); g_assert_cmpint(s->drain_count, ==, 0); - bdrv_drain_all_begin(); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + do_drain_begin(drain_type, bs); + g_assert_cmpint(aio_ret, ==, 0); g_assert_cmpint(s->drain_count, ==, 1); - bdrv_drain_all_end(); - g_assert_cmpint(s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, !!recursive); + do_drain_end(drain_type, bs); + + g_assert_cmpint(s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + bdrv_unref(backing); bdrv_unref(bs); blk_unref(blk); } +static void test_drv_cb_drain_all(void) +{ + test_drv_cb_common(BDRV_DRAIN_ALL, true); +} + +static void test_drv_cb_drain(void) +{ + test_drv_cb_common(BDRV_DRAIN, false); +} + int main(int argc, char **argv) { bdrv_init(); @@ -132,6 +186,7 @@ int main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); + g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); return g_test_run(); } From 89a6ceab4617fefa5ace6a46be3e2be58925ae71 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Dec 2017 17:00:22 +0100 Subject: [PATCH 414/546] test-bdrv-drain: Test bs->quiesce_counter This is currently only working correctly for bdrv_drain(), not for bdrv_drain_all(). Leave a comment for the drain_all case, we'll address it later. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 3a3eef0f87..323cb0b961 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -178,6 +178,48 @@ static void test_drv_cb_drain(void) test_drv_cb_common(BDRV_DRAIN, false); } +static void test_quiesce_common(enum drain_type drain_type, bool recursive) +{ + BlockBackend *blk; + BlockDriverState *bs, *backing; + + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, + &error_abort); + blk_insert_bs(blk, bs, &error_abort); + + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); + bdrv_set_backing_hd(bs, backing, &error_abort); + + g_assert_cmpint(bs->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + + do_drain_begin(drain_type, bs); + + g_assert_cmpint(bs->quiesce_counter, ==, 1); + g_assert_cmpint(backing->quiesce_counter, ==, !!recursive); + + do_drain_end(drain_type, bs); + + g_assert_cmpint(bs->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + + bdrv_unref(backing); + bdrv_unref(bs); + blk_unref(blk); +} + +static void test_quiesce_drain_all(void) +{ + // XXX drain_all doesn't quiesce + //test_quiesce_common(BDRV_DRAIN_ALL, true); +} + +static void test_quiesce_drain(void) +{ + test_quiesce_common(BDRV_DRAIN, false); +} + int main(int argc, char **argv) { bdrv_init(); @@ -188,5 +230,8 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); + g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); + g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); + return g_test_run(); } From ad90febaf22d95e49fb6821bfb3ebd05b4919417 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 12 Dec 2017 19:04:28 +0100 Subject: [PATCH 415/546] blockjob: Pause job on draining any job BDS Block jobs already paused themselves when their main BlockBackend entered a drained section. This is not good enough: We also want to pause a block job and may not submit new requests if, for example, the mirror target node should be drained. This implements .drained_begin/end callbacks in child_job in order to consider all block nodes related to the job, and removes the BlockBackend callbacks which are unnecessary now because the root of the job main BlockBackend is always referenced with a child_job, too. Signed-off-by: Kevin Wolf --- blockjob.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/blockjob.c b/blockjob.c index 6173e4728c..f5cea84e73 100644 --- a/blockjob.c +++ b/blockjob.c @@ -234,26 +234,23 @@ static char *child_job_get_parent_desc(BdrvChild *c) job->id); } -static const BdrvChildRole child_job = { - .get_parent_desc = child_job_get_parent_desc, - .stay_at_node = true, -}; - -static void block_job_drained_begin(void *opaque) +static void child_job_drained_begin(BdrvChild *c) { - BlockJob *job = opaque; + BlockJob *job = c->opaque; block_job_pause(job); } -static void block_job_drained_end(void *opaque) +static void child_job_drained_end(BdrvChild *c) { - BlockJob *job = opaque; + BlockJob *job = c->opaque; block_job_resume(job); } -static const BlockDevOps block_job_dev_ops = { - .drained_begin = block_job_drained_begin, - .drained_end = block_job_drained_end, +static const BdrvChildRole child_job = { + .get_parent_desc = child_job_get_parent_desc, + .drained_begin = child_job_drained_begin, + .drained_end = child_job_drained_end, + .stay_at_node = true, }; void block_job_remove_all_bdrv(BlockJob *job) @@ -715,7 +712,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver, block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort); bs->job = job; - blk_set_dev_ops(blk, &block_job_dev_ops, job); bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker); QLIST_INSERT_HEAD(&block_jobs, job, job_list); From 7253220de42e82c59e72f29e69285a9a9e9e96ee Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 12 Dec 2017 19:10:19 +0100 Subject: [PATCH 416/546] test-bdrv-drain: Test drain vs. block jobs Block jobs must be paused if any of the involved nodes are drained. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 323cb0b961..9783768a20 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "block/block.h" +#include "block/blockjob_int.h" #include "sysemu/block-backend.h" #include "qapi/error.h" @@ -220,6 +221,123 @@ static void test_quiesce_drain(void) test_quiesce_common(BDRV_DRAIN, false); } + +typedef struct TestBlockJob { + BlockJob common; + bool should_complete; +} TestBlockJob; + +static void test_job_completed(BlockJob *job, void *opaque) +{ + block_job_completed(job, 0); +} + +static void coroutine_fn test_job_start(void *opaque) +{ + TestBlockJob *s = opaque; + + while (!s->should_complete) { + block_job_sleep_ns(&s->common, 100000); + } + + block_job_defer_to_main_loop(&s->common, test_job_completed, NULL); +} + +static void test_job_complete(BlockJob *job, Error **errp) +{ + TestBlockJob *s = container_of(job, TestBlockJob, common); + s->should_complete = true; +} + +BlockJobDriver test_job_driver = { + .instance_size = sizeof(TestBlockJob), + .start = test_job_start, + .complete = test_job_complete, +}; + +static void test_blockjob_common(enum drain_type drain_type) +{ + BlockBackend *blk_src, *blk_target; + BlockDriverState *src, *target; + BlockJob *job; + int ret; + + src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR, + &error_abort); + blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + blk_insert_bs(blk_src, src, &error_abort); + + target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR, + &error_abort); + blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + blk_insert_bs(blk_target, target, &error_abort); + + job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0, + 0, NULL, NULL, &error_abort); + block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); + block_job_start(job); + + g_assert_cmpint(job->pause_count, ==, 0); + g_assert_false(job->paused); + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + + do_drain_begin(drain_type, src); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target, and involves an + * additional block_job_pause_all() */ + g_assert_cmpint(job->pause_count, ==, 3); + } else { + g_assert_cmpint(job->pause_count, ==, 1); + } + /* XXX We don't wait until the job is actually paused. Is this okay? */ + /* g_assert_true(job->paused); */ + g_assert_false(job->busy); /* The job is paused */ + + do_drain_end(drain_type, src); + + g_assert_cmpint(job->pause_count, ==, 0); + g_assert_false(job->paused); + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + + do_drain_begin(drain_type, target); + + if (drain_type == BDRV_DRAIN_ALL) { + /* bdrv_drain_all() drains both src and target, and involves an + * additional block_job_pause_all() */ + g_assert_cmpint(job->pause_count, ==, 3); + } else { + g_assert_cmpint(job->pause_count, ==, 1); + } + /* XXX We don't wait until the job is actually paused. Is this okay? */ + /* g_assert_true(job->paused); */ + g_assert_false(job->busy); /* The job is paused */ + + do_drain_end(drain_type, target); + + g_assert_cmpint(job->pause_count, ==, 0); + g_assert_false(job->paused); + g_assert_false(job->busy); /* We're in block_job_sleep_ns() */ + + ret = block_job_complete_sync(job, &error_abort); + g_assert_cmpint(ret, ==, 0); + + blk_unref(blk_src); + blk_unref(blk_target); + bdrv_unref(src); + bdrv_unref(target); +} + +static void test_blockjob_drain_all(void) +{ + test_blockjob_common(BDRV_DRAIN_ALL); +} + +static void test_blockjob_drain(void) +{ + test_blockjob_common(BDRV_DRAIN); +} + int main(int argc, char **argv) { bdrv_init(); @@ -233,5 +351,8 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); + g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); + g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); + return g_test_run(); } From 8119334918e86f45877cfc139192d54f2449a239 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 14 Dec 2017 10:12:42 +0100 Subject: [PATCH 417/546] block: Don't block_job_pause_all() in bdrv_drain_all() Block jobs are already paused using the BdrvChildRole drain callbacks, so we don't need an additional block_job_pause_all() call. Signed-off-by: Kevin Wolf --- block/io.c | 4 ---- tests/test-bdrv-drain.c | 10 ++++------ 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/block/io.c b/block/io.c index 91a52e2d82..74d2e5278e 100644 --- a/block/io.c +++ b/block/io.c @@ -338,8 +338,6 @@ void bdrv_drain_all_begin(void) * context. */ assert(qemu_get_current_aio_context() == qemu_get_aio_context()); - block_job_pause_all(); - for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { AioContext *aio_context = bdrv_get_aio_context(bs); @@ -395,8 +393,6 @@ void bdrv_drain_all_end(void) aio_enable_external(aio_context); aio_context_release(aio_context); } - - block_job_resume_all(); } void bdrv_drain_all(void) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 9783768a20..6da66ae841 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -284,9 +284,8 @@ static void test_blockjob_common(enum drain_type drain_type) do_drain_begin(drain_type, src); if (drain_type == BDRV_DRAIN_ALL) { - /* bdrv_drain_all() drains both src and target, and involves an - * additional block_job_pause_all() */ - g_assert_cmpint(job->pause_count, ==, 3); + /* bdrv_drain_all() drains both src and target */ + g_assert_cmpint(job->pause_count, ==, 2); } else { g_assert_cmpint(job->pause_count, ==, 1); } @@ -303,9 +302,8 @@ static void test_blockjob_common(enum drain_type drain_type) do_drain_begin(drain_type, target); if (drain_type == BDRV_DRAIN_ALL) { - /* bdrv_drain_all() drains both src and target, and involves an - * additional block_job_pause_all() */ - g_assert_cmpint(job->pause_count, ==, 3); + /* bdrv_drain_all() drains both src and target */ + g_assert_cmpint(job->pause_count, ==, 2); } else { g_assert_cmpint(job->pause_count, ==, 1); } From 0f115168943e5bf2219497abfbf5f7a9c271b9b0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 13 Dec 2017 18:14:18 +0100 Subject: [PATCH 418/546] block: Nested drain_end must still call callbacks bdrv_do_drained_begin() restricts the call of parent callbacks and aio_disable_external() to the outermost drain section, but the block driver callbacks are always called. bdrv_do_drained_end() must match this behaviour, otherwise nodes stay drained even if begin/end calls were balanced. Signed-off-by: Kevin Wolf --- block/io.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/block/io.c b/block/io.c index 74d2e5278e..6038a16c58 100644 --- a/block/io.c +++ b/block/io.c @@ -273,19 +273,21 @@ void bdrv_drained_begin(BlockDriverState *bs) void bdrv_drained_end(BlockDriverState *bs) { + int old_quiesce_counter; + if (qemu_in_coroutine()) { bdrv_co_yield_to_drain(bs, false); return; } assert(bs->quiesce_counter > 0); - if (atomic_fetch_dec(&bs->quiesce_counter) > 1) { - return; - } + old_quiesce_counter = atomic_fetch_dec(&bs->quiesce_counter); /* Re-enable things in child-to-parent order */ bdrv_drain_invoke(bs, false, false); - bdrv_parent_drained_end(bs); - aio_enable_external(bdrv_get_aio_context(bs)); + if (old_quiesce_counter == 1) { + bdrv_parent_drained_end(bs); + aio_enable_external(bdrv_get_aio_context(bs)); + } } /* From 6c429a6a97d183aeb2c00f8680aaf3d9e900359d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 13 Dec 2017 18:14:49 +0100 Subject: [PATCH 419/546] test-bdrv-drain: Test nested drain sections Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 6da66ae841..9098b77ab4 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -85,6 +85,7 @@ static void aio_ret_cb(void *opaque, int ret) enum drain_type { BDRV_DRAIN_ALL, BDRV_DRAIN, + DRAIN_TYPE_MAX, }; static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) @@ -221,6 +222,60 @@ static void test_quiesce_drain(void) test_quiesce_common(BDRV_DRAIN, false); } +static void test_nested(void) +{ + BlockBackend *blk; + BlockDriverState *bs, *backing; + BDRVTestState *s, *backing_s; + enum drain_type outer, inner; + + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, + &error_abort); + s = bs->opaque; + blk_insert_bs(blk, bs, &error_abort); + + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); + backing_s = backing->opaque; + bdrv_set_backing_hd(bs, backing, &error_abort); + + for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) { + for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) { + /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */ + int bs_quiesce = (outer != BDRV_DRAIN_ALL) + + (inner != BDRV_DRAIN_ALL); + int backing_quiesce = 0; + int backing_cb_cnt = (outer != BDRV_DRAIN) + + (inner != BDRV_DRAIN); + + g_assert_cmpint(bs->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + do_drain_begin(outer, bs); + do_drain_begin(inner, bs); + + g_assert_cmpint(bs->quiesce_counter, ==, bs_quiesce); + g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce); + g_assert_cmpint(s->drain_count, ==, 2); + g_assert_cmpint(backing_s->drain_count, ==, backing_cb_cnt); + + do_drain_end(inner, bs); + do_drain_end(outer, bs); + + g_assert_cmpint(bs->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + } + } + + bdrv_unref(backing); + bdrv_unref(bs); + blk_unref(blk); +} + typedef struct TestBlockJob { BlockJob common; @@ -349,6 +404,8 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); + g_test_add_func("/bdrv-drain/nested", test_nested); + g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); From 0152bf400fe3ca7facb382683bfcccda70ebf51a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Dec 2017 13:03:13 +0100 Subject: [PATCH 420/546] block: Don't notify parents in drain call chain This is in preparation for subtree drains, i.e. drained sections that affect not only a single node, but recursively all child nodes, too. Calling the parent callbacks for drain is pointless when we just came from that parent node recursively and leads to multiple increases of bs->quiesce_counter in a single drain call. Don't do it. In order for this to work correctly, the parent callback must be called for every bdrv_drain_begin/end() call, not only for the outermost one: If we have a node N with two parents A and B, recursive draining of A should cause the quiesce_counter of B to increase because its child N is drained independently of B. If now B is recursively drained, too, A must increase its quiesce_counter because N is drained independently of A only now, even if N is going from quiesce_counter 1 to 2. Signed-off-by: Kevin Wolf --- block.c | 13 ++++++++---- block/io.c | 47 +++++++++++++++++++++++++++++++------------ include/block/block.h | 4 ++-- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/block.c b/block.c index dd90dca896..6c247167b8 100644 --- a/block.c +++ b/block.c @@ -1972,13 +1972,16 @@ static void bdrv_replace_child_noperm(BdrvChild *child, BlockDriverState *new_bs) { BlockDriverState *old_bs = child->bs; + int i; if (old_bs && new_bs) { assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); } if (old_bs) { if (old_bs->quiesce_counter && child->role->drained_end) { - child->role->drained_end(child); + for (i = 0; i < old_bs->quiesce_counter; i++) { + child->role->drained_end(child); + } } if (child->role->detach) { child->role->detach(child); @@ -1991,7 +1994,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child, if (new_bs) { QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); if (new_bs->quiesce_counter && child->role->drained_begin) { - child->role->drained_begin(child); + for (i = 0; i < new_bs->quiesce_counter; i++) { + child->role->drained_begin(child); + } } if (child->role->attach) { @@ -4759,7 +4764,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) AioContext *ctx = bdrv_get_aio_context(bs); aio_disable_external(ctx); - bdrv_parent_drained_begin(bs); + bdrv_parent_drained_begin(bs, NULL); bdrv_drain(bs); /* ensure there are no in-flight requests */ while (aio_poll(ctx, false)) { @@ -4773,7 +4778,7 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) */ aio_context_acquire(new_context); bdrv_attach_aio_context(bs, new_context); - bdrv_parent_drained_end(bs); + bdrv_parent_drained_end(bs, NULL); aio_enable_external(ctx); aio_context_release(new_context); } diff --git a/block/io.c b/block/io.c index 6038a16c58..09de0a9070 100644 --- a/block/io.c +++ b/block/io.c @@ -40,22 +40,28 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, BdrvRequestFlags flags); -void bdrv_parent_drained_begin(BlockDriverState *bs) +void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { + if (c == ignore) { + continue; + } if (c->role->drained_begin) { c->role->drained_begin(c); } } } -void bdrv_parent_drained_end(BlockDriverState *bs) +void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) { BdrvChild *c, *next; QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { + if (c == ignore) { + continue; + } if (c->role->drained_end) { c->role->drained_end(c); } @@ -139,6 +145,7 @@ typedef struct { BlockDriverState *bs; bool done; bool begin; + BdrvChild *parent; } BdrvCoDrainData; static void coroutine_fn bdrv_drain_invoke_entry(void *opaque) @@ -211,6 +218,9 @@ static bool bdrv_drain_recurse(BlockDriverState *bs) return waited; } +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent); +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent); + static void bdrv_co_drain_bh_cb(void *opaque) { BdrvCoDrainData *data = opaque; @@ -219,9 +229,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) bdrv_dec_in_flight(bs); if (data->begin) { - bdrv_drained_begin(bs); + bdrv_do_drained_begin(bs, data->parent); } else { - bdrv_drained_end(bs); + bdrv_do_drained_end(bs, data->parent); } data->done = true; @@ -229,7 +239,7 @@ static void bdrv_co_drain_bh_cb(void *opaque) } static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, - bool begin) + bool begin, BdrvChild *parent) { BdrvCoDrainData data; @@ -243,6 +253,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, .bs = bs, .done = false, .begin = begin, + .parent = parent, }; bdrv_inc_in_flight(bs); aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), @@ -254,29 +265,34 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, assert(data.done); } -void bdrv_drained_begin(BlockDriverState *bs) +static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) { if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, true); + bdrv_co_yield_to_drain(bs, true, parent); return; } /* Stop things in parent-to-child order */ if (atomic_fetch_inc(&bs->quiesce_counter) == 0) { aio_disable_external(bdrv_get_aio_context(bs)); - bdrv_parent_drained_begin(bs); } + bdrv_parent_drained_begin(bs, parent); bdrv_drain_invoke(bs, true, false); bdrv_drain_recurse(bs); } -void bdrv_drained_end(BlockDriverState *bs) +void bdrv_drained_begin(BlockDriverState *bs) +{ + bdrv_do_drained_begin(bs, NULL); +} + +static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) { int old_quiesce_counter; if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, false); + bdrv_co_yield_to_drain(bs, false, parent); return; } assert(bs->quiesce_counter > 0); @@ -284,12 +300,17 @@ void bdrv_drained_end(BlockDriverState *bs) /* Re-enable things in child-to-parent order */ bdrv_drain_invoke(bs, false, false); + bdrv_parent_drained_end(bs, parent); if (old_quiesce_counter == 1) { - bdrv_parent_drained_end(bs); aio_enable_external(bdrv_get_aio_context(bs)); } } +void bdrv_drained_end(BlockDriverState *bs) +{ + bdrv_do_drained_end(bs, NULL); +} + /* * Wait for pending requests to complete on a single BlockDriverState subtree, * and suspend block driver's internal I/O until next request arrives. @@ -346,7 +367,7 @@ void bdrv_drain_all_begin(void) /* Stop things in parent-to-child order */ aio_context_acquire(aio_context); aio_disable_external(aio_context); - bdrv_parent_drained_begin(bs); + bdrv_parent_drained_begin(bs, NULL); bdrv_drain_invoke(bs, true, true); aio_context_release(aio_context); @@ -391,7 +412,7 @@ void bdrv_drain_all_end(void) /* Re-enable things in child-to-parent order */ aio_context_acquire(aio_context); bdrv_drain_invoke(bs, false, true); - bdrv_parent_drained_end(bs); + bdrv_parent_drained_end(bs, NULL); aio_enable_external(aio_context); aio_context_release(aio_context); } diff --git a/include/block/block.h b/include/block/block.h index c05cac57e5..60c5d11029 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -585,7 +585,7 @@ void bdrv_io_unplug(BlockDriverState *bs); * Begin a quiesced section of all users of @bs. This is part of * bdrv_drained_begin. */ -void bdrv_parent_drained_begin(BlockDriverState *bs); +void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore); /** * bdrv_parent_drained_end: @@ -593,7 +593,7 @@ void bdrv_parent_drained_begin(BlockDriverState *bs); * End a quiesced section of all users of @bs. This is part of * bdrv_drained_end. */ -void bdrv_parent_drained_end(BlockDriverState *bs); +void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); /** * bdrv_drained_begin: From b0165585900f050f403cecba9d89adeccf35dd6c Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 17:05:44 +0100 Subject: [PATCH 421/546] block: Add bdrv_subtree_drained_begin/end() bdrv_drained_begin() waits for the completion of requests in the whole subtree, but it only actually keeps its immediate bs parameter quiesced until bdrv_drained_end(). Add a version that keeps the whole subtree drained. As of this commit, graph changes cannot be allowed during a subtree drained section, but this will be fixed soon. Signed-off-by: Kevin Wolf --- block/io.c | 54 ++++++++++++++++++++++++++++++++++--------- include/block/block.h | 13 +++++++++++ 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/block/io.c b/block/io.c index 09de0a9070..6befef166d 100644 --- a/block/io.c +++ b/block/io.c @@ -145,6 +145,7 @@ typedef struct { BlockDriverState *bs; bool done; bool begin; + bool recursive; BdrvChild *parent; } BdrvCoDrainData; @@ -218,8 +219,10 @@ static bool bdrv_drain_recurse(BlockDriverState *bs) return waited; } -static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent); -static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent); +static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent); +static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent); static void bdrv_co_drain_bh_cb(void *opaque) { @@ -229,9 +232,9 @@ static void bdrv_co_drain_bh_cb(void *opaque) bdrv_dec_in_flight(bs); if (data->begin) { - bdrv_do_drained_begin(bs, data->parent); + bdrv_do_drained_begin(bs, data->recursive, data->parent); } else { - bdrv_do_drained_end(bs, data->parent); + bdrv_do_drained_end(bs, data->recursive, data->parent); } data->done = true; @@ -239,7 +242,8 @@ static void bdrv_co_drain_bh_cb(void *opaque) } static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, - bool begin, BdrvChild *parent) + bool begin, bool recursive, + BdrvChild *parent) { BdrvCoDrainData data; @@ -253,6 +257,7 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, .bs = bs, .done = false, .begin = begin, + .recursive = recursive, .parent = parent, }; bdrv_inc_in_flight(bs); @@ -265,10 +270,13 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, assert(data.done); } -static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) +static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent) { + BdrvChild *child, *next; + if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, true, parent); + bdrv_co_yield_to_drain(bs, true, recursive, parent); return; } @@ -280,19 +288,32 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent) bdrv_parent_drained_begin(bs, parent); bdrv_drain_invoke(bs, true, false); bdrv_drain_recurse(bs); + + if (recursive) { + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { + bdrv_do_drained_begin(child->bs, true, child); + } + } } void bdrv_drained_begin(BlockDriverState *bs) { - bdrv_do_drained_begin(bs, NULL); + bdrv_do_drained_begin(bs, false, NULL); } -static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) +void bdrv_subtree_drained_begin(BlockDriverState *bs) { + bdrv_do_drained_begin(bs, true, NULL); +} + +static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent) +{ + BdrvChild *child, *next; int old_quiesce_counter; if (qemu_in_coroutine()) { - bdrv_co_yield_to_drain(bs, false, parent); + bdrv_co_yield_to_drain(bs, false, recursive, parent); return; } assert(bs->quiesce_counter > 0); @@ -304,11 +325,22 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent) if (old_quiesce_counter == 1) { aio_enable_external(bdrv_get_aio_context(bs)); } + + if (recursive) { + QLIST_FOREACH_SAFE(child, &bs->children, next, next) { + bdrv_do_drained_end(child->bs, true, child); + } + } } void bdrv_drained_end(BlockDriverState *bs) { - bdrv_do_drained_end(bs, NULL); + bdrv_do_drained_end(bs, false, NULL); +} + +void bdrv_subtree_drained_end(BlockDriverState *bs) +{ + bdrv_do_drained_end(bs, true, NULL); } /* diff --git a/include/block/block.h b/include/block/block.h index 60c5d11029..de9c5a2b9b 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -607,6 +607,14 @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore); */ void bdrv_drained_begin(BlockDriverState *bs); +/** + * Like bdrv_drained_begin, but recursively begins a quiesced section for + * exclusive access to all child nodes as well. + * + * Graph changes are not allowed during a subtree drain section. + */ +void bdrv_subtree_drained_begin(BlockDriverState *bs); + /** * bdrv_drained_end: * @@ -614,6 +622,11 @@ void bdrv_drained_begin(BlockDriverState *bs); */ void bdrv_drained_end(BlockDriverState *bs); +/** + * End a quiescent section started by bdrv_subtree_drained_begin(). + */ +void bdrv_subtree_drained_end(BlockDriverState *bs); + void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child, Error **errp); void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp); From d2a85d0f42f328d5e4c948262234b4071e9a2a8e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 18:13:53 +0100 Subject: [PATCH 422/546] test-bdrv-drain: Tests for bdrv_subtree_drain Add a subtree drain version to the existing test cases. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 9098b77ab4..f363d51b34 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -85,6 +85,7 @@ static void aio_ret_cb(void *opaque, int ret) enum drain_type { BDRV_DRAIN_ALL, BDRV_DRAIN, + BDRV_SUBTREE_DRAIN, DRAIN_TYPE_MAX, }; @@ -93,6 +94,7 @@ static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) switch (drain_type) { case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; case BDRV_DRAIN: bdrv_drained_begin(bs); break; + case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break; default: g_assert_not_reached(); } } @@ -102,6 +104,7 @@ static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) switch (drain_type) { case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; case BDRV_DRAIN: bdrv_drained_end(bs); break; + case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break; default: g_assert_not_reached(); } } @@ -180,6 +183,11 @@ static void test_drv_cb_drain(void) test_drv_cb_common(BDRV_DRAIN, false); } +static void test_drv_cb_drain_subtree(void) +{ + test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); +} + static void test_quiesce_common(enum drain_type drain_type, bool recursive) { BlockBackend *blk; @@ -222,6 +230,11 @@ static void test_quiesce_drain(void) test_quiesce_common(BDRV_DRAIN, false); } +static void test_quiesce_drain_subtree(void) +{ + test_quiesce_common(BDRV_SUBTREE_DRAIN, true); +} + static void test_nested(void) { BlockBackend *blk; @@ -244,7 +257,8 @@ static void test_nested(void) /* XXX bdrv_drain_all() doesn't increase the quiesce_counter */ int bs_quiesce = (outer != BDRV_DRAIN_ALL) + (inner != BDRV_DRAIN_ALL); - int backing_quiesce = 0; + int backing_quiesce = (outer == BDRV_SUBTREE_DRAIN) + + (inner == BDRV_SUBTREE_DRAIN); int backing_cb_cnt = (outer != BDRV_DRAIN) + (inner != BDRV_DRAIN); @@ -391,6 +405,11 @@ static void test_blockjob_drain(void) test_blockjob_common(BDRV_DRAIN); } +static void test_blockjob_drain_subtree(void) +{ + test_blockjob_common(BDRV_SUBTREE_DRAIN); +} + int main(int argc, char **argv) { bdrv_init(); @@ -400,14 +419,20 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); + g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", + test_drv_cb_drain_subtree); g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); + g_test_add_func("/bdrv-drain/quiesce/drain_subtree", + test_quiesce_drain_subtree); g_test_add_func("/bdrv-drain/nested", test_nested); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); + g_test_add_func("/bdrv-drain/blockjob/drain_subtree", + test_blockjob_drain_subtree); return g_test_run(); } From 0582eb1006518881ecf93ba69c051335334a03e6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 Dec 2017 18:51:16 +0100 Subject: [PATCH 423/546] test-bdrv-drain: Test behaviour in coroutine context If bdrv_do_drained_begin/end() are called in coroutine context, they first use a BH to get out of the coroutine context. Call some existing tests again from a coroutine to cover this code path. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index f363d51b34..354c6151a0 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -82,6 +82,34 @@ static void aio_ret_cb(void *opaque, int ret) *aio_ret = ret; } +typedef struct CallInCoroutineData { + void (*entry)(void); + bool done; +} CallInCoroutineData; + +static coroutine_fn void call_in_coroutine_entry(void *opaque) +{ + CallInCoroutineData *data = opaque; + + data->entry(); + data->done = true; +} + +static void call_in_coroutine(void (*entry)(void)) +{ + Coroutine *co; + CallInCoroutineData data = { + .entry = entry, + .done = false, + }; + + co = qemu_coroutine_create(call_in_coroutine_entry, &data); + qemu_coroutine_enter(co); + while (!data.done) { + aio_poll(qemu_get_aio_context(), true); + } +} + enum drain_type { BDRV_DRAIN_ALL, BDRV_DRAIN, @@ -188,6 +216,16 @@ static void test_drv_cb_drain_subtree(void) test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); } +static void test_drv_cb_co_drain(void) +{ + call_in_coroutine(test_drv_cb_drain); +} + +static void test_drv_cb_co_drain_subtree(void) +{ + call_in_coroutine(test_drv_cb_drain_subtree); +} + static void test_quiesce_common(enum drain_type drain_type, bool recursive) { BlockBackend *blk; @@ -235,6 +273,16 @@ static void test_quiesce_drain_subtree(void) test_quiesce_common(BDRV_SUBTREE_DRAIN, true); } +static void test_quiesce_co_drain(void) +{ + call_in_coroutine(test_quiesce_drain); +} + +static void test_quiesce_co_drain_subtree(void) +{ + call_in_coroutine(test_quiesce_drain_subtree); +} + static void test_nested(void) { BlockBackend *blk; @@ -422,11 +470,22 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", test_drv_cb_drain_subtree); + // XXX bdrv_drain_all() doesn't work in coroutine context + g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); + g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree", + test_drv_cb_co_drain_subtree); + + g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); g_test_add_func("/bdrv-drain/quiesce/drain_subtree", test_quiesce_drain_subtree); + // XXX bdrv_drain_all() doesn't work in coroutine context + g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); + g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree", + test_quiesce_co_drain_subtree); + g_test_add_func("/bdrv-drain/nested", test_nested); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); From 27e64474a384e68ca928fa875930b921b53d61f4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 14 Dec 2017 11:41:17 +0100 Subject: [PATCH 424/546] test-bdrv-drain: Recursive draining with multiple parents Test that drain sections are correctly propagated through the graph. Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 354c6151a0..690b585b4d 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -338,6 +338,79 @@ static void test_nested(void) blk_unref(blk); } +static void test_multiparent(void) +{ + BlockBackend *blk_a, *blk_b; + BlockDriverState *bs_a, *bs_b, *backing; + BDRVTestState *a_s, *b_s, *backing_s; + + blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, + &error_abort); + a_s = bs_a->opaque; + blk_insert_bs(blk_a, bs_a, &error_abort); + + blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, + &error_abort); + b_s = bs_b->opaque; + blk_insert_bs(blk_b, bs_b, &error_abort); + + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); + backing_s = backing->opaque; + bdrv_set_backing_hd(bs_a, backing, &error_abort); + bdrv_set_backing_hd(bs_b, backing, &error_abort); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(a_s->drain_count, ==, 0); + g_assert_cmpint(b_s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 1); + g_assert_cmpint(bs_b->quiesce_counter, ==, 1); + g_assert_cmpint(backing->quiesce_counter, ==, 1); + g_assert_cmpint(a_s->drain_count, ==, 1); + g_assert_cmpint(b_s->drain_count, ==, 1); + g_assert_cmpint(backing_s->drain_count, ==, 1); + + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 2); + g_assert_cmpint(bs_b->quiesce_counter, ==, 2); + g_assert_cmpint(backing->quiesce_counter, ==, 2); + g_assert_cmpint(a_s->drain_count, ==, 2); + g_assert_cmpint(b_s->drain_count, ==, 2); + g_assert_cmpint(backing_s->drain_count, ==, 2); + + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 1); + g_assert_cmpint(bs_b->quiesce_counter, ==, 1); + g_assert_cmpint(backing->quiesce_counter, ==, 1); + g_assert_cmpint(a_s->drain_count, ==, 1); + g_assert_cmpint(b_s->drain_count, ==, 1); + g_assert_cmpint(backing_s->drain_count, ==, 1); + + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(a_s->drain_count, ==, 0); + g_assert_cmpint(b_s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + bdrv_unref(backing); + bdrv_unref(bs_a); + bdrv_unref(bs_b); + blk_unref(blk_a); + blk_unref(blk_b); +} + typedef struct TestBlockJob { BlockJob common; @@ -487,6 +560,7 @@ int main(int argc, char **argv) test_quiesce_co_drain_subtree); g_test_add_func("/bdrv-drain/nested", test_nested); + g_test_add_func("/bdrv-drain/multiparent", test_multiparent); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); From d736f119dae6d292e8d60f2e02fa51a79524113e Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 18 Dec 2017 16:05:48 +0100 Subject: [PATCH 425/546] block: Allow graph changes in subtree drained section We need to remember how many of the drain sections in which a node is were recursive (i.e. subtree drain rather than node drain), so that they can be correctly applied when children are added or removed during the drained section. With this change, it is safe to modify the graph even inside a bdrv_subtree_drained_begin/end() section. Signed-off-by: Kevin Wolf --- block.c | 32 +++++++++++++++++++++++++++++--- block/io.c | 28 ++++++++++++++++++++++++---- include/block/block.h | 2 -- include/block/block_int.h | 5 +++++ 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/block.c b/block.c index 6c247167b8..8b46ba21b1 100644 --- a/block.c +++ b/block.c @@ -822,6 +822,18 @@ static void bdrv_child_cb_drained_end(BdrvChild *child) bdrv_drained_end(bs); } +static void bdrv_child_cb_attach(BdrvChild *child) +{ + BlockDriverState *bs = child->opaque; + bdrv_apply_subtree_drain(child, bs); +} + +static void bdrv_child_cb_detach(BdrvChild *child) +{ + BlockDriverState *bs = child->opaque; + bdrv_unapply_subtree_drain(child, bs); +} + static int bdrv_child_cb_inactivate(BdrvChild *child) { BlockDriverState *bs = child->opaque; @@ -889,6 +901,8 @@ const BdrvChildRole child_file = { .inherit_options = bdrv_inherited_options, .drained_begin = bdrv_child_cb_drained_begin, .drained_end = bdrv_child_cb_drained_end, + .attach = bdrv_child_cb_attach, + .detach = bdrv_child_cb_detach, .inactivate = bdrv_child_cb_inactivate, }; @@ -911,6 +925,8 @@ const BdrvChildRole child_format = { .inherit_options = bdrv_inherited_fmt_options, .drained_begin = bdrv_child_cb_drained_begin, .drained_end = bdrv_child_cb_drained_end, + .attach = bdrv_child_cb_attach, + .detach = bdrv_child_cb_detach, .inactivate = bdrv_child_cb_inactivate, }; @@ -953,6 +969,8 @@ static void bdrv_backing_attach(BdrvChild *c) parent->backing_blocker); bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET, parent->backing_blocker); + + bdrv_child_cb_attach(c); } static void bdrv_backing_detach(BdrvChild *c) @@ -963,6 +981,8 @@ static void bdrv_backing_detach(BdrvChild *c) bdrv_op_unblock_all(c->bs, parent->backing_blocker); error_free(parent->backing_blocker); parent->backing_blocker = NULL; + + bdrv_child_cb_detach(c); } /* @@ -1978,14 +1998,17 @@ static void bdrv_replace_child_noperm(BdrvChild *child, assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); } if (old_bs) { + /* Detach first so that the recursive drain sections coming from @child + * are already gone and we only end the drain sections that came from + * elsewhere. */ + if (child->role->detach) { + child->role->detach(child); + } if (old_bs->quiesce_counter && child->role->drained_end) { for (i = 0; i < old_bs->quiesce_counter; i++) { child->role->drained_end(child); } } - if (child->role->detach) { - child->role->detach(child); - } QLIST_REMOVE(child, next_parent); } @@ -1999,6 +2022,9 @@ static void bdrv_replace_child_noperm(BdrvChild *child, } } + /* Attach only after starting new drained sections, so that recursive + * drain sections coming from @child don't get an extra .drained_begin + * callback. */ if (child->role->attach) { child->role->attach(child); } diff --git a/block/io.c b/block/io.c index 6befef166d..7ea402352e 100644 --- a/block/io.c +++ b/block/io.c @@ -270,8 +270,8 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs, assert(data.done); } -static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, - BdrvChild *parent) +void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, + BdrvChild *parent) { BdrvChild *child, *next; @@ -290,6 +290,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, bool recursive, bdrv_drain_recurse(bs); if (recursive) { + bs->recursive_quiesce_counter++; QLIST_FOREACH_SAFE(child, &bs->children, next, next) { bdrv_do_drained_begin(child->bs, true, child); } @@ -306,8 +307,8 @@ void bdrv_subtree_drained_begin(BlockDriverState *bs) bdrv_do_drained_begin(bs, true, NULL); } -static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, - BdrvChild *parent) +void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, + BdrvChild *parent) { BdrvChild *child, *next; int old_quiesce_counter; @@ -327,6 +328,7 @@ static void bdrv_do_drained_end(BlockDriverState *bs, bool recursive, } if (recursive) { + bs->recursive_quiesce_counter--; QLIST_FOREACH_SAFE(child, &bs->children, next, next) { bdrv_do_drained_end(child->bs, true, child); } @@ -343,6 +345,24 @@ void bdrv_subtree_drained_end(BlockDriverState *bs) bdrv_do_drained_end(bs, true, NULL); } +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent) +{ + int i; + + for (i = 0; i < new_parent->recursive_quiesce_counter; i++) { + bdrv_do_drained_begin(child->bs, true, child); + } +} + +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent) +{ + int i; + + for (i = 0; i < old_parent->recursive_quiesce_counter; i++) { + bdrv_do_drained_end(child->bs, true, child); + } +} + /* * Wait for pending requests to complete on a single BlockDriverState subtree, * and suspend block driver's internal I/O until next request arrives. diff --git a/include/block/block.h b/include/block/block.h index de9c5a2b9b..9b12774ddf 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -610,8 +610,6 @@ void bdrv_drained_begin(BlockDriverState *bs); /** * Like bdrv_drained_begin, but recursively begins a quiesced section for * exclusive access to all child nodes as well. - * - * Graph changes are not allowed during a subtree drain section. */ void bdrv_subtree_drained_begin(BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index e107163594..29cafa4236 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -717,6 +717,8 @@ struct BlockDriverState { /* Accessed with atomic ops. */ int quiesce_counter; + int recursive_quiesce_counter; + unsigned int write_gen; /* Current data generation */ /* Protected by reqs_lock. */ @@ -768,6 +770,9 @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags); +void bdrv_apply_subtree_drain(BdrvChild *child, BlockDriverState *new_parent); +void bdrv_unapply_subtree_drain(BdrvChild *child, BlockDriverState *old_parent); + int get_tmp_filename(char *filename, int size); BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size, const char *filename); From acebcf8de82da9a583875a0d32cb6c9a9d29cdb5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 18 Dec 2017 12:59:34 +0100 Subject: [PATCH 426/546] test-bdrv-drain: Test graph changes in drained section Signed-off-by: Kevin Wolf --- tests/test-bdrv-drain.c | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c index 690b585b4d..d760e2b243 100644 --- a/tests/test-bdrv-drain.c +++ b/tests/test-bdrv-drain.c @@ -411,6 +411,85 @@ static void test_multiparent(void) blk_unref(blk_b); } +static void test_graph_change(void) +{ + BlockBackend *blk_a, *blk_b; + BlockDriverState *bs_a, *bs_b, *backing; + BDRVTestState *a_s, *b_s, *backing_s; + + blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, + &error_abort); + a_s = bs_a->opaque; + blk_insert_bs(blk_a, bs_a, &error_abort); + + blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, + &error_abort); + b_s = bs_b->opaque; + blk_insert_bs(blk_b, bs_b, &error_abort); + + backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); + backing_s = backing->opaque; + bdrv_set_backing_hd(bs_a, backing, &error_abort); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(a_s->drain_count, ==, 0); + g_assert_cmpint(b_s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); + do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); + + bdrv_set_backing_hd(bs_b, backing, &error_abort); + g_assert_cmpint(bs_a->quiesce_counter, ==, 5); + g_assert_cmpint(bs_b->quiesce_counter, ==, 5); + g_assert_cmpint(backing->quiesce_counter, ==, 5); + g_assert_cmpint(a_s->drain_count, ==, 5); + g_assert_cmpint(b_s->drain_count, ==, 5); + g_assert_cmpint(backing_s->drain_count, ==, 5); + + bdrv_set_backing_hd(bs_b, NULL, &error_abort); + g_assert_cmpint(bs_a->quiesce_counter, ==, 3); + g_assert_cmpint(bs_b->quiesce_counter, ==, 2); + g_assert_cmpint(backing->quiesce_counter, ==, 3); + g_assert_cmpint(a_s->drain_count, ==, 3); + g_assert_cmpint(b_s->drain_count, ==, 2); + g_assert_cmpint(backing_s->drain_count, ==, 3); + + bdrv_set_backing_hd(bs_b, backing, &error_abort); + g_assert_cmpint(bs_a->quiesce_counter, ==, 5); + g_assert_cmpint(bs_b->quiesce_counter, ==, 5); + g_assert_cmpint(backing->quiesce_counter, ==, 5); + g_assert_cmpint(a_s->drain_count, ==, 5); + g_assert_cmpint(b_s->drain_count, ==, 5); + g_assert_cmpint(backing_s->drain_count, ==, 5); + + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); + do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); + do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); + + g_assert_cmpint(bs_a->quiesce_counter, ==, 0); + g_assert_cmpint(bs_b->quiesce_counter, ==, 0); + g_assert_cmpint(backing->quiesce_counter, ==, 0); + g_assert_cmpint(a_s->drain_count, ==, 0); + g_assert_cmpint(b_s->drain_count, ==, 0); + g_assert_cmpint(backing_s->drain_count, ==, 0); + + bdrv_unref(backing); + bdrv_unref(bs_a); + bdrv_unref(bs_b); + blk_unref(blk_a); + blk_unref(blk_b); +} + typedef struct TestBlockJob { BlockJob common; @@ -561,6 +640,7 @@ int main(int argc, char **argv) g_test_add_func("/bdrv-drain/nested", test_nested); g_test_add_func("/bdrv-drain/multiparent", test_multiparent); + g_test_add_func("/bdrv-drain/graph-change", test_graph_change); g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); From 44487eb973f895d68989cf931e25f309ec9807f9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 13:53:36 +0100 Subject: [PATCH 427/546] commit: Simplify reopen of base Since commit bde70715, base is the only node that is reopened in commit_start(). This means that the code, which still involves an explicit BlockReopenQueue, can now be simplified by using bdrv_reopen(). Signed-off-by: Kevin Wolf Reviewed-by: Fam Zheng --- block/commit.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/block/commit.c b/block/commit.c index c5327551ce..bb6c904704 100644 --- a/block/commit.c +++ b/block/commit.c @@ -277,7 +277,6 @@ void commit_start(const char *job_id, BlockDriverState *bs, const char *filter_node_name, Error **errp) { CommitBlockJob *s; - BlockReopenQueue *reopen_queue = NULL; int orig_base_flags; BlockDriverState *iter; BlockDriverState *commit_top_bs = NULL; @@ -299,12 +298,7 @@ void commit_start(const char *job_id, BlockDriverState *bs, /* convert base to r/w, if necessary */ orig_base_flags = bdrv_get_flags(base); if (!(orig_base_flags & BDRV_O_RDWR)) { - reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL, - orig_base_flags | BDRV_O_RDWR); - } - - if (reopen_queue) { - bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err); + bdrv_reopen(base, orig_base_flags | BDRV_O_RDWR, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); goto fail; From 1a63a907507fbbcfaee3f622907ec244b7eabda8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 6 Dec 2017 20:24:44 +0100 Subject: [PATCH 428/546] block: Keep nodes drained between reopen_queue/multiple The bdrv_reopen*() implementation doesn't like it if the graph is changed between queuing nodes for reopen and actually reopening them (one of the reasons is that queuing can be recursive). So instead of draining the device only in bdrv_reopen_multiple(), require that callers already drained all affected nodes, and assert this in bdrv_reopen_queue(). Signed-off-by: Kevin Wolf Reviewed-by: Fam Zheng --- block.c | 23 ++++++++++++++++------- block/replication.c | 6 ++++++ qemu-io-cmds.c | 3 +++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index 8b46ba21b1..a8da4f2b25 100644 --- a/block.c +++ b/block.c @@ -2766,6 +2766,7 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference, * returns a pointer to bs_queue, which is either the newly allocated * bs_queue, or the existing bs_queue being used. * + * bs must be drained between bdrv_reopen_queue() and bdrv_reopen_multiple(). */ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs, @@ -2781,6 +2782,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BdrvChild *child; QDict *old_options, *explicit_options; + /* Make sure that the caller remembered to use a drained section. This is + * important to avoid graph changes between the recursive queuing here and + * bdrv_reopen_multiple(). */ + assert(bs->quiesce_counter > 0); + if (bs_queue == NULL) { bs_queue = g_new0(BlockReopenQueue, 1); QSIMPLEQ_INIT(bs_queue); @@ -2905,6 +2911,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, * If all devices prepare successfully, then the changes are committed * to all devices. * + * All affected nodes must be drained between bdrv_reopen_queue() and + * bdrv_reopen_multiple(). */ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp) { @@ -2914,11 +2922,8 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er assert(bs_queue != NULL); - aio_context_release(ctx); - bdrv_drain_all_begin(); - aio_context_acquire(ctx); - QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) { + assert(bs_entry->state.bs->quiesce_counter > 0); if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) { error_propagate(errp, local_err); goto cleanup; @@ -2947,8 +2952,6 @@ cleanup: } g_free(bs_queue); - bdrv_drain_all_end(); - return ret; } @@ -2958,12 +2961,18 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) { int ret = -1; Error *local_err = NULL; - BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); + BlockReopenQueue *queue; + bdrv_subtree_drained_begin(bs); + + queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); } + + bdrv_subtree_drained_end(bs); + return ret; } diff --git a/block/replication.c b/block/replication.c index e41e293d2b..b1ea3caa4b 100644 --- a/block/replication.c +++ b/block/replication.c @@ -394,6 +394,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, new_secondary_flags = s->orig_secondary_flags; } + bdrv_subtree_drained_begin(s->hidden_disk->bs); + bdrv_subtree_drained_begin(s->secondary_disk->bs); + if (orig_hidden_flags != new_hidden_flags) { reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs, NULL, new_hidden_flags); @@ -409,6 +412,9 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable, reopen_queue, &local_err); error_propagate(errp, local_err); } + + bdrv_subtree_drained_end(s->hidden_disk->bs); + bdrv_subtree_drained_end(s->secondary_disk->bs); } static void backup_job_cleanup(BlockDriverState *bs) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index de8e3de726..a6a70fc3dc 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -2013,8 +2013,11 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv) opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL; qemu_opts_reset(&reopen_opts); + bdrv_subtree_drained_begin(bs); brq = bdrv_reopen_queue(NULL, bs, opts, flags); bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err); + bdrv_subtree_drained_end(bs); + if (local_err) { error_report_err(local_err); } else { From 4a42fa0ee20b51b326f6494cb50218b52471a261 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Tue, 14 Nov 2017 13:42:42 -0500 Subject: [PATCH 429/546] acpi: Update TPM2 ACPI table to more recent specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More recent specs of the TPM2 ACPI table add fields for the log area start address and the log area minimum size, which we already use for the TCPA table. Signed-off-by: Stefan Berger Reviewed-by: Marc-André Lureau --- hw/i386/acpi-build.c | 19 ++++++++++++++----- include/hw/acpi/acpi-defs.h | 7 +++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 5a6dee081c..18b939e469 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2274,16 +2274,25 @@ build_tpm_tcpa(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) } static void -build_tpm2(GArray *table_data, BIOSLinker *linker) +build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) { - Acpi20TPM2 *tpm2_ptr; - - tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); + Acpi20TPM2 *tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); + unsigned log_addr_size = sizeof(tpm2_ptr->log_area_start_address); + unsigned log_addr_offset = + (char *)&tpm2_ptr->log_area_start_address - table_data->data; tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); if (TPM_IS_TIS(tpm_find())) { tpm2_ptr->control_area_address = cpu_to_le64(0); tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + + tpm2_ptr->log_area_minimum_length = + cpu_to_le32(TPM_LOG_AREA_MINIMUM_SIZE); + + /* log area start address to be filled by Guest linker */ + bios_linker_loader_add_pointer(linker, + ACPI_BUILD_TABLE_FILE, log_addr_offset, log_addr_size, + ACPI_BUILD_TPMLOG_FILE, 0); } else { g_warn_if_reached(); } @@ -2695,7 +2704,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) if (misc.tpm_version == TPM_VERSION_2_0) { acpi_add_table(table_offsets, tables_blob); - build_tpm2(tables_blob, tables->linker); + build_tpm2(tables_blob, tables->linker, tables->tcpalog); } } if (pcms->numa_nodes) { diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 72be675dd6..80c8099a23 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -558,8 +558,8 @@ typedef struct Acpi20Tcpa Acpi20Tcpa; /* * TPM2 * - * Following Level 00, Rev 00.37 of specs: - * http://www.trustedcomputinggroup.org/resources/tcg_acpi_specification + * Following Version 1.2, Revision 8 of specs: + * https://trustedcomputinggroup.org/tcg-acpi-specification/ */ struct Acpi20TPM2 { ACPI_TABLE_HEADER_DEF @@ -567,6 +567,9 @@ struct Acpi20TPM2 { uint16_t reserved; uint64_t control_area_address; uint32_t start_method; + uint8_t start_method_params[12]; + uint32_t log_area_minimum_length; + uint64_t log_area_start_address; } QEMU_PACKED; typedef struct Acpi20TPM2 Acpi20TPM2; From 65255e8efdd5fca602bcc4ff61a879939ff75f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 14 Nov 2017 11:25:35 +0100 Subject: [PATCH 430/546] target/*helper: don't check retaddr before calling cpu_restore_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cpu_restore_state officially supports being passed an address it can't resolve the state for. As a result the checks in the helpers are superfluous and can be removed. This makes the code consistent with other users of cpu_restore_state. Of course this does nothing to address what to do if cpu_restore_state can't resolve the state but so far it seems this is handled elsewhere. The change was made with included coccinelle script. Signed-off-by: Alex Bennée [rth: Fixed up comment indentation. Added second hunk to script to combine cpu_restore_state and cpu_loop_exit.] Signed-off-by: Richard Henderson --- scripts/coccinelle/cpu_restore_state.cocci | 19 +++++++++++++++++++ target/alpha/mem_helper.c | 13 +++---------- target/arm/op_helper.c | 18 ++++++------------ target/i386/svm_helper.c | 4 +--- target/lm32/op_helper.c | 7 ++----- target/m68k/op_helper.c | 7 ++----- target/microblaze/op_helper.c | 7 ++----- target/moxie/helper.c | 4 +--- target/nios2/mmu.c | 7 ++----- target/openrisc/mmu_helper.c | 6 +----- target/tricore/op_helper.c | 13 +++---------- target/unicore32/op_helper.c | 7 ++----- 12 files changed, 44 insertions(+), 68 deletions(-) create mode 100644 scripts/coccinelle/cpu_restore_state.cocci diff --git a/scripts/coccinelle/cpu_restore_state.cocci b/scripts/coccinelle/cpu_restore_state.cocci new file mode 100644 index 0000000000..61bc749d14 --- /dev/null +++ b/scripts/coccinelle/cpu_restore_state.cocci @@ -0,0 +1,19 @@ +// Remove unneeded tests before calling cpu_restore_state +// +// spatch --macro-file scripts/cocci-macro-file.h \ +// --sp-file ./scripts/coccinelle/cpu_restore_state.cocci \ +// --keep-comments --in-place --use-gitgrep --dir target +@@ +expression A; +expression C; +@@ +-if (A) { + cpu_restore_state(C, A); +-} +@@ +expression A; +expression C; +@@ +- cpu_restore_state(C, A); +- cpu_loop_exit(C); ++ cpu_loop_exit_restore(C, A); diff --git a/target/alpha/mem_helper.c b/target/alpha/mem_helper.c index 3c06baa93a..430eea470b 100644 --- a/target/alpha/mem_helper.c +++ b/target/alpha/mem_helper.c @@ -34,9 +34,7 @@ void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr, uint64_t pc; uint32_t insn; - if (retaddr) { - cpu_restore_state(cs, retaddr); - } + cpu_restore_state(cs, retaddr); pc = env->pc; insn = cpu_ldl_code(env, pc); @@ -58,9 +56,7 @@ void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, AlphaCPU *cpu = ALPHA_CPU(cs); CPUAlphaState *env = &cpu->env; - if (retaddr) { - cpu_restore_state(cs, retaddr); - } + cpu_restore_state(cs, retaddr); env->trap_arg0 = addr; env->trap_arg1 = access_type == MMU_DATA_STORE ? 1 : 0; @@ -80,11 +76,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = alpha_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret != 0)) { - if (retaddr) { - cpu_restore_state(cs, retaddr); - } /* Exception index and error code are already set */ - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, retaddr); } } #endif /* CONFIG_USER_ONLY */ diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c index c2bb4f3a43..b36206343d 100644 --- a/target/arm/op_helper.c +++ b/target/arm/op_helper.c @@ -182,10 +182,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); deliver_fault(cpu, addr, access_type, mmu_idx, &fi); } @@ -199,10 +197,8 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, ARMCPU *cpu = ARM_CPU(cs); ARMMMUFaultInfo fi = {}; - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); fi.type = ARMFault_Alignment; deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); @@ -221,10 +217,8 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, ARMCPU *cpu = ARM_CPU(cs); ARMMMUFaultInfo fi = {}; - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); /* The EA bit in syndromes and fault status registers is an * IMPDEF classification of external aborts. ARM implementations diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index f479239875..303106981c 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -584,9 +584,7 @@ void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1, { CPUState *cs = CPU(x86_env_get_cpu(env)); - if (retaddr) { - cpu_restore_state(cs, retaddr); - } + cpu_restore_state(cs, retaddr); qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", diff --git a/target/lm32/op_helper.c b/target/lm32/op_helper.c index 2177c8ad12..30f670eee8 100644 --- a/target/lm32/op_helper.c +++ b/target/lm32/op_helper.c @@ -151,11 +151,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = lm32_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, retaddr); } } #endif diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 63089511cb..78bfb9f0cc 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -46,11 +46,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = m68k_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, retaddr); } } diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 1e07e21c1c..4cf51568df 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -40,11 +40,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = mb_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, retaddr); } } #endif diff --git a/target/moxie/helper.c b/target/moxie/helper.c index 330299f5a7..2ecee89f11 100644 --- a/target/moxie/helper.c +++ b/target/moxie/helper.c @@ -36,9 +36,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = moxie_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - cpu_restore_state(cs, retaddr); - } + cpu_restore_state(cs, retaddr); } cpu_loop_exit(cs); } diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c index fe9298af50..0cd8647510 100644 --- a/target/nios2/mmu.c +++ b/target/nios2/mmu.c @@ -42,11 +42,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = nios2_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, retaddr); } } diff --git a/target/openrisc/mmu_helper.c b/target/openrisc/mmu_helper.c index a44d0aa51a..a3e182c42d 100644 --- a/target/openrisc/mmu_helper.c +++ b/target/openrisc/mmu_helper.c @@ -33,12 +33,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = openrisc_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (ret) { - if (retaddr) { - /* now we have a real cpu fault. */ - cpu_restore_state(cs, retaddr); - } /* Raise Exception. */ - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, retaddr); } } #endif diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index 7af202c8c0..40ed229486 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -31,9 +31,7 @@ raise_exception_sync_internal(CPUTriCoreState *env, uint32_t class, int tin, { CPUState *cs = CPU(tricore_env_get_cpu(env)); /* in case we come from a helper-call we need to restore the PC */ - if (pc) { - cpu_restore_state(cs, pc); - } + cpu_restore_state(cs, pc); /* Tin is loaded into d[15] */ env->gpr_d[15] = tin; @@ -2804,13 +2802,8 @@ static inline void QEMU_NORETURN do_raise_exception_err(CPUTriCoreState *env, CPUState *cs = CPU(tricore_env_get_cpu(env)); cs->exception_index = exception; env->error_code = error_code; - - if (pc) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, pc); - } - - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, pc); } void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, diff --git a/target/unicore32/op_helper.c b/target/unicore32/op_helper.c index 0872c29faa..8788642a7f 100644 --- a/target/unicore32/op_helper.c +++ b/target/unicore32/op_helper.c @@ -251,11 +251,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = uc32_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - if (retaddr) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + /* now we have a real cpu fault */ + cpu_loop_exit_restore(cs, retaddr); } } #endif From 1f5940e4642f4a2c64bcba724eaff3c28ae38c54 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Nov 2017 11:29:34 +0100 Subject: [PATCH 431/546] target/moxie: Fix tlb_fill We should not exit unless moxie_cpu_handle_mmu_fault has failed. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson --- target/moxie/helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/moxie/helper.c b/target/moxie/helper.c index 2ecee89f11..6890ffd71c 100644 --- a/target/moxie/helper.c +++ b/target/moxie/helper.c @@ -36,9 +36,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, ret = moxie_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret)) { - cpu_restore_state(cs, retaddr); + cpu_loop_exit_restore(cs, retaddr); } - cpu_loop_exit(cs); } void helper_raise_exception(CPUMoxieState *env, int ex) From f764718d0cb30af9f1f8e1d6a33622cc05ca4155 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Nov 2017 12:47:37 +0100 Subject: [PATCH 432/546] tcg: Remove TCGV_UNUSED* and TCGV_IS_UNUSED* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are now trivial sets and tests against NULL. Unwrap. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/alpha/translate.c | 22 ++++++------- target/arm/translate-a64.c | 35 +++++++++----------- target/arm/translate.c | 29 ++++++++--------- target/cris/translate.c | 2 +- target/hppa/translate.c | 63 ++++++++++++++++++------------------ target/i386/translate.c | 13 ++++---- target/m68k/translate.c | 14 ++++---- target/mips/translate.c | 2 +- target/nios2/translate.c | 6 ++-- target/ppc/translate.c | 2 +- target/s390x/translate.c | 42 ++++++++++++------------ target/sh4/translate.c | 4 +-- target/sparc/translate.c | 2 +- target/tilegx/translate.c | 10 +++--- target/unicore32/translate.c | 4 +-- tcg/tcg-op.h | 4 --- tcg/tcg.c | 4 +-- tcg/tcg.h | 9 ------ 18 files changed, 123 insertions(+), 144 deletions(-) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 629f35ec8e..73a1b5e63e 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -156,7 +156,7 @@ void alpha_translate_init(void) static TCGv load_zero(DisasContext *ctx) { - if (TCGV_IS_UNUSED_I64(ctx->zero)) { + if (!ctx->zero) { ctx->zero = tcg_const_i64(0); } return ctx->zero; @@ -164,7 +164,7 @@ static TCGv load_zero(DisasContext *ctx) static TCGv dest_sink(DisasContext *ctx) { - if (TCGV_IS_UNUSED_I64(ctx->sink)) { + if (!ctx->sink) { ctx->sink = tcg_temp_new(); } return ctx->sink; @@ -172,18 +172,18 @@ static TCGv dest_sink(DisasContext *ctx) static void free_context_temps(DisasContext *ctx) { - if (!TCGV_IS_UNUSED_I64(ctx->sink)) { + if (ctx->sink) { tcg_gen_discard_i64(ctx->sink); tcg_temp_free(ctx->sink); - TCGV_UNUSED_I64(ctx->sink); + ctx->sink = NULL; } - if (!TCGV_IS_UNUSED_I64(ctx->zero)) { + if (ctx->zero) { tcg_temp_free(ctx->zero); - TCGV_UNUSED_I64(ctx->zero); + ctx->zero = NULL; } - if (!TCGV_IS_UNUSED_I64(ctx->lit)) { + if (ctx->lit) { tcg_temp_free(ctx->lit); - TCGV_UNUSED_I64(ctx->lit); + ctx->lit = NULL; } } @@ -2948,9 +2948,9 @@ static int alpha_tr_init_disas_context(DisasContextBase *dcbase, /* Similarly for flush-to-zero. */ ctx->tb_ftz = -1; - TCGV_UNUSED_I64(ctx->zero); - TCGV_UNUSED_I64(ctx->sink); - TCGV_UNUSED_I64(ctx->lit); + ctx->zero = NULL; + ctx->sink = NULL; + ctx->lit = NULL; /* Bound the number of insns to execute to those left on the page. */ if (in_superpage(ctx, ctx->base.pc_first)) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 625ef2dfd2..460bab5987 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -405,10 +405,7 @@ static void unallocated_encoding(DisasContext *s) static void init_tmp_a64_array(DisasContext *s) { #ifdef CONFIG_DEBUG_TCG - int i; - for (i = 0; i < ARRAY_SIZE(s->tmp_a64); i++) { - TCGV_UNUSED_I64(s->tmp_a64[i]); - } + memset(s->tmp_a64, 0, sizeof(s->tmp_a64)); #endif s->tmp_a64_count = 0; } @@ -6276,7 +6273,7 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn) return; } - TCGV_UNUSED_PTR(fpst); + fpst = NULL; break; case 0xc: /* FMAXNMP */ case 0xd: /* FADDP */ @@ -6371,7 +6368,7 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn) tcg_temp_free_i32(tcg_res); } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } @@ -6387,7 +6384,7 @@ static void handle_shri_with_rndacc(TCGv_i64 tcg_res, TCGv_i64 tcg_src, bool is_u, int size, int shift) { bool extended_result = false; - bool round = !TCGV_IS_UNUSED_I64(tcg_rnd); + bool round = tcg_rnd != NULL; int ext_lshift = 0; TCGv_i64 tcg_src_hi; @@ -6533,7 +6530,7 @@ static void handle_scalar_simd_shri(DisasContext *s, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } tcg_rn = read_fp_dreg(s, rn); @@ -6649,7 +6646,7 @@ static void handle_vec_simd_sqshrn(DisasContext *s, bool is_scalar, bool is_q, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -8239,8 +8236,8 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn) gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env); tcg_fpstatus = get_fpstatus_ptr(); } else { - TCGV_UNUSED_I32(tcg_rmode); - TCGV_UNUSED_PTR(tcg_fpstatus); + tcg_rmode = NULL; + tcg_fpstatus = NULL; } if (size == 3) { @@ -8360,7 +8357,7 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -8502,7 +8499,7 @@ static void handle_vec_simd_shrn(DisasContext *s, bool is_q, uint64_t round_const = 1ULL << (shift - 1); tcg_round = tcg_const_i64(round_const); } else { - TCGV_UNUSED_I64(tcg_round); + tcg_round = NULL; } for (i = 0; i < elements; i++) { @@ -9168,7 +9165,7 @@ static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode, if (opcode >= 0x58) { fpst = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(fpst); + fpst = NULL; } if (!fp_access_check(s)) { @@ -9305,7 +9302,7 @@ static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode, } } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } @@ -10226,13 +10223,13 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn) if (need_fpstatus) { tcg_fpstatus = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(tcg_fpstatus); + tcg_fpstatus = NULL; } if (need_rmode) { tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode)); gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env); } else { - TCGV_UNUSED_I32(tcg_rmode); + tcg_rmode = NULL; } if (size == 3) { @@ -10593,7 +10590,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) if (is_fp) { fpst = get_fpstatus_ptr(); } else { - TCGV_UNUSED_PTR(fpst); + fpst = NULL; } if (size == 3) { @@ -10917,7 +10914,7 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } } - if (!TCGV_IS_UNUSED_PTR(fpst)) { + if (fpst) { tcg_temp_free_ptr(fpst); } } diff --git a/target/arm/translate.c b/target/arm/translate.c index e15192d5d6..46c25ae2c1 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -2169,8 +2169,8 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn) tmp3 = tcg_const_i32((insn & 1) << 5); break; default: - TCGV_UNUSED_I32(tmp2); - TCGV_UNUSED_I32(tmp3); + tmp2 = NULL; + tmp3 = NULL; } gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3); tcg_temp_free_i32(tmp3); @@ -4939,7 +4939,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) } } else /* size == 0 */ { if (load) { - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; for (n = 0; n < 4; n++) { tmp = tcg_temp_new_i32(); gen_aa32_ld8u(s, tmp, addr, get_mem_index(s)); @@ -6643,11 +6643,11 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) tmp = neon_load_reg(rn, 1); neon_store_scratch(2, tmp); } - TCGV_UNUSED_I32(tmp3); + tmp3 = NULL; for (pass = 0; pass < 2; pass++) { if (src1_wide) { neon_load_reg64(cpu_V0, rn + pass); - TCGV_UNUSED_I32(tmp); + tmp = NULL; } else { if (pass == 1 && rd == rn) { tmp = neon_load_scratch(2); @@ -6660,7 +6660,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) } if (src2_wide) { neon_load_reg64(cpu_V1, rm + pass); - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; } else { if (pass == 1 && rd == rm) { tmp2 = neon_load_scratch(2); @@ -7078,7 +7078,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (rm & 1) { return 1; } - TCGV_UNUSED_I32(tmp2); + tmp2 = NULL; for (pass = 0; pass < 2; pass++) { neon_load_reg64(cpu_V0, rm + pass); tmp = tcg_temp_new_i32(); @@ -7217,7 +7217,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) if (neon_2rm_is_float_op(op)) { tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass)); - TCGV_UNUSED_I32(tmp); + tmp = NULL; } else { tmp = neon_load_reg(rm, pass); } @@ -8666,7 +8666,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) rn = (insn >> 16) & 0xf; tmp = load_reg(s, rn); } else { - TCGV_UNUSED_I32(tmp); + tmp = NULL; } rd = (insn >> 12) & 0xf; switch(op1) { @@ -9505,7 +9505,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) /* compute total size */ loaded_base = 0; - TCGV_UNUSED_I32(loaded_var); + loaded_var = NULL; n = 0; for(i=0;i<16;i++) { if (insn & (1 << i)) @@ -10074,7 +10074,7 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) tcg_gen_addi_i32(addr, addr, -offset); } - TCGV_UNUSED_I32(loaded_var); + loaded_var = NULL; for (i = 0; i < 16; i++) { if ((insn & (1 << i)) == 0) continue; @@ -11355,7 +11355,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) } else if (op != 0xf) { /* mvn doesn't read its first operand */ tmp = load_reg(s, rd); } else { - TCGV_UNUSED_I32(tmp); + tmp = NULL; } tmp2 = load_reg(s, rm); @@ -11686,7 +11686,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) tcg_gen_addi_i32(addr, addr, 4); } } - TCGV_UNUSED_I32(tmp); + tmp = NULL; if (insn & (1 << 8)) { if (insn & (1 << 11)) { /* pop pc */ @@ -11831,8 +11831,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn) case 12: { /* load/store multiple */ - TCGv_i32 loaded_var; - TCGV_UNUSED_I32(loaded_var); + TCGv_i32 loaded_var = NULL; rn = (insn >> 8) & 0x7; addr = load_reg(s, rn); for (i = 0; i < 8; i++) { diff --git a/target/cris/translate.c b/target/cris/translate.c index 2831419845..74822ed31f 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -2603,7 +2603,7 @@ static int dec_movem_mr(CPUCRISState *env, DisasContext *dc) tcg_gen_addi_tl(addr, cpu_R[dc->op1], i * 8); gen_load(dc, tmp32, addr, 4, 0); } else { - TCGV_UNUSED(tmp32); + tmp32 = NULL; } tcg_temp_free(addr); diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 53aa1f88c4..31d9a2a31b 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -125,7 +125,7 @@ void hppa_translate_init(void) int i; - TCGV_UNUSED(cpu_gr[0]); + cpu_gr[0] = NULL; for (i = 1; i < 32; i++) { cpu_gr[i] = tcg_global_mem_new(cpu_env, offsetof(CPUHPPAState, gr[i]), @@ -140,28 +140,31 @@ void hppa_translate_init(void) static DisasCond cond_make_f(void) { - DisasCond r = { .c = TCG_COND_NEVER }; - TCGV_UNUSED(r.a0); - TCGV_UNUSED(r.a1); - return r; + return (DisasCond){ + .c = TCG_COND_NEVER, + .a0 = NULL, + .a1 = NULL, + }; } static DisasCond cond_make_n(void) { - DisasCond r = { .c = TCG_COND_NE, .a0_is_n = true, .a1_is_0 = true }; - r.a0 = cpu_psw_n; - TCGV_UNUSED(r.a1); - return r; + return (DisasCond){ + .c = TCG_COND_NE, + .a0 = cpu_psw_n, + .a0_is_n = true, + .a1 = NULL, + .a1_is_0 = true + }; } static DisasCond cond_make_0(TCGCond c, TCGv a0) { - DisasCond r = { .c = c, .a1_is_0 = true }; + DisasCond r = { .c = c, .a1 = NULL, .a1_is_0 = true }; assert (c != TCG_COND_NEVER && c != TCG_COND_ALWAYS); r.a0 = tcg_temp_new(); tcg_gen_mov_tl(r.a0, a0); - TCGV_UNUSED(r.a1); return r; } @@ -199,8 +202,8 @@ static void cond_free(DisasCond *cond) } cond->a0_is_n = false; cond->a1_is_0 = false; - TCGV_UNUSED(cond->a0); - TCGV_UNUSED(cond->a1); + cond->a0 = NULL; + cond->a1 = NULL; /* fallthru */ case TCG_COND_ALWAYS: cond->c = TCG_COND_NEVER; @@ -716,9 +719,8 @@ static DisasCond do_sed_cond(unsigned orig, TCGv res) static DisasCond do_unit_cond(unsigned cf, TCGv res, TCGv in1, TCGv in2) { DisasCond cond; - TCGv tmp, cb; + TCGv tmp, cb = NULL; - TCGV_UNUSED(cb); if (cf & 8) { /* Since we want to test lots of carry-out bits all at once, do not * do our normal thing and compute carry-in of bit B+1 since that @@ -826,8 +828,8 @@ static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, DisasCond cond; dest = tcg_temp_new(); - TCGV_UNUSED(cb); - TCGV_UNUSED(cb_msb); + cb = NULL; + cb_msb = NULL; if (shift) { tmp = get_temp(ctx); @@ -856,7 +858,7 @@ static DisasJumpType do_add(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, } /* Compute signed overflow if required. */ - TCGV_UNUSED(sv); + sv = NULL; if (is_tsv || c == 6) { sv = do_add_sv(ctx, dest, in1, in2); if (is_tsv) { @@ -919,7 +921,7 @@ static DisasJumpType do_sub(DisasContext *ctx, unsigned rt, TCGv in1, TCGv in2, tcg_temp_free(zero); /* Compute signed overflow if required. */ - TCGV_UNUSED(sv); + sv = NULL; if (is_tsv || c == 6) { sv = do_sub_sv(ctx, dest, in1, in2); if (is_tsv) { @@ -965,7 +967,7 @@ static DisasJumpType do_cmpclr(DisasContext *ctx, unsigned rt, TCGv in1, tcg_gen_sub_tl(dest, in1, in2); /* Compute signed overflow if required. */ - TCGV_UNUSED(sv); + sv = NULL; if ((cf >> 1) == 6) { sv = do_sub_sv(ctx, dest, in1, in2); } @@ -2070,8 +2072,7 @@ static DisasJumpType trans_ds(DisasContext *ctx, uint32_t insn, /* Install the new nullification. */ if (cf) { - TCGv sv; - TCGV_UNUSED(sv); + TCGv sv = NULL; if (cf >> 1 == 6) { /* ??? The lshift is supposed to contribute to overflow. */ sv = do_add_sv(ctx, dest, add1, add2); @@ -2542,7 +2543,7 @@ static DisasJumpType trans_cmpb(DisasContext *ctx, uint32_t insn, tcg_gen_sub_tl(dest, in1, in2); - TCGV_UNUSED(sv); + sv = NULL; if (c == 6) { sv = do_sub_sv(ctx, dest, in1, in2); } @@ -2571,8 +2572,8 @@ static DisasJumpType trans_addb(DisasContext *ctx, uint32_t insn, } in2 = load_gpr(ctx, r); dest = dest_gpr(ctx, r); - TCGV_UNUSED(sv); - TCGV_UNUSED(cb_msb); + sv = NULL; + cb_msb = NULL; switch (c) { default: @@ -3732,18 +3733,16 @@ static int hppa_tr_init_disas_context(DisasContextBase *dcbase, { DisasContext *ctx = container_of(dcbase, DisasContext, base); TranslationBlock *tb = ctx->base.tb; - int i, bound; + int bound; ctx->cs = cs; ctx->iaoq_f = tb->pc; ctx->iaoq_b = tb->cs_base; ctx->iaoq_n = -1; - TCGV_UNUSED(ctx->iaoq_n_var); + ctx->iaoq_n_var = NULL; ctx->ntemps = 0; - for (i = 0; i < ARRAY_SIZE(ctx->temps); ++i) { - TCGV_UNUSED(ctx->temps[i]); - } + memset(ctx->temps, 0, sizeof(ctx->temps)); bound = -(tb->pc | TARGET_PAGE_MASK) / 4; return MIN(max_insns, bound); @@ -3804,7 +3803,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) tcg_gen_addi_tl(ctx->iaoq_n_var, cpu_iaoq_b, 4); } else { ctx->iaoq_n = ctx->iaoq_b + 4; - TCGV_UNUSED(ctx->iaoq_n_var); + ctx->iaoq_n_var = NULL; } if (unlikely(ctx->null_cond.c == TCG_COND_ALWAYS)) { @@ -3819,7 +3818,7 @@ static void hppa_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) /* Free any temporaries allocated. */ for (i = 0, n = ctx->ntemps; i < n; ++i) { tcg_temp_free(ctx->temps[i]); - TCGV_UNUSED(ctx->temps[i]); + ctx->temps[i] = NULL; } ctx->ntemps = 0; diff --git a/target/i386/translate.c b/target/i386/translate.c index 23d7eec964..0135415d92 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -689,7 +689,7 @@ static void gen_compute_eflags(DisasContext *s) return; } - TCGV_UNUSED(zero); + zero = NULL; dst = cpu_cc_dst; src1 = cpu_cc_src; src2 = cpu_cc_src2; @@ -2050,9 +2050,8 @@ static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s, /* Compute the address, with a minimum number of TCG ops. */ static TCGv gen_lea_modrm_1(AddressParts a) { - TCGv ea; + TCGv ea = NULL; - TCGV_UNUSED(ea); if (a.index >= 0) { if (a.scale == 0) { ea = cpu_regs[a.index]; @@ -2067,7 +2066,7 @@ static TCGv gen_lea_modrm_1(AddressParts a) } else if (a.base >= 0) { ea = cpu_regs[a.base]; } - if (TCGV_IS_UNUSED(ea)) { + if (!ea) { tcg_gen_movi_tl(cpu_A0, a.disp); ea = cpu_A0; } else if (a.disp != 0) { @@ -3951,7 +3950,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0); /* Re-use the carry-out from a previous round. */ - TCGV_UNUSED(carry_in); + carry_in = NULL; carry_out = (b == 0x1f6 ? cpu_cc_dst : cpu_cc_src2); switch (s->cc_op) { case CC_OP_ADCX: @@ -3979,7 +3978,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, break; } /* If we can't reuse carry-out, get it out of EFLAGS. */ - if (TCGV_IS_UNUSED(carry_in)) { + if (!carry_in) { if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) { gen_compute_eflags(s); } @@ -7673,7 +7672,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_mov_tl(a0, cpu_A0); } else { gen_op_mov_v_reg(ot, t0, rm); - TCGV_UNUSED(a0); + a0 = NULL; } gen_op_mov_v_reg(ot, t1, reg); tcg_gen_andi_tl(cpu_tmp0, t0, 3); diff --git a/target/m68k/translate.c b/target/m68k/translate.c index bbda7399ec..09226eba81 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -3948,8 +3948,8 @@ DISAS_INSN(bfop_reg) int ofs = extract32(ext, 6, 5); /* big bit-endian */ TCGv mask, tofs, tlen; - TCGV_UNUSED(tofs); - TCGV_UNUSED(tlen); + tofs = NULL; + tlen = NULL; if ((insn & 0x0f00) == 0x0d00) { /* bfffo */ tofs = tcg_temp_new(); tlen = tcg_temp_new(); @@ -3965,7 +3965,7 @@ DISAS_INSN(bfop_reg) } tcg_gen_andi_i32(QREG_CC_N, QREG_CC_N, ~maski); mask = tcg_const_i32(ror32(maski, ofs)); - if (!TCGV_IS_UNUSED(tofs)) { + if (tofs) { tcg_gen_movi_i32(tofs, ofs); tcg_gen_movi_i32(tlen, len); } @@ -3977,13 +3977,13 @@ DISAS_INSN(bfop_reg) tcg_gen_andi_i32(tmp, tmp, 31); mask = tcg_const_i32(0x7fffffffu); tcg_gen_shr_i32(mask, mask, tmp); - if (!TCGV_IS_UNUSED(tlen)) { + if (tlen) { tcg_gen_addi_i32(tlen, tmp, 1); } } else { /* Immediate width */ mask = tcg_const_i32(0x7fffffffu >> (len - 1)); - if (!TCGV_IS_UNUSED(tlen)) { + if (tlen) { tcg_gen_movi_i32(tlen, len); } } @@ -3993,7 +3993,7 @@ DISAS_INSN(bfop_reg) tcg_gen_rotl_i32(QREG_CC_N, src, tmp); tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask); tcg_gen_rotr_i32(mask, mask, tmp); - if (!TCGV_IS_UNUSED(tofs)) { + if (tofs) { tcg_gen_mov_i32(tofs, tmp); } } else { @@ -4001,7 +4001,7 @@ DISAS_INSN(bfop_reg) tcg_gen_rotli_i32(QREG_CC_N, src, ofs); tcg_gen_andc_i32(QREG_CC_N, QREG_CC_N, mask); tcg_gen_rotri_i32(mask, mask, ofs); - if (!TCGV_IS_UNUSED(tofs)) { + if (tofs) { tcg_gen_movi_i32(tofs, ofs); } } diff --git a/target/mips/translate.c b/target/mips/translate.c index b022f840c9..d05ee67e63 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -20453,7 +20453,7 @@ void mips_tcg_init(void) { int i; - TCGV_UNUSED(cpu_gpr[0]); + cpu_gpr[0] = NULL; for (i = 1; i < 32; i++) cpu_gpr[i] = tcg_global_mem_new(cpu_env, offsetof(CPUMIPSState, active_tc.gpr[i]), diff --git a/target/nios2/translate.c b/target/nios2/translate.c index 51a54ff760..cb8624e8d2 100644 --- a/target/nios2/translate.c +++ b/target/nios2/translate.c @@ -125,7 +125,7 @@ static uint8_t get_opxcode(uint32_t code) static TCGv load_zero(DisasContext *dc) { - if (TCGV_IS_UNUSED_I32(dc->zero)) { + if (!dc->zero) { dc->zero = tcg_const_i32(0); } return dc->zero; @@ -755,12 +755,12 @@ static void handle_instruction(DisasContext *dc, CPUNios2State *env) goto illegal_op; } - TCGV_UNUSED_I32(dc->zero); + dc->zero = NULL; instr = &i_type_instructions[op]; instr->handler(dc, code, instr->flags); - if (!TCGV_IS_UNUSED_I32(dc->zero)) { + if (dc->zero) { tcg_temp_free(dc->zero); } diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 4075fc8589..0ef21cce33 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -3495,7 +3495,7 @@ static void gen_bcond(DisasContext *ctx, int type) else tcg_gen_mov_tl(target, cpu_lr); } else { - TCGV_UNUSED(target); + target = NULL; } if (LK(ctx->opcode)) gen_setlr(ctx, ctx->nip); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index eede2ed157..ac55886792 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -434,11 +434,9 @@ static void set_cc_static(DisasContext *s) /* calculates cc into cc_op */ static void gen_op_calc_cc(DisasContext *s) { - TCGv_i32 local_cc_op; - TCGv_i64 dummy; + TCGv_i32 local_cc_op = NULL; + TCGv_i64 dummy = NULL; - TCGV_UNUSED_I32(local_cc_op); - TCGV_UNUSED_I64(dummy); switch (s->cc_op) { default: dummy = tcg_const_i64(0); @@ -528,10 +526,10 @@ static void gen_op_calc_cc(DisasContext *s) tcg_abort(); } - if (!TCGV_IS_UNUSED_I32(local_cc_op)) { + if (local_cc_op) { tcg_temp_free_i32(local_cc_op); } - if (!TCGV_IS_UNUSED_I64(dummy)) { + if (dummy) { tcg_temp_free_i64(dummy); } @@ -1189,7 +1187,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, goto egress; } } else { - if (TCGV_IS_UNUSED_I64(cdest)) { + if (!cdest) { /* E.g. bcr %r0 -> no branch. */ ret = NO_EXIT; goto egress; @@ -1451,7 +1449,7 @@ static ExitStatus op_ni(DisasContext *s, DisasOps *o) static ExitStatus op_bas(DisasContext *s, DisasOps *o) { tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); - if (!TCGV_IS_UNUSED_I64(o->in2)) { + if (o->in2) { tcg_gen_mov_i64(psw_addr, o->in2); per_branch(s, false); return EXIT_PC_UPDATED; @@ -3031,7 +3029,7 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; o->g_out = o->g_in2; - TCGV_UNUSED_I64(o->in2); + o->in2 = NULL; o->g_in2 = false; return NO_EXIT; } @@ -3043,7 +3041,7 @@ static ExitStatus op_mov2e(DisasContext *s, DisasOps *o) o->out = o->in2; o->g_out = o->g_in2; - TCGV_UNUSED_I64(o->in2); + o->in2 = NULL; o->g_in2 = false; switch (s->tb->flags & FLAG_MASK_ASC) { @@ -3077,8 +3075,8 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o) o->out2 = o->in2; o->g_out = o->g_in1; o->g_out2 = o->g_in2; - TCGV_UNUSED_I64(o->in1); - TCGV_UNUSED_I64(o->in2); + o->in1 = NULL; + o->in2 = NULL; o->g_in1 = o->g_in2 = false; return NO_EXIT; } @@ -5945,11 +5943,11 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) s->insn = insn; s->fields = &f; o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; - TCGV_UNUSED_I64(o.out); - TCGV_UNUSED_I64(o.out2); - TCGV_UNUSED_I64(o.in1); - TCGV_UNUSED_I64(o.in2); - TCGV_UNUSED_I64(o.addr1); + o.out = NULL; + o.out2 = NULL; + o.in1 = NULL; + o.in2 = NULL; + o.addr1 = NULL; /* Implement the instruction. */ if (insn->help_in1) { @@ -5972,19 +5970,19 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) } /* Free any temporaries created by the helpers. */ - if (!TCGV_IS_UNUSED_I64(o.out) && !o.g_out) { + if (o.out && !o.g_out) { tcg_temp_free_i64(o.out); } - if (!TCGV_IS_UNUSED_I64(o.out2) && !o.g_out2) { + if (o.out2 && !o.g_out2) { tcg_temp_free_i64(o.out2); } - if (!TCGV_IS_UNUSED_I64(o.in1) && !o.g_in1) { + if (o.in1 && !o.g_in1) { tcg_temp_free_i64(o.in1); } - if (!TCGV_IS_UNUSED_I64(o.in2) && !o.g_in2) { + if (o.in2 && !o.g_in2) { tcg_temp_free_i64(o.in2); } - if (!TCGV_IS_UNUSED_I64(o.addr1)) { + if (o.addr1) { tcg_temp_free_i64(o.addr1); } diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 038663cc05..012156b97b 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1940,7 +1940,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) op_dst = op_src = op_opc = -1; mt_dst = -1; st_src = st_mop = -1; - TCGV_UNUSED(op_arg); + op_arg = NULL; i = 0; #define NEXT_INSN \ @@ -2228,7 +2228,7 @@ static int decode_gusa(DisasContext *ctx, CPUSH4State *env, int *pmax_insns) } /* If op_src is not a valid register, then op_arg was a constant. */ - if (op_src < 0 && !TCGV_IS_UNUSED(op_arg)) { + if (op_src < 0 && op_arg) { tcg_temp_free_i32(op_arg); } diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 849a02aebd..71e0853e43 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -5922,7 +5922,7 @@ void sparc_tcg_init(void) *rtl[i].ptr = tcg_global_mem_new(cpu_env, rtl[i].off, rtl[i].name); } - TCGV_UNUSED(cpu_regs[0]); + cpu_regs[0] = NULL; for (i = 1; i < 8; ++i) { cpu_regs[i] = tcg_global_mem_new(cpu_env, offsetof(CPUSPARCState, gregs[i]), diff --git a/target/tilegx/translate.c b/target/tilegx/translate.c index d55549dabc..d63bf5bba3 100644 --- a/target/tilegx/translate.c +++ b/target/tilegx/translate.c @@ -143,7 +143,7 @@ static bool check_gr(DisasContext *dc, uint8_t reg) static TCGv load_zero(DisasContext *dc) { - if (TCGV_IS_UNUSED_I64(dc->zero)) { + if (!dc->zero) { dc->zero = tcg_const_i64(0); } return dc->zero; @@ -2324,7 +2324,7 @@ static void translate_one_bundle(DisasContext *dc, uint64_t bundle) for (i = 0; i < ARRAY_SIZE(dc->wb); i++) { DisasContextTemp *wb = &dc->wb[i]; wb->reg = TILEGX_R_NOREG; - TCGV_UNUSED_I64(wb->val); + wb->val = NULL; } dc->num_wb = 0; @@ -2384,9 +2384,9 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) dc->exit_tb = false; dc->atomic_excp = TILEGX_EXCP_NONE; dc->jmp.cond = TCG_COND_NEVER; - TCGV_UNUSED_I64(dc->jmp.dest); - TCGV_UNUSED_I64(dc->jmp.val1); - TCGV_UNUSED_I64(dc->zero); + dc->jmp.dest = NULL; + dc->jmp.val1 = NULL; + dc->zero = NULL; if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { qemu_log_lock(); diff --git a/target/unicore32/translate.c b/target/unicore32/translate.c index 384aa86027..5b51f2166d 100644 --- a/target/unicore32/translate.c +++ b/target/unicore32/translate.c @@ -1230,7 +1230,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) if (UCOP_OPCODES != 0x0f && UCOP_OPCODES != 0x0d) { tmp = load_reg(s, UCOP_REG_N); } else { - TCGV_UNUSED(tmp); + tmp = NULL; } switch (UCOP_OPCODES) { @@ -1652,7 +1652,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) /* compute total size */ loaded_base = 0; - TCGV_UNUSED(loaded_var); + loaded_var = NULL; n = 0; for (i = 0; i < 6; i++) { if (UCOP_SET(i)) { diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 3129159907..ca07b32b65 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -807,8 +807,6 @@ void tcg_gen_lookup_and_goto_ptr(void); #define tcg_global_mem_new tcg_global_mem_new_i32 #define tcg_temp_local_new() tcg_temp_local_new_i32() #define tcg_temp_free tcg_temp_free_i32 -#define TCGV_UNUSED(x) TCGV_UNUSED_I32(x) -#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I32(x) #define tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i32 #define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i32 #else @@ -817,8 +815,6 @@ void tcg_gen_lookup_and_goto_ptr(void); #define tcg_global_mem_new tcg_global_mem_new_i64 #define tcg_temp_local_new() tcg_temp_local_new_i64() #define tcg_temp_free tcg_temp_free_i64 -#define TCGV_UNUSED(x) TCGV_UNUSED_I64(x) -#define TCGV_IS_UNUSED(x) TCGV_IS_UNUSED_I64(x) #define tcg_gen_qemu_ld_tl tcg_gen_qemu_ld_i64 #define tcg_gen_qemu_st_tl tcg_gen_qemu_st_i64 #endif diff --git a/tcg/tcg.c b/tcg/tcg.c index c22f1c4441..68bcd2267b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1358,8 +1358,8 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) TCGv_i64 retl, reth; TCGTemp *split_args[MAX_OPC_PARAM]; - TCGV_UNUSED_I64(retl); - TCGV_UNUSED_I64(reth); + retl = NULL; + reth = NULL; if (sizemask != 0) { for (i = real_args = 0; i < nargs; ++i) { int is_64bit = sizemask & (1 << (i+1)*2); diff --git a/tcg/tcg.h b/tcg/tcg.h index cb7b329876..c21194c858 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -428,15 +428,6 @@ typedef TCGv_ptr TCGv_env; #error Unhandled TARGET_LONG_BITS value #endif -/* See the comment before tcgv_i32_temp. */ -#define TCGV_UNUSED_I32(x) (x = (TCGv_i32)NULL) -#define TCGV_UNUSED_I64(x) (x = (TCGv_i64)NULL) -#define TCGV_UNUSED_PTR(x) (x = (TCGv_ptr)NULL) - -#define TCGV_IS_UNUSED_I32(x) ((x) == (TCGv_i32)NULL) -#define TCGV_IS_UNUSED_I64(x) ((x) == (TCGv_i64)NULL) -#define TCGV_IS_UNUSED_PTR(x) ((x) == (TCGv_ptr)NULL) - /* call flags */ /* Helper does not read globals (either directly or through an exception). It implies TCG_CALL_NO_WRITE_GLOBALS. */ From 15fa08f8451babc88d733bd411d4c94976f9d0f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Nov 2017 15:19:14 +0100 Subject: [PATCH 433/546] tcg: Dynamically allocate TCGOps With no fixed array allocation, we can't overflow a buffer. This will be important as optimizations related to host vectors may expand the number of ops used. Use QTAILQ to link the ops together. Signed-off-by: Richard Henderson --- include/exec/gen-icount.h | 9 +-- include/qemu/queue.h | 5 ++ target/arm/translate-a64.c | 2 +- target/arm/translate.c | 2 +- target/arm/translate.h | 10 +-- target/cris/translate.c | 2 - target/lm32/translate.c | 2 - target/microblaze/translate.c | 4 -- tcg/optimize.c | 16 +---- tcg/tcg-op.c | 24 ------- tcg/tcg.c | 125 +++++++++++++--------------------- tcg/tcg.h | 35 ++++------ 12 files changed, 78 insertions(+), 158 deletions(-) diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h index 049bba86e9..54aaa61d65 100644 --- a/include/exec/gen-icount.h +++ b/include/exec/gen-icount.h @@ -5,7 +5,7 @@ /* Helpers for instruction counting code generation. */ -static int icount_start_insn_idx; +static TCGOp *icount_start_insn; static inline void gen_tb_start(TranslationBlock *tb) { @@ -26,8 +26,8 @@ static inline void gen_tb_start(TranslationBlock *tb) /* We emit a movi with a dummy immediate argument. Keep the insn index * of the movi so that we later (when we know the actual insn count) * can update the immediate argument with the actual insn count. */ - icount_start_insn_idx = tcg_op_buf_count(); tcg_gen_movi_i32(imm, 0xdeadbeef); + icount_start_insn = tcg_last_op(); tcg_gen_sub_i32(count, count, imm); tcg_temp_free_i32(imm); @@ -48,14 +48,11 @@ static inline void gen_tb_end(TranslationBlock *tb, int num_insns) if (tb_cflags(tb) & CF_USE_ICOUNT) { /* Update the num_insn immediate parameter now that we know * the actual insn count. */ - tcg_set_insn_param(icount_start_insn_idx, 1, num_insns); + tcg_set_insn_param(icount_start_insn, 1, num_insns); } gen_set_label(tcg_ctx->exitreq_label); tcg_gen_exit_tb((uintptr_t)tb + TB_EXIT_REQUESTED); - - /* Terminate the linked list. */ - tcg_ctx->gen_op_buf[tcg_ctx->gen_op_buf[0].prev].next = 0; } static inline void gen_io_start(void) diff --git a/include/qemu/queue.h b/include/qemu/queue.h index 35292c3155..aa270d2b38 100644 --- a/include/qemu/queue.h +++ b/include/qemu/queue.h @@ -425,6 +425,11 @@ struct { \ (var); \ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) +#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev_var) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var) && ((prev_var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)), 1); \ + (var) = (prev_var)) + /* * Tail queue access methods. */ diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 460bab5987..ba94f7d045 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -11290,8 +11290,8 @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - dc->insn_start_idx = tcg_op_buf_count(); tcg_gen_insn_start(dc->pc, 0, 0); + dc->insn_start = tcg_last_op(); } static bool aarch64_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, diff --git a/target/arm/translate.c b/target/arm/translate.c index 46c25ae2c1..c690658493 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -12096,10 +12096,10 @@ static void arm_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu) { DisasContext *dc = container_of(dcbase, DisasContext, base); - dc->insn_start_idx = tcg_op_buf_count(); tcg_gen_insn_start(dc->pc, (dc->condexec_cond << 4) | (dc->condexec_mask >> 1), 0); + dc->insn_start = tcg_last_op(); } static bool arm_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu, diff --git a/target/arm/translate.h b/target/arm/translate.h index 410ba79c0d..cd7313ace7 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -66,8 +66,8 @@ typedef struct DisasContext { bool ss_same_el; /* Bottom two bits of XScale c15_cpar coprocessor access control reg */ int c15_cpar; - /* TCG op index of the current insn_start. */ - int insn_start_idx; + /* TCG op of the current insn_start. */ + TCGOp *insn_start; #define TMP_A64_MAX 16 int tmp_a64_count; TCGv_i64 tmp_a64[TMP_A64_MAX]; @@ -117,9 +117,9 @@ static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn) syn >>= ARM_INSN_START_WORD2_SHIFT; /* We check and clear insn_start_idx to catch multiple updates. */ - assert(s->insn_start_idx != 0); - tcg_set_insn_param(s->insn_start_idx, 2, syn); - s->insn_start_idx = 0; + assert(s->insn_start != NULL); + tcg_set_insn_param(s->insn_start, 2, syn); + s->insn_start = NULL; } /* is_jmp field values */ diff --git a/target/cris/translate.c b/target/cris/translate.c index 74822ed31f..f51a731db9 100644 --- a/target/cris/translate.c +++ b/target/cris/translate.c @@ -3297,8 +3297,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) qemu_log("--------------\n"); qemu_log("IN: %s\n", lookup_symbol(pc_start)); log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log("\nisize=%d osize=%d\n", - dc->pc - pc_start, tcg_op_buf_count()); qemu_log_unlock(); } #endif diff --git a/target/lm32/translate.c b/target/lm32/translate.c index b8b2b13e36..2e1c5e6d01 100644 --- a/target/lm32/translate.c +++ b/target/lm32/translate.c @@ -1156,8 +1156,6 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) qemu_log_lock(); qemu_log("\n"); log_target_disas(cs, pc_start, dc->pc - pc_start); - qemu_log("\nisize=%d osize=%d\n", - dc->pc - pc_start, tcg_op_buf_count()); qemu_log_unlock(); } #endif diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index e7b5597c46..7628b0e25b 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1808,11 +1808,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) && qemu_log_in_addr_range(pc_start)) { qemu_log_lock(); qemu_log("--------------\n"); -#if DISAS_GNU log_target_disas(cs, pc_start, dc->pc - pc_start); -#endif - qemu_log("\nisize=%d osize=%d\n", - dc->pc - pc_start, tcg_op_buf_count()); qemu_log_unlock(); } #endif diff --git a/tcg/optimize.c b/tcg/optimize.c index 438321c6cc..e495680e95 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -602,8 +602,8 @@ static bool swap_commutative2(TCGArg *p1, TCGArg *p2) /* Propagate constants and copies, fold constant expressions. */ void tcg_optimize(TCGContext *s) { - int oi, oi_next, nb_temps, nb_globals; - TCGOp *prev_mb = NULL; + int nb_temps, nb_globals; + TCGOp *op, *op_next, *prev_mb = NULL; struct tcg_temp_info *infos; TCGTempSet temps_used; @@ -617,17 +617,13 @@ void tcg_optimize(TCGContext *s) bitmap_zero(temps_used.l, nb_temps); infos = tcg_malloc(sizeof(struct tcg_temp_info) * nb_temps); - for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { + QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { tcg_target_ulong mask, partmask, affected; int nb_oargs, nb_iargs, i; TCGArg tmp; - - TCGOp * const op = &s->gen_op_buf[oi]; TCGOpcode opc = op->opc; const TCGOpDef *def = &tcg_op_defs[opc]; - oi_next = op->next; - /* Count the arguments, and initialize the temps that are going to be used */ if (opc == INDEX_op_call) { @@ -1261,9 +1257,6 @@ void tcg_optimize(TCGContext *s) rh = op->args[1]; tcg_opt_gen_movi(s, op, rl, (int32_t)a); tcg_opt_gen_movi(s, op2, rh, (int32_t)(a >> 32)); - - /* We've done all we need to do with the movi. Skip it. */ - oi_next = op2->next; break; } goto do_default; @@ -1280,9 +1273,6 @@ void tcg_optimize(TCGContext *s) rh = op->args[1]; tcg_opt_gen_movi(s, op, rl, (int32_t)r); tcg_opt_gen_movi(s, op2, rh, (int32_t)(r >> 32)); - - /* We've done all we need to do with the movi. Skip it. */ - oi_next = op2->next; break; } goto do_default; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 3cad30b1f2..0c509bfe46 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -42,30 +42,6 @@ extern TCGv_i32 TCGV_HIGH_link_error(TCGv_i64); #define TCGV_HIGH TCGV_HIGH_link_error #endif -/* Note that this is optimized for sequential allocation during translate. - Up to and including filling in the forward link immediately. We'll do - proper termination of the end of the list after we finish translation. */ - -static inline TCGOp *tcg_emit_op(TCGOpcode opc) -{ - TCGContext *ctx = tcg_ctx; - int oi = ctx->gen_next_op_idx; - int ni = oi + 1; - int pi = oi - 1; - TCGOp *op = &ctx->gen_op_buf[oi]; - - tcg_debug_assert(oi < OPC_BUF_SIZE); - ctx->gen_op_buf[0].prev = oi; - ctx->gen_next_op_idx = ni; - - memset(op, 0, offsetof(TCGOp, args)); - op->opc = opc; - op->prev = pi; - op->next = ni; - - return op; -} - void tcg_gen_op1(TCGOpcode opc, TCGArg a1) { TCGOp *op = tcg_emit_op(opc); diff --git a/tcg/tcg.c b/tcg/tcg.c index 68bcd2267b..f26949a900 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -862,9 +862,8 @@ void tcg_func_start(TCGContext *s) s->goto_tb_issue_mask = 0; #endif - s->gen_op_buf[0].next = 1; - s->gen_op_buf[0].prev = 0; - s->gen_next_op_idx = 1; + QTAILQ_INIT(&s->ops); + QTAILQ_INIT(&s->free_ops); } static inline TCGTemp *tcg_temp_alloc(TCGContext *s) @@ -1339,7 +1338,6 @@ bool tcg_op_supported(TCGOpcode op) and endian swap in tcg_reg_alloc_call(). */ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) { - TCGContext *s = tcg_ctx; int i, real_args, nb_rets, pi; unsigned sizemask, flags; TCGHelperInfo *info; @@ -1395,17 +1393,7 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) } #endif /* TCG_TARGET_EXTEND_ARGS */ - i = s->gen_next_op_idx; - tcg_debug_assert(i < OPC_BUF_SIZE); - s->gen_op_buf[0].prev = i; - s->gen_next_op_idx = i + 1; - op = &s->gen_op_buf[i]; - - /* Set links for sequential allocation during translation. */ - memset(op, 0, offsetof(TCGOp, args)); - op->opc = INDEX_op_call; - op->prev = i - 1; - op->next = i + 1; + op = tcg_emit_op(INDEX_op_call); pi = 0; if (ret != NULL) { @@ -1622,20 +1610,18 @@ void tcg_dump_ops(TCGContext *s) { char buf[128]; TCGOp *op; - int oi; - for (oi = s->gen_op_buf[0].next; oi != 0; oi = op->next) { + QTAILQ_FOREACH(op, &s->ops, link) { int i, k, nb_oargs, nb_iargs, nb_cargs; const TCGOpDef *def; TCGOpcode c; int col = 0; - op = &s->gen_op_buf[oi]; c = op->opc; def = &tcg_op_defs[c]; if (c == INDEX_op_insn_start) { - col += qemu_log("%s ----", oi != s->gen_op_buf[0].next ? "\n" : ""); + col += qemu_log("\n ----"); for (i = 0; i < TARGET_INSN_START_WORDS; ++i) { target_ulong a; @@ -1898,65 +1884,51 @@ static void process_op_defs(TCGContext *s) void tcg_op_remove(TCGContext *s, TCGOp *op) { - int next = op->next; - int prev = op->prev; - - /* We should never attempt to remove the list terminator. */ - tcg_debug_assert(op != &s->gen_op_buf[0]); - - s->gen_op_buf[next].prev = prev; - s->gen_op_buf[prev].next = next; - - memset(op, 0, sizeof(*op)); + QTAILQ_REMOVE(&s->ops, op, link); + QTAILQ_INSERT_TAIL(&s->free_ops, op, link); #ifdef CONFIG_PROFILER atomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1); #endif } +static TCGOp *tcg_op_alloc(TCGOpcode opc) +{ + TCGContext *s = tcg_ctx; + TCGOp *op; + + if (likely(QTAILQ_EMPTY(&s->free_ops))) { + op = tcg_malloc(sizeof(TCGOp)); + } else { + op = QTAILQ_FIRST(&s->free_ops); + QTAILQ_REMOVE(&s->free_ops, op, link); + } + memset(op, 0, offsetof(TCGOp, link)); + op->opc = opc; + + return op; +} + +TCGOp *tcg_emit_op(TCGOpcode opc) +{ + TCGOp *op = tcg_op_alloc(opc); + QTAILQ_INSERT_TAIL(&tcg_ctx->ops, op, link); + return op; +} + TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, TCGOpcode opc, int nargs) { - int oi = s->gen_next_op_idx; - int prev = old_op->prev; - int next = old_op - s->gen_op_buf; - TCGOp *new_op; - - tcg_debug_assert(oi < OPC_BUF_SIZE); - s->gen_next_op_idx = oi + 1; - - new_op = &s->gen_op_buf[oi]; - *new_op = (TCGOp){ - .opc = opc, - .prev = prev, - .next = next - }; - s->gen_op_buf[prev].next = oi; - old_op->prev = oi; - + TCGOp *new_op = tcg_op_alloc(opc); + QTAILQ_INSERT_BEFORE(old_op, new_op, link); return new_op; } TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, TCGOpcode opc, int nargs) { - int oi = s->gen_next_op_idx; - int prev = old_op - s->gen_op_buf; - int next = old_op->next; - TCGOp *new_op; - - tcg_debug_assert(oi < OPC_BUF_SIZE); - s->gen_next_op_idx = oi + 1; - - new_op = &s->gen_op_buf[oi]; - *new_op = (TCGOp){ - .opc = opc, - .prev = prev, - .next = next - }; - s->gen_op_buf[next].prev = oi; - old_op->next = oi; - + TCGOp *new_op = tcg_op_alloc(opc); + QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); return new_op; } @@ -2006,23 +1978,19 @@ static void tcg_la_bb_end(TCGContext *s) static void liveness_pass_1(TCGContext *s) { int nb_globals = s->nb_globals; - int oi, oi_prev; + TCGOp *op, *op_prev; tcg_la_func_end(s); - for (oi = s->gen_op_buf[0].prev; oi != 0; oi = oi_prev) { + QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, TCGOpHead, link, op_prev) { int i, nb_iargs, nb_oargs; TCGOpcode opc_new, opc_new2; bool have_opc_new2; TCGLifeData arg_life = 0; TCGTemp *arg_ts; - - TCGOp * const op = &s->gen_op_buf[oi]; TCGOpcode opc = op->opc; const TCGOpDef *def = &tcg_op_defs[opc]; - oi_prev = op->prev; - switch (opc) { case INDEX_op_call: { @@ -2233,8 +2201,9 @@ static void liveness_pass_1(TCGContext *s) static bool liveness_pass_2(TCGContext *s) { int nb_globals = s->nb_globals; - int nb_temps, i, oi, oi_next; + int nb_temps, i; bool changes = false; + TCGOp *op, *op_next; /* Create a temporary for each indirect global. */ for (i = 0; i < nb_globals; ++i) { @@ -2256,16 +2225,13 @@ static bool liveness_pass_2(TCGContext *s) its->state = TS_DEAD; } - for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { - TCGOp *op = &s->gen_op_buf[oi]; + QTAILQ_FOREACH_SAFE(op, &s->ops, link, op_next) { TCGOpcode opc = op->opc; const TCGOpDef *def = &tcg_op_defs[opc]; TCGLifeData arg_life = op->life; int nb_iargs, nb_oargs, call_flags; TCGTemp *arg_ts, *dir_ts; - oi_next = op->next; - if (opc == INDEX_op_call) { nb_oargs = op->callo; nb_iargs = op->calli; @@ -3168,13 +3134,16 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #ifdef CONFIG_PROFILER TCGProfile *prof = &s->prof; #endif - int i, oi, oi_next, num_insns; + int i, num_insns; + TCGOp *op; #ifdef CONFIG_PROFILER { int n; - n = s->gen_op_buf[0].prev + 1; + QTAILQ_FOREACH(op, &s->ops, link) { + n++; + } atomic_set(&prof->op_count, prof->op_count + n); if (n > prof->op_count_max) { atomic_set(&prof->op_count_max, n); @@ -3260,11 +3229,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb) #endif num_insns = -1; - for (oi = s->gen_op_buf[0].next; oi != 0; oi = oi_next) { - TCGOp * const op = &s->gen_op_buf[oi]; + QTAILQ_FOREACH(op, &s->ops, link) { TCGOpcode opc = op->opc; - oi_next = op->next; #ifdef CONFIG_PROFILER atomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1); #endif diff --git a/tcg/tcg.h b/tcg/tcg.h index c21194c858..a577447846 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -29,6 +29,7 @@ #include "cpu.h" #include "exec/tb-context.h" #include "qemu/bitops.h" +#include "qemu/queue.h" #include "tcg-mo.h" #include "tcg-target.h" @@ -48,8 +49,6 @@ * and up to 4 + N parameters on 64-bit archs * (N = number of input arguments + output arguments). */ #define MAX_OPC_PARAM (4 + (MAX_OPC_PARAM_PER_ARG * MAX_OPC_PARAM_ARGS)) -#define OPC_BUF_SIZE 640 -#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR) #define CPU_TEMP_BUF_NLONGS 128 @@ -572,23 +571,18 @@ typedef struct TCGOp { unsigned callo : 2; /* 14 */ unsigned : 2; /* 16 */ - /* Index of the prev/next op, or 0 for the end of the list. */ - unsigned prev : 16; /* 32 */ - unsigned next : 16; /* 48 */ - /* Lifetime data of the operands. */ - unsigned life : 16; /* 64 */ + unsigned life : 16; /* 32 */ + + /* Next and previous opcodes. */ + QTAILQ_ENTRY(TCGOp) link; /* Arguments for the opcode. */ TCGArg args[MAX_OPC_PARAM]; } TCGOp; -/* Make sure that we don't expand the structure without noticing. */ -QEMU_BUILD_BUG_ON(sizeof(TCGOp) != 8 + sizeof(TCGArg) * MAX_OPC_PARAM); - /* Make sure operands fit in the bitfields above. */ QEMU_BUILD_BUG_ON(NB_OPS > (1 << 8)); -QEMU_BUILD_BUG_ON(OPC_BUF_SIZE > (1 << 16)); typedef struct TCGProfile { int64_t tb_count1; @@ -642,8 +636,6 @@ struct TCGContext { int goto_tb_issue_mask; #endif - int gen_next_op_idx; - /* Code generation. Note that we specifically do not use tcg_insn_unit here, because there's too much arithmetic throughout that relies on addition and subtraction working on bytes. Rely on the GCC @@ -674,12 +666,12 @@ struct TCGContext { TCGTempSet free_temps[TCG_TYPE_COUNT * 2]; TCGTemp temps[TCG_MAX_TEMPS]; /* globals first, temps after */ + QTAILQ_HEAD(TCGOpHead, TCGOp) ops, free_ops; + /* Tells which temporary holds a given register. It does not take into account fixed registers */ TCGTemp *reg_to_temp[TCG_TARGET_NB_REGS]; - TCGOp gen_op_buf[OPC_BUF_SIZE]; - uint16_t gen_insn_end_off[TCG_MAX_INSNS]; target_ulong gen_insn_data[TCG_MAX_INSNS][TARGET_INSN_START_WORDS]; }; @@ -769,21 +761,21 @@ static inline TCGv_i32 TCGV_HIGH(TCGv_i64 t) } #endif -static inline void tcg_set_insn_param(int op_idx, int arg, TCGArg v) +static inline void tcg_set_insn_param(TCGOp *op, int arg, TCGArg v) { - tcg_ctx->gen_op_buf[op_idx].args[arg] = v; + op->args[arg] = v; } -/* The number of opcodes emitted so far. */ -static inline int tcg_op_buf_count(void) +/* The last op that was emitted. */ +static inline TCGOp *tcg_last_op(void) { - return tcg_ctx->gen_next_op_idx; + return QTAILQ_LAST(&tcg_ctx->ops, TCGOpHead); } /* Test for whether to terminate the TB for using too many opcodes. */ static inline bool tcg_op_buf_full(void) { - return tcg_op_buf_count() >= OPC_MAX_SIZE; + return false; } /* pool based memory allocation */ @@ -967,6 +959,7 @@ bool tcg_op_supported(TCGOpcode op); void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args); +TCGOp *tcg_emit_op(TCGOpcode opc); void tcg_op_remove(TCGContext *s, TCGOp *op); TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, TCGOpcode opc, int narg); TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, TCGOpcode opc, int narg); From cd9090aa9dbba30db8aec9a2fc103aaf1ab0f5a7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Nov 2017 13:02:51 +0100 Subject: [PATCH 434/546] tcg: Generalize TCGOp parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We had two fields specific to INDEX_op_call. Rename these and add some macros so that the fields may be reused for other opcodes. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 4 ++-- tcg/tcg.c | 22 +++++++++++----------- tcg/tcg.h | 10 ++++++---- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index e495680e95..2cbbeefd53 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -627,8 +627,8 @@ void tcg_optimize(TCGContext *s) /* Count the arguments, and initialize the temps that are going to be used */ if (opc == INDEX_op_call) { - nb_oargs = op->callo; - nb_iargs = op->calli; + nb_oargs = TCGOP_CALLO(op); + nb_iargs = TCGOP_CALLI(op); for (i = 0; i < nb_oargs + nb_iargs; i++) { TCGTemp *ts = arg_temp(op->args[i]); if (ts) { diff --git a/tcg/tcg.c b/tcg/tcg.c index f26949a900..93caa0be93 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1430,7 +1430,7 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) } else { nb_rets = 0; } - op->callo = nb_rets; + TCGOP_CALLO(op) = nb_rets; real_args = 0; for (i = 0; i < nargs; i++) { @@ -1469,10 +1469,10 @@ void tcg_gen_callN(void *func, TCGTemp *ret, int nargs, TCGTemp **args) } op->args[pi++] = (uintptr_t)func; op->args[pi++] = flags; - op->calli = real_args; + TCGOP_CALLI(op) = real_args; /* Make sure the fields didn't overflow. */ - tcg_debug_assert(op->calli == real_args); + tcg_debug_assert(TCGOP_CALLI(op) == real_args); tcg_debug_assert(pi <= ARRAY_SIZE(op->args)); #if defined(__sparc__) && !defined(__arch64__) \ @@ -1634,8 +1634,8 @@ void tcg_dump_ops(TCGContext *s) } } else if (c == INDEX_op_call) { /* variable number of arguments */ - nb_oargs = op->callo; - nb_iargs = op->calli; + nb_oargs = TCGOP_CALLO(op); + nb_iargs = TCGOP_CALLI(op); nb_cargs = def->nb_cargs; /* function name, flags, out args */ @@ -1996,8 +1996,8 @@ static void liveness_pass_1(TCGContext *s) { int call_flags; - nb_oargs = op->callo; - nb_iargs = op->calli; + nb_oargs = TCGOP_CALLO(op); + nb_iargs = TCGOP_CALLI(op); call_flags = op->args[nb_oargs + nb_iargs + 1]; /* pure functions can be removed if their result is unused */ @@ -2233,8 +2233,8 @@ static bool liveness_pass_2(TCGContext *s) TCGTemp *arg_ts, *dir_ts; if (opc == INDEX_op_call) { - nb_oargs = op->callo; - nb_iargs = op->calli; + nb_oargs = TCGOP_CALLO(op); + nb_iargs = TCGOP_CALLI(op); call_flags = op->args[nb_oargs + nb_iargs + 1]; } else { nb_iargs = def->nb_iargs; @@ -2915,8 +2915,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) static void tcg_reg_alloc_call(TCGContext *s, TCGOp *op) { - const int nb_oargs = op->callo; - const int nb_iargs = op->calli; + const int nb_oargs = TCGOP_CALLO(op); + const int nb_iargs = TCGOP_CALLI(op); const TCGLifeData arg_life = op->life; int flags, nb_regs, i; TCGReg reg; diff --git a/tcg/tcg.h b/tcg/tcg.h index a577447846..f25efa9795 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -566,10 +566,9 @@ typedef uint16_t TCGLifeData; typedef struct TCGOp { TCGOpcode opc : 8; /* 8 */ - /* The number of out and in parameter for a call. */ - unsigned calli : 4; /* 12 */ - unsigned callo : 2; /* 14 */ - unsigned : 2; /* 16 */ + /* Parameters for this opcode. See below. */ + unsigned param1 : 4; /* 12 */ + unsigned param2 : 4; /* 16 */ /* Lifetime data of the operands. */ unsigned life : 16; /* 32 */ @@ -581,6 +580,9 @@ typedef struct TCGOp { TCGArg args[MAX_OPC_PARAM]; } TCGOp; +#define TCGOP_CALLI(X) (X)->param1 +#define TCGOP_CALLO(X) (X)->param2 + /* Make sure operands fit in the bitfields above. */ QEMU_BUILD_BUG_ON(NB_OPS > (1 << 8)); From 923ed1750186591b04d7d61399f6d68b4e0608f2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Nov 2017 14:47:02 +0100 Subject: [PATCH 435/546] tcg: Add tcg_signed_cond Complimenting the existing tcg_unsigned_cond. Signed-off-by: Richard Henderson --- tcg/tcg.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tcg/tcg.h b/tcg/tcg.h index f25efa9795..8c45f7edbc 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -488,6 +488,12 @@ static inline TCGCond tcg_unsigned_cond(TCGCond c) return c & 2 ? (TCGCond)(c ^ 6) : c; } +/* Create a "signed" version of an "unsigned" comparison. */ +static inline TCGCond tcg_signed_cond(TCGCond c) +{ + return c & 4 ? (TCGCond)(c ^ 6) : c; +} + /* Must a comparison be considered unsigned? */ static inline bool is_unsigned_cond(TCGCond c) { From 1df3caa946e08b387511dfba3a37d78910e51796 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 13 Dec 2017 16:52:57 -0600 Subject: [PATCH 436/546] tcg: Allow 6 arguments to TCG helpers We already handle this in the backends, and the lifetime datum for the TCGOp is already large enough. Signed-off-by: Richard Henderson --- include/exec/helper-gen.h | 11 +++++++++++ include/exec/helper-head.h | 2 ++ include/exec/helper-proto.h | 5 +++++ include/exec/helper-tcg.h | 7 +++++++ tcg/tcg.h | 2 +- tcg/tci.c | 12 ++++++++---- tcg/tci/tcg-target.inc.c | 6 ++++-- 7 files changed, 38 insertions(+), 7 deletions(-) diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h index 15204ab961..22381a1708 100644 --- a/include/exec/helper-gen.h +++ b/include/exec/helper-gen.h @@ -56,6 +56,16 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ tcg_gen_callN(HELPER(name), dh_retvar(ret), 5, args); \ } +#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \ +static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ + dh_arg_decl(t1, 1), dh_arg_decl(t2, 2), dh_arg_decl(t3, 3), \ + dh_arg_decl(t4, 4), dh_arg_decl(t5, 5), dh_arg_decl(t6, 6)) \ +{ \ + TCGTemp *args[6] = { dh_arg(t1, 1), dh_arg(t2, 2), dh_arg(t3, 3), \ + dh_arg(t4, 4), dh_arg(t5, 5), dh_arg(t6, 6) }; \ + tcg_gen_callN(HELPER(name), dh_retvar(ret), 6, args); \ +} + #include "helper.h" #include "trace/generated-helpers.h" #include "trace/generated-helpers-wrappers.h" @@ -67,6 +77,7 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \ #undef DEF_HELPER_FLAGS_3 #undef DEF_HELPER_FLAGS_4 #undef DEF_HELPER_FLAGS_5 +#undef DEF_HELPER_FLAGS_6 #undef GEN_HELPER #endif /* HELPER_GEN_H */ diff --git a/include/exec/helper-head.h b/include/exec/helper-head.h index 639eefdbc0..e1fd08f2ba 100644 --- a/include/exec/helper-head.h +++ b/include/exec/helper-head.h @@ -125,6 +125,8 @@ DEF_HELPER_FLAGS_4(name, 0, ret, t1, t2, t3, t4) #define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \ DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5) +#define DEF_HELPER_6(name, ret, t1, t2, t3, t4, t5, t6) \ + DEF_HELPER_FLAGS_6(name, 0, ret, t1, t2, t3, t4, t5, t6) /* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h index 954bef85ce..74943edb13 100644 --- a/include/exec/helper-proto.h +++ b/include/exec/helper-proto.h @@ -26,6 +26,10 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ dh_ctype(t4), dh_ctype(t5)); +#define DEF_HELPER_FLAGS_6(name, flags, ret, t1, t2, t3, t4, t5, t6) \ +dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ + dh_ctype(t4), dh_ctype(t5), dh_ctype(t6)); + #include "helper.h" #include "trace/generated-helpers.h" #include "tcg-runtime.h" @@ -36,5 +40,6 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \ #undef DEF_HELPER_FLAGS_3 #undef DEF_HELPER_FLAGS_4 #undef DEF_HELPER_FLAGS_5 +#undef DEF_HELPER_FLAGS_6 #endif /* HELPER_PROTO_H */ diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h index b0c5bafa99..b3bdb0c399 100644 --- a/include/exec/helper-tcg.h +++ b/include/exec/helper-tcg.h @@ -39,6 +39,12 @@ | dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) \ | dh_sizemask(t5, 5) }, +#define DEF_HELPER_FLAGS_6(NAME, FLAGS, ret, t1, t2, t3, t4, t5, t6) \ + { .func = HELPER(NAME), .name = str(NAME), .flags = FLAGS, \ + .sizemask = dh_sizemask(ret, 0) | dh_sizemask(t1, 1) \ + | dh_sizemask(t2, 2) | dh_sizemask(t3, 3) | dh_sizemask(t4, 4) \ + | dh_sizemask(t5, 5) | dh_sizemask(t6, 6) }, + #include "helper.h" #include "trace/generated-helpers.h" #include "tcg-runtime.h" @@ -50,5 +56,6 @@ #undef DEF_HELPER_FLAGS_3 #undef DEF_HELPER_FLAGS_4 #undef DEF_HELPER_FLAGS_5 +#undef DEF_HELPER_FLAGS_6 #endif /* HELPER_TCG_H */ diff --git a/tcg/tcg.h b/tcg/tcg.h index 8c45f7edbc..2ce497cebf 100644 --- a/tcg/tcg.h +++ b/tcg/tcg.h @@ -41,7 +41,7 @@ #else #define MAX_OPC_PARAM_PER_ARG 1 #endif -#define MAX_OPC_PARAM_IARGS 5 +#define MAX_OPC_PARAM_IARGS 6 #define MAX_OPC_PARAM_OARGS 1 #define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS) diff --git a/tcg/tci.c b/tcg/tci.c index 63f2cd54ab..33edca1903 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -40,7 +40,7 @@ tcg_abort(); \ } while (0) -#if MAX_OPC_PARAM_IARGS != 5 +#if MAX_OPC_PARAM_IARGS != 6 # error Fix needed, number of supported input arguments changed! #endif #if TCG_TARGET_REG_BITS == 32 @@ -48,11 +48,12 @@ typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, + tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong); #else typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, tcg_target_ulong, - tcg_target_ulong); + tcg_target_ulong, tcg_target_ulong); #endif static tcg_target_ulong tci_read_reg(const tcg_target_ulong *regs, TCGReg index) @@ -520,7 +521,9 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) tci_read_reg(regs, TCG_REG_R7), tci_read_reg(regs, TCG_REG_R8), tci_read_reg(regs, TCG_REG_R9), - tci_read_reg(regs, TCG_REG_R10)); + tci_read_reg(regs, TCG_REG_R10), + tci_read_reg(regs, TCG_REG_R11), + tci_read_reg(regs, TCG_REG_R12)); tci_write_reg(regs, TCG_REG_R0, tmp64); tci_write_reg(regs, TCG_REG_R1, tmp64 >> 32); #else @@ -528,7 +531,8 @@ uintptr_t tcg_qemu_tb_exec(CPUArchState *env, uint8_t *tb_ptr) tci_read_reg(regs, TCG_REG_R1), tci_read_reg(regs, TCG_REG_R2), tci_read_reg(regs, TCG_REG_R3), - tci_read_reg(regs, TCG_REG_R5)); + tci_read_reg(regs, TCG_REG_R5), + tci_read_reg(regs, TCG_REG_R6)); tci_write_reg(regs, TCG_REG_R0, tmp64); #endif break; diff --git a/tcg/tci/tcg-target.inc.c b/tcg/tci/tcg-target.inc.c index 913c3802a3..cc949bea85 100644 --- a/tcg/tci/tcg-target.inc.c +++ b/tcg/tci/tcg-target.inc.c @@ -292,7 +292,7 @@ static const int tcg_target_reg_alloc_order[] = { #endif }; -#if MAX_OPC_PARAM_IARGS != 5 +#if MAX_OPC_PARAM_IARGS != 6 # error Fix needed, number of supported input arguments changed! #endif @@ -305,14 +305,16 @@ static const int tcg_target_call_iarg_regs[] = { TCG_REG_R4, #endif TCG_REG_R5, + TCG_REG_R6, #if TCG_TARGET_REG_BITS == 32 /* 32 bit hosts need 2 * MAX_OPC_PARAM_IARGS registers. */ - TCG_REG_R6, TCG_REG_R7, #if TCG_TARGET_NB_REGS >= 16 TCG_REG_R8, TCG_REG_R9, TCG_REG_R10, + TCG_REG_R11, + TCG_REG_R12, #else # error Too few input registers available #endif From 4fad446bc955fcaa08a21388cf82268824bea10e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 17 Dec 2017 06:50:23 +0100 Subject: [PATCH 437/546] tcg: add cs_base and flags to -d exec output Signed-off-by: Paolo Bonzini Message-Id: <20171217055023.29225-1-pbonzini@redhat.com> [rth: Also change the Chain logging in helper_lookup_tb_ptr.] Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 6 ++++-- accel/tcg/tcg-runtime.c | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 4452cd9856..280200f737 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -146,8 +146,10 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) uint8_t *tb_ptr = itb->tc.ptr; qemu_log_mask_and_addr(CPU_LOG_EXEC, itb->pc, - "Trace %p [%d: " TARGET_FMT_lx "] %s\n", - itb->tc.ptr, cpu->cpu_index, itb->pc, + "Trace %d: %p [" + TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n", + cpu->cpu_index, itb->tc.ptr, + itb->cs_base, itb->pc, itb->flags, lookup_symbol(itb->pc)); #if defined(DEBUG_DISAS) diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c index 4172ffda82..d0d4484406 100644 --- a/accel/tcg/tcg-runtime.c +++ b/accel/tcg/tcg-runtime.c @@ -156,8 +156,9 @@ void *HELPER(lookup_tb_ptr)(CPUArchState *env) return tcg_ctx->code_gen_epilogue; } qemu_log_mask_and_addr(CPU_LOG_EXEC, pc, - "Chain %p [%d: " TARGET_FMT_lx "] %s\n", - tb->tc.ptr, cpu->cpu_index, pc, + "Chain %d: %p [" + TARGET_FMT_lx "/" TARGET_FMT_lx "/%#x] %s\n", + cpu->cpu_index, tb->tc.ptr, cs_base, pc, flags, lookup_symbol(pc)); return tb->tc.ptr; } From c983ca845782bf91171b5ec4e59d122a21229745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Dec 2017 15:53:59 +0100 Subject: [PATCH 438/546] dump: fix note_name_equal() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the function argument "name" instead of hardcoded "VMCOREINFO". All callers use "VMCOREINFO" as argument, so this isn't an exposed bug, thankfully. Simplify a little bit the code while touching this. Suggested-by: Andrew Jones Reported-by: Laszlo Ersek Signed-off-by: Marc-André Lureau --- dump.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dump.c b/dump.c index d4a8c942eb..e9dfed060a 100644 --- a/dump.c +++ b/dump.c @@ -788,12 +788,7 @@ static bool note_name_equal(DumpState *s, get_note_sizes(s, note, &head_size, &name_size, NULL); head_size = ROUND_UP(head_size, 4); - if (name_size != len || - memcmp(note + head_size, "VMCOREINFO", len)) { - return false; - } - - return true; + return name_size == len && memcmp(note + head_size, name, len) == 0; } /* write common header, sub header and elf note to vmcore */ From c3b1642b9b6b3ba4314d6be3be509d396372cfd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 12 Dec 2017 17:27:58 +0100 Subject: [PATCH 439/546] dump-guest-memory.py: fix "You can't do that without a process to debug" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the script is run with a core (no running process), it produces an error: (gdb) dump-guest-memory /tmp/vmcore X86_64 guest RAM blocks: target_start target_end host_addr message count ---------------- ---------------- ---------------- ------- ----- 0000000000000000 00000000000a0000 00007f7935800000 added 1 00000000000a0000 00000000000b0000 00007f7934200000 added 2 00000000000c0000 00000000000ca000 00007f79358c0000 added 3 00000000000ca000 00000000000cd000 00007f79358ca000 joined 3 00000000000cd000 00000000000e8000 00007f79358cd000 joined 3 00000000000e8000 00000000000f0000 00007f79358e8000 joined 3 00000000000f0000 0000000000100000 00007f79358f0000 joined 3 0000000000100000 0000000080000000 00007f7935900000 joined 3 00000000fd000000 00000000fe000000 00007f7934200000 added 4 00000000fffc0000 0000000100000000 00007f7935600000 added 5 Python Exception You can't do that without a process to debug.: Error occurred in Python command: You can't do that without a process to debug. Replace the object_resolve_path_type() function call with a local volatile variable. Signed-off-by: Marc-André Lureau Reviewed-by: Laszlo Ersek --- hw/misc/vmcoreinfo.c | 3 +++ scripts/dump-guest-memory.py | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c index 31db57ab44..a2805527cb 100644 --- a/hw/misc/vmcoreinfo.c +++ b/hw/misc/vmcoreinfo.c @@ -35,6 +35,8 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) { VMCoreInfoState *s = VMCOREINFO(dev); FWCfgState *fw_cfg = fw_cfg_find(); + /* for gdb script dump-guest-memory.py */ + static VMCoreInfoState * volatile vmcoreinfo_state G_GNUC_UNUSED; /* Given that this function is executing, there is at least one VMCOREINFO * device. Check if there are several. @@ -56,6 +58,7 @@ static void vmcoreinfo_realize(DeviceState *dev, Error **errp) &s->vmcoreinfo, sizeof(s->vmcoreinfo), false); qemu_register_reset(vmcoreinfo_reset, dev); + vmcoreinfo_state = s; } static const VMStateDescription vmstate_vmcoreinfo = { diff --git a/scripts/dump-guest-memory.py b/scripts/dump-guest-memory.py index 1af26c1a45..09bec92b50 100644 --- a/scripts/dump-guest-memory.py +++ b/scripts/dump-guest-memory.py @@ -546,8 +546,7 @@ def phys_memory_read(self, addr, size): return None def add_vmcoreinfo(self): - vmci = '(VMCoreInfoState *)' + \ - 'object_resolve_path_type("", "vmcoreinfo", 0)' + vmci = 'vmcoreinfo_realize::vmcoreinfo_state' if not gdb.parse_and_eval("%s" % vmci) \ or not gdb.parse_and_eval("(%s)->has_vmcoreinfo" % vmci): return From 7cd7b5ca9be805e8a4ced4c07014c24e34812f27 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:28:57 +0100 Subject: [PATCH 440/546] target-m68k: sync CC_OP before gen_jmp_tb() And remove update_cc_op() from gen_exception() because there is one in gen_jmp_im(). Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-2-laurent@vivier.eu> --- target/m68k/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index bbda7399ec..0e9d651a2a 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -270,7 +270,6 @@ static void gen_raise_exception(int nr) static void gen_exception(DisasContext *s, uint32_t where, int nr) { - update_cc_op(s); gen_jmp_im(s, where); gen_raise_exception(nr); } @@ -2897,6 +2896,7 @@ DISAS_INSN(branch) gen_jmp_tb(s, 0, s->pc); } else { /* Unconditional branch. */ + update_cc_op(s); gen_jmp_tb(s, 0, base + offset); } } @@ -4875,6 +4875,7 @@ static void gen_fjmpcc(DisasContext *s, int cond, TCGLabel *l1) DisasCompare c; gen_fcc_cond(&c, s, cond); + update_cc_op(s); tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1); free_cond(&c); } From 4131c242cc850aaf76e59d4c787d220f07850cf5 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:28:58 +0100 Subject: [PATCH 441/546] target/m68k: fix gen_get_ccr() As gen_helper_get_ccr() is able to compute CCR from cc_op and flags, we don't need to flush flags before to call it. flush_flags() and get_ccr() use COMPUTE_CCR() to compute flags. get_ccr() computes CCR value, whereas flush_flags update live cc_op and flags. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-3-laurent@vivier.eu> --- target/m68k/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 0e9d651a2a..1e9fb01252 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2478,7 +2478,6 @@ static TCGv gen_get_ccr(DisasContext *s) { TCGv dest; - gen_flush_flags(s); update_cc_op(s); dest = tcg_temp_new(); gen_helper_get_ccr(dest, cpu_env); From ef59760b885ecca0d49df46f36bb6d34fbe9445a Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:28:59 +0100 Subject: [PATCH 442/546] linux-user, m68k: correctly manage SR in context Use cpu_m68k_get_ccr()/cpu_m68k_set_ccr() to setup and restore correctly the value of SR in the context structure. Fix target_rt_setup_ucontext(). Fixes: 3219de458c ("linux-user: correctly manage SR in ucontext") Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-4-laurent@vivier.eu> --- linux-user/signal.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index dae14d4a89..74fa03f96d 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -5612,13 +5612,14 @@ struct target_rt_sigframe static void setup_sigcontext(struct target_sigcontext *sc, CPUM68KState *env, abi_ulong mask) { + uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env); __put_user(mask, &sc->sc_mask); __put_user(env->aregs[7], &sc->sc_usp); __put_user(env->dregs[0], &sc->sc_d0); __put_user(env->dregs[1], &sc->sc_d1); __put_user(env->aregs[0], &sc->sc_a0); __put_user(env->aregs[1], &sc->sc_a1); - __put_user(env->sr, &sc->sc_sr); + __put_user(sr, &sc->sc_sr); __put_user(env->pc, &sc->sc_pc); } @@ -5634,7 +5635,7 @@ restore_sigcontext(CPUM68KState *env, struct target_sigcontext *sc) __get_user(env->aregs[1], &sc->sc_a1); __get_user(env->pc, &sc->sc_pc); __get_user(temp, &sc->sc_sr); - env->sr = (env->sr & 0xff00) | (temp & 0xff); + cpu_m68k_set_ccr(env, temp); } /* @@ -5726,7 +5727,7 @@ static inline int target_rt_setup_ucontext(struct target_ucontext *uc, CPUM68KState *env) { target_greg_t *gregs = uc->tuc_mcontext.gregs; - uint32_t sr = cpu_m68k_get_ccr(env); + uint32_t sr = (env->sr & 0xff00) | cpu_m68k_get_ccr(env); __put_user(TARGET_MCONTEXT_VERSION, &uc->tuc_mcontext.version); __put_user(env->dregs[0], &gregs[0]); From 16a14cdf575a2eda4698930d22b75072537754dd Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:00 +0100 Subject: [PATCH 443/546] target/m68k: use insn_pc to generate instruction fault address Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-5-laurent@vivier.eu> --- target/m68k/translate.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 1e9fb01252..a1e424e3db 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -1509,12 +1509,12 @@ DISAS_INSN(dbcc) DISAS_INSN(undef_mac) { - gen_exception(s, s->pc - 2, EXCP_LINEA); + gen_exception(s, s->insn_pc, EXCP_LINEA); } DISAS_INSN(undef_fpu) { - gen_exception(s, s->pc - 2, EXCP_LINEF); + gen_exception(s, s->insn_pc, EXCP_LINEF); } DISAS_INSN(undef) @@ -1523,8 +1523,8 @@ DISAS_INSN(undef) for the 680x0 series, as well as those that are implemented but actually illegal for CPU32 or pre-68020. */ qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x", - insn, s->pc - 2); - gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED); + insn, s->insn_pc); + gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED); } DISAS_INSN(mulw) @@ -2583,7 +2583,7 @@ DISAS_INSN(swap) DISAS_INSN(bkpt) { - gen_exception(s, s->pc - 2, EXCP_DEBUG); + gen_exception(s, s->insn_pc, EXCP_DEBUG); } DISAS_INSN(pea) @@ -2636,7 +2636,7 @@ DISAS_INSN(pulse) DISAS_INSN(illegal) { - gen_exception(s, s->pc - 2, EXCP_ILLEGAL); + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); } /* ??? This should be atomic. */ @@ -2666,7 +2666,7 @@ DISAS_INSN(mull) if (ext & 0x400) { if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) { - gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED); return; } @@ -4240,7 +4240,7 @@ DISAS_INSN(move_from_sr) TCGv sr; if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } sr = gen_get_sr(s); @@ -4250,7 +4250,7 @@ DISAS_INSN(move_from_sr) DISAS_INSN(move_to_sr) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } gen_set_sr(env, s, insn, 0); @@ -4260,7 +4260,7 @@ DISAS_INSN(move_to_sr) DISAS_INSN(move_from_usp) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } tcg_gen_ld_i32(AREG(insn, 0), cpu_env, @@ -4270,7 +4270,7 @@ DISAS_INSN(move_from_usp) DISAS_INSN(move_to_usp) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } tcg_gen_st_i32(AREG(insn, 0), cpu_env, @@ -4287,7 +4287,7 @@ DISAS_INSN(stop) uint16_t ext; if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } @@ -4301,10 +4301,10 @@ DISAS_INSN(stop) DISAS_INSN(rte) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } - gen_exception(s, s->pc - 2, EXCP_RTE); + gen_exception(s, s->insn_pc, EXCP_RTE); } DISAS_INSN(movec) @@ -4313,7 +4313,7 @@ DISAS_INSN(movec) TCGv reg; if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } @@ -4331,7 +4331,7 @@ DISAS_INSN(movec) DISAS_INSN(intouch) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } /* ICache fetch. Implement as no-op. */ @@ -4340,7 +4340,7 @@ DISAS_INSN(intouch) DISAS_INSN(cpushl) { if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } /* Cache push/invalidate. Implement as no-op. */ @@ -4348,7 +4348,7 @@ DISAS_INSN(cpushl) DISAS_INSN(wddata) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); } DISAS_INSN(wdebug) @@ -4356,7 +4356,7 @@ DISAS_INSN(wdebug) M68kCPU *cpu = m68k_env_get_cpu(env); if (IS_USER(s)) { - gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } /* TODO: Implement wdebug. */ @@ -4365,7 +4365,7 @@ DISAS_INSN(wdebug) DISAS_INSN(trap) { - gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf)); + gen_exception(s, s->insn_pc, EXCP_TRAP0 + (insn & 0xf)); } static void gen_load_fcr(DisasContext *s, TCGv res, int reg) From 5beb144e04f44772804ac8405b6a54a17fe78909 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:01 +0100 Subject: [PATCH 444/546] target/m68k: add CPU_LOG_INT trace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display the interrupts/exceptions information in QEMU logs (-d int) Signed-off-by: Laurent Vivier Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-6-laurent@vivier.eu> --- target/m68k/cpu.h | 8 +++ target/m68k/op_helper.c | 117 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 5d03764eab..acc2629216 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -45,6 +45,8 @@ #define EXCP_ADDRESS 3 /* Address error. */ #define EXCP_ILLEGAL 4 /* Illegal instruction. */ #define EXCP_DIV0 5 /* Divide by zero */ +#define EXCP_CHK 6 /* CHK, CHK2 Instructions */ +#define EXCP_TRAPCC 7 /* FTRAPcc, TRAPcc, TRAPV Instructions */ #define EXCP_PRIVILEGE 8 /* Privilege violation. */ #define EXCP_TRACE 9 #define EXCP_LINEA 10 /* Unimplemented line-A (MAC) opcode. */ @@ -53,6 +55,9 @@ #define EXCP_DEBEGBP 13 /* Breakpoint debug interrupt. */ #define EXCP_FORMAT 14 /* RTE format error. */ #define EXCP_UNINITIALIZED 15 +#define EXCP_SPURIOUS 24 /* Spurious interrupt */ +#define EXCP_INT_LEVEL_1 25 /* Level 1 Interrupt autovector */ +#define EXCP_INT_LEVEL_7 31 /* Level 7 Interrupt autovector */ #define EXCP_TRAP0 32 /* User trap #0. */ #define EXCP_TRAP15 47 /* User trap #15. */ #define EXCP_FP_BSUN 48 /* Branch Set on Unordered */ @@ -63,6 +68,9 @@ #define EXCP_FP_OVFL 53 /* Overflow */ #define EXCP_FP_SNAN 54 /* Signaling Not-A-Number */ #define EXCP_FP_UNIMP 55 /* Unimplemented Data type */ +#define EXCP_MMU_CONF 56 /* MMU Configuration Error */ +#define EXCP_MMU_ILLEGAL 57 /* MMU Illegal Operation Error */ +#define EXCP_MMU_ACCESS 58 /* MMU Access Level Violation Error */ #define EXCP_UNSUPPORTED 61 #define EXCP_RTE 0x100 diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 63089511cb..123981af55 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -68,10 +68,116 @@ static void do_rte(CPUM68KState *env) helper_set_sr(env, fmt); } +static const char *m68k_exception_name(int index) +{ + switch (index) { + case EXCP_ACCESS: + return "Access Fault"; + case EXCP_ADDRESS: + return "Address Error"; + case EXCP_ILLEGAL: + return "Illegal Instruction"; + case EXCP_DIV0: + return "Divide by Zero"; + case EXCP_CHK: + return "CHK/CHK2"; + case EXCP_TRAPCC: + return "FTRAPcc, TRAPcc, TRAPV"; + case EXCP_PRIVILEGE: + return "Privilege Violation"; + case EXCP_TRACE: + return "Trace"; + case EXCP_LINEA: + return "A-Line"; + case EXCP_LINEF: + return "F-Line"; + case EXCP_DEBEGBP: /* 68020/030 only */ + return "Copro Protocol Violation"; + case EXCP_FORMAT: + return "Format Error"; + case EXCP_UNINITIALIZED: + return "Unitialized Interruot"; + case EXCP_SPURIOUS: + return "Spurious Interrupt"; + case EXCP_INT_LEVEL_1: + return "Level 1 Interrupt"; + case EXCP_INT_LEVEL_1 + 1: + return "Level 2 Interrupt"; + case EXCP_INT_LEVEL_1 + 2: + return "Level 3 Interrupt"; + case EXCP_INT_LEVEL_1 + 3: + return "Level 4 Interrupt"; + case EXCP_INT_LEVEL_1 + 4: + return "Level 5 Interrupt"; + case EXCP_INT_LEVEL_1 + 5: + return "Level 6 Interrupt"; + case EXCP_INT_LEVEL_1 + 6: + return "Level 7 Interrupt"; + case EXCP_TRAP0: + return "TRAP #0"; + case EXCP_TRAP0 + 1: + return "TRAP #1"; + case EXCP_TRAP0 + 2: + return "TRAP #2"; + case EXCP_TRAP0 + 3: + return "TRAP #3"; + case EXCP_TRAP0 + 4: + return "TRAP #4"; + case EXCP_TRAP0 + 5: + return "TRAP #5"; + case EXCP_TRAP0 + 6: + return "TRAP #6"; + case EXCP_TRAP0 + 7: + return "TRAP #7"; + case EXCP_TRAP0 + 8: + return "TRAP #8"; + case EXCP_TRAP0 + 9: + return "TRAP #9"; + case EXCP_TRAP0 + 10: + return "TRAP #10"; + case EXCP_TRAP0 + 11: + return "TRAP #11"; + case EXCP_TRAP0 + 12: + return "TRAP #12"; + case EXCP_TRAP0 + 13: + return "TRAP #13"; + case EXCP_TRAP0 + 14: + return "TRAP #14"; + case EXCP_TRAP0 + 15: + return "TRAP #15"; + case EXCP_FP_BSUN: + return "FP Branch/Set on unordered condition"; + case EXCP_FP_INEX: + return "FP Inexact Result"; + case EXCP_FP_DZ: + return "FP Divide by Zero"; + case EXCP_FP_UNFL: + return "FP Underflow"; + case EXCP_FP_OPERR: + return "FP Operand Error"; + case EXCP_FP_OVFL: + return "FP Overflow"; + case EXCP_FP_SNAN: + return "FP Signaling NAN"; + case EXCP_FP_UNIMP: + return "FP Unimplemented Data Type"; + case EXCP_MMU_CONF: /* 68030/68851 only */ + return "MMU Configuration Error"; + case EXCP_MMU_ILLEGAL: /* 68851 only */ + return "MMU Illegal Operation"; + case EXCP_MMU_ACCESS: /* 68851 only */ + return "MMU Access Level Violation"; + case 64 ... 255: + return "User Defined Vector"; + } + return "Unassigned"; +} + static void do_interrupt_all(CPUM68KState *env, int is_hw) { CPUState *cs = CPU(m68k_env_get_cpu(env)); uint32_t sp; + uint32_t sr; uint32_t fmt; uint32_t retaddr; uint32_t vector; @@ -109,10 +215,17 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) vector = cs->exception_index << 2; + sr = env->sr | cpu_m68k_get_ccr(env); + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n", + ++count, m68k_exception_name(cs->exception_index), + vector, env->pc, env->aregs[7], sr); + } + fmt |= 0x40000000; fmt |= vector << 16; - fmt |= env->sr; - fmt |= cpu_m68k_get_ccr(env); + fmt |= sr; env->sr |= SR_S; if (is_hw) { From d2f8fb8e7f8e7d082103d705e178c9f72e0bea77 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:02 +0100 Subject: [PATCH 445/546] target/m68k: manage 680x0 stack frames 680x0 manages several stack frame formats: - format 0: four-word stack frame - format 1: four-word throwaway stack frame - format 2: six-word stack frame - format 3: Floating-Point post-instruction stack frame - format 4: eight-word stack frame - format 7: access-error stack frame Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-7-laurent@vivier.eu> --- target/m68k/cpu.h | 1 + target/m68k/helper.c | 10 ++- target/m68k/op_helper.c | 160 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 164 insertions(+), 7 deletions(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index acc2629216..cd4b3a7c7b 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -178,6 +178,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); uint32_t cpu_m68k_get_ccr(CPUM68KState *env); void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); +void cpu_m68k_set_sr(CPUM68KState *env, uint32_t); void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val); diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 7e50ff5871..af57ffcea9 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -316,13 +316,17 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v) return val; } -void HELPER(set_sr)(CPUM68KState *env, uint32_t val) +void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr) { - env->sr = val & 0xffe0; - cpu_m68k_set_ccr(env, val); + env->sr = sr & 0xffe0; + cpu_m68k_set_ccr(env, sr); m68k_switch_sp(env); } +void HELPER(set_sr)(CPUM68KState *env, uint32_t val) +{ + cpu_m68k_set_sr(env, val); +} /* MAC unit. */ /* FIXME: The MAC unit implementation is a bit of a mess. Some helpers diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 123981af55..5c7b27b9ca 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -54,7 +54,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, } } -static void do_rte(CPUM68KState *env) +static void cf_rte(CPUM68KState *env) { uint32_t sp; uint32_t fmt; @@ -65,7 +65,46 @@ static void do_rte(CPUM68KState *env) sp |= (fmt >> 28) & 3; env->aregs[7] = sp + 8; - helper_set_sr(env, fmt); + cpu_m68k_set_sr(env, fmt); +} + +static void m68k_rte(CPUM68KState *env) +{ + uint32_t sp; + uint16_t fmt; + uint16_t sr; + + sp = env->aregs[7]; +throwaway: + sr = cpu_lduw_kernel(env, sp); + sp += 2; + env->pc = cpu_ldl_kernel(env, sp); + sp += 4; + if (m68k_feature(env, M68K_FEATURE_QUAD_MULDIV)) { + /* all except 68000 */ + fmt = cpu_lduw_kernel(env, sp); + sp += 2; + switch (fmt >> 12) { + case 0: + break; + case 1: + env->aregs[7] = sp; + cpu_m68k_set_sr(env, sr); + goto throwaway; + case 2: + case 3: + sp += 4; + break; + case 4: + sp += 8; + break; + case 7: + sp += 52; + break; + } + } + env->aregs[7] = sp; + cpu_m68k_set_sr(env, sr); } static const char *m68k_exception_name(int index) @@ -173,7 +212,7 @@ static const char *m68k_exception_name(int index) return "Unassigned"; } -static void do_interrupt_all(CPUM68KState *env, int is_hw) +static void cf_interrupt_all(CPUM68KState *env, int is_hw) { CPUState *cs = CPU(m68k_env_get_cpu(env)); uint32_t sp; @@ -189,7 +228,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) switch (cs->exception_index) { case EXCP_RTE: /* Return from an exception. */ - do_rte(env); + cf_rte(env); return; case EXCP_HALT_INSN: if (semihosting_enabled() @@ -247,6 +286,119 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) env->pc = cpu_ldl_kernel(env, env->vbr + vector); } +static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp, + uint16_t format, uint16_t sr, + uint32_t addr, uint32_t retaddr) +{ + CPUState *cs = CPU(m68k_env_get_cpu(env)); + switch (format) { + case 4: + *sp -= 4; + cpu_stl_kernel(env, *sp, env->pc); + *sp -= 4; + cpu_stl_kernel(env, *sp, addr); + break; + case 3: + case 2: + *sp -= 4; + cpu_stl_kernel(env, *sp, addr); + break; + } + *sp -= 2; + cpu_stw_kernel(env, *sp, (format << 12) + (cs->exception_index << 2)); + *sp -= 4; + cpu_stl_kernel(env, *sp, retaddr); + *sp -= 2; + cpu_stw_kernel(env, *sp, sr); +} + +static void m68k_interrupt_all(CPUM68KState *env, int is_hw) +{ + CPUState *cs = CPU(m68k_env_get_cpu(env)); + uint32_t sp; + uint32_t retaddr; + uint32_t vector; + uint16_t sr, oldsr; + + retaddr = env->pc; + + if (!is_hw) { + switch (cs->exception_index) { + case EXCP_RTE: + /* Return from an exception. */ + m68k_rte(env); + return; + case EXCP_TRAP0 ... EXCP_TRAP15: + /* Move the PC after the trap instruction. */ + retaddr += 2; + break; + } + } + + vector = cs->exception_index << 2; + + sr = env->sr | cpu_m68k_get_ccr(env); + if (qemu_loglevel_mask(CPU_LOG_INT)) { + static int count; + qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n", + ++count, m68k_exception_name(cs->exception_index), + vector, env->pc, env->aregs[7], sr); + } + + /* + * MC68040UM/AD, chapter 9.3.10 + */ + + /* "the processor first make an internal copy" */ + oldsr = sr; + /* "set the mode to supervisor" */ + sr |= SR_S; + /* "suppress tracing" */ + sr &= ~SR_T; + /* "sets the processor interrupt mask" */ + if (is_hw) { + sr |= (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT); + } + cpu_m68k_set_sr(env, sr); + sp = env->aregs[7]; + + sp &= ~1; + if (cs->exception_index == EXCP_ADDRESS) { + do_stack_frame(env, &sp, 2, oldsr, 0, retaddr); + } else if (cs->exception_index == EXCP_ILLEGAL || + cs->exception_index == EXCP_DIV0 || + cs->exception_index == EXCP_CHK || + cs->exception_index == EXCP_TRAPCC || + cs->exception_index == EXCP_TRACE) { + /* FIXME: addr is not only env->pc */ + do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr); + } else if (is_hw && oldsr & SR_M && + cs->exception_index >= EXCP_SPURIOUS && + cs->exception_index <= EXCP_INT_LEVEL_7) { + do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + oldsr = sr; + env->aregs[7] = sp; + cpu_m68k_set_sr(env, sr &= ~SR_M); + sp = env->aregs[7] & ~1; + do_stack_frame(env, &sp, 1, oldsr, 0, retaddr); + } else { + do_stack_frame(env, &sp, 0, oldsr, 0, retaddr); + } + + env->aregs[7] = sp; + /* Jump to vector. */ + env->pc = cpu_ldl_kernel(env, env->vbr + vector); +} + +static void do_interrupt_all(CPUM68KState *env, int is_hw) +{ + if (m68k_feature(env, M68K_FEATURE_M68000)) { + m68k_interrupt_all(env, is_hw); + return; + } + cf_interrupt_all(env, is_hw); +} + void m68k_cpu_do_interrupt(CPUState *cs) { M68kCPU *cpu = M68K_CPU(cs); From 8bf6cbaf396a8b54b138bb8a7c3377f2868ed16e Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:03 +0100 Subject: [PATCH 446/546] target/m68k: add chk and chk2 chk and chk2 compare a value to boundaries, and trigger a CHK exception if the value is out of bounds. Signed-off-by: Laurent Vivier Suggested-by: Richard Henderson Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-8-laurent@vivier.eu> --- linux-user/main.c | 7 ++++ target/m68k/cpu.c | 2 ++ target/m68k/cpu.h | 1 + target/m68k/helper.h | 3 ++ target/m68k/op_helper.c | 61 ++++++++++++++++++++++++++++++++ target/m68k/translate.c | 77 ++++++++++++++++++++++++++++++++++++++++- 6 files changed, 150 insertions(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index 71696ed33d..99a551b04f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2985,6 +2985,13 @@ void cpu_loop(CPUM68KState *env) info._sifields._sigfault._addr = env->pc; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; + case EXCP_CHK: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTOVF; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; case EXCP_DIV0: info.si_signo = TARGET_SIGFPE; info.si_errno = 0; diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 0a3dd83548..57ffcb2114 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -134,6 +134,7 @@ static void m68020_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CAS); m68k_set_feature(env, M68K_FEATURE_BKPT); m68k_set_feature(env, M68K_FEATURE_RTD); + m68k_set_feature(env, M68K_FEATURE_CHK2); } #define m68030_cpu_initfn m68020_cpu_initfn #define m68040_cpu_initfn m68020_cpu_initfn @@ -156,6 +157,7 @@ static void m68060_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CAS); m68k_set_feature(env, M68K_FEATURE_BKPT); m68k_set_feature(env, M68K_FEATURE_RTD); + m68k_set_feature(env, M68K_FEATURE_CHK2); } static void m5208_cpu_initfn(Object *obj) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index cd4b3a7c7b..68396bdd70 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -305,6 +305,7 @@ enum m68k_features { M68K_FEATURE_CAS, M68K_FEATURE_BKPT, M68K_FEATURE_RTD, + M68K_FEATURE_CHK2, }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/target/m68k/helper.h b/target/m68k/helper.h index eebe52dae5..78483da003 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -94,3 +94,6 @@ DEF_HELPER_FLAGS_4(bfchg_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32) DEF_HELPER_FLAGS_4(bfclr_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32) DEF_HELPER_FLAGS_4(bfset_mem, TCG_CALL_NO_WG, i32, env, i32, s32, i32) DEF_HELPER_FLAGS_4(bfffo_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32) + +DEF_HELPER_3(chk, void, env, s32, s32) +DEF_HELPER_4(chk2, void, env, s32, s32, s32) diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 5c7b27b9ca..7e97d03f82 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -947,3 +947,64 @@ uint64_t HELPER(bfffo_mem)(CPUM68KState *env, uint32_t addr, is already zero. */ return n | ffo; } + +void HELPER(chk)(CPUM68KState *env, int32_t val, int32_t ub) +{ + /* From the specs: + * X: Not affected, C,V,Z: Undefined, + * N: Set if val < 0; cleared if val > ub, undefined otherwise + * We implement here values found from a real MC68040: + * X,V,Z: Not affected + * N: Set if val < 0; cleared if val >= 0 + * C: if 0 <= ub: set if val < 0 or val > ub, cleared otherwise + * if 0 > ub: set if val > ub and val < 0, cleared otherwise + */ + env->cc_n = val; + env->cc_c = 0 <= ub ? val < 0 || val > ub : val > ub && val < 0; + + if (val < 0 || val > ub) { + CPUState *cs = CPU(m68k_env_get_cpu(env)); + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, GETPC()); + + /* flags have been modified by gen_flush_flags() */ + env->cc_op = CC_OP_FLAGS; + /* Adjust PC to end of the insn. */ + env->pc += 2; + + cs->exception_index = EXCP_CHK; + cpu_loop_exit(cs); + } +} + +void HELPER(chk2)(CPUM68KState *env, int32_t val, int32_t lb, int32_t ub) +{ + /* From the specs: + * X: Not affected, N,V: Undefined, + * Z: Set if val is equal to lb or ub + * C: Set if val < lb or val > ub, cleared otherwise + * We implement here values found from a real MC68040: + * X,N,V: Not affected + * Z: Set if val is equal to lb or ub + * C: if lb <= ub: set if val < lb or val > ub, cleared otherwise + * if lb > ub: set if val > ub and val < lb, cleared otherwise + */ + env->cc_z = val != lb && val != ub; + env->cc_c = lb <= ub ? val < lb || val > ub : val > ub && val < lb; + + if (env->cc_c) { + CPUState *cs = CPU(m68k_env_get_cpu(env)); + + /* Recover PC and CC_OP for the beginning of the insn. */ + cpu_restore_state(cs, GETPC()); + + /* flags have been modified by gen_flush_flags() */ + env->cc_op = CC_OP_FLAGS; + /* Adjust PC to end of the insn. */ + env->pc += 4; + + cs->exception_index = EXCP_CHK; + cpu_loop_exit(cs); + } +} diff --git a/target/m68k/translate.c b/target/m68k/translate.c index a1e424e3db..7f52065375 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4203,6 +4203,80 @@ DISAS_INSN(ff1) gen_helper_ff1(reg, reg); } +DISAS_INSN(chk) +{ + TCGv src, reg; + int opsize; + + switch ((insn >> 7) & 3) { + case 3: + opsize = OS_WORD; + break; + case 2: + if (m68k_feature(env, M68K_FEATURE_CHK2)) { + opsize = OS_LONG; + break; + } + /* fallthru */ + default: + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + SRC_EA(env, src, opsize, 1, NULL); + reg = gen_extend(DREG(insn, 9), opsize, 1); + + gen_flush_flags(s); + gen_helper_chk(cpu_env, reg, src); +} + +DISAS_INSN(chk2) +{ + uint16_t ext; + TCGv addr1, addr2, bound1, bound2, reg; + int opsize; + + switch ((insn >> 9) & 3) { + case 0: + opsize = OS_BYTE; + break; + case 1: + opsize = OS_WORD; + break; + case 2: + opsize = OS_LONG; + break; + default: + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + + ext = read_im16(env, s); + if ((ext & 0x0800) == 0) { + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + return; + } + + addr1 = gen_lea(env, s, insn, OS_UNSIZED); + addr2 = tcg_temp_new(); + tcg_gen_addi_i32(addr2, addr1, opsize_bytes(opsize)); + + bound1 = gen_load(s, opsize, addr1, 1); + tcg_temp_free(addr1); + bound2 = gen_load(s, opsize, addr2, 1); + tcg_temp_free(addr2); + + reg = tcg_temp_new(); + if (ext & 0x8000) { + tcg_gen_mov_i32(reg, AREG(ext, 12)); + } else { + gen_ext(reg, DREG(ext, 12), opsize, 1); + } + + gen_flush_flags(s); + gen_helper_chk2(cpu_env, reg, bound1, bound2); + tcg_temp_free(reg); +} + static TCGv gen_get_sr(DisasContext *s) { TCGv ccr; @@ -5306,7 +5380,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(undef, 0000, 0000); INSN(arith_im, 0080, fff8, CF_ISA_A); INSN(arith_im, 0000, ff00, M68000); - INSN(undef, 00c0, ffc0, M68000); + INSN(chk2, 00c0, f9c0, CHK2); INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); BASE(bitop_reg, 0100, f1c0); BASE(bitop_reg, 0140, f1c0); @@ -5339,6 +5413,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(move, 1000, f000); BASE(move, 2000, f000); BASE(move, 3000, f000); + INSN(chk, 4000, f040, M68000); INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); INSN(negx, 4000, ff00, M68000); From 9d4f0429f3dc1dc6c67de3eaa3106e6c1cfa1524 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:04 +0100 Subject: [PATCH 447/546] target/m68k: add move16 move16 moves the source line to the destination line. Lines are aligned to 16-byte boundaries and are 16 bytes long. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-9-laurent@vivier.eu> --- target/m68k/cpu.c | 10 +++++- target/m68k/cpu.h | 1 + target/m68k/translate.c | 72 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 57ffcb2114..1936efd170 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -137,7 +137,15 @@ static void m68020_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CHK2); } #define m68030_cpu_initfn m68020_cpu_initfn -#define m68040_cpu_initfn m68020_cpu_initfn + +static void m68040_cpu_initfn(Object *obj) +{ + M68kCPU *cpu = M68K_CPU(obj); + CPUM68KState *env = &cpu->env; + + m68020_cpu_initfn(obj); + m68k_set_feature(env, M68K_FEATURE_M68040); +} static void m68060_cpu_initfn(Object *obj) { diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 68396bdd70..2ac4ab191e 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -306,6 +306,7 @@ enum m68k_features { M68K_FEATURE_BKPT, M68K_FEATURE_RTD, M68K_FEATURE_CHK2, + M68K_FEATURE_M68040, /* instructions specific to MC68040 */ }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 7f52065375..0ef933a545 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4277,6 +4277,76 @@ DISAS_INSN(chk2) tcg_temp_free(reg); } +static void m68k_copy_line(TCGv dst, TCGv src, int index) +{ + TCGv addr; + TCGv_i64 t0, t1; + + addr = tcg_temp_new(); + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_andi_i32(addr, src, ~15); + tcg_gen_qemu_ld64(t0, addr, index); + tcg_gen_addi_i32(addr, addr, 8); + tcg_gen_qemu_ld64(t1, addr, index); + + tcg_gen_andi_i32(addr, dst, ~15); + tcg_gen_qemu_st64(t0, addr, index); + tcg_gen_addi_i32(addr, addr, 8); + tcg_gen_qemu_st64(t1, addr, index); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free(addr); +} + +DISAS_INSN(move16_reg) +{ + int index = IS_USER(s); + TCGv tmp; + uint16_t ext; + + ext = read_im16(env, s); + if ((ext & (1 << 15)) == 0) { + gen_exception(s, s->insn_pc, EXCP_ILLEGAL); + } + + m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index); + + /* Ax can be Ay, so save Ay before incrementing Ax */ + tmp = tcg_temp_new(); + tcg_gen_mov_i32(tmp, AREG(ext, 12)); + tcg_gen_addi_i32(AREG(insn, 0), AREG(insn, 0), 16); + tcg_gen_addi_i32(AREG(ext, 12), tmp, 16); + tcg_temp_free(tmp); +} + +DISAS_INSN(move16_mem) +{ + int index = IS_USER(s); + TCGv reg, addr; + + reg = AREG(insn, 0); + addr = tcg_const_i32(read_im32(env, s)); + + if ((insn >> 3) & 1) { + /* MOVE16 (xxx).L, (Ay) */ + m68k_copy_line(reg, addr, index); + } else { + /* MOVE16 (Ay), (xxx).L */ + m68k_copy_line(addr, reg, index); + } + + tcg_temp_free(addr); + + if (((insn >> 3) & 2) == 0) { + /* (Ay)+ */ + tcg_gen_addi_i32(reg, reg, 16); + } +} + static TCGv gen_get_sr(DisasContext *s) { TCGv ccr; @@ -5578,6 +5648,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(fsave, f300, ffc0, FPU); INSN(intouch, f340, ffc0, CF_ISA_A); INSN(cpushl, f428, ff38, CF_ISA_A); + INSN(move16_mem, f600, ffe0, M68040); + INSN(move16_reg, f620, fff8, M68040); INSN(wddata, fb00, ff00, CF_ISA_A); INSN(wdebug, fbc0, ffc0, CF_ISA_A); #undef INSN From 6ad257641d60f8c4a47972af9027b1c9bb5af787 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:05 +0100 Subject: [PATCH 448/546] target/m68k: softmmu cleanup don't compile supervisor only instructions in linux-user mode Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-10-laurent@vivier.eu> --- target/m68k/translate.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 0ef933a545..f77005215f 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4391,6 +4391,7 @@ DISAS_INSN(move_from_sr) DEST_EA(env, insn, OS_WORD, sr, NULL); } +#if defined(CONFIG_SOFTMMU) DISAS_INSN(move_to_sr) { if (IS_USER(s)) { @@ -4423,6 +4424,11 @@ DISAS_INSN(move_to_usp) DISAS_INSN(halt) { + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + gen_exception(s, s->pc, EXCP_HALT_INSN); } @@ -4506,6 +4512,7 @@ DISAS_INSN(wdebug) /* TODO: Implement wdebug. */ cpu_abort(CPU(cpu), "WDEBUG not implemented"); } +#endif DISAS_INSN(trap) { @@ -5063,10 +5070,16 @@ DISAS_INSN(fscc) tcg_temp_free(tmp); } +#if defined(CONFIG_SOFTMMU) DISAS_INSN(frestore) { M68kCPU *cpu = m68k_env_get_cpu(env); + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + /* TODO: Implement frestore. */ cpu_abort(CPU(cpu), "FRESTORE not implemented"); } @@ -5075,9 +5088,15 @@ DISAS_INSN(fsave) { M68kCPU *cpu = m68k_env_get_cpu(env); + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + /* TODO: Implement fsave. */ cpu_abort(CPU(cpu), "FSAVE not implemented"); } +#endif static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper) { @@ -5502,7 +5521,9 @@ void register_m68k_insns (CPUM68KState *env) INSN(not, 4680, fff8, CF_ISA_A); INSN(not, 4600, ff00, M68000); INSN(undef, 46c0, ffc0, M68000); +#if defined(CONFIG_SOFTMMU) INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); +#endif INSN(nbcd, 4800, ffc0, M68000); INSN(linkl, 4808, fff8, M68000); BASE(pea, 4840, ffc0); @@ -5517,7 +5538,9 @@ void register_m68k_insns (CPUM68KState *env) BASE(tst, 4a00, ff00); INSN(tas, 4ac0, ffc0, CF_ISA_B); INSN(tas, 4ac0, ffc0, M68000); +#if defined(CONFIG_SOFTMMU) INSN(halt, 4ac8, ffff, CF_ISA_A); +#endif INSN(pulse, 4acc, ffff, CF_ISA_A); BASE(illegal, 4afc, ffff); INSN(mull, 4c00, ffc0, CF_ISA_A); @@ -5528,14 +5551,16 @@ void register_m68k_insns (CPUM68KState *env) BASE(trap, 4e40, fff0); BASE(link, 4e50, fff8); BASE(unlk, 4e58, fff8); +#if defined(CONFIG_SOFTMMU) INSN(move_to_usp, 4e60, fff8, USP); INSN(move_from_usp, 4e68, fff8, USP); - BASE(nop, 4e71, ffff); BASE(stop, 4e72, ffff); BASE(rte, 4e73, ffff); + INSN(movec, 4e7b, ffff, CF_ISA_A); +#endif + BASE(nop, 4e71, ffff); INSN(rtd, 4e74, ffff, RTD); BASE(rts, 4e75, ffff); - INSN(movec, 4e7b, ffff, CF_ISA_A); BASE(jump, 4e80, ffc0); BASE(jump, 4ec0, ffc0); INSN(addsubq, 5000, f080, M68000); @@ -5639,19 +5664,21 @@ void register_m68k_insns (CPUM68KState *env) BASE(undef_fpu, f000, f000); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); - INSN(frestore, f340, ffc0, CF_FPU); - INSN(fsave, f300, ffc0, CF_FPU); INSN(fpu, f200, ffc0, FPU); INSN(fscc, f240, ffc0, FPU); INSN(fbcc, f280, ff80, FPU); +#if defined(CONFIG_SOFTMMU) + INSN(frestore, f340, ffc0, CF_FPU); + INSN(fsave, f300, ffc0, CF_FPU); INSN(frestore, f340, ffc0, FPU); INSN(fsave, f300, ffc0, FPU); INSN(intouch, f340, ffc0, CF_ISA_A); INSN(cpushl, f428, ff38, CF_ISA_A); - INSN(move16_mem, f600, ffe0, M68040); - INSN(move16_reg, f620, fff8, M68040); INSN(wddata, fb00, ff00, CF_ISA_A); INSN(wdebug, fbc0, ffc0, CF_ISA_A); +#endif + INSN(move16_mem, f600, ffe0, M68040); + INSN(move16_reg, f620, fff8, M68040); #undef INSN } From f58ed1c50add3e76331afdc92387c0da9dd9e443 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:06 +0100 Subject: [PATCH 449/546] target/m68k: add cpush/cinv Add cache lines invalidate and cache lines push as no-op operations, as we don't have cache. These instructions are 68040 only. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-11-laurent@vivier.eu> --- target/m68k/translate.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index f77005215f..98efe6b976 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4496,6 +4496,24 @@ DISAS_INSN(cpushl) /* Cache push/invalidate. Implement as no-op. */ } +DISAS_INSN(cpush) +{ + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + /* Cache push/invalidate. Implement as no-op. */ +} + +DISAS_INSN(cinv) +{ + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + /* Invalidate cache line. Implement as no-op. */ +} + DISAS_INSN(wddata) { gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); @@ -5674,6 +5692,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(fsave, f300, ffc0, FPU); INSN(intouch, f340, ffc0, CF_ISA_A); INSN(cpushl, f428, ff38, CF_ISA_A); + INSN(cpush, f420, ff20, M68040); + INSN(cinv, f400, ff20, M68040); INSN(wddata, fb00, ff00, CF_ISA_A); INSN(wdebug, fbc0, ffc0, CF_ISA_A); #endif From 0bdb2b3bf5660f892ddbfa09baea56cdca57ad1d Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:07 +0100 Subject: [PATCH 450/546] target/m68k: add reset The instruction traps if the CPU is not in Supervisor state but the helper is empty because there is no easy way to reset all the peripherals without resetting the CPU itself. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-12-laurent@vivier.eu> --- target/m68k/helper.c | 7 +++++++ target/m68k/helper.h | 4 ++++ target/m68k/translate.c | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/target/m68k/helper.c b/target/m68k/helper.c index af57ffcea9..52b054e1a3 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -711,3 +711,10 @@ void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) res |= (uint64_t)(val & 0xffff0000) << 16; env->macc[acc + 1] = res; } + +#if defined(CONFIG_SOFTMMU) +void HELPER(reset)(CPUM68KState *env) +{ + /* FIXME: reset all except CPU */ +} +#endif diff --git a/target/m68k/helper.h b/target/m68k/helper.h index 78483da003..d27ea37d60 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -97,3 +97,7 @@ DEF_HELPER_FLAGS_4(bfffo_mem, TCG_CALL_NO_WG, i64, env, i32, s32, i32) DEF_HELPER_3(chk, void, env, s32, s32) DEF_HELPER_4(chk2, void, env, s32, s32, s32) + +#if defined(CONFIG_SOFTMMU) +DEF_HELPER_FLAGS_1(reset, TCG_CALL_NO_RWG, void, env) +#endif diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 98efe6b976..e8f7d07f3f 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2762,6 +2762,18 @@ DISAS_INSN(unlk) tcg_temp_free(src); } +#if defined(CONFIG_SOFTMMU) +DISAS_INSN(reset) +{ + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + + gen_helper_reset(cpu_env); +} +#endif + DISAS_INSN(nop) { } @@ -5572,6 +5584,7 @@ void register_m68k_insns (CPUM68KState *env) #if defined(CONFIG_SOFTMMU) INSN(move_to_usp, 4e60, fff8, USP); INSN(move_from_usp, 4e68, fff8, USP); + INSN(reset, 4e70, ffff, M68000); BASE(stop, 4e72, ffff); BASE(rte, 4e73, ffff); INSN(movec, 4e7b, ffff, CF_ISA_A); From fff3b4b0e16c76669e56173acb9d3cc6aac85e85 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:08 +0100 Subject: [PATCH 451/546] target/m68k: implement fsave/frestore Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-13-laurent@vivier.eu> --- target/m68k/translate.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index e8f7d07f3f..b8ed85c237 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5103,28 +5103,35 @@ DISAS_INSN(fscc) #if defined(CONFIG_SOFTMMU) DISAS_INSN(frestore) { - M68kCPU *cpu = m68k_env_get_cpu(env); + TCGv addr; if (IS_USER(s)) { gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } - - /* TODO: Implement frestore. */ - cpu_abort(CPU(cpu), "FRESTORE not implemented"); + if (m68k_feature(s->env, M68K_FEATURE_M68040)) { + SRC_EA(env, addr, OS_LONG, 0, NULL); + /* FIXME: check the state frame */ + } else { + disas_undef(env, s, insn); + } } DISAS_INSN(fsave) { - M68kCPU *cpu = m68k_env_get_cpu(env); - if (IS_USER(s)) { gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } - /* TODO: Implement fsave. */ - cpu_abort(CPU(cpu), "FSAVE not implemented"); + if (m68k_feature(s->env, M68K_FEATURE_M68040)) { + /* always write IDLE */ + TCGv idle = tcg_const_i32(0x41000000); + DEST_EA(env, insn, OS_LONG, idle, NULL); + tcg_temp_free(idle); + } else { + disas_undef(env, s, insn); + } } #endif From 01490ea8f575656a9431fc0170a82bc6064fa2ef Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:09 +0100 Subject: [PATCH 452/546] target/m68k: move CCR/SR functions The following patches will be clearer if we move functions before adding new ones. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-14-laurent@vivier.eu> --- target/m68k/translate.c | 111 ++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index b8ed85c237..1f867a4f7a 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2131,6 +2131,61 @@ DISAS_INSN(bitop_im) } } +static TCGv gen_get_ccr(DisasContext *s) +{ + TCGv dest; + + update_cc_op(s); + dest = tcg_temp_new(); + gen_helper_get_ccr(dest, cpu_env); + return dest; +} + +static TCGv gen_get_sr(DisasContext *s) +{ + TCGv ccr; + TCGv sr; + + ccr = gen_get_ccr(s); + sr = tcg_temp_new(); + tcg_gen_andi_i32(sr, QREG_SR, 0xffe0); + tcg_gen_or_i32(sr, sr, ccr); + return sr; +} + +static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) +{ + if (ccr_only) { + tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0); + tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0); + tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1); + tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0); + tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0); + } else { + gen_helper_set_sr(cpu_env, tcg_const_i32(val)); + } + set_cc_op(s, CC_OP_FLAGS); +} + +static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, + int ccr_only) +{ + if ((insn & 0x38) == 0) { + if (ccr_only) { + gen_helper_set_ccr(cpu_env, DREG(insn, 0)); + } else { + gen_helper_set_sr(cpu_env, DREG(insn, 0)); + } + set_cc_op(s, CC_OP_FLAGS); + } else if ((insn & 0x3f) == 0x3c) { + uint16_t val; + val = read_im16(env, s); + gen_set_sr_im(s, val, ccr_only); + } else { + disas_undef(env, s, insn); + } +} + DISAS_INSN(arith_im) { int op; @@ -2474,16 +2529,6 @@ DISAS_INSN(clr) tcg_temp_free(zero); } -static TCGv gen_get_ccr(DisasContext *s) -{ - TCGv dest; - - update_cc_op(s); - dest = tcg_temp_new(); - gen_helper_get_ccr(dest, cpu_env); - return dest; -} - DISAS_INSN(move_from_ccr) { TCGv ccr; @@ -2510,40 +2555,6 @@ DISAS_INSN(neg) tcg_temp_free(dest); } -static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) -{ - if (ccr_only) { - tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0); - tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0); - tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1); - tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0); - tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0); - } else { - gen_helper_set_sr(cpu_env, tcg_const_i32(val)); - } - set_cc_op(s, CC_OP_FLAGS); -} - -static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, - int ccr_only) -{ - if ((insn & 0x38) == 0) { - if (ccr_only) { - gen_helper_set_ccr(cpu_env, DREG(insn, 0)); - } else { - gen_helper_set_sr(cpu_env, DREG(insn, 0)); - } - set_cc_op(s, CC_OP_FLAGS); - } else if ((insn & 0x3f) == 0x3c) { - uint16_t val; - val = read_im16(env, s); - gen_set_sr_im(s, val, ccr_only); - } else { - disas_undef(env, s, insn); - } -} - - DISAS_INSN(move_to_ccr) { gen_set_sr(env, s, insn, 1); @@ -4359,18 +4370,6 @@ DISAS_INSN(move16_mem) } } -static TCGv gen_get_sr(DisasContext *s) -{ - TCGv ccr; - TCGv sr; - - ccr = gen_get_ccr(s); - sr = tcg_temp_new(); - tcg_gen_andi_i32(sr, QREG_SR, 0xffe0); - tcg_gen_or_i32(sr, sr, ccr); - return sr; -} - DISAS_INSN(strldsr) { uint16_t ext; From b6a21d8d8f69ac04fd6180e752a65d582c07e948 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:10 +0100 Subject: [PATCH 453/546] target/m68k: add 680x0 "move to SR" instruction Some cleanup, and allows SR to be moved from any addressing mode. Previous code was wrong for coldfire: coldfire also allows to use addressing mode to set SR/CCR. It only supports Data register to get SR/CCR (move from) Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-15-laurent@vivier.eu> --- target/m68k/translate.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 1f867a4f7a..8f23cade04 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2162,27 +2162,34 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0); tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0); } else { - gen_helper_set_sr(cpu_env, tcg_const_i32(val)); + TCGv sr = tcg_const_i32(val); + gen_helper_set_sr(cpu_env, sr); + tcg_temp_free(sr); } set_cc_op(s, CC_OP_FLAGS); } -static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, - int ccr_only) +static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) { - if ((insn & 0x38) == 0) { - if (ccr_only) { - gen_helper_set_ccr(cpu_env, DREG(insn, 0)); - } else { - gen_helper_set_sr(cpu_env, DREG(insn, 0)); - } - set_cc_op(s, CC_OP_FLAGS); - } else if ((insn & 0x3f) == 0x3c) { + if (ccr_only) { + gen_helper_set_ccr(cpu_env, val); + } else { + gen_helper_set_sr(cpu_env, val); + } + set_cc_op(s, CC_OP_FLAGS); +} + +static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, + bool ccr_only) +{ + if ((insn & 0x3f) == 0x3c) { uint16_t val; val = read_im16(env, s); gen_set_sr_im(s, val, ccr_only); } else { - disas_undef(env, s, insn); + TCGv src; + SRC_EA(env, src, OS_WORD, 0, NULL); + gen_set_sr(s, src, ccr_only); } } @@ -2557,7 +2564,7 @@ DISAS_INSN(neg) DISAS_INSN(move_to_ccr) { - gen_set_sr(env, s, insn, 1); + gen_move_to_sr(env, s, insn, true); } DISAS_INSN(not) @@ -4409,7 +4416,7 @@ DISAS_INSN(move_to_sr) gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); return; } - gen_set_sr(env, s, insn, 0); + gen_move_to_sr(env, s, insn, false); gen_lookup_tb(s); } @@ -5556,9 +5563,8 @@ void register_m68k_insns (CPUM68KState *env) BASE(move_to_ccr, 44c0, ffc0); INSN(not, 4680, fff8, CF_ISA_A); INSN(not, 4600, ff00, M68000); - INSN(undef, 46c0, ffc0, M68000); #if defined(CONFIG_SOFTMMU) - INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); + BASE(move_to_sr, 46c0, ffc0); #endif INSN(nbcd, 4800, ffc0, M68000); INSN(linkl, 4808, fff8, M68000); From b5ae1edc294f78865ede38377c0a9b92da4370e0 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:11 +0100 Subject: [PATCH 454/546] target/m68k: add andi/ori/eori to SR/CCR Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-16-laurent@vivier.eu> --- target/m68k/translate.c | 53 +++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 8f23cade04..499aaa2f3d 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -2201,6 +2201,7 @@ DISAS_INSN(arith_im) TCGv dest; TCGv addr; int opsize; + bool with_SR = ((insn & 0x3f) == 0x3c); op = (insn >> 9) & 7; opsize = insn_opsize(insn); @@ -2217,32 +2218,73 @@ DISAS_INSN(arith_im) default: abort(); } - SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr); + + if (with_SR) { + /* SR/CCR can only be used with andi/eori/ori */ + if (op == 2 || op == 3 || op == 6) { + disas_undef(env, s, insn); + return; + } + switch (opsize) { + case OS_BYTE: + src1 = gen_get_ccr(s); + break; + case OS_WORD: + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + src1 = gen_get_sr(s); + break; + case OS_LONG: + disas_undef(env, s, insn); + return; + } + } else { + SRC_EA(env, src1, opsize, 1, (op == 6) ? NULL : &addr); + } dest = tcg_temp_new(); switch (op) { case 0: /* ori */ tcg_gen_or_i32(dest, src1, im); - gen_logic_cc(s, dest, opsize); + if (with_SR) { + gen_set_sr(s, dest, opsize == OS_BYTE); + } else { + DEST_EA(env, insn, opsize, dest, &addr); + gen_logic_cc(s, dest, opsize); + } break; case 1: /* andi */ tcg_gen_and_i32(dest, src1, im); - gen_logic_cc(s, dest, opsize); + if (with_SR) { + gen_set_sr(s, dest, opsize == OS_BYTE); + } else { + DEST_EA(env, insn, opsize, dest, &addr); + gen_logic_cc(s, dest, opsize); + } break; case 2: /* subi */ tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, src1, im); tcg_gen_sub_i32(dest, src1, im); gen_update_cc_add(dest, im, opsize); set_cc_op(s, CC_OP_SUBB + opsize); + DEST_EA(env, insn, opsize, dest, &addr); break; case 3: /* addi */ tcg_gen_add_i32(dest, src1, im); gen_update_cc_add(dest, im, opsize); tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, im); set_cc_op(s, CC_OP_ADDB + opsize); + DEST_EA(env, insn, opsize, dest, &addr); break; case 5: /* eori */ tcg_gen_xor_i32(dest, src1, im); - gen_logic_cc(s, dest, opsize); + if (with_SR) { + gen_set_sr(s, dest, opsize == OS_BYTE); + } else { + DEST_EA(env, insn, opsize, dest, &addr); + gen_logic_cc(s, dest, opsize); + } break; case 6: /* cmpi */ gen_update_cc_cmp(s, src1, im, opsize); @@ -2251,9 +2293,6 @@ DISAS_INSN(arith_im) abort(); } tcg_temp_free(im); - if (op != 6) { - DEST_EA(env, insn, opsize, dest, &addr); - } tcg_temp_free(dest); } From 6e22b28e22aa6ed1b8db6f24da2633868019d4c9 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:12 +0100 Subject: [PATCH 455/546] target/m68k: add the Interrupt Stack Pointer Add the third stack pointer, the Interrupt Stack Pointer (ISP) (680x0 only). This stack will be needed in softmmu mode. Update movec to set/get the value of the three stacks. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-17-laurent@vivier.eu> --- target/m68k/cpu.c | 8 ++-- target/m68k/cpu.h | 70 ++++++++++++++++++++++++++++++++++- target/m68k/gdbstub.c | 2 +- target/m68k/helper.c | 82 +++++++++++++++++++++++++++++++++++++---- target/m68k/helper.h | 4 +- target/m68k/monitor.c | 1 + target/m68k/translate.c | 40 ++++++++++++++++++-- 7 files changed, 190 insertions(+), 17 deletions(-) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 1936efd170..03126ba543 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -55,17 +55,17 @@ static void m68k_cpu_reset(CPUState *s) mcc->parent_reset(s); memset(env, 0, offsetof(CPUM68KState, end_reset_fields)); -#if !defined(CONFIG_USER_ONLY) - env->sr = 0x2700; +#ifdef CONFIG_SOFTMMU + cpu_m68k_set_sr(env, SR_S | SR_I); +#else + cpu_m68k_set_sr(env, 0); #endif - m68k_switch_sp(env); for (i = 0; i < 8; i++) { env->fregs[i].d = nan; } cpu_m68k_set_fpcr(env, 0); env->fpsr = 0; - cpu_m68k_set_ccr(env, 0); /* TODO: We should set PC from the interrupt vector. */ env->pc = 0; } diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 2ac4ab191e..759b30d389 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -89,7 +89,7 @@ typedef struct CPUM68KState { /* SSP and USP. The current_sp is stored in aregs[7], the other here. */ int current_sp; - uint32_t sp[2]; + uint32_t sp[3]; /* Condition flags. */ uint32_t cc_op; @@ -223,6 +223,74 @@ typedef enum { #define M68K_SSP 0 #define M68K_USP 1 +#define M68K_ISP 2 + +/* m68k Control Registers */ + +/* ColdFire */ +/* Memory Management Control Registers */ +#define M68K_CR_ASID 0x003 +#define M68K_CR_ACR0 0x004 +#define M68K_CR_ACR1 0x005 +#define M68K_CR_ACR2 0x006 +#define M68K_CR_ACR3 0x007 +#define M68K_CR_MMUBAR 0x008 + +/* Processor Miscellaneous Registers */ +#define M68K_CR_PC 0x80F + +/* Local Memory and Module Control Registers */ +#define M68K_CR_ROMBAR0 0xC00 +#define M68K_CR_ROMBAR1 0xC01 +#define M68K_CR_RAMBAR0 0xC04 +#define M68K_CR_RAMBAR1 0xC05 +#define M68K_CR_MPCR 0xC0C +#define M68K_CR_EDRAMBAR 0xC0D +#define M68K_CR_SECMBAR 0xC0E +#define M68K_CR_MBAR 0xC0F + +/* Local Memory Address Permutation Control Registers */ +#define M68K_CR_PCR1U0 0xD02 +#define M68K_CR_PCR1L0 0xD03 +#define M68K_CR_PCR2U0 0xD04 +#define M68K_CR_PCR2L0 0xD05 +#define M68K_CR_PCR3U0 0xD06 +#define M68K_CR_PCR3L0 0xD07 +#define M68K_CR_PCR1U1 0xD0A +#define M68K_CR_PCR1L1 0xD0B +#define M68K_CR_PCR2U1 0xD0C +#define M68K_CR_PCR2L1 0xD0D +#define M68K_CR_PCR3U1 0xD0E +#define M68K_CR_PCR3L1 0xD0F + +/* MC680x0 */ +/* MC680[1234]0/CPU32 */ +#define M68K_CR_SFC 0x000 +#define M68K_CR_DFC 0x001 +#define M68K_CR_USP 0x800 +#define M68K_CR_VBR 0x801 /* + Coldfire */ + +/* MC680[234]0 */ +#define M68K_CR_CACR 0x002 /* + Coldfire */ +#define M68K_CR_CAAR 0x802 /* MC68020 and MC68030 only */ +#define M68K_CR_MSP 0x803 +#define M68K_CR_ISP 0x804 + +/* MC68040/MC68LC040 */ +#define M68K_CR_TC 0x003 +#define M68K_CR_ITT0 0x004 +#define M68K_CR_ITT1 0x005 +#define M68K_CR_DTT0 0x006 +#define M68K_CR_DTT1 0x007 +#define M68K_CR_MMUSR 0x805 +#define M68K_CR_URP 0x806 +#define M68K_CR_SRP 0x807 + +/* MC68EC040 */ +#define M68K_CR_IACR0 0x004 +#define M68K_CR_IACR1 0x005 +#define M68K_CR_DACR0 0x006 +#define M68K_CR_DACR1 0x007 #define M68K_FPIAR_SHIFT 0 #define M68K_FPIAR (1 << M68K_FPIAR_SHIFT) diff --git a/target/m68k/gdbstub.c b/target/m68k/gdbstub.c index c7f44c9bb3..99e5be8132 100644 --- a/target/m68k/gdbstub.c +++ b/target/m68k/gdbstub.c @@ -63,7 +63,7 @@ int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) } else { switch (n) { case 16: - env->sr = tmp; + cpu_m68k_set_sr(env, tmp); break; case 17: env->pc = tmp; diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 52b054e1a3..a999389e9a 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -171,28 +171,84 @@ void m68k_cpu_init_gdb(M68kCPU *cpu) /* TODO: Add [E]MAC registers. */ } -void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) +void HELPER(cf_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) { M68kCPU *cpu = m68k_env_get_cpu(env); switch (reg) { - case 0x02: /* CACR */ + case M68K_CR_CACR: env->cacr = val; m68k_switch_sp(env); break; - case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */ + case M68K_CR_ACR0: + case M68K_CR_ACR1: + case M68K_CR_ACR2: + case M68K_CR_ACR3: /* TODO: Implement Access Control Registers. */ break; - case 0x801: /* VBR */ + case M68K_CR_VBR: env->vbr = val; break; /* TODO: Implement control registers. */ default: - cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", + cpu_abort(CPU(cpu), + "Unimplemented control register write 0x%x = 0x%x\n", reg, val); } } +void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) +{ + M68kCPU *cpu = m68k_env_get_cpu(env); + + switch (reg) { + /* MC680[1234]0 */ + case M68K_CR_VBR: + env->vbr = val; + return; + /* MC680[234]0 */ + case M68K_CR_CACR: + env->cacr = val; + m68k_switch_sp(env); + return; + /* MC680[34]0 */ + case M68K_CR_USP: + env->sp[M68K_USP] = val; + return; + case M68K_CR_MSP: + env->sp[M68K_SSP] = val; + return; + case M68K_CR_ISP: + env->sp[M68K_ISP] = val; + return; + } + cpu_abort(CPU(cpu), "Unimplemented control register write 0x%x = 0x%x\n", + reg, val); +} + +uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) +{ + M68kCPU *cpu = m68k_env_get_cpu(env); + + switch (reg) { + /* MC680[1234]0 */ + case M68K_CR_VBR: + return env->vbr; + /* MC680[234]0 */ + case M68K_CR_CACR: + return env->cacr; + /* MC680[34]0 */ + case M68K_CR_USP: + return env->sp[M68K_USP]; + case M68K_CR_MSP: + return env->sp[M68K_SSP]; + case M68K_CR_ISP: + return env->sp[M68K_ISP]; + } + cpu_abort(CPU(cpu), "Unimplemented control register read 0x%x\n", + reg); +} + void HELPER(set_macsr)(CPUM68KState *env, uint32_t val) { uint32_t acc; @@ -232,8 +288,20 @@ void m68k_switch_sp(CPUM68KState *env) int new_sp; env->sp[env->current_sp] = env->aregs[7]; - new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) - ? M68K_SSP : M68K_USP; + if (m68k_feature(env, M68K_FEATURE_M68000)) { + if (env->sr & SR_S) { + if (env->sr & SR_M) { + new_sp = M68K_SSP; + } else { + new_sp = M68K_ISP; + } + } else { + new_sp = M68K_USP; + } + } else { + new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP) + ? M68K_SSP : M68K_USP; + } env->aregs[7] = env->sp[new_sp]; env->current_sp = new_sp; } diff --git a/target/m68k/helper.h b/target/m68k/helper.h index d27ea37d60..57f210aa14 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -8,7 +8,9 @@ DEF_HELPER_4(divsl, void, env, int, int, s32) DEF_HELPER_4(divull, void, env, int, int, i32) DEF_HELPER_4(divsll, void, env, int, int, s32) DEF_HELPER_2(set_sr, void, env, i32) -DEF_HELPER_3(movec, void, env, i32, i32) +DEF_HELPER_3(cf_movec_to, void, env, i32, i32) +DEF_HELPER_3(m68k_movec_to, void, env, i32, i32) +DEF_HELPER_2(m68k_movec_from, i32, env, i32) DEF_HELPER_4(cas2w, void, env, i32, i32, i32) DEF_HELPER_4(cas2l, void, env, i32, i32, i32) DEF_HELPER_4(cas2l_parallel, void, env, i32, i32, i32) diff --git a/target/m68k/monitor.c b/target/m68k/monitor.c index 5605323a81..52781e85f0 100644 --- a/target/m68k/monitor.c +++ b/target/m68k/monitor.c @@ -30,6 +30,7 @@ static const MonitorDef monitor_defs[] = { { "sr", offsetof(CPUM68KState, sr) }, { "ssp", offsetof(CPUM68KState, sp[0]) }, { "usp", offsetof(CPUM68KState, sp[1]) }, + { "isp", offsetof(CPUM68KState, sp[2]) }, { NULL }, }; diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 499aaa2f3d..4d5173c4be 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4514,7 +4514,7 @@ DISAS_INSN(rte) gen_exception(s, s->insn_pc, EXCP_RTE); } -DISAS_INSN(movec) +DISAS_INSN(cf_movec) { uint16_t ext; TCGv reg; @@ -4531,7 +4531,32 @@ DISAS_INSN(movec) } else { reg = DREG(ext, 12); } - gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg); + gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg); + gen_lookup_tb(s); +} + +DISAS_INSN(m68k_movec) +{ + uint16_t ext; + TCGv reg; + + if (IS_USER(s)) { + gen_exception(s, s->insn_pc, EXCP_PRIVILEGE); + return; + } + + ext = read_im16(env, s); + + if (ext & 0x8000) { + reg = AREG(ext, 12); + } else { + reg = DREG(ext, 12); + } + if (insn & 1) { + gen_helper_m68k_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg); + } else { + gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff)); + } gen_lookup_tb(s); } @@ -5638,7 +5663,8 @@ void register_m68k_insns (CPUM68KState *env) INSN(reset, 4e70, ffff, M68000); BASE(stop, 4e72, ffff); BASE(rte, 4e73, ffff); - INSN(movec, 4e7b, ffff, CF_ISA_A); + INSN(cf_movec, 4e7b, ffff, CF_ISA_A); + INSN(m68k_movec, 4e7a, fffe, M68000); #endif BASE(nop, 4e71, ffff); INSN(rtd, 4e74, ffff, RTD); @@ -5945,6 +5971,14 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "RP "); break; } + cpu_fprintf(f, "\n"); +#ifdef CONFIG_SOFTMMU + cpu_fprintf(f, "%sA7(MSP) = %08x %sA7(USP) = %08x %sA7(ISP) = %08x\n", + env->current_sp == M68K_SSP ? "->" : " ", env->sp[M68K_SSP], + env->current_sp == M68K_USP ? "->" : " ", env->sp[M68K_USP], + env->current_sp == M68K_ISP ? "->" : " ", env->sp[M68K_ISP]); + cpu_fprintf(f, "VBR = 0x%08x\n", env->vbr); +#endif } void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, From cc5230267678c26b7f96157086f45fd8a347eb21 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Thu, 4 Jan 2018 02:29:13 +0100 Subject: [PATCH 456/546] target/m68k: fix m68k_cpu_dump_state() Display correctly the Trace bits for 680x0 (2 bits instead of 1 for Coldfire). Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson Message-Id: <20180104012913.30763-18-laurent@vivier.eu> --- target/m68k/cpu.h | 3 ++- target/m68k/translate.c | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 759b30d389..2985b039e1 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -219,7 +219,8 @@ typedef enum { #define SR_I 0x0700 #define SR_M 0x1000 #define SR_S 0x2000 -#define SR_T 0x8000 +#define SR_T_SHIFT 14 +#define SR_T 0xc000 #define M68K_SSP 0 #define M68K_USP 1 diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 4d5173c4be..4a6d799ee2 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -5936,9 +5936,12 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, } cpu_fprintf (f, "PC = %08x ", env->pc); sr = env->sr | cpu_m68k_get_ccr(env); - cpu_fprintf(f, "SR = %04x %c%c%c%c%c ", sr, (sr & CCF_X) ? 'X' : '-', - (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', - (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); + cpu_fprintf(f, "SR = %04x T:%x I:%x %c%c %c%c%c%c%c\n", + sr, (sr & SR_T) >> SR_T_SHIFT, (sr & SR_I) >> SR_I_SHIFT, + (sr & SR_S) ? 'S' : 'U', (sr & SR_M) ? '%' : 'I', + (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', + (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', + (sr & CCF_C) ? 'C' : '-'); cpu_fprintf(f, "FPSR = %08x %c%c%c%c ", env->fpsr, (env->fpsr & FPSR_CC_A) ? 'A' : '-', (env->fpsr & FPSR_CC_I) ? 'I' : '-', From bd3be4dbbf0491d6db8bf326706747b4629ace4b Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 457/546] virtio-9p: move unrealize/realize after virtio_9p_transport definition And drop the now useless forward declaration of virtio_9p_transport. Signed-off-by: Greg Kurz --- hw/9pfs/virtio-9p-device.c | 60 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 62650b0a6b..c3ae7de3a2 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -20,8 +20,6 @@ #include "hw/virtio/virtio-access.h" #include "qemu/iov.h" -static const struct V9fsTransport virtio_9p_transport; - static void virtio_9p_push_and_notify(V9fsPDU *pdu) { V9fsState *s = pdu->s; @@ -104,35 +102,6 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) g_free(cfg); } -static void virtio_9p_device_realize(DeviceState *dev, Error **errp) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - V9fsVirtioState *v = VIRTIO_9P(dev); - V9fsState *s = &v->state; - - if (v9fs_device_realize_common(s, errp)) { - goto out; - } - - v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); - virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); - v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); - v9fs_register_transport(s, &virtio_9p_transport); - -out: - return; -} - -static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) -{ - VirtIODevice *vdev = VIRTIO_DEVICE(dev); - V9fsVirtioState *v = VIRTIO_9P(dev); - V9fsState *s = &v->state; - - virtio_cleanup(vdev); - v9fs_device_unrealize_common(s, errp); -} - static void virtio_9p_reset(VirtIODevice *vdev) { V9fsVirtioState *v = (V9fsVirtioState *)vdev; @@ -223,6 +192,35 @@ static const struct V9fsTransport virtio_9p_transport = { .push_and_notify = virtio_9p_push_and_notify, }; +static void virtio_9p_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + V9fsVirtioState *v = VIRTIO_9P(dev); + V9fsState *s = &v->state; + + if (v9fs_device_realize_common(s, errp)) { + goto out; + } + + v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag); + virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size); + v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output); + v9fs_register_transport(s, &virtio_9p_transport); + +out: + return; +} + +static void virtio_9p_device_unrealize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + V9fsVirtioState *v = VIRTIO_9P(dev); + V9fsState *s = &v->state; + + virtio_cleanup(vdev); + v9fs_device_unrealize_common(s, errp); +} + /* virtio-9p device */ static const VMStateDescription vmstate_virtio_9p = { From 01847522bc1165438d933092d9482dd917342662 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 458/546] 9pfs: fix XattrOperations typedef To comply with the QEMU coding style. Signed-off-by: Greg Kurz --- fsdev/file-op-9p.h | 5 +++-- hw/9pfs/9p-xattr.h | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 474c79d003..05b3ef3574 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -30,7 +30,6 @@ typedef struct FsCred dev_t fc_rdev; } FsCred; -struct xattr_operations; struct FsContext; struct V9fsPath; @@ -67,6 +66,8 @@ typedef struct extended_ops { typedef struct FileOperations FileOperations; +typedef struct XattrOperations XattrOperations; + /* * Structure to store the various fsdev's passed through command line. */ @@ -85,7 +86,7 @@ typedef struct FsContext uid_t uid; char *fs_root; int export_flags; - struct xattr_operations **xops; + XattrOperations **xops; struct extended_ops exops; FsThrottle *fst; /* fs driver specific data */ diff --git a/hw/9pfs/9p-xattr.h b/hw/9pfs/9p-xattr.h index 0d83996575..35bcd24f77 100644 --- a/hw/9pfs/9p-xattr.h +++ b/hw/9pfs/9p-xattr.h @@ -16,8 +16,7 @@ #include "qemu/xattr.h" -typedef struct xattr_operations -{ +struct XattrOperations { const char *name; ssize_t (*getxattr)(FsContext *ctx, const char *path, const char *name, void *value, size_t size); @@ -27,7 +26,7 @@ typedef struct xattr_operations void *value, size_t size, int flags); int (*removexattr)(FsContext *ctx, const char *path, const char *name); -} XattrOperations; +}; ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, const char *name, void *value, size_t size); From 1a8d0bb31a02f492cb8c77b3022e652bc288da7c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 459/546] fsdev: fix some type definitions To comply with the QEMU coding style. Signed-off-by: Greg Kurz --- fsdev/file-op-9p.h | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 05b3ef3574..32125100ce 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -22,21 +22,19 @@ #define SM_LOCAL_MODE_BITS 0600 #define SM_LOCAL_DIR_MODE_BITS 0700 -typedef struct FsCred -{ +typedef struct FsCred { uid_t fc_uid; gid_t fc_gid; mode_t fc_mode; dev_t fc_rdev; } FsCred; -struct FsContext; -struct V9fsPath; +typedef struct FsContext FsContext; +typedef struct V9fsPath V9fsPath; -typedef struct extended_ops { - int (*get_st_gen)(struct FsContext *, struct V9fsPath *, - mode_t, uint64_t *); -} extended_ops; +typedef struct ExtendedOps { + int (*get_st_gen)(FsContext *, V9fsPath *, mode_t, uint64_t *); +} ExtendedOps; /* export flags */ #define V9FS_IMMEDIATE_WRITEOUT 0x00000001 @@ -81,24 +79,23 @@ typedef struct FsDriverEntry { mode_t dmode; } FsDriverEntry; -typedef struct FsContext -{ +struct FsContext { uid_t uid; char *fs_root; int export_flags; XattrOperations **xops; - struct extended_ops exops; + ExtendedOps exops; FsThrottle *fst; /* fs driver specific data */ void *private; mode_t fmode; mode_t dmode; -} FsContext; +}; -typedef struct V9fsPath { +struct V9fsPath { uint16_t size; char *data; -} V9fsPath; +}; typedef union V9fsFidOpenState V9fsFidOpenState; @@ -106,9 +103,9 @@ void cred_init(FsCred *); struct FileOperations { - int (*parse_opts)(QemuOpts *, struct FsDriverEntry *); - int (*init)(struct FsContext *); - void (*cleanup)(struct FsContext *); + int (*parse_opts)(QemuOpts *, FsDriverEntry *); + int (*init)(FsContext *); + void (*cleanup)(FsContext *); int (*lstat)(FsContext *, V9fsPath *, struct stat *); ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t); int (*chmod)(FsContext *, V9fsPath *, FsCred *); From 8e71b96c62d4d3b5e757ca84ba12424ce10ea7d3 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 460/546] 9pfs: fix some type definitions To comply with the QEMU coding style. Signed-off-by: Greg Kurz --- hw/9pfs/9p.c | 6 +++--- hw/9pfs/9p.h | 12 ++++++------ hw/9pfs/virtio-9p-device.c | 2 +- hw/9pfs/xen-9p-backend.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 52d46632fe..76f90f2b78 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -99,10 +99,10 @@ static int omode_to_uflags(int8_t mode) return ret; } -struct dotl_openflag_map { +typedef struct DotlOpenflagMap { int dotl_flag; int open_flag; -}; +} DotlOpenflagMap; static int dotl_to_open_flags(int flags) { @@ -113,7 +113,7 @@ static int dotl_to_open_flags(int flags) */ int oflags = flags & O_ACCMODE; - struct dotl_openflag_map dotl_oflag_map[] = { + DotlOpenflagMap dotl_oflag_map[] = { { P9_DOTL_CREATE, O_CREAT }, { P9_DOTL_EXCL, O_EXCL }, { P9_DOTL_NOCTTY , O_NOCTTY }, diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index cdfc4f4ce7..6e3b483917 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -94,10 +94,10 @@ enum { P9_QTFILE = 0x00, }; -enum p9_proto_version { +typedef enum P9ProtoVersion { V9FS_PROTO_2000U = 0x01, V9FS_PROTO_2000L = 0x02, -}; +} P9ProtoVersion; #define P9_NOTAG UINT16_MAX #define P9_NOFID UINT32_MAX @@ -118,6 +118,7 @@ static inline char *rpath(FsContext *ctx, const char *path) typedef struct V9fsPDU V9fsPDU; typedef struct V9fsState V9fsState; +typedef struct V9fsTransport V9fsTransport; typedef struct { uint32_t size_le; @@ -238,10 +239,10 @@ struct V9fsState FileOperations *ops; FsContext ctx; char *tag; - enum p9_proto_version proto_version; + P9ProtoVersion proto_version; int32_t msize; V9fsPDU pdus[MAX_REQ]; - const struct V9fsTransport *transport; + const V9fsTransport *transport; /* * lock ensuring atomic path update * on rename. @@ -367,8 +368,7 @@ struct V9fsTransport { void (*push_and_notify)(V9fsPDU *pdu); }; -static inline int v9fs_register_transport(V9fsState *s, - const struct V9fsTransport *t) +static inline int v9fs_register_transport(V9fsState *s, const V9fsTransport *t) { assert(!s->transport); s->transport = t; diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index c3ae7de3a2..43f4e53f33 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -184,7 +184,7 @@ static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov, *pniov = elem->out_num; } -static const struct V9fsTransport virtio_9p_transport = { +static const V9fsTransport virtio_9p_transport = { .pdu_vmarshal = virtio_pdu_vmarshal, .pdu_vunmarshal = virtio_pdu_vunmarshal, .init_in_iov_from_pdu = virtio_init_in_iov_from_pdu, diff --git a/hw/9pfs/xen-9p-backend.c b/hw/9pfs/xen-9p-backend.c index ee87f08926..df2a4100bf 100644 --- a/hw/9pfs/xen-9p-backend.c +++ b/hw/9pfs/xen-9p-backend.c @@ -233,7 +233,7 @@ static void xen_9pfs_push_and_notify(V9fsPDU *pdu) qemu_bh_schedule(ring->bh); } -static const struct V9fsTransport xen_9p_transport = { +static const V9fsTransport xen_9p_transport = { .pdu_vmarshal = xen_9pfs_pdu_vmarshal, .pdu_vunmarshal = xen_9pfs_pdu_vunmarshal, .init_in_iov_from_pdu = xen_9pfs_init_in_iov_from_pdu, From c4ce2c0ff3e54639bb9c130fd9ade8d3503b661d Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 461/546] 9pfs: handle: fix type definition To comply with the QEMU coding style. Signed-off-by: Greg Kurz --- hw/9pfs/9p-handle.c | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index 9875f1894c..65b12de230 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -41,10 +41,10 @@ #define BTRFS_SUPER_MAGIC 0x9123683E #endif -struct handle_data { +typedef struct HandleData { int mountfd; int handle_bytes; -}; +} HandleData; static inline int name_to_handle(int dirfd, const char *name, struct file_handle *fh, int *mnt_id, int flags) @@ -79,7 +79,7 @@ static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { int fd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); if (fd < 0) { @@ -94,7 +94,7 @@ static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char *buf, size_t bufsz) { int fd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); if (fd < 0) { @@ -118,7 +118,7 @@ static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs) static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags, V9fsFidOpenState *fs) { - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fs->fd = open_by_handle(data->mountfd, fs_path->data, flags); return fs->fd; @@ -207,7 +207,7 @@ static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs, static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { int fd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -222,7 +222,7 @@ static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, FsCred *credp) { int dirfd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); if (dirfd < 0) { @@ -240,7 +240,7 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, FsCred *credp) { int dirfd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); if (dirfd < 0) { @@ -272,7 +272,7 @@ static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, { int ret; int dirfd, fd; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); if (dirfd < 0) { @@ -297,7 +297,7 @@ static int handle_symlink(FsContext *fs_ctx, const char *oldpath, V9fsPath *dir_path, const char *name, FsCred *credp) { int fd, dirfd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); if (dirfd < 0) { @@ -322,7 +322,7 @@ static int handle_link(FsContext *ctx, V9fsPath *oldpath, V9fsPath *dirpath, const char *name) { int oldfd, newdirfd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH); if (oldfd < 0) { @@ -342,7 +342,7 @@ static int handle_link(FsContext *ctx, V9fsPath *oldpath, static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY); if (fd < 0) { @@ -363,7 +363,7 @@ static int handle_rename(FsContext *ctx, const char *oldpath, static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { int fd, ret; - struct handle_data *data = (struct handle_data *)fs_ctx->private; + HandleData *data = (HandleData *) fs_ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); if (fd < 0) { @@ -379,7 +379,7 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, { int ret; int fd; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -418,7 +418,7 @@ static int handle_statfs(FsContext *ctx, V9fsPath *fs_path, struct statfs *stbuf) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -433,7 +433,7 @@ static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, void *value, size_t size) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -448,7 +448,7 @@ static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path, void *value, size_t size) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -463,7 +463,7 @@ static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, void *value, size_t size, int flags) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -478,7 +478,7 @@ static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path, const char *name) { int fd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); if (fd < 0) { @@ -495,7 +495,7 @@ static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, char *buffer; struct file_handle *fh; int dirfd, ret, mnt_id; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; /* "." and ".." are not allowed */ if (!strcmp(name, ".") || !strcmp(name, "..")) { @@ -536,7 +536,7 @@ static int handle_renameat(FsContext *ctx, V9fsPath *olddir, const char *new_name) { int olddirfd, newdirfd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH); if (olddirfd < 0) { @@ -557,7 +557,7 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir, const char *name, int flags) { int dirfd, ret; - struct handle_data *data = (struct handle_data *)ctx->private; + HandleData *data = (HandleData *) ctx->private; int rflags; dirfd = open_by_handle(data->mountfd, dir->data, O_PATH); @@ -609,7 +609,7 @@ static int handle_init(FsContext *ctx) int ret, mnt_id; struct statfs stbuf; struct file_handle fh; - struct handle_data *data = g_malloc(sizeof(struct handle_data)); + HandleData *data = g_malloc(sizeof(HandleData)); data->mountfd = open(ctx->fs_root, O_DIRECTORY); if (data->mountfd < 0) { @@ -646,7 +646,7 @@ out: static void handle_cleanup(FsContext *ctx) { - struct handle_data *data = ctx->private; + HandleData *data = ctx->private; close(data->mountfd); g_free(data); From 7bd41d3db6b16775f5e17151fd380b976fed2d2f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 462/546] 9pfs: fix type in *_parse_opts declarations To comply with the QEMU coding style. Signed-off-by: Greg Kurz Reviewed-by: Eric Blake --- hw/9pfs/9p-handle.c | 2 +- hw/9pfs/9p-local.c | 2 +- hw/9pfs/9p-proxy.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index 65b12de230..26ac90fc5c 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -652,7 +652,7 @@ static void handle_cleanup(FsContext *ctx) g_free(data); } -static int handle_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) +static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse) { const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index e51af87309..155834db28 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1459,7 +1459,7 @@ static void local_cleanup(FsContext *ctx) g_free(data); } -static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse) +static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse) { const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 28b20a7c3d..652940726e 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -1111,7 +1111,7 @@ static int connect_namedsocket(const char *path) return sockfd; } -static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs) +static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs) { const char *socket = qemu_opt_get(opts, "socket"); const char *sock_fd = qemu_opt_get(opts, "sock_fd"); From d1471233bb07611458b701e670e5e2ba0ac12e7c Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 463/546] 9pfs: fix error path in pdu_submit() If we receive an unsupported request id, we first decide to return -ENOTSUPP to the client, but since the request id causes is_read_only_op() to return false, we change the error to be -EROFS if the fsdev is read-only. This doesn't make sense since we don't know what the client asked for. This patch ensures that -EROFS can only be returned if the request id is supported. Signed-off-by: Greg Kurz Reviewed-by: Eric Blake --- hw/9pfs/9p.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 76f90f2b78..558efb41de 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3473,14 +3473,12 @@ void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr) if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) || (pdu_co_handlers[pdu->id] == NULL)) { handler = v9fs_op_not_supp; + } else if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) { + handler = v9fs_fs_ro; } else { handler = pdu_co_handlers[pdu->id]; } - if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) { - handler = v9fs_fs_ro; - } - qemu_co_queue_init(&pdu->complete); co = qemu_coroutine_create(handler, pdu); qemu_coroutine_enter(co); From 75673590942fd74c9befa31ef09f4b0f8f1c7eb2 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:22 +0100 Subject: [PATCH 464/546] 9pfs: make pdu_marshal() and pdu_unmarshal() static functions They're only used by the 9p core code. Signed-off-by: Greg Kurz Reviewed-by: Eric Blake --- hw/9pfs/9p.c | 4 ++-- hw/9pfs/9p.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 558efb41de..1e4ebbe576 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -41,7 +41,7 @@ enum { Oappend = 0x80, }; -ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) +static ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) { ssize_t ret; va_list ap; @@ -53,7 +53,7 @@ ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) return ret; } -ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) +static ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) { ssize_t ret; va_list ap; diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 6e3b483917..ffe658ab89 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -349,8 +349,6 @@ int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, int v9fs_device_realize_common(V9fsState *s, Error **errp); void v9fs_device_unrealize_common(V9fsState *s, Error **errp); -ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); -ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...); V9fsPDU *pdu_alloc(V9fsState *s); void pdu_free(V9fsPDU *pdu); void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr); From 65b70fc7dee3ec24afd606946ee7e093105c4875 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 465/546] tests: virtio-9p: fix ISR dependence Like other virtio tests, use the used ring APIs instead of assuming ISR being set means the request has completed. Signed-off-by: Greg Kurz Reviewed-by: Stefan Hajnoczi --- tests/virtio-9p-test.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index ad33d96387..ebd24b20f6 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -18,6 +18,8 @@ #include "standard-headers/linux/virtio_pci.h" #include "hw/9pfs/9p.h" +#define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) + static const char mount_tag[] = "qtest"; typedef struct { @@ -111,6 +113,7 @@ typedef struct { /* No r_size, it is hardcoded to P9_MAX_SIZE */ size_t t_off; size_t r_off; + uint32_t free_head; } P9Req; static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) @@ -124,11 +127,6 @@ static void v9fs_memskip(P9Req *req, size_t len) req->r_off += len; } -static void v9fs_memrewind(P9Req *req, size_t len) -{ - req->r_off -= len; -} - static void v9fs_memread(P9Req *req, void *addr, size_t len) { memread(req->r_msg + req->r_off, addr, len); @@ -227,12 +225,12 @@ static P9Req *v9fs_req_init(QVirtIO9P *v9p, uint32_t size, uint8_t id, static void v9fs_req_send(P9Req *req) { QVirtIO9P *v9p = req->v9p; - uint32_t free_head; req->r_msg = guest_alloc(v9p->qs->alloc, P9_MAX_SIZE); - free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, true); + req->free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, + true); qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); - qvirtqueue_kick(v9p->dev, v9p->vq, free_head); + qvirtqueue_kick(v9p->dev, v9p->vq, req->free_head); req->t_off = 0; } @@ -250,19 +248,13 @@ static void v9fs_req_recv(P9Req *req, uint8_t id) { QVirtIO9P *v9p = req->v9p; P9Hdr hdr; - int i; - for (i = 0; i < 10; i++) { - qvirtio_wait_queue_isr(v9p->dev, v9p->vq, 1000 * 1000); + qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, + QVIRTIO_9P_TIMEOUT_US); - v9fs_memread(req, &hdr, 7); - hdr.size = ldl_le_p(&hdr.size); - hdr.tag = lduw_le_p(&hdr.tag); - if (hdr.size >= 7) { - break; - } - v9fs_memrewind(req, 7); - } + v9fs_memread(req, &hdr, 7); + hdr.size = ldl_le_p(&hdr.size); + hdr.tag = lduw_le_p(&hdr.tag); g_assert_cmpint(hdr.size, >=, 7); g_assert_cmpint(hdr.size, <=, P9_MAX_SIZE); From d8803b1ad06734d36878645328011dc86108af9f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 466/546] tests: virtio-9p: set DRIVER_OK before using the device Signed-off-by: Greg Kurz --- tests/virtio-9p-test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index ebd24b20f6..00f00f7246 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -75,6 +75,9 @@ static QVirtIO9P *qvirtio_9p_pci_start(void) qvirtio_set_driver(v9p->dev); v9p->vq = qvirtqueue_setup(v9p->dev, v9p->qs->alloc, 0); + + qvirtio_set_driver_ok(v9p->dev); + return v9p; } From 91cda4e8f372602795e3a2f4bd2e3adaf9f82255 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 467/546] fsdev: improve error handling of backend opts parsing This patch changes some error messages in the backend opts parsing code and convert backends to propagate QEMU Error objects instead of calling error_report(). Signed-off-by: Greg Kurz --- fsdev/file-op-9p.h | 2 +- fsdev/qemu-fsdev.c | 4 +++- hw/9pfs/9p-handle.c | 2 +- hw/9pfs/9p-local.c | 33 +++++++++++++++++++-------------- hw/9pfs/9p-proxy.c | 16 +++++++++++++--- 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 32125100ce..b6d4eaffe3 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -103,7 +103,7 @@ void cred_init(FsCred *); struct FileOperations { - int (*parse_opts)(QemuOpts *, FsDriverEntry *); + int (*parse_opts)(QemuOpts *, FsDriverEntry *, Error **errp); int (*init)(FsContext *); void (*cleanup)(FsContext *); int (*lstat)(FsContext *, V9fsPath *, struct stat *); diff --git a/fsdev/qemu-fsdev.c b/fsdev/qemu-fsdev.c index 266e442b87..941e309657 100644 --- a/fsdev/qemu-fsdev.c +++ b/fsdev/qemu-fsdev.c @@ -37,6 +37,7 @@ int qemu_fsdev_add(QemuOpts *opts) const char *fsdriver = qemu_opt_get(opts, "fsdriver"); const char *writeout = qemu_opt_get(opts, "writeout"); bool ro = qemu_opt_get_bool(opts, "readonly", 0); + Error *local_err = NULL; if (!fsdev_id) { error_report("fsdev: No id specified"); @@ -74,7 +75,8 @@ int qemu_fsdev_add(QemuOpts *opts) } if (fsle->fse.ops->parse_opts) { - if (fsle->fse.ops->parse_opts(opts, &fsle->fse)) { + if (fsle->fse.ops->parse_opts(opts, &fsle->fse, &local_err)) { + error_report_err(local_err); g_free(fsle->fse.fsdev_id); g_free(fsle); return -1; diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index 26ac90fc5c..e50941075b 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -652,7 +652,7 @@ static void handle_cleanup(FsContext *ctx) g_free(data); } -static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse) +static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) { const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 155834db28..e1a4b844a5 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1459,16 +1459,21 @@ static void local_cleanup(FsContext *ctx) g_free(data); } -static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse) +static void error_append_security_model_hint(Error **errp) +{ + error_append_hint(errp, "Valid options are: security_model=" + "[passthrough|mapped-xattr|mapped-file|none]\n"); +} + +static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) { const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); - Error *err = NULL; + Error *local_err = NULL; if (!sec_model) { - error_report("Security model not specified, local fs needs security model"); - error_printf("valid options are:" - "\tsecurity_model=[passthrough|mapped-xattr|mapped-file|none]\n"); + error_setg(errp, "security_model property not set"); + error_append_security_model_hint(errp); return -1; } @@ -1482,20 +1487,20 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse) } else if (!strcmp(sec_model, "mapped-file")) { fse->export_flags |= V9FS_SM_MAPPED_FILE; } else { - error_report("Invalid security model %s specified", sec_model); - error_printf("valid options are:" - "\t[passthrough|mapped-xattr|mapped-file|none]\n"); + error_setg(errp, "invalid security_model property '%s'", sec_model); + error_append_security_model_hint(errp); return -1; } if (!path) { - error_report("fsdev: No path specified"); + error_setg(errp, "path property not set"); return -1; } - fsdev_throttle_parse_opts(opts, &fse->fst, &err); - if (err) { - error_reportf_err(err, "Throttle configuration is not valid: "); + fsdev_throttle_parse_opts(opts, &fse->fst, &local_err); + if (local_err) { + error_propagate(errp, local_err); + error_prepend(errp, "invalid throttle configuration: "); return -1; } @@ -1507,11 +1512,11 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse) qemu_opt_get_number(opts, "dmode", SM_LOCAL_DIR_MODE_BITS) & 0777; } else { if (qemu_opt_find(opts, "fmode")) { - error_report("fmode is only valid for mapped 9p modes"); + error_setg(errp, "fmode is only valid for mapped security modes"); return -1; } if (qemu_opt_find(opts, "dmode")) { - error_report("dmode is only valid for mapped 9p modes"); + error_setg(errp, "dmode is only valid for mapped security modes"); return -1; } } diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index 652940726e..f6fb7a408f 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -1111,17 +1111,27 @@ static int connect_namedsocket(const char *path) return sockfd; } -static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs) +static void error_append_socket_sockfd_hint(Error **errp) +{ + error_append_hint(errp, "Either specify socket=/some/path where /some/path" + " points to a listening AF_UNIX socket or sock_fd=fd" + " where fd is a file descriptor to a connected AF_UNIX" + " socket\n"); +} + +static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp) { const char *socket = qemu_opt_get(opts, "socket"); const char *sock_fd = qemu_opt_get(opts, "sock_fd"); if (!socket && !sock_fd) { - error_report("Must specify either socket or sock_fd"); + error_setg(errp, "both socket and sock_fd properties are missing"); + error_append_socket_sockfd_hint(errp); return -1; } if (socket && sock_fd) { - error_report("Both socket and sock_fd options specified"); + error_setg(errp, "both socket and sock_fd properties are set"); + error_append_socket_sockfd_hint(errp); return -1; } if (socket) { From 65603a801e14a89701b359cd12d7c5b1764e6de1 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 468/546] fsdev: improve error handling of backend init This patch changes some error messages in the backend init code and convert backends to propagate QEMU Error objects instead of calling error_report(). One notable improvement is that the local backend now provides a more detailed error report when it fails to open the shared directory. Signed-off-by: Greg Kurz --- fsdev/file-op-9p.h | 2 +- hw/9pfs/9p-handle.c | 2 +- hw/9pfs/9p-local.c | 3 ++- hw/9pfs/9p-proxy.c | 14 +++++++------- hw/9pfs/9p-synth.c | 2 +- hw/9pfs/9p.c | 6 +++--- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index b6d4eaffe3..3fa062b39f 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -104,7 +104,7 @@ void cred_init(FsCred *); struct FileOperations { int (*parse_opts)(QemuOpts *, FsDriverEntry *, Error **errp); - int (*init)(FsContext *); + int (*init)(FsContext *, Error **errp); void (*cleanup)(FsContext *); int (*lstat)(FsContext *, V9fsPath *, struct stat *); ssize_t (*readlink)(FsContext *, V9fsPath *, char *, size_t); diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index e50941075b..c5adfe6f3a 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -604,7 +604,7 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path, #endif } -static int handle_init(FsContext *ctx) +static int handle_init(FsContext *ctx, Error **errp) { int ret, mnt_id; struct statfs stbuf; diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index e1a4b844a5..b25c185ff0 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1400,13 +1400,14 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, #endif } -static int local_init(FsContext *ctx) +static int local_init(FsContext *ctx, Error **errp) { struct statfs stbuf; LocalData *data = g_malloc(sizeof(*data)); data->mountfd = open(ctx->fs_root, O_DIRECTORY | O_RDONLY); if (data->mountfd == -1) { + error_setg_errno(errp, errno, "failed to open '%s'", ctx->fs_root); goto err; } diff --git a/hw/9pfs/9p-proxy.c b/hw/9pfs/9p-proxy.c index f6fb7a408f..f030c6a428 100644 --- a/hw/9pfs/9p-proxy.c +++ b/hw/9pfs/9p-proxy.c @@ -1083,25 +1083,25 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path, return err; } -static int connect_namedsocket(const char *path) +static int connect_namedsocket(const char *path, Error **errp) { int sockfd, size; struct sockaddr_un helper; if (strlen(path) >= sizeof(helper.sun_path)) { - error_report("Socket name too long"); + error_setg(errp, "socket name too long"); return -1; } sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { - error_report("Failed to create socket: %s", strerror(errno)); + error_setg_errno(errp, errno, "failed to create client socket"); return -1; } strcpy(helper.sun_path, path); helper.sun_family = AF_UNIX; size = strlen(helper.sun_path) + sizeof(helper.sun_family); if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) { - error_report("Failed to connect to %s: %s", path, strerror(errno)); + error_setg_errno(errp, errno, "failed to connect to '%s'", path); close(sockfd); return -1; } @@ -1144,17 +1144,17 @@ static int proxy_parse_opts(QemuOpts *opts, FsDriverEntry *fs, Error **errp) return 0; } -static int proxy_init(FsContext *ctx) +static int proxy_init(FsContext *ctx, Error **errp) { V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy)); int sock_id; if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) { - sock_id = connect_namedsocket(ctx->fs_root); + sock_id = connect_namedsocket(ctx->fs_root, errp); } else { sock_id = atoi(ctx->fs_root); if (sock_id < 0) { - error_report("Socket descriptor not initialized"); + error_setg(errp, "socket descriptor not initialized"); } } if (sock_id < 0) { diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index df0a8de08a..8f255e91c0 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -514,7 +514,7 @@ static int synth_unlinkat(FsContext *ctx, V9fsPath *dir, return -1; } -static int synth_init(FsContext *ctx) +static int synth_init(FsContext *ctx, Error **errp) { QLIST_INIT(&synth_root.child); qemu_mutex_init(&synth_mutex); diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 1e4ebbe576..909a611394 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -3542,9 +3542,9 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp) s->fid_list = NULL; qemu_co_rwlock_init(&s->rename_lock); - if (s->ops->init(&s->ctx) < 0) { - error_setg(errp, "9pfs Failed to initialize fs-driver with id:%s" - " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root); + if (s->ops->init(&s->ctx, errp) < 0) { + error_prepend(errp, "cannot initialize fsdev '%s': ", + s->fsconf.fsdev_id); goto out; } From db3b3c7281ca82e2647e072a1f97db111313dd73 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 469/546] 9pfs: deprecate handle backend This backend raise some concerns: - doesn't support symlinks - fails +100 tests in the PJD POSIX file system test suite [1] - requires the QEMU process to run with the CAP_DAC_READ_SEARCH capability, which isn't recommended for security reasons This backend should not be used and wil be removed. The 'local' backend is the recommended alternative. [1] https://www.tuxera.com/community/posix-test-suite/ Signed-off-by: Greg Kurz Reviewed-by: Daniel P. Berrange Reviewed-by: Aneesh Kumar K.V --- hw/9pfs/9p-handle.c | 2 ++ qemu-doc.texi | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/hw/9pfs/9p-handle.c b/hw/9pfs/9p-handle.c index c5adfe6f3a..c1681d3c8a 100644 --- a/hw/9pfs/9p-handle.c +++ b/hw/9pfs/9p-handle.c @@ -657,6 +657,8 @@ static int handle_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) const char *sec_model = qemu_opt_get(opts, "security_model"); const char *path = qemu_opt_get(opts, "path"); + warn_report("handle backend is deprecated"); + if (sec_model) { error_report("Invalid argument security_model specified with handle fsdriver"); return -1; diff --git a/qemu-doc.texi b/qemu-doc.texi index ae90f7199e..454a8313d0 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2724,6 +2724,14 @@ default channel subsystem image for guests that do not support multiple channel subsystems, all devices can be put into the default channel subsystem image. +@subsection -fsdev handle (since 2.12.0) + +The ``handle'' fsdev backend does not support symlinks and causes the 9p +filesystem in the guest to fail a fair amount of tests from the PJD POSIX +filesystem test suite. Also it requires the CAP_DAC_READ_SEARCH capability, +which is not the recommended way to run QEMU. This backend should not be +used and it will be removed with no replacement. + @section qemu-img command line arguments @subsection convert -s (since 2.0.0) From ffcfb446db1776198a3fe02b75bfecfa1d0b7ab3 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 8 Jan 2018 11:18:23 +0100 Subject: [PATCH 470/546] MAINTAINERS: Drop Aneesh as 9pfs maintainer Aneesh has been working on other topics for some time now. Let's reflect that in the MAINTAINERS file, so that people stop Cc'ing him. Signed-off-by: Greg Kurz Acked-by: Aneesh Kumar K.V --- MAINTAINERS | 2 -- 1 file changed, 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 73a5555735..bc2d3a4ef1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1083,13 +1083,11 @@ F: include/hw/virtio/ F: tests/virtio-balloon-test.c virtio-9p -M: Aneesh Kumar K.V M: Greg Kurz S: Supported F: hw/9pfs/ F: fsdev/ F: tests/virtio-9p-test.c -T: git git://github.com/kvaneesh/QEMU.git T: git git://github.com/gkurz/qemu.git 9p-next virtio-blk From 418638d3e448e0ed79d55cc43a26f7a65c22007f Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Nov 2017 21:09:11 -0600 Subject: [PATCH 471/546] nbd/server: Implement sparse reads atop structured reply The reason that NBD added structured reply in the first place was to allow for efficient reads of sparse files, by allowing the reply to include chunks to quickly communicate holes to the client without sending lots of zeroes over the wire. Time to implement this in the server; our client can already read such data. We can only skip holes insofar as the block layer can query them; and only if the client is okay with a fragmented request (if a client requests NBD_CMD_FLAG_DF and the entire read is a hole, we could technically return a single NBD_REPLY_TYPE_OFFSET_HOLE, but that's a fringe case not worth catering to here). Sadly, the control flow is a bit wonkier than I would have preferred, but it was minimally invasive to have a split in the action between a fragmented read (handled directly where we recognize NBD_CMD_READ with the right conditions, and sending multiple chunks) vs. a single read (handled at the end of nbd_trip, for both simple and structured replies, when we know there is only one thing being read). Likewise, I didn't make any effort to optimize the final chunk of a fragmented read to set the NBD_REPLY_FLAG_DONE, but unconditionally send that as a separate NBD_REPLY_TYPE_NONE. Signed-off-by: Eric Blake Message-Id: <20171107030912.23930-2-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-- nbd/trace-events | 1 + 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index 92c0fdd03b..be7310cb41 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1303,6 +1303,7 @@ static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, uint64_t offset, void *data, size_t size, + bool final, Error **errp) { NBDStructuredReadData chunk; @@ -1313,13 +1314,73 @@ static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, assert(size); trace_nbd_co_send_structured_read(handle, offset, data, size); - set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_OFFSET_DATA, - handle, sizeof(chunk) - sizeof(chunk.h) + size); + set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0, + NBD_REPLY_TYPE_OFFSET_DATA, handle, + sizeof(chunk) - sizeof(chunk.h) + size); stq_be_p(&chunk.offset, offset); return nbd_co_send_iov(client, iov, 2, errp); } +static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, + uint64_t handle, + uint64_t offset, + uint8_t *data, + size_t size, + Error **errp) +{ + int ret = 0; + NBDExport *exp = client->exp; + size_t progress = 0; + + while (progress < size) { + int64_t pnum; + int status = bdrv_block_status_above(blk_bs(exp->blk), NULL, + offset + progress, + size - progress, &pnum, NULL, + NULL); + + if (status < 0) { + error_setg_errno(errp, -status, "unable to check for holes"); + return status; + } + assert(pnum && pnum <= size - progress); + if (status & BDRV_BLOCK_ZERO) { + NBDStructuredReadHole chunk; + struct iovec iov[] = { + {.iov_base = &chunk, .iov_len = sizeof(chunk)}, + }; + + trace_nbd_co_send_structured_read_hole(handle, offset + progress, + pnum); + set_be_chunk(&chunk.h, 0, NBD_REPLY_TYPE_OFFSET_HOLE, + handle, sizeof(chunk) - sizeof(chunk.h)); + stq_be_p(&chunk.offset, offset + progress); + stl_be_p(&chunk.length, pnum); + ret = nbd_co_send_iov(client, iov, 1, errp); + } else { + ret = blk_pread(exp->blk, offset + progress + exp->dev_offset, + data + progress, pnum); + if (ret < 0) { + error_setg_errno(errp, -ret, "reading from file failed"); + break; + } + ret = nbd_co_send_structured_read(client, handle, offset + progress, + data + progress, pnum, false, + errp); + } + + if (ret < 0) { + break; + } + progress += pnum; + } + if (!ret) { + ret = nbd_co_send_structured_done(client, handle, errp); + } + return ret; +} + static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, uint64_t handle, uint32_t error, @@ -1481,6 +1542,16 @@ static coroutine_fn void nbd_trip(void *opaque) } } + if (client->structured_reply && !(request.flags & NBD_CMD_FLAG_DF)) { + ret = nbd_co_send_sparse_read(req->client, request.handle, + request.from, req->data, request.len, + &local_err); + if (ret < 0) { + goto reply; + } + goto done; + } + ret = blk_pread(exp->blk, request.from + exp->dev_offset, req->data, request.len); if (ret < 0) { @@ -1561,7 +1632,8 @@ reply: } else if (reply_data_len) { ret = nbd_co_send_structured_read(req->client, request.handle, request.from, req->data, - reply_data_len, &local_err); + reply_data_len, true, + &local_err); } else { ret = nbd_co_send_structured_done(req->client, request.handle, &local_err); diff --git a/nbd/trace-events b/nbd/trace-events index 92568edce5..2b8268ce8c 100644 --- a/nbd/trace-events +++ b/nbd/trace-events @@ -57,6 +57,7 @@ nbd_blk_aio_detach(const char *name, void *ctx) "Export %s: Detaching clients fr nbd_co_send_simple_reply(uint64_t handle, uint32_t error, const char *errname, int len) "Send simple reply: handle = %" PRIu64 ", error = %" PRIu32 " (%s), len = %d" nbd_co_send_structured_done(uint64_t handle) "Send structured reply done: handle = %" PRIu64 nbd_co_send_structured_read(uint64_t handle, uint64_t offset, void *data, size_t size) "Send structured read data reply: handle = %" PRIu64 ", offset = %" PRIu64 ", data = %p, len = %zu" +nbd_co_send_structured_read_hole(uint64_t handle, uint64_t offset, size_t size) "Send structured read hole reply: handle = %" PRIu64 ", offset = %" PRIu64 ", len = %zu" nbd_co_send_structured_error(uint64_t handle, int err, const char *errname, const char *msg) "Send structured error reply: handle = %" PRIu64 ", error = %d (%s), msg = '%s'" nbd_co_receive_request_decode_type(uint64_t handle, uint16_t type, const char *name) "Decoding type: handle = %" PRIu64 ", type = %" PRIu16 " (%s)" nbd_co_receive_request_payload_received(uint64_t handle, uint32_t len) "Payload received: handle = %" PRIu64 ", len = %" PRIu32 From e2de3256c373fe32c7a7d9ef2f2093c643bb6656 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 6 Nov 2017 21:09:12 -0600 Subject: [PATCH 472/546] nbd/server: Optimize final chunk of sparse read If we are careful to handle 0-length read requests correctly, we can optimize our sparse read to send the NBD_REPLY_FLAG_DONE bit on our last OFFSET_DATA or OFFSET_HOLE chunk rather than needing a separate chunk. Signed-off-by: Eric Blake Message-Id: <20171107030912.23930-3-eblake@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy --- nbd/server.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nbd/server.c b/nbd/server.c index be7310cb41..e443b3cf5c 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1339,12 +1339,14 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, offset + progress, size - progress, &pnum, NULL, NULL); + bool final; if (status < 0) { error_setg_errno(errp, -status, "unable to check for holes"); return status; } assert(pnum && pnum <= size - progress); + final = progress + pnum == size; if (status & BDRV_BLOCK_ZERO) { NBDStructuredReadHole chunk; struct iovec iov[] = { @@ -1353,7 +1355,8 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, trace_nbd_co_send_structured_read_hole(handle, offset + progress, pnum); - set_be_chunk(&chunk.h, 0, NBD_REPLY_TYPE_OFFSET_HOLE, + set_be_chunk(&chunk.h, final ? NBD_REPLY_FLAG_DONE : 0, + NBD_REPLY_TYPE_OFFSET_HOLE, handle, sizeof(chunk) - sizeof(chunk.h)); stq_be_p(&chunk.offset, offset + progress); stl_be_p(&chunk.length, pnum); @@ -1366,7 +1369,7 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, break; } ret = nbd_co_send_structured_read(client, handle, offset + progress, - data + progress, pnum, false, + data + progress, pnum, final, errp); } @@ -1375,9 +1378,6 @@ static int coroutine_fn nbd_co_send_sparse_read(NBDClient *client, } progress += pnum; } - if (!ret) { - ret = nbd_co_send_structured_done(client, handle, errp); - } return ret; } @@ -1542,7 +1542,8 @@ static coroutine_fn void nbd_trip(void *opaque) } } - if (client->structured_reply && !(request.flags & NBD_CMD_FLAG_DF)) { + if (client->structured_reply && !(request.flags & NBD_CMD_FLAG_DF) && + request.len) { ret = nbd_co_send_sparse_read(req->client, request.handle, request.from, req->data, request.len, &local_err); From c4365735a7d38f4355c6f77e6670d3972315f7c2 Mon Sep 17 00:00:00 2001 From: Murilo Opsfelder Araujo Date: Fri, 5 Jan 2018 11:32:41 -0200 Subject: [PATCH 473/546] block/nbd: fix segmentation fault when .desc is not null-terminated The find_desc_by_name() from util/qemu-option.c relies on the .name not being NULL to call strcmp(). This check becomes unsafe when the list is not NULL-terminated, which is the case of nbd_runtime_opts in block/nbd.c, and can result in segmentation fault when strcmp() tries to access an invalid memory: #0 0x00007fff8c75f7d4 in __strcmp_power9 () from /lib64/libc.so.6 #1 0x00000000102d3ec8 in find_desc_by_name (desc=0x1036d6f0, name=0x28e46670 "server.path") at util/qemu-option.c:166 #2 0x00000000102d93e0 in qemu_opts_absorb_qdict (opts=0x28e47a80, qdict=0x28e469a0, errp=0x7fffec247c98) at util/qemu-option.c:1026 #3 0x000000001012a2e4 in nbd_open (bs=0x28e42290, options=0x28e469a0, flags=24578, errp=0x7fffec247d80) at block/nbd.c:406 #4 0x00000000100144e8 in bdrv_open_driver (bs=0x28e42290, drv=0x1036e070 , node_name=0x0, options=0x28e469a0, open_flags=24578, errp=0x7fffec247f50) at block.c:1135 #5 0x0000000010015b04 in bdrv_open_common (bs=0x28e42290, file=0x0, options=0x28e469a0, errp=0x7fffec247f50) at block.c:1395 >From gdb, the desc[i].name was not NULL and resulted in strcmp() accessing an invalid memory: >>> p desc[5] $8 = { name = 0x1037f098 "R27A", type = 1561964883, help = 0xc0bbb23e , def_value_str = 0x2 } >>> p desc[6] $9 = { name = 0x103dac78 <__gcov0.do_qemu_init_bdrv_nbd_init> "\001", type = 272101528, help = 0x29ec0b754403e31f , def_value_str = 0x81f343b9 } This patch fixes the segmentation fault in strcmp() by adding a NULL element at the end of nbd_runtime_opts.desc list, which is the common practice to most of other structs like runtime_opts in block/null.c. Thus, the desc[i].name != NULL check becomes safe because it will not evaluate to true when .desc list reached its end. Reported-by: R. Nageswara Sastry Buglink: https://bugs.launchpad.net/qemu/+bug/1727259 Signed-off-by: Murilo Opsfelder Araujo Message-Id: <20180105133241.14141-2-muriloo@linux.vnet.ibm.com> CC: qemu-stable@nongnu.org Fixes: 7ccc44fd7d1dfa62c4d6f3a680df809d6e7068ce Signed-off-by: Eric Blake --- block/nbd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/block/nbd.c b/block/nbd.c index a50d24b50a..8b8ba56cdd 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -388,6 +388,7 @@ static QemuOptsList nbd_runtime_opts = { .type = QEMU_OPT_STRING, .help = "ID of the TLS credentials to use", }, + { /* end of list */ } }, }; From d2d0852271ca2d0a4df4c31312289a816266a0aa Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 8 Jan 2018 17:10:42 +0000 Subject: [PATCH 474/546] configure: Fix incorrect string comparison operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit c97d6d2cdf97ed we accidentally added code to configure that uses '==' for string equality testing. This is a bashism -- the portable way to write this is '='. This fixes the "Unexpected operator error" complaint produced if the system /bin/sh is dash. Fixes: c97d6d2cdf97ed Reported-by: Philippe Mathieu-Daudé Signed-off-by: Peter Maydell Reviewed-by: Eric Blake Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-id: 1515431442-23795-1-git-send-email-peter.maydell@linaro.org --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 56f9716609..6a040821c6 100755 --- a/configure +++ b/configure @@ -5076,7 +5076,7 @@ fi ################################################# # Check to see if we have the Hypervisor framework -if [ "$darwin" == "yes" ] ; then +if [ "$darwin" = "yes" ] ; then cat > $TMPC << EOF #include int main() { return 0;} From 33071f6888913ef2c6600e827bf63bbb86e249a8 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 19:44:46 -0700 Subject: [PATCH 475/546] target/xtensa: use libisa for instruction decoding Replace manual opcode analysis with libisa-based code. This makes it possible to support variable-encoding instructions of the core ISA, like const16, and will allow to support advanced Xtensa features, like FLIX and TIE. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 3 + target/xtensa/helper.c | 37 + target/xtensa/translate.c | 2236 ++----------------------------------- 3 files changed, 128 insertions(+), 2148 deletions(-) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 9a34cc825e..e93bbb3c6d 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -392,6 +392,9 @@ struct XtensaConfig { uint32_t configid[2]; void *isa_internal; + xtensa_isa isa; + XtensaOpcodeOps **opcode_ops; + const XtensaOpcodeTranslators **opcode_translators; uint32_t clock_freq_khz; diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index 216f1988aa..5009fecedc 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -52,10 +52,47 @@ static void xtensa_core_class_init(ObjectClass *oc, void *data) cc->gdb_num_core_regs = config->gdb_regmap.num_regs; } +static void init_libisa(XtensaConfig *config) +{ + unsigned i, j; + unsigned opcodes; + + config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL); + assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH); + opcodes = xtensa_isa_num_opcodes(config->isa); + config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes); + + for (i = 0; i < opcodes; ++i) { + const char *opc_name = xtensa_opcode_name(config->isa, i); + XtensaOpcodeOps *ops = NULL; + + assert(xtensa_opcode_num_operands(config->isa, i) <= MAX_OPCODE_ARGS); + if (!config->opcode_translators) { + ops = xtensa_find_opcode_ops(&xtensa_core_opcodes, opc_name); + } else { + for (j = 0; !ops && config->opcode_translators[j]; ++j) { + ops = xtensa_find_opcode_ops(config->opcode_translators[j], + opc_name); + } + } +#ifdef DEBUG + if (ops == NULL) { + fprintf(stderr, + "opcode translator not found for %s's opcode '%s'\n", + config->name, opc_name); + } +#endif + config->opcode_ops[i] = ops; + } +} + void xtensa_finalize_config(XtensaConfig *config) { unsigned i, n = 0; + if (config->isa_internal) { + init_libisa(config); + } if (config->gdb_regmap.num_regs) { return; } diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index f6a53cdfc2..cf204fcb60 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -77,6 +77,8 @@ typedef struct DisasContext { unsigned cpenable; uint32_t *raw_arg; + xtensa_insnbuf insnbuf; + xtensa_insnbuf slotbuf; } DisasContext; static TCGv_i32 cpu_pc; @@ -254,11 +256,6 @@ void xtensa_translate_init(void) } } -static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt) -{ - return xtensa_option_bits_enabled(dc->config, opt); -} - static inline bool option_enabled(DisasContext *dc, int opt) { return xtensa_option_enabled(dc->config, opt); @@ -471,21 +468,21 @@ static void gen_jumpi_check_loop_end(DisasContext *dc, int slot) } static void gen_brcond(DisasContext *dc, TCGCond cond, - TCGv_i32 t0, TCGv_i32 t1, uint32_t offset) + TCGv_i32 t0, TCGv_i32 t1, uint32_t addr) { TCGLabel *label = gen_new_label(); tcg_gen_brcond_i32(cond, t0, t1, label); gen_jumpi_check_loop_end(dc, 0); gen_set_label(label); - gen_jumpi(dc, dc->pc + offset, 1); + gen_jumpi(dc, addr, 1); } static void gen_brcondi(DisasContext *dc, TCGCond cond, - TCGv_i32 t0, uint32_t t1, uint32_t offset) + TCGv_i32 t0, uint32_t t1, uint32_t addr) { TCGv_i32 tmp = tcg_const_i32(t1); - gen_brcond(dc, cond, t0, tmp, offset); + gen_brcond(dc, cond, t0, tmp, addr); tcg_temp_free(tmp); } @@ -947,2164 +944,98 @@ static TCGv_i32 gen_mac16_m(TCGv_i32 v, bool hi, bool is_unsigned) return m; } -static inline unsigned xtensa_op0_insn_len(unsigned op0) +static inline unsigned xtensa_op0_insn_len(DisasContext *dc, uint8_t op0) { - return op0 >= 8 ? 2 : 3; + return xtensa_isa_length_from_chars(dc->config->isa, &op0); } static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) { -#define HAS_OPTION_BITS(opt) do { \ - if (!option_bits_enabled(dc, opt)) { \ - qemu_log_mask(LOG_GUEST_ERROR, "Option is not enabled %s:%d\n", \ - __FILE__, __LINE__); \ - goto invalid_opcode; \ - } \ - } while (0) + xtensa_isa isa = dc->config->isa; + unsigned char b[MAX_INSN_LENGTH] = {cpu_ldub_code(env, dc->pc)}; + unsigned len = xtensa_op0_insn_len(dc, b[0]); + xtensa_format fmt; + unsigned slot, slots; + unsigned i; -#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt)) - -#define TBD() qemu_log_mask(LOG_UNIMP, "TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__) -#define RESERVED() do { \ - qemu_log_mask(LOG_GUEST_ERROR, "RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \ - dc->pc, b0, b1, b2, __FILE__, __LINE__); \ - goto invalid_opcode; \ - } while (0) - - -#ifdef TARGET_WORDS_BIGENDIAN -#define OP0 (((b0) & 0xf0) >> 4) -#define OP1 (((b2) & 0xf0) >> 4) -#define OP2 ((b2) & 0xf) -#define RRR_R ((b1) & 0xf) -#define RRR_S (((b1) & 0xf0) >> 4) -#define RRR_T ((b0) & 0xf) -#else -#define OP0 (((b0) & 0xf)) -#define OP1 (((b2) & 0xf)) -#define OP2 (((b2) & 0xf0) >> 4) -#define RRR_R (((b1) & 0xf0) >> 4) -#define RRR_S (((b1) & 0xf)) -#define RRR_T (((b0) & 0xf0) >> 4) -#endif -#define RRR_X ((RRR_R & 0x4) >> 2) -#define RRR_Y ((RRR_T & 0x4) >> 2) -#define RRR_W (RRR_R & 0x3) - -#define RRRN_R RRR_R -#define RRRN_S RRR_S -#define RRRN_T RRR_T - -#define RRI4_R RRR_R -#define RRI4_S RRR_S -#define RRI4_T RRR_T -#ifdef TARGET_WORDS_BIGENDIAN -#define RRI4_IMM4 ((b2) & 0xf) -#else -#define RRI4_IMM4 (((b2) & 0xf0) >> 4) -#endif - -#define RRI8_R RRR_R -#define RRI8_S RRR_S -#define RRI8_T RRR_T -#define RRI8_IMM8 (b2) -#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8) - -#ifdef TARGET_WORDS_BIGENDIAN -#define RI16_IMM16 (((b1) << 8) | (b2)) -#else -#define RI16_IMM16 (((b2) << 8) | (b1)) -#endif - -#ifdef TARGET_WORDS_BIGENDIAN -#define CALL_N (((b0) & 0xc) >> 2) -#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2)) -#else -#define CALL_N (((b0) & 0x30) >> 4) -#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10)) -#endif -#define CALL_OFFSET_SE \ - (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET) - -#define CALLX_N CALL_N -#ifdef TARGET_WORDS_BIGENDIAN -#define CALLX_M ((b0) & 0x3) -#else -#define CALLX_M (((b0) & 0xc0) >> 6) -#endif -#define CALLX_S RRR_S - -#define BRI12_M CALLX_M -#define BRI12_S RRR_S -#ifdef TARGET_WORDS_BIGENDIAN -#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2)) -#else -#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4)) -#endif -#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12) - -#define BRI8_M BRI12_M -#define BRI8_R RRI8_R -#define BRI8_S RRI8_S -#define BRI8_IMM8 RRI8_IMM8 -#define BRI8_IMM8_SE RRI8_IMM8_SE - -#define RSR_SR (b1) - - uint8_t b0 = cpu_ldub_code(env, dc->pc); - uint8_t b1 = cpu_ldub_code(env, dc->pc + 1); - uint8_t b2 = 0; - unsigned len = xtensa_op0_insn_len(OP0); - - static const uint32_t B4CONST[] = { - 0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 - }; - - static const uint32_t B4CONSTU[] = { - 32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 - }; - - switch (len) { - case 2: - HAS_OPTION(XTENSA_OPTION_CODE_DENSITY); - break; - - case 3: - b2 = cpu_ldub_code(env, dc->pc + 2); - break; - - default: - RESERVED(); + if (len == XTENSA_UNDEFINED) { + qemu_log_mask(LOG_GUEST_ERROR, + "unknown instruction length (pc = %08x)\n", + dc->pc); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return; } + dc->next_pc = dc->pc + len; - - switch (OP0) { - case 0: /*QRST*/ - switch (OP1) { - case 0: /*RST0*/ - switch (OP2) { - case 0: /*ST0*/ - if ((RRR_R & 0xc) == 0x8) { - HAS_OPTION(XTENSA_OPTION_BOOLEAN); - } - - switch (RRR_R) { - case 0: /*SNM0*/ - switch (CALLX_M) { - case 0: /*ILL*/ - gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); - break; - - case 1: /*reserved*/ - RESERVED(); - break; - - case 2: /*JR*/ - switch (CALLX_N) { - case 0: /*RET*/ - case 2: /*JX*/ - if (gen_window_check1(dc, CALLX_S)) { - gen_jump(dc, cpu_R[CALLX_S]); - } - break; - - case 1: /*RETWw*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - { - TCGv_i32 tmp = tcg_const_i32(dc->pc); - gen_helper_retw(tmp, cpu_env, tmp); - gen_jump(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 3: /*reserved*/ - RESERVED(); - break; - } - break; - - case 3: /*CALLX*/ - if (!gen_window_check2(dc, CALLX_S, CALLX_N << 2)) { - break; - } - switch (CALLX_N) { - case 0: /*CALLX0*/ - { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); - tcg_gen_movi_i32(cpu_R[0], dc->next_pc); - gen_jump(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 1: /*CALLX4w*/ - case 2: /*CALLX8w*/ - case 3: /*CALLX12w*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - { - TCGv_i32 tmp = tcg_temp_new_i32(); - - tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); - gen_callw(dc, CALLX_N, tmp); - tcg_temp_free(tmp); - } - break; - } - break; - } - break; - - case 1: /*MOVSPw*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_window_check2(dc, RRR_T, RRR_S)) { - TCGv_i32 pc = tcg_const_i32(dc->pc); - gen_helper_movsp(cpu_env, pc); - tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); - tcg_temp_free(pc); - } - break; - - case 2: /*SYNC*/ - switch (RRR_T) { - case 0: /*ISYNC*/ - break; - - case 1: /*RSYNC*/ - break; - - case 2: /*ESYNC*/ - break; - - case 3: /*DSYNC*/ - break; - - case 8: /*EXCW*/ - HAS_OPTION(XTENSA_OPTION_EXCEPTION); - break; - - case 12: /*MEMW*/ - break; - - case 13: /*EXTW*/ - break; - - case 15: /*NOP*/ - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 3: /*RFEIx*/ - switch (RRR_T) { - case 0: /*RFETx*/ - HAS_OPTION(XTENSA_OPTION_EXCEPTION); - switch (RRR_S) { - case 0: /*RFEx*/ - if (gen_check_privilege(dc)) { - tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); - gen_check_interrupts(dc); - gen_jump(dc, cpu_SR[EPC1]); - } - break; - - case 1: /*RFUEx*/ - RESERVED(); - break; - - case 2: /*RFDEx*/ - if (gen_check_privilege(dc)) { - gen_jump(dc, cpu_SR[ - dc->config->ndepc ? DEPC : EPC1]); - } - break; - - case 4: /*RFWOw*/ - case 5: /*RFWUw*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc)) { - TCGv_i32 tmp = tcg_const_i32(1); - - tcg_gen_andi_i32( - cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); - tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]); - - if (RRR_S == 4) { - tcg_gen_andc_i32(cpu_SR[WINDOW_START], - cpu_SR[WINDOW_START], tmp); - } else { - tcg_gen_or_i32(cpu_SR[WINDOW_START], - cpu_SR[WINDOW_START], tmp); - } - - gen_helper_restore_owb(cpu_env); - gen_check_interrupts(dc); - gen_jump(dc, cpu_SR[EPC1]); - - tcg_temp_free(tmp); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 1: /*RFIx*/ - HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT); - if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) { - if (gen_check_privilege(dc)) { - tcg_gen_mov_i32(cpu_SR[PS], - cpu_SR[EPS2 + RRR_S - 2]); - gen_check_interrupts(dc); - gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]); - } - } else { - qemu_log_mask(LOG_GUEST_ERROR, "RFI %d is illegal\n", RRR_S); - gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); - } - break; - - case 2: /*RFME*/ - TBD(); - break; - - default: /*reserved*/ - RESERVED(); - break; - - } - break; - - case 4: /*BREAKx*/ - HAS_OPTION(XTENSA_OPTION_DEBUG); - if (dc->debug) { - gen_debug_exception(dc, DEBUGCAUSE_BI); - } - break; - - case 5: /*SYSCALLx*/ - HAS_OPTION(XTENSA_OPTION_EXCEPTION); - switch (RRR_S) { - case 0: /*SYSCALLx*/ - gen_exception_cause(dc, SYSCALL_CAUSE); - break; - - case 1: /*SIMCALL*/ - if (semihosting_enabled()) { - if (gen_check_privilege(dc)) { - gen_helper_simcall(cpu_env); - } - } else { - qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); - gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); - } - break; - - default: - RESERVED(); - break; - } - break; - - case 6: /*RSILx*/ - HAS_OPTION(XTENSA_OPTION_INTERRUPT); - if (gen_check_privilege(dc) && - gen_window_check1(dc, RRR_T)) { - tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); - tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); - tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); - gen_check_interrupts(dc); - gen_jumpi_check_loop_end(dc, 0); - } - break; - - case 7: /*WAITIx*/ - HAS_OPTION(XTENSA_OPTION_INTERRUPT); - if (gen_check_privilege(dc)) { - gen_waiti(dc, RRR_S); - } - break; - - case 8: /*ANY4p*/ - case 9: /*ALL4p*/ - case 10: /*ANY8p*/ - case 11: /*ALL8p*/ - HAS_OPTION(XTENSA_OPTION_BOOLEAN); - { - const unsigned shift = (RRR_R & 2) ? 8 : 4; - TCGv_i32 mask = tcg_const_i32( - ((1 << shift) - 1) << RRR_S); - TCGv_i32 tmp = tcg_temp_new_i32(); - - tcg_gen_and_i32(tmp, cpu_SR[BR], mask); - if (RRR_R & 1) { /*ALL*/ - tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S); - } else { /*ANY*/ - tcg_gen_add_i32(tmp, tmp, mask); - } - tcg_gen_shri_i32(tmp, tmp, RRR_S + shift); - tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], - tmp, RRR_T, 1); - tcg_temp_free(mask); - tcg_temp_free(tmp); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - - } - break; - - case 1: /*AND*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 2: /*OR*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 3: /*XOR*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 4: /*ST1*/ - switch (RRR_R) { - case 0: /*SSR*/ - if (gen_window_check1(dc, RRR_S)) { - gen_right_shift_sar(dc, cpu_R[RRR_S]); - } - break; - - case 1: /*SSL*/ - if (gen_window_check1(dc, RRR_S)) { - gen_left_shift_sar(dc, cpu_R[RRR_S]); - } - break; - - case 2: /*SSA8L*/ - if (gen_window_check1(dc, RRR_S)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); - gen_right_shift_sar(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 3: /*SSA8B*/ - if (gen_window_check1(dc, RRR_S)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); - gen_left_shift_sar(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 4: /*SSAI*/ - { - TCGv_i32 tmp = tcg_const_i32( - RRR_S | ((RRR_T & 1) << 4)); - gen_right_shift_sar(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 6: /*RER*/ - HAS_OPTION(XTENSA_OPTION_EXTERN_REGS); - if (gen_check_privilege(dc) && - gen_window_check2(dc, RRR_S, RRR_T)) { - gen_helper_rer(cpu_R[RRR_T], cpu_env, cpu_R[RRR_S]); - } - break; - - case 7: /*WER*/ - HAS_OPTION(XTENSA_OPTION_EXTERN_REGS); - if (gen_check_privilege(dc) && - gen_window_check2(dc, RRR_S, RRR_T)) { - gen_helper_wer(cpu_env, cpu_R[RRR_T], cpu_R[RRR_S]); - } - break; - - case 8: /*ROTWw*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc)) { - TCGv_i32 tmp = tcg_const_i32( - RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); - gen_helper_rotw(cpu_env, tmp); - tcg_temp_free(tmp); - /* This can change tb->flags, so exit tb */ - gen_jumpi_check_loop_end(dc, -1); - } - break; - - case 14: /*NSAu*/ - HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA); - if (gen_window_check2(dc, RRR_S, RRR_T)) { - tcg_gen_clrsb_i32(cpu_R[RRR_T], cpu_R[RRR_S]); - } - break; - - case 15: /*NSAUu*/ - HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA); - if (gen_window_check2(dc, RRR_S, RRR_T)) { - tcg_gen_clzi_i32(cpu_R[RRR_T], cpu_R[RRR_S], 32); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 5: /*TLB*/ - HAS_OPTION_BITS( - XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) | - XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | - XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)); - if (gen_check_privilege(dc) && - gen_window_check2(dc, RRR_S, RRR_T)) { - TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0); - - switch (RRR_R & 7) { - case 3: /*RITLB0*/ /*RDTLB0*/ - gen_helper_rtlb0(cpu_R[RRR_T], - cpu_env, cpu_R[RRR_S], dtlb); - break; - - case 4: /*IITLB*/ /*IDTLB*/ - gen_helper_itlb(cpu_env, cpu_R[RRR_S], dtlb); - /* This could change memory mapping, so exit tb */ - gen_jumpi_check_loop_end(dc, -1); - break; - - case 5: /*PITLB*/ /*PDTLB*/ - tcg_gen_movi_i32(cpu_pc, dc->pc); - gen_helper_ptlb(cpu_R[RRR_T], - cpu_env, cpu_R[RRR_S], dtlb); - break; - - case 6: /*WITLB*/ /*WDTLB*/ - gen_helper_wtlb( - cpu_env, cpu_R[RRR_T], cpu_R[RRR_S], dtlb); - /* This could change memory mapping, so exit tb */ - gen_jumpi_check_loop_end(dc, -1); - break; - - case 7: /*RITLB1*/ /*RDTLB1*/ - gen_helper_rtlb1(cpu_R[RRR_T], - cpu_env, cpu_R[RRR_S], dtlb); - break; - - default: - tcg_temp_free(dtlb); - RESERVED(); - break; - } - tcg_temp_free(dtlb); - } - break; - - case 6: /*RT0*/ - if (!gen_window_check2(dc, RRR_R, RRR_T)) { - break; - } - switch (RRR_S) { - case 0: /*NEG*/ - tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); - break; - - case 1: /*ABS*/ - { - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 neg = tcg_temp_new_i32(); - - tcg_gen_neg_i32(neg, cpu_R[RRR_T]); - tcg_gen_movcond_i32(TCG_COND_GE, cpu_R[RRR_R], - cpu_R[RRR_T], zero, cpu_R[RRR_T], neg); - tcg_temp_free(neg); - tcg_temp_free(zero); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 7: /*reserved*/ - RESERVED(); - break; - - case 8: /*ADD*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 9: /*ADD**/ - case 10: - case 11: - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8); - tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); - tcg_temp_free(tmp); - } - break; - - case 12: /*SUB*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 13: /*SUB**/ - case 14: - case 15: - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12); - tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); - tcg_temp_free(tmp); - } - break; - } - break; - - case 1: /*RST1*/ - switch (OP2) { - case 0: /*SLLI*/ - case 1: - if (gen_window_check2(dc, RRR_R, RRR_S)) { - tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S], - 32 - (RRR_T | ((OP2 & 1) << 4))); - } - break; - - case 2: /*SRAI*/ - case 3: - if (gen_window_check2(dc, RRR_R, RRR_T)) { - tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T], - RRR_S | ((OP2 & 1) << 4)); - } - break; - - case 4: /*SRLI*/ - if (gen_window_check2(dc, RRR_R, RRR_T)) { - tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S); - } - break; - - case 6: /*XSR*/ - if (gen_check_sr(dc, RSR_SR, SR_X) && - (RSR_SR < 64 || gen_check_privilege(dc)) && - gen_window_check1(dc, RRR_T)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - bool rsr_end, wsr_end; - - tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); - rsr_end = gen_rsr(dc, cpu_R[RRR_T], RSR_SR); - wsr_end = gen_wsr(dc, RSR_SR, tmp); - tcg_temp_free(tmp); - if (rsr_end && !wsr_end) { - gen_jumpi_check_loop_end(dc, 0); - } - } - break; - - /* - * Note: 64 bit ops are used here solely because SAR values - * have range 0..63 - */ -#define gen_shift_reg(cmd, reg) do { \ - TCGv_i64 tmp = tcg_temp_new_i64(); \ - tcg_gen_extu_i32_i64(tmp, reg); \ - tcg_gen_##cmd##_i64(v, v, tmp); \ - tcg_gen_extrl_i64_i32(cpu_R[RRR_R], v); \ - tcg_temp_free_i64(v); \ - tcg_temp_free_i64(tmp); \ - } while (0) - -#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) - - case 8: /*SRC*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]); - gen_shift(shr); - } - break; - - case 9: /*SRL*/ - if (!gen_window_check2(dc, RRR_R, RRR_T)) { - break; - } - if (dc->sar_5bit) { - tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); - } else { - TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]); - gen_shift(shr); - } - break; - - case 10: /*SLL*/ - if (!gen_window_check2(dc, RRR_R, RRR_S)) { - break; - } - if (dc->sar_m32_5bit) { - tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32); - } else { - TCGv_i64 v = tcg_temp_new_i64(); - TCGv_i32 s = tcg_const_i32(32); - tcg_gen_sub_i32(s, s, cpu_SR[SAR]); - tcg_gen_andi_i32(s, s, 0x3f); - tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]); - gen_shift_reg(shl, s); - tcg_temp_free(s); - } - break; - - case 11: /*SRA*/ - if (!gen_window_check2(dc, RRR_R, RRR_T)) { - break; - } - if (dc->sar_5bit) { - tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); - } else { - TCGv_i64 v = tcg_temp_new_i64(); - tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]); - gen_shift(sar); - } - break; -#undef gen_shift -#undef gen_shift_reg - - case 12: /*MUL16U*/ - HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - TCGv_i32 v1 = tcg_temp_new_i32(); - TCGv_i32 v2 = tcg_temp_new_i32(); - tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]); - tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]); - tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); - tcg_temp_free(v2); - tcg_temp_free(v1); - } - break; - - case 13: /*MUL16S*/ - HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - TCGv_i32 v1 = tcg_temp_new_i32(); - TCGv_i32 v2 = tcg_temp_new_i32(); - tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]); - tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]); - tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); - tcg_temp_free(v2); - tcg_temp_free(v1); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 2: /*RST2*/ - if (OP2 >= 8 && !gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - break; - } - - if (OP2 >= 12) { - HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV); - TCGLabel *label = gen_new_label(); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label); - gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE); - gen_set_label(label); - } - - switch (OP2) { -#define BOOLEAN_LOGIC(fn, r, s, t) \ - do { \ - HAS_OPTION(XTENSA_OPTION_BOOLEAN); \ - TCGv_i32 tmp1 = tcg_temp_new_i32(); \ - TCGv_i32 tmp2 = tcg_temp_new_i32(); \ - \ - tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \ - tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \ - tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \ - tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \ - tcg_temp_free(tmp1); \ - tcg_temp_free(tmp2); \ - } while (0) - - case 0: /*ANDBp*/ - BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T); - break; - - case 1: /*ANDBCp*/ - BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T); - break; - - case 2: /*ORBp*/ - BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T); - break; - - case 3: /*ORBCp*/ - BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T); - break; - - case 4: /*XORBp*/ - BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T); - break; - -#undef BOOLEAN_LOGIC - - case 8: /*MULLi*/ - HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL); - tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - break; - - case 10: /*MULUHi*/ - case 11: /*MULSHi*/ - HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH); - { - TCGv lo = tcg_temp_new(); - - if (OP2 == 10) { - tcg_gen_mulu2_i32(lo, cpu_R[RRR_R], - cpu_R[RRR_S], cpu_R[RRR_T]); - } else { - tcg_gen_muls2_i32(lo, cpu_R[RRR_R], - cpu_R[RRR_S], cpu_R[RRR_T]); - } - tcg_temp_free(lo); - } - break; - - case 12: /*QUOUi*/ - tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - break; - - case 13: /*QUOSi*/ - case 15: /*REMSi*/ - { - TCGLabel *label1 = gen_new_label(); - TCGLabel *label2 = gen_new_label(); - - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000, - label1); - tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff, - label1); - tcg_gen_movi_i32(cpu_R[RRR_R], - OP2 == 13 ? 0x80000000 : 0); - tcg_gen_br(label2); - gen_set_label(label1); - if (OP2 == 13) { - tcg_gen_div_i32(cpu_R[RRR_R], - cpu_R[RRR_S], cpu_R[RRR_T]); - } else { - tcg_gen_rem_i32(cpu_R[RRR_R], - cpu_R[RRR_S], cpu_R[RRR_T]); - } - gen_set_label(label2); - } - break; - - case 14: /*REMUi*/ - tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 3: /*RST3*/ - switch (OP2) { - case 0: /*RSR*/ - if (gen_check_sr(dc, RSR_SR, SR_R) && - (RSR_SR < 64 || gen_check_privilege(dc)) && - gen_window_check1(dc, RRR_T)) { - if (gen_rsr(dc, cpu_R[RRR_T], RSR_SR)) { - gen_jumpi_check_loop_end(dc, 0); - } - } - break; - - case 1: /*WSR*/ - if (gen_check_sr(dc, RSR_SR, SR_W) && - (RSR_SR < 64 || gen_check_privilege(dc)) && - gen_window_check1(dc, RRR_T)) { - gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); - } - break; - - case 2: /*SEXTu*/ - HAS_OPTION(XTENSA_OPTION_MISC_OP_SEXT); - if (gen_window_check2(dc, RRR_R, RRR_S)) { - int shift = 24 - RRR_T; - - if (shift == 24) { - tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - } else if (shift == 16) { - tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - } else { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift); - tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift); - tcg_temp_free(tmp); - } - } - break; - - case 3: /*CLAMPSu*/ - HAS_OPTION(XTENSA_OPTION_MISC_OP_CLAMPS); - if (gen_window_check2(dc, RRR_R, RRR_S)) { - TCGv_i32 tmp1 = tcg_temp_new_i32(); - TCGv_i32 tmp2 = tcg_temp_new_i32(); - TCGv_i32 zero = tcg_const_i32(0); - - tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T); - tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]); - tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7)); - - tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31); - tcg_gen_xori_i32(tmp1, tmp1, 0xffffffff >> (25 - RRR_T)); - - tcg_gen_movcond_i32(TCG_COND_EQ, cpu_R[RRR_R], tmp2, zero, - cpu_R[RRR_S], tmp1); - tcg_temp_free(tmp1); - tcg_temp_free(tmp2); - tcg_temp_free(zero); - } - break; - - case 4: /*MINu*/ - case 5: /*MAXu*/ - case 6: /*MINUu*/ - case 7: /*MAXUu*/ - HAS_OPTION(XTENSA_OPTION_MISC_OP_MINMAX); - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - static const TCGCond cond[] = { - TCG_COND_LE, - TCG_COND_GE, - TCG_COND_LEU, - TCG_COND_GEU - }; - tcg_gen_movcond_i32(cond[OP2 - 4], cpu_R[RRR_R], - cpu_R[RRR_S], cpu_R[RRR_T], - cpu_R[RRR_S], cpu_R[RRR_T]); - } - break; - - case 8: /*MOVEQZ*/ - case 9: /*MOVNEZ*/ - case 10: /*MOVLTZ*/ - case 11: /*MOVGEZ*/ - if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { - static const TCGCond cond[] = { - TCG_COND_EQ, - TCG_COND_NE, - TCG_COND_LT, - TCG_COND_GE, - }; - TCGv_i32 zero = tcg_const_i32(0); - - tcg_gen_movcond_i32(cond[OP2 - 8], cpu_R[RRR_R], - cpu_R[RRR_T], zero, cpu_R[RRR_S], cpu_R[RRR_R]); - tcg_temp_free(zero); - } - break; - - case 12: /*MOVFp*/ - case 13: /*MOVTp*/ - HAS_OPTION(XTENSA_OPTION_BOOLEAN); - if (gen_window_check2(dc, RRR_R, RRR_S)) { - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 tmp = tcg_temp_new_i32(); - - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T); - tcg_gen_movcond_i32(OP2 & 1 ? TCG_COND_NE : TCG_COND_EQ, - cpu_R[RRR_R], tmp, zero, - cpu_R[RRR_S], cpu_R[RRR_R]); - - tcg_temp_free(tmp); - tcg_temp_free(zero); - } - break; - - case 14: /*RUR*/ - if (gen_window_check1(dc, RRR_R)) { - int st = (RRR_S << 4) + RRR_T; - if (uregnames[st].name) { - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]); - } else { - qemu_log_mask(LOG_UNIMP, "RUR %d not implemented, ", st); - TBD(); - } - } - break; - - case 15: /*WUR*/ - if (gen_window_check1(dc, RRR_T)) { - if (uregnames[RSR_SR].name) { - gen_wur(RSR_SR, cpu_R[RRR_T]); - } else { - qemu_log_mask(LOG_UNIMP, "WUR %d not implemented, ", RSR_SR); - TBD(); - } - } - break; - - } - break; - - case 4: /*EXTUI*/ - case 5: - if (gen_window_check2(dc, RRR_R, RRR_T)) { - int shiftimm = RRR_S | ((OP1 & 1) << 4); - int maskimm = (1 << (OP2 + 1)) - 1; - - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); - tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); - tcg_temp_free(tmp); - } - break; - - case 6: /*CUST0*/ - RESERVED(); - break; - - case 7: /*CUST1*/ - RESERVED(); - break; - - case 8: /*LSCXp*/ - switch (OP2) { - case 0: /*LSXf*/ - case 1: /*LSXUf*/ - case 4: /*SSXf*/ - case 5: /*SSXUf*/ - HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); - if (gen_window_check2(dc, RRR_S, RRR_T) && - gen_check_cpenable(dc, 0)) { - TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_add_i32(addr, cpu_R[RRR_S], cpu_R[RRR_T]); - gen_load_store_alignment(dc, 2, addr, false); - if (OP2 & 0x4) { - tcg_gen_qemu_st32(cpu_FR[RRR_R], addr, dc->cring); - } else { - tcg_gen_qemu_ld32u(cpu_FR[RRR_R], addr, dc->cring); - } - if (OP2 & 0x1) { - tcg_gen_mov_i32(cpu_R[RRR_S], addr); - } - tcg_temp_free(addr); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 9: /*LSC4*/ - if (!gen_window_check2(dc, RRR_S, RRR_T)) { - break; - } - switch (OP2) { - case 0: /*L32E*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc) && - gen_window_check2(dc, RRR_S, RRR_T)) { - TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[RRR_S], - (0xffffffc0 | (RRR_R << 2))); - tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring); - tcg_temp_free(addr); - } - break; - - case 4: /*S32E*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_check_privilege(dc) && - gen_window_check2(dc, RRR_S, RRR_T)) { - TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[RRR_S], - (0xffffffc0 | (RRR_R << 2))); - tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring); - tcg_temp_free(addr); - } - break; - - case 5: /*S32N*/ - if (gen_window_check2(dc, RRI4_S, RRI4_T)) { - TCGv_i32 addr = tcg_temp_new_i32(); - - tcg_gen_addi_i32(addr, cpu_R[RRI4_S], RRI4_IMM4 << 2); - gen_load_store_alignment(dc, 2, addr, false); - tcg_gen_qemu_st32(cpu_R[RRI4_T], addr, dc->cring); - tcg_temp_free(addr); - } - break; - - default: - RESERVED(); - break; - } - break; - - case 10: /*FP0*/ - /*DEPBITS*/ - if (option_enabled(dc, XTENSA_OPTION_DEPBITS)) { - if (!gen_window_check2(dc, RRR_S, RRR_T)) { - break; - } - tcg_gen_deposit_i32(cpu_R[RRR_T], cpu_R[RRR_T], cpu_R[RRR_S], - OP2, RRR_R + 1); - break; - } - - HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); - switch (OP2) { - case 0: /*ADD.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_add_s(cpu_FR[RRR_R], cpu_env, - cpu_FR[RRR_S], cpu_FR[RRR_T]); - } - break; - - case 1: /*SUB.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_sub_s(cpu_FR[RRR_R], cpu_env, - cpu_FR[RRR_S], cpu_FR[RRR_T]); - } - break; - - case 2: /*MUL.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_mul_s(cpu_FR[RRR_R], cpu_env, - cpu_FR[RRR_S], cpu_FR[RRR_T]); - } - break; - - case 4: /*MADD.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_madd_s(cpu_FR[RRR_R], cpu_env, - cpu_FR[RRR_R], cpu_FR[RRR_S], - cpu_FR[RRR_T]); - } - break; - - case 5: /*MSUB.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_msub_s(cpu_FR[RRR_R], cpu_env, - cpu_FR[RRR_R], cpu_FR[RRR_S], - cpu_FR[RRR_T]); - } - break; - - case 8: /*ROUND.Sf*/ - case 9: /*TRUNC.Sf*/ - case 10: /*FLOOR.Sf*/ - case 11: /*CEIL.Sf*/ - case 14: /*UTRUNC.Sf*/ - if (gen_window_check1(dc, RRR_R) && - gen_check_cpenable(dc, 0)) { - static const unsigned rounding_mode_const[] = { - float_round_nearest_even, - float_round_to_zero, - float_round_down, - float_round_up, - [6] = float_round_to_zero, - }; - TCGv_i32 rounding_mode = tcg_const_i32( - rounding_mode_const[OP2 & 7]); - TCGv_i32 scale = tcg_const_i32(RRR_T); - - if (OP2 == 14) { - gen_helper_ftoui(cpu_R[RRR_R], cpu_FR[RRR_S], - rounding_mode, scale); - } else { - gen_helper_ftoi(cpu_R[RRR_R], cpu_FR[RRR_S], - rounding_mode, scale); - } - - tcg_temp_free(rounding_mode); - tcg_temp_free(scale); - } - break; - - case 12: /*FLOAT.Sf*/ - case 13: /*UFLOAT.Sf*/ - if (gen_window_check1(dc, RRR_S) && - gen_check_cpenable(dc, 0)) { - TCGv_i32 scale = tcg_const_i32(-RRR_T); - - if (OP2 == 13) { - gen_helper_uitof(cpu_FR[RRR_R], cpu_env, - cpu_R[RRR_S], scale); - } else { - gen_helper_itof(cpu_FR[RRR_R], cpu_env, - cpu_R[RRR_S], scale); - } - tcg_temp_free(scale); - } - break; - - case 15: /*FP1OP*/ - switch (RRR_T) { - case 0: /*MOV.Sf*/ - if (gen_check_cpenable(dc, 0)) { - tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_FR[RRR_S]); - } - break; - - case 1: /*ABS.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_abs_s(cpu_FR[RRR_R], cpu_FR[RRR_S]); - } - break; - - case 4: /*RFRf*/ - if (gen_window_check1(dc, RRR_R) && - gen_check_cpenable(dc, 0)) { - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_FR[RRR_S]); - } - break; - - case 5: /*WFRf*/ - if (gen_window_check1(dc, RRR_S) && - gen_check_cpenable(dc, 0)) { - tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_R[RRR_S]); - } - break; - - case 6: /*NEG.Sf*/ - if (gen_check_cpenable(dc, 0)) { - gen_helper_neg_s(cpu_FR[RRR_R], cpu_FR[RRR_S]); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 11: /*FP1*/ - /*DEPBITS*/ - if (option_enabled(dc, XTENSA_OPTION_DEPBITS)) { - if (!gen_window_check2(dc, RRR_S, RRR_T)) { - break; - } - tcg_gen_deposit_i32(cpu_R[RRR_T], cpu_R[RRR_T], cpu_R[RRR_S], - OP2 + 16, RRR_R + 1); - break; - } - - HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); - -#define gen_compare(rel, br, a, b) \ - do { \ - if (gen_check_cpenable(dc, 0)) { \ - TCGv_i32 bit = tcg_const_i32(1 << br); \ - \ - gen_helper_##rel(cpu_env, bit, cpu_FR[a], cpu_FR[b]); \ - tcg_temp_free(bit); \ - } \ - } while (0) - - switch (OP2) { - case 1: /*UN.Sf*/ - gen_compare(un_s, RRR_R, RRR_S, RRR_T); - break; - - case 2: /*OEQ.Sf*/ - gen_compare(oeq_s, RRR_R, RRR_S, RRR_T); - break; - - case 3: /*UEQ.Sf*/ - gen_compare(ueq_s, RRR_R, RRR_S, RRR_T); - break; - - case 4: /*OLT.Sf*/ - gen_compare(olt_s, RRR_R, RRR_S, RRR_T); - break; - - case 5: /*ULT.Sf*/ - gen_compare(ult_s, RRR_R, RRR_S, RRR_T); - break; - - case 6: /*OLE.Sf*/ - gen_compare(ole_s, RRR_R, RRR_S, RRR_T); - break; - - case 7: /*ULE.Sf*/ - gen_compare(ule_s, RRR_R, RRR_S, RRR_T); - break; - -#undef gen_compare - - case 8: /*MOVEQZ.Sf*/ - case 9: /*MOVNEZ.Sf*/ - case 10: /*MOVLTZ.Sf*/ - case 11: /*MOVGEZ.Sf*/ - if (gen_window_check1(dc, RRR_T) && - gen_check_cpenable(dc, 0)) { - static const TCGCond cond[] = { - TCG_COND_EQ, - TCG_COND_NE, - TCG_COND_LT, - TCG_COND_GE, - }; - TCGv_i32 zero = tcg_const_i32(0); - - tcg_gen_movcond_i32(cond[OP2 - 8], cpu_FR[RRR_R], - cpu_R[RRR_T], zero, cpu_FR[RRR_S], cpu_FR[RRR_R]); - tcg_temp_free(zero); - } - break; - - case 12: /*MOVF.Sf*/ - case 13: /*MOVT.Sf*/ - HAS_OPTION(XTENSA_OPTION_BOOLEAN); - if (gen_check_cpenable(dc, 0)) { - TCGv_i32 zero = tcg_const_i32(0); - TCGv_i32 tmp = tcg_temp_new_i32(); - - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T); - tcg_gen_movcond_i32(OP2 & 1 ? TCG_COND_NE : TCG_COND_EQ, - cpu_FR[RRR_R], tmp, zero, - cpu_FR[RRR_S], cpu_FR[RRR_R]); - - tcg_temp_free(tmp); - tcg_temp_free(zero); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 1: /*L32R*/ - if (gen_window_check1(dc, RRR_T)) { - TCGv_i32 tmp = tcg_const_i32( - ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? - 0 : ((dc->pc + 3) & ~3)) + - (0xfffc0000 | (RI16_IMM16 << 2))); - - if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { - tcg_gen_add_i32(tmp, tmp, dc->litbase); - } - tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring); - tcg_temp_free(tmp); - } - break; - - case 2: /*LSAI*/ -#define gen_load_store(type, shift) do { \ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { \ - TCGv_i32 addr = tcg_temp_new_i32(); \ - \ - tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \ - if (shift) { \ - gen_load_store_alignment(dc, shift, addr, false); \ - } \ - tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ - tcg_temp_free(addr); \ - } \ - } while (0) - - switch (RRI8_R) { - case 0: /*L8UI*/ - gen_load_store(ld8u, 0); - break; - - case 1: /*L16UI*/ - gen_load_store(ld16u, 1); - break; - - case 2: /*L32I*/ - gen_load_store(ld32u, 2); - break; - - case 4: /*S8I*/ - gen_load_store(st8, 0); - break; - - case 5: /*S16I*/ - gen_load_store(st16, 1); - break; - - case 6: /*S32I*/ - gen_load_store(st32, 2); - break; - -#define gen_dcache_hit_test(w, shift) do { \ - if (gen_window_check1(dc, RRI##w##_S)) { \ - TCGv_i32 addr = tcg_temp_new_i32(); \ - TCGv_i32 res = tcg_temp_new_i32(); \ - tcg_gen_addi_i32(addr, cpu_R[RRI##w##_S], \ - RRI##w##_IMM##w << shift); \ - tcg_gen_qemu_ld8u(res, addr, dc->cring); \ - tcg_temp_free(addr); \ - tcg_temp_free(res); \ - } \ - } while (0) - -#define gen_dcache_hit_test4() gen_dcache_hit_test(4, 4) -#define gen_dcache_hit_test8() gen_dcache_hit_test(8, 2) - - case 7: /*CACHEc*/ - if (RRI8_T < 8) { - HAS_OPTION(XTENSA_OPTION_DCACHE); - } - - switch (RRI8_T) { - case 0: /*DPFRc*/ - gen_window_check1(dc, RRI8_S); - break; - - case 1: /*DPFWc*/ - gen_window_check1(dc, RRI8_S); - break; - - case 2: /*DPFROc*/ - gen_window_check1(dc, RRI8_S); - break; - - case 3: /*DPFWOc*/ - gen_window_check1(dc, RRI8_S); - break; - - case 4: /*DHWBc*/ - gen_dcache_hit_test8(); - break; - - case 5: /*DHWBIc*/ - gen_dcache_hit_test8(); - break; - - case 6: /*DHIc*/ - if (gen_check_privilege(dc)) { - gen_dcache_hit_test8(); - } - break; - - case 7: /*DIIc*/ - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI8_S); - } - break; - - case 8: /*DCEc*/ - switch (OP1) { - case 0: /*DPFLl*/ - HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_dcache_hit_test4(); - } - break; - - case 2: /*DHUl*/ - HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_dcache_hit_test4(); - } - break; - - case 3: /*DIUl*/ - HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI4_S); - } - break; - - case 4: /*DIWBc*/ - HAS_OPTION(XTENSA_OPTION_DCACHE); - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI4_S); - } - break; - - case 5: /*DIWBIc*/ - HAS_OPTION(XTENSA_OPTION_DCACHE); - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI4_S); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - - } - break; - -#undef gen_dcache_hit_test -#undef gen_dcache_hit_test4 -#undef gen_dcache_hit_test8 - -#define gen_icache_hit_test(w, shift) do { \ - if (gen_window_check1(dc, RRI##w##_S)) { \ - TCGv_i32 addr = tcg_temp_new_i32(); \ - tcg_gen_movi_i32(cpu_pc, dc->pc); \ - tcg_gen_addi_i32(addr, cpu_R[RRI##w##_S], \ - RRI##w##_IMM##w << shift); \ - gen_helper_itlb_hit_test(cpu_env, addr); \ - tcg_temp_free(addr); \ - }\ - } while (0) - -#define gen_icache_hit_test4() gen_icache_hit_test(4, 4) -#define gen_icache_hit_test8() gen_icache_hit_test(8, 2) - - case 12: /*IPFc*/ - HAS_OPTION(XTENSA_OPTION_ICACHE); - gen_window_check1(dc, RRI8_S); - break; - - case 13: /*ICEc*/ - switch (OP1) { - case 0: /*IPFLl*/ - HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_icache_hit_test4(); - } - break; - - case 2: /*IHUl*/ - HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_icache_hit_test4(); - } - break; - - case 3: /*IIUl*/ - HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI4_S); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 14: /*IHIc*/ - HAS_OPTION(XTENSA_OPTION_ICACHE); - gen_icache_hit_test8(); - break; - - case 15: /*IIIc*/ - HAS_OPTION(XTENSA_OPTION_ICACHE); - if (gen_check_privilege(dc)) { - gen_window_check1(dc, RRI8_S); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - -#undef gen_icache_hit_test -#undef gen_icache_hit_test4 -#undef gen_icache_hit_test8 - - case 9: /*L16SI*/ - gen_load_store(ld16s, 1); - break; -#undef gen_load_store - - case 10: /*MOVI*/ - if (gen_window_check1(dc, RRI8_T)) { - tcg_gen_movi_i32(cpu_R[RRI8_T], - RRI8_IMM8 | (RRI8_S << 8) | - ((RRI8_S & 0x8) ? 0xfffff000 : 0)); - } - break; - -#define gen_load_store_no_hw_align(type) do { \ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { \ - TCGv_i32 addr = tcg_temp_local_new_i32(); \ - tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \ - gen_load_store_alignment(dc, 2, addr, true); \ - tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ - tcg_temp_free(addr); \ - } \ - } while (0) - - case 11: /*L32AIy*/ - HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); - gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/ - break; - - case 12: /*ADDI*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE); - } - break; - - case 13: /*ADDMI*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], - RRI8_IMM8_SE << 8); - } - break; - - case 14: /*S32C1Iy*/ - HAS_OPTION(XTENSA_OPTION_CONDITIONAL_STORE); - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - TCGLabel *label = gen_new_label(); - TCGv_i32 tmp = tcg_temp_local_new_i32(); - TCGv_i32 addr = tcg_temp_local_new_i32(); - TCGv_i32 tpc; - - tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]); - tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); - gen_load_store_alignment(dc, 2, addr, true); - - tpc = tcg_const_i32(dc->pc); - gen_helper_check_atomctl(cpu_env, tpc, addr); - tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); - tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T], - cpu_SR[SCOMPARE1], label); - - tcg_gen_qemu_st32(tmp, addr, dc->cring); - - gen_set_label(label); - tcg_temp_free(tpc); - tcg_temp_free(addr); - tcg_temp_free(tmp); - } - break; - - case 15: /*S32RIy*/ - HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); - gen_load_store_no_hw_align(st32); /*TODO release?*/ - break; -#undef gen_load_store_no_hw_align - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 3: /*LSCIp*/ - switch (RRI8_R) { - case 0: /*LSIf*/ - case 4: /*SSIf*/ - case 8: /*LSIUf*/ - case 12: /*SSIUf*/ - HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); - if (gen_window_check1(dc, RRI8_S) && - gen_check_cpenable(dc, 0)) { - TCGv_i32 addr = tcg_temp_new_i32(); - tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); - gen_load_store_alignment(dc, 2, addr, false); - if (RRI8_R & 0x4) { - tcg_gen_qemu_st32(cpu_FR[RRI8_T], addr, dc->cring); - } else { - tcg_gen_qemu_ld32u(cpu_FR[RRI8_T], addr, dc->cring); - } - if (RRI8_R & 0x8) { - tcg_gen_mov_i32(cpu_R[RRI8_S], addr); - } - tcg_temp_free(addr); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - case 4: /*MAC16d*/ - HAS_OPTION(XTENSA_OPTION_MAC16); - { - enum { - MAC16_UMUL = 0x0, - MAC16_MUL = 0x4, - MAC16_MULA = 0x8, - MAC16_MULS = 0xc, - MAC16_NONE = 0xf, - } op = OP1 & 0xc; - bool is_m1_sr = (OP2 & 0x3) == 2; - bool is_m2_sr = (OP2 & 0xc) == 0; - uint32_t ld_offset = 0; - - if (OP2 > 9) { - RESERVED(); - } - - switch (OP2 & 2) { - case 0: /*MACI?/MACC?*/ - is_m1_sr = true; - ld_offset = (OP2 & 1) ? -4 : 4; - - if (OP2 >= 8) { /*MACI/MACC*/ - if (OP1 == 0) { /*LDINC/LDDEC*/ - op = MAC16_NONE; - } else { - RESERVED(); - } - } else if (op != MAC16_MULA) { /*MULA.*.*.LDINC/LDDEC*/ - RESERVED(); - } - break; - - case 2: /*MACD?/MACA?*/ - if (op == MAC16_UMUL && OP2 != 7) { /*UMUL only in MACAA*/ - RESERVED(); - } - break; - } - - if (op != MAC16_NONE) { - if (!is_m1_sr && !gen_window_check1(dc, RRR_S)) { - break; - } - if (!is_m2_sr && !gen_window_check1(dc, RRR_T)) { - break; - } - } - - if (ld_offset && !gen_window_check1(dc, RRR_S)) { - break; - } - - { - TCGv_i32 vaddr = tcg_temp_new_i32(); - TCGv_i32 mem32 = tcg_temp_new_i32(); - - if (ld_offset) { - tcg_gen_addi_i32(vaddr, cpu_R[RRR_S], ld_offset); - gen_load_store_alignment(dc, 2, vaddr, false); - tcg_gen_qemu_ld32u(mem32, vaddr, dc->cring); - } - if (op != MAC16_NONE) { - TCGv_i32 m1 = gen_mac16_m( - is_m1_sr ? cpu_SR[MR + RRR_X] : cpu_R[RRR_S], - OP1 & 1, op == MAC16_UMUL); - TCGv_i32 m2 = gen_mac16_m( - is_m2_sr ? cpu_SR[MR + 2 + RRR_Y] : cpu_R[RRR_T], - OP1 & 2, op == MAC16_UMUL); - - if (op == MAC16_MUL || op == MAC16_UMUL) { - tcg_gen_mul_i32(cpu_SR[ACCLO], m1, m2); - if (op == MAC16_UMUL) { - tcg_gen_movi_i32(cpu_SR[ACCHI], 0); - } else { - tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31); - } - } else { - TCGv_i32 lo = tcg_temp_new_i32(); - TCGv_i32 hi = tcg_temp_new_i32(); - - tcg_gen_mul_i32(lo, m1, m2); - tcg_gen_sari_i32(hi, lo, 31); - if (op == MAC16_MULA) { - tcg_gen_add2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], - cpu_SR[ACCLO], cpu_SR[ACCHI], - lo, hi); - } else { - tcg_gen_sub2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], - cpu_SR[ACCLO], cpu_SR[ACCHI], - lo, hi); - } - tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]); - - tcg_temp_free_i32(lo); - tcg_temp_free_i32(hi); - } - tcg_temp_free(m1); - tcg_temp_free(m2); - } - if (ld_offset) { - tcg_gen_mov_i32(cpu_R[RRR_S], vaddr); - tcg_gen_mov_i32(cpu_SR[MR + RRR_W], mem32); - } - tcg_temp_free(vaddr); - tcg_temp_free(mem32); - } - } - break; - - case 5: /*CALLN*/ - switch (CALL_N) { - case 0: /*CALL0*/ - tcg_gen_movi_i32(cpu_R[0], dc->next_pc); - gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); - break; - - case 1: /*CALL4w*/ - case 2: /*CALL8w*/ - case 3: /*CALL12w*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - if (gen_window_check1(dc, CALL_N << 2)) { - gen_callwi(dc, CALL_N, - (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); - } - break; - } - break; - - case 6: /*SI*/ - switch (CALL_N) { - case 0: /*J*/ - gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0); - break; - - case 1: /*BZ*/ - if (gen_window_check1(dc, BRI12_S)) { - static const TCGCond cond[] = { - TCG_COND_EQ, /*BEQZ*/ - TCG_COND_NE, /*BNEZ*/ - TCG_COND_LT, /*BLTZ*/ - TCG_COND_GE, /*BGEZ*/ - }; - - gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0, - 4 + BRI12_IMM12_SE); - } - break; - - case 2: /*BI0*/ - if (gen_window_check1(dc, BRI8_S)) { - static const TCGCond cond[] = { - TCG_COND_EQ, /*BEQI*/ - TCG_COND_NE, /*BNEI*/ - TCG_COND_LT, /*BLTI*/ - TCG_COND_GE, /*BGEI*/ - }; - - gen_brcondi(dc, cond[BRI8_M & 3], - cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE); - } - break; - - case 3: /*BI1*/ - switch (BRI8_M) { - case 0: /*ENTRYw*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - { - TCGv_i32 pc = tcg_const_i32(dc->pc); - TCGv_i32 s = tcg_const_i32(BRI12_S); - TCGv_i32 imm = tcg_const_i32(BRI12_IMM12 << 3); - gen_helper_entry(cpu_env, pc, s, imm); - tcg_temp_free(imm); - tcg_temp_free(s); - tcg_temp_free(pc); - /* This can change tb->flags, so exit tb */ - gen_jumpi_check_loop_end(dc, -1); - } - break; - - case 1: /*B1*/ - switch (BRI8_R) { - case 0: /*BFp*/ - case 1: /*BTp*/ - HAS_OPTION(XTENSA_OPTION_BOOLEAN); - { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S); - gen_brcondi(dc, - BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ, - tmp, 0, 4 + RRI8_IMM8_SE); - tcg_temp_free(tmp); - } - break; - - case 8: /*LOOP*/ - case 9: /*LOOPNEZ*/ - case 10: /*LOOPGTZ*/ - HAS_OPTION(XTENSA_OPTION_LOOP); - if (gen_window_check1(dc, RRI8_S)) { - uint32_t lend = dc->pc + RRI8_IMM8 + 4; - TCGv_i32 tmp = tcg_const_i32(lend); - - tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1); - tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc); - gen_helper_wsr_lend(cpu_env, tmp); - tcg_temp_free(tmp); - - if (BRI8_R > 8) { - TCGLabel *label = gen_new_label(); - tcg_gen_brcondi_i32( - BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT, - cpu_R[RRI8_S], 0, label); - gen_jumpi(dc, lend, 1); - gen_set_label(label); - } - - gen_jumpi(dc, dc->next_pc, 0); - } - break; - - default: /*reserved*/ - RESERVED(); - break; - - } - break; - - case 2: /*BLTUI*/ - case 3: /*BGEUI*/ - if (gen_window_check1(dc, BRI8_S)) { - gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU, - cpu_R[BRI8_S], B4CONSTU[BRI8_R], - 4 + BRI8_IMM8_SE); - } - break; - } - break; - - } - break; - - case 7: /*B*/ - { - TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ; - - switch (RRI8_R & 7) { - case 0: /*BNONE*/ /*BANY*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); - gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); - tcg_temp_free(tmp); - } - break; - - case 1: /*BEQ*/ /*BNE*/ - case 2: /*BLT*/ /*BGE*/ - case 3: /*BLTU*/ /*BGEU*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - static const TCGCond cond[] = { - [1] = TCG_COND_EQ, - [2] = TCG_COND_LT, - [3] = TCG_COND_LTU, - [9] = TCG_COND_NE, - [10] = TCG_COND_GE, - [11] = TCG_COND_GEU, - }; - gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T], - 4 + RRI8_IMM8_SE); - } - break; - - case 4: /*BALL*/ /*BNALL*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); - gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T], - 4 + RRI8_IMM8_SE); - tcg_temp_free(tmp); - } - break; - - case 5: /*BBC*/ /*BBS*/ - if (gen_window_check2(dc, RRI8_S, RRI8_T)) { -#ifdef TARGET_WORDS_BIGENDIAN - TCGv_i32 bit = tcg_const_i32(0x80000000); -#else - TCGv_i32 bit = tcg_const_i32(0x00000001); -#endif - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f); -#ifdef TARGET_WORDS_BIGENDIAN - tcg_gen_shr_i32(bit, bit, tmp); -#else - tcg_gen_shl_i32(bit, bit, tmp); -#endif - tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit); - gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); - tcg_temp_free(tmp); - tcg_temp_free(bit); - } - break; - - case 6: /*BBCI*/ /*BBSI*/ - case 7: - if (gen_window_check1(dc, RRI8_S)) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_andi_i32(tmp, cpu_R[RRI8_S], -#ifdef TARGET_WORDS_BIGENDIAN - 0x80000000 >> (((RRI8_R & 1) << 4) | RRI8_T)); -#else - 0x00000001 << (((RRI8_R & 1) << 4) | RRI8_T)); -#endif - gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); - tcg_temp_free(tmp); - } - break; - - } - } - break; - -#define gen_narrow_load_store(type) do { \ - if (gen_window_check2(dc, RRRN_S, RRRN_T)) { \ - TCGv_i32 addr = tcg_temp_new_i32(); \ - tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \ - gen_load_store_alignment(dc, 2, addr, false); \ - tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \ - tcg_temp_free(addr); \ - } \ - } while (0) - - case 8: /*L32I.Nn*/ - gen_narrow_load_store(ld32u); - break; - - case 9: /*S32I.Nn*/ - gen_narrow_load_store(st32); - break; -#undef gen_narrow_load_store - - case 10: /*ADD.Nn*/ - if (gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T)) { - tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]); - } - break; - - case 11: /*ADDI.Nn*/ - if (gen_window_check2(dc, RRRN_R, RRRN_S)) { - tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], - RRRN_T ? RRRN_T : -1); - } - break; - - case 12: /*ST2n*/ - if (!gen_window_check1(dc, RRRN_S)) { - break; - } - if (RRRN_T < 8) { /*MOVI.Nn*/ - tcg_gen_movi_i32(cpu_R[RRRN_S], - RRRN_R | (RRRN_T << 4) | - ((RRRN_T & 6) == 6 ? 0xffffff80 : 0)); - } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/ - TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ; - - gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0, - 4 + (RRRN_R | ((RRRN_T & 3) << 4))); - } - break; - - case 13: /*ST3n*/ - switch (RRRN_R) { - case 0: /*MOV.Nn*/ - if (gen_window_check2(dc, RRRN_S, RRRN_T)) { - tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]); - } - break; - - case 15: /*S3*/ - switch (RRRN_T) { - case 0: /*RET.Nn*/ - gen_jump(dc, cpu_R[0]); - break; - - case 1: /*RETW.Nn*/ - HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); - { - TCGv_i32 tmp = tcg_const_i32(dc->pc); - gen_helper_retw(tmp, cpu_env, tmp); - gen_jump(dc, tmp); - tcg_temp_free(tmp); - } - break; - - case 2: /*BREAK.Nn*/ - HAS_OPTION(XTENSA_OPTION_DEBUG); - if (dc->debug) { - gen_debug_exception(dc, DEBUGCAUSE_BN); - } - break; - - case 3: /*NOP.Nn*/ - break; - - case 6: /*ILL.Nn*/ - gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - default: /*reserved*/ - RESERVED(); - break; - } - break; - - default: /*reserved*/ - RESERVED(); - break; + for (i = 1; i < len; ++i) { + b[i] = cpu_ldub_code(env, dc->pc + i); } + xtensa_insnbuf_from_chars(isa, dc->insnbuf, b, len); + fmt = xtensa_format_decode(isa, dc->insnbuf); + if (fmt == XTENSA_UNDEFINED) { + qemu_log_mask(LOG_GUEST_ERROR, + "unrecognized instruction format (pc = %08x)\n", + dc->pc); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return; + } + slots = xtensa_format_num_slots(isa, fmt); + for (slot = 0; slot < slots; ++slot) { + xtensa_opcode opc; + unsigned opnd, vopnd, opnds; + uint32_t raw_arg[MAX_OPCODE_ARGS]; + uint32_t arg[MAX_OPCODE_ARGS]; + XtensaOpcodeOps *ops; + dc->raw_arg = raw_arg; + + xtensa_format_get_slot(isa, fmt, slot, dc->insnbuf, dc->slotbuf); + opc = xtensa_opcode_decode(isa, fmt, slot, dc->slotbuf); + if (opc == XTENSA_UNDEFINED) { + qemu_log_mask(LOG_GUEST_ERROR, + "unrecognized opcode in slot %d (pc = %08x)\n", + slot, dc->pc); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return; + } + opnds = xtensa_opcode_num_operands(isa, opc); + + for (opnd = vopnd = 0; opnd < opnds; ++opnd) { + if (xtensa_operand_is_visible(isa, opc, opnd)) { + uint32_t v; + + xtensa_operand_get_field(isa, opc, opnd, fmt, slot, + dc->slotbuf, &v); + xtensa_operand_decode(isa, opc, opnd, &v); + raw_arg[vopnd] = v; + if (xtensa_operand_is_PCrelative(isa, opc, opnd)) { + xtensa_operand_undo_reloc(isa, opc, opnd, &v, dc->pc); + } + arg[vopnd] = v; + ++vopnd; + } + } + ops = dc->config->opcode_ops[opc]; + if (ops) { + ops->translate(dc, arg, ops->par); + } else { + qemu_log_mask(LOG_GUEST_ERROR, + "unimplemented opcode '%s' in slot %d (pc = %08x)\n", + xtensa_opcode_name(isa, opc), slot, dc->pc); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + return; + } + } if (dc->is_jmp == DISAS_NEXT) { gen_check_loop_end(dc, 0); } dc->pc = dc->next_pc; - - return; - -invalid_opcode: - qemu_log_mask(LOG_GUEST_ERROR, "INVALID(pc = %08x)\n", dc->pc); - gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); -#undef HAS_OPTION } static inline unsigned xtensa_insn_len(CPUXtensaState *env, DisasContext *dc) { uint8_t b0 = cpu_ldub_code(env, dc->pc); - return xtensa_op0_insn_len(OP0); + return xtensa_op0_insn_len(dc, b0); } static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc) @@ -3153,6 +1084,11 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >> XTENSA_TBFLAG_WINDOW_SHIFT); + if (dc.config->isa) { + dc.insnbuf = xtensa_insnbuf_alloc(dc.config->isa); + dc.slotbuf = xtensa_insnbuf_alloc(dc.config->isa); + } + init_litbase(&dc); init_sar_tracker(&dc); if (dc.icount) { @@ -3233,6 +1169,10 @@ done: if (dc.icount) { tcg_temp_free(dc.next_icount); } + if (dc.config->isa) { + xtensa_insnbuf_free(dc.config->isa, dc.insnbuf); + xtensa_insnbuf_free(dc.config->isa, dc.slotbuf); + } if (tb_cflags(tb) & CF_LAST_IO) { gen_io_end(); From e55239e2b65dbef085917e2dcc7336276877dfed Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 3 Nov 2017 20:30:30 -0700 Subject: [PATCH 476/546] target/xtensa: tests: fix memctl SR test memctl SR is not available on dc232b, as it was introduced in more recent hardware release. Now that this information is available through the libisa the test fails. Fix the test. Signed-off-by: Max Filippov --- tests/tcg/xtensa/test_sr.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S index 42e3e5e386..052f1e04a7 100644 --- a/tests/tcg/xtensa/test_sr.S +++ b/tests/tcg/xtensa/test_sr.S @@ -44,7 +44,6 @@ test_end test_sr acchi, 1 test_sr acclo, 1 -test_sr /*memctl*/97, 0 test_sr_mask /*atomctl*/99, 0, 0 test_sr_mask /*br*/4, 0, 0 test_sr_mask /*cacheattr*/98, 0, 0 @@ -76,6 +75,7 @@ test_sr lcount, 1 test_sr lend, 1 test_sr litbase, 1 test_sr m0, 1 +test_sr_mask /*memctl*/97, 0, 0 test_sr misc0, 1 test_sr_mask /*prefctl*/40, 0, 0 test_sr_mask /*prid*/235, 0, 1 From 5b9b27639e4af3e957da1959ad51f94e53c2e6f1 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 20 Feb 2017 10:41:45 -0800 Subject: [PATCH 477/546] target/xtensa: drop DisasContext::litbase It doesn't help much, always-set bit 0 of the LITBASE SR is easy to compensate with decrement of the l32r immediate argument. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index cf204fcb60..27078e9f5b 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -59,7 +59,6 @@ typedef struct DisasContext { int ring; uint32_t lbeg; uint32_t lend; - TCGv_i32 litbase; int is_jmp; int singlestep_enabled; @@ -261,21 +260,6 @@ static inline bool option_enabled(DisasContext *dc, int opt) return xtensa_option_enabled(dc->config, opt); } -static void init_litbase(DisasContext *dc) -{ - if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { - dc->litbase = tcg_temp_local_new_i32(); - tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000); - } -} - -static void reset_litbase(DisasContext *dc) -{ - if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { - tcg_temp_free(dc->litbase); - } -} - static void init_sar_tracker(DisasContext *dc) { dc->sar_5bit = false; @@ -1089,7 +1073,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) dc.slotbuf = xtensa_insnbuf_alloc(dc.config->isa); } - init_litbase(&dc); init_sar_tracker(&dc); if (dc.icount) { dc.next_icount = tcg_temp_local_new_i32(); @@ -1164,7 +1147,6 @@ void gen_intermediate_code(CPUState *cs, TranslationBlock *tb) dc.pc + xtensa_insn_len(env, &dc) <= next_page_start && !tcg_op_buf_full()); done: - reset_litbase(&dc); reset_sar_tracker(&dc); if (dc.icount) { tcg_temp_free(dc.next_icount); @@ -1667,12 +1649,13 @@ static void translate_l32r(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { if (gen_window_check1(dc, arg[0])) { - TCGv_i32 tmp = (dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? - tcg_const_i32(dc->raw_arg[1] - 1) : - tcg_const_i32(arg[1]); + TCGv_i32 tmp; if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { - tcg_gen_add_i32(tmp, tmp, dc->litbase); + tmp = tcg_const_i32(dc->raw_arg[1] - 1); + tcg_gen_add_i32(tmp, cpu_SR[LITBASE], tmp); + } else { + tmp = tcg_const_i32(arg[1]); } tcg_gen_qemu_ld32u(cpu_R[arg[0]], tmp, dc->cring); tcg_temp_free(tmp); From 13f6a7cd3a736b40e14b28d7e4df45ec9333f155 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Sun, 29 Jan 2017 03:50:25 -0800 Subject: [PATCH 478/546] target/xtensa: add internal/noop SRs and opcodes Add two special registers: MMID and DDR: - MMID is write-only and the only side effect of writing to it is output to the trace port, which is not emulated; - DDR is only accessible in debug mode, which is not emulated. Add two debug-mode-only opcodes: - rfdd and rfdo do return from the debug mode, which is not emulated. Add three internal opcodes for full MMU: - hwwdtlba and hwwitlba are the internal opcodes that write a value into autoupdate DTLB or ITLB entry. - ldpte is internal opcode that loads PTE entry that covers the most recent page fault address. None of these three opcodes may appear in a valid instruction. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 2 ++ target/xtensa/translate.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index e93bbb3c6d..80e9b47e84 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -127,6 +127,7 @@ enum { WINDOW_BASE = 72, WINDOW_START = 73, PTEVADDR = 83, + MMID = 89, RASID = 90, ITLBCFG = 91, DTLBCFG = 92, @@ -134,6 +135,7 @@ enum { MEMCTL = 97, CACHEATTR = 98, ATOMCTL = 99, + DDR = 104, IBREAKA = 128, DBREAKA = 144, DBREAKC = 160, diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 27078e9f5b..3e8a0015b3 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -135,6 +135,7 @@ static const XtensaReg sregnames[256] = { [WINDOW_START] = XTENSA_REG("WINDOW_START", XTENSA_OPTION_WINDOWED_REGISTER), [PTEVADDR] = XTENSA_REG("PTEVADDR", XTENSA_OPTION_MMU), + [MMID] = XTENSA_REG_BITS("MMID", XTENSA_OPTION_ALL), [RASID] = XTENSA_REG("RASID", XTENSA_OPTION_MMU), [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU), [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU), @@ -142,6 +143,7 @@ static const XtensaReg sregnames[256] = { [MEMCTL] = XTENSA_REG_BITS("MEMCTL", XTENSA_OPTION_ALL), [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR), [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL), + [DDR] = XTENSA_REG("DDR", XTENSA_OPTION_DEBUG), [IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG), [IBREAKA + 1] = XTENSA_REG("IBREAKA1", XTENSA_OPTION_DEBUG), [DBREAKA] = XTENSA_REG("DBREAKA0", XTENSA_OPTION_DEBUG), @@ -2761,6 +2763,12 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "extw", .translate = translate_nop, + }, { + .name = "hwwdtlba", + .translate = translate_ill, + }, { + .name = "hwwitlba", + .translate = translate_ill, }, { .name = "idtlb", .translate = translate_itlb, @@ -2846,6 +2854,9 @@ static const XtensaOpcodeOps core_ops[] = { .name = "ldinc", .translate = translate_mac16, .par = (const uint32_t[]){MAC16_NONE, 0, 0, 4}, + }, { + .name = "ldpte", + .translate = translate_ill, }, { .name = "loop", .translate = translate_loop, @@ -3264,9 +3275,15 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "retw.n", .translate = translate_retw, + }, { + .name = "rfdd", + .translate = translate_ill, }, { .name = "rfde", .translate = translate_rfde, + }, { + .name = "rfdo", + .translate = translate_ill, }, { .name = "rfe", .translate = translate_rfe, @@ -3367,6 +3384,10 @@ static const XtensaOpcodeOps core_ops[] = { .name = "rsr.dbreakc1", .translate = translate_rsr, .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "rsr.ddr", + .translate = translate_rsr, + .par = (const uint32_t[]){DDR}, }, { .name = "rsr.debugcause", .translate = translate_rsr, @@ -3802,6 +3823,10 @@ static const XtensaOpcodeOps core_ops[] = { .name = "wsr.dbreakc1", .translate = translate_wsr, .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "wsr.ddr", + .translate = translate_wsr, + .par = (const uint32_t[]){DDR}, }, { .name = "wsr.debugcause", .translate = translate_wsr, @@ -3994,6 +4019,10 @@ static const XtensaOpcodeOps core_ops[] = { .name = "wsr.misc3", .translate = translate_wsr, .par = (const uint32_t[]){MISC + 3}, + }, { + .name = "wsr.mmid", + .translate = translate_wsr, + .par = (const uint32_t[]){MMID}, }, { .name = "wsr.prid", .translate = translate_wsr, @@ -4121,6 +4150,10 @@ static const XtensaOpcodeOps core_ops[] = { .name = "xsr.dbreakc1", .translate = translate_xsr, .par = (const uint32_t[]){DBREAKC + 1}, + }, { + .name = "xsr.ddr", + .translate = translate_xsr, + .par = (const uint32_t[]){DDR}, }, { .name = "xsr.debugcause", .translate = translate_xsr, From d1e9b0068ac9544297042f1c4bbbf1a31a3eee3b Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 17 Feb 2017 16:39:30 -0800 Subject: [PATCH 479/546] target/xtensa: implement salt/saltu SALT/SALTU are recent additions to the core Xtensa ISA that do signed/unsigned setcond. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 3e8a0015b3..bf4bd2d48d 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -2194,6 +2194,16 @@ static void translate_s32e(DisasContext *dc, const uint32_t arg[], } } +static void translate_salt(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check3(dc, arg[0], arg[1], arg[2])) { + tcg_gen_setcond_i32(par[0], + cpu_R[arg[0]], + cpu_R[arg[1]], cpu_R[arg[2]]); + } +} + static void translate_sext(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { @@ -3661,6 +3671,14 @@ static const XtensaOpcodeOps core_ops[] = { .name = "s8i", .translate = translate_ldst, .par = (const uint32_t[]){MO_UB, false, true}, + }, { + .name = "salt", + .translate = translate_salt, + .par = (const uint32_t[]){TCG_COND_LT}, + }, { + .name = "saltu", + .translate = translate_salt, + .par = (const uint32_t[]){TCG_COND_LTU}, }, { .name = "sext", .translate = translate_sext, From e98727417aa639024af9d17650f8811dc408885c Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Fri, 17 Feb 2017 16:21:36 -0800 Subject: [PATCH 480/546] target/xtensa: implement GPIO32 GPIO32 is not in the core ISA, but it was widely used in Diamond Cores. This implementation doesn't do actual I/O and doesn't handle the case of GPIO32 state being a part of coprocessor. Signed-off-by: Max Filippov --- target/xtensa/cpu.h | 1 + target/xtensa/translate.c | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 80e9b47e84..d9404aa50a 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -108,6 +108,7 @@ enum { }; enum { + EXPSTATE = 230, THREADPTR = 231, FCR = 232, FSR = 233, diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index bf4bd2d48d..6f26e42a2b 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -204,6 +204,7 @@ static const XtensaReg sregnames[256] = { }; static const XtensaReg uregnames[256] = { + [EXPSTATE] = XTENSA_REG_BITS("EXPSTATE", XTENSA_OPTION_ALL), [THREADPTR] = XTENSA_REG("THREADPTR", XTENSA_OPTION_THREAD_POINTER), [FCR] = XTENSA_REG("FCR", XTENSA_OPTION_FP_COPROCESSOR), [FSR] = XTENSA_REG("FSR", XTENSA_OPTION_FP_COPROCESSOR), @@ -1513,6 +1514,13 @@ static void translate_clamps(DisasContext *dc, const uint32_t arg[], } } +static void translate_clrb_expstate(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + /* TODO: GPIO32 may be a part of coprocessor */ + tcg_gen_andi_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], ~(1u << arg[0])); +} + /* par[0]: privileged, par[1]: check memory access */ static void translate_dcache(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) @@ -2008,6 +2016,15 @@ static void translate_quou(DisasContext *dc, const uint32_t arg[], } } +static void translate_read_impwire(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + /* TODO: GPIO32 may be a part of coprocessor */ + tcg_gen_movi_i32(cpu_R[arg[0]], 0); + } +} + static void translate_rer(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { @@ -2152,6 +2169,13 @@ static void translate_rur(DisasContext *dc, const uint32_t arg[], } } +static void translate_setb_expstate(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + /* TODO: GPIO32 may be a part of coprocessor */ + tcg_gen_ori_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], 1u << arg[0]); +} + static void translate_s32c1i(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { @@ -2440,6 +2464,15 @@ static void translate_wer(DisasContext *dc, const uint32_t arg[], } } +static void translate_wrmsk_expstate(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check2(dc, arg[0], arg[1])) { + /* TODO: GPIO32 may be a part of coprocessor */ + tcg_gen_and_i32(cpu_UR[EXPSTATE], cpu_R[arg[0]], cpu_R[arg[1]]); + } +} + static void translate_wsr(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) { @@ -2700,6 +2733,9 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "clamps", .translate = translate_clamps, + }, { + .name = "clrb_expstate", + .translate = translate_clrb_expstate, }, { .name = "depbits", .translate = translate_depbits, @@ -3262,6 +3298,9 @@ static const XtensaOpcodeOps core_ops[] = { .name = "rdtlb1", .translate = translate_rtlb, .par = (const uint32_t[]){true, 1}, + }, { + .name = "read_impwire", + .translate = translate_read_impwire, }, { .name = "rems", .translate = translate_quos, @@ -3629,6 +3668,10 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "rsync", .translate = translate_nop, + }, { + .name = "rur.expstate", + .translate = translate_rur, + .par = (const uint32_t[]){EXPSTATE}, }, { .name = "rur.fcr", .translate = translate_rur, @@ -3679,6 +3722,9 @@ static const XtensaOpcodeOps core_ops[] = { .name = "saltu", .translate = translate_salt, .par = (const uint32_t[]){TCG_COND_LTU}, + }, { + .name = "setb_expstate", + .translate = translate_setb_expstate, }, { .name = "sext", .translate = translate_sext, @@ -3769,6 +3815,9 @@ static const XtensaOpcodeOps core_ops[] = { .name = "witlb", .translate = translate_wtlb, .par = (const uint32_t[]){false}, + }, { + .name = "wrmsk_expstate", + .translate = translate_wrmsk_expstate, }, { .name = "wsr.176", .translate = translate_wsr, @@ -4077,6 +4126,10 @@ static const XtensaOpcodeOps core_ops[] = { .name = "wsr.windowstart", .translate = translate_wsr, .par = (const uint32_t[]){WINDOW_START}, + }, { + .name = "wur.expstate", + .translate = translate_wur, + .par = (const uint32_t[]){EXPSTATE}, }, { .name = "wur.fcr", .translate = translate_wur, From c5ac936e5e8356cf6bba8e39519a273ab0fc6fed Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 2 Nov 2017 15:05:56 -0700 Subject: [PATCH 481/546] target/xtensa: implement const16 const16 is an opcode that shifts 16 lower bits of an address register to the 16 upper bits and puts its immediate operand into the lower 16 bits. It is not controlled by an Xtensa option and doesn't have a fixed opcode. Signed-off-by: Max Filippov --- target/xtensa/translate.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 6f26e42a2b..4bdfcd24d0 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1521,6 +1521,17 @@ static void translate_clrb_expstate(DisasContext *dc, const uint32_t arg[], tcg_gen_andi_i32(cpu_UR[EXPSTATE], cpu_UR[EXPSTATE], ~(1u << arg[0])); } +static void translate_const16(DisasContext *dc, const uint32_t arg[], + const uint32_t par[]) +{ + if (gen_window_check1(dc, arg[0])) { + TCGv_i32 c = tcg_const_i32(arg[1]); + + tcg_gen_deposit_i32(cpu_R[arg[0]], c, cpu_R[arg[0]], 16, 16); + tcg_temp_free(c); + } +} + /* par[0]: privileged, par[1]: check memory access */ static void translate_dcache(DisasContext *dc, const uint32_t arg[], const uint32_t par[]) @@ -2736,6 +2747,9 @@ static const XtensaOpcodeOps core_ops[] = { }, { .name = "clrb_expstate", .translate = translate_clrb_expstate, + }, { + .name = "const16", + .translate = translate_const16, }, { .name = "depbits", .translate = translate_depbits, From 5a6539e627faf9251e1db78238b9f9b870610518 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 31 Oct 2017 16:17:43 -0700 Subject: [PATCH 482/546] target/xtensa: implement disassembler Add disas/xtensa.c and use libisa for instruction decoding/opcode name lookup. Signed-off-by: Max Filippov --- MAINTAINERS | 1 + disas/Makefile.objs | 1 + disas/xtensa.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ include/disas/bfd.h | 1 + target/xtensa/cpu.c | 9 +++ 5 files changed, 145 insertions(+) create mode 100644 disas/xtensa.c diff --git a/MAINTAINERS b/MAINTAINERS index 0255113470..4e2795bc02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -259,6 +259,7 @@ S: Maintained F: target/xtensa/ F: hw/xtensa/ F: tests/tcg/xtensa/ +F: disas/xtensa.c TriCore M: Bastian Koppelmann diff --git a/disas/Makefile.objs b/disas/Makefile.objs index 194648fb1a..53556f8f5a 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_XTENSA_DIS) += xtensa.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/xtensa.c b/disas/xtensa.c new file mode 100644 index 0000000000..114326a4fc --- /dev/null +++ b/disas/xtensa.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2017, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "qemu/osdep.h" +#include "disas/bfd.h" +#include "hw/xtensa/xtensa-isa.h" + +int print_insn_xtensa(bfd_vma memaddr, struct disassemble_info *info) +{ + xtensa_isa isa = info->private_data; + xtensa_insnbuf insnbuf = xtensa_insnbuf_alloc(isa); + xtensa_insnbuf slotbuf = xtensa_insnbuf_alloc(isa); + bfd_byte *buffer = g_malloc(1); + int status = info->read_memory_func(memaddr, buffer, 1, info); + xtensa_format fmt; + unsigned slot, slots; + unsigned len; + + if (status) { + info->memory_error_func(status, memaddr, info); + len = -1; + goto out; + } + len = xtensa_isa_length_from_chars(isa, buffer); + if (len == XTENSA_UNDEFINED) { + info->fprintf_func(info->stream, ".byte 0x%02x", buffer[0]); + len = 1; + goto out; + } + buffer = g_realloc(buffer, len); + status = info->read_memory_func(memaddr + 1, buffer + 1, len - 1, info); + if (status) { + info->fprintf_func(info->stream, ".byte 0x%02x", buffer[0]); + info->memory_error_func(status, memaddr + 1, info); + len = 1; + goto out; + } + + xtensa_insnbuf_from_chars(isa, insnbuf, buffer, len); + fmt = xtensa_format_decode(isa, insnbuf); + if (fmt == XTENSA_UNDEFINED) { + unsigned i; + + for (i = 0; i < len; ++i) { + info->fprintf_func(info->stream, "%s 0x%02x", + i ? ", " : ".byte ", buffer[i]); + } + goto out; + } + slots = xtensa_format_num_slots(isa, fmt); + + if (slots > 1) { + info->fprintf_func(info->stream, "{ "); + } + + for (slot = 0; slot < slots; ++slot) { + xtensa_opcode opc; + unsigned opnd, vopnd, opnds; + + if (slot) { + info->fprintf_func(info->stream, "; "); + } + xtensa_format_get_slot(isa, fmt, slot, insnbuf, slotbuf); + opc = xtensa_opcode_decode(isa, fmt, slot, slotbuf); + if (opc == XTENSA_UNDEFINED) { + info->fprintf_func(info->stream, "???"); + continue; + } + opnds = xtensa_opcode_num_operands(isa, opc); + + info->fprintf_func(info->stream, "%s", xtensa_opcode_name(isa, opc)); + + for (opnd = vopnd = 0; opnd < opnds; ++opnd) { + if (xtensa_operand_is_visible(isa, opc, opnd)) { + uint32_t v = 0xbadc0de; + int rc; + + info->fprintf_func(info->stream, vopnd ? ", " : "\t"); + xtensa_operand_get_field(isa, opc, opnd, fmt, slot, + slotbuf, &v); + rc = xtensa_operand_decode(isa, opc, opnd, &v); + if (rc == XTENSA_UNDEFINED) { + info->fprintf_func(info->stream, "???"); + } else if (xtensa_operand_is_register(isa, opc, opnd)) { + xtensa_regfile rf = xtensa_operand_regfile(isa, opc, opnd); + + info->fprintf_func(info->stream, "%s%d", + xtensa_regfile_shortname(isa, rf), v); + } else if (xtensa_operand_is_PCrelative(isa, opc, opnd)) { + xtensa_operand_undo_reloc(isa, opc, opnd, &v, memaddr); + info->fprintf_func(info->stream, "0x%x", v); + } else { + info->fprintf_func(info->stream, "%d", v); + } + ++vopnd; + } + } + } + if (slots > 1) { + info->fprintf_func(info->stream, " }"); + } + +out: + g_free(buffer); + xtensa_insnbuf_free(isa, insnbuf); + xtensa_insnbuf_free(isa, slotbuf); + + return len; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index 46c7ec3376..932453750c 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -428,6 +428,7 @@ int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); int print_insn_big_nios2 (bfd_vma, disassemble_info*); int print_insn_little_nios2 (bfd_vma, disassemble_info*); +int print_insn_xtensa (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 91961789a5..1c982a0b2e 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -93,6 +93,14 @@ static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) return oc; } +static void xtensa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) +{ + XtensaCPU *cpu = XTENSA_CPU(cs); + + info->private_data = cpu->env.config->isa; + info->print_insn = print_insn_xtensa; +} + static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -164,6 +172,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) cc->do_unassigned_access = xtensa_cpu_do_unassigned_access; #endif cc->debug_excp_handler = xtensa_breakpoint_handler; + cc->disas_set_info = xtensa_cpu_disas_set_info; cc->tcg_initialize = xtensa_translate_init; dc->vmsd = &vmstate_xtensa_cpu; } From 9156245ec49b36d934ed09d49ffbd5dd37285374 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Thu, 7 Dec 2017 18:50:57 +0300 Subject: [PATCH 483/546] nbd/server: add additional assert to nbd_export_put This place is not obvious, nbd_export_close may theoretically reduce refcount to 0. It may happen if someone calls nbd_export_put on named export not through nbd_export_set_name when refcount is 1. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Reviewed-by: Max Reitz Message-Id: <20171207155102.66622-2-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- nbd/server.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nbd/server.c b/nbd/server.c index e443b3cf5c..6cf2eeb2c1 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -1190,6 +1190,12 @@ void nbd_export_put(NBDExport *exp) nbd_export_close(exp); } + /* nbd_export_close() may theoretically reduce refcount to 0. It may happen + * if someone calls nbd_export_put() on named export not through + * nbd_export_set_name() when refcount is 1. So, let's assert that + * it is > 0. + */ + assert(exp->refcount > 0); if (--exp->refcount == 0) { assert(exp->name == NULL); assert(exp->description == NULL); From 7e450a8f50ac12fc8f69b6ce555254c84efcf407 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Dubois Date: Wed, 22 Nov 2017 07:32:50 +0100 Subject: [PATCH 484/546] target/sparc: remove MemoryRegionSection check code from sparc_cpu_get_phys_page_debug() This code is preventing the MMU debug code from displaying virtual mappings of IO devices (anything that is not located in the RAM). Before this patch, Qemu would output 0xffffffffffffffff (-1) as the physical address corresponding to an IO device virtual address. With this patch the intended physical address is displayed. Signed-off-by: Jean-Christophe Dubois Signed-off-by: Mark Cave-Ayland --- target/sparc/mmu_helper.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index d5b6c1e48c..f2d2250e7a 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -857,18 +857,12 @@ hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) CPUSPARCState *env = &cpu->env; hwaddr phys_addr; int mmu_idx = cpu_mmu_index(env, false); - MemoryRegionSection section; if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { return -1; } } - section = memory_region_find(get_system_memory(), phys_addr, 1); - memory_region_unref(section.mr); - if (!int128_nz(section.size)) { - return -1; - } return phys_addr; } #endif From 28edc7c92a7491a9c077fd5b5686e5a226b8138b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 485/546] apb: move QOM macros and typedefs from apb.c to apb.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This also includes the related IOMMUState typedef and defines. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 85 -------------------------------------- include/hw/pci-host/apb.h | 86 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 85 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 64025cd8cc..f743a4e312 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -82,91 +82,6 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) #define MAX_IVEC 0x40 #define NO_IRQ_REQUEST (MAX_IVEC + 1) -#define IOMMU_PAGE_SIZE_8K (1ULL << 13) -#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) -#define IOMMU_PAGE_SIZE_64K (1ULL << 16) -#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1)) - -#define IOMMU_NREGS 3 - -#define IOMMU_CTRL 0x0 -#define IOMMU_CTRL_TBW_SIZE (1ULL << 2) -#define IOMMU_CTRL_MMU_EN (1ULL) - -#define IOMMU_CTRL_TSB_SHIFT 16 - -#define IOMMU_BASE 0x8 -#define IOMMU_FLUSH 0x10 - -#define IOMMU_TTE_DATA_V (1ULL << 63) -#define IOMMU_TTE_DATA_SIZE (1ULL << 61) -#define IOMMU_TTE_DATA_W (1ULL << 1) - -#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL -#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL - -#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL - -#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL - -typedef struct IOMMUState { - AddressSpace iommu_as; - IOMMUMemoryRegion iommu; - - uint64_t regs[IOMMU_NREGS]; -} IOMMUState; - -#define TYPE_APB "pbm" - -#define APB_DEVICE(obj) \ - OBJECT_CHECK(APBState, (obj), TYPE_APB) - -#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region" - -typedef struct APBState { - PCIHostState parent_obj; - - MemoryRegion apb_config; - MemoryRegion pci_config; - MemoryRegion pci_mmio; - MemoryRegion pci_ioport; - uint64_t pci_irq_in; - IOMMUState iommu; - uint32_t pci_control[16]; - uint32_t pci_irq_map[8]; - uint32_t pci_err_irq_map[4]; - uint32_t obio_irq_map[32]; - qemu_irq *pbm_irqs; - qemu_irq *ivec_irqs; - unsigned int irq_request; - uint32_t reset_control; - unsigned int nr_resets; -} APBState; - -#define TYPE_PBM_PCI_BRIDGE "pbm-bridge" -#define PBM_PCI_BRIDGE(obj) \ - OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) - -typedef struct PBMPCIBridge { - /*< private >*/ - PCIBridge parent_obj; - - /* Is this busA with in-built devices (ebus)? */ - bool busA; -} PBMPCIBridge; - static inline void pbm_set_request(APBState *s, unsigned int irq_num) { APB_DPRINTF("%s: request irq %d\n", __func__, irq_num); diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index b19bd55c40..5d39c03bc4 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -2,6 +2,92 @@ #define PCI_HOST_APB_H #include "qemu-common.h" +#include "hw/pci/pci_host.h" + +#define IOMMU_NREGS 3 + +#define IOMMU_PAGE_SIZE_8K (1ULL << 13) +#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) +#define IOMMU_PAGE_SIZE_64K (1ULL << 16) +#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1)) + +#define IOMMU_CTRL 0x0 +#define IOMMU_CTRL_TBW_SIZE (1ULL << 2) +#define IOMMU_CTRL_MMU_EN (1ULL) + +#define IOMMU_CTRL_TSB_SHIFT 16 + +#define IOMMU_BASE 0x8 +#define IOMMU_FLUSH 0x10 + +#define IOMMU_TTE_DATA_V (1ULL << 63) +#define IOMMU_TTE_DATA_SIZE (1ULL << 61) +#define IOMMU_TTE_DATA_W (1ULL << 1) + +#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL +#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL + +#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL + +#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL + +typedef struct IOMMUState { + AddressSpace iommu_as; + IOMMUMemoryRegion iommu; + + uint64_t regs[IOMMU_NREGS]; +} IOMMUState; + +#define TYPE_APB "pbm" + +#define APB_DEVICE(obj) \ + OBJECT_CHECK(APBState, (obj), TYPE_APB) + +#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region" + +typedef struct APBState { + PCIHostState parent_obj; + + MemoryRegion apb_config; + MemoryRegion pci_config; + MemoryRegion pci_mmio; + MemoryRegion pci_ioport; + uint64_t pci_irq_in; + IOMMUState iommu; + uint32_t pci_control[16]; + uint32_t pci_irq_map[8]; + uint32_t pci_err_irq_map[4]; + uint32_t obio_irq_map[32]; + qemu_irq *pbm_irqs; + qemu_irq *ivec_irqs; + unsigned int irq_request; + uint32_t reset_control; + unsigned int nr_resets; +} APBState; + +typedef struct PBMPCIBridge { + /*< private >*/ + PCIBridge parent_obj; + + /* Is this busA with in-built devices (ebus)? */ + bool busA; +} PBMPCIBridge; + +#define TYPE_PBM_PCI_BRIDGE "pbm-bridge" +#define PBM_PCI_BRIDGE(obj) \ + OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) PCIBus *pci_apb_init(hwaddr special_base, hwaddr mem_base, From ad6856e875ee0f60fb89c74b0410fd99c2c5e9a2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 486/546] sun4u: ebus QOMify tidy-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main change here is to introduce the proper TYPE_EBUS/EBUS QOM macros and remove the use of DO_UPCAST. Alongside this there are some a couple of minor cosmetic changes and a rename of pci_ebus_realize() to ebus_realize() since the ebus device is always what is effectively a PCI-ISA bridge. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé --- hw/sparc64/sun4u.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 1672f256e7..394b7d6c59 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -81,11 +81,16 @@ struct hwdef { }; typedef struct EbusState { - PCIDevice pci_dev; + /*< private >*/ + PCIDevice parent_obj; + MemoryRegion bar0; MemoryRegion bar1; } EbusState; +#define TYPE_EBUS "ebus" +#define EBUS(obj) OBJECT_CHECK(EbusState, (obj), TYPE_EBUS) + void DMA_init(ISABus *bus, int high_page_enable) { } @@ -236,9 +241,9 @@ pci_ebus_init(PCIDevice *pci_dev, qemu_irq *irqs) return isa_bus; } -static void pci_ebus_realize(PCIDevice *pci_dev, Error **errp) +static void ebus_realize(PCIDevice *pci_dev, Error **errp) { - EbusState *s = DO_UPCAST(EbusState, pci_dev, pci_dev); + EbusState *s = EBUS(pci_dev); if (!isa_bus_new(DEVICE(pci_dev), get_system_memory(), pci_address_space_io(pci_dev), errp)) { @@ -264,7 +269,7 @@ static void ebus_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->realize = pci_ebus_realize; + k->realize = ebus_realize; k->vendor_id = PCI_VENDOR_ID_SUN; k->device_id = PCI_DEVICE_ID_SUN_EBUS; k->revision = 0x01; @@ -272,10 +277,10 @@ static void ebus_class_init(ObjectClass *klass, void *data) } static const TypeInfo ebus_info = { - .name = "ebus", + .name = TYPE_EBUS, .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(EbusState), .class_init = ebus_class_init, + .instance_size = sizeof(EbusState), .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, @@ -463,7 +468,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_busA->slot_reserved_mask = 0xfffffff1; pci_busB->slot_reserved_mask = 0xfffffff0; - ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, "ebus"); + ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, TYPE_EBUS); qdev_init_nofail(DEVICE(ebus)); isa_bus = pci_ebus_init(ebus, pbm_irqs); From 8c40b8d9fb596cd1e9517d0176043c478bb8e7e2 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 487/546] sun4u: move ISABus inside of EBusState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the EBus is effectively a PCI-ISA bridge then the underlying ISA bus should be contained within the PCI bridge itself. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/sparc64/sun4u.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 394b7d6c59..63b4aaa6eb 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -84,6 +84,7 @@ typedef struct EbusState { /*< private >*/ PCIDevice parent_obj; + ISABus *isa_bus; MemoryRegion bar0; MemoryRegion bar1; } EbusState; @@ -245,8 +246,10 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); - if (!isa_bus_new(DEVICE(pci_dev), get_system_memory(), - pci_address_space_io(pci_dev), errp)) { + s->isa_bus = isa_bus_new(DEVICE(pci_dev), get_system_memory(), + pci_address_space_io(pci_dev), errp); + if (!s->isa_bus) { + error_setg(errp, "unable to instantiate EBUS ISA bus"); return; } From c796eddaad58301611315ae3c16f3ef26ccf207a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 488/546] sun4u: remove pci_ebus_init() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is initialisation that should really take place in the ebus realize function. As part of this we also rework the ebus IRQ mapping so that instead of having to pass in the array of pbm_irqs, we obtain a reference to them by looking up the APB device during ebus realize. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 4 +--- hw/sparc64/sun4u.c | 29 ++++++++++++++--------------- include/hw/pci-host/apb.h | 3 +-- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index f743a4e312..b0f80f63eb 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -614,8 +614,7 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) PCIBus *pci_apb_init(hwaddr special_base, hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB, - qemu_irq **pbm_irqs) + qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB) { DeviceState *dev; SysBusDevice *s; @@ -646,7 +645,6 @@ PCIBus *pci_apb_init(hwaddr special_base, memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio); - *pbm_irqs = d->pbm_irqs; d->ivec_irqs = ivec_irqs; pci_create_simple(phb->bus, 0, "pbm-pci"); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 63b4aaa6eb..f3203ea887 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -230,21 +230,11 @@ static void isa_irq_handler(void *opaque, int n, int level) } /* EBUS (Eight bit bus) bridge */ -static ISABus * -pci_ebus_init(PCIDevice *pci_dev, qemu_irq *irqs) -{ - qemu_irq *isa_irq; - ISABus *isa_bus; - - isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(pci_dev), "isa.0")); - isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16); - isa_bus_irqs(isa_bus, isa_irq); - return isa_bus; -} - static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); + APBState *apb; + qemu_irq *isa_irq; s->isa_bus = isa_bus_new(DEVICE(pci_dev), get_system_memory(), pci_address_space_io(pci_dev), errp); @@ -253,6 +243,15 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) return; } + apb = APB_DEVICE(object_resolve_path_type("", TYPE_APB, NULL)); + if (!apb) { + error_setg(errp, "unable to locate APB PCI host bridge"); + return; + } + + isa_irq = qemu_allocate_irqs(isa_irq_handler, apb->pbm_irqs, 16); + isa_bus_irqs(s->isa_bus, isa_irq); + pci_dev->config[0x04] = 0x06; // command = bus master, pci mem pci_dev->config[0x05] = 0x00; pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error @@ -443,7 +442,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, PCIDevice *ebus, *pci_dev; ISABus *isa_bus; SysBusDevice *s; - qemu_irq *ivec_irqs, *pbm_irqs; + qemu_irq *ivec_irqs; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; DeviceState *dev; @@ -462,7 +461,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX); pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA, - &pci_busB, &pbm_irqs); + &pci_busB); /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is reserved (leaving no slots free after on-board devices) however slots @@ -474,7 +473,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, TYPE_EBUS); qdev_init_nofail(DEVICE(ebus)); - isa_bus = pci_ebus_init(ebus, pbm_irqs); + isa_bus = EBUS(ebus)->isa_bus; i = 0; if (hwdef->console_serial_base) { diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 5d39c03bc4..35d7d5ad7b 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -91,6 +91,5 @@ typedef struct PBMPCIBridge { PCIBus *pci_apb_init(hwaddr special_base, hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3, - qemu_irq **pbm_irqs); + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3); #endif From 0fe22ffbbc6b65fe6bd453b37120edba91fc169e Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 489/546] sun4u: move initialisation of all ISABus devices into ebus_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This belongs in the PCI-ISA bridge rather than at the machine level. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko --- hw/sparc64/sun4u.c | 78 +++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index f3203ea887..b441f1ecdb 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -85,6 +85,7 @@ typedef struct EbusState { PCIDevice parent_obj; ISABus *isa_bus; + uint64_t console_serial_base; MemoryRegion bar0; MemoryRegion bar1; } EbusState; @@ -234,7 +235,10 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); APBState *apb; + DeviceState *dev; qemu_irq *isa_irq; + DriveInfo *fd[MAX_FD]; + int i; s->isa_bus = isa_bus_new(DEVICE(pci_dev), get_system_memory(), pci_address_space_io(pci_dev), errp); @@ -252,6 +256,38 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) isa_irq = qemu_allocate_irqs(isa_irq_handler, apb->pbm_irqs, 16); isa_bus_irqs(s->isa_bus, isa_irq); + /* Serial ports */ + i = 0; + if (s->console_serial_base) { + serial_mm_init(pci_address_space(pci_dev), s->console_serial_base, + 0, NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); + i++; + } + serial_hds_isa_init(s->isa_bus, i, MAX_SERIAL_PORTS); + + /* Parallel ports */ + parallel_hds_isa_init(s->isa_bus, MAX_PARALLEL_PORTS); + + /* Keyboard */ + isa_create_simple(s->isa_bus, "i8042"); + + /* Floppy */ + for (i = 0; i < MAX_FD; i++) { + fd[i] = drive_get(IF_FLOPPY, 0, i); + } + dev = DEVICE(isa_create(s->isa_bus, TYPE_ISA_FDC)); + if (fd[0]) { + qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]), + &error_abort); + } + if (fd[1]) { + qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]), + &error_abort); + } + qdev_prop_set_uint32(dev, "dma", -1); + qdev_init_nofail(dev); + + /* PCI */ pci_dev->config[0x04] = 0x06; // command = bus master, pci mem pci_dev->config[0x05] = 0x00; pci_dev->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error @@ -267,15 +303,23 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1); } +static Property ebus_properties[] = { + DEFINE_PROP_UINT64("console-serial-base", EbusState, + console_serial_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void ebus_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->realize = ebus_realize; k->vendor_id = PCI_VENDOR_ID_SUN; k->device_id = PCI_DEVICE_ID_SUN_EBUS; k->revision = 0x01; k->class_id = PCI_CLASS_BRIDGE_OTHER; + dc->props = ebus_properties; } static const TypeInfo ebus_info = { @@ -440,11 +484,9 @@ static void sun4uv_init(MemoryRegion *address_space_mem, uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; PCIBus *pci_bus, *pci_busA, *pci_busB; PCIDevice *ebus, *pci_dev; - ISABus *isa_bus; SysBusDevice *s; qemu_irq *ivec_irqs; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DriveInfo *fd[MAX_FD]; DeviceState *dev; FWCfgState *fw_cfg; NICInfo *nd; @@ -471,20 +513,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_busB->slot_reserved_mask = 0xfffffff0; ebus = pci_create_multifunction(pci_busA, PCI_DEVFN(1, 0), true, TYPE_EBUS); + qdev_prop_set_uint64(DEVICE(ebus), "console-serial-base", + hwdef->console_serial_base); qdev_init_nofail(DEVICE(ebus)); - isa_bus = EBUS(ebus)->isa_bus; - - i = 0; - if (hwdef->console_serial_base) { - serial_mm_init(address_space_mem, hwdef->console_serial_base, 0, - NULL, 115200, serial_hds[i], DEVICE_BIG_ENDIAN); - i++; - } - - serial_hds_isa_init(isa_bus, i, MAX_SERIAL_PORTS); - parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS); - pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA"); memset(&macaddr, 0, sizeof(MACAddr)); @@ -523,24 +555,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, qdev_init_nofail(&pci_dev->qdev); pci_ide_create_devs(pci_dev, hd); - isa_create_simple(isa_bus, "i8042"); - - /* Floppy */ - for(i = 0; i < MAX_FD; i++) { - fd[i] = drive_get(IF_FLOPPY, 0, i); - } - dev = DEVICE(isa_create(isa_bus, TYPE_ISA_FDC)); - if (fd[0]) { - qdev_prop_set_drive(dev, "driveA", blk_by_legacy_dinfo(fd[0]), - &error_abort); - } - if (fd[1]) { - qdev_prop_set_drive(dev, "driveB", blk_by_legacy_dinfo(fd[1]), - &error_abort); - } - qdev_prop_set_uint32(dev, "dma", -1); - qdev_init_nofail(dev); - /* Map NVRAM into I/O (ebus) space */ nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59); s = SYS_BUS_DEVICE(nvram); From b26f441903f8d6efcd0501ec6d0a2c8a51a13eae Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 490/546] apb: APB QOMify tidy-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use DeviceClass rather than SysBusDeviceClass in pbm_host_class_init() and adjust pci_pbm_init_device() accordingly. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index b0f80f63eb..c7837efb7a 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -705,12 +705,12 @@ static const MemoryRegionOps pci_config_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int pci_pbm_init_device(SysBusDevice *dev) +static int pci_pbm_init_device(DeviceState *dev) { - APBState *s; + APBState *s = APB_DEVICE(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(s); unsigned int i; - s = APB_DEVICE(dev); for (i = 0; i < 8; i++) { s->pci_irq_map[i] = (0x1f << 6) | (i << 2); } @@ -728,18 +728,18 @@ static int pci_pbm_init_device(SysBusDevice *dev) memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s, "apb-config", 0x10000); /* at region 0 */ - sysbus_init_mmio(dev, &s->apb_config); + sysbus_init_mmio(sbd, &s->apb_config); memory_region_init_io(&s->pci_config, OBJECT(s), &pci_config_ops, s, "apb-pci-config", 0x1000000); /* at region 1 */ - sysbus_init_mmio(dev, &s->pci_config); + sysbus_init_mmio(sbd, &s->pci_config); /* pci_ioport */ memory_region_init(&s->pci_ioport, OBJECT(s), "apb-pci-ioport", 0x1000000); /* at region 2 */ - sysbus_init_mmio(dev, &s->pci_ioport); + sysbus_init_mmio(sbd, &s->pci_ioport); return 0; } @@ -783,11 +783,10 @@ static const TypeInfo pbm_pci_host_info = { static void pbm_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - k->init = pci_pbm_init_device; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); + dc->init = pci_pbm_init_device; dc->reset = pci_pbm_reset; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo pbm_host_info = { From 588978c0a1e9f5596a12d124b530bdf698ed9104 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 491/546] apb: return APBState from pci_apb_init() rather than PCIBus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a first step towards removing pci_apb_init() completely. Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko --- hw/pci-host/apb.c | 8 ++++---- hw/sparc64/sun4u.c | 6 ++++-- include/hw/pci-host/apb.h | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index c7837efb7a..0c709992ec 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -612,9 +612,9 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) pci_bridge_update_mappings(PCI_BRIDGE(br)); } -PCIBus *pci_apb_init(hwaddr special_base, - hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB) +APBState *pci_apb_init(hwaddr special_base, + hwaddr mem_base, + qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB) { DeviceState *dev; SysBusDevice *s; @@ -675,7 +675,7 @@ PCIBus *pci_apb_init(hwaddr special_base, qdev_init_nofail(&pci_dev->qdev); *busA = pci_bridge_get_sec_bus(br); - return phb->bus; + return d; } static void pci_pbm_reset(DeviceState *d) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index b441f1ecdb..a64ddc569d 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -482,6 +482,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, Nvram *nvram; unsigned int i; uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry; + APBState *apb; PCIBus *pci_bus, *pci_busA, *pci_busB; PCIDevice *ebus, *pci_dev; SysBusDevice *s; @@ -502,8 +503,9 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX); - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA, - &pci_busB); + apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA, + &pci_busB); + pci_bus = PCI_HOST_BRIDGE(apb)->bus; /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is reserved (leaving no slots free after on-board devices) however slots diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 35d7d5ad7b..a4ef51adc8 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -89,7 +89,7 @@ typedef struct PBMPCIBridge { #define PBM_PCI_BRIDGE(obj) \ OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) -PCIBus *pci_apb_init(hwaddr special_base, - hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3); +APBState *pci_apb_init(hwaddr special_base, + hwaddr mem_base, + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3); #endif From 2a4d6af51b8330bfd7a7dd677927b8dd2f5f5f08 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 492/546] apb: use gpios to wire up the apb device to the SPARC CPU IRQs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko --- hw/pci-host/apb.c | 6 ++---- hw/sparc64/sparc64.c | 2 ++ hw/sparc64/sun4u.c | 12 ++++++++---- include/hw/pci-host/apb.h | 6 ++++-- include/hw/sparc/sparc64.h | 2 ++ 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 0c709992ec..c0b97e41bf 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -79,7 +79,6 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) #define RESET_WCMASK 0x98000000 #define RESET_WMASK 0x60000000 -#define MAX_IVEC 0x40 #define NO_IRQ_REQUEST (MAX_IVEC + 1) static inline void pbm_set_request(APBState *s, unsigned int irq_num) @@ -614,7 +613,7 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) APBState *pci_apb_init(hwaddr special_base, hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **busA, PCIBus **busB) + PCIBus **busA, PCIBus **busB) { DeviceState *dev; SysBusDevice *s; @@ -645,8 +644,6 @@ APBState *pci_apb_init(hwaddr special_base, memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio); - d->ivec_irqs = ivec_irqs; - pci_create_simple(phb->bus, 0, "pbm-pci"); /* APB IOMMU */ @@ -721,6 +718,7 @@ static int pci_pbm_init_device(DeviceState *dev) s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i; } s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC); + qdev_init_gpio_out_named(DEVICE(s), s->ivec_irqs, "ivec-irq", MAX_IVEC); s->irq_request = NO_IRQ_REQUEST; s->pci_irq_in = 0ULL; diff --git a/hw/sparc64/sparc64.c b/hw/sparc64/sparc64.c index 9453e2c390..95a06f00b2 100644 --- a/hw/sparc64/sparc64.c +++ b/hw/sparc64/sparc64.c @@ -350,6 +350,8 @@ SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr) uint32_t hstick_frequency = 100 * 1000000; cpu = SPARC_CPU(cpu_create(cpu_type)); + qdev_init_gpio_in_named(DEVICE(cpu), sparc64_cpu_set_ivec_irq, + "ivec-irq", IVEC_MAX); env = &cpu->env; env->tick = cpu_timer_create("tick", cpu, tick_irq, diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index a64ddc569d..2afd3f28dd 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -486,7 +486,6 @@ static void sun4uv_init(MemoryRegion *address_space_mem, PCIBus *pci_bus, *pci_busA, *pci_busB; PCIDevice *ebus, *pci_dev; SysBusDevice *s; - qemu_irq *ivec_irqs; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DeviceState *dev; FWCfgState *fw_cfg; @@ -502,9 +501,14 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); - ivec_irqs = qemu_allocate_irqs(sparc64_cpu_set_ivec_irq, cpu, IVEC_MAX); - apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_busA, - &pci_busB); + apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, &pci_busA, &pci_busB); + + /* Wire up PCI interrupts to CPU */ + for (i = 0; i < IVEC_MAX; i++) { + qdev_connect_gpio_out_named(DEVICE(apb), "ivec-irq", i, + qdev_get_gpio_in_named(DEVICE(cpu), "ivec-irq", i)); + } + pci_bus = PCI_HOST_BRIDGE(apb)->bus; /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index a4ef51adc8..f7ead680f3 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -50,6 +50,8 @@ typedef struct IOMMUState { uint64_t regs[IOMMU_NREGS]; } IOMMUState; +#define MAX_IVEC 0x40 + #define TYPE_APB "pbm" #define APB_DEVICE(obj) \ @@ -71,7 +73,7 @@ typedef struct APBState { uint32_t pci_err_irq_map[4]; uint32_t obio_irq_map[32]; qemu_irq *pbm_irqs; - qemu_irq *ivec_irqs; + qemu_irq ivec_irqs[MAX_IVEC]; unsigned int irq_request; uint32_t reset_control; unsigned int nr_resets; @@ -91,5 +93,5 @@ typedef struct PBMPCIBridge { APBState *pci_apb_init(hwaddr special_base, hwaddr mem_base, - qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3); + PCIBus **bus2, PCIBus **bus3); #endif diff --git a/include/hw/sparc/sparc64.h b/include/hw/sparc/sparc64.h index ca3bb4be71..5af4344459 100644 --- a/include/hw/sparc/sparc64.h +++ b/include/hw/sparc/sparc64.h @@ -1,4 +1,6 @@ +#define IVEC_MAX 0x40 + SPARCCPU *sparc64_cpu_devinit(const char *cpu_type, uint64_t prom_addr); void sparc64_cpu_set_ivec_irq(void *opaque, int irq, int level); From 4272ad40189c73324da59047f5232ec795111c4b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 493/546] apb: move the two secondary PCI bridges objects into APBState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables us to remove these parameters from pci_apb_init(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 14 +++++--------- hw/sparc64/sun4u.c | 5 ++++- include/hw/pci-host/apb.h | 5 +++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index c0b97e41bf..823661a8a6 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -612,8 +612,7 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) } APBState *pci_apb_init(hwaddr special_base, - hwaddr mem_base, - PCIBus **busA, PCIBus **busB) + hwaddr mem_base) { DeviceState *dev; SysBusDevice *s; @@ -621,7 +620,6 @@ APBState *pci_apb_init(hwaddr special_base, APBState *d; IOMMUState *is; PCIDevice *pci_dev; - PCIBridge *br; /* Ultrasparc PBM main bus */ dev = qdev_create(NULL, TYPE_APB); @@ -659,18 +657,16 @@ APBState *pci_apb_init(hwaddr special_base, /* APB secondary busses */ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, TYPE_PBM_PCI_BRIDGE); - br = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(br, "pciB", pci_pbm_map_irq); + d->bridgeB = PCI_BRIDGE(pci_dev); + pci_bridge_map_irq(d->bridgeB, "pciB", pci_pbm_map_irq); qdev_init_nofail(&pci_dev->qdev); - *busB = pci_bridge_get_sec_bus(br); pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, TYPE_PBM_PCI_BRIDGE); - br = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(br, "pciA", pci_pbm_map_irq); + d->bridgeA = PCI_BRIDGE(pci_dev); + pci_bridge_map_irq(d->bridgeA, "pciA", pci_pbm_map_irq); qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); qdev_init_nofail(&pci_dev->qdev); - *busA = pci_bridge_get_sec_bus(br); return d; } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 2afd3f28dd..47952befcb 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "hw/hw.h" #include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" #include "hw/pci-host/apb.h" #include "hw/i386/pc.h" @@ -501,7 +502,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); - apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, &pci_busA, &pci_busB); + apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); /* Wire up PCI interrupts to CPU */ for (i = 0; i < IVEC_MAX; i++) { @@ -510,6 +511,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } pci_bus = PCI_HOST_BRIDGE(apb)->bus; + pci_busA = pci_bridge_get_sec_bus(apb->bridgeA); + pci_busB = pci_bridge_get_sec_bus(apb->bridgeB); /* Only in-built Simba PBMs can exist on the root bus, slot 0 on busA is reserved (leaving no slots free after on-board devices) however slots diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index f7ead680f3..ae15d8ce59 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -68,6 +68,8 @@ typedef struct APBState { MemoryRegion pci_ioport; uint64_t pci_irq_in; IOMMUState iommu; + PCIBridge *bridgeA; + PCIBridge *bridgeB; uint32_t pci_control[16]; uint32_t pci_irq_map[8]; uint32_t pci_err_irq_map[4]; @@ -92,6 +94,5 @@ typedef struct PBMPCIBridge { OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) APBState *pci_apb_init(hwaddr special_base, - hwaddr mem_base, - PCIBus **bus2, PCIBus **bus3); + hwaddr mem_base); #endif From cacd05805eeea393ec929fe841f9a68aa2140d92 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 494/546] apb: remove pci_apb_init() and instantiate APB device using qdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By making the special_base and mem_base values qdev properties, we can move the remaining parts of pci_apb_init() into the pbm init() and realize() functions. This finally allows us to instantiate the APB directly using standard qdev create/init functions in sun4u.c. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 126 +++++++++++++++++++------------------- hw/sparc64/sun4u.c | 6 +- include/hw/pci-host/apb.h | 4 +- 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 823661a8a6..787be744a2 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -611,66 +611,6 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) pci_bridge_update_mappings(PCI_BRIDGE(br)); } -APBState *pci_apb_init(hwaddr special_base, - hwaddr mem_base) -{ - DeviceState *dev; - SysBusDevice *s; - PCIHostState *phb; - APBState *d; - IOMMUState *is; - PCIDevice *pci_dev; - - /* Ultrasparc PBM main bus */ - dev = qdev_create(NULL, TYPE_APB); - d = APB_DEVICE(dev); - phb = PCI_HOST_BRIDGE(dev); - phb->bus = pci_register_bus(DEVICE(phb), "pci", - pci_apb_set_irq, pci_apb_map_irq, d, - &d->pci_mmio, - &d->pci_ioport, - 0, 32, TYPE_PCI_BUS); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - /* apb_config */ - sysbus_mmio_map(s, 0, special_base); - /* PCI configuration space */ - sysbus_mmio_map(s, 1, special_base + 0x1000000ULL); - /* pci_ioport */ - sysbus_mmio_map(s, 2, special_base + 0x2000000ULL); - - memory_region_init(&d->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); - memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio); - - pci_create_simple(phb->bus, 0, "pbm-pci"); - - /* APB IOMMU */ - is = &d->iommu; - memset(is, 0, sizeof(IOMMUState)); - - memory_region_init_iommu(&is->iommu, sizeof(is->iommu), - TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev), - "iommu-apb", UINT64_MAX); - address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as"); - pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); - - /* APB secondary busses */ - pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, - TYPE_PBM_PCI_BRIDGE); - d->bridgeB = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(d->bridgeB, "pciB", pci_pbm_map_irq); - qdev_init_nofail(&pci_dev->qdev); - - pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, - TYPE_PBM_PCI_BRIDGE); - d->bridgeA = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(d->bridgeA, "pciA", pci_pbm_map_irq); - qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); - qdev_init_nofail(&pci_dev->qdev); - - return d; -} - static void pci_pbm_reset(DeviceState *d) { unsigned int i; @@ -698,10 +638,62 @@ static const MemoryRegionOps pci_config_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static int pci_pbm_init_device(DeviceState *dev) +static void pci_pbm_realize(DeviceState *dev, Error **errp) { APBState *s = APB_DEVICE(dev); + PCIHostState *phb = PCI_HOST_BRIDGE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(s); + PCIDevice *pci_dev; + IOMMUState *is; + + /* apb_config */ + sysbus_mmio_map(sbd, 0, s->special_base); + /* PCI configuration space */ + sysbus_mmio_map(sbd, 1, s->special_base + 0x1000000ULL); + /* pci_ioport */ + sysbus_mmio_map(sbd, 2, s->special_base + 0x2000000ULL); + + memory_region_init(&s->pci_mmio, OBJECT(s), "pci-mmio", 0x100000000ULL); + memory_region_add_subregion(get_system_memory(), s->mem_base, + &s->pci_mmio); + + phb->bus = pci_register_bus(dev, "pci", + pci_apb_set_irq, pci_apb_map_irq, s, + &s->pci_mmio, + &s->pci_ioport, + 0, 32, TYPE_PCI_BUS); + + pci_create_simple(phb->bus, 0, "pbm-pci"); + + /* APB IOMMU */ + is = &s->iommu; + memset(is, 0, sizeof(IOMMUState)); + + memory_region_init_iommu(&is->iommu, sizeof(is->iommu), + TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev), + "iommu-apb", UINT64_MAX); + address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as"); + pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); + + /* APB secondary busses */ + pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, + TYPE_PBM_PCI_BRIDGE); + s->bridgeB = PCI_BRIDGE(pci_dev); + pci_bridge_map_irq(s->bridgeB, "pciB", pci_pbm_map_irq); + qdev_init_nofail(&pci_dev->qdev); + + pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, + TYPE_PBM_PCI_BRIDGE); + s->bridgeA = PCI_BRIDGE(pci_dev); + pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbm_map_irq); + qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); + qdev_init_nofail(&pci_dev->qdev); +} + +static void pci_pbm_init(Object *obj) +{ + APBState *s = APB_DEVICE(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); unsigned int i; for (i = 0; i < 8; i++) { @@ -734,8 +726,6 @@ static int pci_pbm_init_device(DeviceState *dev) /* at region 2 */ sysbus_init_mmio(sbd, &s->pci_ioport); - - return 0; } static void pbm_pci_host_realize(PCIDevice *d, Error **errp) @@ -774,12 +764,19 @@ static const TypeInfo pbm_pci_host_info = { }, }; +static Property pbm_pci_host_properties[] = { + DEFINE_PROP_UINT64("special-base", APBState, special_base, 0), + DEFINE_PROP_UINT64("mem-base", APBState, mem_base, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void pbm_host_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->init = pci_pbm_init_device; + dc->realize = pci_pbm_realize; dc->reset = pci_pbm_reset; + dc->props = pbm_pci_host_properties; set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } @@ -787,6 +784,7 @@ static const TypeInfo pbm_host_info = { .name = TYPE_APB, .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(APBState), + .instance_init = pci_pbm_init, .class_init = pbm_host_class_init, }; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 47952befcb..0a30fb8d08 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -502,7 +502,11 @@ static void sun4uv_init(MemoryRegion *address_space_mem, prom_init(hwdef->prom_addr, bios_name); - apb = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); + /* Init APB (PCI host bridge) */ + apb = APB_DEVICE(qdev_create(NULL, TYPE_APB)); + qdev_prop_set_uint64(DEVICE(apb), "special-base", APB_SPECIAL_BASE); + qdev_prop_set_uint64(DEVICE(apb), "mem-base", APB_MEM_BASE); + qdev_init_nofail(DEVICE(apb)); /* Wire up PCI interrupts to CPU */ for (i = 0; i < IVEC_MAX; i++) { diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index ae15d8ce59..f0074f7a51 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -62,6 +62,8 @@ typedef struct IOMMUState { typedef struct APBState { PCIHostState parent_obj; + hwaddr special_base; + hwaddr mem_base; MemoryRegion apb_config; MemoryRegion pci_config; MemoryRegion pci_mmio; @@ -93,6 +95,4 @@ typedef struct PBMPCIBridge { #define PBM_PCI_BRIDGE(obj) \ OBJECT_CHECK(PBMPCIBridge, (obj), TYPE_PBM_PCI_BRIDGE) -APBState *pci_apb_init(hwaddr special_base, - hwaddr mem_base); #endif From d9e4d6829c14d3e3d71906b0dc7e7ec9a77654bf Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 495/546] apb: split pci_pbm_map_irq() into separate functions for bus A and bus B After the previous refactoring it is now possible to use separate functions to improve the clarity of the interrupt paths. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko --- hw/pci-host/apb.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 787be744a2..8bdbbfd214 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -517,32 +517,27 @@ static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num) return irq_num; } -static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num) +static int pci_pbmA_map_irq(PCIDevice *pci_dev, int irq_num) { - PBMPCIBridge *br = PBM_PCI_BRIDGE(pci_bridge_get_device( - PCI_BUS(qdev_get_parent_bus(DEVICE(pci_dev))))); - - int bus_offset; - if (br->busA) { - bus_offset = 0x0; - - /* The on-board devices have fixed (legacy) OBIO intnos */ - switch (PCI_SLOT(pci_dev->devfn)) { - case 1: - /* Onboard NIC */ - return 0x21; - case 3: - /* Onboard IDE */ - return 0x20; - - default: - /* Normal intno, fall through */ - break; - } - } else { - bus_offset = 0x10; + /* The on-board devices have fixed (legacy) OBIO intnos */ + switch (PCI_SLOT(pci_dev->devfn)) { + case 1: + /* Onboard NIC */ + return 0x21; + case 3: + /* Onboard IDE */ + return 0x20; + default: + /* Normal intno, fall through */ + break; } - return (bus_offset + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f; + + return ((PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f; +} + +static int pci_pbmB_map_irq(PCIDevice *pci_dev, int irq_num) +{ + return (0x10 + (PCI_SLOT(pci_dev->devfn) << 2) + irq_num) & 0x1f; } static void pci_apb_set_irq(void *opaque, int irq_num, int level) @@ -679,13 +674,13 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, TYPE_PBM_PCI_BRIDGE); s->bridgeB = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(s->bridgeB, "pciB", pci_pbm_map_irq); + pci_bridge_map_irq(s->bridgeB, "pciB", pci_pbmB_map_irq); qdev_init_nofail(&pci_dev->qdev); pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 1), true, TYPE_PBM_PCI_BRIDGE); s->bridgeA = PCI_BRIDGE(pci_dev); - pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbm_map_irq); + pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbmA_map_irq); qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); qdev_init_nofail(&pci_dev->qdev); } From 33c5eb02c4f51515896a5a13cb68f6f01ce8d0af Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 496/546] apb: remove busA property from PBMPCIBridge state Since the previous commit the only remaining use of the qdev busA property is to configure the PCI bridge in front of the onboard ebus devices differently to allow early OpenBIOS serial console access. Instead we can now manually update the PCI configuration for bridge A in pci_pbm_reset() and thus completely remove the busA property from the PBMPCIBridge state. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko --- hw/pci-host/apb.c | 29 +++++++++++++---------------- include/hw/pci-host/apb.h | 3 --- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 8bdbbfd214..5562f1adfd 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -581,18 +581,11 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) * the reset value should be zero unless the boot pin is tied high * (which is true) and thus it should be PCI_COMMAND_MEMORY. */ - uint16_t cmd = PCI_COMMAND_MEMORY; PBMPCIBridge *br = PBM_PCI_BRIDGE(dev); pci_bridge_initfn(dev, TYPE_PCI_BUS); - /* If initialising busA, ensure that we allow IO transactions so that - we get the early serial console until OpenBIOS configures the bridge */ - if (br->busA) { - cmd |= PCI_COMMAND_IO; - } - - pci_set_word(dev->config + PCI_COMMAND, cmd); + pci_set_word(dev->config + PCI_COMMAND, PCI_COMMAND_MEMORY); pci_set_word(dev->config + PCI_STATUS, PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); @@ -608,8 +601,10 @@ static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp) static void pci_pbm_reset(DeviceState *d) { - unsigned int i; APBState *s = APB_DEVICE(d); + PCIDevice *pci_dev; + unsigned int i; + uint16_t cmd; for (i = 0; i < 8; i++) { s->pci_irq_map[i] &= PBM_PCI_IMR_MASK; @@ -625,6 +620,15 @@ static void pci_pbm_reset(DeviceState *d) /* Power on reset */ s->reset_control = POR; } + + /* As this is the busA PCI bridge which contains the on-board devices + * attached to the ebus, ensure that we initially allow IO transactions + * so that we get the early serial console until OpenBIOS can properly + * configure the PCI bridge itself */ + pci_dev = PCI_DEVICE(s->bridgeA); + cmd = pci_get_word(pci_dev->config + PCI_COMMAND); + pci_set_word(pci_dev->config + PCI_COMMAND, cmd | PCI_COMMAND_IO); + pci_bridge_update_mappings(PCI_BRIDGE(pci_dev)); } static const MemoryRegionOps pci_config_ops = { @@ -681,7 +685,6 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) TYPE_PBM_PCI_BRIDGE); s->bridgeA = PCI_BRIDGE(pci_dev); pci_bridge_map_irq(s->bridgeA, "pciA", pci_pbmA_map_irq); - qdev_prop_set_bit(DEVICE(pci_dev), "busA", true); qdev_init_nofail(&pci_dev->qdev); } @@ -783,11 +786,6 @@ static const TypeInfo pbm_host_info = { .class_init = pbm_host_class_init, }; -static Property pbm_pci_properties[] = { - DEFINE_PROP_BOOL("busA", PBMPCIBridge, busA, false), - DEFINE_PROP_END_OF_LIST(), -}; - static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -803,7 +801,6 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_bridge_reset; dc->vmsd = &vmstate_pci_device; - dc->props = pbm_pci_properties; } static const TypeInfo pbm_pci_bridge_info = { diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index f0074f7a51..dd49437ff1 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -86,9 +86,6 @@ typedef struct APBState { typedef struct PBMPCIBridge { /*< private >*/ PCIBridge parent_obj; - - /* Is this busA with in-built devices (ebus)? */ - bool busA; } PBMPCIBridge; #define TYPE_PBM_PCI_BRIDGE "pbm-bridge" From 4b10c8d7012eea39e96819545eb21d28228831c6 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 497/546] ebus: wire up OBIO interrupts to APB pbm via qdev GPIOs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables us to remove the static array mapping in the ISA IRQ handler (and the embedded reference to the APB device) by formalising the interrupt wiring via the qdev GPIO API. For more clarity we replace the APB OBIO interrupt numbers with constants designating the interrupt source, and rename isa_irq_handler() to ebus_isa_irq_handler(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 2 +- hw/sparc64/sun4u.c | 47 ++++++++++++++++++++------------------- include/hw/pci-host/apb.h | 8 ++++++- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 5562f1adfd..54edbddb03 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -703,7 +703,7 @@ static void pci_pbm_init(Object *obj) for (i = 0; i < 32; i++) { s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i; } - s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC); + qdev_init_gpio_in_named(DEVICE(s), pci_apb_set_irq, "pbm-irq", MAX_IVEC); qdev_init_gpio_out_named(DEVICE(s), s->ivec_irqs, "ivec-irq", MAX_IVEC); s->irq_request = NO_IRQ_REQUEST; s->pci_irq_in = 0ULL; diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 0a30fb8d08..1456c3370d 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -86,6 +86,7 @@ typedef struct EbusState { PCIDevice parent_obj; ISABus *isa_bus; + qemu_irq isa_bus_irqs[ISA_NUM_IRQS]; uint64_t console_serial_base; MemoryRegion bar0; MemoryRegion bar1; @@ -211,23 +212,15 @@ typedef struct ResetData { uint64_t prom_addr; } ResetData; -static void isa_irq_handler(void *opaque, int n, int level) +static void ebus_isa_irq_handler(void *opaque, int n, int level) { - static const int isa_irq_to_ivec[16] = { - [1] = 0x29, /* keyboard */ - [4] = 0x2b, /* serial */ - [6] = 0x27, /* floppy */ - [7] = 0x22, /* parallel */ - [12] = 0x2a, /* mouse */ - }; - qemu_irq *irqs = opaque; - int ivec; + EbusState *s = EBUS(opaque); + qemu_irq irq = s->isa_bus_irqs[n]; - assert(n < ARRAY_SIZE(isa_irq_to_ivec)); - ivec = isa_irq_to_ivec[n]; - EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec); - if (ivec) { - qemu_set_irq(irqs[ivec], level); + /* Pass ISA bus IRQs onto their gpio equivalent */ + EBUS_DPRINTF("Set ISA IRQ %d level %d\n", n, level); + if (irq) { + qemu_set_irq(irq, level); } } @@ -235,7 +228,6 @@ static void isa_irq_handler(void *opaque, int n, int level) static void ebus_realize(PCIDevice *pci_dev, Error **errp) { EbusState *s = EBUS(pci_dev); - APBState *apb; DeviceState *dev; qemu_irq *isa_irq; DriveInfo *fd[MAX_FD]; @@ -248,14 +240,11 @@ static void ebus_realize(PCIDevice *pci_dev, Error **errp) return; } - apb = APB_DEVICE(object_resolve_path_type("", TYPE_APB, NULL)); - if (!apb) { - error_setg(errp, "unable to locate APB PCI host bridge"); - return; - } - - isa_irq = qemu_allocate_irqs(isa_irq_handler, apb->pbm_irqs, 16); + /* ISA bus */ + isa_irq = qemu_allocate_irqs(ebus_isa_irq_handler, s, ISA_NUM_IRQS); isa_bus_irqs(s->isa_bus, isa_irq); + qdev_init_gpio_out_named(DEVICE(s), s->isa_bus_irqs, "isa-irq", + ISA_NUM_IRQS); /* Serial ports */ i = 0; @@ -530,6 +519,18 @@ static void sun4uv_init(MemoryRegion *address_space_mem, hwdef->console_serial_base); qdev_init_nofail(DEVICE(ebus)); + /* Wire up "well-known" ISA IRQs to APB legacy obio IRQs */ + qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 7, + qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_LPT_IRQ)); + qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 6, + qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_FDD_IRQ)); + qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 1, + qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_KBD_IRQ)); + qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 12, + qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_MSE_IRQ)); + qdev_connect_gpio_out_named(DEVICE(ebus), "isa-irq", 4, + qdev_get_gpio_in_named(DEVICE(apb), "pbm-irq", OBIO_SER_IRQ)); + pci_dev = pci_create_simple(pci_busA, PCI_DEVFN(2, 0), "VGA"); memset(&macaddr, 0, sizeof(MACAddr)); diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index dd49437ff1..09ebd53f60 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -52,6 +52,13 @@ typedef struct IOMMUState { #define MAX_IVEC 0x40 +/* OBIO IVEC IRQs */ +#define OBIO_LPT_IRQ 0x22 +#define OBIO_FDD_IRQ 0x27 +#define OBIO_KBD_IRQ 0x29 +#define OBIO_MSE_IRQ 0x2a +#define OBIO_SER_IRQ 0x2b + #define TYPE_APB "pbm" #define APB_DEVICE(obj) \ @@ -76,7 +83,6 @@ typedef struct APBState { uint32_t pci_irq_map[8]; uint32_t pci_err_irq_map[4]; uint32_t obio_irq_map[32]; - qemu_irq *pbm_irqs; qemu_irq ivec_irqs[MAX_IVEC]; unsigned int irq_request; uint32_t reset_control; From a5546222e3eafc9b6bc784c1bffbc8e1614d5e5b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 498/546] apb: replace OBIO interrupt numbers in pci_pbmA_map_irq() with constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following on from the previous commit, we can also do the same with with legacy OBIO interrupts in pci_pbmA_map_irq(). Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- hw/pci-host/apb.c | 4 ++-- include/hw/pci-host/apb.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 54edbddb03..44b08c090e 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -523,10 +523,10 @@ static int pci_pbmA_map_irq(PCIDevice *pci_dev, int irq_num) switch (PCI_SLOT(pci_dev->devfn)) { case 1: /* Onboard NIC */ - return 0x21; + return OBIO_NIC_IRQ; case 3: /* Onboard IDE */ - return 0x20; + return OBIO_HDD_IRQ; default: /* Normal intno, fall through */ break; diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 09ebd53f60..6194c8cbad 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -53,6 +53,8 @@ typedef struct IOMMUState { #define MAX_IVEC 0x40 /* OBIO IVEC IRQs */ +#define OBIO_HDD_IRQ 0x20 +#define OBIO_NIC_IRQ 0x21 #define OBIO_LPT_IRQ 0x22 #define OBIO_FDD_IRQ 0x27 #define OBIO_KBD_IRQ 0x29 From 8bcf1c7962c297ea4cf47a8f7400afca38bc270f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 499/546] sparc64: introduce trace-events for hw/sparc64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in preparation for switching code in hw/sparc64 from DPRINTF over to trace events. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé --- Makefile.objs | 1 + hw/sparc64/trace-events | 1 + 2 files changed, 2 insertions(+) create mode 100644 hw/sparc64/trace-events diff --git a/Makefile.objs b/Makefile.objs index 285c6f3c15..c8b1bba593 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -140,6 +140,7 @@ trace-events-subdirs += hw/input trace-events-subdirs += hw/timer trace-events-subdirs += hw/dma trace-events-subdirs += hw/sparc +trace-events-subdirs += hw/sparc64 trace-events-subdirs += hw/sd trace-events-subdirs += hw/isa trace-events-subdirs += hw/mem diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events new file mode 100644 index 0000000000..9284b1fbad --- /dev/null +++ b/hw/sparc64/trace-events @@ -0,0 +1 @@ +# See docs/devel/tracing.txt for syntax documentation. From 69520948e10dde53cb2f49a0c2809847347ae042 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Thu, 21 Dec 2017 07:32:57 +0000 Subject: [PATCH 500/546] sun4u: switch from EBUS_DPRINTF() macro to trace-events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Artyom Tarasenko --- hw/sparc64/sun4u.c | 12 ++---------- hw/sparc64/trace-events | 3 +++ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 1456c3370d..5d802bdfde 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -47,17 +47,9 @@ #include "hw/ide/pci.h" #include "hw/loader.h" #include "elf.h" +#include "trace.h" #include "qemu/cutils.h" -//#define DEBUG_EBUS - -#ifdef DEBUG_EBUS -#define EBUS_DPRINTF(fmt, ...) \ - do { printf("EBUS: " fmt , ## __VA_ARGS__); } while (0) -#else -#define EBUS_DPRINTF(fmt, ...) -#endif - #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define PROM_SIZE_MAX (4 * 1024 * 1024) @@ -218,7 +210,7 @@ static void ebus_isa_irq_handler(void *opaque, int n, int level) qemu_irq irq = s->isa_bus_irqs[n]; /* Pass ISA bus IRQs onto their gpio equivalent */ - EBUS_DPRINTF("Set ISA IRQ %d level %d\n", n, level); + trace_ebus_isa_irq_handler(n, level); if (irq) { qemu_set_irq(irq, level); } diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events index 9284b1fbad..04d80b7f70 100644 --- a/hw/sparc64/trace-events +++ b/hw/sparc64/trace-events @@ -1 +1,4 @@ # See docs/devel/tracing.txt for syntax documentation. + +# hw/sparc64/sun4u.c +ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d" From ba51ef25571c58d09dcfe1f67056b30327dfaa46 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 501/546] sun4m: move sun4m_iommu.c from hw/dma to hw/sparc This seems more appropriate and brings sun4m in line with the other architectures. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/dma/Makefile.objs | 1 - hw/dma/trace-events | 10 ---------- hw/sparc/Makefile.objs | 2 +- hw/{dma => sparc}/sun4m_iommu.c | 11 ++++++----- hw/sparc/trace-events | 10 ++++++++++ 5 files changed, 17 insertions(+), 17 deletions(-) rename hw/{dma => sparc}/sun4m_iommu.c (98%) diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs index 087c8e6855..0b3a009b87 100644 --- a/hw/dma/Makefile.objs +++ b/hw/dma/Makefile.objs @@ -8,7 +8,6 @@ common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o common-obj-$(CONFIG_ZYNQ_DEVCFG) += xlnx-zynq-devcfg.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o common-obj-$(CONFIG_STP2000) += sparc32_dma.o -common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dpdma.o obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o diff --git a/hw/dma/trace-events b/hw/dma/trace-events index 6b367f053b..22f53d0ff2 100644 --- a/hw/dma/trace-events +++ b/hw/dma/trace-events @@ -18,15 +18,5 @@ sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg sparc32_dma_enable_raise(void) "Raise DMA enable" sparc32_dma_enable_lower(void) "Lower DMA enable" -# hw/dma/sun4m_iommu.c -sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" -sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" -sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = 0x%"PRIx64 -sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush 0x%x" -sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush 0x%x" -sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr 0x%"PRIx64" => pte 0x%"PRIx64", *pte = 0x%x" -sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva 0x%"PRIx64" => pa 0x%"PRIx64" iopte = 0x%x" -sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64 - # hw/dma/i8257.c i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d" diff --git a/hw/sparc/Makefile.objs b/hw/sparc/Makefile.objs index c987b5b5df..e2d0828c39 100644 --- a/hw/sparc/Makefile.objs +++ b/hw/sparc/Makefile.objs @@ -1 +1 @@ -obj-y += sun4m.o leon3.o +obj-y += sun4m_iommu.o sun4m.o leon3.o diff --git a/hw/dma/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c similarity index 98% rename from hw/dma/sun4m_iommu.c rename to hw/sparc/sun4m_iommu.c index 30a05e8823..72a9af555f 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/sparc/sun4m_iommu.c @@ -125,7 +125,7 @@ #define IOMMU_PAGE_SHIFT 12 #define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT) -#define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1) +#define IOMMU_PAGE_MASK (~(IOMMU_PAGE_SIZE - 1)) static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) @@ -218,8 +218,8 @@ static void iommu_mem_write(void *opaque, hwaddr addr, s->regs[saddr] = val & IOMMU_SBCFG_MASK; break; case IOMMU_ARBEN: - // XXX implement SBus probing: fault when reading unmapped - // addresses, fault cause and address stored to MMU/IOMMU + /* XXX implement SBus probing: fault when reading unmapped + addresses, fault cause and address stored to MMU/IOMMU */ s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; break; case IOMMU_MASK_ID: @@ -272,8 +272,9 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr, trace_sun4m_iommu_bad_addr(addr); s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV | IOMMU_AFSR_FAV; - if (!is_write) + if (!is_write) { s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD; + } s->regs[IOMMU_AFAR] = addr; qemu_irq_raise(s->irq); } @@ -322,7 +323,7 @@ static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu, } static const VMStateDescription vmstate_iommu = { - .name ="iommu", + .name = "iommu", .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { diff --git a/hw/sparc/trace-events b/hw/sparc/trace-events index efd765cbe6..6e7259f8f8 100644 --- a/hw/sparc/trace-events +++ b/hw/sparc/trace-events @@ -6,6 +6,16 @@ sun4m_cpu_reset_interrupt(unsigned int level) "Reset CPU IRQ %d" sun4m_cpu_set_irq_raise(int level) "Raise CPU IRQ %d" sun4m_cpu_set_irq_lower(int level) "Lower CPU IRQ %d" +# hw/sparc/sun4m_iommu.c +sun4m_iommu_mem_readl(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" +sun4m_iommu_mem_writel(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" +sun4m_iommu_mem_writel_ctrl(uint64_t iostart) "iostart = 0x%"PRIx64 +sun4m_iommu_mem_writel_tlbflush(uint32_t val) "tlb flush 0x%x" +sun4m_iommu_mem_writel_pgflush(uint32_t val) "page flush 0x%x" +sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "get flags addr 0x%"PRIx64" => pte 0x%"PRIx64", *pte = 0x%x" +sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva 0x%"PRIx64" => pa 0x%"PRIx64" iopte = 0x%x" +sun4m_iommu_bad_addr(uint64_t addr) "bad addr 0x%"PRIx64 + # hw/sparc/leon3.c leon3_set_irq(int intno) "Set CPU IRQ %d" leon3_reset_irq(int intno) "Reset CPU IRQ %d" From 1527f4886c88c8ac7faf507122580e964c2259a7 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 502/546] sun4m: move IOMMU declarations from sun4m.h to sun4m_iommu.h Also updating the relevant .c files as required. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/dma/sparc32_dma.c | 1 + hw/sparc/sun4m.c | 1 + hw/sparc/sun4m_iommu.c | 1 + include/hw/sparc/sun4m.h | 21 -------------- include/hw/sparc/sun4m_iommu.h | 51 ++++++++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 include/hw/sparc/sun4m_iommu.h diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 01afb758b6..c04ad79305 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -29,6 +29,7 @@ #include "hw/hw.h" #include "hw/sparc/sparc32_dma.h" #include "hw/sparc/sun4m.h" +#include "hw/sparc/sun4m_iommu.h" #include "hw/sysbus.h" #include "sysemu/dma.h" #include "qapi/error.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index e71648404c..efaff5849d 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/timer.h" #include "hw/sparc/sun4m.h" +#include "hw/sparc/sun4m_iommu.h" #include "hw/timer/m48t59.h" #include "hw/sparc/sparc32_dma.h" #include "hw/block/fdc.h" diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c index 72a9af555f..311c82d2bb 100644 --- a/hw/sparc/sun4m_iommu.c +++ b/hw/sparc/sun4m_iommu.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "hw/sparc/sun4m.h" +#include "hw/sparc/sun4m_iommu.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" #include "trace.h" diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index c557b0dd53..9e06467ac2 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -8,27 +8,6 @@ /* Devices used by sparc32 system. */ -/* iommu.c */ -#define TYPE_SUN4M_IOMMU "sun4m-iommu" -#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) - -#define TYPE_SUN4M_IOMMU_MEMORY_REGION "sun4m-iommu-memory-region" - -#define IOMMU_NREGS (4 * 4096 / 4) - -typedef struct IOMMUState { - SysBusDevice parent_obj; - - AddressSpace iommu_as; - IOMMUMemoryRegion iommu; - - MemoryRegion iomem; - uint32_t regs[IOMMU_NREGS]; - hwaddr iostart; - qemu_irq irq; - uint32_t version; -} IOMMUState; - /* sparc32_dma.c */ #include "hw/sparc/sparc32_dma.h" diff --git a/include/hw/sparc/sun4m_iommu.h b/include/hw/sparc/sun4m_iommu.h new file mode 100644 index 0000000000..938937eb04 --- /dev/null +++ b/include/hw/sparc/sun4m_iommu.h @@ -0,0 +1,51 @@ +/* + * QEMU Sun4m iommu emulation + * + * Copyright (c) 2003-2005 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SUN4M_IOMMU_H +#define SUN4M_IOMMU_H + +#include "qemu-common.h" +#include "hw/sysbus.h" + +#define IOMMU_NREGS (4 * 4096 / 4) + +typedef struct IOMMUState { + SysBusDevice parent_obj; + + AddressSpace iommu_as; + IOMMUMemoryRegion iommu; + + MemoryRegion iomem; + uint32_t regs[IOMMU_NREGS]; + hwaddr iostart; + qemu_irq irq; + uint32_t version; +} IOMMUState; + +#define TYPE_SUN4M_IOMMU "sun4m-iommu" +#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) + +#define TYPE_SUN4M_IOMMU_MEMORY_REGION "sun4m-iommu-memory-region" + +#endif From f5980f757c028ec68ff8442c418db8462415af2a Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 503/546] sun4m: remove include/hw/sparc/sun4m.h and all references to it With the previous commit there is now nothing left in sun4m.h so it can be removed, along with all remaining references to it. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/dma/sparc32_dma.c | 1 - hw/intc/slavio_intctl.c | 1 - hw/net/lance.c | 2 +- hw/sparc/sun4m.c | 1 - hw/sparc/sun4m_iommu.c | 1 - hw/timer/slavio_timer.c | 1 - include/hw/sparc/sun4m.h | 14 -------------- 7 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 include/hw/sparc/sun4m.h diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index c04ad79305..7b00a27de6 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "hw/sparc/sparc32_dma.h" -#include "hw/sparc/sun4m.h" #include "hw/sparc/sun4m_iommu.h" #include "hw/sysbus.h" #include "sysemu/dma.h" diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index 84e0bee4a9..817e02617e 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "hw/sparc/sun4m.h" #include "monitor/monitor.h" #include "hw/sysbus.h" #include "hw/intc/intc.h" diff --git a/hw/net/lance.c b/hw/net/lance.c index 23929fd1e6..0028bc525d 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -40,7 +40,7 @@ #include "net/net.h" #include "qemu/timer.h" #include "qemu/sockets.h" -#include "hw/sparc/sun4m.h" +#include "hw/sparc/sparc32_dma.h" #include "hw/net/lance.h" #include "trace.h" #include "sysemu/sysemu.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index efaff5849d..dd0038095b 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -28,7 +28,6 @@ #include "hw/sysbus.h" #include "qemu/error-report.h" #include "qemu/timer.h" -#include "hw/sparc/sun4m.h" #include "hw/sparc/sun4m_iommu.h" #include "hw/timer/m48t59.h" #include "hw/sparc/sparc32_dma.h" diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c index 311c82d2bb..b677601fc6 100644 --- a/hw/sparc/sun4m_iommu.c +++ b/hw/sparc/sun4m_iommu.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "hw/sparc/sun4m.h" #include "hw/sparc/sun4m_iommu.h" #include "hw/sysbus.h" #include "exec/address-spaces.h" diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index a8cc9c0148..4694b653a7 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -23,7 +23,6 @@ */ #include "qemu/osdep.h" -#include "hw/sparc/sun4m.h" #include "qemu/timer.h" #include "hw/ptimer.h" #include "hw/sysbus.h" diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h deleted file mode 100644 index 9e06467ac2..0000000000 --- a/include/hw/sparc/sun4m.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef SUN4M_H -#define SUN4M_H - -#include "qemu-common.h" -#include "exec/hwaddr.h" -#include "qapi/qmp/types.h" -#include "hw/sysbus.h" - -/* Devices used by sparc32 system. */ - -/* sparc32_dma.c */ -#include "hw/sparc/sparc32_dma.h" - -#endif From aea5b071012d3507885724362913d0b71dd6c303 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 504/546] apb: QOMify IOMMU This is in preparation to split the IOMMU device out of the APB. As part of this commit we also enforce separation of the IOMMU and APB devices by using a QOM object link to pass the IOMMU reference and accessing the IOMMU registers via a separate memory region mapped into the APB config space rather than directly. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/pci-host/apb.c | 77 +++++++++++++++++++++++++++++---------- hw/sparc64/sun4u.c | 7 +++- include/hw/pci-host/apb.h | 8 +++- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 44b08c090e..060e6e6d1c 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -36,6 +36,7 @@ #include "hw/pci-host/apb.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" +#include "qapi/error.h" #include "qemu/log.h" /* debug APB */ @@ -250,8 +251,8 @@ static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, return ret; } -static void iommu_config_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) +static void iommu_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) { IOMMUState *is = opaque; @@ -295,7 +296,7 @@ static void iommu_config_write(void *opaque, hwaddr addr, } } -static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) { IOMMUState *is = opaque; uint64_t val; @@ -344,7 +345,6 @@ static void apb_config_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { APBState *s = opaque; - IOMMUState *is = &s->iommu; APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val); @@ -352,9 +352,6 @@ static void apb_config_writel (void *opaque, hwaddr addr, case 0x30 ... 0x4f: /* DMA error registers */ /* XXX: not implemented yet */ break; - case 0x200 ... 0x217: /* IOMMU */ - iommu_config_write(is, (addr & 0x1f), val, size); - break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { unsigned int ino = (addr & 0x3f) >> 3; @@ -426,7 +423,6 @@ static uint64_t apb_config_readl (void *opaque, hwaddr addr, unsigned size) { APBState *s = opaque; - IOMMUState *is = &s->iommu; uint32_t val; switch (addr & 0xffff) { @@ -434,9 +430,6 @@ static uint64_t apb_config_readl (void *opaque, val = 0; /* XXX: not implemented yet */ break; - case 0x200 ... 0x217: /* IOMMU */ - val = iommu_config_read(is, (addr & 0x1f), size); - break; case 0xc00 ... 0xc3f: /* PCI interrupt control */ if (addr & 4) { val = s->pci_irq_map[(addr & 0x3f) >> 3]; @@ -643,7 +636,6 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) PCIHostState *phb = PCI_HOST_BRIDGE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(s); PCIDevice *pci_dev; - IOMMUState *is; /* apb_config */ sysbus_mmio_map(sbd, 0, s->special_base); @@ -665,14 +657,9 @@ static void pci_pbm_realize(DeviceState *dev, Error **errp) pci_create_simple(phb->bus, 0, "pbm-pci"); /* APB IOMMU */ - is = &s->iommu; - memset(is, 0, sizeof(IOMMUState)); - - memory_region_init_iommu(&is->iommu, sizeof(is->iommu), - TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(dev), - "iommu-apb", UINT64_MAX); - address_space_init(&is->iommu_as, MEMORY_REGION(&is->iommu), "pbm-as"); - pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, is); + memory_region_add_subregion_overlap(&s->apb_config, 0x200, + sysbus_mmio_get_region(SYS_BUS_DEVICE(s->iommu), 0), 1); + pci_setup_iommu(phb->bus, pbm_pci_dma_iommu, s->iommu); /* APB secondary busses */ pci_dev = pci_create_multifunction(phb->bus, PCI_DEVFN(1, 0), true, @@ -708,6 +695,12 @@ static void pci_pbm_init(Object *obj) s->irq_request = NO_IRQ_REQUEST; s->pci_irq_in = 0ULL; + /* IOMMU */ + object_property_add_link(obj, "iommu", TYPE_SUN4U_IOMMU, + (Object **) &s->iommu, + qdev_prop_allow_set_link_before_realize, + 0, NULL); + /* apb_config */ memory_region_init_io(&s->apb_config, OBJECT(s), &apb_config_ops, s, "apb-config", 0x10000); @@ -814,6 +807,49 @@ static const TypeInfo pbm_pci_bridge_info = { }, }; +static const MemoryRegionOps iommu_mem_ops = { + .read = iommu_mem_read, + .write = iommu_mem_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void iommu_reset(DeviceState *d) +{ + IOMMUState *s = SUN4U_IOMMU(d); + + memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t)); +} + +static void iommu_init(Object *obj) +{ + IOMMUState *s = SUN4U_IOMMU(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_iommu(&s->iommu, sizeof(s->iommu), + TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(s), + "iommu-apb", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "pbm-as"); + + memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", + IOMMU_NREGS * sizeof(uint64_t)); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void iommu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = iommu_reset; +} + +static const TypeInfo pbm_iommu_info = { + .name = TYPE_SUN4U_IOMMU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOMMUState), + .instance_init = iommu_init, + .class_init = iommu_class_init, +}; + static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); @@ -832,6 +868,7 @@ static void pbm_register_types(void) type_register_static(&pbm_host_info); type_register_static(&pbm_pci_host_info); type_register_static(&pbm_pci_bridge_info); + type_register_static(&pbm_iommu_info); type_register_static(&pbm_iommu_memory_region_info); } diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 5d802bdfde..aaee3de03a 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -469,7 +469,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, PCIDevice *ebus, *pci_dev; SysBusDevice *s; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; - DeviceState *dev; + DeviceState *iommu, *dev; FWCfgState *fw_cfg; NICInfo *nd; MACAddr macaddr; @@ -478,6 +478,10 @@ static void sun4uv_init(MemoryRegion *address_space_mem, /* init CPUs */ cpu = sparc64_cpu_devinit(machine->cpu_type, hwdef->prom_addr); + /* IOMMU */ + iommu = qdev_create(NULL, TYPE_SUN4U_IOMMU); + qdev_init_nofail(iommu); + /* set up devices */ ram_init(0, machine->ram_size); @@ -487,6 +491,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, apb = APB_DEVICE(qdev_create(NULL, TYPE_APB)); qdev_prop_set_uint64(DEVICE(apb), "special-base", APB_SPECIAL_BASE); qdev_prop_set_uint64(DEVICE(apb), "mem-base", APB_MEM_BASE); + object_property_set_link(OBJECT(apb), OBJECT(iommu), "iommu", &error_abort); qdev_init_nofail(DEVICE(apb)); /* Wire up PCI interrupts to CPU */ diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 6194c8cbad..33dbc7a8cb 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -44,12 +44,18 @@ #define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL typedef struct IOMMUState { + SysBusDevice parent_obj; + AddressSpace iommu_as; IOMMUMemoryRegion iommu; + MemoryRegion iomem; uint64_t regs[IOMMU_NREGS]; } IOMMUState; +#define TYPE_SUN4U_IOMMU "sun4u-iommu" +#define SUN4U_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4U_IOMMU) + #define MAX_IVEC 0x40 /* OBIO IVEC IRQs */ @@ -78,7 +84,7 @@ typedef struct APBState { MemoryRegion pci_mmio; MemoryRegion pci_ioport; uint64_t pci_irq_in; - IOMMUState iommu; + IOMMUState *iommu; PCIBridge *bridgeA; PCIBridge *bridgeB; uint32_t pci_control[16]; From 0ea833c24999093be6369f9145333bd10acfad76 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 505/546] sun4u: split IOMMU device out from apb.c to sun4u_iommu.c By separating the sun4u IOMMU device into new sun4u_iommu.c and sun4m_iommu.h files we noticeably simplify apb.c whilst bringing sun4u in line with all the other IOMMU-supporting architectures. Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/pci-host/apb.c | 273 ------------------------- hw/sparc64/Makefile.objs | 1 + hw/sparc64/sun4u.c | 1 + hw/sparc64/sun4u_iommu.c | 350 +++++++++++++++++++++++++++++++++ include/hw/pci-host/apb.h | 57 +----- include/hw/sparc/sun4u_iommu.h | 50 +++++ 6 files changed, 403 insertions(+), 329 deletions(-) create mode 100644 hw/sparc64/sun4u_iommu.c create mode 100644 include/hw/sparc/sun4u_iommu.h diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 060e6e6d1c..3e796fb6fc 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -49,16 +49,6 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0) #define APB_DPRINTF(fmt, ...) #endif -/* debug IOMMU */ -//#define DEBUG_IOMMU - -#ifdef DEBUG_IOMMU -#define IOMMU_DPRINTF(fmt, ...) \ -do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define IOMMU_DPRINTF(fmt, ...) -#endif - /* * Chipset docs: * PBM: "UltraSPARC IIi User's Manual", @@ -136,211 +126,6 @@ static AddressSpace *pbm_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) return &is->iommu_as; } -/* Called from RCU critical section */ -static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, - IOMMUAccessFlags flag) -{ - IOMMUState *is = container_of(iommu, IOMMUState, iommu); - hwaddr baseaddr, offset; - uint64_t tte; - uint32_t tsbsize; - IOMMUTLBEntry ret = { - .target_as = &address_space_memory, - .iova = 0, - .translated_addr = 0, - .addr_mask = ~(hwaddr)0, - .perm = IOMMU_NONE, - }; - - if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) { - /* IOMMU disabled, passthrough using standard 8K page */ - ret.iova = addr & IOMMU_PAGE_MASK_8K; - ret.translated_addr = addr; - ret.addr_mask = IOMMU_PAGE_MASK_8K; - ret.perm = IOMMU_RW; - - return ret; - } - - baseaddr = is->regs[IOMMU_BASE >> 3]; - tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7; - - if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) { - /* 64K */ - switch (tsbsize) { - case 0: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13; - break; - case 1: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13; - break; - case 2: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13; - break; - case 3: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13; - break; - case 4: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13; - break; - case 5: - offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13; - break; - default: - /* Not implemented, error */ - return ret; - } - } else { - /* 8K */ - switch (tsbsize) { - case 0: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10; - break; - case 1: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10; - break; - case 2: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10; - break; - case 3: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10; - break; - case 4: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10; - break; - case 5: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10; - break; - case 6: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10; - break; - case 7: - offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10; - break; - } - } - - tte = address_space_ldq_be(&address_space_memory, baseaddr + offset, - MEMTXATTRS_UNSPECIFIED, NULL); - - if (!(tte & IOMMU_TTE_DATA_V)) { - /* Invalid mapping */ - return ret; - } - - if (tte & IOMMU_TTE_DATA_W) { - /* Writeable */ - ret.perm = IOMMU_RW; - } else { - ret.perm = IOMMU_RO; - } - - /* Extract phys */ - if (tte & IOMMU_TTE_DATA_SIZE) { - /* 64K */ - ret.iova = addr & IOMMU_PAGE_MASK_64K; - ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K; - ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1); - } else { - /* 8K */ - ret.iova = addr & IOMMU_PAGE_MASK_8K; - ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K; - ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1); - } - - return ret; -} - -static void iommu_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - IOMMUState *is = opaque; - - IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64 - " size: %d\n", addr, val, size); - - switch (addr) { - case IOMMU_CTRL: - if (size == 4) { - is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL; - is->regs[IOMMU_CTRL >> 3] |= val << 32; - } else { - is->regs[IOMMU_CTRL >> 3] = val; - } - break; - case IOMMU_CTRL + 0x4: - is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL; - is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL; - break; - case IOMMU_BASE: - if (size == 4) { - is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL; - is->regs[IOMMU_BASE >> 3] |= val << 32; - } else { - is->regs[IOMMU_BASE >> 3] = val; - } - break; - case IOMMU_BASE + 0x4: - is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL; - is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL; - break; - case IOMMU_FLUSH: - case IOMMU_FLUSH + 0x4: - break; - default: - qemu_log_mask(LOG_UNIMP, - "apb iommu: Unimplemented register write " - "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n", - addr, size, val); - break; - } -} - -static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) -{ - IOMMUState *is = opaque; - uint64_t val; - - switch (addr) { - case IOMMU_CTRL: - if (size == 4) { - val = is->regs[IOMMU_CTRL >> 3] >> 32; - } else { - val = is->regs[IOMMU_CTRL >> 3]; - } - break; - case IOMMU_CTRL + 0x4: - val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL; - break; - case IOMMU_BASE: - if (size == 4) { - val = is->regs[IOMMU_BASE >> 3] >> 32; - } else { - val = is->regs[IOMMU_BASE >> 3]; - } - break; - case IOMMU_BASE + 0x4: - val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL; - break; - case IOMMU_FLUSH: - case IOMMU_FLUSH + 0x4: - val = 0; - break; - default: - qemu_log_mask(LOG_UNIMP, - "apb iommu: Unimplemented register read " - "reg 0x%" HWADDR_PRIx " size 0x%x\n", - addr, size); - val = 0; - break; - } - - IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64 - " size: %d\n", addr, val, size); - - return val; -} - static void apb_config_writel (void *opaque, hwaddr addr, uint64_t val, unsigned size) { @@ -807,69 +592,11 @@ static const TypeInfo pbm_pci_bridge_info = { }, }; -static const MemoryRegionOps iommu_mem_ops = { - .read = iommu_mem_read, - .write = iommu_mem_write, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static void iommu_reset(DeviceState *d) -{ - IOMMUState *s = SUN4U_IOMMU(d); - - memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t)); -} - -static void iommu_init(Object *obj) -{ - IOMMUState *s = SUN4U_IOMMU(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - memory_region_init_iommu(&s->iommu, sizeof(s->iommu), - TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(s), - "iommu-apb", UINT64_MAX); - address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "pbm-as"); - - memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", - IOMMU_NREGS * sizeof(uint64_t)); - sysbus_init_mmio(sbd, &s->iomem); -} - -static void iommu_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = iommu_reset; -} - -static const TypeInfo pbm_iommu_info = { - .name = TYPE_SUN4U_IOMMU, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IOMMUState), - .instance_init = iommu_init, - .class_init = iommu_class_init, -}; - -static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) -{ - IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); - - imrc->translate = pbm_translate_iommu; -} - -static const TypeInfo pbm_iommu_memory_region_info = { - .parent = TYPE_IOMMU_MEMORY_REGION, - .name = TYPE_APB_IOMMU_MEMORY_REGION, - .class_init = pbm_iommu_memory_region_class_init, -}; - static void pbm_register_types(void) { type_register_static(&pbm_host_info); type_register_static(&pbm_pci_host_info); type_register_static(&pbm_pci_bridge_info); - type_register_static(&pbm_iommu_info); - type_register_static(&pbm_iommu_memory_region_info); } type_init(pbm_register_types) diff --git a/hw/sparc64/Makefile.objs b/hw/sparc64/Makefile.objs index cf9de21133..117e0ff27d 100644 --- a/hw/sparc64/Makefile.objs +++ b/hw/sparc64/Makefile.objs @@ -1,3 +1,4 @@ obj-y += sparc64.o +obj-y += sun4u_iommu.o obj-y += sun4u.o obj-y += niagara.o \ No newline at end of file diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index aaee3de03a..ec45ec2801 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -29,6 +29,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_bus.h" +#include "hw/pci/pci_host.h" #include "hw/pci-host/apb.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c new file mode 100644 index 0000000000..e5aa817edb --- /dev/null +++ b/hw/sparc64/sun4u_iommu.c @@ -0,0 +1,350 @@ +/* + * QEMU sun4u IOMMU emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2012,2013 Artyom Tarasenko + * Copyright (c) 2017 Mark Cave-Ayland + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/sparc/sun4u_iommu.h" +#include "exec/address-spaces.h" +#include "qapi/error.h" +#include "qemu/log.h" + +/* debug IOMMU */ +//#define DEBUG_IOMMU + +#ifdef DEBUG_IOMMU +#define IOMMU_DPRINTF(fmt, ...) \ +do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) +#else +#define IOMMU_DPRINTF(fmt, ...) +#endif + + +#define IOMMU_PAGE_SIZE_8K (1ULL << 13) +#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) +#define IOMMU_PAGE_SIZE_64K (1ULL << 16) +#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1)) + +#define IOMMU_CTRL 0x0 +#define IOMMU_CTRL_TBW_SIZE (1ULL << 2) +#define IOMMU_CTRL_MMU_EN (1ULL) + +#define IOMMU_CTRL_TSB_SHIFT 16 + +#define IOMMU_BASE 0x8 +#define IOMMU_FLUSH 0x10 + +#define IOMMU_TTE_DATA_V (1ULL << 63) +#define IOMMU_TTE_DATA_SIZE (1ULL << 61) +#define IOMMU_TTE_DATA_W (1ULL << 1) + +#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL +#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL + +#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL +#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL + +#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL +#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL + + +/* Called from RCU critical section */ +static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, + IOMMUAccessFlags flag) +{ + IOMMUState *is = container_of(iommu, IOMMUState, iommu); + hwaddr baseaddr, offset; + uint64_t tte; + uint32_t tsbsize; + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = 0, + .translated_addr = 0, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE, + }; + + if (!(is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_MMU_EN)) { + /* IOMMU disabled, passthrough using standard 8K page */ + ret.iova = addr & IOMMU_PAGE_MASK_8K; + ret.translated_addr = addr; + ret.addr_mask = IOMMU_PAGE_MASK_8K; + ret.perm = IOMMU_RW; + + return ret; + } + + baseaddr = is->regs[IOMMU_BASE >> 3]; + tsbsize = (is->regs[IOMMU_CTRL >> 3] >> IOMMU_CTRL_TSB_SHIFT) & 0x7; + + if (is->regs[IOMMU_CTRL >> 3] & IOMMU_CTRL_TBW_SIZE) { + /* 64K */ + switch (tsbsize) { + case 0: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_64M) >> 13; + break; + case 1: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_128M) >> 13; + break; + case 2: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_256M) >> 13; + break; + case 3: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_512M) >> 13; + break; + case 4: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_1G) >> 13; + break; + case 5: + offset = (addr & IOMMU_TSB_64K_OFFSET_MASK_2G) >> 13; + break; + default: + /* Not implemented, error */ + return ret; + } + } else { + /* 8K */ + switch (tsbsize) { + case 0: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_8M) >> 10; + break; + case 1: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_16M) >> 10; + break; + case 2: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_32M) >> 10; + break; + case 3: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_64M) >> 10; + break; + case 4: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_128M) >> 10; + break; + case 5: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_256M) >> 10; + break; + case 6: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_512M) >> 10; + break; + case 7: + offset = (addr & IOMMU_TSB_8K_OFFSET_MASK_1G) >> 10; + break; + } + } + + tte = address_space_ldq_be(&address_space_memory, baseaddr + offset, + MEMTXATTRS_UNSPECIFIED, NULL); + + if (!(tte & IOMMU_TTE_DATA_V)) { + /* Invalid mapping */ + return ret; + } + + if (tte & IOMMU_TTE_DATA_W) { + /* Writeable */ + ret.perm = IOMMU_RW; + } else { + ret.perm = IOMMU_RO; + } + + /* Extract phys */ + if (tte & IOMMU_TTE_DATA_SIZE) { + /* 64K */ + ret.iova = addr & IOMMU_PAGE_MASK_64K; + ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_64K; + ret.addr_mask = (IOMMU_PAGE_SIZE_64K - 1); + } else { + /* 8K */ + ret.iova = addr & IOMMU_PAGE_MASK_8K; + ret.translated_addr = tte & IOMMU_TTE_PHYS_MASK_8K; + ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1); + } + + return ret; +} + +static void iommu_mem_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + IOMMUState *is = opaque; + + IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64 + " size: %d\n", addr, val, size); + + switch (addr) { + case IOMMU_CTRL: + if (size == 4) { + is->regs[IOMMU_CTRL >> 3] &= 0xffffffffULL; + is->regs[IOMMU_CTRL >> 3] |= val << 32; + } else { + is->regs[IOMMU_CTRL >> 3] = val; + } + break; + case IOMMU_CTRL + 0x4: + is->regs[IOMMU_CTRL >> 3] &= 0xffffffff00000000ULL; + is->regs[IOMMU_CTRL >> 3] |= val & 0xffffffffULL; + break; + case IOMMU_BASE: + if (size == 4) { + is->regs[IOMMU_BASE >> 3] &= 0xffffffffULL; + is->regs[IOMMU_BASE >> 3] |= val << 32; + } else { + is->regs[IOMMU_BASE >> 3] = val; + } + break; + case IOMMU_BASE + 0x4: + is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL; + is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL; + break; + case IOMMU_FLUSH: + case IOMMU_FLUSH + 0x4: + break; + default: + qemu_log_mask(LOG_UNIMP, + "apb iommu: Unimplemented register write " + "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n", + addr, size, val); + break; + } +} + +static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) +{ + IOMMUState *is = opaque; + uint64_t val; + + switch (addr) { + case IOMMU_CTRL: + if (size == 4) { + val = is->regs[IOMMU_CTRL >> 3] >> 32; + } else { + val = is->regs[IOMMU_CTRL >> 3]; + } + break; + case IOMMU_CTRL + 0x4: + val = is->regs[IOMMU_CTRL >> 3] & 0xffffffffULL; + break; + case IOMMU_BASE: + if (size == 4) { + val = is->regs[IOMMU_BASE >> 3] >> 32; + } else { + val = is->regs[IOMMU_BASE >> 3]; + } + break; + case IOMMU_BASE + 0x4: + val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL; + break; + case IOMMU_FLUSH: + case IOMMU_FLUSH + 0x4: + val = 0; + break; + default: + qemu_log_mask(LOG_UNIMP, + "apb iommu: Unimplemented register read " + "reg 0x%" HWADDR_PRIx " size 0x%x\n", + addr, size); + val = 0; + break; + } + + IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64 + " size: %d\n", addr, val, size); + + return val; +} + +static const MemoryRegionOps iommu_mem_ops = { + .read = iommu_mem_read, + .write = iommu_mem_write, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static void iommu_reset(DeviceState *d) +{ + IOMMUState *s = SUN4U_IOMMU(d); + + memset(s->regs, 0, IOMMU_NREGS * sizeof(uint64_t)); +} + +static void iommu_init(Object *obj) +{ + IOMMUState *s = SUN4U_IOMMU(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_iommu(&s->iommu, sizeof(s->iommu), + TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(s), + "iommu-apb", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "pbm-as"); + + memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", + IOMMU_NREGS * sizeof(uint64_t)); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void iommu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = iommu_reset; +} + +static const TypeInfo pbm_iommu_info = { + .name = TYPE_SUN4U_IOMMU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IOMMUState), + .instance_init = iommu_init, + .class_init = iommu_class_init, +}; + +static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = pbm_translate_iommu; +} + +static const TypeInfo pbm_iommu_memory_region_info = { + .parent = TYPE_IOMMU_MEMORY_REGION, + .name = TYPE_APB_IOMMU_MEMORY_REGION, + .class_init = pbm_iommu_memory_region_class_init, +}; + +static void pbm_register_types(void) +{ + type_register_static(&pbm_iommu_info); + type_register_static(&pbm_iommu_memory_region_info); +} + +type_init(pbm_register_types) diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h index 33dbc7a8cb..604d899b1e 100644 --- a/include/hw/pci-host/apb.h +++ b/include/hw/pci-host/apb.h @@ -1,60 +1,7 @@ #ifndef PCI_HOST_APB_H #define PCI_HOST_APB_H -#include "qemu-common.h" -#include "hw/pci/pci_host.h" - -#define IOMMU_NREGS 3 - -#define IOMMU_PAGE_SIZE_8K (1ULL << 13) -#define IOMMU_PAGE_MASK_8K (~(IOMMU_PAGE_SIZE_8K - 1)) -#define IOMMU_PAGE_SIZE_64K (1ULL << 16) -#define IOMMU_PAGE_MASK_64K (~(IOMMU_PAGE_SIZE_64K - 1)) - -#define IOMMU_CTRL 0x0 -#define IOMMU_CTRL_TBW_SIZE (1ULL << 2) -#define IOMMU_CTRL_MMU_EN (1ULL) - -#define IOMMU_CTRL_TSB_SHIFT 16 - -#define IOMMU_BASE 0x8 -#define IOMMU_FLUSH 0x10 - -#define IOMMU_TTE_DATA_V (1ULL << 63) -#define IOMMU_TTE_DATA_SIZE (1ULL << 61) -#define IOMMU_TTE_DATA_W (1ULL << 1) - -#define IOMMU_TTE_PHYS_MASK_8K 0x1ffffffe000ULL -#define IOMMU_TTE_PHYS_MASK_64K 0x1ffffff8000ULL - -#define IOMMU_TSB_8K_OFFSET_MASK_8M 0x00000000007fe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_16M 0x0000000000ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_32M 0x0000000001ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_64M 0x0000000003ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_128M 0x0000000007ffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_256M 0x000000000fffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_512M 0x000000001fffe000ULL -#define IOMMU_TSB_8K_OFFSET_MASK_1G 0x000000003fffe000ULL - -#define IOMMU_TSB_64K_OFFSET_MASK_64M 0x0000000003ff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_128M 0x0000000007ff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_256M 0x000000000fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_512M 0x000000001fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_1G 0x000000003fff0000ULL -#define IOMMU_TSB_64K_OFFSET_MASK_2G 0x000000007fff0000ULL - -typedef struct IOMMUState { - SysBusDevice parent_obj; - - AddressSpace iommu_as; - IOMMUMemoryRegion iommu; - - MemoryRegion iomem; - uint64_t regs[IOMMU_NREGS]; -} IOMMUState; - -#define TYPE_SUN4U_IOMMU "sun4u-iommu" -#define SUN4U_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4U_IOMMU) +#include "hw/sparc/sun4u_iommu.h" #define MAX_IVEC 0x40 @@ -72,8 +19,6 @@ typedef struct IOMMUState { #define APB_DEVICE(obj) \ OBJECT_CHECK(APBState, (obj), TYPE_APB) -#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region" - typedef struct APBState { PCIHostState parent_obj; diff --git a/include/hw/sparc/sun4u_iommu.h b/include/hw/sparc/sun4u_iommu.h new file mode 100644 index 0000000000..bc4506b5b0 --- /dev/null +++ b/include/hw/sparc/sun4u_iommu.h @@ -0,0 +1,50 @@ +/* + * QEMU sun4u IOMMU emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2012,2013 Artyom Tarasenko + * Copyright (c) 2017 Mark Cave-Ayland + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef SUN4U_IOMMU_H +#define SUN4U_IOMMU_H + +#include "qemu-common.h" +#include "hw/sysbus.h" + +#define IOMMU_NREGS 3 + +typedef struct IOMMUState { + SysBusDevice parent_obj; + + AddressSpace iommu_as; + IOMMUMemoryRegion iommu; + + MemoryRegion iomem; + uint64_t regs[IOMMU_NREGS]; +} IOMMUState; + +#define TYPE_SUN4U_IOMMU "sun4u-iommu" +#define SUN4U_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4U_IOMMU) + +#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region" + +#endif From 4c9fbc38e3559d7540c8bd5cf76915dd21ccad7f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 506/546] sun4u_iommu: update to reflect IOMMU is no longer part of the APB device Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/sparc64/sun4u_iommu.c | 35 +++++++++++++++++----------------- include/hw/sparc/sun4u_iommu.h | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index e5aa817edb..612fec4c64 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -81,8 +81,9 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) /* Called from RCU critical section */ -static IOMMUTLBEntry pbm_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, - IOMMUAccessFlags flag) +static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu, + hwaddr addr, + IOMMUAccessFlags flag) { IOMMUState *is = container_of(iommu, IOMMUState, iommu); hwaddr baseaddr, offset; @@ -233,7 +234,7 @@ static void iommu_mem_write(void *opaque, hwaddr addr, break; default: qemu_log_mask(LOG_UNIMP, - "apb iommu: Unimplemented register write " + "sun4u-iommu: Unimplemented register write " "reg 0x%" HWADDR_PRIx " size 0x%x value 0x%" PRIx64 "\n", addr, size, val); break; @@ -272,7 +273,7 @@ static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) break; default: qemu_log_mask(LOG_UNIMP, - "apb iommu: Unimplemented register read " + "sun4u-iommu: Unimplemented register read " "reg 0x%" HWADDR_PRIx " size 0x%x\n", addr, size); val = 0; @@ -304,9 +305,9 @@ static void iommu_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); memory_region_init_iommu(&s->iommu, sizeof(s->iommu), - TYPE_APB_IOMMU_MEMORY_REGION, OBJECT(s), - "iommu-apb", UINT64_MAX); - address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "pbm-as"); + TYPE_SUN4U_IOMMU_MEMORY_REGION, OBJECT(s), + "iommu-sun4u", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "iommu-as"); memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", IOMMU_NREGS * sizeof(uint64_t)); @@ -320,7 +321,7 @@ static void iommu_class_init(ObjectClass *klass, void *data) dc->reset = iommu_reset; } -static const TypeInfo pbm_iommu_info = { +static const TypeInfo iommu_info = { .name = TYPE_SUN4U_IOMMU, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(IOMMUState), @@ -328,23 +329,23 @@ static const TypeInfo pbm_iommu_info = { .class_init = iommu_class_init, }; -static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); - imrc->translate = pbm_translate_iommu; + imrc->translate = sun4u_translate_iommu; } -static const TypeInfo pbm_iommu_memory_region_info = { +static const TypeInfo sun4u_iommu_memory_region_info = { .parent = TYPE_IOMMU_MEMORY_REGION, - .name = TYPE_APB_IOMMU_MEMORY_REGION, - .class_init = pbm_iommu_memory_region_class_init, + .name = TYPE_SUN4U_IOMMU_MEMORY_REGION, + .class_init = sun4u_iommu_memory_region_class_init, }; -static void pbm_register_types(void) +static void iommu_register_types(void) { - type_register_static(&pbm_iommu_info); - type_register_static(&pbm_iommu_memory_region_info); + type_register_static(&iommu_info); + type_register_static(&sun4u_iommu_memory_region_info); } -type_init(pbm_register_types) +type_init(iommu_register_types) diff --git a/include/hw/sparc/sun4u_iommu.h b/include/hw/sparc/sun4u_iommu.h index bc4506b5b0..a760172e8e 100644 --- a/include/hw/sparc/sun4u_iommu.h +++ b/include/hw/sparc/sun4u_iommu.h @@ -45,6 +45,6 @@ typedef struct IOMMUState { #define TYPE_SUN4U_IOMMU "sun4u-iommu" #define SUN4U_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4U_IOMMU) -#define TYPE_APB_IOMMU_MEMORY_REGION "pbm-iommu-memory-region" +#define TYPE_SUN4U_IOMMU_MEMORY_REGION "sun4u-iommu-memory-region" #endif From 09ecbb785b7f84053d835fd360bffaf871418566 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 507/546] sun4u_iommu: convert from IOMMU_DPRINTF to trace-events Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/sparc64/sun4u_iommu.c | 17 +++-------------- hw/sparc64/trace-events | 4 ++++ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 612fec4c64..51fbc394ce 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -30,16 +30,7 @@ #include "exec/address-spaces.h" #include "qapi/error.h" #include "qemu/log.h" - -/* debug IOMMU */ -//#define DEBUG_IOMMU - -#ifdef DEBUG_IOMMU -#define IOMMU_DPRINTF(fmt, ...) \ -do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0) -#else -#define IOMMU_DPRINTF(fmt, ...) -#endif +#include "trace.h" #define IOMMU_PAGE_SIZE_8K (1ULL << 13) @@ -201,8 +192,7 @@ static void iommu_mem_write(void *opaque, hwaddr addr, { IOMMUState *is = opaque; - IOMMU_DPRINTF("IOMMU config write: 0x%" HWADDR_PRIx " val: %" PRIx64 - " size: %d\n", addr, val, size); + trace_sun4u_iommu_mem_write(addr, val, size); switch (addr) { case IOMMU_CTRL: @@ -280,8 +270,7 @@ static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) break; } - IOMMU_DPRINTF("IOMMU config read: 0x%" HWADDR_PRIx " val: %" PRIx64 - " size: %d\n", addr, val, size); + trace_sun4u_iommu_mem_read(addr, val, size); return val; } diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events index 04d80b7f70..052352feea 100644 --- a/hw/sparc64/trace-events +++ b/hw/sparc64/trace-events @@ -2,3 +2,7 @@ # hw/sparc64/sun4u.c ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d" + +# hw/sparc64/sun4u_iommu.c +sun4u_iommu_mem_read(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d" +sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d" From 602c993a3e7d26a10967cd6ddc8349384e1fb53b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Mon, 8 Jan 2018 18:16:34 +0000 Subject: [PATCH 508/546] sun4u_iommu: add trace event for IOMMU translations Signed-off-by: Mark Cave-Ayland Acked-by: Artyom Tarasenko --- hw/sparc64/sun4u_iommu.c | 2 ++ hw/sparc64/trace-events | 1 + 2 files changed, 3 insertions(+) diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 51fbc394ce..4cf8e69be9 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -184,6 +184,8 @@ static IOMMUTLBEntry sun4u_translate_iommu(IOMMUMemoryRegion *iommu, ret.addr_mask = (IOMMU_PAGE_SIZE_8K - 1); } + trace_sun4u_iommu_translate(ret.iova, ret.translated_addr, tte); + return ret; } diff --git a/hw/sparc64/trace-events b/hw/sparc64/trace-events index 052352feea..2ee2d75f70 100644 --- a/hw/sparc64/trace-events +++ b/hw/sparc64/trace-events @@ -6,3 +6,4 @@ ebus_isa_irq_handler(int n, int level) "Set ISA IRQ %d level %d" # hw/sparc64/sun4u_iommu.c sun4u_iommu_mem_read(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d" sun4u_iommu_mem_write(uint64_t addr, uint64_t val, int size) "addr: 0x%"PRIx64" val: 0x%"PRIx64" size: %d" +sun4u_iommu_translate(uint64_t addr, uint64_t trans_addr, uint64_t tte) "xlate 0x%"PRIx64" => pa 0x%"PRIx64" tte: 0x%"PRIx64 From c334e5f382b008dbe59abc69972ba55e48ce5c1a Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 18 Dec 2017 13:12:26 +1100 Subject: [PATCH 509/546] pseries: Update SLOF firmware image to qemu-slof-20171214 The main changes are: - able to handle more devices with specified bootindex; - implements flatten device tree rendering, for both QEMU and guest kernel. The full list is: > boot: use a temporary bootdev-buf > boot: do not concatenate bootdev > libvirtio: Mark struct virtio_scsi_req_cmd as packed > fdt: Implement "fdt-fetch" method for client interface > rtas: Store RTAS address and entry in the device tree > board-qemu: Fix slof-build-id length > fdt: Pass the resulting device tree to QEMU > fdt: Fix version and add a word for FDT header size > tree: Rework set-chosen-cpu and store /chosen ihandle and phandle > node: Add some documentation > Revert various SLOF-to-QEMU private hypercalls > Use input-device and output-device > netboot: Create bootp-response when bootp is used > libnet/ipv6: assign times_asked value directly > usb-xhci: Reset ERSTSZ together with ERSTBA > virtio-net: rework the driver to support multiple open > board-qemu: add private hcall to inform host on "phandle" update Signed-off-by: Alexey Kardashevskiy Signed-off-by: David Gibson --- pc-bios/README | 2 +- pc-bios/slof.bin | Bin 905200 -> 913880 bytes roms/SLOF | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pc-bios/README b/pc-bios/README index 25fc6ce63f..a843e1e8b1 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -17,7 +17,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20170724. + built from git tag qemu-slof-20171214. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin index 6bb48d40a0929bc9d1e2846a97a91f96d321d60c..d46c83efb706e4664fec834234ba69d96ede3473 100644 GIT binary patch delta 225096 zcmbTf3s{uZ7C-#%J%A%AfuZ3IM^pqv!D|BpIGE_jSm7P-BVN)@o~Z0JCO89XfoVZr zHY)0%fLNwjdN9+%E{17EWo74-;iVIFIpOJsH|G1T{m#J5)c^l{-{wUuUVH7e z*IIk+%R4pizURV~dx}Q!YZr?3BmBCA-K8zg4)r_R)m$j-XFGS>6vvE*FYXx~yktRw ze(3OF@e777j!zh+U-W8`@d($CUA#~?RIeKrKlC2m(BX;k`o#G7&VjmdGj!7zKlb>t zNB*u$);+jv#o#~H&bjxKHv|7@QRrXCKWas$hTYG9sTEZkHY%{Zm&Cs^R4*DeZ0i7{ z(qdDT(G5W*3!Rgcmfi9_Y@xHS((;Xbzk8vxS?u*=gMy|M=^cts(yV?Ew-V0#=|2rd`TJ|JgGE)RU%ygop zBkRGJ^d+FbxX_VxVW-6p9ocwxMhp*R0|CtrWcLpHTuIuatkYLa57t{0mYk*dC0z#m z-E?g-civ9WhG$ry1pPM}rRZ;G6n*|atEdlT;mP~5ubV#%yWa6bZSokUA|c%xoX}UX z+V*D{jipLxa)jcS7yY3wu24}@cQMQ3W`(EbE4_eUmk>Q&47!8$Vbg{A4i?24#fm%F z5R(}_ilJYFJY$hS9}xZx7LC+HyS7{#wR=0ly?*=kSb z;H#Y;+yog^`Dch%JF(#%rw0S{*MIlB_}LR2=K-R#OFh6p6L)AYb>7y0ceexsrw5ZD zjh9DhMRO-MtQ`)Pu-Y;yQhXG|?r8%b^Z?P+J>Fn|c>Yc{9J+WLkIvJzjb)0})iU`nWShLU;@n)(|!XCHq3y3_P46lIh>Nupxn|?HmE$!>3Dm zL&dQ!ETRo)?!v-R@6Nl}XgnUciw(l#c_Zs8itb{O7$j1(Tj?S=l$X` z9;i+|B$X$xoE|I!ymt41r%o5&^doS{N8Dp{1$3x&cQ_ltGQ`Ai7D2YE4yJfA zoEZn`8()N>Kjdu5?O<%l)kbCHeAgq?w$BJpAATVr-PwG7oT7+~aMnHGvJ4&KX1E-M zd-_O$9#kKq59^19U`5@;$9>qC5Jy~<;%D5&8`P*Ve5vTKV~K2f&3qkO!E{H+zha{m zb~HfY3DHicG2i(soV{iA9%Y^3Y z+s(6?04;~;Xs*8*{k8igccR82A3t*V#<1lM%SbJ1&w9?7C>Cn}muH zN!KN$PZ!_B!I+97SwQziuer;?qQ#TuP$V;SU-+&^v24NJKg~dCmh%Uq1095IARCzc zyJGWy+p4!K$`4J7HX&NkUPtiw0W+qF2TpJ^l41hy5|hFF$XraiD2EpdOj$&gl+32EWWPBi+J^ z^#HLt2#@=_8<2w#p=J@QhOqJ7AG_`@!WcGs7XMooZ~H$L!veaBj5s!gTbB!aoQ%Y3 zYb&q0>v#@1x_eLWr`iN*^DQ!3mjb2iwx7IZ&ui1U54Uh}DxRfv&uI%3V0nRP+~(Y8 zDC{N=7C%%5Csnw0ll~9Fh4;)=l=j(R(r8&5i0>Ai8Mv)QDq`_`>&8naRVN4kPP z`L&$qJ$twQ1Ml8#yw6JbgeRQ|Jxv?d`>TU*Vs5@4NPA+^-$IaB(9sxi9cSNwI#5 z{xfdh;XmW5mbv|<%^|v%cXVsTZ6@vnMOvMH6dT9)9u@XcvUku{S8)LET@Amv>v`G= zg3VyzxQBJ=niTC--mdN5B6|?))Te40=Ep`_co@F)qI3;mJ10YhS9v?9aPjRutZP?8 z+a%&C$(?#Oh#L|_lAeufUz>MNF)h|PKoqv0oUOwWb{xe~#*P<9$+ zzXHdT%BU<#OiaMy2#IO}#^O;g9ZS@8FBIZbPd>nVWC_t0&xmEpD7Mk@e$|d2aAt0~^SrI*Nx4tS9?%Ym&^pUNx{d z9`mS*w7ZallGpyx61xr`{8!Z^Nus~VOi>fZ6l4>FuZwq5 zB!iz*n3>=6s7M;k#&nJLYBwcIS(o_ubg^kPNQS>G8b-sBf1bP5C}Sj~8BSfDW0d(6 z^0}cMe64$s{`Z#sh(0Hs|82n%5K*Y1WtpPntnF~55kbzxCbyZNJLtJ%===Fl8O`xp(CC36ES007`=~2xS2CXX3n-TGWV3EpO2BbIz)^R z-S1`H-J}!mm2*qn1h80tZ##<FtH-Gk?j74Giob4aSkC7 za!3KjPII%60=S%6YAAhNd-rn2$!WuAL?+KfUt#Xf1=mhr| z(Gu6K%@L z-9@NbmBQSPTC1XVd!T+*QFl&kr&=^o)wKueyo&nS12y(ONj3jIS#igGaslsp+;P8L zn2o-l-P>(&N0Pm1t~&lL50MSLfjyr4r477(zq*ch=Xo8mhLja3!nhN?wqYWLOn88e z>>A`1HQeRW|5C7`ctFlg@OGI}596bkiT)Y1J`<9}P+YSigXOcp-xag-ldlqt3KPc3 zSU@CCWqjHMcowEr+a;FV4|y?4_n%)j~&}OmBob=#J#F0 z-$y$eZx%WmQ+FM+3gc8%%G~g%!c43|E(~(Ads;UrREHb9Cag+1HppCI4z5CDXJhC8XcXNi`fz39H;%{hG7;yL5)?Bfg z*q2*~&bID~HD^&zT07i@InId((s0t4BrVbau~zTq2=juslUist#6Bu4etgW+vezYlsPWf=h&A zqPKao9W0x-%PwKWU+pcLr!zCF7fCZ%WXx$L=U>CEH}jkgH%~d64GoIMq9{sPM81)p zO=I%WQ9OBmyx1^<-9IK@YkT__^!AIDgtxu>i$@P$>FV9oEB-k-Jy)jYvlT?!$EJko z^YbjCS0)UuNF-&lezuqO3zTfbTY0r6_PI>>i9>rw4{wwmU3-P}jgB79Ra^i3UE=87 z`r!rMtskBgx0mL4<(LmX!42oEj*tThtsEX;d#A$@6a?tkI&b8xi3qjb`za0j;H@*+ zz5ewk_VZC;n#snD%G2Xr&ID$sQ;w6N0m)QW-csP@6ac)1#BaF~xElde+>Fa#d?0i{eR{leq zMu1x;C6b2r$;1Lj^JHxYIN04TcVM}2%wao5 zmbf+GW?^=|bW*aA0pw#Q-@Vwqv{PiyWz)G;5y5jY)(vwpAy~y9bJ+^cIiVIzXO8%{0GQ)FO^lD zQYErl*o%B$lW17Ly4}A|ss_f;;2n_nz1Gg`-0eRz+qaEy-s;=8jv9y;#}=?i(VB%V zwr>}(ki>mmi4;vVdpA+3vX%0lOC=g_eN=ue;A*GMO)0Mf3-%FeP?DZ$xEf0m%)C&GDmvf@kEh)AZoKU;2vhotZSg`^dKA!&tM z(uJ5O*Tjpk#aIQsFYaB;(#7&ctoxWX#&)U8)fvXi8p{{A_vFm}Klh|OO&yx0i&*%W zH5u*9_BKgkFJ^l`^I+Ef&&;qlAji32F}rJm<bGsGm$YZ?*1?R@JIq z!eaQIFQsuN?vY+%xV*;dZ8>|?9?EfhPmYm?-m~UkFFqy4Y^Pg|-qpE=AY_88*8)ahOBoIy%9j7?Cls(Vx6AeqTqwwC& zn&4&Zzr4%Z_}sBm+#$2r#QuFBorMlz)|$}|vo8Yq@vfWfQ+sRJYfo%)OfBj}+`t(V z??;8NCQXawTc2Y8;r~qAl#$t8!;bFX^l;{8H_&udr>`@$+r_#HYSLTn>xv~#s{KXP zM!W*dx<{$pdtBGet-(+vYWRz+=D^eJbI$U`nnIkl};s~Q&Z&NhDca->?fE2)fX6I+uCA><)TC?+flNhlP$8t!S zH?oW2pT0}QMY+n-#ylmP&UgscXRWiC*s-RX70J~PNZ!Z?Twz3EP?Iu?J znJCzbqwdTz?5?!D#zjgPrCq7Jl-Rufindpw(q(0IpZ*Ea!J3uPepmHtgEiK*ephqW zrX%aBlZFpX#?xe}deXL+$wQ)Qs2Bswfcy%dlCpK+Gw_n!dXzFN2f){F|sNV~<7te2HYkl4&MA^$YJR zu-X(I7ACz2&Qbghpe$Kf_OMYgPb0%DPnC4|4`}))W#N2gp-V?tnCSDLHk#Pp4@B)A zHgDR~TF`fQ)5CE~>7D+lGY>AaD+%c(Q8_thKH0lV;W+cD%+*bcP1Z4GM*7$x=xpqa z38z!2qq)&j=uD_GL0cjo-^+56WhjuE`Uf=C?<_R>gS1YGBP~nZkN(tJo0e7FDG^)F zo+L$-LlHkh5#{VL{^KQ)RKY$Ct&~dIdEkek5wnYeKjm_stYcSr&SMzNh5rWa71>=h%caXm+*S9W^PH#LbXR{9EiWOg3>QfUu-Km@ z9zK9Q6l}a5U{7|G27%Q=uF$=V9N^$wVSJhG;a9#CS6_xTTsbPV2iY)wB~K(BWM>m3 zxoa6$hd9CXd5S~z;BV!O?kYQgGLEurSJ?-`c!=!@d?rIRjjh+jkB3;<-B_5&Mak-( z)*F|c$8ItwMc4*W+lhzSupAkRWrSp_+Js+l+#B+mi<0P6f{RBhol?-ccb;7A)YG?t#P*&|K``V){ItQv{YQeXQso;k` zN)W=0rns+?9d}H|)FdoR>P5x}e1r|u8W**U^Le9{V7lppvwS^j1(J`GjSvkyA<69g zR$3#r0xR>POOg_z{l8z?PalN^k7_tD7)(3X7MoI(x{Hq(4LXAn32m*y3=qeVP?Ch0 zBQM+lv?)KlsTA42#J;jkDM9oLw$&j>WB3Ut?ip{zx{Wj#W3D!#`wp=KG>!Gu`~ zTV=Yle8~Dvik*5329DHS;@~Un?mn|R95Jj?bTcmcrMy~*O9NY-85BUNUekQVAsSy{ zy=?$;qm>cUqQ6|d4A&a)UOz3`FB>P~b|N|)qj0w-0auj)#@#78T&zU2H0J7N!~$QR zfG7!CB>@^D4I933Iw4E_;R&dZ@mdhA_~rKRaD>JVuA@e6J4QzxvWsOvKyoPaX3XR~LD>!Xz-v$H{Zx7%w~o(6|vfFJ86a#mFbFZW%`}vxu(gXufDJN zNhgFR;A4y$gTJMaCXgeB5@TwBm=oi}Xq=WC7*3eOzuqN5ZF{jZ*B1_49mD(E+p* z_Wtm#w!%iE3|AM2er~&%A=PQzsa$|G1IS{lP3$@83o^F!fsWsgyh^&uDaeRP-PM{S zeyw2xX3z%NRf9|ER_T2IZbT4yv=gCD*>-NS*-CB0 zD!q2J^%kcSRTkx(90bpBLYeX(v-_)wV2+ko${7(kkfW0q z@rgm!oNX{+n-ZM5la){>RBvQCqsL&Hm{l@{EXiI`l0*ZiZk_%^#yE=X6c~x$UR>#- zL7%bzbjpk>3|;iS)@jLpDR7fxGv3gWZ`$f?X`j+vxk~%#k|f(1Ii)b$#VK2D7bjsX zRMVdEFTa#k7bCAG^iWvN!vBR%)B2@g$_X|*zmTR4Ms?J%YdTR@Jq_O&aMnt+ppiiV zCVve6MpHw5Zn9x(Tmc<$*kHrajc_({NJt7Jn=zh@%wV0?!!KoJG|W0CJ@nNHF0+Ov z3@2gMU^3$*%o;ZES3P|7MPyBwi=Z8*W>a50VZl&HQ}3%(%apaRv+f5ma~bO+>JPC_ zI+tcAV*Cn-mi}OS4JP*Nm-N1=d2zf}9bo4QVZ6%wixIE0o*^5l5KFknY

<{daF+ z0h%$9^E&I(mrUZbjNX5-A!TR0qckBq%Ee1y+ghIC>{$x<=#1Qxp;#o80h>|fbrDzVDBSX?{7 zdS{hbY0i}~B3WITG^Llwxm}%mT`?kxVg$?uF+yfG4kS{$6g`P^IHm;KA788^aVT*! z=C_)pqGkU-$rafr*}dJ*P%*MSnxXp3_pE|26DznR&YfiUbe4f$omMVs$Wm`vvo{) zoe27XT^XW9B%NY${*{jJz#{t;n?CIC(q{iZv1mEPreMg^G2|I;u(digw4a$%EYL1+e5X6 zqc1C!lvy;cEvYv+OKSi54jaeVLt^~9xZk-`&)NT-8y~`d-R`0ClSbmPBd;?jwf(XNJ;%Qsa`elTzoTlSg6f!4&9 zh&88Ke<(b<K7_^ z+18kFQ|*gq9RkQA@hnj< zl4+?AwHl$M0E@)gI(EQc>R;rXVLx=QG=!BjP+CnaX_acgi(yPbQH}k5##xW72~?m) zFlSCJN#+*FNmU#aG}W}4t>OOT!r!V z>~U9>s(LoxzY+noQFQtko8I%pJs&eYR>j#LvqvO(qqzDp`$$^?J83kr6*aGa!ZMjG zX%=DU*?d1l=f}jV^DN4RtUAxO`xn9}9u?z1V^7N0Z1MJItVmm>GRdx){W&Y)+G8rX zyyoTw_KY82y-eMMuKF4~w7Jtn$wjuBuU;&|zQI0B&H}OF8@83_ekuAlu!xile^MT1 zd<*i2Yio`Bzq- z!E4DS_OlDS;WB%RO%xAYVbAlN+oItL>((vjTWSLn_(V+PI_uiVt7hlQYogOtc9EHD zez?jC*i6-spQNoDuB?X1Kdp3(_Zxqenv(;?2c;p8* zReQ`}q*yUaoc)2_#E$KIKeBynOwA)du`d{Zc%(4>j2-CCBKv3dhW~mD-*hp&nLXgY zKAv8mX~rDA9vYh_zG!AqoeFYlr^f2@3yp-i;~KsjDKzS{)>{aC;2L|W+u!m?Zn;FV zEAh00V0Qk!vk3klydhb{{g2(vmw#4c`X6@iScrJ|7u+#@5OV**V&)cRf>SN-p~*>+ z*hp4c>n|9-!c7e}`D=m`dnp|fBi1+4yZdj$F07RMJqs}>%gNGK-E71P`9~_(XKii< zUiAExJ0irOE?Omu!(rHbJK>4tXv}qw=Ys=eHM>$v zEuiWE(fB)#AC_X*{SO@eEZQh6f3WAeE}Bbpa4z|&g+A+9%o6ttO$(dd^`4g{3x{0Y zD*7DUB4+p0Jl=w10-gmwy$)d)yepz^;3De+q&YWOPygz~%g@${q8r#m!&UeLH!*{K zb%TA#%;Ke+*mX@8{cd5bpGBZf7f;?|WBu%K4)NwKTqmr#Ab!0C*B_QgXEdS0aT{Yb zEKU8At?@RShfkWux3XvGYI}VvoMORX(cH@3;2Xn4wUhN2Fz%X^*P_6j=N+Z@oYmx@ ze$_CKrQ~=fq%%J|*?2xXZHt~y=CiJC*}%u}IWKRi=iOrF%R!=K3wfH+?3^Q~ZFMhB z^P|hefS(WZV!Rt0A_g-4B%h5@0N8!rV%fYyF-qTG<(?pih>sX|^5?Xop7U1%GNn_B zX3j%JsfN?mWW9zTWMhQQkKgUT5o0+SaiL*2W8{CnrAIZMA9Sjt}}Wdz&n`D@HZ>%-pZm zbCz2I!2k_rqoR1wpBtkpu@`=evNS9+820pTVNGfza{ANfZ)nhGJ*PJ@qxi_5@8~j1 z+ARW1rW%Z9Kb~B**X2XtmjZHa*Qc2mq}2hs(uGn1$ITN#`5VO)MRwzfs9Y;E9M092%dor z`amATGd>mv0(norA`>%+vw{4cY18B=um1LREA7Rte*0C7;52oV5iVBsgRamdaEE2{ zcEzGP_2g3oyN_$=-OxaT_8ct7AZFab*J_&q9W&v4|H>Ua3K6hVC;pWGb5_DU+lha{ zBK9rp%o&bD76tK0KJl8^5X2wqxRIEk+C9P<#Mh3f$D4Ex#EBe_W}1QTO)&8CBA(j( z^I=r8=1y+l$MoXYJNc*a^>8VFTY7vbHJ0(S=V*t!(<+Hf`KXa+7UN zVLwHAG)9TQK4BOob_wa*b%imCGA+8pjcs@mj+RLUr?&;`uP7`b9c)J2#kb=i=A*l~ z!@n|d@^+nA5z2?~O*&B?%8#dP&ZK@MWNm6rL2bFpcww7zec3iGMS_$Fr805ocHR0( zit^B8g>AZ?dQ8S%Hc5lk7gj1dCGqL^_g_h} zHrkw+mTCIxTPWe(PCIY~YC!KVV+3Hki)Jy=7@Rl~eWQiat+hYgMr!h=5+#fQJe2F- z6bF-dd_=!*C9m8OwQ4=xZv^XeM`RdoDPg#qQn59e-_1^luw>qkEfYz}e8`Y~vUiQS zBaC{x76R#1ORy-z%+B!ph=H1@jU-{`ijrhpz{15xZ71u~A!DtloAb#5#rb4DqhlpL zYt-e9-5xJSq+m#Y{7Dq0@Oj;?B}*|J7)ra!&7?Fp3BS>NE8iYpQ#u+$GNyYm5sl7* zOJYCAuxfj}wB^<6nLJ#jdeaWF|L#&e+nQ!9mX(Ly49(7_M@6SGd~#qh;;LT)@e<9y zLDZ5l{2N^Nu-*&X!cljxvHU%3h+Q4a|HfVx8EO1M_O3XV#)o$-R`-L}H;G@<_~=Zj z71dXi4UJnAZQ~PAxy(3vEGPDW(H|PZyK@OvQ`;YgHtql|PSjkqsgib88?AVD9Pj1t zFe%P!;=niz!_J!ear`0PrHfR6?2yc3E)NwA<9TR}WdeVbrPaGn=Usa%lT6A@sR?ZH zVwxDKtc>o^A4ew;=PsFDyAnVgnvR5*&{TP~P&7O71&Phfn;8srB7XxGA9o*L7=Gs& zl9GDcvU-FO##*g+XkFDVCyVO)kn?pB@7;%R^nuXb&-dY?d)@tfJliOOAK)<&A$hWw zsH@sgkn9WL^jR+$P0AmsV$K6RJ>Z34lkz+I{Q&QWxkvf^453E|Z3gesyR+1kONLq; z%GAmkPHOnhntL+%K+eDWNmwRxgLwUCETf7hqvg&`u9j=nu?W0QuzCsN;>*}eX`o%a z&@kFZN|Kj0j+MB#r_4_K$*oiPXn!2bZr6*kQ}{SO;#;v{3Lh>}N#dO;+|apll~d8t zArIyXz34QR3s-5?R6fx4dVVT5bd_;WD05ax8L~4Glq%Oa(RPu1m10z9@+JKI01-Bm&*;vGFWT8myWwW%jbxg!(MFOe zn90|;qz#@0X@~R`8MFBPeDKG@G0RhGT#TK?BgPDtE`cff0yxq?X77wei0hDpwzEhO zgR|{$5!-Lqw^%?3+qCKTY_1h!XY=tRD~pzG*Hf>G3bz~ObN}`vdbXU|Zo1#D=uo5W zUt8~MXY;rLQfc&|ylt<^eVOsml02mjabl{gV@44=hvUm8kvT_pf(FJuhxb8OwHUVY zIec7)L2@E(+rxkQO_vG&gChAF>)ft3|iE_eW`5|v3jm-B^|At zpUcx}D$>pKkouNq14X`4ub79mTJ&q4VmHidW9T;@45KkZ^F0{0crtA9WmrBR45JDq z!`@PJq#-15dRt)_en>!xCCLk;w`Yhb3m@-axh)2-86B}WEwG^Kw|&Jq3s2;g_~c>% z$Jv53uFM5|en;G0a5|BI>1%2iV26h|FxhkbNvpWb^6##7YtRD7S(7OV?*5 zXbzoPD#{7`b( zo$C`y?ZC;Im}puaDlJIDXaAOkxDnZUHH6xr1C7QCmA++JX;EB-LP_ye^^By{E-X)B ztD^HsapWn4=FU%uTTk&Zwkp?oUYBx}6||ROs&2h9 zNw%xjD{_^ECSm1@%N&sF%1|noR}t(u)oi^Y=Tbv0;uOxo3EwDAuHut=Y{50S_m>ed z;%7WP^;ugm$-X~LMCBk*UY@2dtBP`XmsxjwKm>m+?d8rMWj@kgy5>>#7t&t(Slr6t zv%*VPjDAb0TzFC|CklCJO!poxmS!8qY_Wi*?C|GxH*rnr}CV9J|>_f%A~ygns_H476;s|eC!6`8MTH_!3R+} zYxrce;r6QQF(~?K4IeYB)ZuoVmL;WCaGqdy{$pZ2EPqZ3ZBLdRLvo>H}GM6?=n%ofvQ)Da~t@l7&pg8K0Tt;LH-S02jsjx z+?w;va4U_UYn<{-O4(5{=U;T5_Z-H4d!|_W9FLiIKn9rv9Qf%^v3fey(5+$ee2i|N znUrcdi2B{m8$?52PTSt@Fe0ZApH8-3mYJe{fs$=fb}b;Cpz&hsBA7LB=<{vS{2bpi zYfH91YkRFp`R65~F)5QJPm}VrbZWwl9;5gTNmi7>JCy)K{`RGYS;sRC*s4iv0PI96 zfxL)9KJ6TW&o-6MJCnqZ&+{Q&a`OnLGeLQ*p*+n*Y!QzMpFDu@aci(+giZNWOcw-0 zmMZY*C{`5lEZd|C!l|3~&P;lzKZAolXxol{9hF%KVoQ#@jGpqoTGn4_7frSz14qGLyP2Tm8ZW0OphN(%;w-lRM!%?v6HmY;5| zR{WsmJh7pe$J)riZuWK7-Ar}X(>x<*rUlLmv^vSbzOUXAaExXt%0zQY`&o1TFjy%g zr3pPZ>|S~J>h@?lR%z*bGqt#{Uk35L-q%l$Kcl(z++Y$?-GjUngBx&6_3WL|GG(Mf zLj!4aht8xNDJEF&VDbixY85+|3*!sC+qk!mQW-{~HRqw8_>CcDsYy9?Sj8zlF=ebx z7%ew-19L}rI06{c*!z!Cxw-Ys8TI*oh$wx5hiAPtNv)^y!l*iEgu%0f@On!;G`~ZS zuvv;#M;dk}88kaU(^qc~I3{;9ThGdVi8-73L|b8BzxxWA-^7AT ze&&Kxe(6-Zpv-SVL7pFWp>|{zr!v^lD{@NFFYq(rI(7)rayVGrqt@xwh0;|qQ{hz@>DF~?^m z7#08GR81)M(EU<(b+q6akh&}Ioy1F;c<>KId1!H}IKGK@O6NxiQ`}c$L2G^_kvgzD zq{+KEs+|1isGN9GUSCbj-;CVHuPN&IEVZ2uBV6rN8JvpWpxp{H?(EQ5 z*q2uWkISEau^#aR`c2)X4Hdn%@NnB=>6=3|P!k$V zEoS9pO{u$rCX%({X~pw4o>TF>mAb2Q6`nWoEWq;yo=fq(j;9IF7CevP`3IgQ3H_8i zNeOh5%DA)B3E(dP?}z6Xc-G_v0yqswU=Q;Tl3xXLup zj2{MzPfTvG=-!#!_JsH+D7?LGM8n%em72C_q}ZKvieo-PmKK~tsA+KGk^ z^(GM9FU%QQ5x7MK(v8}#-*-b(~;g@>(_DyO<~h_XtfOv=mGB(L4hR@lt}dzrG9V04D- z^Gi+W%=W2O0V&pfrz5PDPe)iQ#^E62w~eX>|Na@#VpGDBSf;6mmo9SOEl}f3m*1$I z{^*y#^tSvRbr605Ayna6Xyi+h|re0NmK`9G(F~^f(vCs9}F6}4+oXt_8J;NBs6;V(xi0h>dk}Sa+`-+c<_*sx2dmYW)@Vn8N=mV{m!ctEUQe) z=8?nzm6UCL**?rTV?A9_Ue8drN-tCGMESKnfHJ)rKo3Q!0hB=}x1#W;#a|u%mO7m` zs_?~(>JV9_%G75tluu(Q*I_8vj^jwgr47Pyesv2BS?CtvTEK9g$7H!lS^g8rNv0+f zjs?mJld=U)B8NZ2(1526cHoY*sk?5uY}Rd;TRIalnB$C1gL|eoYrzb$NMnK`)>BvxgvY4){n=V_5vxhtDc@hIV7=o3}@a#sDdeRbX`>%zcQ z`wE#WLU-~A8?OhCX;hYY%)_pZl3m>)g^D|>+7Hc$jtVs#n zMz}#+XLVSMnuF^9j-gK5UhHd(jT+TQYnxfG*@1y>55cdZc?7# zNOT^J4JJ5Yq_dThLmC2g=DA(2wrTT>L3c=3ry%NTv@cb5H5%{PDAZ`8MlqhjXtX=g z!RxB=-kILp1?c!P!PF?qi%iOMKM{=8hdN}oJY|I%oSv6~Q&s67e&`)C6pbFy7*oS@ z*VRhD%S&hU?*4;o)AG5+q*PR>H2;G)Jtv3I*7a>PdV4D1l~iWC8yA6m3>Z;9a5)wJ zg$2U{6tD9b4=bicN4pg}osI21)}ADOgM@pMzwxl=@S2p4x2c>u2QB+sF&W;bNFOno zK2hCxlnOnVO(Qtr9^di15$ws7=)qX_8jLg4;agrPjyQOvZDT6&AiF~3J&!hq65QTK zhmYOm>M;FYO|blue9ZPJddCvhh#by8=S5QtG%oN3@^VTXhV+4X$o0gHrD||p4AsR%?$q1Mm}CkjpXBUHC4*9|OMF z?EL;Z@EctC5a1oazX1Ft;MHGBu*3%gUjY0j;LiX*$L6XKhK9pX@GJ@rqhPEHe>W;L z1HS?IZNSIcPq7ma_?WA_8|sk&8&SRz<(*Kb-XFBYcSRXB_8iLQBF$+=UWT-+xxiId z1Kv}jKmf+yCxf6~7L;Kzk-sw=+UN-U0F-Y=nacE(QYEj>=I%&Hml%BU*_l)(cia|WrQdXeRvpT=(X@aM=q+^R zJTByGBGKm|RgklH;7(yF=Y2w?*Lt9ri=uLV_k;mNO7#KA@4n@H$w1vDi?7vyn#JBCg$x!md1X*Vo+JlH)eY-pZaun^grWS0n5FJ?ULY8kcI!>b?#}eCdYA?0aFyJEE5X`* zypOB9a_qW%NmT#$uJ4i~Vp2i}6D@T;HNUll-t}3ITI~8si3y(ZUO>vK)2Aa=z58^; zs&~dkpd6Cy8cAg^#zpkBC_UW6=RgSF)t!*4nDYmV+I@V`P#JsL4XFbo5_L+s?MLtW ztlb#Vov+FFzPx#BH%%`+nTj4ZiyT4?Y98iBpZ}5xniT$ltkh<_0UJej74L~FoExh6 zplI1uG<{4p#sDe0s&J>iJ^U#@iH0iPXQ`vyTYD9fjcBp6pKY;|RZSH~H9l=^H zSH$nE6k>=)ji>cXQRrOEWJ>TT{M zQM#Y^+BzIxxYFIcnq&LZl*pAA3!`h@Q<)D7y zS9QXE2z&Q<9yx^l_kAJwARi7=7B7OUarp4nS0c6=r-#QaHEXN+IL0d(u0+Ic$~OCp z+lTqKn9H?>S}b|+MD}&ifO|)VlS#pV-yyig^=o2)>qPAOXO>AaeuC+a6Y@rXJ@MV7~vC2yiuNPrQ_&i>w7uF*0>5+3V=gL%>6=ZgC)osgfEy5+(K-oZ7_%XRqTy%W(HA|Ov_ z4fG8;s%v;em&@i8Qxre6G7$3N#Wb>iF^ z{!boXE7rab-gwr%5254hMC1Ete@iwUzSGZ67*3+j)U#k;W)ekbd5<1t873ubF2q#~ zZ!4Uhd(?y&K*vj@9EZ6@2s`L*p^^HI|S0D8`31ijq&zg*~`U@(CZ(ZBMWPJ1aL* zokeu;l30u7(B(Z#McAikY(%p#eagQNDu^Z_67!UQnp>aA6~^=M{(RhAJ&z;yXXc9P z^HAF!qxkhaKTdV3KO;E1=GV{o8ybE*yXMH3yj2r4q9rLGvm(umYk{o&n*W{i5iKIV z0e4Xo8+Uv^GIU4d$gT-Sx#e+an`vY>(n)d5Nc>!41AmMs{wRKJz(H|hqxuUm)t7i= z4-Aj%egsZE57BoBH*u(BxCqA0mw0-35|;nBzlK@S|Muq4wwR6XZ*r!`fayMhx=@U>p$F)@j9xv94)1v}n{;C1bS z>+`o{dkKFI^pS}_5?{T;FHEK*m}t>4ok^K+n`D6}AIghPRz$CF`KZ8TB?*18pN0%` zzU9XQ6C0^-vQN7I;I#F4w$T3v(JiS(6#a)^>|&rp77e`h5V_8_sHBz}`**lN6R0*? z9D`2OHS$pr$+Rn=AtfYbp@D^oKboEOO(X!pjSG{Sg{}$1l60%4sEL2hxFK6C{eeH! z1zL079$|PRpoNI3hvMoFh_`r-{SjyN$$_H&N8Y1Lawi%Mq9La-ytT(JZv99NYss;H zK$-d@Kgpc{b7;gbN2|dlkmFV{^(TIR_)fb?$?Qt?ks!NL1F0SSPmw@V`x6`!&xW6H zZ7EqRV*iVg6 z;l8vQ94*b7hNUS6Oqzctw^&A8`==jLYE9QbIjsn48ia0$Q%t|6|Vv8n+W)! z8JN0}Y1o50=l+Ka9H8m-3tZqhZlV0bV}_-~(3vL<4gIPnop&PmA2O^;*1G1v1vr%N zZEjtY5B$)lX6jM`RN{pD=!ehFm zV4-+x4s}W@IX%TFidt|b5Q?d9;o+lFVja8iOT6;<>^JG3W$7tH%2MR4b11JvN)&$J z;SQQ2a5?YS+~_f(#RF5KME~nNWmt-lc;=<2BvHGh+`K5PQSgHhP!4`52T#D55Z97# zHAQ1kHlrSO_WX4o5tu@IoA@9nW#ZNwe3UJPeiY>p0@R`62Qm9RsQ9%kNeLrdQF)4q z@UF4SE5=W;k*iTz%T;t6WyPkHU=oM$hnJ*`pt9mc5RJ+nN{Oek;-x83R1SC|#?yIt z9L5CCVpDRbWHS*w1TQgiTN8{ZOBxn&)VbIdXx8vIBqw$E|BS;>Vk?VGL2yE&f#Eal4vhDCHNlB9t z5qZuz!mGb?wbvrfJNZC{>p%3U+tObX$@ki~Or(eD=n4(e&y-AYf@!{|XBF3sqh~YM z;0mgxW}-$jibc-&k{Fs>XUKhv_9SnH+-Ic~6V$#zRQZ8vinXTRPorlkuo8c|6TB@! z=}s1dXAhj4pCneJ_rQ%$rdSXgzak67a|O`!kJ&rWil$~#K*5|JuQf-E110Ev%h1V`RrVX%LI7BEGXGd`OBFc{P3; zuywIC{qM#eqXdrXCPa^=-{Cl8$Ayn6i{?@OofMws3UTq=es} zYe5}z>wTZm6T0X{Px>>r-X9`vb=G82yOto$xNa#{1Y_)KI6k0qnu>n7h#s8?(mcXg zi---@^x)-6jVV|&k98~8(XWvh#*~L`>yJ_8vnuVxS*F_V~ z%i~337tLf|t`|vnX?g;kd6y;~$&x6)3*8=DThn-#CXvOYK|bBP)He08WLX+cz;s6m zhOV*+M?b{@JQua}^}ppa{I>Gau9}!}V{4N!WYlx~ND_CiIA~pLxOlwadd%25s@+nU zhEIfAJ7ahQK#Tu3-f?_wHBNeqxi#%uaiJ@uOv6&3n`Q}#wYi(-IOE3)L`InAG=;&i z?waX=?w>a-HwtTa%_yGMrKY;OrVI0rsl)fHqE8>qAo0H*n%H*2?3$>anjVagJytWe zmu3j#X~8usdTS~fc-Hjlqe*A&w75v6(@gJ?78duS+%AoEP4}$Hl%~5Lm8KI7I!%u* zX<>xNFCj#c4M}{bzMA)WT9~-dSF@F#*%6w5^hk^P3qJ9nkKfvl*vL=?HaZuZcoEx= z*hGnzewytNLz+`en$Go%ay{eerY|mRz0LgOLhytBnn2w4y3k(}(e<+QJA^X#j!dZe z_GNMB0Jzx&VHyC6OQ+C?4A4y1Rp4dT^E4MnFbk(%%LFnka-5Jo&~i)b8( zksF5J4UEzZ`+G&0>fvd6x9Pyc<-U+Ut3rqO1SxJ-1-|OJJ(x@>FFH-H?q_qk0t6kF z2)*-&&a)i1X)J^@e2soI;F(`x7qwBE)A+jLnP^R)h_BaCF^we^H$|l-5?i{Xo*RQ- zD2qzdi@IpdLH3n+GDb6ySH#yiVl?;P!H*Y-=8^C%JcCE6&-hUYhU4uu)=`?@k^c|I zmr3a3(BDLr9%hY#TYAkE|E?EuJ{@i~tVIL2S6Q#8D%FW&DvDmsdGI)^IcU`M_vgot zZQ8IPT>LLhW5l}{F-{W^e#a9eCjCLbIGV3$psingdd1DHcg)-rn}z>X!H4k1s&O!$ zkZ7@DJemyttfp?f=ARJu0{-6unwgs0w{cT)isnVz_h6(bLBamb^4Y}=2k3lYiw|7w z4NuDOhNlGkz&`w^+hw_}t-%>S3^H}z3}zCj1hvu6@`bZ~%Im%1*+w6@h+tbg!`Thq z1ak=VXmF0*8=f2N151YO{O0Mr%jY?~;rSN8Hjf4f_H58%_l6e`=s~~0?hR-82$bdU zE?*e$16Nb~9t;;*ya^WBePD+-yd=XLelXh`UZ(SgAM%0y-l6u}1R!Gi7ZmJwK|Wn$ zEs+xcP{Cj0vn`(Zpx{T1-tc2S<&PJ+%c*@dxI*VfsPI36ec-kVuJUT{@+X_U;gt>E z@KY9Vc(t2ewhsa9wcZ5w25&geM}V~%-sJ@jZ@AEhe!UOC*I5dgM#1nY2dvE z?+SHA-tak{H~fJQ{Gkv1M|N-edW-7+ZIeoUtvA8P79Y658~()Z4S%ZhfqgV^-r`;U zna!udXVu;WpU3;azUB4aeeE%wgm;>toB3zuJwj* zc~uAsZVmP-5ApMXeKM(#4)NafcX-0^|BxVyH$hOg4_xgH2M2q@Av$k3!srA0)bHAcH_`Oxc|y~`6VZdmpIkR%_5quU51VMuDNyMhX*IlSQsKJcV!@AAn6dT4O6 z-380`p@Atr0!+*Bt}wmX8=l$V4bSqSpJn$cul9!B*|2;551HNIO)w|h8}`X|L*_cX z%jX$=;CgR(e!LHyA>p?9Kg1I3O_0^>4KFP6h8Np?V23xn#E0LK2Jdn;S#6*HLzY>* z36@oR!w=Vb!^?fjm;07Cc+>yA-W$%22kbHbhdkQsP4IYzH~a*F9!6v(1|IOLU>~@_ z8_uduB{NFwMh2&Lx6XffB;976^83H}(7u0&g>mA7YY*lzwA%!|H{!HizniLYb5r6*Pqyr$8CMS{{KE=1EBv0I|2HC zbl~4`MC8w1iTr=zU0Vd+iYNB}Zi^rv|CxX9Pb7G6IH4cb5+f4!8Hsq`XktIr(NDK2 zOE}5nhdd$CfJ`8YBYQ>hZ*W zR#{?yW{;ykk=W1XT`MKw*@PGRftXW}NHC`?v7bu}91MCRBHPz_!~27Y{e=$xg%18j zRg#|8|L~&GL;;JViTx$IqhIFe4=46NQIOa_JL2dMi@v%3hnH0)5-gJhG&P5pI}BLf zpGd!gcWohF;V>}YfzR*Z0BijZuM_}tF$%97MiTza$`c)AJp6j!% z|KU}`4uXlq{+j;8{&`VHf6&n%P3(WN%hB&oT>r!Cj6{O1*)(Zv2`U5Wj2hXK1d+LqE?M!Eu=TyTy52H%4EmfF_3 z`uv(}JL=mxroFx+zqYZpy}pI_w3GKV`+dH%YFb-6qWNw0?a|hj_IgdLYpk`pC%H&5wBdvN?@$;&8`v-K5#Y~u!I!a7fv?iEOc4b|6W}fQqrEq9@m*lgQYhY}@c)4B zVFd!;5Bw1hQy1X}S(U&K1K&wVw1gjJJpvyGewGdI<9|c`I2#uDN#JKEN4$@a-Y*&d6lzDifGYJZj|;nXL-pG+ve5!t@iDce&@ z&pV3$Co+ApaNmF=xP4N#CnO?FijNI)IG%co|3hIW`l0YKAsE0sjtGU1M^r2OS+r0b ztK@K8h5SG8#Z@chtXFU#k_1abvgRv;{@y4VKj@O}OB&0$6_3GQLS|+LLRki)jeZ6> zbgYVX-ioJTx8h|(PIv1V8@&~kcI%{;ws~85@m4WNL;94{Qr>NP?`(czC+bXy! zTp^tn{$u^D2lTnehBSYXycrkx8HS(>9~))E0za+=%C>F3ghM(1j2_X3kK+sNIR1E! z7TC3SW0^p6{Cf&tz>MP@k5{3~H%Kh!*N-ZE6)O|?PA#?ER1ng`MGBAatrGYFEv=}y ztfFM0fa{qetw=kf3w+A)F*b4>ejcCDe9K7<^n`Dba!%;ICt${jJk7VvhR&L)&=FQ3 z@ReFx`L2>}TSTNnde&VEA7xbn->vyK?hv*C5z=QaQFw$=;1R~ko$?e!;2%_Ygi+wf zHJ|W+gTX&b@%JK(9N(LxrEE3{fIlwzdlAN7jz<{x+VI%{g+~|#zEevnwc|S!9$^&t z0WGD{j(=6*5yoDWOD~F4w0Omlw=9S0jJJiXfI&a2)KYe1(8w#K=R7O<8R8@G-FPR0 z(C}|gslp>Z0zae$igp(5B>p+03Xk{*{5aCQvvlW9QAi;@w@>2x5Fc(wAMEMlE$k6( zB`fPg`ujRrqv-drZnU|5gIeIyoqLK&&pcssDBK4u(`Ojls$B(KPPsVuKCa1Od}$sPb-ps+}S1D z6EY9xEPYo2==ZwN_j}M+fxgs*ept}Q!bu8xz)Yq4_s& zq!|LI;^gsN5v9P8EluNJF*N^PlfgzG^`I}qMC(T1??TUa#b4>dl;OsphQDUkY|AxI3Z+O5Ny(J?Nua zpi8rM#?g;OVXWCI|)*EPZ{VjqMY=mc~1H+DPL{U=b8$r1Wmz%Y!C*nqs*G{G3+4V z-!9>x<=`{gDL#SRYl*U>^&Bj;*M7;zb9o&c-s1z za?4m(Kem)!a!6ipo|0$C_Shi4(~4h8{)s^eC%vZp0en`&+@n}-lU%hUL`?;i;J9o_ zz*h||P_f(E!ko6sC31&V4O_=zl@S^%84qMBZ>51!wZ35`7*UWM#yjY_VPPkoafzoHKMb*5b68%X4%qW_wLoBU(F_hF8q8vSa4WHawxRR3#~ z5GDSO97#uW&9O>3L_Qdja4$Kg8Okjs2kUI1QtS{!cHW0cFTZ?eso1aCD#g?A5-E@3 zVmjc+lf>in$ zG06JAfiY-?QWcA7*a#a?x&ZifCmdq$$GyV_+btkXzb72x z@9$z=;6Hf6DHpeZ+jd|!tPuLlgwoN)iMYd#QA|oZ1u+m-eD8PA4QRas*hCLtFD_c_ z#RuRXg_Akl7-+;NcUYZ4q}M&@68-RpAHc6pK7j3tISLHP z_<#~j0r@u_CnKwq?=ZeGrW8-gmi5V&W?CAiL`U<2DYr}u>@Hf(KKF0_%oq{hud;Pq z89}FC+QmwEqiRQFOG1gy6h6R>K9>{WvTEN$&xPTSttc^!;RkhA_8~zS=Jw3)3)h@{t|Royvog_@#L}f0vZ= zarwVh!lHJ58a^MJzmE-rKX#%_>LtIvHLj)5J(@i}&gvxkhjh@(I}Ql45^T~t^7K$d zOIb~~y;>+{&YrXvJz*pogf|56LO+M`%cejHb|&~C+@uxnDc<3vf5;I0VRM!qM_TNuHY&_PJ2ktcaZVjmnP4=YOaZeX|rxlUJ)snCLF@Jd@L4J&~vq7SP6cX|@x6d^MbL5ZhGo1RawvWNdS5uQ}~ zRAe7erG8>W!cDyeicaCpSwqpOii(A49ioz=QX@kj?$pwDUwZDPJH@!P4az~T09S<0<%5nqRF+e%eS2IgB7-Rd-&F>X;a(Y_$-tA&5b~FY zO+qEu*{8^Sw~rNk&o)btq0U+&g9!iK0inp;?SHdR_Q^0h9dV}ep)y6M>{9gCn4_C! z2iiE1K<6O%UZs}0n=)z}1e8LOLy;wizi+UD@7rdXZ<9e$Y1sD~Woy#oP8{^P-&gQ^ zM;v(UqwRR7o!`ek+OF?m&d#TIFMX3te+2p-2}(MrzDEjK36PJZ8^ z65_mVd8AQGFWtMV3{Tm_db5rM-I*g5CJ7o+@GjX>U>+G}6Lv%Hj3~N6*_wuoDR`G` ziT`8{4B2EEa^WM2kV@XU#WT}#`vcl*w5Vmo0?D`xCf&CtAN@>Q|u5O$+?P-wmA`XIkFS^ki+ha5Hg z3O+QD80w)>HUWM6D1ww4;v>6$fX7Ltd$*LzBQnb$3Y^L3kpF`+R`mnOzk^ck;m;4c zwY198Wcg;?Bhv04^d;K=gJCub`7w$=*+HjR)E|mF_$IZqy_GKUQ}&zjqrQrtQ~#s* zLYB(CTUh<0xCc6^oFt`ABOWbFG~!V>y~)i8Wvpog^}UQ3g%O*!u>Xb;W~o0Kl*-5$ z>N`Dn41;ZB>9(yqii_l^r&E8Lk53p<5W#7^pxJ;*ygly*^E zNPn*`;ijBHJhs|-Df{K){>*icPip?1TefftT-NxZ!vHTKKh&A=LpU)|DEQ1HGN-a1 zmT3O@{V=}}etgDS~q>hG8RJBMZKrRPUMR`sKg+^wZ&A-BC6eB{_f~PEadS%LiN+bhkB>_|gg3|0h=kKPbK(_zZkTqj zw@*q2a_CeQ8$E>?D(QhvRiZ*N=tS^iDKuv~(*czrvV#m(cB~1Xn#3=ZY}zRg*KHZ0 za~t)-p7|i}Cq1n1Cpb3$$uJv2oBk6#Z&|!;6Fcjae@@Di8k_tH!vCbfj3@osXVY7O zPwLWo@`j@DB<9}@+jc1CF4p;^fBwE(mC4Rm3xA^EB!q-gPAJ60_hg||YAWkz6OfvsrOULdh^bAEYZ5BH7ynI5^#mMtflCwZqbj0Nx)Ns0$}#Zy{D_R)Lms8 zH%kj`0+d0-Z_@W`X@XuH&RX;oMsrEX;rj3-?`fsj^k7^XVhS9^Sff{`Y#z`Wb&oFT zX-%WZ5dTl{m>%}aslmyADZj(3lmh5zkpz(f+B)?{lwon%I%+=r(<;{gQ;a?0Gbfd5 zNpJSAll^~F5j@t(`?y3z@Jgu&2>J#G;)R+**_sZG;FX}wn>i4d6=9|K3QNF7L16Xw z$^OSyY)E=iJQ86&BdG9^AvP#lyxk{Syxqs!pJ4?23<3CAQ1bmuIY=Xkgcxp5M{; z5qvoNhWurQ3Ow2G<7~W=4B1j5eja4T&+*JEsbZ%{x}>KOITB8CHSvPHCD()(NV+6_ zC3sEJJPa}uA2T<^G!(zD1kezpAxU^TEF!$=5Z+8&znClMm#HB9b22{$g_>CAM)1GahzFcWXK?=$0Z(#Kz}FiSWhvY z9bprkpDKy$_<3B?(c{gZSINGU{}=dD$zNb7{z6rPc}zGW=}mi7<(n^rC_MS`3*3G! zc6rEtuhQ!kFBK>2MG;fru;$NOc@DP%mzAMsBch*F33TvEWBnH@P?Y&+$0Xk`MrBKS zp2GvJ-HTbpbN+Br5Y6gRI=zDUTqo;)4oP^fJJB}J;5ltT5;;F@l0G6>NfZ6^NaFLD zE+{t7DPNz@OZ4^mM$Na9gT!UU^f`kAu)?Y&n=9>rgg=knFXV53eo*!)cF*I<(r#0r zCGU9^doOvT8q-HnbTl|fKNTw#VbViZ#i$`Ve? zFDny7Pt$@acRDS)0A&|bwXa!16?J&8)~3*%b)h8?>v z-6US)WN$y<51Z?E(#9z$by3!6fYBD2s)K_3g2<-r!%!-lW-HFAlhVY1{E6Ma)R# zBYw&fMUot*a-%*))+`sbzMDJFxR8&s>EwUl60P-^DbX{VV{uN56SWc9n*4dPPlh^M zcf)bpMHW+tsihE8`(jWkpn6R*pwMAJMD|Ss75{_X5-#fbJa}S;(!&GO@&U>C%R(0a zm2GoNwW99JvuM*xGsv&8x&5_`o~A%LIsbKzlxxzLu&M<5h{WI7CEFzWZq}bbFKRIq zrnAc=`VkgSpzl}mhu!6m!TvG3{iBLL?m-XxLBEgUKz`EDpeF=oVhkyV694Ny*{31& z!JzC@e8#%jDCEaz74MBmyjii-AC~Z>6O0lGry)Z_<*^Y7cgmxe2<}nx)EVvE4?Y-@ z3{>i-fs?H3KXA}P0ifBA?(0bqCFVbZQV#L|2R;z6Lw!`tzSt7}R{UTA|H-r9I-0_TR|xA@5U%P{yiDv4A*WavwZk6!LE4N`EYBNSk&TI&C{OX^QLdd?H@ zSeRB2YRN-$9Cu3r1iwcaU^*H}#FN8RE|j^KE4B2zB_d^_ zYXB8UIAw`~L?eSXFf?g77pLDGd9pMZA;sfUcaXoRUS!BR|P6Q{IS-hv|1j_D#7%y}w6I z5t>rKCOH|dVg4V&Ec&7FV@li!L&8ZN;mM4r@+98eE>U`NB%Iz(S7C~ow}eRyD&C~{ zaUm#_RD%?E8fE6~NJJ{6d{LX256tPm#~kWKVI9*cl}JK@PpbEpNC_-@&nAAnWQnVe58&fskNjDLQZ zwqK?mya5S4>nO~pyOg{U(V7pr&%`DCjLN&okIzDkV^MH!`;L7~{_zr@??NtGTvpo8 zbaDU|6Dh~s{+)?S_~}X6o(YQ9`VN@!eqYMwMI6X47l9(5KnWVFPDoMzu;2@yiOZG- z0Np7i-QnbMI*gddl%-Ul#9&tbm=x&T(2h^|Qg*o*?3sC?FckhzE{-C^Kd?(1_A_yb zpykaR8BUKC9j#(CSCGd9r}e&%=+)FfQv@%CG;Ya%_Or}#j>bU@w6@#pNY%%qas4|rXj=3_>*nWYL2T4e}su99L5 zfi)=j>F~w8HT%?%>E?w z68_+VPKfV+>KFw~>6>aA^d^2M1_tGlXA}|B5PbCWO{^DA z#WV+ygI_I>4wxmPGWbxLgp&bpDu>M-;jqLz1Mrs|U&>A^1ML6&#XrR~g3eNCJetv% zl)}!$WlM0{t`YoAj;5&?t0j*ec|ta6%dE4Ee-_ zFBM;Yw9WZKgF~R&^qYez>?QB75nt-wlC|4Poo^+PKuQDE21VkpJ*@w)n8u0juRKsl z6V;AMH-b0pi#P5m-o*^OPnYr*-az{+BL0>x>1p;!s!dgsv~Uugvcrrt%|2eUj#myV0NG=Ul;!Bc0&I8)^uv0$iB|FHU|Egqz(6^2fN8_(gC4}hTD%5a=l4iaC8tZ-AjlDpUe-!)M zd8`cl`;yeFe4G5r9A}uFZW2AY_jV^6c9kD>*!RDck97Sv>X&8`y1l2FhF*F!>s1YG zdUJ~CoW}tKr&}c_KjD?1{_uZSvQfJsWDp6UIwLqKbi&oLA2tnCfg(q|=#}GH=4~)# z;J@+o;2n(gcLrGBJGhB^2QQ+&gL8m);w;YFzXe(FZ~m1je=A^xf8+fsR`oZWC(s6m z4EkHA%oxf28y*u0IyDeH=|)%_blZvFx!O@AseK_w>Y+eUOL`}RtYi|0^E4BgcZK5X zpIpA5vQWySf%P{-_UTrFHn>ksD7|VGHaF672|qT-Tk~Ax!sIW)R3%I+BMJCh8E3Oz zftrl6yuYJl>8%xVB!+oqzR6gb%tG!;cve?YeH=dk$uxQ(Nd_}#dKCrx{XqF1vCJ;@+PROHNneGt?F zm+hvn?6vMYsU%MXr9AT#?a3htIIdcH1B)hjO*~ExnI9OSdHQEvlFuxaGTA3QW#+w3 z38$}erbz$2k;D14*Qq}Ir3lSEafxK4TKXV*!U%lApQV+YC=qS+L{zkWC;9?s#j><2 zNl&AkN`%^^W4r-LPlK2;N|7Z#f}4BzZp9a|>%(#2Q-c!ldxbC~6O?e8cPRp-fCeKO zLN#lCTCGy@6JE7hnleNLD5Qn5G<<-1+m6kpyNl#^m*lGA%F@Q91Qp6G{LJixFEGFS zbeDvyT2_;c412TJ@;*yW({5dSoADC|rvLt`UB|Y&`>-5Wy z??l_Pv2?fdHk1ahQ|@#lLGE00T1yg)_cLMOE>A%{34)Rig`DyNK`njL?k!u2%h!p| z6?=LqFlVbpa4JV7XnO$Ns309o*KyB?kRXI zk^h67#J*ErY9Wh4o*6MJiBx<%D-|ViJWukQ@L?@=%eLauA`bo-j!v(X{Ac2_JvJ#@ zdfGzkL6Th)zI6Uw59g%?<}9P&$hkIoLqx`fNtj}`M-kbtwPT?hzjb31->T#~d6fl!7DES`j zR%%sizF#2w=3#19Fpu@apo8Rx=Z-K>3M4=2cJoYJ!l|XbyVpz_9AU;3tOSIon-mK4 zloBma?j~Os>zRTXI*Cs4nRG*J1p4PXhshKSlk(!t zyUTaUrEHnk5^*Lj4IqIT28(1Mqco2^Q=$x1$K>~asmmfZONOzzY|);TpWKV@n^>k};wK13U5 zW4xV)qfgNqEN2?;M_8d~t5_x4jHMkyU)D5y&*n6&@zVx0fBB|`9EdBVpM6@iS<{Bu zAn>tiW5Am~IuO#05rv-syfnf)xI+3;1)m<|aGSh>#95I^Xr6bTzFoU z5jp<0^xk1^_)Os_470X>HD-%Bnz`H7jnRqD%U0tOnvs265 zy=zncPWF6eAZH2}fZb+hKkMf_OH>yz;@uL}g|(T1*;ATjHw>f0=nkkZK1s>Duc|IS zL(RMMR2Ltm=3SMna3AXl2NuL`QP?4E8n>oo_on=9JFGjMRZl8>T;ea?wK)<0p2TP2 zdjvT@#}`*x{Hxb0ydk}6;Gpv9>r&kzE!c9Tt@==YZG=PQ71GapgZ~xEni)6o zH1s%JKmS>YpM^)slK;~Y4v`n|D(kZh6Q95zyFllpp{!XEB500CW&zjFzf!bWv#Lyd zf`AKD@@I7szB7^kxZ>|O@pk^H`UQQ80Q1}|gsV(-G5Tg9Tq+aU!QSjZcE);TZ8l!> z%ML70WCzZk z(xK?^!VQE@DNtQxmv={GcQ&#+8{M_4i|q1lTy>FM-tAFc>|S|SIX`=t4Wk=V$(lW` zg%02+xn#m>s`-y^af2_Zl-xPG9pBz`9pRPqoC1k&Xs&K=%(wWrt7$N&%#OGCW80%j zK~$T@4LDTOX|i(zwyRpr!L(btZPT9Oijw@DW!ATTZjUSeL2WwWH<#{I53fVI{DgEU zD`(W=FUOncoD1?}`o?bYM^?^+C17v)whFpo+o-1MIl2}sUUi90x!}_`5v>y&6QhxFLh$^CFy#%YRR_S-E5Qjh_fsk@ILWO*85Z`Q3RK6-g3~F%CH6)xANA42>v*s4!izN0~3N|Xo=Hi=|%eGnY ziwYEdV+`Nzv5B@csCKC+Yi<{Z?~aHr4BFPC81S+GqK%uBq>x@RsNjPVP6lloQScES ziJd0>HbcSV621`e#|1&-3W4ug+f`P+wICwlTP7rY9=;z>z=Z}Fq~?Wrc@i!|6w z?5sX5ux<0EZKPmxT+$nbtp6-5Pb$)9;TN3F3am^q8rj5Ifu$K0x+I&AuS=gFSQ?vO zDEj6{ZRjp&ehGf-Wh4JW7=hP|o>Y9@TE?!5jpY^jMcT=pnjgr_*rKvFA4}_e*j_1V7X*731ZFS1 zOZD>b^)BV~+gH$7rQrC*xdnmw`xaE;C%ow6uCPdbK~B~JX_@I^Z$$7}Uv}bCaunU; z!xB%CSkT1=7X(&@BOI)S`cxafeSl3Yz{;=sS!WG0-9Uu*bb$=>;aTG>!u!q2xdme^ zYT$^4Zn)_LfNs2>8WnuzdDm|TWS{W#u^HmOw<-~TTJ_aYP}V}_kLqWC^)f-f#{8@W z9Y>SE9*)P2tU71US}-a5eFG;W3j=H#tJ{-0m))=@^@5YX&JRQi7aCU@(blGxj&`G? z)%bK%osoB-tv<^C+R##csJ{K2ld~HFH~%HO?r_v-Xlum|vc03NspWuCZ5(Q9VfXG% zJ#}(uPiph@P%VDvv!lAD!#KC0uA}i}UR~%g zOH+rmvaPp7&E%vR}QQx`EC9AobwM|M(#F zpL1gchB#a{5WR-x{JQ#@!v`|Vut^|7f4H{89h%=*-&XH}Lay39z_=r>Z6ux;l4EM& zOdlo?zw3Iqy}k~`BkVL$v#*_G_A=`KpBSjM~F(JlDL5onu^A zizId!%Ms7&w&jMg)>vHK+;pG?iY`QzTqoHsG7x(FX*Acj2pE@u&FTS^%xa!Q@JEb- z^&5FGx%*@241t>ke?k)Od;+q`guGo!q?taxLEbU8!1tbF4E&#!K7M!n~Wu<`Nbl5HavLG&;YB-+j^ zOJqQ3gs9pTki(NC2C5r%#8}0_HpR6I6GVu_@=S75%qYhA)FLYnvE(7*|7>+2GM8^~ zMq!os5#s!g*8KW5+~`0Or_aa0&JX}D*s_6AEg*uE`+>usY6=R9(8cwL(R!r5&Eb!* zW#${4@Qk?A?3rs->BPFQ1u8z~h_{^FoYR#?otU%f0B>g2%xdk@2F?`JE z3MSNGz8MI9n+CO})|hL_t8v9O*vANpmPguH&BvHhBBujjMEWrcNa^h~VJu%LN1!zp zxm4wSQ%mfCX_|MrVhR*<6Ff;QRue%{^{P{okjhjlt6dng62d2*r26F3uhRYhsyc;g z@;WAeRohvXwyLxYu!>SzpIne$#i&YO7NV^Pn^#1 zHT4Iu9~itoFe|om%l@K@{bDBEzhh^SSXc6!SICIfA8D$s&+llfuSfna!W?agDH^N% zB7?uFjzzkze#584^eZN7ULa;si)n+Rm0wTW0y&KsQgIBgSljiQIgRqQAkPpDpVggH z{5cs?KpB4YPIw5Lxpvzq!OX*pB0&US70$^pr-O1Re4|mjO@Ci^rTB_Nz z_XdoZ2=rPJX+HD}9$75Ud^L{p(T~-*#A8`?5z>zkXGBgecBSo7BcdaNx%1_G>BtF{el{-8Rt zyV+FF_0a}OtQ6c=^#kTA=kIH9gcRi$GkP+h6$UH_NLYrPnyL%X8C;FA&0!sJaW@k|Ea}? z+M8TxRQ%fz8?Nc23<|Ck-zK41lQ675fmYqYc=rd{j|< zWaS|3nCkM|F~D4EBgW@E1dkil+*4U^pYe}v^k6#Fp$79*W) zn4~`)S93EdB_VwpeQ|3I!7&DdS#$1XF^Z z10Sx47VGLLj!)|H5w036Jz`%eZ{`IA>n6XmKS$o|ihBiflbRv+BFkwh%f}6T2PO)+ zF%+wq*dm^jv8sSy2H$Mf;&H|yvFIZ3a`7{_!wdO@XToB}!jE9I?lWzi90*P+$-I>j z`()c%tIj?aW*lm2Zf1a?~a7M10-Ln$Xi24O81#5c!eIRD!`SP@5i#&X0K zw_aBo<@KUWj8*5W++#y!RJR!Qu|rYpQ88KYa;-DOa8g#7VdWtL?7mlgKM2wXe)_Ej{yD8NiYG0I5+a~Wu`NqsF zF!rhTKo%SRd?0n9TP!+SJF1&SgrJ;ltedu2(3XBUZJRh_LLlY#UVed=xS7Cz*cWer zu*Us|st+{P8qEvYVCHn}1qs~2;{$Mp48I8eY9rcIdkwN+Qpw!y=XWECq@*T+6ah;l zHL1iOkh)&l)Yg9FP<51OSFK8<<2};?wLjtN+3&YZn;9`Nauc+l6L75Um{lC5CP?AW zE%)=&TEyW~)zh+yZ5m`z?x%RDAS9S%>QwPiwCu7&X$wWBmbzui%n#UQl-Xs!OPj^Y z0%@r+_d&s@Hj}MD-isB#OiM<`#9ZklQu89#`FcJrT4+8L zAjFAp+u%Ca@{K}0M!uSD`ACp?S49V7Gf2gS87F(@OfL>D<@VbrY;m_^f0N3%7=qaT zWofgg>@F+9uW05MRj?bDrOnSZZ|Uv)!ibZ(OVUPCW9=QSZT0zW9o6mmnDJp*bsb+q zuy~!zff)1V!vNf5Cf*9RH@7yd5Ul*Q1>6Hg#G?heY0eNRQ4n5y?X$!V40omcnS{y6 zUOp#nSt!vo_QSKMFU}Dnv7EPIy5lx;#h7E3pZw0Uw1!`P|E}~cyJGU>yP>|Lwvn%r zhcQ6q35$4oz%!Q+OdX!R0Hlfn{WbPM~Z{}MYySzC78b|gCEgkv@}I|Y{iPsk3cgD zh^{=FtWcQ@ykX2^p_d7{6_Xg%EVKa!k4&qdEk6(IJVI|DOM?x{~-G^KSd z-+FA`xdTs2cT^aBW`f~jyPQFfYY2!4;z5F3MQku+Qk+{5NaV;|Ys5IQo@cRDpZ3p; zDN>b_g^NV;6ZqxXHqPk@%9V>f86T=Ppi?`qJwgjh%;}?mANvbb7Ca<*M9Ug}87SPs zi*OCCJA@KqHqZk(1;ud?R;-Rzh-^9l59GX!&2>k{h3wNU=?}(|0wvy@lVxG7j>y2E zAjF1|baC_5oG;4G4i|)|FBC9=ZCXXyiY=!^P8U8Js&3g=TGHpUhSv0pFG}XcJ_kEI zm|ow)3$>=TqmlcAU}T8s5eJMr`McKiHeW0w*}4BmZmdp_U%u`3i)yb|8g*w*@KQM{Zc zzoi}rih1n)&!%5=;KPmJ)%gEJH@j-lv^gicV(Ci)>K&T!5&677d_vE-j;U5DzH&(Q zJ5@WN+D6q@vgpzD>`m83WdEu>)fTFj_$F1qQnfj%RdTKh-g;RU`_0kxsp0Dt%l<-1 za`pJFm(5%f3SX^AuO5-`{XvCSBCnog1)ob_nR0zMtNL8}{FLkaSeI)1McdDYMLWde zyltE8{X8ebXA?v_#v-B}XH~rY7frJNOAhP*eEN~JReey0&qN5w4YMcYO z4Y&gM$KT-cZ{4w5+x*RQedix5eDsd5Tv+|voA0T6;@HnMR(DhSL0<)X{-*TVa}G{$ z9=iN^Rha)B${u7N0G-=hKq$2QtK*fYxAd`s?)2=G8+uqtclyfQBrzGBFO>cDd8`Nc zl$uI54Eo$gZaTk;@NZ36(^7dS6uulkwF7*tc8K?J<>22Q3tti8Kuz1u->$jJf*&Xm zV9m!PaE%4OLcuk>2bB303x1H`SAxFN2G0|6*yp~Go|)T1MsnDfEuzXXHuwcNF)V1+ z?--r5@Kv2G&hZspiU7*BXDobmkm)xAU&)>0*Ngb~zJ;&LV-b$884y@aYsA+L%+irc z-Vf=mr&*NaD=23OqVHUbzZPGB$ML(tA}*AHZ)+wcE&IMcHp=nQN`*(`tF!p`_4R%c z=%%1T_W*s^LRaA(c8;%8>^`pkHp{&3PFBV7dnXk?-aYgEo5jByACUomdqbzf9|itt z3x8l-!I9&sb1nFuJ_SeP`;`UXhtGCHUaUGt;SmBMbE#N?_ebdj7hN84EU=S{0cJkS-{`5 z;QNRkk@Bb5;Ehs_?@7QjEqD|3%7ttR5OXX8V8N@prJR`755z`unhXESghXidfbX&x>Qp2Gg@Et3;1v+euM`w-puzNb z=tiZOuX%wMi+*pXr1y;iel(2u(;}uU;sFR8*UdfA4@oJProiFl$h7trBqCLRQfu>G|pyu;sD_3i;(jk*21S z0<6v?rxbAeDC3Ta`okZo=U5E8g&6!-1h{RPZz@p;4qtDkEc?DO1vdcSYRRc1dM^Jm z3*OW%>3Irbsg)L@u2TuZe2~hQHdTxV6$8hnHe2)!LyEo+@avHeMc-VZ;GF&orlH|~ zAvvh6)Z2v|?tdt}Z$vWq>VWvFrQiSriwiSgs%`46npE%-z-_s|YTQQue=RxmR=w5* z`d4g*21WcOQ|ezWhAJh<_XZ}Npas8tOw#&S06yD-S5+#-^8mM{a*v_lIe>4r6nC#z zaISxbP0*e$g+P-rVJWC6lW^ZK1nsrpR}3loSFu$)+kzh~RB#ksS`!rect50zMxoN$ zbw2+}L^FASZrW!pK?m{_HSlS+yDIsKM(;zw**}= zt{D0NKg$M(LUBPsx@}dwyiE)t_-;eNy8yRMu?HZSUnzVT+YGAc7hp|`gZ@>^puej5PeY2e^tUYq zRV9j{0^4ufRN6SC;P(M;&f%D18x_0~aKn;wd5(np`T@7?^{-ZjY8~)Dc#*}>IHCmI z0(h|nuk2KUATYSkf;Z(U`d0z3x8VE76ubxUBc{hWH2e&pgExUbrdGdw-I5_C0K~19 zpvp=m2+0e6-Gc8QSMWZ-zi%m6sK7kO!5`b`M--v}Dc)qkWA#dq-vEOx_q#zTE*^>B zSq#+!5}fiP;I`pcGo?FM9bR0$da{8@|s$~*-x1N;>WzK7@`Z^{`9zBef8`64*wAGSNCy(JbR zV}`}BdqOGbLXp{4!Aj*ZpBFMNwCL+cBz+ocEMuz$Zx~l{)&ss%!TFuiRbvvtEy}2} zs=h$cWAJDh9Tq$y;a$AR_!kp?YNk@mM@h!#EX9qaxDasLOxw^%GZjQ-*m71yg3x9> zXen6P$yMTt0R96@!M>n?YFa7aqZYhrK*4hWx80>z4k>syR;r9~i=lcis3yVR_Q_! z;OY}d5*HE-lK$X`gz+<}saq_A>Xd?11902w*wClwQ7cocEc(h-@KjtFHd8yGcpC48 zPDOa5uBq2s4104}|6Lfik)T4Now62u%0v77Ftx`9f03kNP5P82uclMNQ_xPeEp9c1 z67B=v)UR7|S_=eRgiV_&ZZ6*6I zqOVbghQ9~;^$O01ZM8!9?gL`G#juYIY6jePA96*b63+!SSoD{Zp#y+_#xf`sk)&(d z|1k%{&{2biE!N#>y_TRWa};?8;P*k05FAn;o0GU{CoMrY#uYv2rafxOsUkT&fZJ!< zaYbKS)ZC}w{Cs-)OpCs5Qqubox#@h^s%=Dl zr-b_|02hm-8ny=zGI8|*vCd+sB?W5%FSZPAg&}nLzHCOKF9H&AArjMfTXL>a@_iiM zW|I@Up2Prgy~R*7CgDB<@S_&I4hD(~GNvE1;Csp>*!Ljdwp+ygITG%Nyy@Sz=o?BT zJjN%U>BFW6Lr3!@g6Dkt&n z;r?MzrP~fTniN7?0>li{pi?VJ5Q;Q3$7YZ+G^G!4+vc@)OexL*JYvyT7uw)EDFyhp zfz}rl0!`>Di(wCe;bF*jAJQ-)5x$v#AF=4GVF16~C;%+?EGHCy#LSTZKkqtPlj!zN;;L9xfsxbwJo*D8`jr$)8 zf3{K~>VdGWc2#{6?wbJoD$`KCyF$^UnPEFUtAv5#dK+-t)LyCNXwWm`R?DFMC35`{ z-*Y_UYZjueP|D%sb;h@B@NT7GCg4LhI4Ldx{3jN?aX`_R0sf2yuNzVDSQQYqqnM^f zg+LL_u-)$OQ-b_Q0sn&~sCr1zj{^Qz3tm~G;P6;au_AX z#gJ-P45_wTxIKdk4uQIuN_iiPnR3AQIN-LKba$1a?*iOPaV*@}sSu?=*jBl{l?vVg zc(dhMV^G1@0&aVPR6D8QR|5Vei~fp21@8l#|J)XBaNgi>m4E%a7QKuT3 z)-WaorN98)ma+;%!nO5)pSI-GmMC}>aNFMWiaZ792F2d77}WQdhzA`r{$#-`3KT;T z4zU832hGP798KnQ3w{$KLsw>wC8t&?PRRlNQVECuc*3GQ<1Q(H$<>wdhlf4F`>UiLn;|H!9KR(~`7t0}p=O7YI9d|z!pfA1o? zA8$}Z@nQS=lfDPj8+~)^1a*zIHhkl^(r5Ti-tbU*O-Ah3ut4l4lqLMoFb#imcz|HM z1w4dZ<`Vqrq=(@G?xfEJ?Sn4#^A#NQG+zM%1xwMOijov8Q*ft(b%68ZbEiT4TZuW` zNzcE0C6S*0))*A;@L(v1XN!SzD!^LmTg>J?n!a_;vp{pZ%`2q)gXnBv*FT!Re-)R! zLg9otA)P-d)Y|Y*Joi^PSdmtUzmKwMkEQ>54o|^qLh&}Fr>}(4H1^(O>F3V*gA1BF z{RdX`c=|41H|u*GRNacP1}&c@l)$B3EdF@Uj71#IN4S$=DPW(p6m;QFZhFQtG#swzyYQ!g@AFV_ zwSqh4^Mbz{|F}Wc3;c%Oy&>PdI-t3{^OCAbt1AGYtITi4XaCo8ued;qF@}J{yms*?p z0)+5I$f*F47jTDyX&LScrcv~r^kK;1YZjMpueE8}3gKkf0{9;k0~&eZJB^SU0e8}0 zr{E3;rhPV<9{M5Z^Bx{hYMcsQ_n?1M!5#F|QPFP0efm=P?^Z<9J%;b}t34Fl=AnSs zL>jzy8uSd&Tk!`~NS`i>BAFqyj2M73uaF*E>8>DjBZyp57DA*GQYQ67&?6oS9`#T_ zp?2gr^p-pQjHT}KV>8GzM~G%ns2vJs)OaZHNWlz`6wG)*$btV(1;6r8@V>hTdWt)} zzRo=b`UZOn%>0LReT#>J?H&q{OSh`lZ}y-^gpz84f7hap5G51^y1W>58KR^J=^hc% zUsiG)5!GK&a7T(Wb2Tm3&4bMO+yfT)88)kF;C0B$6eYmwfR4G;c;>wx>b~I~ugnMB z+WN-m%K?+DSX26uyIk!Mc&J3QzqHBNe}6>gA126C(}cJNYB2`L&0a083g?!9`uiT(7*0M|E9hS^k%j*!l# z)HrfH+r8-Y*<|QyEB+z{v!8JHfFFUm6=@EQZ-+rSZ65ST9P*|9ke>6L2g3^v2AIiH zFlW9y{Tzy%!=O1k-05R;$~_cN^{y5g)qhazF|o{np^mv-8j5OnTbt*+EcC*ErvjRx z93JGZboU?^{BH9^E{3t2LAj_E%OErVAwBmF4+ccSV!+?x0{vSa2EF59(7RwvT>bd? zhoJWr!r}4U&$=*xe(sGP^k!89Z(g8(!rh>`7?!ali@1U}!Obmo7&I@}-Q#)l-4)E+ z;6cC1q&MRaZ6SRg<=#;f^IkIT#;`uW$n(=S-095d;K{*b-^6N{V23(B1g zTtDddc+j76_jtk6?gkk#2y&ZPjC~#qolsnbe;N2^UidYS+dSm-ddT@6n5#5xQ<9)( zJOt4M<*12;LDu!h^z79OJ!)g2M{O)@W`p11M`a6dge7b6&&&z_Mu-=FUcsFT?{znD z;WykpT{s3gf5ksX#1^8+eQErh*s1s}cR`D$G2<0@x(K!6ma;|5Jot)O&jZ0(YxG5w zQ-{JuS9>t_vG|2kIOD?}8XxgsJS`Yw`Xb?DvWts6TwIKYBHAC5W3?C-yScphe0KvD zM*+Wty?Wu4%vyah66wl(vj_7l9`vud(=Q3I$Ul&mC5XRUAuU;{;EqCCQo?1SQKzwA z{xqn^^rg>vaFbV#FfW||cU7_#XQ#Q#IUClBLUzbGy9hEq%Z~mL@1mUTF~-lP8gueq z?_tAj9yU-dIpsXdZP3`~{+OP*`s|lIm}z7=nDgezIXn-A?KV>L4!S#@*R3X~yn8(u zzv037B-2Y#H+de0=6M;)ALE^ae~!92C+x2OoNRaf=R^Qs&Tqb)g7$a_qO>|9cTNwC z$#XG?99RvUd4=?IUb7oCjW8j7**rG9lF#+az~PpIW#`*DZH%3)e`hdz^|CK{@KGT- zEMN8@>l)y*-?FDY7@zS_$R{T5mLqh_-glR?JjGqk@)E%L%Ue!C%W0@MVz<1;LlBO* zd|?+kPbhk)oKrSA)4?aNkiH_o$`Fz@`if=loGVt^IEfEil@(=d^bdFub_H4J(71xe zl_Li$?t+k8@y`*;6_0r6f7C<&i;%HhW3#>%)M5Rb9^7xabLY=wRX^fx=Pz|<%%^ZT z%+J4t=`Uj8&A-=!?;9QppJWANobO!^KB^>#zLf^+S%FetiSW7&k(C}pWMwlOeF^$j z-sr*id3QTkKF$Wu;bU^;uRIuE@?d+$|n_+dcTY z0Oub|ag@=yy&iJz@Q{Oh0^clcbF!f4JOsVqA?S_XZ}G?B1vA;i<-zQf0(>(63_e+3 za3$#TlMO9sbC+Lm#9e+t9~*oneRk|254MLr*f31^C$^k%DtO&P4hzPMateyDvYEWVR_*g(q^Z!!*va$-7zwLx^WdY*JNX7#{~XTuj0Ybj+Q~Q0 zx)x8tVzD~KopE)Vf;$*j8weG@0dth*>UAD+Hh9RXgp9xNeU?*Di-#a8DW^dLtpB$d zo2xw*ht;Rt4Olae_4AvIHLKnAtvTO=uZnf$AmVGt9`IWievr_k#MgX}>93{FUiGwx zI!d6!y*2N#=v-b=YeVjgYs2n#t}SC-SMlw@+8PhW1`ozQz~?6?X6*wWavt)K!>i;` z)=?S^$IjF7_u^!k=Xs2;^E}4ac`G4fJ^nd@eje|0xFdS!RRFdJo9H*wGh^r7=sVG!FE>kd2b2%%ag5s$6fLHIx}{l#Li#lZt(etg4=R)ehKRu zM~QhP{CtmupWnqsb*xh7(<=S1PGgn^_ zc4xjI+nxD>LRR)C4C4#-c<|9g?5Knw3Ci#MwJ@mig zZg(MHa&k2G)a$s%+~Lk!Snk2w1>Vb(Z76)&LypJX^2r>~pN-#LedOlgj7#)S;vQZ* zH(Bf_X-0F@#V43kUlkHg7>+aq)r$X++;Zy!XUTZ=7r~T_)IW31YOw33W6Aq7vAQsk3-)2qrFe@UD*2j5v!PtrgUUx?}yyWiq1{&=S`4?x~>G`d&xbWMWx$X)smX;=!z{Pt!=)YuFV3U8F3q5}n zb+Jc{Ty(8i>c3H=b%35N3^*iqFRZ}t#GId&TQBxKy;BFCdh zH&#<99D+9SIqp}$2C=;6{950|#YS%e=k zZh6Z?;XCdMw|Z2>R*#C5$w1bi#Sd|(dC+h0px@-AS8L?$>G|%Sm#%YnytJ-Y=jTnO6nTf?r8K%6Gj8b! z8+;e~F7+stOFc^E(t_SaQ*ckR1DSJs*uUcu1$XGX4A0tp{4Enlf-b{(uq*rsi~a*2 zn!AqmKc1dla~a=E@f%Gi`?v?3A5yr`mm`egLqZfLUN=Zf`G(&2pskD*@TQJcy_Y_h zZT?4kR!Vu7gx$i1=S{)gT=|3IZZ5a{X@?}?FeE)I=*8=JevnWc2pyN=#)XuW^7okW zPiR~#n+>dt_aYLxYX|G%-AajUlucA2kIL?G*~De@J~JM}*DhCNu*m!Ps@;nDuz-J% zlibzuH{7jQ#G>!x+ntv>(EOBxqnELMj$Vl#_d#*{BKVu5SF=%$MrkFWaXul?H}-x2 ztFhAJz&54gE>^(14~mA}|3SLWT0ck+W}Z^q6rd;@{UCk8oR<=XYW?VQov*NAF6LF% z^8uvpPGJ*hPwWWJ@r6zpc*e0?m-==uIZ+lwK*j&-6|7A3s>J`D;{RLt|8wqxZ2oar zM^){9h3P(^UkA#b!#Mh|W%nCwB74fLx%!@Eih#mfA_?}aW>N4XtDMfS@7cuqxxDR) zoLt782A8*|l;rJG1SD@j5!CdiKwKS(yMq<*{@o(UDSJj(74N>p%KQk#p3}1XI_nbM z3E7>Lq1Zc(O>p9avQYN6FvE{-pM*ZZMetk+nn$^W*}h@f8&LvI^8(IJsocZjz|J9) zl~2AZX>#RJNnY8<`U4O$pG5+}?A*&KVnnV&aQRwERwA1U$$WXE>|QULIX5Rp$JZ@Y zU4DzA?(I#5ru!t%paSAqC(K>FFT=syCz);($yqNkp@vv;3RU*WUmYs4{F6#*byNC_*X00rftJGX}RfX!~aE_PHRVcM7sMf0< zW?iCvT){_Gds<4rYJwS4g0pk@(*j;AJdNfR(ywN%S;5)4SJwgNhQ>GMgBwF5&KpdU zXxQ(j1cRBB?+Gpqf+m@s0g`}JyFW*ESIFk5Y%J10bjeh;L{h1=R29i?rEG3yJrFVHHV3bvc<+-`s^Y6q z@m%2;E1SmkG6RjX98!e)A-x*g4o;=?Ru{=`rD)iZ8D#(^j$3(l7MW#a(tqLlF zDP_`(nnD%@+E*$YR1|l=rdf1X@ofPQ)@n|S@3X1m|A+LNC(zh~NbnIU1>b1TWvbP( z<~>#w3eH}&PBD?NDEbgqyGg;xGJ;nKHeZ!AskTFQ@#6~+hB)!Yoa;%Znp|ozeRA}> z4$%r-7nJ2%H&e>SSM>Ap-dskFX271@4vaZ8m`*u5RFgvU%q( zL?3D!(iB{YH{n6Sm)r0p@SXTa$-$q3?``n{>l(f3W%TWWBa)!$H3cWZ1eXS-99+cu z@hC6%;8M^9@K4g+@Nf`+!?1(*_0Hk@hii&t+q{IgF}-;J=%e`OFsS*o2b{;s=7q4Xl&`Zs76ea59A8)8sOIgQ40Layh;sqWWt0d9+7;OIqCV#&EZb^3cya{pQEU5YT&ed+LeO7`ht$X z5t^G0GJOvA88>sh3;IhE{eTDhAvTD&oMPS20>2Ia9BR9HDgHDW{slfAy1|o;Tb_5>e_H^=FZN%hAUgW``h`WJKDHGHuYaGqu50hR6- zuO!BPcY<5^9fFI=x0JKtvoKt5p}h!|P89SA{4JGok^fSiL++Twe+f6kxd`o-ur%S7 zb<;48<@{eRL}NEt@qPJv(C-4yk%}+h;x4C$j~y2|w=EI$(CiR&tlwSGu@N>g6SKx~ zP1L$yKR#2up z=C>0aP|PdMp`fpnMer77N?#Ql#o<6oAJ$0pxA!4*+Am$`k9)}J_n?1)=|95K(Dy4= zfD%~U_Y&yr4#m-jLw&C(I5|Y{S9`^Za(kMT^Z(KHJ@8Q#SKG@5VH085yJ83dam6T+ zm(mz4BBk~gQPY4lB87;ED99AaFJ zQ}L^~Fz)idE2qW^@Ok<7Y^luKvqPN3M>s@3OQr2Gj%Sz4JU_c#e8*yV=-IIW@^Sc8M@c_+{9&9W38rnKx?%O+o~2CI>P_l3@0VHaPOLg7PC;wiQtaAKM~-z zpJtz^LZFQoEPVuU} zP~Z{0Rfn7g(92g*QR;Ltz+hv|1%z3P3<1v#;v4~dCY`Fzxy z@A+x4MaK+2kGrG-`|#=cxr~dL;ao%E^PJEjIxs&kSCH8A2f^qu5uZN|T(7ny`lQ&b zLQGhJpGQOd%An#mtCRWHlGtTF=d)nInz%ONJ-W5kIq=C4PGd8oyf#OM)-G@|SEB;g z;v}gL?s4pbsP1bDeT;4GZZuSIMuOMwmE!B@1t&@Q#5I zzpdvMpPAqQ9^2H_Tkoc!(5FW|iaw&g>9%ZKoj7b#Ri&y&@f%g;@>f9*F9)$rwK<&F zo&(3?>a`raSPHxjn-TgKtATlZ==Y*rR&a4@3e?Fcy|`4g6JOlu?MO0^1Mdxk`ob~< zeMB$WpK%$bRV@lH6IqHS2j`HxIfoq8yvKl(6LaXH^@sd2?eD}m2I2w#^BpaJvQ?Jk z@0K}HeD}})yQi0xW4`~c*?X+NOGDp!Y(@+>`}j<4b5xY5v-SFb^#dO8<^>S&aAfmB z;2veXc?od69G9byfNoyKxEzqLgTnFYCeDS5H)ARFnl_vFhzk~{e|f-i9_$zB=zl4U zQFiNI;?4ik4T8V?C8PX1)Ji{Isxo^dP$_vM@ej@ z8rP2t3ZErQV(T8zJr;wlEzL2@?HzFI37~ZmR<<2sTt!0RM-6`VcAHA1 z;#YWvZ|rSXOM?;e?bIg+48iS_Pz z2wV?qhWV#3F8O^O6kY?I7xKzij-ivrW;$`kyX<#_a^PiR$r!qWqN+L55&Y!*4r3as zqsop-=4U7I;7R5t6y7BPConj0<^9uhm|Fock5y;KTHt!}tI;R(n;4g7R<$U6yEt5w z@7ND|9X2BjI}Wj&$_2%a^c{8V{&4g6MKY(qpW>8#1I73IY0PgEpKnzQ=>-4pm0vdX zHQb!GaUz3XOJH@|0fv#R-^-Mo04}UvB^ExBiiNlZA>bi3r3M3{}2Gb$C=z8ddf4oKfsQc-+veeT^?t0e^?>n zU%ZQAvHq*}c6AcxZo5jTDc-dJ9Qr7^3U)o}#BqY`-z9Io`*+FD3@3$N^+SMEtMtdQ zk2Jj60S)0cHZ47`(r|TtHt=eYaijcRy;h{N{MEh&y&iqClR)FK^1ZrV$oXI0EXuC( zRaHhd__gwSRh5yltMu*z7x`)82b}cRP+qUL81yLm@F(S${-)IU4f)h~uzC2Knj-y8 z%@F?fP0a+K9zUKYso9LXdYz;lC@g4Uzf+G%|5A$$z9{%C3>;|Ccg)THPEN>q4=8^ zKY&)ZukaRu<3m;@(98md3;~6|!?@x<%>3%0Xj2~!Df}#YWLWVlJ?9y>(fT?;fC;-h z@lkPiA#*56*0{TvaT~2>X*ZsA5-*tA-5>COut`B;!e217oBD*8QD6N5ABcSq7k3Y4 z+!nlT9!@j(Q$&ZJ8HCg4)iyRQDZ6K)=jG6B#!ZLj0@oc%p-%?p8@LMD0>*8$*N|aF zc$5j!fLkSh#KT+&RbJ?iXPl}{bi?nD7s077XgrVh(EKEvUF@jvfIPX~Q|V;zElU5M zkxpbdwbf3;wKxggGXXLlL*6ryan^?({(_-B@Q5BD+Jg@}(H8Hy0Qj5O3W%=$f}uYJ zB;TJRP697OnfNElwH_)il0Q+d3AeFnMe?UH=;`BJPGsmE$G94&!lOHpq?a-4fxA@4EHy*O}CJpLTwRz9*-{O4ib{C}=u zz7--a{y(3S{{5Nq>fv9LpK-&#rdd+Hsa42NY&w-g{&Wuc^T74^CeTNG|6b1#&^_$!Kgzg`RdXDwzKzm`Y@<14J9`+6tGH#>Q>>aoPJ&zuZ0=t$)I0?p4~5Os7&jFDl?>~%f~pR);;#dpvMQV<{gsY1`YNmFH#5e ztE za052Oufui@JemVf1Ah&hq33ULU~|5Tzq1h7ckt%1(tzdvdnYGd0_XpZN2<_P{+)`( zBPf4A2b`9BHlhyU?*j6~15Pu(G&wxH3C~Z2v9DOK!Z^g22(YKx6+n$4-!{CvSFqjuQ(&!}din$)4BXm{nu@W6Q;-v1t z1Uy13rZzzX5%l4~krPfv&`&X)3*V(@WI?|l5Qbu*_tkMm&d^mYq}CcNuc4SawT4V>!vLr0zWM+Un2kIr+_BT+R+8-&Msp?}o! zx!|#L6z#mwKk+f-O=72%DgPXzcB+_k{07N;e6#=tgpN;uX+3~-=wsZ+>5!t$sDQ%d zCqlhHRObb}q6G#?xeuvWg+8bL&cGE;=c+)y|HH5ozZ0L8b(KN?u$j}`8jxdZE#fh? z-oU^x1&kK=Mq{nCQ0i`Gq`B73S$O+_HH`1h!hQJx#?1wk^?XF>X&bJq=Oao_9`2Q? zl~XDDs7Tya_-K}F&WMo}pBS2LHqa!^o~U$^cOrQws$>NI#kZLMg|kI*KL7E4q37c> z)Ks482{CP61(r)Sr?N-u%a1Tl$K5vX+i>|rV)-YeON(B7r||JYZsI4Zc*=<%zjn_4f3g4_&5uA8QG=mR9%WqVQ~ZmwahJbAhVhdv zP72RZP5fjp^RYdbZ(lZ^UyDB3JHR;GbNO4cahLy~llVUBH!denW+~66%oa{xWsSlHbhuZOpIyQv8+KxXVAnsTzyt8OAVKg}as2sWd74 z9OG)vvzdIwKUt{jKGU$K#Oek4dRh^+B+}X?2BoGbYjyF2)VdQ~9yR^%u5!x%yC1hU zw^h6Z{2Mnk#j`?! zQ_<$|6xhsYMBBxA(tb9cJ^Kt_nxQA?KEo|!;o)b;_y~M<7F1o2&G6x@F#!t5PxyA$ zm;f#=Z$}oNrQkJq=#$Ux<%Q1TGFL1l=hPwe+(uqx&z%uFlR{sRGg{&bQs~3@7i#TO zaX8F)7%lO0LS6ns16TYNZ1H@VoSx_L{Up3BFE4by&Pi?%J5M-C+_nJHC|8*CXIYoB zU4%Y-I)C1($tYBvU6XsK4XUz}1F`u(FRwT12c&iC%cxrkrn6Yx?>XQ4l@y_3F|+G3~dK0MQ( z*DG6HCmVfV(8_b(hj@A3L?(06JJm3G3getS7q1cO%k#36=j)VYx$NY%;W%XyZZ#}} zSN^;N&D+BAyiJCASp!zyX2ZO~w+J=u@|-UxVDNc|S7Pk?3nVb?KwB@y-=2H(ExkeTJgd z?h@z4MvV57o+5Ua^b>>jUs55v)!dyWy9>FylomwPTZdt&SZe7zv(z4xZN~;tu~tXC zUQ`rj$CRwtjyS>!Adn_bzm@NNi3f@Dto$-5nSYzpJQ<6BzA>uK3F&=)m6M)?#lIF^ z?I@GagUhcMj^?kBO;R=~naTVX2x$vr=Ni`e4&$6j7k^hos<>c;x3Pk8P7-xjSunxS z+a&cCsQOnGLNF>o{06L+vCfKL*1x}?frE5u2d8#2&PReyf|`&_+@-h$OS8XIs|;CZ zS~f0^S;B3Pm~=L$Q%JheSxqM@Nc<@`I?qQ(bFY))UyzNv{0o6!<{Y~>5H1greLci! z^fBb1Iwq+QD;(Fz2w{1!7;Ktckis>buKoLr`M=_$C7n5drvS#-*NBZz_C;ffGCU!=uo+ z-|WI~--f0$VGI+bqBi_2aE}p$&oeIhNeTXf)@2mAUtlvvd|6+{b$+}J%DU_*94hq? zIL^2(K>R1bJI;gu6yqlUY2Y3ay$l13Wf3@Mm(j@dT%s#RcG19@ziS8J9uewFwN1F; zP}g2Af7>@<$v{^sMh}6W(_8`UsK21qa|ZT3_^+Z7{{)+nf~zQ%gu4#$2zp25@u7FE z6W@TtQ}2af@?)bB;4gnW{SR7K6aQCl2U=I#IdFM$S$y@<9P~zUy=7g!8L19}$8h-S zt&F=4g9m<;lsTbN+yt~rhN17_XvugvppuzRb1eo`G8=r_veKoN70qRw4Rony+&G}Q z{Bf~t_)AiBgZAaU&C<>uZ238yV%D`HKU*YR@{#e_Jdd+4- z09|2VFXN^|2N+i)V~4J-0`5_p*B-cg3lCzmxI`<7){% z1@4bK2@hd>{Tl_ne@Zl8#|Mq#GUDqgd7<(3lTuBYj|pWpg0T!&u(%fVmpvir*Nf}> zLjUziDR(`-=s@bPPqSP(E_DeQ5D@~!Hw=USdj7Y|aeV{75e2^3z#Q~}OL*L};C)>V zOSyr|vhh%qahjQw2NiF{Pcu`)UH&z|aensMtU$QkK{=R#XLt}dE|sIYQLM;$){Q#_ zVYoHOhLk>UDPPuaQNm5Z|&cd+P|WFNI-}WDU#ZTl*pxEhW698w;E+l-#pY?-may!XMknTWx8S4UXVj>xm>$!yayL^ zqWn9QDXp499L(>~sg+*K3J-|v7Z2?Tx}N3j=p&m$Q%>zqaLsfJ@$2+PNx$WcpqCFD zZ_rtOSVIncxm-(!9hPh9urnebx3(AgD84mhh_So3MkHIA%=)cE!KRNki9Wo(Rm~}x zC7-xRA{=)xXvMyDmb|HUds?Rb_Kb{P#SPvo^>=p|cGA+$clSD>dC>P=xiWYEZU%TA zHe;o)biVyKZpsbs3X&c~Do(gH{2&^SsW)PfTwF%Tvp@d`c~^3{HDZsUh_i7AU4rNa z6u!m4Ih=Q-ML6%k@M#j=aUN`1IISx5;olt>8Ru{+e56l=vwUQwAs0a(awCm2SPGYE zC?BboBw6gf&^eZyjaDyKh1bdSjpQTG$alrs+QYh&W~4rD4(y$HcUcVixwDkpIx*fm z>&190?_6q#aaiu$%J!vS?Qi5T-l@t!#-R=0LwB$-dq>eM(^ri_=pzuLs2=oHL*WPn zepYpoHR@4Aa0m-NW(X?WIHxnLwA(z-9?8^ zeP9ZIItTwDgJ1bUrzGv$KI>hj93SnI4vy~Ulsy4QM=#|*ZcB&=eSeIhkv;hSIByTW zPr1@Pw$Vo_zQ2ocnZs2F6@EeffTT61H#5lOy9{Hl^%fixWe>;Xi0POdF&(oYhapu9 zhKFNP!cfc_v(FIZP>eZXc*ywJz6L)hW9&eKU*X0**GucbhtQ23Mf`N7twN&=sN5)z z6+Rxk+O%{P%_K!0dS)|j>UkH-vRWUV;s5DakY`ojAfkaCydV%2GqJkTTWK{dLLMbu z-D2?D=wp=ChZt8*Fn%}A_ECv>*4>lE&H(G~$Cy)vLvb$7p+VL1-6sq|j@R9%3_*oo z0PYdTafE5>^<~ZIV+i94oLUDb$m5C(x#dhBg;tM0Cw`onM}@07W(;)P1lD7OYTQJD zqf(Rr4`kdFLqOrv42LSvr-961+@`*7)j@?XKu;fl(vvlH@ZkJGMM#L{r0=+`IRw>e zp++*q2|XGp?0wJ%KRNOa%PBhJ_w*FCFv+@SC^Hx%zUMYWkR7^5MMCj&sP9pcP=*wq z6o&rCy61QfL#n2f;E-jDv;mASF#NF5$H2x{@BqfoWCrCBJ34+gb5~^x^rvgBe$jDSVzXw3-==5#77i5LAZt8vN|}z55J) z#wW-HVUjiBHbamVPN*~l6+Xq_x6#LlCQM`87}11{Vni`(LJKn(Bbso?5LAX#)hd4F zxjYKDUBoE-grUC*eR52!OT)0QJY&LrW^NR2=0@QSj$MzV`+fVJ=nt`GM^(<1gY0;; z7dxWtDSSTTik}^iK5FnQ{IEQmxSvmd?w8Ae|NcGnWIfjMiSm5NKXJJTaSv+}S@O7k zn>5}@KZYfB(lWyX_H5GAh6f5?Z}78clXe;W3O{b}bL1w;)Zi*vg@g%{7YfhwtjQU= z!ld`t(qU?V^+1j_@`12mrXw5F^;qvL$qJe5}MzhYy4?BOqHP0iuqR5P3G;Z#w!{UB?kf2s4#el%ZyJiVhz*r zXb}n_W=%I|H;-w$IlC23nmmFy-He$HKIDJ888d|^aJo0#IrhzbYk)O;w+gQ|`0LS!mp_W;z{z|4PC;;nqXM?BUTv4F=90J(K|M;mJd-(v#WvP7)<>c0X=aFlO)MV9b`m=wZ$21XUis z&gsXTbMT6Haj2~8O22Yh7^{myq7Iu8hPp?AX;pTp7JY=Tj>^*Gh+6k_4*vCwa}Bt9 zTO2N7hoNW|`efKR#2!*O4gy{AW0F?gK0}a3MS|iugI$~YzEy`5eiS`@gmEH+ z|2X3|^}!#f1~`@?7>ZeSr_t91DI~;jmT{Z<5M=zP)bj}OPbuWO9(L@fLB?&gn!`U0 zqt|{s{*@CB15{8j{L?}-q{zmm<=N`Wsc!oQlt-2;kFX2 zGz2*|b4MD23Xk%GcXMl%h8A$@W35IX(VBaRaWz(jAC|XE=Tg1sav_#GVaO?5KGo=d zcnEv&a1Ed1Jvw+Aehc_{9qtzA58pR@lP7?byWiO@@De9ga~F2>t_)#c`Q^v+vBA1ac}v2Rl-zR`0Kiz{s*o3 z1!%}4WkBH}VIVeN#Z=0zI+Oq}$t^=e5s`9j_)5kVe&_-1dp_*TYkwB%TVnxOT_&1gIvdt@l%Hd<{U zk1Rk>OKrD7M1~&nSO0>LOOPpyJ+cc7UWRrvZll!=oj}iv{}kgkT8)2!s39OSBfhR_ zA_uJnG>|;)*)x}5POk(DsFd5(Z;RA|94TM08eHV4jZJq*rj{L=-c}0>-T|9FvINP& zQ(AHeH&VOcG~+f}&A`v8M~ey7w)+>feqJO$%l~Yf1Zjfv2=PLKMkammp z=Tmaij5Ml$PBiUi?2 zTV1?W%+`sE!k~E!Xi*{KHd-xGi-w}-#eW;)Hd>t@Z+OOI{;@@Bz_O;?04^wVJJ0 z5x2phIaIGAt|F8ma?q;pg@zn5YPtRfV18_>M9yKK_=m_6s;|gFuM%{BeXaO#u)dy; zSoJ5s?-9ZJQ;geaHGlt~8i(QU|5M{I{QZA3A+76Akh-At|K<|j5C05-$B5bE0QH!> z-ikf8mjtmX2RI{-?PJ_Vt2z8Q1OIS^@}aIeb629T;8OSbS@r+Mzhs5&iI&Yyn8d_;~1C8^11vf z$c(%EQSi&J82A_0IEl}3DZIEA*#BZPeVOZI*5E18#q&XH^Qrw!JpRRxF|KUTA%@04 z1<@9lHvUGjC>JkIg8m*h(_VVnYq-u`oN;RVQm~%v=|o1;RsWOaPNWN6i$6)V*{0do zeLMQF_~amY_V?rpAu+&ul1iq{WncF=GwxtqxvcP=LP7bHR3f@u1Iy9!s2f&zn&nO# za!o9E*1($?Kkt;SL+GEp$aLio(;IwpKn($rqVk5`*?Nje4F=v|mZp;L>qPJjNO6N% zqKc0D%6N39vSA3yurpK{sc5JI<}ueBjsd4MoBS8V6e@p;78@;o#bxNj&!>Wni@wk2 z;vxAqb?YhdN~^;1r{Iu}u5k?mPmx0&HS<*MvR6?vPt`do#IyXVIM}9nh$nz~somwI zx8V5w)LziF{1#WBPk!%5qb&(RF8!yDGJiSo`Fy>^fAF8cj;6=OGr+y{TtNIQ@cSZ{ z1wsR?B@vK)K|u^GWzvf0p^L?5GDV$6nO zh4197EWvN>(bpA!>67PUzwG2B@PK*D`epAdjqVixrK(4pEcn{+TJ${X>6deXx7AA< zzglu^&~-g4(GxFYlp$*O6t4ikTulUQW!SLi;&>)ZT(SQ0G+-}FYKGb**XHrk93xz+ zMkpO{Jzm-u(ruYtVAv@ z%Z3QU{${g&0ttwR}3s z`peN}V>$2(Vjw-Nr^#^-g-?$cfqZ%z z$ZZLBEBEP{jLTuP;W!0EW#m~;uW_pS(d2!4zg$$GKITNWh|m1QmrS1YS?4b>W1Qs{pw(P+@rAO? zR;-a(S<%F;yg2Yb+n)3HEFKi;L1(4-bs&+jXYm_sTamvy!4R{aRa0C}F<&uz{H#g} z2j9h;;E~7Fe^yO#smD#mvqyLYHd-wiD-lHB8_uxD17ZKleq6;XD*$>_@yh9np*{yg zqnO|L0U}wpE8pc|Ki6Ik`?;=y;W?Wbo~u#}b9P8FAmm%{Nz3;Y6)-%5z*u>A?Xi8Fp68OR5P5>?o^rZaMfZoS}nQw62_VTiYn$`md)?tG>tu` z#j2fRTKJs3KMREXtGFUpz2n&11BHE89W}H?(I>B3(PU|J8va0sf5M4=-idF+Iqz!f zX7Ne-YFbRR(e`X&Jj^)f!^Mk$d+F(I=t;7kz5>6+UFmx&0x9-VG}utIoD~gq%3h&? zROFBwl`VHgDa(yxoCo6KQQ%(ovzL0`6{H4%Ts;$we#6)$)Pdlo=rJMS*3lIzvP&3O z4k?@l>ZONP3pYc~ycYrmvDKRl9V$p$a_CU2Q90=N>p6)2V^GE+!o?4Q?B$DGjhqKw z30Se!$HAmch@NruN$E*6UczdMD<`TX|8F{=)%7SmT&O>fr56|K;y32oQA`bU zYn?Cu7U)*Fmf|+egWMmOHk$l2`Uu2YinkVD7snU5{)m;{7N_UsYv+N@V=!x1V4*Dp z&Ge>`qque}>*u_xD6ZWhqqugzu=8D-BpyLrtLB9gZw4Q^eS+1h;3*tm-h|uE`+vb3 zFV+<}b~7TlPQKy8zpl4a_8#@Gb;{DzmdYYncZ0kJSr_GEURNuMd4RQU0h?j-y|zp9 z>mJQE@8b2Wal0t)bqAF~oFpGKb`;K#P)$wA`~MHnp!vv}Gx*2BUKY(`)k*EsQC zk+<<=Oq2NGz-UV7dkyes~h zisaea#1|9r{LwrG)lqdIjRFs;C)K|?{XyVcY7e@k<86u;95?4rqD-_HW%l>doj+r za`~?%+}ZeApkSJd^)+;m52TwGRxOS_6+YPD=K|e)o58Q}$>QYx`pxq}KY&f<3p?}& zI}6YdE`22sf54q9u^h)XQ+-6R8RVBpofeX6Iu=0eB~quk?c$GS^Q+;%^jJ2(i$5*! zdz8QHtD6CkftA?;E`AnxTYdQ=70iE;aUOuex5)Y$U~TEm3b~NgiT)OmEYPIjdKZ^( zjPP&4Du(y!PO`Sl%~nuNchTYL78N2^;NlG+dsNw$#vJ$-VJOeqvVYl}K;h6WX)LQ0 zVx#=GoCc<)#C4b=qot&0)3P@Lg`-qKy-X8RC+|TY?!VlNaU(7-=ZMS8d^Pzpeu18L*d8|Yu%p`x8CNMMoZf=9o#veD z5k8)&L!a>8j7xzwJVy$)=Sac!!O){esG0TO?DG|7g-8+P(IfT>7&OP+NWD^-Eq=>z2oVX)j9O6 zWn4r&=3DP7I%EiNq+WRkxJT+$9>sr(`GtYDRKIf8&_fSYQ*FF*-VhK^S_iEi zG%DTjT=c=eBfBWu-=uJgfX@Fg^9K$5XN;qWV?scAsssuRfq5)Y%(&uLid1ncT=5SE zzn;ow*3(vV-zLPZdgB)X+whUBNE&cMy+fYz#&(!BqYRlfqj0k}cs+4{LQvUJcq8mn zHjEnEv0M0srIn^DeqKy1Ks)vdf?M@2ew1;=f6ys=3oEobncC3`x`(0P6Q)O!Ps)Bz zr9ilHnDL#Ia-E+Cz7r|W;+J^L+Bwh=;90j*rBE4Q{0~YI52R-b@~F)}P>E;`xwz8L zdR%-7@neNn5uCtR6@OTkt;oe!GHx1Poz3qWFd{zT1Mrcf$2ES~U#|$e`hnnau-r8Z zcpq$B1K7h~(AuSHj2)W5HM46m$XX;^yaBkOA6bN=q!WJx7dfw%ewBgfui`E2hl#!i z^ikLhM_xVYl+DE_i>Ya#>AB~WrDia0q|*ICJ|m*3+1dOmqA7e~NSp?yHu8nsZhov{ zcYrCoBXr*3-(4#DF>7}es*Ewykap8i&+5tJp)XS7S3$j^9+v>_njdgm=9S58$JuKRNG1zyD8XoY2XR_+a(VkntMxpH;wQ z&V60u#2B>xyaNpdm;>qJJDujg!B7(}k#Lt~fYqdmLn_!XxmhY`nv0f3CKa^d_>T4C zxbf8Fyn*|o{-$QWvGbRJ6Tzp*G3zfqA>@&rzmy;g9#3}t#RfkaHA3wtR%XP->hJ??0`#=%I6_MsueY(S-FA4R|;zx&={ej{zK zwHJ9Wel5syQlBqE#RxmE6*|rDi%%fwzMuRVHhq3ZnT^CWvk`^gAnp^Ezc!TVtlmF} zF7xDb@qR*n;_EX(*Yd6k@pUy_IlnHxESrD&N%YAM1w<=c7sqc) z&^qw?b}_&n*6Vb_;m1~h4S%8S^dAZii);GV)AE}BKnUnGY|KVX#CD(rvwH+~O`Ph> zL+t^YAbO%x=#w5*034Ty!s|d*FRea6gVlv=(I?^MJeUKknL%k$3`v>h1A7GHaO*$@ zj2`px4OQoywg{Prg*OHpiWNS@Dff3=-ZQ9eG!`|A^6@Ce*r z@f~b1OtSt;%dv-smO|iK2&VJIY3apy8CsujgNu(uPs{aH6+{kNEqFu!rTK*uTZ}@w ziZjwO-;j&2++&POJHD$FzS6*zp6yQZSfJbWyFu36p23-GIl#D$7H+$Evk+@{K|Z(f zCVpZZ#~1&bW#TBAXT3Q>&c8QDi!-Yp)|-@SkAS{8Pn<0J-%PTm?P5N@xkt=L|C?zi zz8CA!!5bj%F)t7Dr>O^NJ<-Ehg+9V~a4zF2914%ib?mK>@Xv3(<$UjG$HL*(TU2r$ zfp}{m<2G6?5N}bwJjV4_ja(q#nhm<{SR8#g_Lk|G!WYT~Qv42~hu%XGhPeSZX@J99DT1pa6Q21 zq@nlJ+95NwVTQtQ2HnH4_iiJ+AO1-J*R%IV1M@Kaepg;S-=|vgVi?b>=KJ$FHuk8DOPpDrsKK;&XsBO(nurSQOqM7o{{F0LAsFKb>)! zyX2$2Alldm#fCl(^9Q{QeF`55ysZ-5YmpBoFfQ%4;j~_9{;G=pK#l_+OS8i+VTF_a z7$>P4MHAbaEj~MgKH~9#TB>d8`!=}v9`yA1RS+5c2heD4%s$6>3*+pCiys7z^EIc# zt9S_RgLlP3T>Jro;B^9Yv{p=-N!HN?h8a3Q!u-)k8CPZ$zAT$xW%KCM+59dp&*;jJ z%A$4;^|O_}v)OVA{|A0mOB+@HnRYqrpjBN$(^5hf>MY zMCIup#xzm*F|06;<0|WzDj+qzc)lO&ojqhV9gkg`jjMTmtZ(*^T)aPUk3u{)Q1EN> zT^Synt;jVzlyT)~A^OPKvD?s)0hu$mqK{Pq(`K4lH;&QFa7(Pjw?Qos$3__fyg(eo zuXQ0Q?T$I0d@H{&W*w^qpU2v8OigWeP!+?m`Pq71+$h2aBjBR}Ey?D0@uk4!Esx4$ zE18FF(U0T`+0~450lWBi;C^fc*zl*;t7H4cdNs*9b_l2&72gI|@EyiYg-5da-9a7A z=6CUoT;KlLUaoKd#J5yXetrL`W{?URuV4RE17y3iTAk+8_!w4|??2aO+i~%&z}w2r zJ<$Gh7voZ28@@-}ZoAC-CoRN!gi4(FE6s5#H?5pp90L(orN!wtc(4a|Jt{w{f}mcgoYjw}=fJ59JRJLI zrx|s9P~js@X5e+M~M$3KT*fmT_={yHQ@wqdDA)1iFd^a z%TJsDpB5T5F;1LfoO7n|fAy0`&3{#hcH+OrWXr2!_}92>c^97oylu^Jk0Ae=#<;ZC zhS#z^oU0)t<^S57Lw;Wl`DT{S@N_uYNv;$pBM|U-;PGTX)DYE$Q9~z30n-9CCxAX8 zd{PC#ral&Ph0j1w=kG*h@Xr+ZE$(a(uL>gq9n!SOT-Cq=G(8FD$hdeyToA@iZURj= zq#W36;L3p=jB{pPhbe-jN8yUU1z4M3?QfzQCx71&xO=wRMmQ-*q@6bY_2Bo2*vB$r?ugu6evHEm4xr^9 zQz$gSx)AyZ#m9#jx2f;j;Ns`_3gr|Sy*>jtMboqyn^A11s`yml)NBwBU@OPw{spa5 zR4jzcp)m#cZtUtF@`81WrVZgXHu6y6_{tlOy!U@n3{;a-Mezxxig0Pijfna4+E+D# z2a))MW`ka=3U|7k4|FU3gfi6un{t~}lNgRs6yQ&0qN}-~0x5o#n{XSO7T`}BcvgRs z5Ia4rPiQu@Rjco+1PQ>xW~a)+HQp!kzHgrOi8^)o1m!Be2AB!3j!f8FN2XZn$dt0x z%pkQ>A$BHN8Jr(@B{~y_N{>Wm9s{lqnDdfZ%(#tK%U4F;>CLk;jmoqdPzK*(6emX+ zoc>`z1FVd3a-)*|sUIr!XtL2yLqfxF>(df2cpSz)?azX;8r>@Tl=@x@ReU~`@#$fG z8qJ}3Iy?WVJjDa&(j1&J(|OjXTZBl=`m`wrC(TNlBhp*!&|lE{lol?+RS^;lT>P}T zM=nm&vg0wj(<6b4uQaoPs}cZ6(I{Cbr=vWm)3s_xjxNtSy;L9rtkWwY;$?I-<2G8Y z08Z}_6E=4GDA2Y#Z+}w*vBCCn#%=23!4!p`r5-lv>xQ~gA_uL1hZ(o2kA*?u*P^HK zs|DfTazXeX6+L%F`1cJEpu*y%%vz3pGB8NoxBWN1_DA$| zE7)7mw8JL-Z1?F&#wnSE%cQyZnW4aReKz_qd&W$f!fAoh`GvmVBLkHB zGs6%Vfj${nZ15|5EAY0&xC_u3d_jd4pfgSU{QntzvLwC{K)>!TChlkW5Kg=_;4`_v z#H`P3D8rJXf{H!-1+C92(deV-&$u}Vg-7f>tOkNN9aB2BxRO$LyL+DcssL~0yv1!MIv+4u+v*e2( zn=yv7LxJfEdC+H7$rxie>s>O|Svr{MV-|8j>+Ed8e~5pwhTT#+J3oiOGR94QwKgb+ zlmQiN#qZn~$nWN_D|1qT{K9foxo3~$Fn888=fv~#yWPavKgW=~4q=~Dn3}P1II)Mn zp!NAMakz(RMFCfI0o zd=z?ZYlFKupBuxtjTSDbMf+S0dLGB&b2EtxTRAq;kJP|^&^kvc&_~RreJ&2%V=A0` zl=+n+o`&ZhGxR8YiNVh)JGYGN>xLC!y`f0qY2aQC9XAZv=+nSXFfRI9q)#zkPKylHGho7$gtSUr*%xySd<6QWC&yy)g-j{Jp$sU2&4!{XR7+svG!9fRp$#>Kq+E}&Ib)eTodQR z20uG=-YiOh5@dL^SxaG>>v_6J);FXODo#qo3G;>QO5Tfx^H|DCRO7OI^UV#ja&S3cnS-*?4_ zojt7oo`KR8*o@3xluuUrFNU1x)#Tm9(X8s?EVa|XuXDNBDDT2v+#+}fSQk&Tr!uX+ z-ZuIe@kLsKwMg`~(FgvePd=9OWhYkfr5OSa*_UPr6fW;A`oA3P#F4k+FNZ>}Zioto z3=LyLqZ~U-eB%thTIP!~-*n~BTxL`w;tBKR0z-kq`K$e3F6Hojx!S3{iXJiha=jsO zm`x_xr9R_Grh6b=acXEH-M zTFs*0oRLZp&p#c;hx}px0YflK^1-mbh4C`#V+c`dfQ!#|3jO{IPU`D;31m1g$58UH zCU|@|Ae=WDdj5bdd!mK&;_|jYI4_}g_Bfeicse(nx1T;wD)i^I3Y*2@ybF-`2w!{W zxyx~h*goV$uE5=v_7Sj6`>Lt-I3e*^-NWrifmdJF>d?oS+taG3r&Hlk;9hPl1g;+q z!gAV$+b20)m-O_Oyu=ogZg7;~CFAAV7`|i{-9o;+NBENZ92(X*X?(?Cc=!@JgzAHd zqL0B`vYBxsu^ozl)8)L8mkzkz?up=cm`tlOEO&^5X~tI>JE9iBkQeSa!buLwFRbi1 z6HK}X9JY>TO)7jl`2B5)!{iY>4s>$t%aP6iofm%fn?2z`61Ybi0(-pi{2UdVUy_5r zLg4to#0X7(!fEK9U+CQ2BR_=Kv3;*cezyWOV+%%e#tLxH7a7Y77wlBXLC#@8tGB^| zjHvf^1a1 zV%g~^2y~t#6_F7Bg5gexnZU~=BL4$Fg*`HE@}FkhL6xQ9|8);{Pn8B z&fshJZEzY9?L5K>^`tuPJlbjafDQzmCp!tO1noLIS6+dM(K!yGX&!=0q429`@8QlX zgq}&^&d61k=Un%lRejr_ljn>F`=Y0hl#3zQpK%+lRwO}uUj_%P@}PNspyY;vTQ75k zSBVA1A5_P};7MLQf;imLD%_=1wB=paLxXm1e06{v2!^|CW}K7j;`kWpdvv_-veys{ zu^?5DcBXi>!kg)d|3ZHVuWrHW9t(%4EU1JyTj4=cL8u&4&%wVj2Y*uzekybE z%XnPRSBoJA!y&43Jrt$rBNP@nspCbAcgV&gwTx3T^$4(jYoLbHH{7mP25xq$uEWW* zMcLE@U4>Qhz5HPdXV3U4ue`9;sCEttQhC@q%Cc%u98K#)w$7^+?tJ@ufx-dd@NI@% z0DTNPJkpR;c$KgW!D)t|jXnv^U|ftEgH$-4UZRVta5yP6^azJ{FsE|40)5i3+X;OQ zl@i9!qoQKU!?c3x@mH=KVO&{KI9{FoH!9J~dS?r&cwW{wThPV(@z^e-v1!wEehPhf zb{UP0aA|Rai_a6Y3lVl0Gs;6x?bE(x-3q8GsD)vY^`x zj{>=EUbo?+#ZkzA`FL@eG4b*m@59aINytybMh4x#V7M@djz=U5Rm6-kEtD5|dEr95 z=UlA8-Ds$ru^F1XH3IXf$8ITjNTW0PTY!1wuA7>=(i3;&MIrE4IJ3G3tO4PoLEe+5 zXf&9bziOt|AfetK$UgQFwRXGR(yR;qGKtOG_*y<+@W{>h+{>b(-B>o@NgZ zcW?HNNcWS_0Gb*8V$$RhiQ*C&sbWOflTM4jN2H1?881WY{sqIub@Jv*xEMEI`r!Pj z*tzn${BFg?>%pW)Do#S+-{hpO$4XwDq{zg=JxHI2pFLN>kmVxCZ<3FBra} z8haiiz5?%l#`VeY@D*FUOW+DzHh7i56=%E^_G&MWAiZdf@-Wz|nh#yQqTU93&B`G- zPu5nih8%P?+l*P*Yc=>iW??V<7B=pS#==)dycJ$aXZ;j=BZuOhvOo5~>wvxQf!70j zzynVJ`{pnY0!}c!E;p`h0&hPLe%v?2os+!ql_$h3@n3mLE+|)?2D3g*lIUZaTzQsp zSyjHP6@HGUOauUb!w!?6wCm0{XW`rP82~00nN;VWnMlx-;ulOGBd#b1g(V%B?x z!LRVS20w0#mFE{ui;3hzPKC|}AB9NaG;ehKO5a+>m3_s(+2B|BNe=bZ;@Npr)zws0 z9wEK@h8(y#0`}zU`G!S>ZvpNR>XJg@r&U?G&N(Y7HWVqm7vqXQf<8iB(wlLc`fb%& zaxHp#6|zGmeHpjW{)hw=p}!%(F)Ja1dh8WWMW;{bH2UNa6&>M%57$6x>=Qm++|cxw z#GM8l7u%IMPhOAP4;q(=w^6QTV&8CL`4NuW2vZ%4=>0zdqhUQqMJ&tVhPp zR}x^HmIvK#hVgMu`WyM(V$;y|Qm67SN4FuS%uxPyca=JGkx=}L4gPa%ex=02DtxZL zO?(}EO_~Ruk%72Y2Ec!9i2Egye(fM`M{vzwTO)wtYv;j)N6Gi;Ne6F zFWjeU*~fSrdALs$0)A`-*zni2i2et|eWo)#fv!&Hit4k5=_-{f1&aQTQ#%m1r28C! zyhp729A(^ybsstt)a`Lh`Cymb zlUG^Gw%3L0)(e@{T)o1HyyUVreKF zw1Ab_XpwlO?54wxT~C7FjCzM_2yl;QoWtMRDDn`yc>?HdqxF@vq7UzHo@n3+#-}hY zE3J*6949>rPhcNROOY;!*QN&0#|UpR9b*S>neNR$Y`^%m z)L8gdC~S8Jm<)rrjsb1~mm$Lr{RP9fj$@od?BaDf^q^op_3R+LE5uDjO=6@IZ+#cE zI5yL<2$YM3N?^GmP~$|to!{+Fwo^IGAhTE{ z+41-=yHeQE%qTthT@obgt8Mr8DN2`67N7(4KobXqmO`8B@A5Y*{S2OuMFP_16dhifje&i?or}*jyCw& z@Ti3bz8rlxG|DVF;=cogyQmDNV>6b&yE-r~*8+6t5Bvc%9;I_vg;-|?gzt)iA&$*h zhR9*D=v+%XSlJTvKNubzaFUgHY%qi#tx1YZ4ig#YYDA8pr;*!JpU9<>OkV2bD3b?C zvTcx)OsMa|XOl-$pOn{2azi%x`&CR{ zF3E{(@|Xyd8zniJO&&{BQodc1Q|M`7sU|9sngK zKIf$Gz__WW*}l6$lD{92&L-bO#z?wC zlB*1I1Cy&IIhsu#A7OHhB-a|`1e5C|Ii5|vH_GICNhVubSm=aMxVBu96X@yWIQryy zqa-J@$@dYJ$lE13g`OsTUmSfRH%W4HHaQw%@?l9%8{`C&TO~P@O}@X3$>*HVonOuO z{Ygn46Od%GrMWgS%4A%bkaWZ#$C+Fz$z)5HPB3|pB-`2K$yH3QkYws=(ht-!xmuE= z+2pAaCf7(Zacj~wid-kjaZqW|;)M%)_zQ-|)C+RESSX&YofmrZRhQTTcZX<9`n!%_9KP0d&%3!So zyL}(J=VhGI??dt-H^sy8u0kWFvkOV&`@Nor3B-m#xz$fA?UM9h@ z0R6wHa%#rH;Nl1qt0Zw7Ni0?p_yILC_#uH$Dlcj!*sU7iQwoer@OFUyB@Iq>HFWQzdmz6nncf+7lCME9n zIf-!;D3bVffhFQ>jY=XZiEop{M&)8kf*r>L z{GIZmS%NnbxVegTrzJR*z?b6;W+dp0&kyGLwxyiL@%dl7)VG7l<8a$^JcSBmpv_Wf zTtuRM?j>}mLdzsNR-mu4E8}d5E|O@9HB?D-8_+!8s~M;1UNW1CGPzcgyGIn2eRHFCb+Y$Fsy#dYh9Y{Hc?<2EsC~`!S`$Wm?8)+6QljvB1HpdyY zCAvtUe~mC&CDCmX%`h63=!Zb_d@WJuT$Iedsf6N^eEa=m_RS;??r=-UFNx6jZKYJ5tf z9UmaGryHE22WVVhM46nH?ssDiKZA0N%V7po@WjBMkLy2 zN`BDqyWre7CI9OM;(H$O>0VnB7fr$Pke6XSRTA7r;3Z`YMkV+mf%yuom0-82`CZy| za{5e#>Q2gTgQU#?t)NqqwIn3Cj=*4u!K4J=Ca_C{!IT6$)&Pvy3^q&fMu7fE(y6Gy zO4&QX#Ec|5BylzCp5Sw8e?XBEU|e!e2ubjB0_ifA(la3Rl5~#$RC3qu&12fE-mf%!?{y|Zv?uRfqn04Rha}v`jP$coK zsFb)bB*D)K{5I>pFCxJ{(*fR+V9qiLjwSGR1=lY9@qOA}+z(35;eKY>?m_ z0`G5NFd@Np0R5BV&h}d9o|Ir>N)kK%7!s3}?q&(zD8MvxrX@I)Ky{50%}CH8aB5U? z-tTkLKc?~m=%1Q&4*wVir=^$}k;FbTA@Rc`gJlvND?r6*OK_0@)67{V!EFRiZ)Pwm z!4CoYXOubTX2Rfu879Uh@%EoU;>T4CHb`&|fj=P(ReFCyg6jyJUB+Nif^P%#|1{*Z z{sg*znr33NB;Gg+5)a22OiOSof%BA_j07D5V@b(5(dUF7qCgQCk1!aL;O7AS@styI z2nPR`XmD|2nIw*V2ojH`7_=q0h`{;;gH;mTM&M)Y#l)xtKP2$+5OdZ_u-j}Hd>ofU zvte*?EfX6gaSn(DtCX6A1lJL`&SuV}1m6~5lEIV&JI=vDqtWR$2M3MD1k=)zHWjpj z7g7vnBeV76#(Kw?aiGD88W=10t?ej31-4$ZAOrm3f`rG}VGxg#8{+G7f9c5~jq;3;3 zyW@;TCHkR2)p`8nT8Va>NBZ|fm^Uub+a+4XXoE!O0L^Q+r`D;TM}yrHXL3@K-xfl9 z2}B4crzG0(XJnwsX0%zNH%c_YXj-CEf%@CM?#%fa4Xe3KQXlX+iTM;ZA@e57JP?xT z=K?*b(1<|0mqN51wrjCr?@*eWVEBPDDKvIIIraAlqqamB0nKaoUcy;EpT>72&E%*g ze<+0Bw;8RKXtx-t`ato?2qn@)T%Ga1nu*uq#ulB)AQr|B?o$=@Beo9Tc%v61y#cM28IP zj!W=%0z1YTY>?m_0V;zD39chBU^8b@f^P%#2NF)}0vOC!#AZpn@#l~zh_Xalf>Q}p zXU$VG5_ANZl$=w2PWtCmdI0^wv~&39&}~&QF(Qe57D7$9fx$8fjul{rL0f{02<%E2 z@;kLkg4+nZTyaJv_#r@lHyk_{!eBRLFfNI=|1TtplthCB=MdP-X59$^c5g(tZ5sG{ zC7GO*R8xT;p>>L-9qL znm{(acZlgBrWYCXDyB!6UTV-&OfO^lpltfpWlXo3UXe||#%6jI)2j`7is@0N*JRU6 zqfD=5dYwT}F+I-o`fU1jYWxjMUvAJ7ET3R{V>Z1nk&&I6B-6JWbQQl8)0?vC|3l&= z-^}#G2EBplX{NVk)B7oUhUw=Fdb5=OfltzZ5Xh!~EyVN?(~Asxg6R>amuA!ZN0?s5 z^g-G5uPgmF(<=yFqVedWz{y+4LLZOmAlTVS}DvdYb92+4MmXre~ObE}K3$B}SHq$Gz>9^SEqyDE=F}>QLCzu{( zdQCQcSQ*o6nOIdvT^GnZ7-nUZuvLVtP|H z{Z106@i#O5utAS7JuT?5SQ`C2Z1N1u*Nx%<`PexFk4rorGVlh*OAS29xNYFgj8_XB z%at;mVM1-TfcWMb9E#(!^+)py!|{Ycx1CTuo|i4EVtF#44X7x}c&mYv9q4_88l68* z0PrFMZ(zL4z!L(`3qMlf)GmS}k3bKfx&vv(8x1_ec*?*jQ>5px z!0`YIN3?r@2_&c)=uRVpzyhM{c&Wq}Qmf&;6kcZFHuDeCaXfcI-)tfS3vD#IqB_Pa z44fiB{8a|tDDfv-vvKvIT7z#{0&gp62xOBVi%YSFP&VG5)WA#wjbC%?8?}t%w_fuK z3S$kW+4Ry3)625)yCaNejo;@}_cR;qZ2k$vNA@eSahJbJ;B5(X9jne3xEo!eD2hfK zNaKUhjYW!p4jMwQn>^~l1LR=@{2Xc!TCxx1#uWe_%AshdCfbr$ocweO_ zk&TN;UqT^jbP^4Cf`IgDcKW5zCvwV3ZN|xGLvuF$I*K6C4?7J{QDvmF=`W|yCwgl( zURuNWIRno~{3#!~Q&{{|D4VYQd8$bGGx4d?Z2C()&Zo+<@x^tlcThI||Lgh^c&Dms z{mVrm_oxt(3gK$?$ZIuRK;l&~rGilrQ?zZg7NfQrR5b0g8WlCRedXA`YWiwljT3h2!#NkH3^Ep*golKvcmm9Ql&u zjo|HJOFV&8^Cu9IcoL~@FD~&6QeFNiiD!}O@@W?r=Um=1W??`^{?dXWl$Xk7q`J{Z zC0;?Q8!bt^hE$X92}rz-RF@xgak1|rIMFjp3bhTPriWifiEi}2B~He5qeBw6k?Qgf zNIZ&ElaEGR{IJkv3H+fcSlhTn=&~eIT_G;FM&y&Y&y5WhRX(qHZX(k*5M0u7baGMoEtF780$1 z9c<(YCq3Pvmc)mU`tm4$hqOmrPKmBSf-rP>5Q(n<`J%)lNHuwNS$TQXkeB`N@|Yn{ za`?t<=<RXf3L@1U=<5>p6__uB7fU{B@U}>~yexN7!rMuO0OcTENME8HsMcB=IUzEqHYa&XHK!-5!W=_hPOYL~$YY#bjaC^)&XE&kgD*+Eic~9q+~E=@ z=k@YQj_lNt=<>==!;mLAY8BB!sw%08gncdTudnP0^p#o$xxZ9uBh`)Jm%*Xb z|J|C$UqOk^4@o?TR4eR1lA;B@-aQG2lUGDJKjCr_#O3hxJqag1!TH@<$P=DKqLsI2 zLgE?GdC0=hN@dVwXWS2N_(qPQ5N zd!4F4({*U4&=qaNKvNnRas|SnD+7kWkVsvJ+dxRIfh%Hq%=PxCjO{p^EstgbP zBOo#uyxsqZ$U^=Rqb6&{cz6Y098zp(JasvXsL)EjiTWVlh0Ja3gB^>SaA6Lszvq z2^+Z^$%ZWJ>Ml`(uzTL8`xo?zxH{;$a&=@YGYvA+Phtr9)%Y+9%#4Y1vAt3vwj8c3 zBv-CZauTj&mXnQ`w2^Ub2(cWo*vpY1o?)OC+OS+}p{t41yzS3O;i6ZW5~ug7O1kXX z+I@v?i%8v8Q3~Unh-y^l^j?^OSHPb?ptVC+8<9tisvxcYnzYgJ{2Agl`hy;QO_%4- z*p-?;*AS`u(~-iq$gG4vQBKG3+{Q}j&zNhB@J|ufLdDwKmL~8yNHUQ&OjHMMk{0@} z$#PEh-)nLl-#aBuI<84^>P=ezy#_u}o5AdsQFTq(u;54w_`)PPHOOgn;*RnvbdAvn zh_k&4ao)QsZM0k)Jh89ia|jx>_|Ka8YA;y|39U7PWgZh+E}YHGSR$CdiX2u9kq zd5-%YIUL_7gFML>UE}Ugb7b5k+*RxNDTIo!s68RXGy*A-n|aqF!;qs29s^aQ%E!wj}Brn;7G?nkAMPu}6o^+}1O8yc)?%jNnfc zf4{9~oL_|{X>K+im8E9gQpe;t4eK3P|FvJbWAakHVBjQ&=2}wZxL^4a$KzQkkK1$< z$%}698Qt#}I%o*zrErbo6Y)6V?HD_8#Wy&Qe%JzU#Vb<3?G-le4y;~&VMAOA(^cXQ zG-I5cK#i6L4BnA=(8NU!dcD4$&3QOe2HzcTi@`g3_Uu*j+R`MKo0b^36TSQK)jffO zmS#8?k0Vb$QS|iDPI#QHBIACXeN6)y4Lxz3_ zd6aiOC7K`8utm5Fo$ZO$JtM{XyLy5rs!njd%_UW!uP4tn3##VV#|%7$Je5d}>GF74 z{BCp#6@lxMobSW0MiZ}Ue0_%V@HhwF?G0kt-95pDz6TDMR5z}#FL2y1xyW%9`|C>_ z_dTg_Tn=Qh?>)Gh{(%ZGwu5&gpr_tL1ImF0#h}48<8e{E2iqY()-BHap0^D=i#*w* z!dOftZnQeBIw;4QUi0{6*xTNV&Ji)x9ZB0JE>bl#g{sD~80S$92mFz$8p{%#SJhaS ziqB;M=nu`w)Eo*v}YjGa)QtUo- z>ru2{T-M<1Lh;hdP#yb*h=^SdTO01v7VaCOTzLP0v=w)4 zjY)7C{@C}U?fWPmsLu^4&cmhD{XOG);*!p~R)*yUP;mbZc~e+QIUL_VEAgVME#AH# zJDQmkfg8$P62%1{KwIx$6wwE;RQPVyx01_2&f0%aT5fr@Yjd$Z+oA!n-aZO6)ozIM zQw9fct6e;PkQL~zxEEJq+CQ&vxfp`sfVXBSzC!zGv3>*fe`+Vv8RR;Xi=qV` ze-l(O0ym=~^_uRUywc+8GYTT{Ai30(ViY*dbGVcPZ_SYWjR8@65Hk&hL=#ib_S_gT z@TO=$-S_UsDCcJekVma}(R){*b zTx#=rW1b7oXiH&-~n9|hVba~n2ktg*E$7d!*5qjP>Wy2$wJMKG zQIUHTD@=@wsTF1gR#O~ghE^mve?UnDAJfM1iWKJ)Hu9+Mii~GI%jqAsC7tt56ISGf zjmKNWvd1v9sqNVca#5=iu1*>#^GIKrLZ|bNG+O4k>JTd`98YABCm+#S5rQ!_PN+noP|iD@$Alm()4v_)WUfXad+QyEY5brh8l$T3P32qMd;! z(L44m;Rs}9Q?wpOYqhz^fhCcF%$ArA8GH?SH1drR${!v>pmlU zlM!yU>fVHnJq}{}Z%V+b*0idx-IV0`K>_5c__SNRxacXIj!&yfFw2G2jCWJc8~Zmo zoTqcUrw|W15(?c^0Z_4-A7wRkgKgwd?y8hK&#$65XyswQ+d+ALmt2+QJp8erMf?s6e#7Wqwx;7kXqe?dVRvEFLnv`@6spcZCjDs67CzCi;q`~Qft0J+nXV30~5si)T zbkDYw8xlpj8d$bbi_XmfL%HP%-y9K%CU!z2pTj&s2f*DoVI<;t3ug^sM`T{;8MjvvFsfF~o3z9o1IMp6!UumORY_m-0i&P>-Z~^E z^($1ZIn^o`^IaX}_#p|YR^zxj6{yy|s?B{->t$7=xelT3LUn4pAzcsI-dQDy4ROPV z;K=kvt$A(<7`$wrTOuO$GWz_XFJTT>-ro}C!YbCc#JsU^?n~5|S+C?<5?nZex9nfS zHMS$^lsoTt--3Gw*l~yvFGE*_jo2SZK9F9_(8IaXtFY_y3C_>P2Q$F? z=T58fLzdW;cCSu*>+ou7KFtq|=Q8B|DQ-Co0?hI*j!1C-!(?7sTp^T(Q1blsMJxRH3@GB z!?sve>AP>M1s=Qyvrco@-;Px=r*$hZ$Nd{kW}@qCwkWyjiP$z8vHIOrXw-! z4cde`QmNzhj#B`7do+d)CTlS~-{={4V2+Ea4!$`ldIv7_TjJ zr6hL0Z=u37X=}W;%E_4(kpSrjb8XGtFm zC!zY*QnTuV%;9lP(;V*F zR7K*xI`y0l%x0P^&522y7~`-h_IO*n3%M@Og=b}?u)}dgAoVsP^dpid2aB9X*KojF zb5sQ?Zeixd$Q-3U$kq45wI0;{33gqb^K&Z5Q?X624u`g}8S{;`-N=U4b+{4@;Wqiy z^pw{JM5n#=W{pl8Al83qP>R{yj2e;aqa6QHe&8L=<@Iq+9~M9!F0W6zrHWJELD&zA zNHEQX_fsxrIF2e5QHXU|QtCOLvCm=5--WNoS^H>ftl0fsOcnHWO5gf2H=`!G^%O>} zi%zYG)Vnl@=zxCxASbCwL0X69fm1~gdxTHC{jOd%K8St|R?hYK$uGJj8T%fM*_5Yo zD>(=U4y#0aJUv8~&{%{9* z(!&q!Q1LC~wD26B5Dwt+?a% zKSVGOPe?3|RPzMmCHEnUI=m$Lq`^C)41T)Lr#Y{d|G^B$e{3U9KIGixf5b;v4X0Kl z=FnXzF%4L++RF?U!D)V>17$u!JN`H)b=(y@G+5%sn!j<9`24v*FvWb0yzr zijyY)W946qd=3q^4H~m%N9!|#LtF6<_#@O5b6ddR2a!ieZVPf;xpP~D<3Da8Px9Vj z{cSN$A668>e~~*WDVE^;j~$Wt*Oudm+el2S>`!oR0Co2@>0@upa`G^$Iu)JcxL;PD z<3Cnab2yGxY@iV9CmG;muSAjUy{(L#=F3!7T!lJD-)&V+t9HDNO3~D)k9X)dPPz9i@d@zOPnFwld-mO4=3!x&A41uPmteH;7SK)kSF1ycM7w9Gv;7lxC~A!8CMW3l;Axhdq376CjmA^)ytBylP}dGshVEd7?kpQ5euC@^ZKrZ)mGejBktb(s zZXCr$U(hWMM}iHcT923%ka$yepD*b7E~-9RXdA+|#5)}Kt8cXE5j9W#E-FNOWM}6E z5)UHPoH^2SW_ai>+ntDK{~LW--LSnY#)UD;a{opbwWX~Dr_r0s|HfcCQt@fmq_vCn*~gS%9EOR(s&oXw~13fu^FU)Bz{+$n^EDu%V>rpi;#mKcjMIiD-56jS3~Kkuh7ZW zqx^SAIIp_G-8RP&Xa{=JecosY<<8x4uJ&_?z>sw_|Ie$+>Jv=MD0fvPS1)WPsLX`J|!UW8pl&jiPuGI z5n6KD*XYAPq0o>KBDD^b!c#b?WA7wK@@>w?ssrEP>TOCw#E|-z-}g}2nwg)KJoS6r zVH3KCT-NAWQBiZv-~ts)G5X;BWeT66E&D$QGHrMuD?{Iud0(r>SDA7WSkw45DYaJy6UqfH*w#F@taw*k!YB7$hzEewZ zTm`t6zbjpG;`sctl>U;75Wqt1raQx>b5*#%=bg#EsjU8?U`&A|Hjd5XB$$JwVME0ZtRU6*x7`UpF(S~!qHVoZc58=Sn&{2Ct)yD!ekqiy8j<9*m0(j0tW23f7Jqmz=)iP#7WZ-;DajTWPp z;P~!7hfAuB?tKN09~~FfZK-X^T`Gx!r}yj z<^NPR`ug*1dIwj7~r^y^n(!t7vGMy z##zU;0FzqG4fKOlBh9M1yZm5+hj_HwI<;K9${LtKJ8xr)&C?Qc}MvGFPJWJZQ9#d zaXs`shwT3%C-s|dYpfq*jp^w~2(No$E7Sepkel|_jbJBaho}d=1Aw~i%JtP_yeRb$ zN8JcFT*!sUg{D_tJw+~r>S?Zy2sT0((>E9K*5Qb-C7;}whQBP|g@SYePt(vD!~luW zE%h<=Dz`R8+!IDm_+?6#S@-6KI{Bc5^_O+Yw_SdGeaPV39{-S7cyZ6T-iIQbKAu8_ zR(%LBYGH#W#_kAbkB>?)Ij|$@bLfuPl)W;_3QT;+sPXY}DVRa3IWs z=e$~G9%^uW2JV|e&ze$_dRYEwnb|NF%Z%DkJk;SzlWS6V$Zg5Khbe+u-PKXr!$FQu z!G-@g7^kOsLJw1fH6`p)QXu`S_lM)0Ki)weHGeqit?Lg{BsBdKl9JE4^Toq?PRFPP zNZsN132BjtXj|5Yi=3y958gT<3!L;TZpVMP%EfRyu|Z}|Ag@TQ#`#J1!1yhD+lL#R zJ)t6E<1qnEt%%Hc-O3P`qb(?SKSqxjfj^-Id6fQ0LCe0?cOWL zTj-Gl7%haf#`U7EnTXWLcxEo@g&8%uJ(BZgm`5D0tlmp{q%g3PHEx(UxVs;zc;~&d zcT#h~x%3we_x?xf+=5z!9x-ioiPsPBs`r*DbcE^ zrr1Y~$YBbPLC;dxSdT`$M`}*l85?U~Dawr@UPUN%XYlKNJ6n79W{5}lA5C#NT2~-9 zT@AuVGn`iye>BVSc?smnUS3ppMspthT~ypJq`-wyi1S_4Tx~!fEph(f4Dw{Gj6{pb zG<;Y9dj8$uN2{DipKB4X7OzKZoJSCXyC8D&^1#V{({uLFT`*<3Z*V-?_9pyCy|qa! z+ruYj21aDD)sWNTVouqeqvm7puU@W+2XMx=hgk_$J|MNug5B! zj#6pl^&rPp|9DJ%6tTv2Kh|&y7q{AouzTy~u@+azL`BO+7}S`3jKZM>8DR?U243B* zc^tIP_u(iVydQ?ggPcFHK?-=Rd4*Jsm04 z5w-6@igH@yqd4k;G5eDR^^l01K-EodU9OS zB~Gic^F*2BC+DSn)m_h@807RxF_D4U{^M*ZR_DCBsClBnaat0fXPsP?dhSVM=!p&& z!_NqIAm$G+vZ7b&gpM0wYUaU9+`(6i>bGWDZTx$Z#C9Y71t2)wI{haei`M1oy!DMc*RnZWQE49rnP=sxCJgC9ZK? zN96Xv%8LG6M(Q3I_BD()Qf8aaJ{)45Tmw$N8qMO{ zErZtd)W+t?3diAY0`{y^vcSn6-diAd>s-t?+u%6dEkk{ayDiS2fQBaCcei8k>48b0 zm3L2p)xCyyG4R$YH6liZo{G?D5T{H+Q_=x^=&2}ht(w?k6`|nmYMzRV;AAxagOjid zy9e4&nT=Hv9f(g*2PRKtxH)xT@>FhM39hA|G8zlVRjJ8vUyYHc3S1pet2@L`w1JcR zMq^=)slvfw*uO!{pK6{O0 z<7gKzTZoOYIpG&13pbw*avin2JRNbbE4rWdE>l8J$GKbr!x29k>3z^>U{7^9u>pTs zDnw6Xx}YP4%>ezlJ?(HqXhnM};ufa@$e|+V>Eso>|4QW3WzHW^LZ0+0?zT4c^dRT) z5POyM)zcqOQ&99?l$H8TZ@`a@S;6V*lKE+hk|wN{ucwW!ed>^B%83ex*b%rGzO@=V-osS$fwW5nMV;q!pcB)KH6lVf|)U<$~B)11%Z00O*w zUncZSj+2;bi=?csuAXtW;%kgA8az&;!Jnumif784_noS6{9xs5mE&rGd&X!wR5I0% zjjK|tb2Yp#=JX?~s^>g|o2v8%?fQP4Myrd&XWCpzjs9mk9H+MrVa&g{d=|9c@;Jy0 z?yd7d&SUr|_Qr-VOM0V1&qlr8bnf2T{efrWT<2FLOTsA{pZ(7oZK#Igvl&Qfoly0n zXS3dg+_PBuXk1U*2cyuP`kpOt4IC?F_Q3{49V{jRDT9=xj6^ zLPcj|#EZ^G*%F)fmC@iY#ibmD$LK3LEX|I0i#0C z1vvieq{MM_7RMA|b9!A|(m0R6kU#Oc80Xb(y5~qvE6&$Ta9qvn&rz|O{Am&7$-T7e z#=;DzeRC8iO-*fao--O-J)rwsp39#WMV^XrIPSYu@bHlO4T#gy07#+a`gLI0;}z}u zRpGcgGOtTF_3>?jXTihv?{h4<@h97Tr;Rvpw+RN;5_PB25(3cCAZWcl{xKK zw!(4Mp_)`_tpgsML7vPFdaqbEy$4N?Z8iXFa%#3}Qmi%nG%APmTO3zcN6ik$5xfqn zZT+SM9D2_OXhjP>ALL?qr!@6L3SLTz*__8B>kzNzr{`k^-w;*s(`QkeQ!xq7t1bNV zWM8X}S}UGUd+XQO{W0^WsLo_0%Y`T5n;QGW3AHdipXWTjV3GqrVV{Q7FK}KxeD!?E zn-n+hzvWiv^AuOjvC{(sGcZ}xPaKYazRo$-=Ff|%m*7jN&l^po?tVVs;%dHIZH}uR z`Fw}tr$>;dFbr{A_0$)L9^NHB8?eT7zYuhHDld?ZRt;a)=J@W^4zT?~+963Sp zX>&PWzr*od!;^o>8|E(sIgMdlhS}a47pSC z%aqgVcV<#lXQA(^`oA3Hd`{N?<%not>OJUXoAYPpkcat~qXwRoc#PvXL<$~)zHx@K zn=p7=B*6Q>lJPPg=D-x$|1!xB!@u3}5C2VgpZseG+IXJsVrczx#OqQN_ouTVI8 zU#@am4ZoM=&iLgz=W(;7I2-OwBRwh}r$U!v%Gxj+=N^8n+HS1GW&+R3OUWVcdgK+n z=Y+{(%qu~|viRwt);RwX?G@Xg9pq8qD^ZRko(}ZJ%W%Gu;PifFQ9TslRy+AuQk=(7 zY=O7VDg!6;Ik%U*LQZQ@%_T%4x#bqpD+Nv?D!C*zY8g0LDRKS)90Y;)P9t71LXJ&A z1GdEpm*Sk`l^WNa6d3ps46C<3UTK)Lh!KBQ5jYjx;ygZLodNGXo(fCBUUl8{Dk*3+ z#4%9~lK#gjUJZJy_hu;hjq<9^mDEMst45>jgOA9}@y^RrNc}^FSCd>Ht>b{7t|o_9 z)0|gh`qd1_&z7zIYMxrF|5eAJDUWEpYBZDT+^-fzVh$pH=waBtt4{lBg&V=Of9^2& zuGWTE2RV;Jq%wH#@x52;oWy}c1EjwqzS`vcf*kVXVcYF)uXZ?%E)hE%jj@0#0I^n= zH+EXGQ3ei2qo|f_*<9Jjqa24%H5eTh6(1dLjq{KAT1hUZV%|z|d_fy|@&yY9erax} zP%F;`&dEpt>^y#g=-&EcJf?9D36WOW`yj%mALDd!W<`Qkq*@>Ji#9@iPC?2yT+0)U zV5+IK)#BzbH6(t57F2_$Wki`;7`)qpeXmgwnlH-n*8&{JH;2lo-FS))>h)TL)7U&W zVAF5-*P@(1r!Msp)bM?;B{{7&{;wIqr{}4DiVmSR_^;tc3mth4{1h{++Q`3#rvT{u zZv#NLQr)k~n_HWKOjo`CwGuB=J)HSknd9nI>$S?j5ope%Q`YGI8Ewc=wQF2fT^GI9 z;P_-5`lk@$QAb!k;%!*)-{^SFXpAGoXq4i2>epdMZw}R|Uk`8`ojP#@#hWSx$6hzu zV~Q>Ds5hN0J3^k&Onf~KMr&}jLcE^fIGzB3W7fGOP6glrt)JnZQHD#Y{L%d$)yjr|p zALKaB;yTc?&ZXW*&eq*&r|R%)X$)=zSs3S1{ih73x8$>>E3A-r2i1e z8$qsoOj)#uKcWE~g}-5Q9xHY5C>TF4E%`W&poMQFxR`n%{*5HZ)q|05P~Egz-*p$6~F9<{L&s&1j1Zl)e4L8x%0jb6lSnLHb?pjTYyRXo%X+x17|!F(emy6zHCw z_rDq73Tj$@Gsy9L9C_6AO%!-E4ya-VO)Wq)iD~|+O1+uj_<333%-wQf`(}#M=iA7W zIZSGmxQUYtn_n2~og-meI0S@lNp)|Ex-Nw_#kdfrwG4!;-vyfNJ87{7Z zzX`J`uA;=|<8=S>T=;iMX|q5!#oS+DN>TIIrV^LM^yT~l5k5F0bt;_4^jsx=k}df` z&L3M7E%27_VBK{vw5h@6Xd3?|)wdw+w7tjN&;2EKGQVqk;M)Pw`Q_HPk$*QN8ql47 zB*hSMf7?c)HL9AZ-i~to_W|Td9?wI-nHjm1!->lZb;HpMGZ%YJ238DjO~5`>Z^7wZ+p{^mF`#}Qk%rrxhjI$M^0@7P@JJn<^R z21#Kly8~V_@Mx$Wm ztb+GHxBG6w&=;@5x;UNQeSSA(a1QchGi~A`c#77a-!EmCza=yO9PJq%K|Gt#DqgwC`5E6?Md^+KTmVjSDZ#BTuzyxL%!l zsx^9onoi$saapx%rdCu>f6IJjN z)ZLT!&2UphNv}wgbN~A#uC7|?{W8Zd2qI5vRd-`H`!rNx&$h&BNVO_pg3FzTO^>=R ze!pSzQm@Hz)q3x@yy5YFhx6#-4cP5)9UJ+#X1yxb|4LS;%uj2~S=afIlabfgc`*e7yPB}hs zIFAF`6!B^=_d${KD9i!h{l}CjosQR~F0jF)Q9c+%qSZ9o6s^;@TrYnhN5j}N&}e=w zjo@QaOq_vQ(iW)y18P~#pz0MLbU6OU3i5E^LwBVY%cy`0Y>64+hf@tIfQCT#hj{M= z1GN7`Bi72h4`VQ*IWRRKjbe1rz@C=VrsNNkT=-8UOJ1ej{l|wHcmHwhhgmN6N6M2} zj^h{9B%bHE3c`mD$N!WTwH#hWoq4ns5S!tczhZw_;gV5&5bjJF~9r-k>Hb{4J_qD{#q-Bq;vBXn+eP9}0%LXsJ8sDEU%0iMl_osD{_ zCHf-=@|t6R%8CqlI-)Bg9k1H#qcWGn3(#ldDD=OhfT@0io}V?>&(KG8E{)%Zu@_LO zSt(9c&`L!YPJwr?&$~Zrd-b_+f!5+5Q9v{eI!z`G8daf=5#2upMGK@KsZPY(Z;U+$ z&k&!Gwnm0J|Aex%OLOHqUcn(IlQe=JQv$D&wuhq^B>)@24(Bd1>oc-_V(~| zVv~zqU?Wd-3yG$V$<;njuYQN~e{LWTy?=Sr(S_&Hk=S`w&sGn2;{kKnv7%Wi@6ASH z6BK&?T$W%AsaE&}H4)5Xb0$OluLP$r>=KE*HB~G;53|5|c`MjMl_F=d-s#w~ylT~d z<+9hqGCTa5jS zq_ZDmw)h=t@b+)9;k(F&1(f`8l3T)}9sC_EsR`p_Ot$p=>&H~GR#RM%Bp~N+&^|U| zjEOQwcGN8UalyMCwd{9jaW>s5cM2DqVQb+9wugNZK&shNWqd-R)^N4M`Xs_} z6_rnHj;lHRlPJe0caWzqs(ljkCc)kR%L@KlEz+MPxU}z0lH)3@pQJdhdgmu;j$br{ zJR(JrBlx7`*72ZE%AEIuR{1~h zD#tIv&YjBht6k%~A3m?Q^ncReydRb(#|v5HsorgOV)z7?GFXH|pHQ^4FwmwD#amNs zPyACUBMv!PqnDi2V&^qO(QO+0IQV-kSKhQ<_A8=Yl8=?MB$)aXS zMfuYd$JMi!pQb%`Ho~1FeRr~4Sj~{1<~XiG^QqDFe~Ckms#S2^!%wEU`;%!4QDxtu zvSBMDG7Hs`{pr?iSOn=$GoRMDGDdz4`~=nKJ~i4raJX!6gkZS zblxg>OI6^rq-S)KV~tS{c7B%TI)53G4&>a`WcCHxOFo}DTvpu#{fsKAl}pblT>!t1 zv4JB1pOrWdzsunL_gy}#xSwA+_A{g5)b8iAL9VZEvVKa$fb0%_WYbceKcFHEcFlIR95%)c!Z@{&f&I`O`A^hKGM1FmTMFe@1;T zjz}JtS@co0&of-^;)LY$-Z%bszYzPIi*pimH)?&K8$PL1lh3Q%77lKl3sIMg3sSwt zdAgJXZ(U3=KwUm>xua_AMcT^yd57z$cz!;_aa9Jvdi$w34jJ*dxJiPeLPNIOEr+69 z?c#zcUxeA8UQZVr;gEl^F_h$z7(NBm@l-NE_RhN=@ z&H3ZHgah7t*KcTulQ`F^{skL+YCKfp3ruPB4(_JEXpVk?2ect0#{G|cS-S6wxM@YI zCpdm_MkM}6Tf)CcasF=(@>DDiC;o~OZa@kB>iY*@@R8tuA*hMoE%SPf75aCYO>Nn*BG7clCVMziV7)K|$pHhDdz#H}s1e{zi{imZf&fjl>uu^!qgj z{ugEJ*Yu>m#6|}n`V-Us7eQ1<=3fTAy~im4z0dc2X+vCVAdILY%=m778RPt~aqI-% zJC5H>wpHZ5^qykq|1!fh($vHV%9mM=t1k3q&Kwah-+dM)GupX7(q=GrT5)mHoc}kw}@u&!`9{+cvQMf8uTsV z(3eA;q+@lEesNy~IRER+z$J2W4}E2G4kICU2@Jb;oldy~HB^E6D#0by&gZM77Y^9m z@?Eg6(p(r_tp>AJQHJHKygRRdU)|05s>X5JEJNSzK7C&`Ir(=ICTChmv_2Wd^Dj`EP^Hg~kH*;xJs;4QWy4$8~JYRnJPk<&C(_m*YtkwL$p0!<8C$P8HH zj!7V=xvFk|f0N|6>dfCz6*PG@8+?=I_+=3h9MC%4H(Bp#uh|2bdep08-(c#%iz&U| zI9ypZ$u|Y}qo?9rD7lZU^?qZ7U9HaFl)WdnzA++?^X&%Q@a~F#GiVkwAaoaT3IT7# zG=b9Saft43XiWd^_kaB%yCf zT&piWuUv+i32JBdZIkoI7o~ac=BXHQC93WVQ?N8+7(=lu@iFB~3a(PPE5P}q9f=1y zE<0Gbi|VS```^5jw`n5XaZZO!<1|~60TGpa$?M47WiE%UjlCFG z&>|t_%!U}0IHg*kL`mWe*RHs5@s_DO+}+~Bc#ffpLVC|kN~I3xu|H~o7q2Y00tZnc zdPyn-!;L19TZ-`TAeTqYgV#~b>ttwDczD$Huzz@r%c;;0k8@nKkS9G{q9f#chli8b zTGi#AAv`?A@lsSOX1%^OJjZ#}w}$6Aj!v^g>omi0_WTfnF>Q%=MKE%BcsLplu88?d zFcejb53g`DsCSXF0-5MU=;7WM9wZjT;(ZSS?;`>Xj5Z#g;fx~pF*|O9 z$qYq@!`m34#u}Qq9x=iN(@3xxUJ9N&&4E=HPvLEhhPWakOUE%3oSaC`FefEl;yBuA znbuC*;35E1xR|y~w$r5WHiKN_G}$Azsc{?*W?*WIgALAK;UG^@#2O9<#e>VN(bHA; z*`~vV{a6lhT*Y$RE_aFR-ZtR1d}Rn&aq&tsDGz8^YUWMFW$(7+dk~fR6}=x6N~n%cCMu z@jJk_12yeDaOJh;5fj_$uVZ$pS z7#SntT;(*J*)2!d@b1pY!@?sd3|ix><{gpZxSH@rP(hmfKaiy`j=%$NsKxj^r&S*t z;m{5htKf)&>mdFp%5goS#8nXB7W}jRk(HKl=|}N7bOla=E{{sEuCytNnm^Fatsw2H z6vSl(X+H;Te+C>$oTfCbIh-sQPpJw zQI22LK^}et#80ob#vK$$a9Ulj1d<&81<8?GisLw0i`^`H$4=ouma}o{38a;yBR4GH zH(O(-t8Nl-xUjrx4+jbyKc|d587aEm;^1(A04*v9(ikFv3diN?XE;#h_zXN>1fQq- ze2w#d=;|E5TGhsz^yUOwocCL^&2f1s77kG8HNWLqbvQ62uK{}kTtIb$o*>6@<11D5 zJ9Q5(ncO`>Pn3({n9_lm`c>3$k1;OQ{;?-v=;6K@^sK9!z!BG;jJHViWVxK$m-gg1 zj?HZF7Huf>IGn#GjXc@KBuI;7Pl@wWlaeoUd>=d|4ZH5#y?40BXjRo}J%e29nxeFZ zNfV_V)YIU+UmDd`Yn^?Dq+W~TcwDc+YS-cXHFZx954E|qvx1ygYm61)IOguyY8(_^ zOX`S@NPl~J|-Eq%A7yJL7wy~99I{}R+Z!Oj%L^zuVjY{`;{ExxEiwCku9xN)YboX0gmHy(Wx~E zimK#x5zebhZfA2`mA_q-pjOFG zzkXS+=hrXC@e?R+R2~Iav**{>;W(XMpqwN9`V~3v*RRBJ)u`K*IbKd8PvzrcAFFTg zb~S^qO1>#NF5fcvhUABYP0QH1YjM0>mX+E*B2oZ*x3{^{;-IIreOx#$pD_5C80CzLBhlrRodj^L{3TK3Nj`&QSl1-Ko9#gb5@7^rNlM}c5yTi4%WlP3 zS(29^UYP~hJ8BSly_B-#aVx~-TLw>2L1Cl2M49-}0fVQg5Rccd@!m^;mldi%R`B@TA8S)e` zDmaHkb7)FY6z@QVmt`bR71jB=#LGza@(U8LA=TvfB$&z}Jzc&k@itOj{(CMyDQrHY zv5X=LLm{fDu7DeAccKT}Ks50&gFj7F!7scaD*2SbS0tWBsyTQ=QsOy7{!NMJ4f(9Z zi(G!{&Mv+%9HL0-1r(%0)ll$e<8WxukXMd24f%_uot7bAm-rCUVf*8Mat)mNfJcNW z(H-hYJc3k<@YJtF<1R$75|n(L^Ray-oLp~?*CQ{v@n#4Ouhb_eaWCZt85gY=hE3`d@??gyp zi+um~61S0R@;3$~oIEWzNWCx zqmr<>!t$WR<4ARRZ(a%Sm@wpHQa;V)_f>W>N}l46|CXod|D(b?=8@Rs3j026oma#qZ}ic9Uy^tZspij$w8Y6@&7Wz9iz@6b zT;WK*X7F+lj-@W8+mrDaOZCv~?Y97V#AED`A>Z`yaS^1N{10L-J}ErT#vfV%D+4YO z9+yC>DNL^qJOF=JdV1k;M*XMDX>wf7Fqf9*irn0OEs2+q>cu+}A4IAZ{{zzR8YMn^ zz#6k~Wkm|LkZMA4*@?!rf$K&ao_vJrrpfL~_<9h=Jukavn z&ECx<;u)m6Jjs!K z4v8-RjKnE0x;)8|d;y8RQJL`_NfeRl3M5DhWh7bwGi1l@tpL~MNsiynn!=$ZM}}HRba|2^yn{rSwkb4W(gB&O3TiD!{&#T^or zc+QZ=7bReC;UNvl7YyE!cnPU)kMiVp8HrxL!mGeF`Pm8NNq!KCE>Ch@qYe)5Tt})a z1Y9D#GdZR!kQ^CmBhlm&cMAJ)Yz}W}dHi=tU*l)v4hiwAiH81nqntl*vZ%VeE%_wp z6Q7FU6A1k3gyb`vKbZU^yICZfzpFD6&m-0RIk+Usu06s@ugLiWPnI|ZRJTWRBws|qEPn1h)R}g>0k6ox-&F&gm-Y!}9rpLlvat2TGq(}BOJ$18V7l-5O zX2UK8j;~20Pj*U3^!mzmVV5%S;dHGh9bQ9%q%ep?S0D!ouOZPKT2qyH6R9SDur2Wx zQeD2`;k#1e%cJ~R0ZCA*D|94oBlQ&^pO$zOsV2WRBJl)LU0$yJyCx0!IP&|VX1kI> zP2r#n@`O{W7oZBx(c^BtyE+Cf1GTGnr+Ch;C4(n0~Z$r@}yUF$6l{Zj%vJmgu$-4Pk<~8+eT#N3%6mr!4;2fAy0;z z9QO?puN8C_6-@HvkcRvAJA_Zh|74BMq8gII5D{B&Rlsg|Y7mbI?H%4Nzy*}W-GUrH zGlx73?iO)7*G}QxY~)|UKO=^_MU_AdkkOKb6s=D{HyGD&&>>ASW zDE=m#Vx`N+C7##t@8j?7s79pVAkh`b5yJ7hUI=9=;8>Ks(DQ+P^v35Bwjc0mc)tI1t$Z9lcMHmPhR3_VY?N{7`$?T9Mtt9QZHxVsv=}pmk&t! z5>l-qV+s;4Bh@RiU0f0sm+&iMwIyCN@T|n^BJm8S>+2ev-!35eCdaL`#9N|80ay}5 zUU!fjM&Opj44nKTJoSIzIRmds`J#c>B~HA)<#C@_qyid-0#$(Uj)Av5d}+|Yha?{3 zxO)c;c9y1e9M{32s8k@&w!uGdJg&GvMq()yq~q;d2cNY@4eNfcOVl@7vxniwNuIOz zvzl45(>3fuJoNUQwP)xkH`~=M)2^`{QGCvtW*txE;J;Zp(SV%wYpNJJ!>>D+95GJp z+O&2JZGl{Bo9UB9s%cH@UJ@4tq}KI2yZDIfcNX=gHM9Hrq^tToRI4u21%ct&`8m+1YcaoRd3w-h%m4PF`Ri z07RV7H)34R&r`DwJnE1svyKuM^o`i1_o(C{Ke0^xDW|~5t-aqHQQvmq*$d7%YyOn8 z7R)<)%4uhuWJm3JC!b|cw9cMjPbF}Ieaf#+KY7aOXPi9Wo_Urv|MZja*OXtKzQ6`` z_GxFFGTBub?kK6NaV;sBd(6_tBM;J}_j~;Hi zKgE=Dzj1VmY4|H;mc!hb@x;UW5u@}YQik8EA3i!2{~I-?Yp8zGO#Qu!9(`=dBY)A4 z(?77}@u7dHZNKfaw?oe~DfBPoOpVCavAg(ZHKJO_#)OvqB=IkIj}c8ewt1jlX>};d z_{Q)px$fag>kj!Ilj~+m>v!_~mRxte*d4%zglCl*U5a8=ioUQaj6-^tum`eG79pMr zWNtQJJQc+Hg-o;9d+GKzO_(MQ2C-Y%uzeo{u|Mt1t^Y5b5$<62H@>h<?7`Ou=zkHYmaPolYrx=zwA@*;_B_Ls{&&y(ii-55=^F910#cL8&rj%!x3?Dfy25 zSr$u$5;e}C1QaJ6(kHK0l=Mnwdn{Ao=_N`Z;8&RvOk&7QtRFLp%$ry|vxvuUV)q03 z`X=^RxG9+0GrNN$%!Vq9m>b3nqbn9m8A_ZrR&G2;?F+~6jH2(0F_{A4Y@Bz`;Ods%%#Fsit-8YOs^paqxDS`xP`hK)c zw1lw{o$z7_t1Xiv#i!xy)($Yk2Sii7v|zK?(2b3RF5bnXt0}l?r;_jKo6tqDT$JpH zU?YOm?$Z0MKz*q`xN}F(-dzm`KwODC|Tl-0Y9#9{m zAM1~X;6**eseWuiq%*l%39wZ1Mm1}Uw2A?GmdZ@E^Y!d;rr$*Im6V{cSA!I8N^rX^ zCGIN-_SW&clvU=VCh?y*mJ->gv{X?__bG~FmEMwGk$gdnGO$72lP|1C;$62-VU9KN zmh|n(2gJh$HUjPMFi4?3HL#SBv1-dH7esJ>soe4XSyp7!ko^j`Y#)}Cyr1Oja$UIk zBj(f$DY6ogSMN_3DI-}gu!zR{^DKQ=4DrUWIp z4JqPBjEh#@Wr~-t6bpEdSd^R*_cA#rbnyywa3~upEb**I^nKC36}^f)n8tdFh%Dr+ zE%6vNSBe_YLT9MgL!6Cg6W9r%PmuX&a{hPMC zTdm6cB|gMb2fk|jWhCp*=Xdp*B{LDmpZ|q4J_Z1y#3&jdvIelE;QT5@4}MjWSoNM@ z)qCbo@w!X5A?()Z`F*`jO4+y^%EX)@%-rL?Pkf8uk3p8oL17|gsO;S@W1uK~BJ0j) zZug4RF9{;q1`11(bk9djtd~y7fyAn-Y)E25dM@bj1AjZi7h*-o7}hg(Ua_}juR9T} zN-$uqSAzLNF@h`|Ei9^Ezyi1NMO(eH>=*^FedK+Sl_F&!L@>-n3mXj7{#j ztfxNQ2OvU4;A-)vco65#ea~z^b3vTYda*9ZFw9FDW<3RW(14nYiDUJwjM*L zn%txsHmoNwO4vuj(LQ`al#Rqh;hSmnjO)ev4fXAZf2{O$?fl=0`OeXrmaBGZTHYI? z0e_9tfR~qh!EU25Ja=SdDRk9`-a-lPE%pXLhllsv73USr>j7SGRQ+iTo78isudby{ zy$SW;7&at2^-o;_VL3iJwZn*hI`1oNw<5Kr{;B=ds`I>p`BwezRyHy^RclF)x1vvd zBTBa`UD`qwrMl4FZdFW|#dISZV@PGbygUx6PLp@J-Nve=i^TyW?3r36>WyqzxM#BV z4$6+BEX;(UGS8y2_?vv)40)wDHz1Fxj-rC6G+_S@6QHzD%rUPZt%Zt09rH#9Mv-V? zOJ(6a?pcwSD(7q)Qjup3#a>X7G!aSvr9QYGVyKyQI+iyFpUb!7T+H^$~m7@IRNHe;khZ-Y#I-K{i68*jK;88u_%wm0bp@WFYs*y>`^qkdn?P@6S zOAq$A>HKsygy-BY)}^ySJ^!`cOGhNWc>`1GSkau$hGR&7B!l%AX%kos-huBa@+QdX z@ppuOtpiU}e)QKMhTg_{dP!}!$x&zO6p&Wl*2$t?#Y_6G6FccG6D7UG7fxi+Do->s zQLQ@>qt~rVeWmtJSiCtUT&x|+LUruc%iaOezr>X8okGFPJ;c%5S!DOLbmB?Am((At z<&x0PMdR(Vm!DFT6B0B{a&>kf6?5OD&R&&GlG01X{IdfeD*`98zG_e6#Kg%mxS+`1 zqG&Qp0v_41XTMB$os0u@$Wf!y3Yon9`(-jS_Z+a*E61Ot%UH3%$_Dlv(BZD2kt4Wg zB`0=RS%KFuqo#NbLyK3hihAuRFX9ncDXysv7eTW?z&{G*a{O;qtYv1ZxRvrV4I;@WZlF1 z4_!&j)?HFqMYF;tDDKuw_v?9`HBTP)shKTY_h2!H#_nM~`0Ej(=^oavXG>vds;8Y# zV>+piGzk54mK<4~{EDJnN^mz_TkUR2uRO9v*ruaa{<>ufv$C^aQ2X}0-udeumGJvw z%XBsyn`Zx+j-=ajhOo?FhVY)liLBJ&c3YL6Sb)!9lkRplKphha@BPbkA1=1>b$Ex%B_JzG^-Eb4ireOsY>NtN5Og2`VQCn9FDOx7ai&SZlU_bc}Q8JT~r*xh*T zn7hT?sOW5pqUK`XbRfG_4;h*0z3VS@Le08z@Ko@Uy(Iy~rR939THu-SJ+R!zc(cu5@3u zuP{V8ZaYmzzfe(z!Z6Ili=}-6%1pf#>{*fyGQ?vfa|E1sj_~*~TCPIYx zd=5+OQLoMhs($oZ9|FB(5>a#6lH1O?rOTif@x;BADG{x4?qVye5A1oB=K08_Q8kp zUE>E;i#nO{k`@uO2rHit#BGaMhIsLQhG}#zyLrqW>5ZzlA3yd-E_>z?POGv#Q&g43 zKfn_C?l$QGyQQa_zh4of^?==~WKzoGQvE(2fc&$2zo=iyMv0ik?6GL%;%}vLWt%xG zkb}Q16t2Z=e2B%I^W0){$)-Hfv=}StZzDz65_Wgu*`q{?l)h3O?$1iw0hWW8F=s_J zW*bs@B5NX#7d1=R2DV;U9>j|K{TsD;53+yr?kj2vC*I>tdF592)r)kVH;m1x-LaH? z8Oo15vC%obua4DzvC%cXEX*Su29!^lUl}_ii3?i+`xif4wJ|HZr;Z&C+4ykwCJ)t0 zqm_Nsb7R=7pF~R`GX$;NVlG*k|B8P0EiACz_`}A$SH{jUF&#VpVr`z2y~X%@Ki8&| zund0h$`hUDe@e~48uLG?dZtwDei?o~iiIydc}mLZg7KXAlR5gyqqR_Ws*YDLs0}M+ zXE@6d=hxuCAV+jri{U+|cJNx9yRavObsY{b3q{^K%#3fR2d01Punqi0Z4*7BKOyG! zLOD;U1M^Xt?lb#E)YB|^+Hxw&D^lDzimaf4-|=0S!zh;FKRq`nEqR3!g3b7PqeIaF zKZWS0+k?^o2LLunxIn_eneHzV#HOclwscW6Jk7q1{amV|tWa6pRIKFDK?RW;b5=H5 zS?!eC&o{6~y0EQcqF`hAmdnB}*aLx>lN}r_ngr9=mTqCkb=}pYPMU}qOIBrB+4DaO zTLmVZ-XqXedf<-MmQ}E~bs>w5Iji!mY~Sr7+l51+S8I>B*h?(!-%{tKTl*8e^C^Hb z-M_?1VF>rP4&2WjxO^|JWxv?7iwz!Ig{4DPd3-^T-{>jZ&b_%b-$C2tN*{vlO27fk_iqTx9yTU%Rg;zNR^>(^XafCF=Z6Q+wC8Iw!2c{*vP9Y)Xzv7 zr)SE{jETe0*`%3Mj;B#a3lr|4BZ?|haDlj|irL3Wr;-}|D>T*rV`%ip*NJn7mL={d znfN4*v@CHyr;D(?>~Exqy->u@P{dyLDF1nZ=(CTVj;fMV<(*iLV7hz_bDiSE0->vh z=NE{<)z~LGC)QQNQ-ZBZpMj#aniYiTRkK&d3HyHbSl6m1%!qzOO_;~%ou&kcnCDr) z;1udbF?uondA4b&l-TZ|&`|Cm>E*00=SgIO3Yndp#VlS~%`YGk^}QidUSPeW zvq5nu)##+?cUIV5fPrrp)i1Dq(Ro(3O~$nk#RBk%my^k0Ov_uW%D}TC;sEP0=t)>= z+cK4((xSH5k7@bGUhb$JMjBN)7}~_j18nN;`-vFgs-Qdh!)RV!;eL* zo~xpFxWOpL+dsl!?j(XeU3Q^-m56zfm86}Q4WkKee-uW`{Tj6Ay`jNnxJcXuufe(f z?_Ro#Pl$#WkphgO&r4W|o)UMwgr)s<;e3hxEkrs4Cf4INAH*{5U|*p>$ae7yv&4G` z;RqKH_XpVseu0TTHSA-Pr1q>ZPGD4H#$v^#2JgR?kmR1S11RGt%kz|BL2-!f3VpI( z^@?XtiIa!ePDh;k1bLLbsCWL=bM7P8n46Me#IZ>*j->Dm04Ml^bb{i|6=Nm4VS8K zGH|B*!qU!O=%^RWxI;nQF-}z#g^&5c#&wZ+h0|jP~b8p1YTO+ z-x!aDLZKH=y2coi-@2qAE4`9ioZA#7wGs2kI)#BXC8H>!_53-MAKz9YoZl(7CM-%F zCy>3d@HJPu-R5rbq%`_2Tu z6&p2V%vT~zz<~!h)}h{#UQza{OIXQ#_ae~}jcKOB{@&DW59;ZY*Gy2H!}dTgo0X`U zPaRL2`Q*f5_8&&(Prn|JR+um$s&HnP!{!)8Kl9swv{zQsnYMd6rCQPwC5UEgflVAa z%=$WjC`?dB%}DsFXbDc<@m@b8As`ROxlSTFl&El7X#y%`6f7nc+a_Rn4?M2<*ohhC zT9lO`ckU_FPfju+zoMREvZy97x4GS<`sRd!vO`nA4@O;(pac{S=yLcTvM{1gP5Mr? z0=g|Dltv$ z=*c7DYZ0057nTuh*29eOR2>RPkWte*^mAxX!5-=oCJO6NWrZ3D=RToooot@JK`^mF z0$WG#NN$Z*R`x2rXS%Q3MEz@6K5i=FaXR<&&(icaMr55~!L;{ZWz0pmIu&Q8``kdP z;Kc!cf?x=sASS}Vyc!_=V@{^}wLO^cr8Gf%F4uepC{MarmR`bJaE4Q5K3Y&W_8q0F z>3G3n=>Rb9&V&NT9(aJIc%GuT{-yBbHKb^k<#@_!S)Qoq5mXDEO-k^J6N)V#1}RK5 zZ!SzQoheMn%37Y#&ssPrBWgvn65w2d1B>x6-nTJXj%M>_N2T6U@GauUZ93y{TeAw> z;I*CSHCvUKg62UN>}#xvG<$NaaL^uG{wW)}MDr991e?)SO+OUab`C7qLjvvWLKjOE zb_lR18(87SH8TPy4x15rJgqQeNWSqqw|j;)AZ_}0fUTLEr@udOn8Q6Jf2JF;l`-W^ zVTL7Z`4mOJJfYj3!oe9)uRv%STiwP%y}|OD8pVT6*xqCMD97#}3oVAQf zD%9VRgd-kSIM|xyxHM$5V|9x~W*m0{G?pbbX4$S>AjQC~Q><)#Gv50u#SmC#gW!Vf zf=h!gP;lEzvl7!Q+nplp4L0yL+8(=LhHgoYi_S5QR%m@`0hU(AL%uqoJ@ zyb`%`d;k3O?d-t#5;$f>L0$1!??AvxJ>%D2atCKsfeV2l2L&s8;;0SGoE7SzK$$5S z>2&vp3bGnf>W4_FAHXsR=KL9H0cqnVz@0J*@@IY*JeC5gDYw8;>R9wO-LtB49xre? znz0$z2&Z-5v)SRE*5Rl#uLYzPxCdP@^;VcY_iEIP;D9u{#fgwzDhNGaYFwMLuZMNtc)h@uSAFNX9FK>A=v z-#Z{pI%*;ub&1DO$0EOc+u^5WG)Sn|Hvic3S3XiWIk(Y?&cO>HP&5hT(7~v4Y?W2-O5w29ZBYNn)>$_$ax1XwveN+E*qxKrdE#VPJ^ zvF<4A7dM>h(x{9sWz#$T8B3mWsn3d|hmMi)994khEvXK~k`{S>GIc z77d0n(kX7F73|rhICU^oqGlu>Pn!`>0exHkj47(yKpbYQRE#9fp+vh43Y1OLq})={ zZk39a{XacaINxTs^_0^Y#0iZP14wcxbBmQdbyZeFD zmRF$}n`Rr#$MO_{CJ5P@mF~`{bhSNidSEjq-qU71R zT#KQe1OJI|9b@-}KXt;&R(&XG;*=Uu_A9Ou)@1WAVSR@U8uOPIsigQmZ+O|WN!7;V z_7s_gLlg?LrWswJuh5CZC_G(NcAMDq4*TnfzsPY_W^mM3Gq^o#=Rmtno5AfiHG|uY z;*NJ&a$uF~2e5Fy%kCYqbQLxK|HUHsJ$4UFo&l31Z4cx1eMQ-OY<>cv{#PSY2)lC8 za?JZoFKi(!ScKvK^dwyC68jeUTy1yB=YD&&e12%J*=So3m8HhNz1rx~E3k{=8ELWa z^N`vFFmKAW*Lcf;mwAJjm=f$qJYHCh)SA~e1+nG~!DOIpDGP{~gE{80w|&cN$Jr#tmWat8;J)DEuB15nqqz|rugS`sV#NnIwtULFYFLIT(pGgP zU_T^0)R2{t%5*zUS3$;uXquTL;BW>E;y(xR`aNQtnrg)%;h(||*QH0CNdJ62e6 z-;-g=bM2E3xvD>8PqKv~`6Hx~h0>=T3%~Xe;r?b~3znGWEfkM@gjA9%))IBDoI&_e zulGs}>ReWJRg-f2Q`-l%+J#oXujCq{!BfocDNOl{J?5!W z{TZ7dScOztC&Er+yLO(q^)xfG8zS#Cdqk4gi3_LMr@=ACoYKWs_E_ydK4;lXmYfhV zXW0Azn0lEgIK$#S$m%ofxxiAVmF0=aU$Vc+*GI&=U$U~`c$LW`wR0NS79MO=!G~+F z{SSL8fIB?9yw%@fkF;pC*wV;~xZ`#aa}FCTh3R75IkuS>y)FiP&kSi(14((sa^dIB zqj&nFwU@D^Gz*N&;9S!PN3#)R*@<*g=fDwRrn_jCSou9^&9%~AFQU#fM_^UWhj`s` zp8ev%uDihAVVPp;MYe$#o)wK3S&trt?}L?sEwVeX9@OWr9CRVm{r6KM>|g9#mQnlT zzgQ`oB|Q$i3s`D%rD)F!^7sy9%cyEm6<{Zv8rw}p=l=oCS(gx=PKyao863D7grgyj z#8tEU--nBnP3(LA*B3=iGqxR;4;A(FENv1k%{b|wCx%>Nb3#h1jXA6JR)8BWv48N# zip3p2vN3n%n}{QXt}!|zpo}M^uQu&~_tE;YQW=0ULd)bF#(@$(RU$#`V{KSgb zZ1Kp?Yv&g&5-U?g|^UV+= ze`QkxSJ%+%Q@>)gUfpVC)5Vv+viPuId)@RTn7WQIH~j}+AC%Ui?~Mdb{SSMg$HNOq zZaFeLl@wa_XS)CLvxvBYXc#M!udrMAUtX=XUcr_eyDT354QES>A@^@Aab9VIF=vg% z%BKBBEWCffWt+dj)c`i_Ea6i7C|yzwYvh)Qmu6k1!ixH@g%PK{PB=$Riv^3;pXl9~ zvndaF(ffDy7+*S6l>Lq^v!&6p$b}t~JwHmH$aF82BRC~dXgnp;{a~ax`8#`#KlH3v z{9pC~;wq(;^$MRVT?*a}qb!LQ*{#fg4Xc7yT(NuLsBi%sv<9lXOLn5E&}+}dGH}S2 z)B>soil$cV|1bGajB3O2%A%#h*2bQWUNnv*!))%blrU!vMu|Ix?kbxTJ?2G^&=KUc zM!UPk%Er__b`|^dJQs0#4Z`MBiTLYm63>|@@~*SqfhnoqueFM@>)0C02@wZwU-fwrqqhpzqPZ80q_*7c)J~!=(bjiEA0sV;kY=s6gT%=ZrEx# z4hiUcs3teNkEJ|2nLownuYb0l$MT%6&$jTl__{5khVfnlZ@(;swJGrB`OnfjHqU4y z4CAe`m^xr($>JBrC-b=jg^}~S`J7W?9p@AHy!E1<^B##dX(XCGa0Zzpn)S*SI8fp>r$Dn8Y5H(y^W>I3-8L9=8~ zik1K#B`N~>NF?FiYLz&e8XErIJ`%XG0Vh~MT|*I;FquZSr|=~8+cbJpvDllh4@ zQshp9i$ZtJ+?c%Tcn#8(w3+CQfiH|EK#9Pe0&T8Nzfj3w)A5bubUjTfJG;oG{; znMPJzBy$lo+2RWl^P@-R7Z<@z92NXpKI!xS&HC znEi=|)~L2OQ%0{Rp}{G#C2SJWA$))L>D!6e=$R2`x~IbhLU<9Mj!WaA{EbO7r10uF zly0%d^tMd*Olc0lHfdv;q033oz*CZ+3+n@?60GL(nJ?C6-NZu~znkGhIBww6&I)H3 zPvp}Mi34H0cR+*{C)6K@@mpuy`#M!Gy7-TLN5H%JMen`>3*K8rI7$}<{S`em30yhh z(1cA5>U(w)jP1-m^rSy?BN=TyJSSDm?8;XLW8(L;(TXc#=ezQFWWca+{`bK3t%O+{ z&c9@F`*OQ+#@fWf2tJ74iI9lk4~DFBs@28_cLZNKDhq)x&4fH*?`-DjJmC8h4E#bL z{1)IvZ6r7I=YqwRNPapc3n3MVxlaK0+e$Or+h!0o8OO?cZ zpx-pIQ&p^?+%6)eKbq2-zuyqyQ_fND^eayh3vcGLgEqLVY@|Goj}bN9v9M{n8J*2I zif`X|avr;w)nHyKNw#-98JB&w03Ad2hdEUQ7dqWC@ORm~6C8jA!f(ZA%Fc!qzp@ z6y?FY74{sS=)2X6udTR+PYwoO(9|~d{*+ON$f5wsxC!ml=B4xTqz)y$pG(MtSoE*YO#Ey``54`j%8P|o1-b0%% z`Xup3acg!%65luImWzZ|r{gzTpf}l5V@_GHmGxReWmtgK2+POZxbd55A!7SbKAfi@ zKMdt#cnWUy4dYV-vaPIV?VMr!Q^u8Zbk(Gfu%__v?jsiw156!_NPO{`?vy9Q;uQW0 zJ6GFhI1ggIhD%>he@2Os!A^4l8SEJI#*W~#dCDTOWdz^FhsKGqBY9$v8!`!iSFm(+ zIjc)9#>X7|{z1uKQCsQ^juK!}Gr^!k0`$a|awCwol;cIpC_bBA7i&lH9el`eku)04 zHgsq0+|fLZv8%P)#&EkX*a{`oTUl4pFO?_rK}dzE7-!?x<9;|d$rX6l4aHVQOA1GZBu+u|xJJm6}ame{rD^0gnHXWrCYjHe{rx*sv z^xjlBs!pYj`N=@dxlJdIOyu9;_V1S4 z;ZQ#_F?JIF068aMGJlADBJw8l2k7p@WIi(Fkh&eTHbg{O`S|SRB(rC|x~}P2CAjGc zx++L^>b;c80HZ$y#}pDwYaAS@Pixu++JX++bV*y#K`UOc@;-sMF5t#Y*9r?9t!=UL z2YL6Ky~CPk^78$(%^5tZ)|tuQX18Z~4?8{kDbuXV)z!oqhi4cXMk~t`x(sN;d!{=o zj_{s&-{VHtXi85Q9?$O=EsXaTJMQEym~NHb#ouDx#MG%gH#Xu!szRM@EgEH^;{&5B z*i-G?JW)Rt^SqnI4^xqXeioK2z7HqnO<8<0dr_oJMESmxmlc^&ihU3#;5@_TBj0)MG{Pt!A$qJ7qNAMT?zS*!J`%0JQ^#nUOczhyC;?D zcH)}G3_d;(hp0snV&x1ziI09?oSeZ&N>r2xxR;x|R?!Jf!BItTt^m~?_j2JWZMv5a z_Pj>Tc_8t3{79V7JfxM9MuJ5^RU8o-hMF=tm*>9lI5JuDK$>~^;h<=Hos`bMn{asE)j~X5SyuIIiA5R`A zRYsp!J9b+w-bS_*D<_a9rhEDoBc|WSZ^JZi%YCvBWR|-7ct7+s7)HBrAD`4ENe*5v zacTx1*1@#hmuZd4G>gV*)Qb@-=kv7CA#(7g6QRy6%V4jBqGi5pB?GNQ*?0yGKQ^0> z)Yp9*DD#*4unh~e#I3$!>lbt|oVWlC6JekQJ`7uZ8MgW}ys!Wa6P8GZeWm6|Lnesl zSRI2;(3K>Te04%myjYyWCkIw-O~h+f2o|I#a!~cc0uh$WQ+f5X!kWu*vLJnHOD>-u zQf0Qd-KoQiB3@gFVU>S~4`LSa&-lPX5p_RO@JC;WBlq)}39<&=?x6EPI+`87OQ|AX zp?%S-$J{k^<3swf@c|05wFMAh;RF0R-oJeFV&uyc=fuN{`FLdS1B>}oHT0TR7xkzO zSi=8{Jv)+U^FuT!h==*dEKX7s4bRFNpMx={09`MayRKGJ z#p;Zr_}c4Bk@sTz$n5UeQK~rHT@GW!t;RH5PH3f4QXb(Bv_?U5_z{^7D4ZJ~fp&U7 zA^PO;{?S#`PwE@Z_{KLb$ssw#^gO;HGAq-4`6952v94PS!XRH<$s>I`bBm&CEz2-G zL{{0~7?Mx5NlVB;_^pvgv5tD{Rk7t!p35S|^+)-={2#B2>5p*-sK4@jx_}z!l|@{5 z3`@E<_KSs&V@Q7E&f2=id29fG^=xfpKIU@#mES~60e^>IJSDy<;Db_MmBUK$T+B_W zn_SsT>D6e{E9GfQnE9yFT7I7rJkH`&%B@b))!y<%=N*~t|H9=+om|P zfs^Af(X>A3w2ieX!M0r7LTtY{oVtwDjJ-`&Dt+q`=i=llxjlCQ2PAu&esE?BmmT{P z;oHR(JMwb)3^BHlPjGBcr|&eZ%JF4lT`?~ScRC%7u}L0-m5RE1ux*o4!h3LM zsj!y7dz?64UxE5x&l5E(zz=ZBO1_55-(1Nj1c_>^@=luwSOu2@ZtN=T0N}ZJ6~70c zy}Y@K-;FjrakaNC5k-BTeS#2p672q<;Cc&_BhWYP(qt+^0gE=dttXso-g?}z3>CjHzY92Mf3qfW~ig4w# z4n9&9A2U%=4Bj%KU(0(D7h5UxnYES&5sj|g{`j)zUDGVJISTh{W}9;fAyKh_oi zr)yh+ve3--)9K-7 zM)n;v9rcOMSn?c>nyBB0iwU+WSv~2AQ=!h?dl3@CZo-MebJ!S@q|-bkMyvAIC+Hn2 zjga4*6)6Ew^D%L9BTsS^-f~<1HM*9GE132+bH4me&T|!$_IjzNyk~{Mr*K?mJ~<>E znb5=(E#=!Q`pYi?Xp(9_G9=&Js3`!vf^zFP1|@9UZgYT8t<*zyU|4@lui;*nX9BJx{sNj4 zD-ul>C9phQ7ljUEg&#`KAUtiU$8>Z%FcjrcC|_7O-kOE7ko4`kErc(R)7j8yK+$`z z7s_LRsz8QL~ge!WB-BW3AZdPOw4$mKCUfHP=7W^ zQFtT%7GgPYSW$F+@J?6sRuXgHKcg)r$XHTo#h|kdx$UwsE})L`7~KjlhWlJ9c8d+q za+AZk6Oz`!ABu5*5!?5f?yJja!kD}RQ-BIK3e%N<=J<+4k~qCG=yO%zE-_}e5-?gg=k@f;u1$De!}A25SMjvs*@kC4o~?KW zR)(!41E3GMbHXP!;Y+m4_Q$2m zA;?QTItu92QCqrKN0y5A&y#nMTZet)Yu)t9fNJ4-j`wgBNSCAzQerdaY;z(R%S3{D z?YRC{;oPYj5Juz1l5H*+?YZgIL23E>jvMm#K559WnuJa0|DILldQ2umY}hsuPx><- z3&7{<~olM`f2ICcWE@4f2(;BOXIr74y$jnK}Yytzbesa1kCRNLyRS zdCHel!|5e~c4M*5ND0QOJRvQHdM60Rv%#-EVs^_7svqT@Fm`%L7mKiM<@+H)c%W3|jfbsqY#+r0I$}D}VR+flHrRmG_!}OLPmzoa2*fEBxC42; zLPTuiw=9u1rXu`U6|OC8gUW?8sj3J*7b%ZXhC}-dO2s4~LY9+E=A&*mZNN}$)8_zc zeCt{%zG(ob42LB^WBM~!Yh-f{Moq1b)75)I{b6sSqb8^+urDN*T?sz#|HxE%b^C9wy?^9H+}cDv}EUwR?_jDOP2(bSbreI;yPmHctIf z``E3G7@#bO`bm8(kFSU)fv8{U&jiG$?$j;z6-*rkBIBqYTwG5L!o?-5wxtYMErwRY zWxH&#Dx2i2CG{+3GoGIR{S1v!-Ifu9_7NH_`XyI?F6PC6W?y-F^<+c!gzcr9)7!=V71@v9fm;--E$ihlOy7W0_AgtY zTWG1c(SU|d{xQloEg;6KV1YEIdlOy^x^=rxnawG)M{FeF;6)LBxycCnXfM6PQWZp>|@T^r5g#ue=dPVGFu= z)zy`gf9~qxJ*6ER;BzD6{c?Yaqms!o?%M}pNwgT>fTsr zP;hJ9yK5EE{E2(RL@b-iI^CLCJKWmi)kX(wN@|0uW6Um6U%9j^^#%^8Y(?Bq51}nd zr)K|hHE=uYVgM}fYEz``rD;7p^(xOYX(nHu(u_{J8d=GM9A#1gUL0h}qBgBc+3Oyj zw2zL-fX)iDuLS;_if^^ZIvws%_95XRHx8$D*n4iZm>Wr^-=+MXaTbaxUq*DQyS28g zc6eq}>6NV)JPpNALsS`!Nk1ZGs7!ym;7vkSB~&&zWRo}jwl_!%d2WrVod^r0#%Nxu zMqs!1308v&SuReuSh!p~*g>jQ6FpyNRW=+YDxa3-5o{XeZl{SAr76`X+U>qAs(JOM za-t=5d0L!Cu%|^UwJ3Y(lxDY5n;3T-NJJZ^5FwI=k)D_owPC^2YE|~8tN1H+&B zEWl^DQ+ppOLm7;-RK|ZkNVSDof+i^uVd@Dt>fr)6?O;%iX-M_EY$1^g!+bsUvf*Qtd%>0DN2{W&T`B^+>( zcjJ?2Ik$RxYe%KZt7ECGb5XNiY87<`p#B22etRR{XVAOjFztt3+XGlC%<&q*t#GIH zqa7--`W+QM?HOR2uvJ~umu%mHd2pcpd21p}E;8LeP04is=LpdQPmA#~;46T~r-{E> zoI6>Kr!2}?vb`E*8&DRFIxC&W*qbQ#*6o1>Q3T4@<4n=<8weJnP`#dJONmD1Mif4c z!mm(f^)QVAJ`eb{z#ju%&PX80Ex^<2Y8~+VfsgUf-wb>T@MXZ41Fv}S-GQgZf%|cJ zrrYsrlc#`T=7vc%Ez^Enpw95sd&k(vmUmy!n9f*I;RMZA(2PT`4|wVZqi#L$&jLTt zQ`cjX%kdtXNYrfw%`>3ERhM7YdBXx*N(2h1#~U--!%YLJqPmt0h@lVu)wIWI ztjby$-g3ig0haO2S7|<{Y#mR_^PsLGVjoYAln!ew#tL4J=%MRH);``ZayxPLLC+J; zef*Xw((P#pk1(_tcVd8Y!VBf$c+f0aWhbvgwZkg6E{h1KhLA2Ev`nQ9_(U}BBXXUuWgu_z9~Lf=d=yVPUAF!YiOp>>{M& z2mXi-cUrToO63iDSKTi+QoOmJn{k@mx}W#+bXVH0`-epJzjwV-TEwbE^(9*BdU{Fw z7J5e)k-#c%r+50B`9V-x!SUmUg7=>^6udXdfO3o&m9j@zvdh4+DZM((M`DIhMODn4 zzM|%N92v?a-04U`mx)9jnr;NpyD?`6w6cA_e2?QTn|tc|7|B(P@L9}h)a>r#ZszaQ zO-if6kIG6N&Kp#SPvbd#yJUZX4@r<+Mbk%AXAF{}s|t4;JI4X#tf+s1_Zu!X0>4u~ zT9$iVYh{OUM)@YPth^&E8(hE-Tb1rhh5i8VJx%%&rqd^6QO*u0w)*DDcN=A#8xMQ% z*}zNX;u|dF)*I73_O_95XXl>b#QuToO-*~@-pu( z5sp{o4cp+cIm%1M+`4Mvd>K35cpiQkyVm-w zukcAYF2Jt>&EQEJ^D+a)jl+Cv;&GR`4wD`{F$aFhd_##a9~~P3cn`sz&GBV`t3}KJIcnXlccg9McY61@S7* z;58zqmfy!+Wg@>8`}5%Gs)cm?fM~7de+@rgJx)1!5~pe}Ie$35N7#>`Cq#3E|0OoK zCbPXdfmD{+zOR^`h_DzBd`u+0&RO_0@1^1dexQ5+eR6xf!YdcH z5nfv1K3;8_t%MPs*#LQ>-hjp-N6j1D(Ea!xj||l~aeZk;0Y4%xyuml8dHG-0Q$1fk zS#k10FeQYLEN_*GqemfLFgE25IjoFQuM2e!$#_84Cm# z-@J(q^8=fY;vN@d(I4e$sk{cOS+=!Hg^@l|gj@l5H{tz0&wDB@$K|`V!i+WpwmeWV zZfj!2Sh3|OPYkLsmJf#BPaLHq)SAt25$hvDuRc`}ze6U$!?n)0=mIRr*S!t%K!n3@ z^KWBe$~9J6Opj6*&I&#=SCe#k{Bf74spI#B2fw*97CV$BFntAZeU9PmJ@}Zg9pig> z@R8c!clfs~lpny^`Ag=b$6d88@8aBsyS9j=hZoF8QD^!;!QSN(W&h;8 zdbtosIWjuU?<(8|HBufh8%j=y_x_3Can*>{f8w;vb)+_ z{1Ru=tH+6&FQK-bTf~(w`5RQHrh(uSwO1PWTRL80sXhD+Z`Xy#G>k35a7aVqN+9bR z`CmAXX%H#rac?vB#I{Q@SGG09{ARMqeV~I|tueooPRbKwT7~mGf0W0b6j#pUfHn4n z{CN~nbAb=)1@m}r7T~n-Al=!g-^DP03&t%Mct)(g9#MN1Zbkp0k%L@i=9w$!z3nzo%oBsn(OpH|%v_mP~ z_7Ma>(J8pGWK)Yq_>-U?6nm2R8eIV~avp*awmh*XGR>45Bnu+>U~z)JQS@ozV?yAqamX;YiN6sVdxH8V`=oEiDP@I47@LvZ^bMk{nSa~89~~I!5UmG|V74`0-%#tk zgqtU!YNO?e=){R1`51$~kqAi%V{_0zZtTfS{5UWPKyXv8zFz2mf?4$6)Rz6k&oJIE zODz63f3Q2W=Dsn?{8msa5mOJvg?}U8;yLjboN?8Y~>}(L% zf1!q(D6oG-nfePi`kw%EXe7WMti$bz3agmj!taW$Xs{~Ta#n~v=n+P&*Af zuau`Nd57X?)iquweKJdPBAB%NN?`$}|H1VzJU9IZJ_kO*SJbEd3PJ+#fh))>Xl(j# z{K4?JRx?v~_RPCb=j3m=`2dJaL2}l+FstH1@Y~jiuP#h~$6JT%gBy zIPymj7hvhzH?#f0)ug!0_9f@Uo4+H(3}K?-cmA&)2EEDRK7(=oOd0;03`oca%O@M~ zi;Mq7hA||G;8r98v^}boS9Ujq4_O_!5r|L#$E9}#hlj|n&ENigRRhWO@C zL#UX3jVE?DL|}BBOP!KR&M@dj*)`mxgJSBh@z^njFjpmhCKdDjO!sdxK6hpq!gr?0 zQRiTB7X$ss^-VNH;8NQa`U#Zs!G>Tl;5ttmVbBxL;tWF{YL}E-9FHYFelY>c=|dl< zlmo_qxRPS4IRQr5gnHE3&#!Yss38Ih!N)6xq|G<@7>6N+LJkS)VEF@>v^<~$wB8@r zO1QE;hIqnzY*kzyWQd_qqq5cu=r+pAt#K_R4&e{oZ-}C@@`VtM${sXCP+9q61O8h~ z5>A3W-G?T@CU}-x^*@cvB!UMKB^It6nrH~OY-iZU4BV8wN(sh)h$$FZGkE;>%0bel z*{yG~SK(JlODZi!2g58|bz~|t=Im_U+|GL$DzY-$bLA9NR(WR^uJYt8rS}eXjBQ5{ z;Xeja+RkT(=E&t%X8VFe;-_}_FibSo&HtWSA+HwE2;H=U8Q_EX-oJ$rANhHkV!cT3 zC>ui`;t(D6xoII>pv8?Vlg4NDx)Q$2`RX3sKN;UuDjw&$KJR*NJCl`>aTMcFyu11oYRD3< z2whrimYlX^woiT4hPu#2A9~UsaF@mP2we`fYm3xP>S4%6Hpae*ORnx|Ec)?V^ytk< z-6ITFV3Kau_2Rp;Ypply?qfZ6(?_Ax%oBF!Z5;r^^4&J`JFX+*%_!YozS}7lM(c7> z=R~wFmhUbVP0_l$`R+0?wui1a(Ahn78JI2M;}>*0-c{SwLzl`D;~TAt{(X{-`nY9D z{5il+}yLuaLH_+{Jv<2fs~W67U-$FpTyeKQ}+hr75EvH-n!$I z2V?r^?hW<+xZmzABEOGr43Gb{wx*A+I|~f2#@Ab-pFuZ7{MuKS)Jb@vHa=F@i}Cm^ zwG;d4hT)~9_Hn&#F9XloJ_cO|>!fWJdHr?w_KI&!eqL_4CV9qt)@)5s+Ts%w(b!+t zt9v~CHo!srY(PBuki>@#(0#Zg@QDC@#O6U@lOS^y*yufM zB1F<4ut^9Ot%G#WK@90mi3u{bw=z5@O7TJ;ooK6MB&a&3%+$bIu+M zU9y3z4Nq;vBIlhwSt2GuH-ViOa}sp@@o*&Q`bD2#|3{|h#VZNAWKf(>(EY$i;lrUs z`0uDEL{lP+Hfo&E57CYI%bq+nuoGguUW33^7u-2}Fkam-NzOTYoOmBfUR0cr5TkB} zbGiC6=Ip`pps!p}`j+EkNgLHQpG7|!@hsWXAnJzbjY)zlNqVFIX^js|D?G03KJCA_0NyHN|z%JPG2wD4@b zADrh0*AeXKY+!aHAv)nXHb1yU3(xgqIFE{b>d$j(;rlFpa3f%cPlfq5Ex~*u@F|x* z><0(D=UYzi^e;Rjpg}%8rj$sD zUlLF4cL>l~@Q8fvG{qy0gy@8q`ISGKqAh>4P76O?qlKU7pr`gB;S*U}g1?q&;e4kS zUQVEoK!twv4x6^z;nc!TuK==r2vE|ZC3woBg-g8^2o3sDKl-&1TKcsXExgVTUawcn zJK}%6AH%2XR03~4*x;$)h0FXJe8vynn4+z}vCI#yk#J}HZ?b3!p7mp}IZInE{NSy1 z+Vbb}v~Wd)A8aGoC;nY}LUcOWt}-pW$L0suY2kg1TKIWC_&}Yu{6!MTH~tURXbE1n zXyI4$v~aB-{TqJeZ`5h&-}Hmuw)w^X+x`SCS_XBf;H#l`Qnc{9^;-D-MlF22ObdUc z*TjE##K(Fq!AZXgpE$MU|FrqRbz1mSzw%ETwdM6rHU2vWnNxZ#!KoH4{FzM)pVs@q zHCp)d6hGL%+)=M3_@Yh=pDEMAU-~ip(yxAlU;VFa+WKELYGKF!_%S?d(Gr}^(!$@_ zv~XjK7QR@fh5zLTH#;@uj);FpXb=&<`c-JNY0KO4{NNftxK0aS^`pNY;alzqkK`Ie zc%-hymmoYcFhvW8_`!1O*_k&Y!}7HBVKrJfJi-S?{6}`v`yc@8Eq<^c1A|Lj-rtuY z>i2hQ%dsfLzmCKfIiRc)hX0304)kLXukR$F@Q3uVQL=&OzuFa@KisBQ|lz&npsKQh-Q5gjVd^<%iur7d5SqJwhkI5W)esH4}b~?52$~x`%ANiyoL8(n!VYOd_Yy1RWTcf3aIz7bcKN||TDaD4VGvpCSE1IwLZgW3oqlk=7Iqws&?4%xwD2*TAMDh^ z@Axr%SFbI9*N@-3d75%ZM zZFO4shMz{-^_}JL|M1B6`c4Ej%>Cd1ZG+td%Cz)>e&vBJ+VUW$A6(x7Q~ZT@?_%jd zsIW^52V1moh)oOMju+3=>NR_a`NcetK~K^g5$&(2ETRirW;weg2P~A^WZrpFtk}f$%8?eM)LD z|CwgLdocYh%jmbszH|PMO^r*yo`$h$hQPFhK{pIeOB?k5!Tpl9!Tr((^j+uwSZRmB z&^@?6qsi#E4ep;GAKd?vHMl=BVf6b4pZ{aC4F_g}!JUyg38UXOxIeeV=+_zjw!!`K z?!bH?PRbWI4Q5zkI8Y_YF8-=G^$)GxlJ)Pwy$xBxL-DU=&5DI?>=AX}&MGLn5gIH@ za?zpwj>eJ!k&^Ue9Q5m%h?eOIkyi9NK;Q77H;H~lZv%a#iyo1GLw|>ee@E(1gMPXP zy<1c%dT$^wGS@{9%fBJtFPbF12|Y`%K9YdXvdUl4Sd%3>6g>|5brPe4=_R69(G#FI zG7&A)tAurv)L#esXcs*w|Azj0kx+EVT4Oxu&7uMHP*dynrGvW$Dry{bCXUyt%G`3Uqqp=?- z#Q=*XAsS1yQro23{4X$HhwS5^KnCl*kZ>r-P^=Z?7u8AWXzXuk-TtFTx3AZV^iDi| zdc9%$(ox}P{)CIm-8yV z`ap0hn}MDf+1cJC(u&?1$f;abv2cEklDG0H&g~tdU(vhpIW{-Fm+bV4_z$HY1A)*I zSDd5jHGK#2DCs+j1HpuZ)Dg9KFS7%ARP@?FXl{bY@NaaT{5u-kfjlZY^0+b~F?oPa z{^J`odlemdtV}4Pq8F&YA&)%nlJ@%oA$@y8@z(iq|F^PJwJFhqwrFQZAUv;jp&B(A*Qs%m zL)^P1f1fCk?Hv(OwHtQsfSu|~P|;-P)U@Wm19lX>7WDZGD=UdUX(!P!4xoqbXck?& z@!rfGc!5>*yF}zJsUOo*w&NN^g=||eJynb8sai}=)na<97Smg`nBI3we#pyKV0x<- z@~VZrY9W6&>|)k+tA4xaS8bQD?vZkcQ?{*$Q?$-R{;O}Gpk?<`(^K9n4k39{Eea){6+TehWxkbn3WGmI^o>fbj(W7 zXSSrspL*T?t3J!$jsM32`6(?FM~dZ*zRh1Rx|KgoWRF^#-rlk|t00*&$lSNtdIDLC z7pj<`#~F4z4Tjo#ER+su~%3`R&$&~abWA`KiS=CGEq~SKeakXjzt^+pA z4&Kuc2v4;YI0l)I>&@!xX?9yc`XX_YU3dn(b(t{n~zU@GNAYAI@00%&A zn^c3y?Led>^76M$;!a9pZ6$$l^%6Smxidl)c~`UMw=1?p_wQ-aEl1qap!?fXy8S_i zo*4h^)P1REu{3NdVh=gef2D{s(bgpD+GS1oIa)E;LEB-O37HulYRZ_e-8RkdlZXqP z6q7<U2_eDgLTb}iBYX@xTv*l|=H{=&Fzuoqd zA60|>`Iq|IMae!4$o-K(s8ruSf&!<+?YyM5UiRaDd}L#J>Ddy*;lbadaGu1m`>UXz z*)#bsh;8pT1eyY&3td}OJ{fIK8+;ut4`EH+Zra15G;7vu@V4}271-B#djg_Lvhx-6 zja$CTI--u;TKT_e^jdLpYbSu5d*v|N10}sR@;9-ETnltz@II}zq zu;Us0O@XWu+oPlt0WaYXlo$?mNCEc9gTKz;@5S{8v%9N>s+%I$)g>3my%r4EA$S-_ z4K}bBr(fuW>jA?;243*zIZEntIp~V}F*6 zJy?Yyur+!p?D=0Qj6K)}2X$dXFjF7TPVJz)Hm68^Jd8bv1#Y>=$;Z5G-Ioxl$K>kW zpdIE7J!ftouImQTjiKC!>pDdzJVPGWb^E1$rknD(t^uN)^yl5T-WkADy^kTv++LLUc?d_XZlV`=pzjp-&s!^`99q@ z)`Zw2J)!~nlf0(zK8W4t_Q67u@6s*zA7QhLa~R~AIfk?THCedJMf*1 z5>kh=s63XI0N(ezC$9dmSE0xHal+Ny}qOo39gBAeD=jm{%Zn{`}#*zc~+fpYX?}S=XuZacp{4&Y54S?*zJPhVw_`!Ft%w#~Va9?5*Pb@T|+w z-;QT~wI1>Cc>2Wic&|u2iFoYsAwM3c{IMSg@ociv!+*{{`_(4Hmdh0DDbsyhPnAf+ zUXuOi{MmiZpJ^Y@G;3F8=I;Q-$M)K!IhXx|?YeK<@5Sb`c9B?qBx_{yadOUfg8M#B z9Ks;hdL^M*8#!2~TXu%~W-<>o1afCrE)>5%k~KEjTC0V4o#u6!aX!=VOyx)pbq0b9 zrKmcbisG5b=YDpEgJk(mD-c|yuFw4xP!|4`LeqfRw+&VWa+WWyT%sSav%}L}n+(Gs zU)^VTo)#r(+~vEA`1wf)XO0~(pNRZ45(v*-a!D0uZ2UI)S2XrhytV*+tN1R0uY5h8 zi>o^pO3psf>`7@ozH)6XPeJ{T4r1dfi^x8{u1)=p#{6z_(4I=aH3E0HlR3`oPqABt ze*3Pm{Xj?s>P$sW6U!aOZnJcPGLBz79^hyH$X`w)*MY6SUdq~61H)p6)p<_N(PiS^ z!&#%h%5PKeRGxr2p(Q%wy5)>K-ell3uwp>tJDX|0p4NRkg5E%GrCJm|ufble;PFn~ z+K!MRex&JV@Mm=}s1|_#rNM)B|DOgCppnk}^^5QcM5x!< z|E0l${r{f^WrUSZ(Io#>(Qt$ZDIy-j&l};Bb%C(`QUuC=T(5Tg$=*QroXXkai^sA? zuClLV;zXqAxbmJHkZ(ZEUdFFp@J(l1PKse}JZZ=s!Ds7_;njyD^`cX?Dbafjb9Xxp z8!vT7nzTI6S;n^~G;Y&*4#qXkbJV0W&U<0r#8W)U*pbdac1=a~l9f`AYca@pL{z8f zG21|u?r$fY4cT;Zka1ok?SRxMj>D?cq!lqEXZq)O&+s|dGl`#*A)AiJ!q4Glku<(T zM73q2NwxS#T+d}qo|$gM737lT)pLy-l<5j>FHH_|rde;gt))w<#k*x_>uytiMq|5a z<*>yGXK`B{spUl5aw%=rHiLJG=HMovSbTR@VdyEm5d>>FPo;n^6T|Mtw_H4hFQk*6 zJk>1N7ly&7l! zqmjXVj^HR>4m^$ldaB8Xj@yEu&*V(lCxb%G|1{~f{pr&<>wmgfv_al}&*08_P3KDD zxNLsBX8?ZtbjX#)w2moKZDy;$6REUR$lv4%j- zyxOXHb8D0?drNezPU}9_q+8xYu&rY$(GP9OG{w3zuKDcT&>*BcG=8j2w_HSNDiYSq zTd`Qe09dx9PAJ4wO0?xF7Hxx;p@JZEnGmC3yy)?`?W&563qmv`|r_MSGVTl z@p&F!iglWV)Zyr}>wz5YQUS}?a+)M(H1=GlZZi}%1VX1RlQela3ZHLM{g{12GOqi! z!xr`VZ5SFM+tD=iin%Xm<nQ7OWJoa{Bn4_8|MT&iH^eKy@MV1%^f+;4!#hV`uNel z>(v3?9sO@J`9eb=T)cdm{%DkIkU6t2P^MmJ8l0&Y(t+SKaoQ_c`HPM>YSPhq-SYX` z_8B{vWz!^09!?HUL{#6tO?v|GMZSVTeSu>3(|4ja5Sr$C``q4IQ!%hVT;E)$x2Lr| zJJ&S$sVa?AktJhKml0!!Y;lmIoMU#313Zz!px7Qc0rC>S0ewD)*r?UPySg=65`~7VSM|TFZ0bFVzKt>WvBs z<0F0cK8CmTtbhf6fwwequB3PM9ey6#XG*jId*xC!2JG|f+3?Ct=6N+&E93|>&Z{X+ zXMxo+WYJ=VumjBZbL~$4DKLfWwl%oa-~*Fxi<%h=yO{sXH6q8Q1)_ z0h(Prl$;^nwwtx~iz-9DQ};Q5l=2Jy&~iY1)C>_!h5JY$3z&3%Sj!pX9SWaJID?N! zKV%|kHrdx9s()TI#zn`kiGJ2c0!_N*jCEH8awjcbe#xA9)oSbLpSt*91w1Rv%`QjI zL%@Abv0W=uwLabq6MxcqWY|asJwtRNWJ4KaUF_}f|LnM25ozo=*W7Zhx$Umg2Dn-? z9H51T4f2?q#mM*6RWZvqMaO%4I?uruX3b383~M6^S8EyQ)d zB}og!EB(a48`}=u=P`Q~HwddLXX_hDPR5*#GNs&J7^uIyQ0sY!hR{BVRcL$_PbZ$Q zd^Y223Rc)c3Rt0i54Te*;;LtdU#k+uzs57;aZN<8((S%R-Lf9e>}z!zXZhCyqUqPJ z*Mq;`D%zyJ@2552>v+;%IeS@+?72!P_IgV7WBj1N*4HKmARqdE`t}LIZ-%3>*SkgQ zTlk#m>-}2bmklC~eum&L@n+XsxP`=tFcW46RIl|M>eekA{v{ql{|2|He%V2GdIr;b z@PV%1;H^*A|8%oKufW4kyyCd5MzrB>ZKwwyeESV<#r5EWbI_Z7Rr_zx^4H1Ejw-F^ z73%k-be|_TFLPXZuNP`M>9e=aJze-<=)4v4W>+e@y*nX&7suET2iQ}m74>vd%ZAAz z+d)bgC+b%T(cOy?`V~Hrr&@d>@3*d#yFGWPf_UBLJvcveH2wHhTKi$kQ=oi-$m_ek z40maMit9}5M(7DpgC^YFr(1J3@~b}4BOU%FjUZPFJNi1w@e5J5LzEyh5Kb(YGWUPg zqwQzh9xqn-SM8Tn_)NtS@*FiIy^|cX15IcHEXM(J$?%B1(II-@M!;`$5r3I(?Z8TO zpGSlf@=FSU&yc+Km?ygbz;l5~^A|4GmmBsfYcG2L(XI3^bM_EqkOSoeaLWel{bfWu zXpZEYC8GOxm}76Yi-F%^ZoZk;e7ubF`%j#RH@ijIJ6Yqa?b5E&{5*0TI0tI$i)%hR z5v{t0H`C7QsIaZ368$Og?4V?Mrl{8LIb5A|F4RKl{07gnuY zru5s(tPBkKkH*XhOobeA#!b=&?J(B>JHY(xFxLv#hFt^QfhAId{S6TuDJ$Yg?A4=A zGCLP-JQ+FC-!zHTA26wYLn&v2Z*^!n=Ih1B9R83sIoXT1i>j8)y?CBF*E_4gZODwY z)0@^U2gFw#K?#Gty`9=d-J1Ly4<~{XOL{K0uR=45-_i;>K%SkpfqG511L_uOeBvqD z+e>m3Fb8fMCOU7yc<;u`G4r)aH3-mN4a#(%cM?1)d1R>q&Wy2Qdlq(SK@Nl+{%xyh z`lEEXX)v7?GT+;^!C5sT%cp|D)hzDX+){-tvbPw#o#xWx zy$nAd^fk~O$X-^1O_aFj7(NyDyOLn=G7o#dOGps!iTcAoCwilU*?(=e);*Uks(>(LR(C^Zs;!j!Qzsh?(HvA6m+t2iH zoCmb0N86!qnX&zPhbrlJDNVQaRRwZqE?%;D_9gSw-GiC5S+qBwpIcEI{&5sG)xYZ= zoz;D%3dZFMZ6yl@dInq0q$oM@nDByWWc_mWjjWRF&$z@?}#hMTn-K3U${*f}wfxXuj49}}vCbB=o8^p}a zGv!}IV>`i9m5tcSdxGJ){92joG|a*BR44vnu|Fk(x$_p6OBsDL+4P7v6g(q*u2}86 z*X-GQ6u!NsOnax}PYuD)lKGM*kErvRC3b{w&hS*^RPkn*9b=rgc#OYSs}#qWZU)3l zflf(zH1>WVn2nT>Q%>cvL+r?VeWbWcw>$>#r^LWVS>va0<(n1Hj@kU(BJnZqF3}j- z70mQMu-4fnB%t-N;B8?voDCdOjYw{ z*Qk8(8Wm%?Khr>PWw6`_anbZQtf?R1jXSi-59)P3d8x{%xGKtf*cY{k)CAiBLd7!*ov!2fDQ1q{AU`^FhG1qC}2L5nfmos1Rs;O4MnuVkNb4X zL%|vQ8~*L&XUG^|!O`7w=guZM`XCvV?l8{wUe*C^a14?H zt{t-m`7Q?!nZ97NH`(@nmJM>CfA1HC|NNfC};H6 z1il<}g?<8v$!YJ-Zmre)%=cdnccjDPt9cu5`$-A6OPb=c2mCXw#?Duhp|(|&1j7YW z%$p_uMS11QV>dpDh=yQza_Ex^(TXAeY(rgSST=z=3pS-RzS;P@3a`<}`yO+QK_&#UyY9*x_T zQKkD#=aHeWyPg|6LK)x;{w>W4=$ULI_4yfXh3?ydbcwF4@E5aUpW<=3{-aA2h82R( zvV_B5NX9Gvo^V439t0ZM(IR6{Fn(XlSiCjnjUE*Q@{j)N>H8!^z zS7)O8Pq=~JLwe(?wT3n7KF>oQ#nm=)EmTiQsb?x*~=uGYZQI#TxJcULS~2mK@M|2!$1lTY4K%)<|mFgaa0!hK`bpp z!sG2-FykTIjTsUyxXi~PYk2M80QoKiKiA>&h3QwQBA8pbum&Fr)gK6&!Wr}1GT9E{ zA3fxS$Dd{fZqo;Xk*X!jYN}Am|`5UuY5 zd(+25#0=c$miJm5Nmhv{85%Aqdb?gZnjfMXV|o~0Tn&1XGr@YfWxd?ma%J)pz4VHT ztLAvE=50GC%1%&)PS`z7x~0u%GG?BdIYYK!L<{h1q`b}MS0=b`JJ=Kq)zA}s_oU!J z2X7uPcfILQOrFJc%a^E}0dCnKuf4|Fnx7pHMCQz^n7v}*67kqOS)+?=#wx9tJHd_xqE4`%rQgf}&kRv@Tmt%>B;h2=>lp(2evSEk#~Z73z;Bf{fDxdS30+X%K9s>K5^)#9eDY8ypbwXLF8wVf>%E+dL{ zedI^*g|XFh64Ew~s1+w1p9%y%LBqgL?^g8uA%(zKCTu)@E8+N87FM`m{g4XKD;@ge zCx~7raYx@|eY(jX(g?iP;XhqZ-TWc=Y)*Bp!+-jBNKd=yv%-^S4oL@c>aUx+VcoR~ zx6W8i^u9n8_||RfuATbzhK=jCZPN6~I=%UM_}2v^!>0~u((HM0(IC5fsEdml+3lq+ zUR#yjLh81PzLB`}$x90>CfhzyCflKws8cQOTd5ZJtyJ4AdQ{udk}uhMM6qm#;mdgQ zF=E5;-w#wDMpYl55m)_`=v6Ilca4(#y`p3kyx69_7#J(w{nW1w zj25T9JbbkH`KWMYhe`f9y8=&O&x&=BD?QU7xP4R$59v4 zMaohvBQWH$OZ71VBR>YrR1hQZ|18FYPd%en%UY4Z@b%YRv+e3@zcO{x)~(lUl`#A| zmn>WOwmTxtRF4-l=EL>Dc<&-t6D=>Us<@~9YOAs`^=0a`f zq5QlENh9b&NZ0G`NCaI7PhX`jf|lI_)J4#;O9MO-K^KM#@@5PW8Eb_kms7X1Wh{D> z-I4g>1lj#25wZTrZj#m- zxF~%3@ET3cj|WC?+A5Y5g$sv8tqUwdk$x%DPFZC?5JkZExS}iqwq?$>{byo-pn3{ZZmaJVzQgo z-O>2ZDY8qNM`H<*U24`(80fK5snX?*UaJbYSdcTOL&jOmnURTeZFyFgZu-E`tdo&*>gx! z)T&5nyfC71&cwoY!s9X%OKkpy5{90_GL18T1qD`!XF1ENsuz?b6rVM}8!ett<`>oz zK}o<<8k@ozzYyR5CKc%v0got!`Gp-CFV%e3f)2v*kqODKzu*e|G{lAY z{0Db<@b~_T$)@mReqRG=}~O3KEI6k@x2tF&##`RPh~cpPAsQ1;s2%J zo0uvT0U=hBT$|{HozN+rEvJPG=A6={U^@uD&1>H+4U!n~{Zx-Azjc& zF4+RnR%&A{0ep`H{uiEt;r4Jvh#n<+eo;hpo)(^*w~Vuq5Phv+Lwxs^>2F9fZU^#}Ab${r>3q%2bp8Yo-G#{i0>wxDf~Ltz-?{etUG|;Q zxHiNW8gv&pf1C~ki8<6aDJ+H^dik7iqU=!VmEl|d5?m)vUYdPWB+m(-5{k#gu5-fY zAKJMp`>NsLja#p2I25hVJ`@g~f9Tn(vcFf9H8Fm+_-%9c8HXNg&VKoZQ8VV0#n)YR z)ioQYUcKq+_{Og{#Aj_46SimPkGOhW<5ios#J6s0xa#`#U*9Z}SvluK?B0*FaxM}R z!Z`)v!K2xhSP;$`DJF(gF4cBbB zcGE-&oxP#{nrk<0nHb-E#g>gzw}3riBgH8>h+~ zUUkK_+w!j6wiSUM`tKj)ZVgUR%BEi1unu-)FmV}7Tn3{8kV4qtNjDBn*^xVM_%!K5 z!@8~4Zkl@4HS0D?ZzK;`v|CzveA9L7uKGGI(ZpN#Wtc!UoEoECfj{K?)r$!=8!|b9OL;A=u4X<0SAl+j=Sjiu&t!mXk&rEtDt}8(Chj{gQTymm%=#E z21i>MO4*58TfQmUl>T1X$AKgU&vwZdi*8A;)>Ksn!386E&6^NUo&x>r4t@22sFU<{a%^w}rTHC>d*8)(6G?gv%bx}MLymkkZU%wAXalGB zJD@-7&^NYgy@B0YVbpczO0DQfJ z*R~RlHgt{c(3k|lO=v?+4*!Z~BHRi*m2?Q3I*D*02*SZ@ID>nD|H#4D)@uIjPk}#- zk<^*!oP$5*5ywyHNr(R{g%ZUf4Id?3zE!yqo~z?35PsnZ)Uu~1fdAgXS2BMe@ISlo zVy!0l4De4Kd@~!Kgvk(g@VYYf`9lbSA#1clSly)+$y&-jfN*FET{(_$G+C1!{>_aV z&uRxg)xoQqh#zg1Ylv6WYCPDBYqqQ!M__Z0CgdD|z#0c%0SDy~gkxD(JNR05v;p}4 zaq#7EMDgQS)?E%>)2Z=L9QY#=NBzkY@Jccq_$CO49f6e*Ef6RH{(^(AD<-@G_!~~q zr3scLkoB&^zqw2kf*rs=0F^QtQuawG>%Sa;~}3BN^BP!YoIijxrI3$Kgc|zLW$)sNV2WJL1j_X{ARkli^Dp z{u(kI><0fe4!(kLnSgN8Lj079n>$I7BgFm1xFF<#TB@gRyZ{2B{HV=GuuCGbBw_}U)QQwZEOluP>w zFGsy)IsBU=z}5Im!Z3Sm3clS=0&(DD9D#LGKprrVJ;A{@S7=zKI=k4x*Oh5JfO(%i z9XMtBiekdiB(pDc1U57hp%ns^mMw7Q$BsburM9E78`vS#Q1%s$o|Vm-Ke!S2*BpFf zE$P8Rm;FtJ%lM$C@!695;NCvRtW&f9B;N~|8M-%;}!>=#HH7&2h!IxHPESL@ia$H4P+ofd=3sUHpX_4<>+5aq#sO8qW;_pW)!kBc!Jbc(T$VtZmnX5Zc_; z4!#Vjlt*wJ@M~>{#&l~~Exozla`-nP1M0xE&2tUS=32rLdG7Z#Kk7dkt0n`1CJxW2HZ7dtH{y7HsJs5=-JdvdTvFMvK@SR1?ee7{E;Guu&Iv(-U0qa z2VdPvcnbIoC*t1{97h{j;P9^`1EDbRr4GKlm<0NPZvvjA>9@L_2rv}+x^1A)p7#;p z|L!PS-Aw!?7~_zGuO~fOaqzpwz8ZaX$V}Yh@F&;QYdrKS2oF1iwT&czltzB$;Ojdz zp0yFU>ukA_`3Hczrr(+}%^$1<{##TAorJFbSmAp8jlAy|*wo`P{E;JYbDVHAk$*b; zt11YGp&_nmSp$RW7zO+^N6(fH!ez5jR36UFOKup@Sa2A4T~l>wTH}G$z~?wNH+B+^ zHDySZgRf;=+N^c(4TZ%2CUDn95`hCEdS*R@D>FDYt*fNRsU9FE9C zE)hfi;TTxotnnPwTVAe%Z)n$e;6mUd2$vT@t6DWd8qSM5695CJ4osv#-gF0#Yq&`^ zd0)2ir~bwUBEaW4hBq-@2E5Y2Hx$z*EC5w`t}(m3S*pg-1^g=8z|j%48V)3YU+*Yd z0X}t90#7;k=6b>lfwwsL@##gSKIMGyqxzc-m1^+e!Q~bFM{n z)quvckh;7#z)v$T+(Z0m^3>KtO~PnweV-<%RR0x;hanUl-P_l+;YvW^v9C01OzuaA z<~Rxjlkm$|MGL{iGXP{bUF+VlYM^Jp=m>1`_yH9Ek|(cBCh-c z8Excah*5y3*V+y$=|u>IQG|;X*|>j^RDymngNXmUj@F&(Q|dT!u8TMbgQFi zQ-v0gSNKESr2)nA2xB%6ZFcxK5`T6%a93&6G;97)7w~&s{N!j*>Uq*NYu6WQfj|ui zZ#n|CP@oP71Y8bnZY5lf#2=l=Zo>M+$Iy=*J!{F)7+8mXO1PZ0YlslsgF(x41Xi*` zR{<|{@Y-The*n1a4#IMFv>mv7LxP4f8=2%|*d_K{=-fEKvlb`FVJln)dWd}+@QqLu zk^Lw=kJ7YZ|K=#-t4PT=%)Tm&##XbQ6mZunJWvJvRR>?!srj>H=H#s9{dt+jgEhd_>5^vc#(GT%w1V)7Be0eYOvmMM zw&UoQoy3nO_yao=t#PoZ1DP1^x*4>J^amwg>e7=OM*?VuyJqKFI3kZ=9JuSQ&$?QG z@_>%vu1k_-afJqg4+CH41aMi8#c)2DTU1ZDlfmq7GV_6QEWDk=Jix~?KO z7858Va4keD;GjH0(}B|^3I2+$=ph_U)U{pR*r;)NXEGUm$Tl3SN)bT{9JYs`^&EyH zz>hf*ukIuQ7MSSk!1?6(3=05%&*8tkm2lV@5mdDzW*RUSYM_l9>UQT)fXh$q{@YNAD|Dmi5gbfa%Zh#CU;t^Ln___)* zJPLTDgV%Kt4*H01JNTx0!mEJa;^6C=2~XC6aJxg;TucNM(TF=8d?hK$`VMf{O`J82 z#NQ44F^7M7A>p;ak2;yVsgrOtBXEUb-?~`Mib_Cu%Mr+qI|A9~IR=(B5e`Em)KV(@ zIGIrZ!6$&bR?_M!;%`F1J42j|Z7L%|B?zvwTn%Sp8}PFn!yCJZe>!lNLvDENCEJ!{Eu zs1P{aS4aIvV_%`j0u3Pi#hLe|qz9@4BV9}BT8b=)VjP+07+Bs+0`KEAu*<Rd zlN@|$M__@LfZ>s)4xwg%6mLLtgSVXi#Sy(u9Ya!5sW8@i1eu1&+5>gYv7sOnw+v zxXE7x-hCeY;|T{puQxzoK)&CDmy|LLOd;GfAit}w#)Dse)I;JX|Dp{33xL4zVjqEO zL?+KmX2dHbE}r<0+y!HggDm~FkEoRuLFdb2+?%;;r(zZd&LWy}Cu+%Od$P0wd4#Jb zYUPxPcy6RX9CO9fFY zcRd<;E+U1K3q{jgxeJ1YqU){P3-JD&O~GF{AaOGqMDUy31q;1A*)Kf-ONnIX17a@` zZhC%FdH(Qka!(7UME7rU$B1977?LCY{F~evUiu?&*h_x|dIBDyM_!k>xT;s_PxZ3? zM|yKN2a{sdZ*vzUJ;E5G5(-fxj3F~%{uJOw7(-BR3OD($BzH~zElwDN3Vp~{D6jS~ za2?^MfxSKk_BjS1Nk`Ng@+kh4h3PmX?SrtN2&RFzeGI(oW8gjDva}roTK@-x8~XFc z!@e3(Lm&_9iPuQy$thLl7-+(uGJw1(Xe3Ssn((K>SNZ5)LwM5kNY07f_%R*YOt{J4 z;$vW!PXKpAPm`lxPEH(%;65}>_%RKf^f7?i#;hOpPVU562Ra}pb-aZ}PUr-Fa4aAmFOzGGL9mxZoQX*;%Ekfhg!T2H{9g7J!{2p2jJ@RZ}By#8q!Uyvwt)aL07`V;H zzz*OjlMDlLL?k}gfHm~EkN%e=F6V(Ma1z))4+F@&!VUgmdEN$warRCA81%qd6@ar2 z;HBjPBA5d6fqN`-!xj;4^55XYe`6*;?8ETQJ`vnPxM|=$AN~)#`G;dzyk`6G$vEMA zP50qG(|7n99|N)`JXZAKvL+;M1Tg$K^E>$m7hZu@MUg2Gox%d3*+eh$j5-stg&wK z;YWrtY63SnEek0cR21mSv9xrGGBRZOWXO7p^q3L9O}H_{BZ~roBCm)?j+YULJ?~*Z z>oKcFsuB?4KVci?QR5@;^D(#AJHI3MdFN~7qtF8xvp`1fCmi9}!zc4K^6x$dKJhVt zit;iLLq#dv$X6@}_~3x0{iqeoBZ4U~-`k;>PesM5GYn|`D}40d2K!zE7~A0;aqOfI zzfVQw7kKmMqjHp8a~qYv%12-g;YNn?@AlzG4JiXA|J#H4Y5b#B{=41+qb3g)Kq7HO ztx;2a_^kR$ce$*;_$w%O%Apke!5R4t~%|DhiXE-!=u{VEmY_*R8uHI5*k$%Cj z&%!bmjv8ybb`;g_b#5N}ma>cZO#{3_84(ms^Nyeh@?Psi5vH-1Lq(_+$02+CqgK%_ z9|2^-5y0Q-0RM+R4*lK7p-&(<`0OX=KNNjN1S8^8ZuAfU|0&<{;kTu;Y^a<9Rw6 z{Nr!%=09~J1!nUr`%&vuEG%9TpIU7SNc-Sl;lqE_JK|HH^>!$pgd(qnCBDi>pb>`G z;wKM3_JQwY+2Nz7#YfKp2t&`D3`NI%6!8LO)Wn2{utJf7(g{AbF~O%cCR`=@H$)27 zPxuxbk;7pRiHs_0O}Lpb)82jF{!Q5H9q5D}k;;+&p{BhOJ>f%dxrxI>_fW`9L}hr% zO`PH*S1#Jhq#O^R5!b{uK63ashbJPV&$TA*_c3_TNAOK0n6xJPL^#nW!qf1OBk()? z7^QR?JobwCv>DzGoYnw*q4@YjWMtAh4a4Rse2b6p+dlm7dh<`hUVP z2~hb-YqC%6OumH_nt~4lKhMK~qdpEi>!ar#=vZ6sq39DIMW1;qIvt;m#9Ej6$KPuJs_F`UJgcD|UMG@LJ9;q83! zP8h}HFw3BLpLg<#ANA350y-84#2pn_M~dI|5q{5G_zWxy>i-Dkp|y{wbw-i5o-@Y# z=)tNGJR=|;*cY*q))_u)!5Kbl!5OVE?J*A^2&yA$ zomC~8_RAqSi(NK6IBT<8(j~ZCbmU_Q&N}F0@vx8Ft0Hxwl>5L(?n7_6siQ=^PdYkv zvbW$=4&5lwske%b^D*XA@AHw{>tpa41lxxnW2mP3EVNU(rVRVj;?VIWdGo|jG!2>d znl00OX3MlXD7qd$rk?A3^xWVMOuiDKj;J+l4+!JYF%|g~;WVEjoc5+@lc$hrfA?{K zGi7AtY`J8-oN51TE>fce&*ns#dg@{K)PR`xd*cZ5&R=Fijuf!dm%D9%PJ`sssGL`C@op#?O4egZ^ufSL{&I4 z=A0HEv0Xl5Pl)sdL$Ea|Iq4(#x{qK#f;c}jkaJKTUiEoS)LYLv#n5r9n3NxhCC{1T zBRk(mwhprQdiZdIj~*UuV^GhLXSH)ZCfhmteH8KFn~J)j=$9T2z2~EcmoufuHQ7od zP=d^xldW{3x1v&B-VBFI@g02U$>A+s;UmapW(uajk0Hx&fY&`^ww3N9{f3@%?7C&T&{JPNX`+prtk34)8eBi4e3ttaTX@l z^a1>R8h#9&=b`U4SMRtr;0i;N=;@NWiQ~qHYKhI*X@{k!7m@&B_?|dB&K)>Nd8qm{A+ypTYUI;;lZ8P$uyzICSwPZ;My~WY_`vk z&Gs3x+0Kxi&iO|hwPyQ_+3by?cN~g!_I2Ko%;qsQ9qWMF@8KuUWk%ZZDazR#xSNk5a+atwo1A4owLtJ@=+fT z-u2;s&zpZPM`A=ccf916)5plw+!fvi=C1NFu)~MH#fSf-i{JgEWbW(U0_8ptl&c6b z11K*Ob)#{SU+uC3E`8w3fjK@S?(&pKpMtw*<$HbPc%V!lpC)lLWp}yP$ObOm9Q;dDa_t=GTkF z%W{t~-zTE^J`v4Ni}YJ^uRh;h61KDO$fqI}M7=#+5F_01Z~^AO*A?7?`4ab-0}Fg2 zS>O}N0-v#2pvNX-Xcq7g$f2=MVHkr2A9_bnG0{7Mipf6wYkc_EXY#{7zVv;Ek3dVN zfZ~72hySEE|H6A(V}O)1ul+=1a7w` zt&4re;$ok%xR`TpjNQdI_!z>i#o%bTnKwAK7ppNk3!tgUXN)StqOBZDSY?5CsFi#w zF&2o*a#6Bc-mtFZTpI=}c|Mtf?f54f(x6XqRQeRhC6wqcDv@{#@X|f%qmH4a_#Y?u$YW^ftEw%kM%?N{No+=5ccRv- z$BQ;8ULv|>Q?8n^l}Mh)rB!vEB%dNq+aHOYYgOOs!?o8ir6Pc-hqdzkMCQPloYv$n zAFXeS^muqUN;l(0KYC;1-ptFUiTJ5tF4N2vsu^45!@N;*ZPN`-Nz%?+BK;=vx$HgB zdupVhXxV4*T7FoS^Jn32?;X{iX||Z9?Q!j7GmSI?kkOqsvPaIhfE*t#0s^hm^tPdtfGh zj2XZDsOXp&8ME*>Im&VLqK|wpKY<2|ktw!9s&QpFP=P-9SHy&M8mx^%&r58gNPxU> z3Q4oIMv|5*kC&Kq+-;};da_~k~Q=t{@EtAkYEcz!Q<13y}z2hSO zMcM0?y|F#siCyu&NJ-H}x=2?p7HQdS)aWfzp)3o*#hrNYd-+L%n!>`K5KC+!%O~BymB%bPGbKl zn~fqh2hLpDq}tL;jiL=UYi}++YFJ_XRi$QZuaB{hTTX|O>DtJuS)!^K6MWTTC=269 zyZrBRm68Rt>IS0Uh^`mCSv$GvJb=^zG}YePx6`X<>dslEBaWoEV{L= z%W)!+;>TO2;CGMaeaG9>mJLX5`c}III1n#H#Mnf~>#c9J5a9wgT}S3;Sq*g{e_igoQ)!b=nou<`F` zXB-HoDdDs(g} zE|h~*<+mu+;h{U2)w$IjtO_n_t&56&sjEo;&smP&dc z@P(B84ZgplaiwW&C*j75k)PK1M!5@;{1hbX*_bD+W0BFPSQ~jCL=3iIiE<>g@jKM+ zRBh?T`$!=<78)Q!yv5{fGTtub2p-Wi zz{9{Hhe47RLmJJ~_%RfJtqhol!mrhc^Z|M5`kK~^Kbl*O%HdMn&2 zBk)kT6&EQ=;ntl>LFih%X!RwO`n56_9;Lpm8o0aEE6_)%+g1?HrOtS*o`L^%mC{@K zZ_VKI(AzkXHDBjT2QRL$Cndb{28oCRKQ-OkqWWsw`_q zg8!%&{i9JcJK7-OQOi3Hs29v3fq#zls9<|KgDFNS4>fQi-eqhZoLiYOTDGSnuU0UtUV7s zyYLqFFggErAz-hB?Lv8b;%|zQ=Od#xSi3$jEX(--%e&0N?IPSPT;}J@@Q5=1r+WRp zv(Vd-J1c;DjO3lGMME|szw==qxlT3Gp*wp-gZ!}FodfXCW5jnCd&}>ht}>Tp?e0n~V?t-gcMSj;-(K{Ee-gO=5a=`T|>fV!Q;cuk!t{a4f zJJUsXeaoP$RDphrNGSSkL{Ff_d%Gu@zDwy3-Sw!_6S@ok>HT7?0e2TuTdCTjyVH%Y9^-Lei)g^Z*3f@+@2V4cY!sa550Sg!V7m1UPSzCkNJ&)wE5%U z&ljUg@!_aF3GdkUH2UD*p?SYYjl!7VeKPrD&UuMk;8ZlBFI|3%aCVLHx8)d)3BId` z?tu&S;_*PeXj+F9Jc|=2UQZLe{hN^VnBeXGdcl2g zl3s8hl)DU>a3h`v_vi)p!Dn>4uU^aTyOr9sYD*u&^5Zq1ABy|n33bvw*LtWHMm;9p zL$c^S7J`RvRSQArp>}GYQEl>JY%9DRcz8YZyM{Xl4#|{0ym>Ir6Y}9J3FiTdqc8c5 zGPC&`K+eafR7>$G)rV6)PN0@Nox?pA?0K@RM{wsEH+xDSk=CJvmofZ>BWgV&txLQ_ z_W1yQLrV>Y`w`rcTpB4D`^a}dnu#A{6dw^k9yX)^X7=c$J(AW*d&I}DN6WnZeRMT& zk3o4$MNGF4o{)X)AsFw| zrT61e)LtptRwH*mmN}Ao68Mq)b+U5k4ks%Omo~stGSa>q_Bc8+{x=eFf)>nm{$i+QjhGr z^)P<3!o>rtBO}-UM2@VN69<5MOpF87z}@xUgg%TNSV1@qOb+98Kk>k3QH2#_(E&LI zZhJH@4&VaMYxzBJkoY;cJ?Kk&M|2Vo93^@};?Bx-;92zC!L!`!KKL7ivmHv-0lD*Y z>mmH{eZW)lIz|hiCy%K0_@iiK@lhfqs_-Ldq#`!3mv9b%N1JgDfce{q|2SIPp&CTY zgjYfExJ~o;+a$n>q;t~IcL`6(zO&{Y%n=Ek6N(Pz0ksW*-YD6k)9mp7;`Ir5DYzft7C(-_6RK>a0@oYJ0ubKe8PD=8LtNJo;ZxJ zAYAhYau}BrBOgD?t{7Ju$qOCQmxkwBhu-mCHao%ZwOQ(n(|w*!>8;y~ZuH@G=ZwKP zZ_zqu63*T+|E$5d&7V*wg!P?rw=)GiM%FrS1?F)Y?d0L2Y`&uG!LPf)?;3U+r!8#f z6MFO4Y0Q>a5|EQ|og{hH58TW6Pa~?ll0TK%ca7pJRp>+Rr>h80$Ufv4XFpARFSy)# zu{NOh7T`-9`^|M zX~l=-{y^edaUiF!r8aWvSWGvsaXP${cGrgo=>EsghUv?rpT+6&=x5WR>~{PZL;N#+ zc~kVWk3nnqpns|_hn^Uv??XMY6+AA7a|_W&CZ4#CaB|qj8&!!VpTHdOTJN6t5V*%s zJn?tJ6KGvS@x&+Sx%rhn*#C@hZU0^_y(bG4Zm<0I5ItFB2-KmEK%PvYnTa1GQBUpy z<~Cf1zU05pz^e%78cWE2(kaR(_n|Kpv8Q$TTPiw?#tT0}IM*IZN%0>w_!&1dS_eM) zv8N|FrH0`nm0<9Q_{a(}z=owF=sB{+z$xM*#>s(a;gQYKzDHz7t|LXJLpK-(D6%6r z8vKl(H2B$}*9lL^GlFYf__=h(qu75APX~>0trUw|KfjXjgzP)(!q0C(PwFx<^z+*Y zw*yo5p@_$f1zN!<4LnN%3E77M#*d@tHqa)?;D3qmgzSUAO*X*IOvoT5o^(Ur{SvfIr=e$UwS? z@PuNu4W}oe@3CJ>PXqp6_|X|vLNb7~>`Pn^fyzI6Ak0AHHcSzuXA+)3>yCiO-Wam< z7H~;D3H(TY8nX0O^fDY;4a3(FL3<>HZ~(snjoTqs#MRD*+0kzie*&#?R5V;3DVWF( zJaq!7N2Z?oSaf`b8+K292D*C%FOzDb*3lfo$-i92@lBC5^>M-)HqI+%nwnCEy1$Wn3- z1eN5|asb>T&G-rtzYL#5etH$?u5)#6E&2%L={hub_+TjfTXC~=HJ~IWn zJQDc~PXVK_p20<-S0bOmrH3bu1bZd&8Eg%}k11pXa?J8pbPSGo88}w%ZQxjy5C3lP z+XE$65_LqaV*@H9i;l@s_Q=SyA;OJ}Ji86Jtxze$uc-BGpU&{JACR1$a>M}ohlHE@ zJ^}8YN_A2sYCUI8CBnNf!d?~8H6D0aX4shPT@w|-S!CMLhk-5`h)2zL?I3E9=$<3w(DOWZ5}>;bJbxj2wgE-MFX&%{#;vCV{Vzzu zVj?8aN=1?Y{CK$@qT`b8G33Xq2{(r5csFnl2adl5+;l+Nd7JPAT9^G7E++GD^4+am%P8=lM z$j*!7fO|OhqB+bo3NM<&%=m54vs!)|Oey}bkEr$H4s=%I$29x|Fprbeiy!NEL0^(P zF)3&0d+AET4Sm0meD0Z8k3NR;7c)fsO57g#g`6zzHJa)8JOSvTU(l6s_b%`?Oi?w4hPJ?y+J6YOEa|}C&7!i9bB8%v>L*_a} z;OE!P=$v-wT*jPs3^6hV#t<{cpfaYv&vVXmZq7ZN^!2*EIq&E1dCs4ElP2k32Y28* z@PdCGNvDRtc0p#T$zO4I5C|50soSs}Kvo`dvmv}xyMy{}>En(yhFv{53P*NO983Ja zjTHWB|3))P&x7s$Mq{RP+8E*QZ+L6#`}Ak$zilm|P$b~ahzJO_J>D$`=z{@nsvzML7w*Bm|L?DQTJBJ*T?oQ;`3qA$J%{U3~%ky+r9?oHPpuc!&SUd*5)76#JTbx zhat4gm4Ci2%Rnf{obCklnkv3k=KUf0(#E8e%;4`s zHCCLr$K{(pYd@S}*wwS$9OlYS@wu{}AF8=hOZtI8Dd+#;U2f{zm?Ix91Jv^M`BCmcDr2@T5t9i;6mgTv7OC@%*tFDJ~r`~}d_3LUCO8->mr6Q?xA{9@MU zLVEfQe(vc{bJL6PS=m`ER(0rNcWPV|-^yIAX%17W^ydqArz|w0DKmUT4AIV_tySxk z`ovIvt>4V!Y3cQOh%J-&Uqi)G{?`O~a^wjgZ^3n<;a>+}l)+&X`p|kXEr(LlL17OW zGvDJ`H@O(^y4or3JS*vvXdBmmj}a4MMC9LUAh>ced^qy&2G?1F8ToIyf`k9Y$A6G# z@ZWg5J^tDbL#kBnW=~S?EDB{kdNTg6qMHyd`bf6c}FR4J+CC%$m=Lw2X)@bJjPt*n`B;Y zaHWr%Pm0%9Bl^>?&wck+tmM8{sQ(X#QMSJ2t|QdNr^w1{`;M?%HKTjcMtXh6n5!AB zIKRpHV`CwfHA=gW)k0M1D}IqkulD1`>{rI?U(v^QxB21~I6f`+C3@feu?Q3_<8f?S z5l%abMgPAud5ik*A}C~V7!^7`9!wjULHp1~MUJ1#oO|YRz6KqiE0@A?@@olv{CT;R z{V&32naGI9|89Um28WTz|85tVo*nsLk`84xQiZE5)I6xNk|Xoc07dZPoNdbC(gcTU=__i=;7U(HFsjw_N!#i zJpBfviDF0ljbg4MDvm$$!Y;v0AIyXJMuFTfDb1%jib_-N@6mo6jp&MR;xzGobdhea@Kf1ukKxBb zo6_0uX78YG9T0YHL3%=~zr^vT)C*F4{U%&-8aNxj7+jyr-R!5q&rb?5pDws}6CN0( z3}&zakB4V~w>nS*#9D07?>RW zu`=X?H~GP5QnVDx8$Ltz&EW7amFQ=Pow(+rpP~AY%+Mczufr4(2KHAEYQ%%HqXUhS zos@t%hG?KHjkg9o-Y6m~$LY|2jAOL#zaRWeUcsGL(W^ z28U6}(gAL+4c#jZyOAWFBeEQ&`=DzXk+OYU@Ievr;M(Y*W@uUpH^^AJgR;;=M+T{- zOKSl?sw0E$L_^!8JpH?jzyW9ViCbm=Em39R#FN`J8lkj~k%h0itj0qY} zO9v;-rH^Y48xcJTg|_^GA$k(NVh0M>Mo(JDDRO1Q4trS7oKyGsONM@e^|u-NisO?6 z$h6_4{f0b=HcAwp!d%7AGgnJe#aA5Pd9)PowNFCrC=O$4hF6J;(k0PwH-y200zVsy zhRyu9LWlBr1t)DLg%$4+@vb?T%s(+W>kkQt8PPVR3Ud7- zpyXqjJ2=zp+=|mo(e-mA4o8R3!XWP8ApIPjz&miFoVg!F1z(NR5&F9dCoDJ_&^*us zsK8GfoTv7Xjm)K=NB^w&a|UNWks09L2cPkUdEpxX5I8c61=3N0Q}&h~M5yA#jSfVq za`)gcdK?|kT-V2&KcdmyNQjI~gFVc31Jd6Q-778n2br7thrlfrjUsvZ<_{Uz8?z|& zOdm@wU6kgM&U0uZq1XVNEEN*}gW6J|*eFlm`@5EOM3d2CApXIqB|zm(cKy?+$KSzs!Vvqq~fLfevk)m(5( zHdPDV{N1=pRW0rir`z0kJNEu6TH@M{HAKWioTS)Ff>jy3dQRcC+w-h?t4N+Xag)+^ z`WPe4cC^ut(Tc+n2@@I0|iq5Eq zz%nDwp!shakUmw2ri83eU`R6_6Q@e(Q$=wKtj|PFbS!YWPryAMtDgLgm3ML@qGRdl zrp-m8xYdKg?S_JKwUnPej>Y%6iTm=g_$oI%fXVZQiApOco@kCe4zcBl<~V%#hwiq= z;ahU>g!9_yI5RZ+83+IUXzSqZ1CQ_%j*i=olU}|i=5I0Q6+J}pUKy}jJ$I>AU8&yT zM()EJt=?r=c1e%bIbm5jz8h`J0FU1(pD>I+AfGUNE)Bg54kP0U%fYnjmxa(qPbPG^ z-S^}EHzV9setslq28Ut(dC2h;tM>B;AhV=FE8S){vDuBRg!@*R-9*a5Vt!_%2*=YQ zgl#)B3%Q;>*Y(UCcm{`&ZjIa-Jg$0sRvfyP__fAHTh(lRd^vh0kO^9O>Cxi zmps}OW+8LsPVq&u+vnj`(aY&MejWPp02XK+zE{Jga}S@heD38lo-fiuuIm%?EBJ-M zvi*gT+@8evY~9 z$D@jWaVWT657z(UB5=Bh8N>L+b}-9yJiiLOKfNc#2ylViE6e0rKU9g9_bQthBK1Yelw|)6I#=Np{;PiYYxB~mL>30lS0KV>WAmaTsZRu;{eDeub}F(of&#DxLL zFN_FYdtnvq^?Fb|OLr1W>x)Rxv0LjiC0+z{%nR_W?sW2yFtS= z@C*)P+BQ56ruT@)@DkFualC{_tN0RmkqKUcF9f95O)uF2eXYjyg^E;}ON?uw$K|y! zIBmS!xEj0YG;=I+(tes8i`r>w_u_3RLURKCr_I7iucYElvXax%qAr!witM7(-xr0f zo!$pOdVi_#@P8?du#G!%j$PU)=ia4rMO|tyT@3v~9s2W^3`Q@#jk%m_1ukFQIXimk zD^Sq)CobTn+n7tkNB_dSF+%@dy1cFNV#5wokrHogFzggxX6P$_D-C_c-vrkRFsK4; z_`ht7;CSxHGs+W;hd}QL2fmC(n7HbQ;xvLbeYGu``gA?^^v@4?6}ilKMxZKnSq28S z9vpDR%BP`j}~Q?Rx`og&G)@FbBS3WD!SXuMdpUKbN`bXAO3B@9Xg>JMj~a zUU67dBsdG-dW;z~Pkdds#qq2#42TeQp)nVu>{-%sK8(*W0HD5csf%Odg z+0*Uzv*k=~o4ww!;{wcn+OSicHciWj%zg>Hu*n5ZPN9vFoxP2@>~Dehf(P+FzqNRC za8nEoy;u>nVccYnrs8Uu8J%q!#eQTkZ<#e!8UDF5O=AW3UhMRyQPX(CAdWUAG?BSO zZLH%soxrEyq<26CFxQXb3Fv!Oya8Vn%EQ{UxQHXQfvBD-M{0VQl~~Pwl)m!6Q%sk6 zS5k0G!dDJ3>^RPqvQmZh#v^g1DwK+&IKB=P({kRGPZWuxrk%1=ab7X>IqxfJ8tKc1 z`J9l9Gl%+b>Cc>V4LgoAXO^MQdC!?+=qvuXh!dOhmSH#4O+FqfpR6tbbB-8tmFF?T zFY|AlFZ2J#Jj0Ij{Kj>Lo#M+3ea`b6_Za$$%k3gIcYt9x)NT2hmjB$bhMe=9YmT$x z_+JNf%Q1JQVaIvS?J)9DT+L54Z#mDoMK0KL)qGL<)$ogjH&<>`+6q+)6iG^2}7R;=9=|_YfqM0Fz+In_`Gf?Se_5f%L{q!wNnhoJO!_9 zVD8{dd%5D%-27mAmEu}lBIScFelR~IY7v}2K>^2g*5ZC~{#RW-&nbM1#!s&`*XUcSMm6NVFo&)qJ3TzF&g*7k@_sE4aF4tmiUhC2O`GV? zbt&16>oy25B6=N_P`BswuSbc6#q~Kk37V^*s3*n=H;-km5>s4VFV(W;jxgeu+GFG9nvA;)@R^<)!{ekWdpQ)2q9T^eoDAJ1G4V&G)OC%EYg@Ue#I zcc|97VGr75NZSl?WvKW?l;rR>%16(y8ErDV3nxqGzoUvG-FXZ7J8we&DI8@uydU_X zozB8bcKSFjX5uFty{Qrp z^d37T0H?|mS3P#{nE35DSpwhG1#Ss^Gx<1yj|@j|?t?%Z0`-osmT7KkdT3ZM+Tz|f zJyc#2ZP_5eCDHFT*)6_{n_HhJntVw0yST2}QvL1*xAB|!3j64H_t_N|P7o1CM8!AA z-v%XPco)tU3-;RREeK`#zsk{D#(;az;ow00grm2dj|Y}c-_mGs?!qkzk?JMUTd2I2 zvfuJ@5q`kV7s=|DL>J-BpC~gP$nuVeE_xj%md-9ZAT-a8es3-mP8iB?^n0`jHsUa< zv^XwaPHc-Vz8FH92fQ)9U602Ypv82ajKegX17_1-z?|o#=f~J!Jx;ypKLNi~;AwbF zf$t;%4&_L3T)u|UU-K5rfF5ZT=Zm2SOgSmsVp5b=1bp2)$!{J-Z@qxJX zuS@!W@zJ-HWVd0Va^K@w;6b5JOX|eUP;iNS;ih)UOOWbYbDq@0(Iu}iuc0=+pGol^ z@!Dza5;Ifo*^)x0Waia=$@}6@EwxJyg6cg?kQ(A0V(w78P|DVTv}>i=r`vJ=Tf@v9 zoXJk{xO_WlYYp44gjDP2P+q&O9n86(9`BT|5w||!=GWoIu64a%@8m4n$h&m|>m8Tz zZmpI#o43|Ntmn)1x%FJ;4$fMAZoNq6dFymg-7Z0D;pnY1m^;)i)aO?0J@^w=?X3$y zbvv%Ztv4}uaMtQ`Yf{*?-MRx*x8p^2>n`T9E|0#gxH;eI$u08RkCR?s#g7<%6h9{P zy}S9qP!`-)??yJ`Z*>WIQ-50ydXsU`_M89WeLE@bZl8rS)kF1L@vE3C{dTkw=k|Hb9cp7-6u$>8y{?L{5d6Zz z=EQq*+{?p7IoOOLUh17K; zFf>i#a5PCBDbe1!=n2fVm1F}o<_@(Bl}Z*F^JI}RPs*|7gz!>;nheR+aI5z$NpXdVO>SiF;H>pHDX%MS(PS^M<%Tnv2hZRzR!fpfr6<6XE~(~%1GyIH2V>E)=>K3m zaT;?6hi))m%*IQiKiC9J1Hc)a)J1yX=noFyWXbr4gYA5&+}DCj*U|T~;x=$8)k<5? z14PZj(WPBtw#{3*9db*`OW$Jd;H+i*BTCYu|DyrS9h`OjIIp)Ki5fsuYbZ=an;bd@ zznHnH-@x3|pI1cxI^y)4z%(eb&VFdg=ON?cDOxWRwMu7x~yJa)t0S? zfn{))Jt1$ibl}v<5B95ZptvP@k1uWQG8HaMC&;zT}@cRa98 z^S{L{$=>B{I}O8;LA0chkSat?xf%iHr=-{}E^lR*SG(Dd2Vzw%$A?MZ6Avc4iQZ88*Op(v9&5=W(0@cLoe+_F zCA&@_a0>O5I8BZMFX)R;69t#IxY-NoDgN>_dN>8TMrD?FyOBED{Fl=*dBLJ^$c?{@ zcbqIg;x>wNpXfrvz4Rp5qJJ+SbKu@Q2fzn>htu8ViU_2WaTr6hVjh@Yksh?svlX-~3qu|_Me%NM znm(qVm%%KnZv~C`H{8Q}L$TnByqG5?(fjbGtyeMJ_f@zp{Y!Cg*hpw)k-#fAxVh5O^4gV~;h@mNKxLL3!k@9UJua7a<;u4VyFAi5wsu{EH!2xXR;H*{i!MK~k8_sJV91p5hr?Q3A!qErG4{?s^ z@kwqC-WnQwaAwCJ$^0r-Gs7-m?%=G4#XBewHu&JnWFCAFZ`)to5wSyMA`|wC-I3%FDYxY{+*EaJg;&dt+>sR-b>O|Q zR2O#&)bzUWtZ^@9uIi$=e2Zv&bEj20Cby{SoGD?{RrURM|Nc@*8lJ;qZRK(N6sL7up>< z@!toy$SVpNl>eu^T>A4eraV zBO4lax;NktH9&4zT@SU(iSSUT>tJ82d?*7w%S3pnS4@P5jtlj+)zj>1t6PfjrA2tU z2+tJZy@FqOLg7~DA+Qwm;ZPBd|8a)_seG7jacy?3qQ4L0iw0;ZKD?sVideayzJYJwc%)jYKT;>uYadD2)gLJ`f{!Fc)JM{?ZjU?< zb4%SGd6VTu#$#e$v8T0`?j_nR!Rk_X%TpWH{UBr$y zdp&_9+GID`&C|{LPaQOE@fyH&y9C-~H-ov#Tk$4vo1b~CPkG>{l4cJ1S%8!NLc1qu zfxzad6&DH1&G%222}fRGMr6^Z04tbtq8?ub?)h(nDpigQ*0KR-IwH>8xGZ~o1LU3~ z&CjMHiN56bKe8TedbR7P+gPAVN&@246I*~Ctj~##6n4V|>s*EZCK-LKnqE9PJNnoKP||jZ(lpwL z@YodQTqKWQBqBFF)@WZNk1dCtrALo#fc{X(%!IabEgyS@1M-?UjcfMUHh&@>m*0UD zeC&O$Ud?owg^hcq%OZ^%1+m`Z%(&ys2$Hz9M=f#(#Z=&j*B~lIT+*0;e8W_JOCi7xA;Bh#$JW`vd(s->B~f zx;$AD+Cb}@xRKC?iAD4&Nt=EXxOdeVgogMDM>n{C+=Fiw+^_;|ZOWh4OLB;f_3H68 z;u*xe4XR+OkaXWmb{lch^I-l9>SrNN{}D;Fq5li2M`3vsctper{$c{38^yWy7i2dQ zhf&90WWeT}$e#|lnTAsQ4dCfU25~39rrYjJ`4D(h0*}QH z0^ErQuj7!8B&NW3xryBa@iy6Cx;Os=Z)pA{O_?|jnTV&?P4<)^CvqirUrN0DF6NxL z$CoiziKo#f{d<_Jjw-%d@Cyq8x&g>wtq`b$)?cZ(u_d3DWBpIun)k4a{7TNTwqI4T zy-I`&^(%9P6t9QArGUR`1iv1KF*kp8o8SMH8_-7Hzmf&RlS}TYCrCj~!)iLB1ZjJSUK`!`GOi*GurUVUnOR_kT`Ztx)H7GHe>H=6grAw`k9(@(*NGX}_RK=Rotgm8 zEcV-ZTrDLPCk;LH?-{j}RDBh{2V&~C(&qtrhL*7Sf0oKX38+xE4z3mnS3W}{Z5fzn zGGbsVpLr8<%fLKyK+eETl!%s)>e!}pnR7lKr-Ezxr&4@$c+(uezQ@gh;C^kA1M!^` zX5gml`~j}q$^jPm196ut>^AW?*kI|+? zj~V*Rw@|0_z_i|>zhwaN!c9m25lTQ6&<%dV24REW%bcdGH+uL>w$d**^p~@KrKXSg z{YNNAY96Z|D}%`}(1(C4w8cN2yb5h;&;pQuUJqNQvmfbS+yfv!N^=o zOXH6p6?iK_Jun+=9l%@#X8!+ZPU!kvq5r40Fr}~fxrTllFPs0T##k9Je@;27g(2Ob zrs))pK1Y*?0<*ryRREK(WPSE?H9zN=^IV7DkrF(&)^FeiSm)RGxG@A*zu0jY+soB2 zLLK@3-vpefk37;u1z&{II2aA##pB2oxe;!YPpXmSW=>K)&Hs$jW8UdcK zwi-mA$3N-l!|QR+zYO_h7CT&}&!aa?{dxg}T83&P{q;@EIYW;x^y{m_{d%!q-{Wh* zEw>TBrkSzHUGxmzJ@5h^+7|8$A-nAhad~g}0(IWv`-KGfiB*ig&{~A2#4Sth3r|2^ z*fImB(fYz@y|9tFtVMxumCsaP=!M)C@3@_3A|l?`GP5ApYOiXRnZulG?{UhM`4V26!*33)GIBizhB~Aej=uaHPKAp}fj{rYkA=#w`CYyJwVU6mStR{E^({<$^7p&j zaH2}diWGPX%u*;lltCACknyWGk%6YKc#*a9sv2qTxtam5Zeu^h@tTA;WUsyfV3``P z?qCCBhF>ls)5FpYuDdkM*gorQz{OMf^+= z`luv33Q|A{OqJIhdAt$amQZsMPE()!u>Uw73jcTFQ;U@4} zNJGzh-68zZVxW#ZU&QWBJOBMqens~8HDXa$(m#N;y_Ea=HT)Xz?_Yu^y^Be-5&8Et zSG+DFBgJ2re=*orAp+EHt71J>qE577zfFy?oH~KH;uD1Zylo4iMsr%)d5dhD+HH8s zskO1K!>@lMt!#=z*9UEFczgrrx7A*NZB)S^jxrqhiL}yh`0JIgNo>o>*Cbwx$Ukwt zHU@qgpu+m3P5Q4j;bigi+D&fFar{dGHG@1yMB zQxv?TSqQk(QQ3w>|RKcxoz55ExtZ&UU7F6KPZ)aC0Bd;I!}zYzzw z1b)K---|;`0NTC9PdNIKZ58gPA$CdzpEC<&rbYlhoAKl?6i*DoMnG>l_Bm>JMfgpv%>6aR2R$4$yQ)WPlU`^d09%!a{10qlPft~^N$8V z@e9zhaO-hM&V|W9WA7Hu!(grX6di+H>U`eCm5V);ssJ0hiR{2mSnJ72uG;DFFFD z#+?1%e1!QY>H~dh%vkUaO+394ebV5a0nC-Y;vsO$qJ3v1xMe8cA$wUlul^w6=sQg~ z>9bx1xB=XAR>z(6vZv1y< zZ|IEw&RpQr;is?~yl0!ct`hu0HOUHs1rTUGRLg3Y>N)q&<7>pe7Tm=*db>9J?U!WH zMu&I3#N45F;3<#4>^2U-+u?V;0jkAa(o1Tv+s>Thdi+g!gScy_xIt{&wGWkUfUZ%< zcU$bM^4+`GFVE2>JJCkGcb73&@f7dy>#LD}ceUUrt3p2I3AiBdszqW3I${r$!z&M@y%J}XNIAV%>o+~1T)=qS?Tb$xsY3S zCGjuJExXctYSZ9+)y#SCPJbMa8&kFgY9jnfso$n9g`Qv)1hyevD-G1hEyh2`kmY(lkO?o&~$@$8+TUCS;Q*(2-stD_=#j^Ve_QU!f-wdujkMnLacK=2Q z)Eq2u`C*)SyAMFFml)d_mH6*5oV0}1_V@R4=BkpsUH(03-!=Y@e;Ok`_xgAA*tV_w z{e7X(7XAAnf5gR&Xj3M%Iw%v4=G8z(~6g ze~>}TGAKCu z(rt=S%74rN(<--wcZh$eia3zdR9E~av~+#id@+XqSV;UL{NhqCQG(mRv{H?(Mw<+1 zWovg99#6|B?f-Zhay^hrV57lRoadOU_)4EDN`4eq`rE+@dG#NGxhC@3A-H!_S`Zu% zUtm(ZzshGA7|9*lKc2Y^RN(UE;o{tKBL9N^ZTu&&f4&5!XG_^obXsA=9UPRc;_ut{ zlmnH}()_3ie}IOSxKX_WGr&qdhhLo8Xa|oG_yDaOePS!_UR{YB-2*hN18_)x(l?nk zgIPx7z(Q~>FIDveR2bq84sA3Jr0hGyfwbV524Xmb5q=>sEwsWy2#lr?BEFG1C+hL7 zMFL2}eH+*$qC7LBW#HhcrTZVL8zctBd%7{Dg!~MbAF0w+M*O zm^;)i%(V|Yiv;Q_!nYE)T!BBt3OJ!F6gZD?UTsBi z`~o*_EY;*c7=&1#G~9uM5zW6hL~wL)3=AgYFec5xiR?&Des6Uhq_!GvZM-EfO(*ap)WX4&?ADOv`51GD+JUD$J{B!a zpSJLG$x(hh3uNiMo0PyQ58bO!{^51+qL|cgMTB+wxR;&GD^+S??<5?APPl z!L@I5Ie38eX|8DB=A!t&j45(!Tozsb;_ z!1^l;eZ@C}dm}X_;9V5{^&AUifCBH4pQrj4J}7|CSDkVQYPPv_$i4X)d;;W9brG=x zyUTGH+s&Z{FulKFv{8pcW`7mG&d}!pJG4M>6jT*R2^K-1&xB^QDZoZyP?&;Bp9(|? znSOp_=&OWY()HUgl1k7Ef#tG)Xt&>yy6hjKwL*a%9JJ{2bP7lRO>4t)CHOZbXm;$Y zWH1E+y`0K9n5PDzLvSEuPW}> zZ;Sq0mE1IVt4M%dMFJctqW_6q|1gTzZ;(55cqn>F^zZ~Iy@A7+xQ8zSvkc4O#o({w zkiEeJ`Uyu5tJ~Vcub{0D4~;J=Y%_SAIRz(uhuVdm;_!B~bU#>m!jGzss+!_ENS}6X z2M0M)fmIp&^^g8%0JJE8augx6aP&Vh=1M=#yqvj1?LwmenSqwtauDCU3jAjl3mlwv z-i+2{97f6ivyilKsK7k2|3f9$6IDD3ZmbZ*M-P^7;Qg@yr7x+Aw49N(vKdTIGtYSTHQ zhE(-@0`yUlBO47n_slVPu6CTu)`2T*>7vL7|#4z&w2=g2X%`ctu$!ALhn z70HuYIC_+3r{0kWb2U+v8Bg`2G~oK$Bu>F9oVe2>NqeV%Y_M~xY$E~7^)4Fi?X zC?fz5_|YmuUnM%$udiOkIyzo(tP53f<%oK!_e}L*vY&g7E-(V@Lz^l(#n4y0LFYGM zh^S;_FpmXXYV~@>(d)p~K8lB@rtpjO7vQ8N>gg{8CwA2%9)n$Sl7KBm36;3sf$hWQ-9z1Kwxg1I8Gc^@x?f>wBS zyjJ zY`oz~aq>*l(iqxf_-g=tImEFW_`HZ2i)A} zONZ07)Rx9^qiR)L=i^4zJU&6V>o?i$9))#(e2N<%LFbDEK4k_XYsppdC?B8Wrq3d^ zgiPj!BFWrlm^V^S!qMY*G3UNjDc&xlt}5aV-y4LemB-f`<}K{DTW0fo5%X0?~OM#KX4p2h;z^f@U~m=72K zhr^#rERdwG4J(NS((1v>ZlVtJNjzmc@lU6*z&;VPG8Q-vcPCai*3bRu9K7SUAHFc+ zOIQv4#8-B=#rjRcjA=MAgMKr>^rAMQ9SFzz(dJCt!9jzecmge3*rnh>9Nfcb4<3`B zZk)u&INQvLNrr7{|L;)c_*N-(OROya3q zX&E5tvQf+(YGZ#?yb3K{zmdey7Z<&ucffC>|LYO=yu`<23p|*Eb zj}01+mfkU*5rf24o0g7)Lz@zVCZT0ng@er73FT-C^!2%_cq8pE!~4lg<%rmz1JJWf z*+Iv7&mN4cE;jGB*x>ch)bAA2XrqgRH!|n3u2Osx_=%qriw%B-^?4#z(V`(gbR$9j zl^?~kV0(w+moaoFHOlwS#7=64Fj!EC_Te!+p45($Wk)-y6Wpf1p@@D@5q(+;B^TkB z>Ix}RU|JS>sWOs>DX7l7nGc|k;tjht7N+6XYrqb}=Ndf2hBW%RzH&&TuW|lRXDr-E zFAfYlI~KkH3O~eQ)HK{xguf{a+hXC}>{)f0Mh9IE?`K{^?LeSPaT*KDEEsYzIAy5( zr12PjhD^sv%UsQ-A&uZaw9JAb3*1yKzUM7A7ug8q5=HYIo-0-K|4WPn3CqUA!4wlh}=F^>&kuJqGrLq8V7NzEO+ zdf9&jEld(r;zR))9JoHHF^*NCr3Y5}{+*-XhlWV^qx5M<(f#ZT1g;Z-rx*qh2!0Vx zK^$DtSTA$6kY&#bfoDKYJ(HCv@R{O59E{BsPqivz&GsvBOng(@*|C$u@S!J~MjHh> zSrtfCT5<8b7k36H_lnC#No;7SV+7qA45hA9IgCj$6klytQi{!T=ynLzU?8X(i=k?P z8(kR|5%+^7v0-)MjY-$WhRuWr%OV=q3T{~x!;n=XX;!P`+ zv0)HeUNnjgb6=Q>+nZrW+?KE5Y0t1@Fe~&ZP{o5e>=Wj)M;UaL_DOoccR8;9fB)6d4gKPoZVmf6DQxT>AH2vGM~@u#|0h1l&@d;bXup zb>?eO)k96O~*fKwia*iy_>Xm}0C|(XDP94$4w$j(J^Mw$tZFbk$9=_LcH2FvK5N&;4r4lNPG*_+qC12Oc(KlZ=lERAryL`Fu~%X zSG*Dw9Jyc2{ou%hVm}FvJmkjd<&=>}U{l!K1E<%cjVU1hNrq)HoEkw_>5WxJrl*bs zyT!sA!1OuUhc^75I$dx?a0p<-QGz*WX$DD>lEFNjh&wo-pA;u>TnB5KqnxMRS^+I(9#m} z0zAQ-JK*`*Xy_~dRQ0JiXu`SQm=r2&i^a*WWhCM>2`wWLpHzgKo#o=h?}WZ3_xL7o zH4>xCS;-iQ(UpE zd&5oRR;F?^t__|a5{Vzk^TJKAs=qkTsk#6Hy-pn;H3LcGp8*@=k3hRex}^U zOR@DOl|MBLYDgb5TXC8NdL5KMu@oS4aOnCg(9-o&Bu2h#4W1UfBv#cUo}%MHPV~64 zDsQjM>9Qh~r(@)7l{o ziOkI~G(og5W2(_c0nfPDja-3Qbw;b3JiD~K;fz(ls$Y1hrotKNB7B3vd1j0q?B~XQC=8da@f>y56d!^wx+PC%Tpg5J&GEC!I?foCOT&%%MV&gM*h4IMHwi|p7 z1+~3=_W4#f-GmpC+dJ?F*0$P(oTi-3{YP}8jegfIX6{fMPn{K~>wKZR1>V8j!CBYe zh?Y%%v)~u1fh#!LPv$seLQmb5z+*~?mYp`BicdQ1CT^xb9Go*jJh&uw&TXt|csS=S z<_^x7D$2vTG%~aU8oOUzLR9Dr35YH~Q9K#**;e;2UIpDkj{{?pXrlvPoQIRn>zH51 zyoTC=fw#;q*(iEQm{Ek6$ne4AWNiY1mdghW-UJ z4c^6^hS#G1<%r<8&EVoFM_<0Eh`~~DOSQg?-NIHahi0iBxCd<{>i7~pKM+uXog3^1 zUwIw80f#Y)Q!3ol(Sdj|Xv!>PFa!#+gm^$d;n6UR>S9t7@`Zd zu1>)XPv8z5W`=vf^oh|J$Gz_ZICP#-2 z&W@%U(@go9iub_b9SUtzMIhL!ILdB~eGI1dK$m8aF$PoLx5uxi0_h#(e$>ww924CL zT#xy08~pmm4M&`4ecs@8Zt9z*!%JEGHH;+ww9pp&S`quNnT6v78wMkf6aPC@tbyi} z-XRXuFwLHK!*bH6rx~iFDnOUvs2XjIWJ8a^mHzt%SNaF+fiG#&^eMg?`b!pR0^;oG zl1_tj;7c|cob{(A4bJ-0HW<8Kyc`&geSN4QV1uuZv6uSm7a96+L>2ma+ThC1^9E=A z>0<)r{xM^N>F${q;4R|QXWH#9U25!m-8> zPC@z?PHJi>M|5t$!5ok91A_!kmVJx9*IevUW9b3*yfpm|$1ZcPo`)xrmqpN`O-zX? ze-c-?iFtS;d08AyP2Qi{B(G*U<*myTEU#m^W5~N%UeEGIzx-12NB)~wp76^X^DJ*> zd5d3uS(fFkEKmC7GZQRtXL-smzoLfaoh(oL<+#q_2l;ieyxWlHSiY6z8NYmXBg=bO zo;Bp;kNo$tJm;4;#nC4DK9=VVc?-+?gj~FlRUeGf2`{h?A zSYFNY8beO$AiWuNEO-3!Ih@{%dX_i(<@o1M_>IkS)MlJIhJ>^yxT9oD#7xtEYBG7Jj;7np7qPGPO`k0?la*Emvsxg7q>$(?3CkKCcWmsd#lm&g6``J_+sYL?gd z<=@J%ypH9LUw&N%ZL+Utc_YGOhgZ7~Nrk+L<;`gJ;^5thq(a`p@+6u!;V|XxEboL& z>)(xN3i~w6y9{}b<=rgb>X+Y4V#+_m@*cmuh3Y}_EXyf(Eq+UezpXzxeyg zd7~6J`Nel6&?f7I6gL~S-TNO7HCyn;J+g(JoFesM~P8>P6(FTTHqohPKY*$}5# z+#Nhxmki&r`AF zMvChUafZc?6xaL3Kg+QgZ* zoPv1?_W}lgopAdWluj)BH4A4)I=)jn+@1Oz82mafz08gawuIPk63l7@dy-hDhM6PS z+r(bXGHVoU;0>ii`u)}&enaV*WiO{#)FMRJLsZriXO-7xFvO;z@WMzLyFv|(HMX(&RykL8Yy^)lxDd5)JgqjS$ z36B35cdKuL<3HwE7?;8&5SC>V3~MBOlHi}>3>^vI7OReP0=HQ{SaReHZX=j?}y|BH>g48yUtWTml$;C*ih#7Xf$W zS?EaN+hp8B&2?@_5xHrj~_{Zj?c|Bn8K*Vib2;X^Sk&?n!$>L~& zEz%Mm6|jY2w}j(vAWe@NU2$K7QJH3j!XCurM!$dv7TX59$|SIw#;} z7Ez@Z5$%_kx^p6uP8GDIhG|^VC4vrAv_{e=K}-6TCETrxN07qq0`D97#k9t9YsT&1P>s4$AB*{EC6af>PJXcZtM z>1;`ptecheZb7REV%wdQlXMGcNx!O;+q0O$(%(8s{EdK{UqXdjLIK9cnMNd?DrmLC zG%o29K|iZ>Yb1SA(9fk=*OByX(2{-=9CzOm3Ogag;)E2R*GgeOpJLh~>Ggt6j5AG2 z>Pnhnnv(QYK_}&zrX@WJTGH>_gd4h*!q&C0I3vZgZ>6wbbeLu(y<5;PrJ3d=-6H5$ zl1%fG?gcIB_tm7^Cjxw(1I&$d+=gmSy^Z{TJtJ-A#syp=;B<#!jet)IcxfX;N5HoQ z6tB-2*XAR2mSz1Jv+TBA>nxhZ^^S}i-gw$1{Y`D)*rz4k~9lb zQur!a-0Cn)OL$a3<)&N0ad$!UjuzI;NH|--9K)=HcLN6ROuC(SA>dsZ7UrdJFIg;2 zN_cg^&HRuG^+UjA35F2~rxLuIv$#4g;Sz%FS=OwP@JYbnkGtKiKSaRgH7snD!huU+ zvDRUjknlW$k1NojN6I@RW3+(Eggj)cE>*H?Ej}UN!BZY~8n_otSS_X>^Nrn*#rxN@HF}O*@ zC0rt4hGC6_PZHdeWavovHehg5+TFJd0XHd&gcP24H!Pl27A+E9FJPM8BqekOROTrO zUllONnrR7-0^+l_Zm1mrH^*6+k;2*S2)H@PFe~BR0%jTJB-}#q{~`?Y67B^I{-)9G zBi}D1r0|+Z$B$9GsXvCn3rS{i!Iluqu;*)P1bdR$i*eR-1bbVsMrMtI4ZH`jUTkqI z?m?^vG&k#H(t@NYS{X*r_p zbXZs;g-?>jt{g*0!nXf}csdttkpHK#5aQ{Hib-m|&x{q(=oU zRXymIblm+EwzQjdGm_30bWo0IR?@pcOM>A>xAT4qJ0!*8ycF*hMnm$F&JVbml~lNu z6d+0v<(wapbgG~+r5l%YiJ(JkShq&fCqaY3q3)KIr4t7QhbfyzDINF#`5)o1O+wQ1 zB<*I}BI)&lj%;L_l+=|}`AtdsDriaY)P&pn0Co1%EE{!8@winKc2o<~jHI&#JuSjC zE9u>mHZsjgx&<^CJk5P|6?H3KBcJUQ5?Ng@Dfi@CNl9Hn zDGQ;SlJr$cQ%uv69tAB4em3QXTnhWyEQ>QzJlmzP<0DM7lHM(8nrTkbErNb7&NMIS zUeJ=@goxWG0!(nE__|0(C(1gtll)KMq^^q#xJ1GXYt{((WGD8933+CYU~dzfm}b@} z*uaOdq1E6r@DMh%nr@c02-)?JmDOaKB?WVdO-eFL3HGXBX=Z7`juJa3&a7LoajOyQ zyog)38nNmemSu(PZpg~&RK7XEwh;TW$|*0{Ucp%J`hc5wm}c9a2Z$w-(OeRB&EkQagi&q{tr$l#<0M|Z^iyn-79-c z6!=!=O$Mg~NuLtahPI-YdAq^)NuKP|`FwmOU4{jefad5_c9f(9bl%7M89yIIJw-xE zN=(xqRqdux>8eqVlrN{VCci(#yvdEch!I=R2l88<^7HYEcl!A^v#g)?b5Fm^&%Hdl1uu+j6FH{96iDlMHFbn| z#?SAMqfNZW&u3RKr^GZr_mE%G@74LtKwvgyLV}zw2n0Ug$b6rltDSs#-p@a){NNwx zP-X8Wb1i}DCIaEuy%9g3pm>F!SI5yN{c3|#KE!Jbo@HJq_~*Q}@vI8q7zU(Ij__R) zB4N_ACEV=iUcxPY?j@Y`^NrnTQ=E1`UlC!R65Jh@DZ>Y2@9p$!-PFZe-5tNc=P&Nv zYKSu|&ieVY4)c9tz0}^D_siAj-rMKr)gfuOBIKqJuWdy&+J)Psz(8uFGb?Iv(uy^< znRz|Vx<2*}q2Gv;uAgL{z**N%Gbexg&No&GS|QL4cCtYdXFUKFiW2R_Nz)HiFi+#G z>r(+qpX@w+tj`eEh!A9O(haDhWYCL~X8`>a^Bm5a{#+FwV2 z`zT}0pfp69;BlOEgGT0cIP3ZsF?ZbjU1jBM_ca;vr7Tb2to!4R+}CR8zs&kcL%*AO zC(c^@vi{7|IO{_?F3SQk)C_Qe#t%BU6(>ERJae+s^{bip`t`@sTqHka=jqQ61O_Kr z(1)`Ypqd?}Lb?I;DM2_&MGSookcxwQ0icgXw;tc(m;ffTI=}d&ICBSQJ$x(kMw~Tw zCpEe0_4t=$Yr9KBQ&P=_FvUhKIP1>3m?v@8oxSeXJOyVHhn9sZQ=NwJI2)y1=kBud z%2c;s9;Tj9kG8tb23%!RJ%*g8QY!0qzg}7%OXUnX{v{Ud+^7Fg8j7X*{KCjZZX*dN z{t?3aBYxqKp>C3dquwH6wIOVByGb~GTWP5Be#a25K^r;WU+*TjBj@`QhCI*mW;eN) zZc9LXZJDB;H>L6F{gTJ z`r`>x?!7qa`l?Sk@RGnF?^-v$!p&maE{l?Y4Dk)LFCpmxPb2Br7ztNK+{^*Ma|LW> zSnW1u(EXKlXltQj8(8kR-Bg~HjfR}dx3bC2? zFm%5hD;r+9vd^$tB*hN|+{_gS`9Q>wQwm7=feN?fGLlyt^7mO@zRPMUr>^@lk1L)XtS z&)}@M1X5GO~*^elg!c@AeSz=R6sd7QNX!xg82(DiGi{;H6!|D8Z!_%s$o z41;>+ah&x4oy@Co)&nG%*Ws+|XPLX7zKgeyuWIy*D@4b`u~pc2c45-3YBuC5T#K7N ziiI|7BUWEUo_(g=ZfwAntGfI~r`*o+Za2FXAC6qrW5~C%oO09p@Oi=*gjG45v_6~~ zN1OOQH}xMZ%m=Bd%c)b4KN!ME_g9B6P(^-~6)dkdkS8-KR6d`1;-TOAPV{wCHC2**0eUh`K)y(AvTNsF)kHq=o= z`HhHmIDYv=>OR>ulKkXYN5YV&+z8gZ8~$h6Kv*XYX*b$ronr54L!M=MH+#<*^1Pc> z-Vr^A5Qx3aubJguA4nKtB<4|>#O6V@?xB zo1W@vU?=(2culWc^BihC>c!H~oK7mKF05x~y?*Wm$@#e#WS^g(h3A-FkcS}i1!*P_ zjy)9ea~0&Fh@Yz<4^{a2S#@q+1)29yjbB*Pjy46U^K&nV zZFwHA*q`=d>A-ob<9^{;t!N{O)zyBkI%Slg5 z+KZF$b1zP_pVzi`{MzeF(l4u_K2Q$re(uFc`MDRP)6Z+SqD_9fxG&v)c}+dbNzc}o zjGudPdi=Z=Hz$S8#X0$1ZeSYqBChzB7kUl>@y8>$_ZHm(@;xs(m;+NO`d^qoyd-d&;e#Mhyi{CXNzuly2>32;9`5pe1xL>R`)itDM zb64Z%lW>FlLg~cdSzT`S1^h`vb!SbJp_fD(-B}}sad@=FFFp&GU_2o&n3K8|eiBuk z%*Ch;7ncT2TuXyU;xtYg_p<476L@kPTq6c)xO+5HI;85e6>QYwH#$4V9M7WhQn@?! z#nMRSXNggS98Ow<@oBda(`bfgWDJw~)5sbcPR&kb_6V@fCy^fFJc2v3-(ut2`=XZV zBgUYpppVqZOv_&?jkv%03tlvO#PPcwpLHF)G}54UlSdl;a`pF$M-qNMz6otgr`gXx z8*tO`=Z)7Rt$z7Aw&NA5Y!;ZJ(^)HuSJ_@aKevzdpH5$y zgOoIZHXT5ZTrOsYw!{J2SSURdC}R-}s1S-usEDH?1O$zuP5^~?eMRrz*}3<6P6qjt}6cqM&Pq4(5gTD1Jif3cSCCLq{4-rRJn7%G^xoa)sjq2@!2l z*J%Ss@UN(H9c^H25L6D>NRrqbAlXs2r_bV7~=Diy}tlyFJ2w zpl{|tgo~+axkmG(qayVH+*jsZo9ltkfe*W;YqVI}fjkxK_{B~i=IW?b1L{Lz@kXPi zGg3Wg=p{r4wV>bQ@~!7Noko9nQ1_~6@RTR7%Dz|P@(26&208yrW)Jm^_-2`9alzhe+H9_pJup+`74h+cZ=xa2xWwK7#%D~Q%`)dnk! zwnH1ZuosrK0;k5<^@vRm(Rd{za9~A>8=I3EdziX~^nb;$$UlPNH~(R*W`Ek)H#N4x zXbMCk2aW#FyF53D8kdPz5m`|*_=ISHU!VrUin75Y>pNQExQgHk{MjYcYH&rB^I-*z zmVv*SM|6LwrYxGG=<{vh6d;fDa~q-tUi|3eR%CERhm)$%D*@|9X(8BvuzspU#I)Fz z82#9(3|?t-In|U`k|E8h`RFDa(652|>S<0V+rri9VNRn7S|~jnj8_^>xPbEHmA@aH z5xdfCLi|Z3Onu8k?}~=~gw&_nF|Q^5Ax(N^h0CKFWt6ka&no8^P@en@*0aS|HaH*p z*ZdINZ0eM-ThtX?$dg?UiRM4zmTC3P{3NLn-7#s2cR7w~6k+xxwQ~F+!ubUx4|{*0 zuxTf`AOEq$ZKRqThh-(666MD*7H2+&?bh6e1RbQB@L*Ipk7+UdLx%H*<)t2OEW_CJ z5l*9byHM{ROiHl==V{phZyn}JzU-Shqr$~P??_Dd&Ox54UgdZgsv5@+Ye{)rbf&6{ z$5C~4-SiJcYR2JP1MgWa|MdVBg6>30JA5Toq3#Ei>?cS`@>fNJZRk}AE;s0i;u9Ew znZTi|NL(xXaBMD~=$k86-`*DyFFny0T`*XZlBA(Ys;XX<<@n(RDIW|%vE)h2(uXS} zL^2~H|0H=`l}hp${wkNt9WLW{m46H`CU5MU-gkIM>WDq?%qiw=gtKb$y~^YIv!hbB z&GE1j9Z|;1&)%zh{HXO`9pQ4y?$uFIq;vQCP*^y;ueQ1HLI-)Y8@}J6$x$4z2@zOm zOVB~8MPPPbWHxF2{Awf23-eMh7tFL*j~MzCekzRQxZN7FTjcyg7kSbv2TsoTOJ8(I zh3RS{nK9%^n3_q$(Nmqjp!pWIB;N>(eFw(+)rRzHA~mIjMf{MuUSp5*N02QltP>cU zGTs+GNf}#7oNlZZ2(L66Of~GvD3?DXCFN}qeG1b?lGAftQ69&%p;~KYn)5U?!COb< zq?wFw=EL^lD@jcE7JsDXDXr=&^PE4TEX@{uv*PlnFikAXNRUX)7~7+!tM{z-vfB zD{-M0Sh&V$Gqv-&Cc)+BN5-DUc5)$U!O?4sHk*@@IHh_qw#1D#Oxhv`d;Ouk4A+~3 z<>~3ZnV<5cdd{FpoZJ}U_##{4c&>u_K#9|H8`CjQe}b*fk!P!^Xg)!b3Y9gU9x6%dW+u3RaKs zqONeZ;G7O-@|ZnG537;Dv{*ICEr`tgt(f)Z4f|;9+J-;1 z4qn?tUJFv_)wqFUL$_5su)3DK)bv6xIvhWe@(9v(=%6pqh7eBlD<`gta^Z!xu%D-1 zYD=Xg=c$AEybQ&4Y0hKfDT22aJHV;Xj9;j^)TtM+*X1C^>L5H{y)4xWfqIdP&231! z#BofE&I?+9xz1>)#dWEN%Ptg(YhFNmgvM~(h)3zzb!43T)PhlKaa$_m1p$-?JT5ku z@>F9I)70Tp>aV&_UCtks2=uOx2qZ1c@hi`ErzbQk=Kl>w!S{e@uP;NUOF(g zgN!Y1N^sc!MnfF%B5lyK5~TG1vYg}iQ3WZV4=i8)B6^W}biBUEg;D3)i`0uK7Kq99 z)SRpk;eoe~s!6`;8=X+|_W`l%>s%ba?cuznh46Z+kY?^ERg4$-cFjxhO+7qZ-{Hbo zc3LnNej|26k9;BUGNLj&A2@VF)KE%DoKmf1RlytVpzqv}UJA-b-|l_8*;+#gbcEu`p}5$!t;bCEu(#rA>_@qj5upE1}{=CffM23JM6+yJuFdsam`e)PC-p+BS!JXYD9S9MsGxBWSava^seuV;-0#14j&L2H4@g~Qy<;XxUd}Lika#}+kQ=2#a7!sepq-N`}CDNoW458`FY~eSNmozSBD;}^PE=gxVrEmc#-2rjv!CPl{k*} zNWF$>A>=EZUxFV-1;14FgVj~etL@k78po41@>E^}i5B;xQ=;+Ou8sWa7N?g~MCY|& zBX7U1CYIG*E`+|E0l8eo;Km5&RbRf*XmeGE8xve!Ejc&Z9LM&$hI0BB0j9d#nBx2( zUSNS=s_J^b8+>SInDf|oX5L1ZkxhS7mecCY=cXLTsY{Sq)%9=6a~`p;fww*l z*soSe)c%eqfHD_TBk`sR$KiGKA9!$6J@TdxG_5pS<9eTNN*wRpP@MSgKX3^^jh35Q zT=*yzvT=^1ZY~P%|8!Iuqu6LoMw=q=)>5L;WNU)aDyD45w-ZaH(i(iZghwDTk3cox z*Vv-G05_S|;31t37REsKhZ+v7X~kfLZEV+8*fkl>FU=!Q#pi8fYfTb)RV&F z!2n(31v}|AM&J*^o7*lLMm>nFp$63Kpx3y>ALIn~ZjNw%FezH#LqBe&2x$7pMWtR! zI6Lvkkq+Fr+2LXb;k%A^Fl3b*H)lAXB)1Weo3k80C@0F$3tyGpJi>YOs|I-MIKoN4 z6u40irmF*X;*I*V6Y&!HW|u35j#N30cw}}`Jc_`{V4d@bM-lw4cr-bGTmyO1!$TtC z5p5f^*yCN?fl|ZkW}`KZO9t9&Dbb>g;pMywuR@-puJH&%9=!D#Y8{lmHW)0iwP`MQ z+_-3w9aa9?VS_J@{Sz-$)x@_pYtqP*`5ebpH(xu#@y}468i$VD%63ZmDwo_y+PMUk{3-tX>?vKyl&Ct6N%}4=Xdy@j02_;(Ji* z_%2|wjvqooFi)kdW?c>PbtI+Xs_oWA3_MSQ(_-tQ97kz2ly*W&(wHN9t(ns)t69b1 zi%!6WXcfA34(CsxJXs&+I69sKJ?n%K$>)6Yqmurv! zzP>)m@y}9+Ao+AK9bPukiuS9pt{>*Yh)E5F@8Yutk0UbTRSedTa2_#;PC^VmTL4al z26J$1eTmDVS2~dEKcOb&DxAlHm}h*I^CvjM1^@A|(sj;%wt+mA@85)otsm!fsya3q zrK_#@`ZlKraI8&yib^FbUC!fiDM!3o&g&7*Q%?YIWeA6U-4?aU7@A2ghV`{UX4KJD zJv&GsF$Blh$udavUEj1gzQu8vk6L7&+5}C1YdbJcSxx;wygi3laGHM`iE3mr zD_oEZ)SZdj5(aOR!nD|JM$4!J*xS#C* zLk!{y%SWiYQ4mPiXo!P7Q3Jm~HOOt_5Yv2C^XF|I$4{a>+3Wg?M(lRVYI;XCgtI%I zk7wgS59v^bVgdQvZ7z2p!Gs%)aePa-(3=(Nr42pt=q zQ)(Le)8|sMm_o3|oi)vh4jt8yV2LZub|qfncqT6zFxG#dGFIjM2@%l&zaaFv&iMm} zrQHU{QzH^@`jrqT@1b?P+dVG)xtbL2iq;<1%p)ns;vUd+|JJOs#5Vs7#TdEFs$cDHh%jM7zEy(qLJ~cMon%j%+k(wTKj~von=3TCK zARe^ApY+)laCDP9sPcH%cn{b4?-QgW1RDF(~hA!pO;a-Bk10vcaoY` zuIf5>en^<_OmKPS=bbjk56mHtdfjP+{j-k5Q%Ld0lwXTkePNL9O#5K?V&_0~YW(Dj zr7Cx4&;~^WYyTuf+&@~0^0=j2HNdI^rJwdqeb$6>EbeuVZ?oDcQV9H-+} zs^44}IF)C#31Z#>Z=Dj6d``Ft?7l~k)v7~ZizHwsX-lyp=iy!v{L(>J@@38s)FfUp zaH>AJ<#HVMYOuGfx}>l96IQp*aqJj9@^b*NZ@0;Le9ab}MfGS&e%#=3iU&U2cKoT$ z`BPk}*A-qrwjDjeMVghftmvmsk#%fDxsDo(4XUeFhip2q)ewt5iXXvhP*$g@2@smb zuqf{bmm67wFG+qR7zK@j!B-_;min&2Hzki&u)*Wf7x8MK+?C}#%5}ku6ZW?vvAae%iBZ%7X`M<&5v;q4!LP^MRpxT1HYD## zzGm>A>ON+Ab?eenhzFoYV8jYGq=}Qp3zkJ6exsV6~+G*{Cl*@s55BjkT;G&AHsp z?7GB_I3S*R=vm9ElE*SfZnU`ivXp2+tUomG8GLpOM~u7Z4yRE{ijE*pivUM3?v{(* zSvEGrr&3u2n&FgHx!VSty_E3&4KsM~Hf-=7hl{HR;CnJAE>i!7=bA;bd)zZ(@HX;f zzF^>4iI@Bb>Y;neoL7s)Jr$0BF)#J1fxES!mG7x@vC!S-hv4HJU(^zr{jC`jl45j! zYbNdRYRHBMG51oCv_?npJn+^R+rUw~d-2AXrj2`3T<%Lb$vcwI7<^Ikc$D$=sdid9 zUvecccYgPl4Zb0H*YEVB_f`$QCV5JAyDf&;Ld9p?fJfTA{P^QnNG@$1%XubF0i1>D#*=#=mTjkkVsgdCtN!%X%1cs#g^5wn} z&d;F|sH8l{Rp-2~$njHZq6mB8RC8aM^IxW#l07Wlw94F9Gk8z(!BixcBr$KND4e83 zO{BHPmpc;oIF3W1d{TFU8InSB|7;6?=8%L4#9=8Kd$8F? zR=4R&-e}mxUD1KNOVzu82S`lQQ_*=K!g1BNABY+_Zh+0v`sM>R=g%N{`1wG}Un<1O zb7*FBBuJ@VxGjn>=C6ZD`_Hh!ld{oNv<`x|&d5tXcw;AK%!P3^!#q$1sTrpykGW{z zTuCaqoS)y4c$MS1h{!{4mos(F!x|o$!C{^_IfX}`Tw8)A-v@Dd%GzVO8q*I} zxCM2=`azfDYB7GW%JJnk@>F7t<9N^JrKl~7l5cQ+IXwKN6@FI#V9TKE!uceQiZS8m zKM6Bopt@WRQ;-Wjy!!D_g!4Jd!@Y;7(X_yyVIxm?0*QvJz&>P)6y5N92zQwe_BYMm z5!gD+8?u7m_FDYVFjq|4$dkdWffG#l2*;^64WT!EB`^7+Uy!&TC48KMK{{owqdL<= zmEZ~DA(!(QcO9~+de1|(;474e>Rb+G+XqwG4d7Hx%P)IioQtV`^N`2!uM|ZQ>iu6) zZgw~i^EEPmW)wKgKOFG~O6+0EYq4IAUCbe{vy9v$Ih*sRWrcIdt}gO$iqmJ}<-;N9 zB4^@_AIyZ4`ol&GoLPh(nIG}pSp0AvSny^dzaimw{lN`3vYMRoZv%xz!{J}%Qy6(|z@(n$^yxT}`IP3~ zhGEXby&CbMdsGe0JlylZTW87YZOHrX^=~L}IrRo(Loql5*ihoU+T3g?b6oY54X%OX zwK694{y8b&RIeK6aZ=TyNq@FGb{HBxEWX9X)Y;#L@u0)aI}8I{T^8CvG1Kartcx6s z4XLKw(B=H>I`Z)4(Fn&8qcZfYv&cu{u^=tP(^!&=sde#Ds*+YLCdCfbL5+j&B9+y;m%17HAr#6N8aHu_M#D7t03=6xZx=br7 zulpZ?Cu?<((6YHrY6Gfb%LqEA(K3uJP{#!=2Vz}hXz|x-{rg-`K>C)G4gBB8~qx|Q@PYV zb-T92n+D#NIF+Z#4-iat#yPGQiI&H4DKCz3tm)x9tyYH%(WcO$`Nahebp6-JYujbvyI-DQq5z(X6{PH+B-5HP$ z$bQw6ACGb#^G+VTrOxmkPX=c)E03aWmrd5D#U6K%Xf;I4TVzzl{PB#*j~xx0YEpk3 z1Cx&YA2*s{HXbD**Nf4ZLmD>0<3KS|>Ku=EIIcqd1Yo^xsCx~@ zma7r}MAYDIQkWKdf>JFeN6KJ4k>t3VT%RCblgH_9bP0l?hQSjK=RjD{+lFEJ{t{An+@n$-|R@f6Fe$C(M4X1 zu`2gT64P+?%Ie7o$5Tnsf!%&p?vn}5qg;C!<({1)gVSP9ri6DaO-;ktjf90cTb0PhIu}DJEtr`_g;OC-PNzy^OZB*oa~g%Dz*}c`q(yv2mF5YUpgtaQs_j zhvaiXpT6ukY_`;K-Nrl@R()$Dg-Yvl2jd7Hg@+rvjU~<>G9oFeD8!Mcj?IKT3 z$cwZ~J_9GzBD1m1h1HgSV}s*^c-;OBoKWk?#un%2HiQe_I%EVm73Kw(JU5}RaJAUj zemr!(t!Z^XJ2a4vd4RDv#7I;Sb|U|Jj8WCZ*i zPx1|>`aBpgH{+y1~3ohXdZKAxUul)H-p5y1*f!<$AzVkzWDI2^ad7~Gd z+mJYJ%AWYaJ4JNC8nF8D(7#ZvHE+&s3-3f6VWBTaPf{D8zZfp#eu4vXmbzCkP9`WX)WVu?e3R8;^2Y4Z`sR$McjY`D8E%H=U%OHV8}`!s7jtti;DNQf1g+M%nXEaU+oVj^xMv$_$Qs z$ZIkBmLvH#$1#R#pT`V#F40u)F6Y$~##2OV_Rgj}S|WLtAO z-!pbHipOWU?^X7DRW!g_=TY3LI_Mm@CLsSj^j2Ac`>J>SDNLrMk=Rfr$-DTh9a`W-2Ht}i#db-AW zj7xhN?0maNWR_tG`Zjje$osF&hn{Y8;jo5AQ{^E>&Og%=JRd(3;d=R`@L)9DqdjA` z5cb-qY0qBIP^7~M)92sPJ_Sj`FQ9U$T>PfoGHd1;!<<$<%@YBW56uF#wbbO}7@g%8Jc@>T?>>2x_Hn%@h<@5zbK`r+SzX*TEmaP&izZ83tLEE<1e&HVOnfUusMirNpT*tehvEJ zQnSV3JoY^vc)vG|Zpm#EI9OS5FLE3O*hWCkoY_ zwiHF?tLXb%D*jA2y2a%N)KSG2qhZuo+EU~4vq_&EY#`AbQRnGfnjBY86I&<{_`YY$ zm+^g%Iw#mN&V>hCW2e(3;{v8K+QISGywk1dr`46+EnTjo&cdE09o-?DfN8O3qa0r- zes#KqOOZH9L|Nf=xMx#bjGhOHSN=ac%=r`XGBSr&r*os;XMq4a;JaC8^XIRtK>(FN#Tqj!* z&KaB=%f{E6p1o zTaGX!fWoEcDAioLuq{%{Rh#%a#|QBINc!I;n)qfgXKig6aw$=U z+>lz_w|bmc$9!9j*2TMy2K0hCVr!Qx;m1@uApK8Mz7FH+%;Nb3ms1Pg^EStEG?Rf| zcm(%6RZ{OdZBYb2VYayO>(J`NE87`*g$LF&g{~px^F?oK(kExjP4Lnd3C@=&T zkZ5ILA#}d6Yn^<)#A&R9`EMZ3->*t_H)yBlDX*I$AIN;2=#97}&71WgVe1{vsNGqd|A@$nr1=7`gQ+h9u6B>@gmIn0tmr37WNN^rA zNJn@6g(T;d^Dm@0evyqlV(|hFYv?-u3mJniN+U@;tgp~87J-e0J4{GzhRe+$m3@%e($aAJS~bSM%;f6-u9>ywZ9H? zVYuHxA=VG_QYq&vnZIJAM#W!AOpEGyNnxK0^`ufS`sx!(!YyM~IQd+Pf+tN^xGst= zlI{;&$zvx9f2TLN*tZ<+ z7bAWTi@g}-azC(zn@8iTGG4Sfk1Djli`8X(!}(&0ljpf(=b`y7ssTpFd(q*v^5I3J zMSe(mlFtUc{;c!x;^YUm1V@l+@mIa}#RA7MBpWDvm*XYQA37pB;C;t?U#y67o-V|k zZ|$-4YzLB5e3fgc1>i-hj^=@SID4_das2j0@q8LLE#PF2QcVvhv^C;q*CpTPJT*J` za9i?Xm-9cQ-UPcZMMUG<=rvJJW7s<1ruEE~Vm9a1a{W?@<3Fql7kc}t7Jtd%{AuIJ zQ?bKAH{0}W^lD^ zys7gNRaz6q*Xd=H&_9Qomy8*WMyoUN>a^>nI@hPsPaghgSn9X@V2)BHwPJom^&;~g z$JIg5OGewNz12${F0b}LFLgPdBz@R_nG%${pyvSkS5J@Hjl3K|MsrB5^e-E&j{4Lt zM14jHCxb~*{tj;S8I7#gkeAckEEdQp#An%3JHzQ8;VRvC@TN%hjhAzrUnb7|j+GEM zmaVCaU(Rz*b&;0~99IMQM0 zwk^TM5T7z^_p1luZOISt4e;Siye-XnH4|?m-?ZYf4YDtSp7MEH*5r{V_i`LZd@|4r z+iRQAp12rP1aGPMZY%oni)|}$J998wLoN)@whHGjCV#2?njao9^9S0cnr#g(jGr%e zet<$%58sAUiI3wawYH5La=7pSxp23+t<8CKYM1O>OgIYvTaSqT2oqd{ixumVj&eMi zAN!#-vyVtp4n~xi_e1m?6^_59xC*XU=6)!53e*4QaB`0L73^7;5KIQKWq~)*9CBJq z7R4Ko3YXNs84aR3z~2hNl6t_8bazVJ7Tn4FNbR`(W;6++Qv_*ULOA(@!$|luouZ-n zgI%2mv7t*yio}|nzc?%L7RO;eI!fj{lE)~b;8T{Fmvooo$-Kyq?uz~^k)XOON44s{ zlHfY1ZVN^F`?SGVlAKh_<|`?VU(z#H)H?1f4yP|AGpP0}IJzw&I#gTD{UR>8L4AQ* ztX~=7yqYdv$#eYDGV)}$N&I?{eKDpa z+|s@nqeVT?zS81i*d7(ZFTWJ9@0y21^T`hcx!mEn>Hx18EvTygD#Ud=mo|iVF<$ba zV?{3^f0`sPE%quEpp}Qi7>9UO=U3C5$1ITtAGG$X!v>j0o{VNVJ{#X>DW%w}IZj?u z6)jdG8PPmSw#F`1L4LK!Icy$NAj1jp)iURQOpcI4*frtcZ}F>D&Z`!GwZ`!QQX{=O z$1hEb2FeRJtFJaWkKxw=Z~fQI^s(-v@G~G|I1^7wOKl0EI+yAvZ z*T)MY7rb<`$jP6iMT?YG=X|Zqc^nj8Ms=X^MRlmkCH^u@FRCeCGeV9jDR&vBBwOk< zgDDAyqWwRi&Pj&Gk!W4!;;d+(ps-uK*5>?AC{KD_5xpGK3*|I*j1l{CRO6CrAojY^ z78tV`@S*wFZLWWrbnEq$Z(gjw9QUe721UN^AkoVDNmY24TOa#mhQq3vUe9v;GHMPo zgXW^0;_C&2S1#iS2{jYfl(6DoR+maH7sj(htAu(SIxhJd=hdqBdP6=G{uD7EBqQWO z%Mfmh+)v?=>Ughv29J|H@cx^v!Ph$mDI4VVF30Iu4@$l0bsePPhUkriKVEv@2(|}{ z-$-&jRpU2O99J9CH_{x(=*s*D>|fRdj>^4((e~5-bKR*yY$!B8!p*4IypiWPhPwy7 za8SKbTp1L0G3M=T#SaqsH;e$v)K)t%^E|Ykr0< zqIP3%w74(|X`zs?)!*M(4brYa50RaaxzBTdPnCyJaWJc{F;N zjH-%v0f9~(8+Rsc3ot^2lHBIgp-$fq6l(G z&1;qV|hmQuUx89zk|+f`j|AV#Y76>Hf2LtW)QjDAD;P8aFJl$@#EE zqrFO$r!aWI)VlJQh?$yNI~{IBt?`}i*sb{cLvLbgFQd~(xYT9!v0rID;LQZ5(V8jZ z)tGoQ$$7M94m<_6Z+e<@7>Z`t;1jm=s?VxLq!vx_Z=0V zC~K43n?}5mLpw%ms`oE%rF{9r!izPbq4b9sa!h>eH`)^VR)*96fh>jht&yM~pYc zfDc!Uw{r%cmn9W^-xj}JG>p`#o zXH+inDbC~8e)PY=tMk@>IGkUGD^tWLTfj*_!+9K*<-z-};RpYb-Qgi_QxEi08;!8Z3kfJ3v%5wheV z(W7J|Pk4vpKgSX0?+|shrfw%OP48zp0;a{bM>vk1Z3cRNRC>3g%hE5>UG_WjK)SU( zWoX#QlO+dG z?ilX~E|JG}WVswpd&{t6%}Gi55r4D2ct@VgsS6rA3LFphiX6wUt~6kG=<8kJ=r}vd zoL3Xx4wvK0@VBv`N4KKvE70*ysevc`2A4y}%z(Gl7~j$I{qEf{?x(RG9+$`05=F>| z6XA{y=YQoOk8-+^F&8(#qnuT((@k((wNBUOxT;+@W#BF3sg!hZm4AtgrHih$#=65? z677>xUi~?WG1ow`jB=e&??gGS-deqr;5hB@uiW)2^qmx^e}#4M%HZsvhV&a{8Mb#aTrP<$)$g4g60I&O zUhf#qrKXK{@?3uZGV)}n7_2Qz{$NEH>`%cakVwsVXr#jNUpJ5^`C2gdykj(mI!}Lx z>{=YhJbabb9`AUZ#?Va>uZHeBU4zG?I{2_}?2K^!*KOqC?#_ho?%+!*XMV5ftuRxRxMI#m8|vQo~7`EM!`$8i_-m&?s9Grb1As+IRD)U=Ledi1>RC+zKf@lYfyoy*I*R;cMedi zcavNRMpM_&Owt5Se46v2p2Kl`3Y{Z8RgrfyoL7%J?`AoURxU$N{Be~P>3uivH)ZVI z0vDpG146SdC<7;_N}Qi9K3276E>{ELU6<3p@sKCAD#z8g2=7u0Ye5eKR_FL{dPK3R zjfi(CMw;G#k{v1syDhqE{I17&Jhgbx?;lWd9nN2bfqyOdQ**#!=bw~l_6KspA^uE? zA@NbpV?^h{hrd4m&m`y7X7`^dj(<5RT#@K8tyFq15`gP`&urt#%Xd4Rc;iAn#>91kZAu{u~zU z_0M*JBW~{*fx#l2CteM$_lgkH;)+)eF8J_D)_Y~nhkBLZMbf4l@NG*9GE`QT%O=}n ztI$Kjs?|BIuF$^M;5dC>0zK*>Ii$h&CGUB`!vZWuPYQ$5;hJg@e6P!KH6Q#7uwGd; zf&MEJ9FyJ$VLds~J zbLt|0Bg#40lO~(~$|+Wo(s`}~$B}a9TBJ1AkbEboW0#Aej;R`sOvgwa?!F)4yb9g> zQH~24>i3huocF#Fayr?7-O%Uv9r?-p`@`H2c61#G_U8-0$$>2A@lBz96L@t-`~C>$ zv5;iITOtRX^yOCUvYWJszF+1_q9AHFA?$P~F8035Nm%rJiw)ppF*rDgz2D?=2%WPA z<5RWt`xHX01ypms@BcxQiLv)Fo^g!a`@Vc(vU1I?=EK*DTp3QZVB8X2BBsTAFj=g} zHM1U@%N1IZPjVbLpi?*F6>476X*#UiYht{|At&|{U%eTxA#grF^|*LX#!z*oj?ogb zE5v(pT)skbxPbBf4 znqQ}Qyr<3u&O_h2dDqes?=f1iQiD8s?)jd_dfHr{CV;iOS~%WAjq$-2j^i&RwC;qb z6EJxpxbgUeC>Q)D-n+q&8m#dNHs`6!fw%rE0UQqDuXRvs$0j&jj=J0}nnM$erc(r@jnZ?UGUi%#(gd2Td2j64-u2!uC6c$cRoE{xat>&Vf9)WLzQ?`V~a z!Ox2%M z|1Z)XgC!-Wet$+OYh{Usg zVbgP*Mv$U)%)M$L^coGLg49dF)_y)?x2!Z<3>xghx;1@Bez+L#E%QR;7Z&l}3dix3 z;G*!bp?i%MqzMST_1~mNb!+-{7-(@bp^xJRj;G99Wvfk$_xe*GW}REn4^`9jcDc&` zAWJ1pjQV}5e`133|Jjhd?N|HY_{1a^P=+U_IQ~D>EM$1tH#|Bq!+AA9P0Vs!?v~;c za~zk)O7V%*yjpY5&LdCdP^#hb`6NEE=;MclFVN%zN_=98E64|w_{1{Du_KJ$jy98z z(D8{b=PyhP2mI2|ks9YiM;ZpM9B-O9&Zfggoamq3VIH37nPSLOy=5y;zQc;q(mEv; zpJ=r4d~whnR-!KxC`^h7?_P|rN%$?yKjO*32CT*H`*kUnNkxwTj+&9m zE&Jt8s0go#=&idG>%2Vuj!&v`oeON?(b9n(cJz;E+W9SMqsisyJ3sL1$7$n}#tptL z^*oNFOXQ(P_Fb}nWGaxGOou$1qQ;Kdm00Y;*c|((TFOT$)wS z`V(GesEAK?xa>t`pgz}k7LI;`On(iJ!P0H{XU00YBnY3*I?O7zXT$mnB!9;J{T?% zc#`tq^pGliDk*D?tvdBoo8zc#^d409iYRa@48M$UFCKCoE{07=9%AaRy2PhuIFC{3 zf>*B?;!|^+Kb_>s{0PVQ#}!}b&63aR@u>yQe_6bLk2O<0*2SlmI1TSpSQ@M=NR7<9 zf%jD|2Jg!d+ZCKT=T*y0ZE$=5A0k4p|8y#r%(plX?>pet2}FFV$N8`^+8hrXqr-94 z&!=`deualT%8x`v>rwalDe0oUc?cl&Vsx zEXqD#G5DtBYob9$=QYV_TY@-}1-LXa&Xra~B;Q4PsQfjf_a#5j8Th4o0jMMG0nw2XL@2hrF&t)g@zjBw8W+ z-yxz8;{ElCn&e9cPc@$5!hJM8&cVJ|lStsb+8gqUbz?s9c$s z{0Qd{xJu&0>*ZA>UN+=Ci4(8OHzZz1s+IqVgpZ439>LFHUD=jGI1_pjky!Z%+WQaD z0Nf4Vg8}T{jq;l1Kcpp}5=BxP+dxV=31&r&!0kR*l3-DIz9q`*mTHo(is(iviSjx> zE_v+Le4g?e?}rLKXt%D&gBMF$@Z_pwp!5-J&`9Ycl-HFql6OSQ=Z6ixAo-E8O{AVT z=!&FEBIWaCgKtQ_CUQPsH+WC-l%|l6=$P zsQ_|-c->xC;#8n+uO@NgHTjixfKN*x)#ckhJ{q4!0=mMmPsFD=NHvAIACWlmx_n;Z zBZhoR;>7Fn6^WNfo{SzqKu^!y&x;iL{^-gE<)+1_RgvfplqFt6svGnq-bAX)KP>SU zQceCEg2{dxi6(#0Bp*jaI{1gKVEaUTj|fs-;c$sZk?Qh}#8XIhdD#c|NE`AwDW4&E zEg}cqAZ!f0(Q8UlAWs7LPe$yZze>D-RCk~%@iJ0PKDCd;sR?xXro`)p{O5gqG`>dz z|IiiMJ`vx;L#h`br{q0|*W|0wK;BO@`A;S!9x>$85>FzXFpB?^HU4B)5-Fs50SX@` z1x@}2DW5UqixSTx)#cxocmb)hPvuu#NmP((3PV&NI#bj|q7?AYY7_rQcms(pFPkh% zye{8Cp5)txe7UCw<%1vrP2t)^py1!1*9tf|BJrpp??^m_RF@x-cp9m0KPT}_&myky zq$IM2LP_Fzq*?)otQC#Fpc7wPm3-OYsl%g!(kN8mmjW62J*2emp|kOqBxHA@48{hr#OFTQPjYXUN<87Ea&Hw zJOU8QA<+VGT}k2vq*?&d8HpE>>hd*-SCDG*pX&JdXgucPAG$)zC*rXNQcdB|dnDdO zs>=t4;xS4!`FV#(`7W2gJ`vz?O7(ed-VI}$5s>R;z~Yo@_U3Sd5>OYQHHXp{NSt_GenjFqq?-JvIj!y4G!(j0!7~&x5^p2b3Rne0)E<@XewEtnTqrzLM2JTCG+OMF)H4(AUW78&rPs|%9P8T`W%A3>`7 zQ;~QPspik&QHht3>hg7olb$Yrh>wd~p0%crt{#^{HA9GuAt*D*h;Fna@g`E;XhY&H zq?-JV5s7<9HFerQYi_?ciB|eT+Ggni1o68^T zAy373km&Ns08db&6@P5r$4BFd2>zifI6e_ikcOtPq%3h8sV<+DcnYZ|e=NlT4kgk^ zborp*cw(63X%{DZ$gy}Jr-;-_z(_HNL^HUgDe)1cxkO~xLkpr5-5?grW@J+*#w>f`ITjEKix&t|hJ4iKqPF3P$PnQoI zi_gk&`6XFjel$L7#89aCM0{2esaC*|35l1G>IKv#?jqIX9Z%xqm@YpqanhSW3z+P4 zN6C=SY5>y}y2zu6X0?!L1sqk7I2qLB*F+`W=JH44nEM4pd`&Xo`zg`v9a)xm1gUP% zk$3{BE-x3aejB(Zzt%$@{`RMlX!47L)xAI7?|{%0*5r{V1u=?CSN;8z)#zJfefrB| zui#}xe+6_e{*z(rQMAj|)-;eOs}27()nI?q;62H=IF45~-d_>Oi zKhr=Nm{yTBS*cj_2f#jcWT|aTwFWRl!STPS&a%$7|CJv_|D80r7q7oL}oAPkId`T4{2o zno&%0+!{x|XWEQn%D_E|rwzRAi$+7=Ke8Y5&D!Uze*(xs)h_ zUw$$9r}N{IcR1cB{k(XX`5Ii2LlpS&pk1B2z_0dhJjN}3HJzmuHX%l*H$%*kD){+S)h>vxx`PMq$;hqVX<85l!nj1Tj)De7{_RPS| zq^>p3I>NWx({of!c#yNcMoj^^uho8i;!JVSJJ!cyyC9#Mw9nxp_l`BM_mZTjAhj-i z)yJn?`l=Xz$2y|-#|d9`CsfNm(*w%?$Mu&c#H>jZ_7)fIwD#_O+!2+X))Cf^6M@vn zJmKwxy+3q={PZ&~x8Jq!-)`&ecRzCaqCPvor*+ns7VQ3|$oi@?<^IXy?oaQ2fN+kT z^3h3WUYNJVmyew?Yo8(d=g4>FoPWU?-=1?}{>(Ej_^M4%%0B!E@mXie%-v4<{E?rV z^M%aOM}GboajrAvqn|kDGoL%gI`jN<^Va8wk2%3Q=j(avFzd{(e&_37`Rbgno^z&k z@ccvUujH-u!%KHRrKnt))E2ePyU$$zrw4amHc Date: Sat, 16 Dec 2017 23:57:46 +0100 Subject: [PATCH 510/546] sm501: Add panel hardware cursor registers also to read function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These were forgotten when adding panel layer support in ffd39257018 "SM501 emulation for R2D-SH4". Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé [dwg: Added reference to earlier commit in message] Signed-off-by: David Gibson --- hw/display/sm501.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 7f1822421a..b9b611131e 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -956,6 +956,19 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, ret = s->dc_panel_v_sync; break; + case SM501_DC_PANEL_HWC_ADDR: + ret = s->dc_panel_hwc_addr; + break; + case SM501_DC_PANEL_HWC_LOC: + ret = s->dc_panel_hwc_location; + break; + case SM501_DC_PANEL_HWC_COLOR_1_2: + ret = s->dc_panel_hwc_color_1_2; + break; + case SM501_DC_PANEL_HWC_COLOR_3: + ret = s->dc_panel_hwc_color_3; + break; + case SM501_DC_VIDEO_CONTROL: ret = s->dc_video_control; break; From 5690d9ecefb946100a4974d57ae03bc5ee11775a Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 16 Dec 2017 23:57:46 +0100 Subject: [PATCH 511/546] sm501: Add some more unimplemented registers These are not really implemented (just return zero or default values) but add these so guests accessing them can run. Signed-off-by: BALATON Zoltan Signed-off-by: David Gibson --- hw/display/sm501.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/hw/display/sm501.c b/hw/display/sm501.c index b9b611131e..4f7dc59b25 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -795,6 +795,8 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, case SM501_ARBTRTN_CONTROL: ret = s->arbitration_control; break; + case SM501_COMMAND_LIST_STATUS: + ret = 0x00180002; /* FIFOs are empty, everything idle */ case SM501_IRQ_MASK: ret = s->irq_mask; break; @@ -812,6 +814,9 @@ static uint64_t sm501_system_config_read(void *opaque, hwaddr addr, case SM501_POWER_MODE_CONTROL: ret = s->power_mode_control; break; + case SM501_ENDIAN_CONTROL: + ret = 0; /* Only default little endian mode is supported */ + break; default: printf("sm501 system config : not implemented register read." @@ -865,6 +870,12 @@ static void sm501_system_config_write(void *opaque, hwaddr addr, case SM501_POWER_MODE_CONTROL: s->power_mode_control = value & 0x00000003; break; + case SM501_ENDIAN_CONTROL: + if (value & 0x00000001) { + printf("sm501 system config : big endian mode not implemented.\n"); + abort(); + } + break; default: printf("sm501 system config : not implemented register write." @@ -924,6 +935,9 @@ static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr, case SM501_DC_PANEL_PANNING_CONTROL: ret = s->dc_panel_panning_control; break; + case SM501_DC_PANEL_COLOR_KEY: + /* Not implemented yet */ + break; case SM501_DC_PANEL_FB_ADDR: ret = s->dc_panel_fb_addr; break; @@ -1035,6 +1049,9 @@ static void sm501_disp_ctrl_write(void *opaque, hwaddr addr, case SM501_DC_PANEL_PANNING_CONTROL: s->dc_panel_panning_control = value & 0xFF3FFF3F; break; + case SM501_DC_PANEL_COLOR_KEY: + /* Not implemented yet */ + break; case SM501_DC_PANEL_FB_ADDR: s->dc_panel_fb_addr = value & 0x8FFFFFF0; break; From 7709dbf12c0bb9a86c186c2c0f7ae67ce363dc80 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 16 Dec 2017 23:42:14 +0100 Subject: [PATCH 512/546] ppc4xx_i2c: Implement basic I2C functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enough to please U-Boot and make it able to detect SDRAM SPD EEPROMs Signed-off-by: François Revol Signed-off-by: BALATON Zoltan Reviewed-by: David Gibson Signed-off-by: David Gibson --- hw/i2c/ppc4xx_i2c.c | 198 ++++++++++++++++++++++++++++++------ include/hw/i2c/ppc4xx_i2c.h | 3 + 2 files changed, 171 insertions(+), 30 deletions(-) diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c index 5a6bde951e..e873a445da 100644 --- a/hw/i2c/ppc4xx_i2c.c +++ b/hw/i2c/ppc4xx_i2c.c @@ -2,6 +2,8 @@ * PPC4xx I2C controller emulation * * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2012 François Revol + * Copyright (c) 2016 BALATON Zoltan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,26 +27,118 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu-common.h" +#include "qemu/log.h" #include "cpu.h" #include "hw/hw.h" #include "hw/i2c/ppc4xx_i2c.h" -/*#define DEBUG_I2C*/ +#define PPC4xx_I2C_MEM_SIZE 0x12 -#define PPC4xx_I2C_MEM_SIZE 0x11 +#define IIC_CNTL_PT (1 << 0) +#define IIC_CNTL_READ (1 << 1) +#define IIC_CNTL_CHT (1 << 2) +#define IIC_CNTL_RPST (1 << 3) + +#define IIC_STS_PT (1 << 0) +#define IIC_STS_ERR (1 << 2) +#define IIC_STS_MDBS (1 << 5) + +#define IIC_EXTSTS_XFRA (1 << 0) + +#define IIC_XTCNTLSS_SRST (1 << 0) + +static void ppc4xx_i2c_reset(DeviceState *s) +{ + PPC4xxI2CState *i2c = PPC4xx_I2C(s); + + /* FIXME: Should also reset bus? + *if (s->address != ADDR_RESET) { + * i2c_end_transfer(s->bus); + *} + */ + + i2c->mdata = 0; + i2c->lmadr = 0; + i2c->hmadr = 0; + i2c->cntl = 0; + i2c->mdcntl = 0; + i2c->sts = 0; + i2c->extsts = 0x8f; + i2c->sdata = 0; + i2c->lsadr = 0; + i2c->hsadr = 0; + i2c->clkdiv = 0; + i2c->intrmsk = 0; + i2c->xfrcnt = 0; + i2c->xtcntlss = 0; + i2c->directcntl = 0x0f; + i2c->intr = 0; +} + +static inline bool ppc4xx_i2c_is_master(PPC4xxI2CState *i2c) +{ + return true; +} static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size) { PPC4xxI2CState *i2c = PPC4xx_I2C(opaque); uint64_t ret; -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr); -#endif switch (addr) { case 0x00: - /*i2c_readbyte(&i2c->mdata);*/ ret = i2c->mdata; + if (ppc4xx_i2c_is_master(i2c)) { + ret = 0xff; + + if (!(i2c->sts & IIC_STS_MDBS)) { + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to read " + "without starting transfer\n", + TYPE_PPC4xx_I2C, __func__); + } else { + int pending = (i2c->cntl >> 4) & 3; + + /* get the next byte */ + int byte = i2c_recv(i2c->bus); + + if (byte < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: read failed " + "for device 0x%02x\n", TYPE_PPC4xx_I2C, + __func__, i2c->lmadr); + ret = 0xff; + } else { + ret = byte; + /* Raise interrupt if enabled */ + /*ppc4xx_i2c_raise_interrupt(i2c)*/; + } + + if (!pending) { + i2c->sts &= ~IIC_STS_MDBS; + /*i2c_end_transfer(i2c->bus);*/ + /*} else if (i2c->cntl & (IIC_CNTL_RPST | IIC_CNTL_CHT)) {*/ + } else if (pending) { + /* current smbus implementation doesn't like + multibyte xfer repeated start */ + i2c_end_transfer(i2c->bus); + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) { + /* if non zero is returned, the adress is not valid */ + i2c->sts &= ~IIC_STS_PT; + i2c->sts |= IIC_STS_ERR; + i2c->extsts |= IIC_EXTSTS_XFRA; + } else { + /*i2c->sts |= IIC_STS_PT;*/ + i2c->sts |= IIC_STS_MDBS; + i2c->sts &= ~IIC_STS_ERR; + i2c->extsts = 0; + } + } + pending--; + i2c->cntl = (i2c->cntl & 0xcf) | (pending << 4); + } + } else { + qemu_log_mask(LOG_UNIMP, "[%s]%s: slave mode not implemented\n", + TYPE_PPC4xx_I2C, __func__); + } break; case 0x02: ret = i2c->sdata; @@ -88,13 +182,15 @@ static uint64_t ppc4xx_i2c_readb(void *opaque, hwaddr addr, unsigned int size) case 0x10: ret = i2c->directcntl; break; + case 0x11: + ret = i2c->intr; + break; default: - ret = 0x00; + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr); + ret = 0; break; } -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " %02" PRIx64 "\n", __func__, addr, ret); -#endif return ret; } @@ -103,26 +199,70 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value, unsigned int size) { PPC4xxI2CState *i2c = opaque; -#ifdef DEBUG_I2C - printf("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", - __func__, addr, value); -#endif + switch (addr) { case 0x00: i2c->mdata = value; - /*i2c_sendbyte(&i2c->mdata);*/ + if (!i2c_bus_busy(i2c->bus)) { + /* assume we start a write transfer */ + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 0)) { + /* if non zero is returned, the adress is not valid */ + i2c->sts &= ~IIC_STS_PT; + i2c->sts |= IIC_STS_ERR; + i2c->extsts |= IIC_EXTSTS_XFRA; + } else { + i2c->sts |= IIC_STS_PT; + i2c->sts &= ~IIC_STS_ERR; + i2c->extsts = 0; + } + } + if (i2c_bus_busy(i2c->bus)) { + if (i2c_send(i2c->bus, i2c->mdata)) { + /* if the target return non zero then end the transfer */ + i2c->sts &= ~IIC_STS_PT; + i2c->sts |= IIC_STS_ERR; + i2c->extsts |= IIC_EXTSTS_XFRA; + i2c_end_transfer(i2c->bus); + } + } break; case 0x02: i2c->sdata = value; break; case 0x04: i2c->lmadr = value; + if (i2c_bus_busy(i2c->bus)) { + i2c_end_transfer(i2c->bus); + } break; case 0x05: i2c->hmadr = value; break; case 0x06: i2c->cntl = value; + if (i2c->cntl & IIC_CNTL_PT) { + if (i2c->cntl & IIC_CNTL_READ) { + if (i2c_bus_busy(i2c->bus)) { + /* end previous transfer */ + i2c->sts &= ~IIC_STS_PT; + i2c_end_transfer(i2c->bus); + } + if (i2c_start_transfer(i2c->bus, i2c->lmadr >> 1, 1)) { + /* if non zero is returned, the adress is not valid */ + i2c->sts &= ~IIC_STS_PT; + i2c->sts |= IIC_STS_ERR; + i2c->extsts |= IIC_EXTSTS_XFRA; + } else { + /*i2c->sts |= IIC_STS_PT;*/ + i2c->sts |= IIC_STS_MDBS; + i2c->sts &= ~IIC_STS_ERR; + i2c->extsts = 0; + } + } else { + /* we actually already did the write transfer... */ + i2c->sts &= ~IIC_STS_PT; + } + } break; case 0x07: i2c->mdcntl = value & 0xDF; @@ -135,6 +275,7 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value, break; case 0x0A: i2c->lsadr = value; + /*i2c_set_slave_address(i2c->bus, i2c->lsadr);*/ break; case 0x0B: i2c->hsadr = value; @@ -149,11 +290,23 @@ static void ppc4xx_i2c_writeb(void *opaque, hwaddr addr, uint64_t value, i2c->xfrcnt = value & 0x77; break; case 0x0F: + if (value & IIC_XTCNTLSS_SRST) { + /* Is it actually a full reset? U-Boot sets some regs before */ + ppc4xx_i2c_reset(DEVICE(i2c)); + break; + } i2c->xtcntlss = value; break; case 0x10: i2c->directcntl = value & 0x7; break; + case 0x11: + i2c->intr = value; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" + HWADDR_PRIx "\n", TYPE_PPC4xx_I2C, __func__, addr); + break; } } @@ -167,21 +320,6 @@ static const MemoryRegionOps ppc4xx_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void ppc4xx_i2c_reset(DeviceState *s) -{ - PPC4xxI2CState *i2c = PPC4xx_I2C(s); - - i2c->mdata = 0x00; - i2c->sdata = 0x00; - i2c->cntl = 0x00; - i2c->mdcntl = 0x00; - i2c->sts = 0x00; - i2c->extsts = 0x00; - i2c->clkdiv = 0x00; - i2c->xfrcnt = 0x00; - i2c->directcntl = 0x0F; -} - static void ppc4xx_i2c_init(Object *o) { PPC4xxI2CState *s = PPC4xx_I2C(o); diff --git a/include/hw/i2c/ppc4xx_i2c.h b/include/hw/i2c/ppc4xx_i2c.h index 3450bda577..3c603071bd 100644 --- a/include/hw/i2c/ppc4xx_i2c.h +++ b/include/hw/i2c/ppc4xx_i2c.h @@ -2,6 +2,8 @@ * PPC4xx I2C controller emulation * * Copyright (c) 2007 Jocelyn Mayer + * Copyright (c) 2012 François Revol + * Copyright (c) 2016 BALATON Zoltan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -55,6 +57,7 @@ typedef struct PPC4xxI2CState { uint8_t xfrcnt; uint8_t xtcntlss; uint8_t directcntl; + uint8_t intr; } PPC4xxI2CState; #endif /* PPC4XX_I2C_H */ From 2b3db9dd34579d3253bb6062db92f2af20b39502 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Mon, 18 Dec 2017 16:58:02 +0100 Subject: [PATCH 513/546] spapr_pci: use warn_report() These two are definitely warnings. Let's use the appropriate API. Signed-off-by: Greg Kurz Signed-off-by: David Gibson --- hw/ppc/spapr_pci.c | 6 +++--- hw/ppc/spapr_pci_vfio.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 88797b3d36..695c820911 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1696,9 +1696,9 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) /* DMA setup */ if (((sphb->page_size_mask & qemu_getrampagesize()) == 0) && kvm_enabled()) { - error_report("System page size 0x%lx is not enabled in page_size_mask " - "(0x%"PRIx64"). Performance may be slow", - qemu_getrampagesize(), sphb->page_size_mask); + warn_report("System page size 0x%lx is not enabled in page_size_mask " + "(0x%"PRIx64"). Performance may be slow", + qemu_getrampagesize(), sphb->page_size_mask); } for (i = 0; i < windows_supported; ++i) { diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 8448e0b024..1f775ea93d 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -50,7 +50,7 @@ static Property spapr_phb_vfio_properties[] = { static void spapr_phb_vfio_instance_init(Object *obj) { if (!qtest_enabled()) { - error_report("spapr-pci-vfio-host-bridge is deprecated"); + warn_report("spapr-pci-vfio-host-bridge is deprecated"); } } From a9dd6604a663d1a88e5cf6b1446d6a1202c3334d Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sat, 16 Dec 2017 23:42:39 +0100 Subject: [PATCH 514/546] hw/ide: Emulate SiI3112 SATA controller This is a common generic PCI SATA controller that is also used in PCs but more importantly guests running on the Sam460ex board prefer this card and have a driver for it (unlike for other SATA controllers already emulated). Signed-off-by: BALATON Zoltan Acked-by: John Snow Signed-off-by: David Gibson --- MAINTAINERS | 6 + default-configs/ppcemb-softmmu.mak | 1 + hw/ide/Makefile.objs | 1 + hw/ide/sii3112.c | 368 +++++++++++++++++++++++++++++ hw/ide/trace-events | 5 + 5 files changed, 381 insertions(+) create mode 100644 hw/ide/sii3112.c diff --git a/MAINTAINERS b/MAINTAINERS index bc2d3a4ef1..8ab86930e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -765,6 +765,12 @@ L: qemu-ppc@nongnu.org S: Odd Fixes F: hw/ppc/virtex_ml507.c +sam460ex +M: BALATON Zoltan +L: qemu-ppc@nongnu.org +S: Maintained +F: hw/ide/sii3112.c + SH4 Machines ------------ R2D diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak index 13917fb7a3..5db4618a5a 100644 --- a/default-configs/ppcemb-softmmu.mak +++ b/default-configs/ppcemb-softmmu.mak @@ -16,3 +16,4 @@ CONFIG_I8259=y CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_SM501=y +CONFIG_IDE_SII3112=y diff --git a/hw/ide/Makefile.objs b/hw/ide/Makefile.objs index f0edca3300..fc328ffbe8 100644 --- a/hw/ide/Makefile.objs +++ b/hw/ide/Makefile.objs @@ -11,3 +11,4 @@ common-obj-$(CONFIG_MICRODRIVE) += microdrive.o common-obj-$(CONFIG_AHCI) += ahci.o common-obj-$(CONFIG_AHCI) += ich.o common-obj-$(CONFIG_ALLWINNER_A10) += ahci-allwinner.o +common-obj-$(CONFIG_IDE_SII3112) += sii3112.o diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c new file mode 100644 index 0000000000..e2f5562bb7 --- /dev/null +++ b/hw/ide/sii3112.c @@ -0,0 +1,368 @@ +/* + * QEMU SiI3112A PCI to Serial ATA Controller Emulation + * + * Copyright (C) 2017 BALATON Zoltan + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +/* For documentation on this and similar cards see: + * http://wiki.osdev.org/User:Quok/Silicon_Image_Datasheets + */ + +#include +#include +#include "trace.h" + +#define TYPE_SII3112_PCI "sii3112" +#define SII3112_PCI(obj) OBJECT_CHECK(SiI3112PCIState, (obj), \ + TYPE_SII3112_PCI) + +typedef struct SiI3112Regs { + uint32_t confstat; + uint32_t scontrol; + uint16_t sien; + uint8_t swdata; +} SiI3112Regs; + +typedef struct SiI3112PCIState { + PCIIDEState i; + MemoryRegion mmio; + SiI3112Regs regs[2]; +} SiI3112PCIState; + +/* The sii3112_reg_read and sii3112_reg_write functions implement the + * Internal Register Space - BAR5 (section 6.7 of the data sheet). + */ + +static uint64_t sii3112_reg_read(void *opaque, hwaddr addr, + unsigned int size) +{ + SiI3112PCIState *d = opaque; + uint64_t val = 0; + + switch (addr) { + case 0x00: + val = d->i.bmdma[0].cmd; + break; + case 0x01: + val = d->regs[0].swdata; + break; + case 0x02: + val = d->i.bmdma[0].status; + break; + case 0x03: + val = 0; + break; + case 0x04 ... 0x07: + val = bmdma_addr_ioport_ops.read(&d->i.bmdma[0], addr - 4, size); + break; + case 0x08: + val = d->i.bmdma[1].cmd; + break; + case 0x09: + val = d->regs[1].swdata; + break; + case 0x0a: + val = d->i.bmdma[1].status; + break; + case 0x0b: + val = 0; + break; + case 0x0c ... 0x0f: + val = bmdma_addr_ioport_ops.read(&d->i.bmdma[1], addr - 12, size); + break; + case 0x10: + val = d->i.bmdma[0].cmd; + val |= (d->regs[0].confstat & (1UL << 11) ? (1 << 4) : 0); /*SATAINT0*/ + val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 6) : 0); /*SATAINT1*/ + val |= (d->i.bmdma[1].status & BM_STATUS_INT ? (1 << 14) : 0); + val |= d->i.bmdma[0].status << 16; + val |= d->i.bmdma[1].status << 24; + break; + case 0x18: + val = d->i.bmdma[1].cmd; + val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 4) : 0); + val |= d->i.bmdma[1].status << 16; + break; + case 0x80 ... 0x87: + if (size == 1) { + val = ide_ioport_read(&d->i.bus[0], addr - 0x80); + } else if (addr == 0x80) { + val = (size == 2) ? ide_data_readw(&d->i.bus[0], 0) : + ide_data_readl(&d->i.bus[0], 0); + } else { + val = (1ULL << (size * 8)) - 1; + } + break; + case 0x8a: + val = (size == 1) ? ide_status_read(&d->i.bus[0], 4) : + (1ULL << (size * 8)) - 1; + break; + case 0xa0: + val = d->regs[0].confstat; + break; + case 0xc0 ... 0xc7: + if (size == 1) { + val = ide_ioport_read(&d->i.bus[1], addr - 0xc0); + } else if (addr == 0xc0) { + val = (size == 2) ? ide_data_readw(&d->i.bus[1], 0) : + ide_data_readl(&d->i.bus[1], 0); + } else { + val = (1ULL << (size * 8)) - 1; + } + break; + case 0xca: + val = (size == 1) ? ide_status_read(&d->i.bus[0], 4) : + (1ULL << (size * 8)) - 1; + break; + case 0xe0: + val = d->regs[1].confstat; + break; + case 0x100: + val = d->regs[0].scontrol; + break; + case 0x104: + val = (d->i.bus[0].ifs[0].blk) ? 0x113 : 0; + break; + case 0x148: + val = d->regs[0].sien << 16; + break; + case 0x180: + val = d->regs[1].scontrol; + break; + case 0x184: + val = (d->i.bus[1].ifs[0].blk) ? 0x113 : 0; + break; + case 0x1c8: + val = d->regs[1].sien << 16; + break; + default: + val = 0; + } + trace_sii3112_read(size, addr, val); + return val; +} + +static void sii3112_reg_write(void *opaque, hwaddr addr, + uint64_t val, unsigned int size) +{ + SiI3112PCIState *d = opaque; + + trace_sii3112_write(size, addr, val); + switch (addr) { + case 0x00: + case 0x10: + bmdma_cmd_writeb(&d->i.bmdma[0], val); + break; + case 0x01: + case 0x11: + d->regs[0].swdata = val & 0x3f; + break; + case 0x02: + case 0x12: + d->i.bmdma[0].status = (val & 0x60) | (d->i.bmdma[0].status & 1) | + (d->i.bmdma[0].status & ~val & 6); + break; + case 0x04 ... 0x07: + bmdma_addr_ioport_ops.write(&d->i.bmdma[0], addr - 4, val, size); + break; + case 0x08: + case 0x18: + bmdma_cmd_writeb(&d->i.bmdma[1], val); + break; + case 0x09: + case 0x19: + d->regs[1].swdata = val & 0x3f; + break; + case 0x0a: + case 0x1a: + d->i.bmdma[1].status = (val & 0x60) | (d->i.bmdma[1].status & 1) | + (d->i.bmdma[1].status & ~val & 6); + break; + case 0x0c ... 0x0f: + bmdma_addr_ioport_ops.write(&d->i.bmdma[1], addr - 12, val, size); + break; + case 0x80 ... 0x87: + if (size == 1) { + ide_ioport_write(&d->i.bus[0], addr - 0x80, val); + } else if (addr == 0x80) { + if (size == 2) { + ide_data_writew(&d->i.bus[0], 0, val); + } else { + ide_data_writel(&d->i.bus[0], 0, val); + } + } + break; + case 0x8a: + if (size == 1) { + ide_cmd_write(&d->i.bus[0], 4, val); + } + break; + case 0xc0 ... 0xc7: + if (size == 1) { + ide_ioport_write(&d->i.bus[1], addr - 0xc0, val); + } else if (addr == 0xc0) { + if (size == 2) { + ide_data_writew(&d->i.bus[1], 0, val); + } else { + ide_data_writel(&d->i.bus[1], 0, val); + } + } + break; + case 0xca: + if (size == 1) { + ide_cmd_write(&d->i.bus[1], 4, val); + } + break; + case 0x100: + d->regs[0].scontrol = val & 0xfff; + if (val & 1) { + ide_bus_reset(&d->i.bus[0]); + } + break; + case 0x148: + d->regs[0].sien = (val >> 16) & 0x3eed; + break; + case 0x180: + d->regs[1].scontrol = val & 0xfff; + if (val & 1) { + ide_bus_reset(&d->i.bus[1]); + } + break; + case 0x1c8: + d->regs[1].sien = (val >> 16) & 0x3eed; + break; + default: + val = 0; + } +} + +static const MemoryRegionOps sii3112_reg_ops = { + .read = sii3112_reg_read, + .write = sii3112_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +/* the PCI irq level is the logical OR of the two channels */ +static void sii3112_update_irq(SiI3112PCIState *s) +{ + int i, set = 0; + + for (i = 0; i < 2; i++) { + set |= s->regs[i].confstat & (1UL << 11); + } + pci_set_irq(PCI_DEVICE(s), (set ? 1 : 0)); +} + +static void sii3112_set_irq(void *opaque, int channel, int level) +{ + SiI3112PCIState *s = opaque; + + trace_sii3112_set_irq(channel, level); + if (level) { + s->regs[channel].confstat |= (1UL << 11); + } else { + s->regs[channel].confstat &= ~(1UL << 11); + } + + sii3112_update_irq(s); +} + +static void sii3112_reset(void *opaque) +{ + SiI3112PCIState *s = opaque; + int i; + + for (i = 0; i < 2; i++) { + s->regs[i].confstat = 0x6515 << 16; + ide_bus_reset(&s->i.bus[i]); + } +} + +static void sii3112_pci_realize(PCIDevice *dev, Error **errp) +{ + SiI3112PCIState *d = SII3112_PCI(dev); + PCIIDEState *s = PCI_IDE(dev); + MemoryRegion *mr; + qemu_irq *irq; + int i; + + pci_config_set_interrupt_pin(dev->config, 1); + pci_set_byte(dev->config + PCI_CACHE_LINE_SIZE, 8); + + /* BAR5 is in PCI memory space */ + memory_region_init_io(&d->mmio, OBJECT(d), &sii3112_reg_ops, d, + "sii3112.bar5", 0x200); + pci_register_bar(dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio); + + /* BAR0-BAR4 are PCI I/O space aliases into BAR5 */ + mr = g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(d), "sii3112.bar0", &d->mmio, 0x80, 8); + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(d), "sii3112.bar1", &d->mmio, 0x88, 4); + pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(d), "sii3112.bar2", &d->mmio, 0xc0, 8); + pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(d), "sii3112.bar3", &d->mmio, 0xc8, 4); + pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, mr); + mr = g_new(MemoryRegion, 1); + memory_region_init_alias(mr, OBJECT(d), "sii3112.bar4", &d->mmio, 0, 16); + pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, mr); + + irq = qemu_allocate_irqs(sii3112_set_irq, d, 2); + for (i = 0; i < 2; i++) { + ide_bus_new(&s->bus[i], sizeof(s->bus[i]), DEVICE(dev), i, 1); + ide_init2(&s->bus[i], irq[i]); + + bmdma_init(&s->bus[i], &s->bmdma[i], s); + s->bmdma[i].bus = &s->bus[i]; + ide_register_restart_cb(&s->bus[i]); + } + qemu_register_reset(sii3112_reset, s); +} + +static void sii3112_pci_exitfn(PCIDevice *dev) +{ + PCIIDEState *d = PCI_IDE(dev); + int i; + + for (i = 0; i < 2; ++i) { + memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io); + memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport); + } +} + +static void sii3112_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *pd = PCI_DEVICE_CLASS(klass); + + pd->vendor_id = 0x1095; + pd->device_id = 0x3112; + pd->class_id = PCI_CLASS_STORAGE_RAID; + pd->revision = 1; + pd->realize = sii3112_pci_realize; + pd->exit = sii3112_pci_exitfn; + dc->desc = "SiI3112A SATA controller"; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); +} + +static const TypeInfo sii3112_pci_info = { + .name = TYPE_SII3112_PCI, + .parent = TYPE_PCI_IDE, + .instance_size = sizeof(SiI3112PCIState), + .class_init = sii3112_pci_class_init, +}; + +static void sii3112_register_types(void) +{ + type_register_static(&sii3112_pci_info); +} + +type_init(sii3112_register_types) diff --git a/hw/ide/trace-events b/hw/ide/trace-events index 601bd97d81..0c39cabe72 100644 --- a/hw/ide/trace-events +++ b/hw/ide/trace-events @@ -37,6 +37,11 @@ bmdma_addr_write(uint64_t data) "data: 0x%016"PRIx64 bmdma_read(uint64_t addr, uint8_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x" bmdma_write(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64 +# hw/ide/sii3112.c +sii3112_read(int size, uint64_t addr, uint64_t val) "bmdma: read (size %d) 0x%"PRIx64" : 0x%02"PRIx64 +sii3112_write(int size, uint64_t addr, uint64_t val) "bmdma: write (size %d) 0x%"PRIx64" : 0x%02"PRIx64 +sii3112_set_irq(int channel, int level) "channel %d level %d" + # hw/ide/via.c bmdma_read_via(uint64_t addr, uint32_t val) "bmdma: readb 0x%"PRIx64" : 0x%02x" bmdma_write_via(uint64_t addr, uint64_t val) "bmdma: writeb 0x%"PRIx64" : 0x%02"PRIx64 From b168a138a8bc9c18e8140fef614a6b66721497fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 15 Dec 2017 14:56:01 +0100 Subject: [PATCH 515/546] ppc/pnv: change powernv_ prefix to pnv_ for overall naming consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'pnv' prefix is now used for all and the routines populating the device tree start with 'pnv_dt'. The handler of the PnvXScomInterface is also renamed to 'dt_xscom' which should reflect that it is populating the device tree under the 'xscom@' node of the chip. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv.c | 94 ++++++++++++++++++-------------------- hw/ppc/pnv_bmc.c | 2 +- hw/ppc/pnv_core.c | 8 ++-- hw/ppc/pnv_lpc.c | 6 +-- hw/ppc/pnv_psi.c | 4 +- hw/ppc/pnv_xscom.c | 10 ++-- include/hw/ppc/pnv.h | 10 ++-- include/hw/ppc/pnv_xscom.h | 4 +- 8 files changed, 67 insertions(+), 71 deletions(-) diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 94ffc8e137..9475e8479c 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -77,8 +77,7 @@ static const char *pnv_chip_core_typename(const PnvChip *o) * that has a different "affinity". In practice, it means one range * per chip. */ -static void powernv_populate_memory_node(void *fdt, int chip_id, hwaddr start, - hwaddr size) +static void pnv_dt_memory(void *fdt, int chip_id, hwaddr start, hwaddr size) { char *mem_name; uint64_t mem_reg_property[2]; @@ -119,7 +118,7 @@ static int get_cpus_node(void *fdt) * device tree, used in XSCOM to address cores and in interrupt * servers. */ -static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt) +static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt) { CPUState *cs = CPU(DEVICE(pc->threads)); DeviceClass *dc = DEVICE_GET_CLASS(cs); @@ -228,8 +227,8 @@ static void powernv_create_core_node(PnvChip *chip, PnvCore *pc, void *fdt) servers_prop, sizeof(servers_prop)))); } -static void powernv_populate_icp(PnvChip *chip, void *fdt, uint32_t pir, - uint32_t nr_threads) +static void pnv_dt_icp(PnvChip *chip, void *fdt, uint32_t pir, + uint32_t nr_threads) { uint64_t addr = PNV_ICP_BASE(chip) | (pir << 12); char *name; @@ -277,13 +276,13 @@ static int pnv_chip_lpc_offset(PnvChip *chip, void *fdt) return offset; } -static void powernv_populate_chip(PnvChip *chip, void *fdt) +static void pnv_dt_chip(PnvChip *chip, void *fdt) { const char *typename = pnv_chip_core_typename(chip); size_t typesize = object_type_get_instance_size(typename); int i; - pnv_xscom_populate(chip, fdt, 0); + pnv_dt_xscom(chip, fdt, 0); /* The default LPC bus of a multichip system is on chip 0. It's * recognized by the firmware (skiboot) using a "primary" @@ -298,20 +297,18 @@ static void powernv_populate_chip(PnvChip *chip, void *fdt) for (i = 0; i < chip->nr_cores; i++) { PnvCore *pnv_core = PNV_CORE(chip->cores + i * typesize); - powernv_create_core_node(chip, pnv_core, fdt); + pnv_dt_core(chip, pnv_core, fdt); /* Interrupt Control Presenters (ICP). One per core. */ - powernv_populate_icp(chip, fdt, pnv_core->pir, - CPU_CORE(pnv_core)->nr_threads); + pnv_dt_icp(chip, fdt, pnv_core->pir, CPU_CORE(pnv_core)->nr_threads); } if (chip->ram_size) { - powernv_populate_memory_node(fdt, chip->chip_id, chip->ram_start, - chip->ram_size); + pnv_dt_memory(fdt, chip->chip_id, chip->ram_start, chip->ram_size); } } -static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off) +static void pnv_dt_rtc(ISADevice *d, void *fdt, int lpc_off) { uint32_t io_base = d->ioport_id; uint32_t io_regs[] = { @@ -331,7 +328,7 @@ static void powernv_populate_rtc(ISADevice *d, void *fdt, int lpc_off) _FDT((fdt_setprop_string(fdt, node, "compatible", "pnpPNP,b00"))); } -static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off) +static void pnv_dt_serial(ISADevice *d, void *fdt, int lpc_off) { const char compatible[] = "ns16550\0pnpPNP,501"; uint32_t io_base = d->ioport_id; @@ -362,7 +359,7 @@ static void powernv_populate_serial(ISADevice *d, void *fdt, int lpc_off) _FDT((fdt_setprop_string(fdt, node, "device_type", "serial"))); } -static void powernv_populate_ipmi_bt(ISADevice *d, void *fdt, int lpc_off) +static void pnv_dt_ipmi_bt(ISADevice *d, void *fdt, int lpc_off) { const char compatible[] = "bt\0ipmi-bt"; uint32_t io_base; @@ -401,17 +398,17 @@ typedef struct ForeachPopulateArgs { int offset; } ForeachPopulateArgs; -static int powernv_populate_isa_device(DeviceState *dev, void *opaque) +static int pnv_dt_isa_device(DeviceState *dev, void *opaque) { ForeachPopulateArgs *args = opaque; ISADevice *d = ISA_DEVICE(dev); if (object_dynamic_cast(OBJECT(dev), TYPE_MC146818_RTC)) { - powernv_populate_rtc(d, args->fdt, args->offset); + pnv_dt_rtc(d, args->fdt, args->offset); } else if (object_dynamic_cast(OBJECT(dev), TYPE_ISA_SERIAL)) { - powernv_populate_serial(d, args->fdt, args->offset); + pnv_dt_serial(d, args->fdt, args->offset); } else if (object_dynamic_cast(OBJECT(dev), "isa-ipmi-bt")) { - powernv_populate_ipmi_bt(d, args->fdt, args->offset); + pnv_dt_ipmi_bt(d, args->fdt, args->offset); } else { error_report("unknown isa device %s@i%x", qdev_fw_name(dev), d->ioport_id); @@ -420,7 +417,7 @@ static int powernv_populate_isa_device(DeviceState *dev, void *opaque) return 0; } -static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset) +static void pnv_dt_isa(ISABus *bus, void *fdt, int lpc_offset) { ForeachPopulateArgs args = { .fdt = fdt, @@ -429,14 +426,13 @@ static void powernv_populate_isa(ISABus *bus, void *fdt, int lpc_offset) /* ISA devices are not necessarily parented to the ISA bus so we * can not use object_child_foreach() */ - qbus_walk_children(BUS(bus), powernv_populate_isa_device, - NULL, NULL, NULL, &args); + qbus_walk_children(BUS(bus), pnv_dt_isa_device, NULL, NULL, NULL, &args); } -static void *powernv_create_fdt(MachineState *machine) +static void *pnv_dt_create(MachineState *machine) { const char plat_compat[] = "qemu,powernv\0ibm,powernv"; - PnvMachineState *pnv = POWERNV_MACHINE(machine); + PnvMachineState *pnv = PNV_MACHINE(machine); void *fdt; char *buf; int off; @@ -479,15 +475,15 @@ static void *powernv_create_fdt(MachineState *machine) /* Populate device tree for each chip */ for (i = 0; i < pnv->num_chips; i++) { - powernv_populate_chip(pnv->chips[i], fdt); + pnv_dt_chip(pnv->chips[i], fdt); } /* Populate ISA devices on chip 0 */ lpc_offset = pnv_chip_lpc_offset(pnv->chips[0], fdt); - powernv_populate_isa(pnv->isa_bus, fdt, lpc_offset); + pnv_dt_isa(pnv->isa_bus, fdt, lpc_offset); if (pnv->bmc) { - pnv_bmc_populate_sensors(pnv->bmc, fdt); + pnv_dt_bmc_sensors(pnv->bmc, fdt); } return fdt; @@ -495,17 +491,17 @@ static void *powernv_create_fdt(MachineState *machine) static void pnv_powerdown_notify(Notifier *n, void *opaque) { - PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine()); + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); if (pnv->bmc) { pnv_bmc_powerdown(pnv->bmc); } } -static void ppc_powernv_reset(void) +static void pnv_reset(void) { MachineState *machine = MACHINE(qdev_get_machine()); - PnvMachineState *pnv = POWERNV_MACHINE(machine); + PnvMachineState *pnv = PNV_MACHINE(machine); void *fdt; Object *obj; @@ -524,7 +520,7 @@ static void ppc_powernv_reset(void) pnv->bmc = IPMI_BMC(obj); } - fdt = powernv_create_fdt(machine); + fdt = pnv_dt_create(machine); /* Pack resulting tree */ _FDT((fdt_pack(fdt))); @@ -552,9 +548,9 @@ static ISABus *pnv_isa_create(PnvChip *chip) return isa_bus; } -static void ppc_powernv_init(MachineState *machine) +static void pnv_init(MachineState *machine) { - PnvMachineState *pnv = POWERNV_MACHINE(machine); + PnvMachineState *pnv = PNV_MACHINE(machine); MemoryRegion *ram; char *fw_filename; long fw_size; @@ -567,7 +563,7 @@ static void ppc_powernv_init(MachineState *machine) } ram = g_new(MemoryRegion, 1); - memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", + memory_region_allocate_system_memory(ram, NULL, "pnv.ram", machine->ram_size); memory_region_add_subregion(get_system_memory(), 0, ram); @@ -974,7 +970,7 @@ static void pnv_chip_class_init(ObjectClass *klass, void *data) static ICSState *pnv_ics_get(XICSFabric *xi, int irq) { - PnvMachineState *pnv = POWERNV_MACHINE(xi); + PnvMachineState *pnv = PNV_MACHINE(xi); int i; for (i = 0; i < pnv->num_chips; i++) { @@ -987,7 +983,7 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq) static void pnv_ics_resend(XICSFabric *xi) { - PnvMachineState *pnv = POWERNV_MACHINE(xi); + PnvMachineState *pnv = PNV_MACHINE(xi); int i; for (i = 0; i < pnv->num_chips; i++) { @@ -1021,7 +1017,7 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir) static void pnv_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { - PnvMachineState *pnv = POWERNV_MACHINE(obj); + PnvMachineState *pnv = PNV_MACHINE(obj); int i; CPUState *cs; @@ -1039,13 +1035,13 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - visit_type_uint32(v, name, &POWERNV_MACHINE(obj)->num_chips, errp); + visit_type_uint32(v, name, &PNV_MACHINE(obj)->num_chips, errp); } static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - PnvMachineState *pnv = POWERNV_MACHINE(obj); + PnvMachineState *pnv = PNV_MACHINE(obj); uint32_t num_chips; Error *local_err = NULL; @@ -1067,13 +1063,13 @@ static void pnv_set_num_chips(Object *obj, Visitor *v, const char *name, pnv->num_chips = num_chips; } -static void powernv_machine_initfn(Object *obj) +static void pnv_machine_initfn(Object *obj) { - PnvMachineState *pnv = POWERNV_MACHINE(obj); + PnvMachineState *pnv = PNV_MACHINE(obj); pnv->num_chips = 1; } -static void powernv_machine_class_props_init(ObjectClass *oc) +static void pnv_machine_class_props_init(ObjectClass *oc) { object_class_property_add(oc, "num-chips", "uint32", pnv_get_num_chips, pnv_set_num_chips, @@ -1083,15 +1079,15 @@ static void powernv_machine_class_props_init(ObjectClass *oc) NULL); } -static void powernv_machine_class_init(ObjectClass *oc, void *data) +static void pnv_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); mc->desc = "IBM PowerNV (Non-Virtualized)"; - mc->init = ppc_powernv_init; - mc->reset = ppc_powernv_reset; + mc->init = pnv_init; + mc->reset = pnv_reset; mc->max_cpus = MAX_CPUS; mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("power8_v2.0"); mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for @@ -1104,7 +1100,7 @@ static void powernv_machine_class_init(ObjectClass *oc, void *data) xic->ics_resend = pnv_ics_resend; ispc->print_info = pnv_pic_print_info; - powernv_machine_class_props_init(oc); + pnv_machine_class_props_init(oc); } #define DEFINE_PNV_CHIP_TYPE(type, class_initfn) \ @@ -1116,11 +1112,11 @@ static void powernv_machine_class_init(ObjectClass *oc, void *data) static const TypeInfo types[] = { { - .name = TYPE_POWERNV_MACHINE, + .name = TYPE_PNV_MACHINE, .parent = TYPE_MACHINE, .instance_size = sizeof(PnvMachineState), - .instance_init = powernv_machine_initfn, - .class_init = powernv_machine_class_init, + .instance_init = pnv_machine_initfn, + .class_init = pnv_machine_class_init, .interfaces = (InterfaceInfo[]) { { TYPE_XICS_FABRIC }, { TYPE_INTERRUPT_STATS_PROVIDER }, diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index 7b60b4c360..b2cf441ee7 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -73,7 +73,7 @@ void pnv_bmc_powerdown(IPMIBmc *bmc) pnv_gen_oem_sel(bmc, SOFT_OFF); } -void pnv_bmc_populate_sensors(IPMIBmc *bmc, void *fdt) +void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt) { int offset; int i; diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index 03317db853..7e8a76df44 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -37,7 +37,7 @@ static const char *pnv_core_cpu_typename(PnvCore *pc) return cpu_type; } -static void powernv_cpu_reset(void *opaque) +static void pnv_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); @@ -54,7 +54,7 @@ static void powernv_cpu_reset(void *opaque) env->msr |= MSR_HVB; /* Hypervisor mode */ } -static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp) +static void pnv_cpu_init(PowerPCCPU *cpu, Error **errp) { CPUPPCState *env = &cpu->env; int core_pir; @@ -73,7 +73,7 @@ static void powernv_cpu_init(PowerPCCPU *cpu, Error **errp) /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, PNV_TIMEBASE_FREQ); - qemu_register_reset(powernv_cpu_reset, cpu); + qemu_register_reset(pnv_cpu_reset, cpu); } /* @@ -139,7 +139,7 @@ static void pnv_core_realize_child(Object *child, XICSFabric *xi, Error **errp) return; } - powernv_cpu_init(cpu, &local_err); + pnv_cpu_init(cpu, &local_err); if (local_err) { error_propagate(errp, local_err); return; diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index f03a80a29b..b777b78e18 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -92,7 +92,7 @@ enum { #define LPC_HC_REGS_OPB_SIZE 0x00001000 -static int pnv_lpc_populate(PnvXScomInterface *dev, void *fdt, int xscom_offset) +static int pnv_lpc_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset) { const char compat[] = "ibm,power8-lpc\0ibm,lpc"; char *name; @@ -482,7 +482,7 @@ static void pnv_lpc_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); - xdc->populate = pnv_lpc_populate; + xdc->dt_xscom = pnv_lpc_dt_xscom; dc->realize = pnv_lpc_realize; } @@ -515,7 +515,7 @@ type_init(pnv_lpc_register_types) */ static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) { - PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine()); + PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine()); uint32_t old_state = pnv->cpld_irqstate; PnvLpcController *lpc = PNV_LPC(opaque); diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 9876c26622..5b969127c3 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -510,7 +510,7 @@ static void pnv_psi_realize(DeviceState *dev, Error **errp) } } -static int pnv_psi_populate(PnvXScomInterface *dev, void *fdt, int xscom_offset) +static int pnv_psi_dt_xscom(PnvXScomInterface *dev, void *fdt, int xscom_offset) { const char compat[] = "ibm,power8-psihb-x\0ibm,psihb-x"; char *name; @@ -546,7 +546,7 @@ static void pnv_psi_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); - xdc->populate = pnv_psi_populate; + xdc->dt_xscom = pnv_psi_dt_xscom; dc->realize = pnv_psi_realize; dc->props = pnv_psi_properties; diff --git a/hw/ppc/pnv_xscom.c b/hw/ppc/pnv_xscom.c index 38bc85f117..e51d634f40 100644 --- a/hw/ppc/pnv_xscom.c +++ b/hw/ppc/pnv_xscom.c @@ -207,15 +207,15 @@ typedef struct ForeachPopulateArgs { int xscom_offset; } ForeachPopulateArgs; -static int xscom_populate_child(Object *child, void *opaque) +static int xscom_dt_child(Object *child, void *opaque) { if (object_dynamic_cast(child, TYPE_PNV_XSCOM_INTERFACE)) { ForeachPopulateArgs *args = opaque; PnvXScomInterface *xd = PNV_XSCOM_INTERFACE(child); PnvXScomInterfaceClass *xc = PNV_XSCOM_INTERFACE_GET_CLASS(xd); - if (xc->populate) { - _FDT((xc->populate(xd, args->fdt, args->xscom_offset))); + if (xc->dt_xscom) { + _FDT((xc->dt_xscom(xd, args->fdt, args->xscom_offset))); } } return 0; @@ -224,7 +224,7 @@ static int xscom_populate_child(Object *child, void *opaque) static const char compat_p8[] = "ibm,power8-xscom\0ibm,xscom"; static const char compat_p9[] = "ibm,power9-xscom\0ibm,xscom"; -int pnv_xscom_populate(PnvChip *chip, void *fdt, int root_offset) +int pnv_dt_xscom(PnvChip *chip, void *fdt, int root_offset) { uint64_t reg[] = { cpu_to_be64(PNV_XSCOM_BASE(chip)), cpu_to_be64(PNV_XSCOM_SIZE) }; @@ -255,7 +255,7 @@ int pnv_xscom_populate(PnvChip *chip, void *fdt, int root_offset) args.fdt = fdt; args.xscom_offset = xscom_offset; - object_child_foreach(OBJECT(chip), xscom_populate_child, &args); + object_child_foreach(OBJECT(chip), xscom_dt_child, &args); return 0; } diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index 59524cd42b..61896f9fd7 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -26,7 +26,7 @@ #include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_occ.h" -#define TYPE_PNV_CHIP "powernv-chip" +#define TYPE_PNV_CHIP "pnv-chip" #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP) #define PNV_CHIP_CLASS(klass) \ OBJECT_CLASS_CHECK(PnvChipClass, (klass), TYPE_PNV_CHIP) @@ -117,9 +117,9 @@ typedef struct PnvChipClass { #define PNV_CHIP_INDEX(chip) \ (((chip)->chip_id >> 2) * 2 + ((chip)->chip_id & 0x3)) -#define TYPE_POWERNV_MACHINE MACHINE_TYPE_NAME("powernv") -#define POWERNV_MACHINE(obj) \ - OBJECT_CHECK(PnvMachineState, (obj), TYPE_POWERNV_MACHINE) +#define TYPE_PNV_MACHINE MACHINE_TYPE_NAME("powernv") +#define PNV_MACHINE(obj) \ + OBJECT_CHECK(PnvMachineState, (obj), TYPE_PNV_MACHINE) typedef struct PnvMachineState { /*< private >*/ @@ -144,7 +144,7 @@ typedef struct PnvMachineState { /* * BMC helpers */ -void pnv_bmc_populate_sensors(IPMIBmc *bmc, void *fdt); +void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt); void pnv_bmc_powerdown(IPMIBmc *bmc); /* diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 38077b4796..7252e219e2 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -36,7 +36,7 @@ typedef struct PnvXScomInterface { typedef struct PnvXScomInterfaceClass { InterfaceClass parent; - int (*populate)(PnvXScomInterface *dev, void *fdt, int offset); + int (*dt_xscom)(PnvXScomInterface *dev, void *fdt, int offset); } PnvXScomInterfaceClass; /* @@ -67,7 +67,7 @@ typedef struct PnvXScomInterfaceClass { #define PNV_XSCOM_OCC_SIZE 0x6000 extern void pnv_xscom_realize(PnvChip *chip, Error **errp); -extern int pnv_xscom_populate(PnvChip *chip, void *fdt, int offset); +extern int pnv_dt_xscom(PnvChip *chip, void *fdt, int offset); extern void pnv_xscom_add_subregion(PnvChip *chip, hwaddr offset, MemoryRegion *mr); From a6a444a87aae0062ffed45374b93217ff3308a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Fri, 22 Dec 2017 10:55:51 +0100 Subject: [PATCH 516/546] target/ppc: more use of the PPC_*() macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also introduce utilities to manipulate bitmasks (originaly from OPAL) which be will be used in the model of the XIVE interrupt controller. Signed-off-by: Cédric Le Goater Signed-off-by: David Gibson --- hw/ppc/pnv_lpc.c | 10 ++++---- target/ppc/cpu.h | 56 +++++++++++++++++++++++++---------------- target/ppc/int_helper.c | 2 +- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index b777b78e18..c42b4a8f6c 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -146,13 +146,13 @@ static bool opb_write(PnvLpcController *lpc, uint32_t addr, uint8_t *data, return success; } -#define ECCB_CTL_READ (1ull << (63 - 15)) +#define ECCB_CTL_READ PPC_BIT(15) #define ECCB_CTL_SZ_LSH (63 - 7) -#define ECCB_CTL_SZ_MASK (0xfull << ECCB_CTL_SZ_LSH) -#define ECCB_CTL_ADDR_MASK 0xffffffffu; +#define ECCB_CTL_SZ_MASK PPC_BITMASK(4, 7) +#define ECCB_CTL_ADDR_MASK PPC_BITMASK(32, 63) -#define ECCB_STAT_OP_DONE (1ull << (63 - 52)) -#define ECCB_STAT_OP_ERR (1ull << (63 - 52)) +#define ECCB_STAT_OP_DONE PPC_BIT(52) +#define ECCB_STAT_OP_ERR PPC_BIT(52) #define ECCB_STAT_RD_DATA_LSH (63 - 37) #define ECCB_STAT_RD_DATA_MASK (0xffffffff << ECCB_STAT_RD_DATA_LSH) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 370b05e76e..a5e49f23e9 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -93,6 +93,19 @@ #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)) +#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be)) | PPC_BIT8(bs)) + +#if HOST_LONG_BITS == 32 +# define MASK_TO_LSH(m) (__builtin_ffsll(m) - 1) +#elif HOST_LONG_BITS == 64 +# define MASK_TO_LSH(m) (__builtin_ffsl(m) - 1) +#else +# error Unknown sizeof long +#endif + +#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m)) +#define SETFIELD(m, v, val) \ + (((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m))) /*****************************************************************************/ /* Exception vectors definitions */ @@ -2349,32 +2362,31 @@ enum { /* Processor Compatibility mask (PCR) */ enum { - PCR_COMPAT_2_05 = 1ull << (63-62), - PCR_COMPAT_2_06 = 1ull << (63-61), - PCR_COMPAT_2_07 = 1ull << (63-60), - PCR_COMPAT_3_00 = 1ull << (63-59), - PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */ - PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */ - PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */ + PCR_COMPAT_2_05 = PPC_BIT(62), + PCR_COMPAT_2_06 = PPC_BIT(61), + PCR_COMPAT_2_07 = PPC_BIT(60), + PCR_COMPAT_3_00 = PPC_BIT(59), + PCR_VEC_DIS = PPC_BIT(0), /* Vec. disable (bit NA since POWER8) */ + PCR_VSX_DIS = PPC_BIT(1), /* VSX disable (bit NA since POWER8) */ + PCR_TM_DIS = PPC_BIT(2), /* Trans. memory disable (POWER8) */ }; /* HMER/HMEER */ enum { - HMER_MALFUNCTION_ALERT = 1ull << (63 - 0), - HMER_PROC_RECV_DONE = 1ull << (63 - 2), - HMER_PROC_RECV_ERROR_MASKED = 1ull << (63 - 3), - HMER_TFAC_ERROR = 1ull << (63 - 4), - HMER_TFMR_PARITY_ERROR = 1ull << (63 - 5), - HMER_XSCOM_FAIL = 1ull << (63 - 8), - HMER_XSCOM_DONE = 1ull << (63 - 9), - HMER_PROC_RECV_AGAIN = 1ull << (63 - 11), - HMER_WARN_RISE = 1ull << (63 - 14), - HMER_WARN_FALL = 1ull << (63 - 15), - HMER_SCOM_FIR_HMI = 1ull << (63 - 16), - HMER_TRIG_FIR_HMI = 1ull << (63 - 17), - HMER_HYP_RESOURCE_ERR = 1ull << (63 - 20), - HMER_XSCOM_STATUS_MASK = 7ull << (63 - 23), - HMER_XSCOM_STATUS_LSH = (63 - 23), + HMER_MALFUNCTION_ALERT = PPC_BIT(0), + HMER_PROC_RECV_DONE = PPC_BIT(2), + HMER_PROC_RECV_ERROR_MASKED = PPC_BIT(3), + HMER_TFAC_ERROR = PPC_BIT(4), + HMER_TFMR_PARITY_ERROR = PPC_BIT(5), + HMER_XSCOM_FAIL = PPC_BIT(8), + HMER_XSCOM_DONE = PPC_BIT(9), + HMER_PROC_RECV_AGAIN = PPC_BIT(11), + HMER_WARN_RISE = PPC_BIT(14), + HMER_WARN_FALL = PPC_BIT(15), + HMER_SCOM_FIR_HMI = PPC_BIT(16), + HMER_TRIG_FIR_HMI = PPC_BIT(17), + HMER_HYP_RESOURCE_ERR = PPC_BIT(20), + HMER_XSCOM_STATUS_MASK = PPC_BITMASK(21, 23), }; /* Alternate Interrupt Location (AIL) */ diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 1c013a0ee3..3a50f1e1b7 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -183,7 +183,7 @@ uint64_t helper_bpermd(uint64_t rs, uint64_t rb) for (i = 0; i < 8; i++) { int index = (rs >> (i*8)) & 0xFF; if (index < 64) { - if (rb & (1ull << (63-index))) { + if (rb & PPC_BIT(index)) { ra |= 1 << i; } } From 307f3d015625e705dba0a0bd2735ce42118fd533 Mon Sep 17 00:00:00 2001 From: John Arbuckle Date: Thu, 4 Jan 2018 14:49:52 -0500 Subject: [PATCH 517/546] Update dtc to fix compilation problem on Mac OS 10.6 Currently QEMU does not build on Mac OS 10.6 because of a missing patch in the dtc subproject. Updating dtc to make the patch available fixes this problem. Signed-off-by: John Arbuckle Signed-off-by: David Gibson --- dtc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtc b/dtc index 558cd81bdd..e54388015a 160000 --- a/dtc +++ b/dtc @@ -1 +1 @@ -Subproject commit 558cd81bdd432769b59bff01240c44f82cfb1a9d +Subproject commit e54388015af1fb4bf04d0bca99caba1074d9cc42 From a7167668898d1a7dbb717fe1e6d5615bd229827c Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 3 Jan 2018 10:10:38 +0100 Subject: [PATCH 518/546] hw/ppc: Remove the deprecated spapr-pci-vfio-host-bridge device It's a deprecated dummy device since QEMU v2.6.0. That should have been enough time to allow the users to update their scripts in case they still use it, so let's remove this legacy code now. Reviewed-by: Alexey Kardashevskiy Signed-off-by: Thomas Huth Signed-off-by: David Gibson --- hw/ppc/spapr_pci_vfio.c | 47 --------------------------------------- qemu-doc.texi | 5 ----- scripts/device-crash-test | 1 - 3 files changed, 53 deletions(-) diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 1f775ea93d..053efb03bd 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -29,31 +29,6 @@ #include "qemu/error-report.h" #include "sysemu/qtest.h" -#define TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE "spapr-pci-vfio-host-bridge" - -#define SPAPR_PCI_VFIO_HOST_BRIDGE(obj) \ - OBJECT_CHECK(sPAPRPHBVFIOState, (obj), TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE) - -typedef struct sPAPRPHBVFIOState sPAPRPHBVFIOState; - -struct sPAPRPHBVFIOState { - sPAPRPHBState phb; - - int32_t iommugroupid; -}; - -static Property spapr_phb_vfio_properties[] = { - DEFINE_PROP_INT32("iommu", sPAPRPHBVFIOState, iommugroupid, -1), - DEFINE_PROP_END_OF_LIST(), -}; - -static void spapr_phb_vfio_instance_init(Object *obj) -{ - if (!qtest_enabled()) { - warn_report("spapr-pci-vfio-host-bridge is deprecated"); - } -} - bool spapr_phb_eeh_available(sPAPRPHBState *sphb) { return vfio_eeh_as_ok(&sphb->iommu_as); @@ -218,25 +193,3 @@ int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb) return RTAS_OUT_SUCCESS; } - -static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->props = spapr_phb_vfio_properties; -} - -static const TypeInfo spapr_phb_vfio_info = { - .name = TYPE_SPAPR_PCI_VFIO_HOST_BRIDGE, - .parent = TYPE_SPAPR_PCI_HOST_BRIDGE, - .instance_size = sizeof(sPAPRPHBVFIOState), - .instance_init = spapr_phb_vfio_instance_init, - .class_init = spapr_phb_vfio_class_init, -}; - -static void spapr_pci_vfio_register_types(void) -{ - type_register_static(&spapr_phb_vfio_info); -} - -type_init(spapr_pci_vfio_register_types) diff --git a/qemu-doc.texi b/qemu-doc.texi index 9d0159832e..a3d2054c90 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -2757,11 +2757,6 @@ The ``host_net_remove'' command is replaced by the ``netdev_del'' command. The ``ivshmem'' device type is replaced by either the ``ivshmem-plain'' or ``ivshmem-doorbell`` device types. -@subsection spapr-pci-vfio-host-bridge (since 2.6.0) - -The ``spapr-pci-vfio-host-bridge'' device type is replaced by -the ``spapr-pci-host-bridge'' device type. - @section System emulator machines @subsection Xilinx EP108 (since 2.11.0) diff --git a/scripts/device-crash-test b/scripts/device-crash-test index c11fd81c52..827d8ec2af 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -119,7 +119,6 @@ ERROR_WHITELIST = [ {'device':'scsi-generic', 'expected':True}, # drive property not set {'device':'scsi-hd', 'expected':True}, # drive property not set {'device':'spapr-pci-host-bridge', 'expected':True}, # BUID not specified for PHB - {'device':'spapr-pci-vfio-host-bridge', 'expected':True}, # BUID not specified for PHB {'device':'spapr-rng', 'expected':True}, # spapr-rng needs an RNG backend! {'device':'spapr-vty', 'expected':True}, # chardev property not set {'device':'tpm-tis', 'expected':True}, # tpm_tis: backend driver with id (null) could not be found From 51f84465dd985fc21589b2eac1f18658fc9783e9 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 4 Jan 2018 14:33:21 +1100 Subject: [PATCH 519/546] spapr: Correct compatibility mode setting for hotplugged CPUs Currently the pseries machine sets the compatibility mode for the guest's cpus in two places: 1) at machine reset and 2) after CAS negotiation. This means that if we set or negotiate a compatiblity mode, then hotplug a cpu, the hotplugged cpu doesn't get the right mode set and will incorrectly have the full native features. To correct this, we set the compatibility mode on a cpu when it is brought online with the 'start-cpu' RTAS call. Given that we no longer need to set the compatibility mode on all CPUs at machine reset, so we change that to only set the mode for the boot cpu. Signed-off-by: David Gibson Reported-by: Satheesh Rajendran Tested-by: Satheesh Rajendran Reviewed-by: Alexey Kardashevskiy --- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_rtas.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 6785a90c60..dfd352c473 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1504,7 +1504,7 @@ static void spapr_machine_reset(void) spapr_ovec_cleanup(spapr->ov5_cas); spapr->ov5_cas = spapr_ovec_new(); - ppc_set_compat_all(spapr->max_compat_pvr, &error_fatal); + ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal); } fdt = spapr_build_fdt(spapr, rtas_addr, spapr->rtas_size); diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 4bb939d3d1..2b89e1d448 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -163,6 +163,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + Error *local_err = NULL; if (!cs->halted) { rtas_st(rets, 0, RTAS_OUT_HW_ERROR); @@ -174,6 +175,14 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, * new cpu enters */ kvm_cpu_synchronize_state(cs); + /* Set compatibility mode to match existing cpus */ + ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &local_err); + if (local_err) { + error_report_err(local_err); + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ From 420a4e955909788263a33d11600839e93480dfd3 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 22 Nov 2017 13:19:57 +0300 Subject: [PATCH 520/546] nbd: rename nbd_option and nbd_opt_reply Rename nbd_option and nbd_opt_reply to NBDOption and NBDOptionReply to correspond to Qemu coding style and other structures here. Signed-off-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Eric Blake Message-Id: <20171122101958.17065-5-vsementsov@virtuozzo.com> Signed-off-by: Eric Blake --- include/block/nbd.h | 8 ++++---- nbd/client.c | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/block/nbd.h b/include/block/nbd.h index 113c707a5e..978e443366 100644 --- a/include/block/nbd.h +++ b/include/block/nbd.h @@ -28,20 +28,20 @@ /* Handshake phase structs - this struct is passed on the wire */ -struct nbd_option { +struct NBDOption { uint64_t magic; /* NBD_OPTS_MAGIC */ uint32_t option; /* NBD_OPT_* */ uint32_t length; } QEMU_PACKED; -typedef struct nbd_option nbd_option; +typedef struct NBDOption NBDOption; -struct nbd_opt_reply { +struct NBDOptionReply { uint64_t magic; /* NBD_REP_MAGIC */ uint32_t option; /* NBD_OPT_* */ uint32_t type; /* NBD_REP_* */ uint32_t length; } QEMU_PACKED; -typedef struct nbd_opt_reply nbd_opt_reply; +typedef struct NBDOptionReply NBDOptionReply; /* Transmission phase structs * diff --git a/nbd/client.c b/nbd/client.c index eea236ca06..89f80f9590 100644 --- a/nbd/client.c +++ b/nbd/client.c @@ -66,7 +66,7 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt, uint32_t len, const char *data, Error **errp) { - nbd_option req; + NBDOption req; QEMU_BUILD_BUG_ON(sizeof(req) != 16); if (len == -1) { @@ -109,7 +109,7 @@ static void nbd_send_opt_abort(QIOChannel *ioc) * payload. Return 0 if successful, -1 with errp set if it is * impossible to continue. */ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, - nbd_opt_reply *reply, Error **errp) + NBDOptionReply *reply, Error **errp) { QEMU_BUILD_BUG_ON(sizeof(*reply) != 20); if (nbd_read(ioc, reply, sizeof(*reply), errp) < 0) { @@ -146,7 +146,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt, * can fall back to other approaches), or -1 with errp set for other * errors. */ -static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, +static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply, Error **errp) { char *msg = NULL; @@ -239,7 +239,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply, static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, Error **errp) { - nbd_opt_reply reply; + NBDOptionReply reply; uint32_t len; uint32_t namelen; char name[NBD_MAX_NAME_SIZE + 1]; @@ -325,7 +325,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match, static int nbd_opt_go(QIOChannel *ioc, const char *wantname, NBDExportInfo *info, Error **errp) { - nbd_opt_reply reply; + NBDOptionReply reply; uint32_t len = strlen(wantname); uint16_t type; int error; @@ -517,7 +517,7 @@ static int nbd_receive_query_exports(QIOChannel *ioc, */ static int nbd_request_simple_option(QIOChannel *ioc, int opt, Error **errp) { - nbd_opt_reply reply; + NBDOptionReply reply; int error; if (nbd_send_option_request(ioc, opt, 0, NULL, errp) < 0) { From dfdcf34031db02eb8d81dd3b1c3415ec900c40bb Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 521/546] linux-user: Add support for big-endian aarch64 Enable big-endian mode for data accesses on aarch64 for big-endian linux user mode. Activate it for all exception levels as documented by ARM: Set the SCTLR EE bit for ELs 1 through 3. Additionally set bit E0E in EL1 to enable it in EL0 as well. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Message-id: 20171220212308.12614-2-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/main.c b/linux-user/main.c index 99a551b04f..450eb3ce65 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -4629,6 +4629,12 @@ int main(int argc, char **argv, char **envp) } env->pc = regs->pc; env->xregs[31] = regs->sp; +#ifdef TARGET_WORDS_BIGENDIAN + env->cp15.sctlr_el[1] |= SCTLR_E0E; + for (i = 1; i < 4; ++i) { + env->cp15.sctlr_el[i] |= SCTLR_EE; + } +#endif } #elif defined(TARGET_ARM) { From cb3aa5fea19cdc108baf6c3aff2e768bf9475b50 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 522/546] linux-user: Add separate aarch64_be uname Make big-endian aarch64 systems identify as aarch64_be as expected by big-endian userland and toolchains. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-3-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/aarch64/target_syscall.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h index 1b62953eeb..604ab99b14 100644 --- a/linux-user/aarch64/target_syscall.h +++ b/linux-user/aarch64/target_syscall.h @@ -8,7 +8,11 @@ struct target_pt_regs { uint64_t pstate; }; +#if defined(TARGET_WORDS_BIGENDIAN) +#define UNAME_MACHINE "aarch64_be" +#else #define UNAME_MACHINE "aarch64" +#endif #define UNAME_MINIMUM_RELEASE "3.8.0" #define TARGET_CLONE_BACKWARDS #define TARGET_MINSIGSTKSZ 2048 From 50f22fa60d95c04a179e2cbf4b5f58d1f6068b61 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:31 +0000 Subject: [PATCH 523/546] linux-user: Fix endianess of aarch64 signal trampoline Since for aarch64 the signal trampoline is synthesized directly into the signal frame we need to make sure the instructions end up little-endian. Otherwise the wrong endianness will cause a SIGILL upon return from the signal handler on big-endian targets. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Message-id: 20171220212308.12614-4-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- linux-user/signal.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/linux-user/signal.c b/linux-user/signal.c index 74fa03f96d..f85f0dd780 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1599,9 +1599,13 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, if (ka->sa_flags & TARGET_SA_RESTORER) { return_addr = ka->sa_restorer; } else { - /* mov x8,#__NR_rt_sigreturn; svc #0 */ - __put_user(0xd2801168, &frame->tramp[0]); - __put_user(0xd4000001, &frame->tramp[1]); + /* + * mov x8,#__NR_rt_sigreturn; svc #0 + * Since these are instructions they need to be put as little-endian + * regardless of target default or current CPU endianness. + */ + __put_user_e(0xd2801168, &frame->tramp[0], le); + __put_user_e(0xd4000001, &frame->tramp[1], le); return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp); } env->xregs[0] = usig; From 722dd7be8c5a9bc73e0a19be1418046ed043ce0b Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:32 +0000 Subject: [PATCH 524/546] configure: Add aarch64_be-linux-user target Add target aarch64_be-linux-user. This allows a qemu-aarch64_be binary to be built that will run big-endian aarch64 binaries. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-5-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- configure | 5 +++-- default-configs/aarch64_be-linux-user.mak | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 default-configs/aarch64_be-linux-user.mak diff --git a/configure b/configure index 6a040821c6..89bd662a6a 100755 --- a/configure +++ b/configure @@ -6439,7 +6439,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + armeb|aarch64_be|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -6494,7 +6494,8 @@ case "$target_name" in mttcg="yes" gdb_xml_files="arm-core.xml arm-vfp.xml arm-vfp3.xml arm-neon.xml" ;; - aarch64) + aarch64|aarch64_be) + TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm bflt="yes" mttcg="yes" diff --git a/default-configs/aarch64_be-linux-user.mak b/default-configs/aarch64_be-linux-user.mak new file mode 100644 index 0000000000..a69d9d2e41 --- /dev/null +++ b/default-configs/aarch64_be-linux-user.mak @@ -0,0 +1 @@ +# Default configuration for aarch64_be-linux-user From f772f212b39a79b4510b0e9b403714cc03dae9b9 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:32 +0000 Subject: [PATCH 525/546] linux-user: Add aarch64_be magic numbers to qemu-binfmt-conf.sh As we now have a linux-user aarch64_be target, we can add it to the list of supported targets in qemu-binfmt-conf.sh Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-6-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 8afc3eb5bb..d69953525c 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -4,7 +4,7 @@ qemu_target_list="i386 i486 alpha arm sparc32plus ppc ppc64 ppc64le m68k \ mips mipsel mipsn32 mipsn32el mips64 mips64el \ -sh4 sh4eb s390x aarch64 hppa" +sh4 sh4eb s390x aarch64 aarch64_be hppa" i386_magic='\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00' i386_mask='\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' @@ -92,6 +92,10 @@ aarch64_magic='\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x aarch64_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff' aarch64_family=arm +aarch64_be_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7' +aarch64_be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' +aarch64_be_family=arm + hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f' hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' hppa_family=hppa From 2ced93eee04ac636387233c64720d0f764d8d24d Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 526/546] linux-user: Separate binfmt arm CPU families Give big-endian arm and aarch64 CPUs their own family in qemu-binfmt-conf.sh to make sure we register qemu-user for binaries of the opposite endianness on arm and aarch64. Apart from the family assignments of the magic values, qemu_get_family() needs to be able to distinguish the two and recognise aarch64{,_be} as well. Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-7-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index d69953525c..597efdbe50 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -24,7 +24,7 @@ arm_family=arm armeb_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28' armeb_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' -armeb_family=arm +armeb_family=armeb sparc_magic='\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02' sparc_mask='\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' @@ -94,7 +94,7 @@ aarch64_family=arm aarch64_be_magic='\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7' aarch64_be_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' -aarch64_be_family=arm +aarch64_be_family=armeb hppa_magic='\x7f\x45\x4c\x46\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x0f' hppa_mask='\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff' @@ -115,9 +115,12 @@ qemu_get_family() { ppc64el|ppc64le) echo "ppcle" ;; - arm|armel|armhf|arm64|armv[4-9]*) + arm|armel|armhf|arm64|armv[4-9]*l|aarch64) echo "arm" ;; + armeb|armv[4-9]*b|aarch64_be) + echo "armeb" + ;; sparc*) echo "sparc" ;; From bfe69cc867dfef4b8af348f1f7e36b2727283c4c Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 527/546] linux-user: Activate armeb handler registration armeb is missing from the target list in qemu-binfmt-conf.sh. Add it so the handler for those binaries gets registered by the script. Signed-off-by: Michael Weiser Reviewed-by: Laurent Vivier Message-id: 20171220212308.12614-8-michael.weiser@gmx.de Signed-off-by: Peter Maydell --- scripts/qemu-binfmt-conf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/qemu-binfmt-conf.sh b/scripts/qemu-binfmt-conf.sh index 597efdbe50..ea5a748745 100755 --- a/scripts/qemu-binfmt-conf.sh +++ b/scripts/qemu-binfmt-conf.sh @@ -2,7 +2,7 @@ # enable automatic i386/ARM/M68K/MIPS/SPARC/PPC/s390/HPPA # program execution by the kernel -qemu_target_list="i386 i486 alpha arm sparc32plus ppc ppc64 ppc64le m68k \ +qemu_target_list="i386 i486 alpha arm armeb sparc32plus ppc ppc64 ppc64le m68k \ mips mipsel mipsn32 mipsn32el mips64 mips64el \ sh4 sh4eb s390x aarch64 aarch64_be hppa" From 0785557f8811133bd69be02aeccf018d47a26373 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 11 Jan 2018 13:25:33 +0000 Subject: [PATCH 528/546] target/arm: Fix stlxp for aarch64_be ldxp loads two consecutive doublewords from memory regardless of CPU endianness. On store, stlxp currently assumes to work with a 128bit value and consequently switches order in big-endian mode. With this change it packs the doublewords in reverse order in anticipation of the 128bit big-endian store operation interposing them so they end up in memory in the right order. This makes it work for both MTTCG and !MTTCG. It effectively implements the ARM ARM STLXP operation pseudo-code: data = if BigEndian() then el1:el2 else el2:el1; With this change an aarch64_be Linux 4.14.4 kernel succeeds to boot up in system emulation mode. Signed-off-by: Michael Weiser Reviewed-by: Richard Henderson Signed-off-by: Peter Maydell --- target/arm/helper-a64.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c index b84ebcae6e..3e00a9ead1 100644 --- a/target/arm/helper-a64.c +++ b/target/arm/helper-a64.c @@ -506,8 +506,11 @@ static uint64_t do_paired_cmpxchg64_be(CPUARMState *env, uint64_t addr, Int128 oldv, cmpv, newv; bool success; - cmpv = int128_make128(env->exclusive_val, env->exclusive_high); - newv = int128_make128(new_lo, new_hi); + /* high and low need to be switched here because this is not actually a + * 128bit store but two doublewords stored consecutively + */ + cmpv = int128_make128(env->exclusive_high, env->exclusive_val); + newv = int128_make128(new_hi, new_lo); if (parallel) { #ifndef CONFIG_ATOMIC128 From 4d027afeb3a9781bf15ad30d43d07a02c2b08c73 Mon Sep 17 00:00:00 2001 From: Zhaoshenglong Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: [PATCH 529/546] Virt: ACPI: fix qemu assert due to re-assigned table data address acpi_data_push uses g_array_set_size to resize the memory size. If there is no enough contiguous memory, the address will be changed. If we use the old value, it will assert. qemu-kvm: hw/acpi/bios-linker-loader.c:214: bios_linker_loader_add_checksum: Assertion `start_offset < file->blob->len' failed.` This issue only happens in building SRAT table now but here we unify the pattern for other tables as well to avoid possible issues in the future. Signed-off-by: Zhaoshenglong Reviewed-by: Andrew Jones Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index 3d78ff68e6..f7fa795278 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -453,6 +453,7 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AcpiSerialPortConsoleRedirection *spcr; const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART]; int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE; + int spcr_start = table_data->len; spcr = acpi_data_push(table_data, sizeof(*spcr)); @@ -476,8 +477,8 @@ build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ - build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2, - NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + spcr_start), + "SPCR", table_data->len - spcr_start, 2, NULL, NULL); } static void @@ -512,8 +513,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) mem_base += numa_info[i].node_mem; } - build_header(linker, table_data, (void *)srat, "SRAT", - table_data->len - srat_start, 3, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + srat_start), + "SRAT", table_data->len - srat_start, 3, NULL, NULL); } static void @@ -522,6 +523,7 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) AcpiTableMcfg *mcfg; const MemMapEntry *memmap = vms->memmap; int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); + int mcfg_start = table_data->len; mcfg = acpi_data_push(table_data, len); mcfg->allocation[0].address = cpu_to_le64(memmap[VIRT_PCIE_ECAM].base); @@ -532,7 +534,8 @@ build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) mcfg->allocation[0].end_bus_number = (memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN) - 1; - build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + mcfg_start), + "MCFG", table_data->len - mcfg_start, 1, NULL, NULL); } /* GTDT */ @@ -651,6 +654,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) static void build_fadt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms, unsigned dsdt_tbl_offset) { + int fadt_start = table_data->len; AcpiFadtDescriptorRev5_1 *fadt = acpi_data_push(table_data, sizeof(*fadt)); unsigned xdsdt_entry_offset = (char *)&fadt->x_dsdt - table_data->data; uint16_t bootflags; @@ -681,8 +685,8 @@ static void build_fadt(GArray *table_data, BIOSLinker *linker, ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->x_dsdt), ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset); - build_header(linker, table_data, - (void *)fadt, "FACP", sizeof(*fadt), 5, NULL, NULL); + build_header(linker, table_data, (void *)(table_data->data + fadt_start), + "FACP", table_data->len - fadt_start, 5, NULL, NULL); } /* DSDT */ From 1fdde6537ecec4a6b416bc232c868b64d645cc62 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:34 +0000 Subject: [PATCH 530/546] imx_fec: Do not link to netdev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binding to a particular netdev doesn't seem to belong to this layer and should probably be done as a part of board or SoC specific code. Convert all of the users of this IP block to use qdev_set_nic_properties() instead. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/arm/fsl-imx6.c | 1 + hw/net/imx_fec.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index 59ef33efa9..b0d4088290 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -385,6 +385,7 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp) spi_table[i].irq)); } + qdev_set_nic_properties(DEVICE(&s->eth), &nd_table[0]); object_property_set_bool(OBJECT(&s->eth), true, "realized", &err); if (err) { error_propagate(errp, err); diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 90e6ee35ba..88b4b049d7 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1171,8 +1171,6 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->conf.peers.ncs[0] = nd_table[0].netdev; - s->nic = qemu_new_nic(&imx_eth_net_info, &s->conf, object_get_typename(OBJECT(dev)), DEVICE(dev)->id, s); From a6383e99ffc3b615d8465aebbd5d48f1fa9b2949 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 531/546] imx_fec: Refactor imx_eth_enable_rx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor imx_eth_enable_rx() to have more meaningfull variable name than 'tmp' and to reduce number of logical negations done. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 88b4b049d7..8b2e4b8ffe 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -536,19 +536,19 @@ static void imx_eth_do_tx(IMXFECState *s) static void imx_eth_enable_rx(IMXFECState *s) { IMXFECBufDesc bd; - bool tmp; + bool rx_ring_full; imx_fec_read_bd(&bd, s->rx_descriptor); - tmp = ((bd.flags & ENET_BD_E) != 0); + rx_ring_full = !(bd.flags & ENET_BD_E); - if (!tmp) { + if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); } else if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } - s->regs[ENET_RDAR] = tmp ? ENET_RDAR_RDAR : 0; + s->regs[ENET_RDAR] = rx_ring_full ? 0 : ENET_RDAR_RDAR; } static void imx_eth_reset(DeviceState *d) From b2b012afdd9c03ba8a1619f45301d34f358d367b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 532/546] imx_fec: Change queue flushing heuristics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In current implementation, packet queue flushing logic seem to suffer from a deadlock like scenario if a packet is received by the interface before before Rx ring is initialized by Guest's driver. Consider the following sequence of events: 1. A QEMU instance is started against a TAP device on Linux host, running Linux guest, e. g., something to the effect of: qemu-system-arm \ -net nic,model=imx.fec,netdev=lan0 \ netdev tap,id=lan0,ifname=tap0,script=no,downscript=no \ ... rest of the arguments ... 2. Once QEMU starts, but before guest reaches the point where FEC deriver is done initializing the HW, Guest, via TAP interface, receives a number of multicast MDNS packets from Host (not necessarily true for every OS, but it happens at least on Fedora 25) 3. Recieving a packet in such a state results in imx_eth_can_receive() returning '0', which in turn causes tap_send() to disable corresponding event (tap.c:203) 4. Once Guest's driver reaches the point where it is ready to recieve packets it prepares Rx ring descriptors and writes ENET_RDAR_RDAR to ENET_RDAR register to indicate to HW that more descriptors are ready. And at this points emulation layer does this: s->regs[index] = ENET_RDAR_RDAR; imx_eth_enable_rx(s); which, combined with: if (!s->regs[ENET_RDAR]) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } results in Rx queue never being flushed and corresponding I/O event beign disabled. To prevent the problem, change the code to always flush packet queue when ENET_RDAR transitions 0 -> ENET_RDAR_RDAR. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 8b2e4b8ffe..eb034ffd0c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -533,7 +533,7 @@ static void imx_eth_do_tx(IMXFECState *s) } } -static void imx_eth_enable_rx(IMXFECState *s) +static void imx_eth_enable_rx(IMXFECState *s, bool flush) { IMXFECBufDesc bd; bool rx_ring_full; @@ -544,7 +544,7 @@ static void imx_eth_enable_rx(IMXFECState *s) if (rx_ring_full) { FEC_PRINTF("RX buffer full\n"); - } else if (!s->regs[ENET_RDAR]) { + } else if (flush) { qemu_flush_queued_packets(qemu_get_queue(s->nic)); } @@ -807,7 +807,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { if (!s->regs[index]) { s->regs[index] = ENET_RDAR_RDAR; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, true); } } else { s->regs[index] = 0; @@ -930,7 +930,7 @@ static int imx_eth_can_receive(NetClientState *nc) FEC_PRINTF("\n"); - return s->regs[ENET_RDAR] ? 1 : 0; + return !!s->regs[ENET_RDAR]; } static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, @@ -1020,7 +1020,7 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } @@ -1116,7 +1116,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, } } s->rx_descriptor = addr; - imx_eth_enable_rx(s); + imx_eth_enable_rx(s, false); imx_eth_update(s); return len; } From 7bac20dc5111963083686743dee00e0ae4fd976b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:35 +0000 Subject: [PATCH 533/546] imx_fec: Move Tx frame buffer away from the stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make Tx frame assembly buffer to be a paort of IMXFECState structure to avoid a concern about having large data buffer on the stack. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 22 +++++++++++----------- include/hw/net/imx_fec.h | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index eb034ffd0c..56cb72273c 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -405,8 +405,7 @@ static void imx_eth_update(IMXFECState *s) static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -431,8 +430,8 @@ static void imx_fec_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, frame_size); - ptr = frame; + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); + ptr = s->frame; frame_size = 0; s->regs[ENET_EIR] |= ENET_INT_TXF; } @@ -456,8 +455,7 @@ static void imx_fec_do_tx(IMXFECState *s) static void imx_enet_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; - uint8_t frame[ENET_MAX_FRAME_SIZE]; - uint8_t *ptr = frame; + uint8_t *ptr = s->frame; uint32_t addr = s->tx_descriptor; while (descnt++ < IMX_MAX_DESC) { @@ -482,13 +480,13 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size += len; if (bd.flags & ENET_BD_L) { if (bd.option & ENET_BD_PINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); if (IP_HEADER_VERSION(ip_hd) == 4) { - net_checksum_calculate(frame, frame_size); + net_checksum_calculate(s->frame, frame_size); } } if (bd.option & ENET_BD_IINS) { - struct ip_header *ip_hd = PKT_GET_IP_HDR(frame); + struct ip_header *ip_hd = PKT_GET_IP_HDR(s->frame); /* We compute checksum only for IPv4 frames */ if (IP_HEADER_VERSION(ip_hd) == 4) { uint16_t csum; @@ -498,8 +496,10 @@ static void imx_enet_do_tx(IMXFECState *s) } } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), frame, len); - ptr = frame; + + qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + ptr = s->frame; + frame_size = 0; if (bd.option & ENET_BD_TX_INT) { s->regs[ENET_EIR] |= ENET_INT_TXF; diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 62ad473b05..67993870a2 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -252,6 +252,9 @@ typedef struct IMXFECState { uint32_t phy_int_mask; bool is_fec; + + /* Buffer used to assemble a Tx frame */ + uint8_t frame[ENET_MAX_FRAME_SIZE]; } IMXFECState; #endif From ff9a7feeab59323d70a9377e9196f042b0647d66 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: [PATCH 534/546] imx_fec: Use ENET_FTRL to determine truncation length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frame truncation length, TRUNC_FL, is determined by the contents of ENET_FTRL register, so convert the code to use it instead of a hardcoded constant. To avoid the case where TRUNC_FL is greater that ENET_MAX_FRAME_SIZE, increase the value of the latter to its theoretical maximum of 16K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Signed-off-by: Andrey Smirnov Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 4 ++-- include/hw/net/imx_fec.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 56cb72273c..50da91bf9e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1052,8 +1052,8 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc_ptr = (uint8_t *) &crc; /* Huge frames are truncted. */ - if (size > ENET_MAX_FRAME_SIZE) { - size = ENET_MAX_FRAME_SIZE; + if (size > s->regs[ENET_FTRL]) { + size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; } diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 67993870a2..a390d704a6 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -86,7 +86,6 @@ #define ENET_TCCR3 393 #define ENET_MAX 400 -#define ENET_MAX_FRAME_SIZE 2032 /* EIR and EIMR */ #define ENET_INT_HB (1 << 31) @@ -155,6 +154,8 @@ #define ENET_RCR_NLC (1 << 30) #define ENET_RCR_GRS (1 << 31) +#define ENET_MAX_FRAME_SIZE (1 << ENET_RCR_MAX_FL_LENGTH) + /* TCR */ #define ENET_TCR_GTS (1 << 0) #define ENET_TCR_FDEN (1 << 2) From 4c5e7a6cdae78ed823042375824ced09cccefbdb Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:36 +0000 Subject: [PATCH 535/546] imx_fec: Use MIN instead of explicit ternary operator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 50da91bf9e..6feda18742 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1076,7 +1076,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, TYPE_IMX_FEC, __func__); break; } - buf_len = (size <= s->regs[ENET_MRBR]) ? size : s->regs[ENET_MRBR]; + buf_len = MIN(size, s->regs[ENET_MRBR]); bd.length = buf_len; size -= buf_len; From ebdd8cddb9e657ef75024b4cc9057dd4ce397a55 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 536/546] imx_fec: Emulate SHIFT16 in ENETx_RACC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed to support latest Linux kernel driver which relies on that functionality. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 23 +++++++++++++++++++++++ include/hw/net/imx_fec.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6feda18742..825c879a28 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1037,6 +1037,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, uint8_t *crc_ptr; unsigned int buf_len; size_t size = len; + bool shift16 = s->regs[ENET_RACC] & ENET_RACC_SHIFT16; FEC_PRINTF("len %d\n", (int)size); @@ -1051,6 +1052,10 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, crc = cpu_to_be32(crc32(~0, buf, size)); crc_ptr = (uint8_t *) &crc; + if (shift16) { + size += 2; + } + /* Huge frames are truncted. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; @@ -1087,6 +1092,24 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, buf_len += size - 4; } buf_addr = bd.data; + + if (shift16) { + /* + * If SHIFT16 bit of ENETx_RACC register is set we need to + * align the payload to 4-byte boundary. + */ + const uint8_t zeros[2] = { 0 }; + + dma_memory_write(&address_space_memory, buf_addr, + zeros, sizeof(zeros)); + + buf_addr += sizeof(zeros); + buf_len -= sizeof(zeros); + + /* We only do this once per Ethernet frame */ + shift16 = false; + } + dma_memory_write(&address_space_memory, buf_addr, buf, buf_len); buf += buf_len; if (size < 4) { diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index a390d704a6..af0840a0fa 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -170,6 +170,8 @@ #define ENET_TWFR_TFWR_LENGTH (6) #define ENET_TWFR_STRFWD (1 << 8) +#define ENET_RACC_SHIFT16 BIT(7) + /* Buffer Descriptor. */ typedef struct { uint16_t length; From f93f961c40a31228e3f66e66d99a68937aa242c5 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 537/546] imx_fec: Add support for multiple Tx DMA rings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More recent version of the IP block support more than one Tx DMA ring, so add the code implementing that feature. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 133 +++++++++++++++++++++++++++++++++------ include/hw/net/imx_fec.h | 18 +++++- 2 files changed, 130 insertions(+), 21 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 825c879a28..77d27f763e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -196,6 +196,31 @@ static const char *imx_eth_reg_name(IMXFECState *s, uint32_t index) } } +/* + * Versions of this device with more than one TX descriptor save the + * 2nd and 3rd descriptors in a subsection, to maintain migration + * compatibility with previous versions of the device that only + * supported a single descriptor. + */ +static bool imx_eth_is_multi_tx_ring(void *opaque) +{ + IMXFECState *s = IMX_FEC(opaque); + + return s->tx_ring_num > 1; +} + +static const VMStateDescription vmstate_imx_eth_txdescs = { + .name = "imx.fec/txdescs", + .version_id = 1, + .minimum_version_id = 1, + .needed = imx_eth_is_multi_tx_ring, + .fields = (VMStateField[]) { + VMSTATE_UINT32(tx_descriptor[1], IMXFECState), + VMSTATE_UINT32(tx_descriptor[2], IMXFECState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_imx_eth = { .name = TYPE_IMX_FEC, .version_id = 2, @@ -203,15 +228,18 @@ static const VMStateDescription vmstate_imx_eth = { .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, IMXFECState, ENET_MAX), VMSTATE_UINT32(rx_descriptor, IMXFECState), - VMSTATE_UINT32(tx_descriptor, IMXFECState), - + VMSTATE_UINT32(tx_descriptor[0], IMXFECState), VMSTATE_UINT32(phy_status, IMXFECState), VMSTATE_UINT32(phy_control, IMXFECState), VMSTATE_UINT32(phy_advertise, IMXFECState), VMSTATE_UINT32(phy_int, IMXFECState), VMSTATE_UINT32(phy_int_mask, IMXFECState), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription * []) { + &vmstate_imx_eth_txdescs, + NULL + }, }; #define PHY_INT_ENERGYON (1 << 7) @@ -406,7 +434,7 @@ static void imx_fec_do_tx(IMXFECState *s) { int frame_size = 0, descnt = 0; uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr = s->tx_descriptor[0]; while (descnt++ < IMX_MAX_DESC) { IMXFECBufDesc bd; @@ -447,16 +475,47 @@ static void imx_fec_do_tx(IMXFECState *s) } } - s->tx_descriptor = addr; + s->tx_descriptor[0] = addr; imx_eth_update(s); } -static void imx_enet_do_tx(IMXFECState *s) +static void imx_enet_do_tx(IMXFECState *s, uint32_t index) { int frame_size = 0, descnt = 0; + uint8_t *ptr = s->frame; - uint32_t addr = s->tx_descriptor; + uint32_t addr, int_txb, int_txf, tdsr; + size_t ring; + + switch (index) { + case ENET_TDAR: + ring = 0; + int_txb = ENET_INT_TXB; + int_txf = ENET_INT_TXF; + tdsr = ENET_TDSR; + break; + case ENET_TDAR1: + ring = 1; + int_txb = ENET_INT_TXB1; + int_txf = ENET_INT_TXF1; + tdsr = ENET_TDSR1; + break; + case ENET_TDAR2: + ring = 2; + int_txb = ENET_INT_TXB2; + int_txf = ENET_INT_TXF2; + tdsr = ENET_TDSR2; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bogus value for index %x\n", + __func__, index); + abort(); + break; + } + + addr = s->tx_descriptor[ring]; while (descnt++ < IMX_MAX_DESC) { IMXENETBufDesc bd; @@ -502,32 +561,32 @@ static void imx_enet_do_tx(IMXFECState *s) frame_size = 0; if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXF; + s->regs[ENET_EIR] |= int_txf; } } if (bd.option & ENET_BD_TX_INT) { - s->regs[ENET_EIR] |= ENET_INT_TXB; + s->regs[ENET_EIR] |= int_txb; } bd.flags &= ~ENET_BD_R; /* Write back the modified descriptor. */ imx_enet_write_bd(&bd, addr); /* Advance to the next descriptor. */ if ((bd.flags & ENET_BD_W) != 0) { - addr = s->regs[ENET_TDSR]; + addr = s->regs[tdsr]; } else { addr += sizeof(bd); } } - s->tx_descriptor = addr; + s->tx_descriptor[ring] = addr; imx_eth_update(s); } -static void imx_eth_do_tx(IMXFECState *s) +static void imx_eth_do_tx(IMXFECState *s, uint32_t index) { if (!s->is_fec && (s->regs[ENET_ECR] & ENET_ECR_EN1588)) { - imx_enet_do_tx(s); + imx_enet_do_tx(s, index); } else { imx_fec_do_tx(s); } @@ -585,7 +644,7 @@ static void imx_eth_reset(DeviceState *d) } s->rx_descriptor = 0; - s->tx_descriptor = 0; + memset(s->tx_descriptor, 0, sizeof(s->tx_descriptor)); /* We also reset the PHY */ phy_reset(s); @@ -791,6 +850,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { IMXFECState *s = IMX_FEC(opaque); + const bool single_tx_ring = !imx_eth_is_multi_tx_ring(s); uint32_t index = offset >> 2; FEC_PRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx_eth_reg_name(s, index), @@ -813,10 +873,18 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, s->regs[index] = 0; } break; - case ENET_TDAR: + case ENET_TDAR1: /* FALLTHROUGH */ + case ENET_TDAR2: /* FALLTHROUGH */ + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDAR2 or TDAR1\n", + TYPE_IMX_FEC, __func__); + return; + } + case ENET_TDAR: /* FALLTHROUGH */ if (s->regs[ENET_ECR] & ENET_ECR_ETHEREN) { s->regs[index] = ENET_TDAR_TDAR; - imx_eth_do_tx(s); + imx_eth_do_tx(s, index); } s->regs[index] = 0; break; @@ -828,8 +896,12 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, if ((s->regs[index] & ENET_ECR_ETHEREN) == 0) { s->regs[ENET_RDAR] = 0; s->rx_descriptor = s->regs[ENET_RDSR]; - s->regs[ENET_TDAR] = 0; - s->tx_descriptor = s->regs[ENET_TDSR]; + s->regs[ENET_TDAR] = 0; + s->regs[ENET_TDAR1] = 0; + s->regs[ENET_TDAR2] = 0; + s->tx_descriptor[0] = s->regs[ENET_TDSR]; + s->tx_descriptor[1] = s->regs[ENET_TDSR1]; + s->tx_descriptor[2] = s->regs[ENET_TDSR2]; } break; case ENET_MMFR: @@ -907,7 +979,29 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, } else { s->regs[index] = value & ~7; } - s->tx_descriptor = s->regs[index]; + s->tx_descriptor[0] = s->regs[index]; + break; + case ENET_TDSR1: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR1\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[1] = s->regs[index]; + break; + case ENET_TDSR2: + if (unlikely(single_tx_ring)) { + qemu_log_mask(LOG_GUEST_ERROR, + "[%s]%s: trying to access TDSR2\n", + TYPE_IMX_FEC, __func__); + return; + } + + s->regs[index] = value & ~7; + s->tx_descriptor[2] = s->regs[index]; break; case ENET_MRBR: s->regs[index] = value & 0x00003ff0; @@ -1203,6 +1297,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) static Property imx_eth_properties[] = { DEFINE_NIC_PROPERTIES(IMXFECState, conf), + DEFINE_PROP_UINT32("tx-ring-num", IMXFECState, tx_ring_num, 1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index af0840a0fa..91ef8f89a6 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -52,6 +52,8 @@ #define ENET_TFWR 81 #define ENET_FRBR 83 #define ENET_FRSR 84 +#define ENET_TDSR1 89 +#define ENET_TDSR2 92 #define ENET_RDSR 96 #define ENET_TDSR 97 #define ENET_MRBR 98 @@ -66,6 +68,8 @@ #define ENET_FTRL 108 #define ENET_TACC 112 #define ENET_RACC 113 +#define ENET_TDAR1 121 +#define ENET_TDAR2 123 #define ENET_MIIGSK_CFGR 192 #define ENET_MIIGSK_ENR 194 #define ENET_ATCR 256 @@ -105,13 +109,18 @@ #define ENET_INT_WAKEUP (1 << 17) #define ENET_INT_TS_AVAIL (1 << 16) #define ENET_INT_TS_TIMER (1 << 15) +#define ENET_INT_TXF2 (1 << 7) +#define ENET_INT_TXB2 (1 << 6) +#define ENET_INT_TXF1 (1 << 3) +#define ENET_INT_TXB1 (1 << 2) #define ENET_INT_MAC (ENET_INT_HB | ENET_INT_BABR | ENET_INT_BABT | \ ENET_INT_GRA | ENET_INT_TXF | ENET_INT_TXB | \ ENET_INT_RXF | ENET_INT_RXB | ENET_INT_MII | \ ENET_INT_EBERR | ENET_INT_LC | ENET_INT_RL | \ ENET_INT_UN | ENET_INT_PLR | ENET_INT_WAKEUP | \ - ENET_INT_TS_AVAIL) + ENET_INT_TS_AVAIL | ENET_INT_TXF1 | \ + ENET_INT_TXB1 | ENET_INT_TXF2 | ENET_INT_TXB2) /* RDAR */ #define ENET_RDAR_RDAR (1 << 24) @@ -234,6 +243,9 @@ typedef struct { #define ENET_BD_BDU (1 << 31) +#define ENET_TX_RING_NUM 3 + + typedef struct IMXFECState { /*< private >*/ SysBusDevice parent_obj; @@ -246,7 +258,9 @@ typedef struct IMXFECState { uint32_t regs[ENET_MAX]; uint32_t rx_descriptor; - uint32_t tx_descriptor; + + uint32_t tx_descriptor[ENET_TX_RING_NUM]; + uint32_t tx_ring_num; uint32_t phy_status; uint32_t phy_control; From 52cfd5846b8979805077ce7608aa36c18a2a9f32 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:37 +0000 Subject: [PATCH 538/546] imx_fec: Use correct length for packet size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use 'frame_size' instead of 'len' when calling qemu_send_packet(), failing to do so results in malformed packets send in case when that packed is fragmented into multiple DMA transactions. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 77d27f763e..6cb9e2e20e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -556,7 +556,7 @@ static void imx_enet_do_tx(IMXFECState *s, uint32_t index) } /* Last buffer in frame. */ - qemu_send_packet(qemu_get_queue(s->nic), s->frame, len); + qemu_send_packet(qemu_get_queue(s->nic), s->frame, frame_size); ptr = s->frame; frame_size = 0; From 894d74cc4f2fa577765bae711b9dc9ac9309521e Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 539/546] imx_fec: Fix a typo in imx_enet_receive() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 6cb9e2e20e..c1cf7f9c58 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1150,7 +1150,7 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf, size += 2; } - /* Huge frames are truncted. */ + /* Huge frames are truncated. */ if (size > s->regs[ENET_FTRL]) { size = s->regs[ENET_FTRL]; flags |= ENET_BD_TR | ENET_BD_LG; From 831858ad9da7eccf4c260c60ed56cff0f1666424 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 540/546] imx_fec: Reserve full FSL_IMX25_FEC_SIZE page for the register file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some i.MX SoCs (e.g. i.MX7) have FEC registers going as far as offset 0x614, so to avoid getting aborts when accessing those on QEMU, extend the register file to cover FSL_IMX25_FEC_SIZE(16K) of address space instead of just 1K. Cc: Peter Maydell Cc: Jason Wang Cc: Philippe Mathieu-Daudé Cc: qemu-devel@nongnu.org Cc: qemu-arm@nongnu.org Cc: yurovsky@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Andrey Smirnov Signed-off-by: Peter Maydell --- hw/net/imx_fec.c | 2 +- include/hw/arm/fsl-imx25.h | 1 - include/hw/net/imx_fec.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index c1cf7f9c58..4fb48f62ba 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1281,7 +1281,7 @@ static void imx_eth_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); memory_region_init_io(&s->iomem, OBJECT(dev), &imx_eth_ops, s, - TYPE_IMX_FEC, 0x400); + TYPE_IMX_FEC, FSL_IMX25_FEC_SIZE); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq[0]); sysbus_init_irq(sbd, &s->irq[1]); diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index d0e8e9d956..65a73714ef 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -192,7 +192,6 @@ typedef struct FslIMX25State { #define FSL_IMX25_UART5_ADDR 0x5002C000 #define FSL_IMX25_UART5_SIZE 0x4000 #define FSL_IMX25_FEC_ADDR 0x50038000 -#define FSL_IMX25_FEC_SIZE 0x4000 #define FSL_IMX25_CCM_ADDR 0x53F80000 #define FSL_IMX25_CCM_SIZE 0x4000 #define FSL_IMX25_GPT4_ADDR 0x53F84000 diff --git a/include/hw/net/imx_fec.h b/include/hw/net/imx_fec.h index 91ef8f89a6..7b3faa4019 100644 --- a/include/hw/net/imx_fec.h +++ b/include/hw/net/imx_fec.h @@ -245,6 +245,7 @@ typedef struct { #define ENET_TX_RING_NUM 3 +#define FSL_IMX25_FEC_SIZE 0x4000 typedef struct IMXFECState { /*< private >*/ From 2ba63e4af69b674f4fabd317dd438061de1ea310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 11 Jan 2018 13:25:38 +0000 Subject: [PATCH 541/546] hw/timer/pxa2xx_timer: replace hw_error() -> qemu_log_mask() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180103224208.30291-2-f4bug@amsat.org Signed-off-by: Peter Maydell --- hw/timer/pxa2xx_timer.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 68ba5a70b3..a489bf5159 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -13,6 +13,7 @@ #include "sysemu/sysemu.h" #include "hw/arm/pxa.h" #include "hw/sysbus.h" +#include "qemu/log.h" #define OSMR0 0x00 #define OSMR1 0x04 @@ -252,8 +253,14 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, case OSNR: return s->snapshot; default: + qemu_log_mask(LOG_UNIMP, + "%s: unknown register 0x%02" HWADDR_PRIx "\n", + __func__, offset); + break; badreg: - hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx "\n", + __func__, offset); } return 0; @@ -377,8 +384,14 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, } break; default: + qemu_log_mask(LOG_UNIMP, + "%s: unknown register 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); + break; badreg: - hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); } } From 487b406af1164dc036c70126f53a20c4c395db92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 11 Jan 2018 13:25:39 +0000 Subject: [PATCH 542/546] hw/sd/pxa2xx_mmci: add read/write() trace events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-id: 20180104000156.30932-1-f4bug@amsat.org [PMM: add missing include] Signed-off-by: Peter Maydell --- hw/sd/pxa2xx_mmci.c | 78 +++++++++++++++++++++++++++++---------------- hw/sd/trace-events | 4 +++ 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index 3deccf02c9..82f8ec0d50 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -19,6 +19,8 @@ #include "hw/qdev.h" #include "hw/qdev-properties.h" #include "qemu/error-report.h" +#include "qemu/log.h" +#include "trace.h" #define TYPE_PXA2XX_MMCI "pxa2xx-mmci" #define PXA2XX_MMCI(obj) OBJECT_CHECK(PXA2xxMMCIState, (obj), TYPE_PXA2XX_MMCI) @@ -278,45 +280,56 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - uint32_t ret; + uint32_t ret = 0; switch (offset) { case MMC_STRPCL: - return 0; + break; case MMC_STAT: - return s->status; + ret = s->status; + break; case MMC_CLKRT: - return s->clkrt; + ret = s->clkrt; + break; case MMC_SPI: - return s->spi; + ret = s->spi; + break; case MMC_CMDAT: - return s->cmdat; + ret = s->cmdat; + break; case MMC_RESTO: - return s->resp_tout; + ret = s->resp_tout; + break; case MMC_RDTO: - return s->read_tout; + ret = s->read_tout; + break; case MMC_BLKLEN: - return s->blklen; + ret = s->blklen; + break; case MMC_NUMBLK: - return s->numblk; + ret = s->numblk; + break; case MMC_PRTBUF: - return 0; + break; case MMC_I_MASK: - return s->intmask; + ret = s->intmask; + break; case MMC_I_REG: - return s->intreq; + ret = s->intreq; + break; case MMC_CMD: - return s->cmd | 0x40; + ret = s->cmd | 0x40; + break; case MMC_ARGH: - return s->arg >> 16; + ret = s->arg >> 16; + break; case MMC_ARGL: - return s->arg & 0xffff; + ret = s->arg & 0xffff; + break; case MMC_RES: - if (s->resp_len < 9) - return s->resp_fifo[s->resp_len ++]; - return 0; + ret = (s->resp_len < 9) ? s->resp_fifo[s->resp_len++] : 0; + break; case MMC_RXFIFO: - ret = 0; while (size-- && s->rx_len) { ret |= s->rx_fifo[s->rx_start++] << (size << 3); s->rx_start &= 0x1f; @@ -324,16 +337,20 @@ static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) } s->intreq &= ~INT_RXFIFO_REQ; pxa2xx_mmci_fifo_update(s); - return ret; + break; case MMC_RDWAIT: - return 0; + break; case MMC_BLKS_REM: - return s->numblk; + ret = s->numblk; + break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect register 0x%02" HWADDR_PRIx "\n", + __func__, offset); } + trace_pxa2xx_mmci_read(size, offset, ret); - return 0; + return ret; } static void pxa2xx_mmci_write(void *opaque, @@ -341,6 +358,7 @@ static void pxa2xx_mmci_write(void *opaque, { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; + trace_pxa2xx_mmci_write(size, offset, value); switch (offset) { case MMC_STRPCL: if (value & STRPCL_STRT_CLK) { @@ -368,8 +386,10 @@ static void pxa2xx_mmci_write(void *opaque, case MMC_SPI: s->spi = value & 0xf; - if (value & SPI_SPI_MODE) - printf("%s: attempted to use card in SPI mode\n", __FUNCTION__); + if (value & SPI_SPI_MODE) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: attempted to use card in SPI mode\n", __func__); + } break; case MMC_CMDAT: @@ -442,7 +462,9 @@ static void pxa2xx_mmci_write(void *opaque, break; default: - hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: incorrect reg 0x%02" HWADDR_PRIx " " + "(value 0x%08" PRIx64 ")\n", __func__, offset, value); } } diff --git a/hw/sd/trace-events b/hw/sd/trace-events index 1fc0bcf44b..6eca3470e2 100644 --- a/hw/sd/trace-events +++ b/hw/sd/trace-events @@ -3,3 +3,7 @@ # hw/sd/milkymist-memcard.c milkymist_memcard_memory_read(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" milkymist_memcard_memory_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x" + +# hw/sd/pxa2xx_mmci.c +pxa2xx_mmci_read(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" +pxa2xx_mmci_write(uint8_t size, uint32_t addr, uint32_t value) "size %d addr 0x%02x value 0x%08x" From 579648554acbd6c22d5cc2f03cf77cfc25332650 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:39 +0000 Subject: [PATCH 543/546] linux-user/arm/nwfpe: Check coprocessor number for FPA emulation Our copy of the nwfpe code for emulating of the old FPA11 floating point unit doesn't check the coprocessor number in the instruction when it emulates it. This means that we might treat some instructions which should really UNDEF as being FPA11 instructions by accident. The kernel's copy of the nwfpe code doesn't make this error; I suspect the bug was noticed and fixed as part of the process of mainlining the nwfpe code more than a decade ago. Add a check that the coprocessor number (which is always in bits [11:8] of the instruction) is either 1 or 2, which is where the FPA11 lives. Reported-by: Richard Henderson Signed-off-by: Peter Maydell --- linux-user/arm/nwfpe/fpa11.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/linux-user/arm/nwfpe/fpa11.c b/linux-user/arm/nwfpe/fpa11.c index 441e3b1cf6..f6f8163eab 100644 --- a/linux-user/arm/nwfpe/fpa11.c +++ b/linux-user/arm/nwfpe/fpa11.c @@ -137,8 +137,17 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) unsigned int nRc = 0; // unsigned long flags; FPA11 *fpa11; + unsigned int cp; // save_flags(flags); sti(); + /* Check that this is really an FPA11 instruction: the coprocessor + * field in bits [11:8] must be 1 or 2. + */ + cp = (opcode >> 8) & 0xf; + if (cp != 1 && cp != 2) { + return 0; + } + qemufpa=qfpa; user_registers=qregs; From 2eea841c11096e8dcc457b80e21f3fbdc32d2590 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 544/546] target/arm: Make disas_thumb2_insn() generate its own UNDEF exceptions Refactor disas_thumb2_insn() so that it generates the code for raising an UNDEF exception for invalid insns, rather than returning a flag which the caller must check to see if it needs to generate the UNDEF code. This brings the function in to line with the behaviour of disas_thumb_insn() and disas_arm_insn(). Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 1513080506-17703-1-git-send-email-peter.maydell@linaro.org --- target/arm/translate.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/target/arm/translate.c b/target/arm/translate.c index c690658493..781be1e219 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -9775,9 +9775,8 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, return 0; } -/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction - is not legal. */ -static int disas_thumb2_insn(DisasContext *s, uint32_t insn) +/* Translate a 32-bit thumb instruction. */ +static void disas_thumb2_insn(DisasContext *s, uint32_t insn) { uint32_t imm, shift, offset; uint32_t rd, rn, rm, rs; @@ -11016,16 +11015,16 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) /* UNPREDICTABLE, unallocated hint or * PLD/PLDW/PLI (literal) */ - return 0; + return; } if (op1 & 1) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) { - return 0; /* PLD/PLDW/PLI or unallocated hint */ + return; /* PLD/PLDW/PLI or unallocated hint */ } /* UNDEF space, or an UNPREDICTABLE */ - return 1; + goto illegal_op; } } memidx = get_mem_index(s); @@ -11151,9 +11150,10 @@ static int disas_thumb2_insn(DisasContext *s, uint32_t insn) default: goto illegal_op; } - return 0; + return; illegal_op: - return 1; + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); } static void disas_thumb_insn(DisasContext *s, uint32_t insn) @@ -12275,10 +12275,7 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) if (is_16bit) { disas_thumb_insn(dc, insn); } else { - if (disas_thumb2_insn(dc, insn)) { - gen_exception_insn(dc, 4, EXCP_UDEF, syn_uncategorized(), - default_exception_el(dc)); - } + disas_thumb2_insn(dc, insn); } /* Advance the Thumb condexec condition. */ From f1945632b43e36bd9f3e0c2feb0e5b152be7ed91 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 545/546] hw/intc/arm_gicv3: Make reserved register addresses RAZ/WI The GICv3 specification says that reserved register addresses should RAZ/WI. This means we need to return MEMTX_OK, not MEMTX_ERROR, because now that we support generating external aborts the latter will cause an abort on new board models. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Message-id: 1513183941-24300-2-git-send-email-peter.maydell@linaro.org Reviewed-by: Alistair Francis --- hw/intc/arm_gicv3_dist.c | 13 +++++++++++++ hw/intc/arm_gicv3_its_common.c | 8 +++----- hw/intc/arm_gicv3_redist.c | 13 +++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 3ea3dd0d40..93fe936862 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -817,6 +817,13 @@ MemTxResult gicv3_dist_read(void *opaque, hwaddr offset, uint64_t *data, "%s: invalid guest read at offset " TARGET_FMT_plx "size %u\n", __func__, offset, size); trace_gicv3_dist_badread(offset, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; + *data = 0; } else { trace_gicv3_dist_read(offset, *data, size, attrs.secure); } @@ -852,6 +859,12 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data, "%s: invalid guest write at offset " TARGET_FMT_plx "size %u\n", __func__, offset, size); trace_gicv3_dist_badwrite(offset, data, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; } else { trace_gicv3_dist_write(offset, data, size, attrs.secure); } diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 2bd2f0f3c9..284c0a7584 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -67,7 +67,8 @@ static MemTxResult gicv3_its_trans_read(void *opaque, hwaddr offset, MemTxAttrs attrs) { qemu_log_mask(LOG_GUEST_ERROR, "ITS read at offset 0x%"PRIx64"\n", offset); - return MEMTX_ERROR; + *data = 0; + return MEMTX_OK; } static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset, @@ -82,15 +83,12 @@ static MemTxResult gicv3_its_trans_write(void *opaque, hwaddr offset, if (ret <= 0) { qemu_log_mask(LOG_GUEST_ERROR, "ITS: Error sending MSI: %s\n", strerror(-ret)); - return MEMTX_DECODE_ERROR; } - - return MEMTX_OK; } else { qemu_log_mask(LOG_GUEST_ERROR, "ITS write at bad offset 0x%"PRIx64"\n", offset); - return MEMTX_DECODE_ERROR; } + return MEMTX_OK; } static const MemoryRegionOps gicv3_its_trans_ops = { diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 77e5cfa327..8a8684d76e 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -455,6 +455,13 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data, "size %u\n", __func__, offset, size); trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; + *data = 0; } else { trace_gicv3_redist_read(gicv3_redist_affid(cs), offset, *data, size, attrs.secure); @@ -505,6 +512,12 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data, "size %u\n", __func__, offset, size); trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data, size, attrs.secure); + /* The spec requires that reserved registers are RAZ/WI; + * so use MEMTX_ERROR returns from leaf functions as a way to + * trigger the guest-error logging but don't return it to + * the caller, or we'll cause a spurious guest data abort. + */ + r = MEMTX_OK; } else { trace_gicv3_redist_write(gicv3_redist_affid(cs), offset, data, size, attrs.secure); From 0cf09852015e47a5fbb974ff7ac320366afd21ee Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 11 Jan 2018 13:25:40 +0000 Subject: [PATCH 546/546] hw/intc/arm_gic: reserved register addresses are RAZ/WI The GICv2 specification says that reserved register addresses must RAZ/WI; now that we implement external abort handling for Arm CPUs this means we must return MEMTX_OK rather than MEMTX_ERROR, to avoid generating a spurious guest data abort. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Message-id: 1513183941-24300-3-git-send-email-peter.maydell@linaro.org Reviewed-by: Alistair Francis --- hw/intc/arm_gic.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 5a0e2a3c1a..d701e49ff9 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -1261,7 +1261,8 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_read: Bad offset %x\n", (int)offset); - return MEMTX_ERROR; + *data = 0; + break; } return MEMTX_OK; } @@ -1329,7 +1330,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, default: qemu_log_mask(LOG_GUEST_ERROR, "gic_cpu_write: Bad offset %x\n", (int)offset); - return MEMTX_ERROR; + return MEMTX_OK; } gic_update(s); return MEMTX_OK;