diff options
72 files changed, 1092 insertions, 501 deletions
@@ -123,3 +123,23 @@ gcc's printf attribute directive in the prototype. This makes it so gcc's -Wformat and -Wformat-security options can do their jobs and cross-check format strings with the number and types of arguments. + +6. C standard, implementation defined and undefined behaviors + +C code in QEMU should be written to the C99 language specification. A copy +of the final version of the C99 standard with corrigenda TC1, TC2, and TC3 +included, formatted as a draft, can be downloaded from: + http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf + +The C language specification defines regions of undefined behavior and +implementation defined behavior (to give compiler authors enough leeway to +produce better code). In general, code in QEMU should follow the language +specification and avoid both undefined and implementation defined +constructs. ("It works fine on the gcc I tested it with" is not a valid +argument...) However there are a few areas where we allow ourselves to +assume certain behaviors because in practice all the platforms we care about +behave in the same way and writing strictly conformant code would be +painful. These are: + * you may assume that integers are 2s complement representation + * you may assume that right shift of a signed integer duplicates + the sign bit (ie it is an arithmetic shift, not a logical shift) @@ -116,7 +116,7 @@ audio_drv_list="" audio_card_list="ac97 es1370 sb16 hda" audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda" block_drv_whitelist="" -host_cc="gcc" +host_cc="cc" libs_softmmu="" libs_tools="" audio_pt_int="" @@ -250,7 +250,16 @@ done # Using uname is really, really broken. Once we have the right set of checks # we can eliminate its usage altogether. -cc="${CC-${cross_prefix}gcc}" +# Preferred compiler: +# ${CC} (if set) +# ${cross_prefix}gcc (if cross-prefix specified) +# system compiler +if test -z "${CC}${cross_prefix}"; then + cc="$host_cc" +else + cc="${CC-${cross_prefix}gcc}" +fi + ar="${AR-${cross_prefix}ar}" objcopy="${OBJCOPY-${cross_prefix}objcopy}" ld="${LD-${cross_prefix}ld}" @@ -2118,7 +2127,7 @@ fi # pixman support probe if test "$pixman" = ""; then - if $pkg_config pixman-1 > /dev/null 2>&1; then + if $pkg_config --atleast-version=0.18.4 pixman-1 > /dev/null 2>&1; then pixman="system" else pixman="internal" @@ -2129,7 +2138,7 @@ if test "$pixman" = "system"; then pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null` else if test ! -d ${source_path}/pixman/pixman; then - echo "ERROR: pixman not present. Your options:" + echo "ERROR: pixman not present (or older than 0.18.4). Your options:" echo " (1) Prefered: Install the pixman devel package (any recent" echo " distro should have packages as Xorg needs pixman too)." echo " (2) Fetch the pixman submodule, using:" @@ -70,10 +70,6 @@ typedef struct TranslationBlock TranslationBlock; #define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * MAX_OPC_PARAM) -extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; -extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; -extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; - #include "qemu-log.h" void gen_intermediate_code(CPUArchState *env, struct TranslationBlock *tb); @@ -607,6 +607,8 @@ static inline void code_gen_alloc(size_t tb_size) exit(1); } + qemu_madvise(code_gen_buffer, code_gen_buffer_size, QEMU_MADV_HUGEPAGE); + /* Steal room for the prologue at the end of the buffer. This ensures (via the MAX_CODE_GEN_BUFFER_SIZE limits above) that direct branches from TB's to the prologue are going to be in range. It also means diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index f9a8270..df2a939 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -272,31 +272,76 @@ static int send_status(int sockfd, struct iovec *iovec, int status) /* * from man 7 capabilities, section * Effect of User ID Changes on Capabilities: - * 4. If the file system user ID is changed from 0 to nonzero (see setfsuid(2)) - * then the following capabilities are cleared from the effective set: - * CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, - * CAP_LINUX_IMMUTABLE (since Linux 2.2.30), CAP_MAC_OVERRIDE, and CAP_MKNOD - * (since Linux 2.2.30). If the file system UID is changed from nonzero to 0, - * then any of these capabilities that are enabled in the permitted set - * are enabled in the effective set. + * If the effective user ID is changed from nonzero to 0, then the permitted + * set is copied to the effective set. If the effective user ID is changed + * from 0 to nonzero, then all capabilities are are cleared from the effective + * set. + * + * The setfsuid/setfsgid man pages warn that changing the effective user ID may + * expose the program to unwanted signals, but this is not true anymore: for an + * unprivileged (without CAP_KILL) program to send a signal, the real or + * effective user ID of the sending process must equal the real or saved user + * ID of the target process. Even when dropping privileges, it is enough to + * keep the saved UID to a "privileged" value and virtfs-proxy-helper won't + * be exposed to signals. So just use setresuid/setresgid. */ -static int setfsugid(int uid, int gid) +static int setugid(int uid, int gid, int *suid, int *sgid) { + int retval; + /* - * We still need DAC_OVERRIDE because we don't change + * We still need DAC_OVERRIDE because we don't change * supplementary group ids, and hence may be subjected DAC rules */ cap_value_t cap_list[] = { CAP_DAC_OVERRIDE, }; - setfsgid(gid); - setfsuid(uid); + *suid = geteuid(); + *sgid = getegid(); + + if (setresgid(-1, gid, *sgid) == -1) { + retval = -errno; + goto err_out; + } + + if (setresuid(-1, uid, *suid) == -1) { + retval = -errno; + goto err_sgid; + } if (uid != 0 || gid != 0) { - return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0); + if (do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0) < 0) { + retval = -errno; + goto err_suid; + } } return 0; + +err_suid: + if (setresuid(-1, *suid, *suid) == -1) { + abort(); + } +err_sgid: + if (setresgid(-1, *sgid, *sgid) == -1) { + abort(); + } +err_out: + return retval; +} + +/* + * This is used to reset the ugid back with the saved values + * There is nothing much we can do checking error values here. + */ +static void resetugid(int suid, int sgid) +{ + if (setresgid(-1, sgid, sgid) == -1) { + abort(); + } + if (setresuid(-1, suid, suid) == -1) { + abort(); + } } /* @@ -578,18 +623,15 @@ static int do_create_others(int type, struct iovec *iovec) v9fs_string_init(&path); v9fs_string_init(&oldpath); - cur_uid = geteuid(); - cur_gid = getegid(); retval = proxy_unmarshal(iovec, offset, "dd", &uid, &gid); if (retval < 0) { return retval; } offset += retval; - retval = setfsugid(uid, gid); + retval = setugid(uid, gid, &cur_uid, &cur_gid); if (retval < 0) { - retval = -errno; - goto err_out; + goto unmarshal_err_out; } switch (type) { case T_MKNOD: @@ -619,9 +661,10 @@ static int do_create_others(int type, struct iovec *iovec) } err_out: + resetugid(cur_uid, cur_gid); +unmarshal_err_out: v9fs_string_free(&path); v9fs_string_free(&oldpath); - setfsugid(cur_uid, cur_gid); return retval; } @@ -641,24 +684,16 @@ static int do_create(struct iovec *iovec) if (ret < 0) { goto unmarshal_err_out; } - cur_uid = geteuid(); - cur_gid = getegid(); - ret = setfsugid(uid, gid); + ret = setugid(uid, gid, &cur_uid, &cur_gid); if (ret < 0) { - /* - * On failure reset back to the - * old uid/gid - */ - ret = -errno; - goto err_out; + goto unmarshal_err_out; } ret = open(path.data, flags, mode); if (ret < 0) { ret = -errno; } -err_out: - setfsugid(cur_uid, cur_gid); + resetugid(cur_uid, cur_gid); unmarshal_err_out: v9fs_string_free(&path); return ret; diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index b03454e..0b5b0d3 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -391,7 +391,7 @@ static int piix4_pm_initfn(PCIDevice *dev) pci_conf[0x3d] = 0x01; // interrupt pin 1 /* APM */ - apm_init(&s->apm, apm_ctrl_changed, s); + apm_init(dev, &s->apm, apm_ctrl_changed, s); if (s->kvm_enabled) { /* Mark SMM as already inited to prevent SMM from running. KVM does not @@ -22,6 +22,7 @@ #include "apm.h" #include "hw.h" +#include "pci.h" //#define DEBUG @@ -35,7 +36,8 @@ #define APM_CNT_IOPORT 0xb2 #define APM_STS_IOPORT 0xb3 -static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) +static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { APMState *apm = opaque; addr &= 1; @@ -51,7 +53,7 @@ static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t apm_ioport_readb(void *opaque, uint32_t addr) +static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size) { APMState *apm = opaque; uint32_t val; @@ -78,12 +80,23 @@ const VMStateDescription vmstate_apm = { } }; -void apm_init(APMState *apm, apm_ctrl_changed_t callback, void *arg) +static const MemoryRegionOps apm_ops = { + .read = apm_ioport_readb, + .write = apm_ioport_writeb, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback, + void *arg) { apm->callback = callback; apm->arg = arg; /* ioport 0xb2, 0xb3 */ - register_ioport_write(APM_CNT_IOPORT, 2, 1, apm_ioport_writeb, apm); - register_ioport_read(APM_CNT_IOPORT, 2, 1, apm_ioport_readb, apm); + memory_region_init_io(&apm->io, &apm_ops, apm, "apm-io", 2); + memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT, + &apm->io); } @@ -4,6 +4,7 @@ #include <stdint.h> #include "qemu-common.h" #include "hw.h" +#include "memory.h" typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg); @@ -13,9 +14,11 @@ typedef struct APMState { apm_ctrl_changed_t callback; void *arg; + MemoryRegion io; } APMState; -void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg); +void apm_init(PCIDevice *dev, APMState *s, apm_ctrl_changed_t callback, + void *arg); extern const VMStateDescription vmstate_apm; diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 9bef96e..40efa8a 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -197,6 +197,7 @@ typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, typedef struct CirrusVGAState { VGACommonState vga; + MemoryRegion cirrus_vga_io; MemoryRegion cirrus_linear_io; MemoryRegion cirrus_linear_bitblt_io; MemoryRegion cirrus_mmio_io; @@ -2432,13 +2433,15 @@ static void cirrus_update_memory_access(CirrusVGAState *s) /* I/O ports */ -static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) +static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int val, index; qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; if (vga_ioport_invalid(s, addr)) { val = 0xff; @@ -2527,13 +2530,15 @@ static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr) return val; } -static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) +static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { CirrusVGAState *c = opaque; VGACommonState *s = &c->vga; int index; qemu_flush_coalesced_mmio_buffer(); + addr += 0x3b0; /* check port range access depending on color/monochrome mode */ if (vga_ioport_invalid(s, addr)) { @@ -2646,7 +2651,7 @@ static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr, if (addr >= 0x100) { return cirrus_mmio_blt_read(s, addr - 0x100); } else { - return cirrus_vga_ioport_read(s, addr + 0x3c0); + return cirrus_vga_ioport_read(s, addr + 0x10, size); } } @@ -2658,7 +2663,7 @@ static void cirrus_mmio_write(void *opaque, hwaddr addr, if (addr >= 0x100) { cirrus_mmio_blt_write(s, addr - 0x100, val); } else { - cirrus_vga_ioport_write(s, addr + 0x3c0, val); + cirrus_vga_ioport_write(s, addr + 0x10, val, size); } } @@ -2784,8 +2789,19 @@ static const MemoryRegionOps cirrus_linear_io_ops = { }, }; +static const MemoryRegionOps cirrus_vga_io_ops = { + .read = cirrus_vga_ioport_read, + .write = cirrus_vga_ioport_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, - MemoryRegion *system_memory) + MemoryRegion *system_memory, + MemoryRegion *system_io) { int i; static int inited; @@ -2817,19 +2833,10 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, s->bustype = CIRRUS_BUSTYPE_ISA; } - register_ioport_write(0x3c0, 16, 1, cirrus_vga_ioport_write, s); - - register_ioport_write(0x3b4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3d4, 2, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3ba, 1, 1, cirrus_vga_ioport_write, s); - register_ioport_write(0x3da, 1, 1, cirrus_vga_ioport_write, s); - - register_ioport_read(0x3c0, 16, 1, cirrus_vga_ioport_read, s); - - register_ioport_read(0x3b4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3d4, 2, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3ba, 1, 1, cirrus_vga_ioport_read, s); - register_ioport_read(0x3da, 1, 1, cirrus_vga_ioport_read, s); + /* Register ioport 0x3b0 - 0x3df */ + memory_region_init_io(&s->cirrus_vga_io, &cirrus_vga_io_ops, s, + "cirrus-io", 0x30); + memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io); memory_region_init(&s->low_mem_container, "cirrus-lowmem-container", @@ -2900,7 +2907,7 @@ static int vga_initfn(ISADevice *dev) vga_common_init(s); cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, - isa_address_space(dev)); + isa_address_space(dev), isa_address_space_io(dev)); s->ds = graphic_console_init(s->update, s->invalidate, s->screen_dump, s->text_update, s); @@ -2948,7 +2955,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) /* setup VGA */ vga_common_init(&s->vga); - cirrus_init_common(s, device_id, 1, pci_address_space(dev)); + cirrus_init_common(s, device_id, 1, pci_address_space(dev), + pci_address_space_io(dev)); s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, s->vga.screen_dump, s->vga.text_update, &s->vga); @@ -58,6 +58,8 @@ static struct dma_cont { int dshift; struct dma_regs regs[4]; qemu_irq *cpu_request_exit; + MemoryRegion channel_io; + MemoryRegion cont_io; } dma_controllers[2]; enum { @@ -149,7 +151,7 @@ static inline int getff (struct dma_cont *d) return ff; } -static uint32_t read_chan (void *opaque, uint32_t nport) +static uint64_t read_chan(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int ichan, nreg, iport, ff, val, dir; @@ -171,7 +173,8 @@ static uint32_t read_chan (void *opaque, uint32_t nport) return (val >> (d->dshift + (ff << 3))) & 0xff; } -static void write_chan (void *opaque, uint32_t nport, uint32_t data) +static void write_chan(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan, nreg; @@ -189,22 +192,23 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data) } } -static void write_cont (void *opaque, uint32_t nport, uint32_t data) +static void write_cont(void *opaque, hwaddr nport, uint64_t data, + unsigned size) { struct dma_cont *d = opaque; int iport, ichan = 0; iport = (nport >> d->dshift) & 0x0f; switch (iport) { - case 0x08: /* command */ + case 0x01: /* command */ if ((data != 0) && (data & CMD_NOT_SUPPORTED)) { - dolog ("command %#x not supported\n", data); + dolog("command %"PRIx64" not supported\n", data); return; } d->command = data; break; - case 0x09: + case 0x02: ichan = data & 3; if (data & 4) { d->status |= 1 << (ichan + 4); @@ -216,7 +220,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0a: /* single mask */ + case 0x03: /* single mask */ if (data & 4) d->mask |= 1 << (data & 3); else @@ -224,7 +228,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) DMA_run(); break; - case 0x0b: /* mode */ + case 0x04: /* mode */ { ichan = data & 3; #ifdef DEBUG_DMA @@ -243,23 +247,23 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) break; } - case 0x0c: /* clear flip flop */ + case 0x05: /* clear flip flop */ d->flip_flop = 0; break; - case 0x0d: /* reset */ + case 0x06: /* reset */ d->flip_flop = 0; d->mask = ~0; d->status = 0; d->command = 0; break; - case 0x0e: /* clear mask for all channels */ + case 0x07: /* clear mask for all channels */ d->mask = 0; DMA_run(); break; - case 0x0f: /* write mask for all channels */ + case 0x08: /* write mask for all channels */ d->mask = data; DMA_run(); break; @@ -277,7 +281,7 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data) #endif } -static uint32_t read_cont (void *opaque, uint32_t nport) +static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size) { struct dma_cont *d = opaque; int iport, val; @@ -463,7 +467,7 @@ void DMA_schedule(int nchan) static void dma_reset(void *opaque) { struct dma_cont *d = opaque; - write_cont (d, (0x0d << d->dshift), 0); + write_cont(d, (0x06 << d->dshift), 0, 1); } static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) @@ -473,38 +477,68 @@ static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len) return dma_pos; } + +static const MemoryRegionOps channel_io_ops = { + .read = read_chan, + .write = write_chan, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +/* IOport from page_base */ +static const MemoryRegionPortio page_portio_list[] = { + { 0x01, 3, 1, .write = write_page, .read = read_page, }, + { 0x07, 1, 1, .write = write_page, .read = read_page, }, + PORTIO_END_OF_LIST(), +}; + +/* IOport from pageh_base */ +static const MemoryRegionPortio pageh_portio_list[] = { + { 0x01, 3, 1, .write = write_pageh, .read = read_pageh, }, + { 0x07, 3, 1, .write = write_pageh, .read = read_pageh, }, + PORTIO_END_OF_LIST(), +}; + +static const MemoryRegionOps cont_io_ops = { + .read = read_cont, + .write = write_cont, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */ static void dma_init2(struct dma_cont *d, int base, int dshift, int page_base, int pageh_base, qemu_irq *cpu_request_exit) { - static const int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 }; int i; d->dshift = dshift; d->cpu_request_exit = cpu_request_exit; - for (i = 0; i < 8; i++) { - register_ioport_write (base + (i << dshift), 1, 1, write_chan, d); - register_ioport_read (base + (i << dshift), 1, 1, read_chan, d); - } - for (i = 0; i < ARRAY_SIZE (page_port_list); i++) { - register_ioport_write (page_base + page_port_list[i], 1, 1, - write_page, d); - register_ioport_read (page_base + page_port_list[i], 1, 1, - read_page, d); - if (pageh_base >= 0) { - register_ioport_write (pageh_base + page_port_list[i], 1, 1, - write_pageh, d); - register_ioport_read (pageh_base + page_port_list[i], 1, 1, - read_pageh, d); - } - } - for (i = 0; i < 8; i++) { - register_ioport_write (base + ((i + 8) << dshift), 1, 1, - write_cont, d); - register_ioport_read (base + ((i + 8) << dshift), 1, 1, - read_cont, d); + + memory_region_init_io(&d->channel_io, &channel_io_ops, d, + "dma-chan", 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base, &d->channel_io); + + isa_register_portio_list(NULL, page_base, page_portio_list, d, + "dma-page"); + if (pageh_base >= 0) { + isa_register_portio_list(NULL, pageh_base, pageh_portio_list, d, + "dma-pageh"); } + + memory_region_init_io(&d->cont_io, &cont_io_ops, d, "dma-cont", + 8 << d->dshift); + memory_region_add_subregion(isa_address_space_io(NULL), + base + (8 << d->dshift), &d->cont_io); + qemu_register_reset(dma_reset, d); dma_reset(d); for (i = 0; i < ARRAY_SIZE (d->regs); ++i) { diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 685fdc0..144a88e 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -264,4 +264,13 @@ MemoryRegion *isa_address_space(ISADevice *dev) return get_system_memory(); } +MemoryRegion *isa_address_space_io(ISADevice *dev) +{ + if (dev) { + return isa_bus_from_device(dev)->address_space_io; + } + + return isabus->address_space_io; +} + type_init(isabus_register_types) @@ -43,6 +43,7 @@ void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); MemoryRegion *isa_address_space(ISADevice *dev); +MemoryRegion *isa_address_space_io(ISADevice *dev); ISADevice *isa_create(ISABus *bus, const char *name); ISADevice *isa_try_create(ISABus *bus, const char *name); ISADevice *isa_create_simple(ISABus *bus, const char *name); diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c index 6585236..878a43e 100644 --- a/hw/lpc_ich9.c +++ b/hw/lpc_ich9.c @@ -497,7 +497,7 @@ static int ich9_lpc_initfn(PCIDevice *d) lpc->isa_bus = isa_bus; ich9_cc_init(lpc); - apm_init(&lpc->apm, ich9_apm_ctrl_changed, lpc); + apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); lpc->machine_ready.notify = ich9_lpc_machine_ready; qemu_add_machine_init_done_notifier(&lpc->machine_ready); diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c index a95a3c1..20b5f1a 100644 --- a/hw/mips_mipssim.c +++ b/hw/mips_mipssim.c @@ -217,7 +217,8 @@ mips_mipssim_init(QEMUMachineInitArgs *args) /* A single 16450 sits at offset 0x3f8. It is attached to MIPS CPU INT2, which is interrupt 4. */ if (serial_hds[0]) - serial_init(0x3f8, env->irq[4], 115200, serial_hds[0]); + serial_init(0x3f8, env->irq[4], 115200, serial_hds[0], + get_system_io()); if (nd_table[0].used) /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */ @@ -98,7 +98,8 @@ void gsi_handler(void *opaque, int n, int level) qemu_set_irq(s->ioapic_irq[n], level); } -static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) +static void ioport80_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { } @@ -116,7 +117,8 @@ void cpu_set_ferr(CPUX86State *s) qemu_irq_raise(ferr_irq); } -static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) +static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data, + unsigned size) { qemu_irq_lower(ferr_irq); } @@ -567,6 +569,14 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } +static const MemoryRegionPortio bochs_bios_portio_list[] = { + { 0x500, 1, 1, .write = bochs_bios_write, }, /* 0x500 */ + { 0x501, 1, 1, .write = bochs_bios_write, }, /* 0x501 */ + { 0x501, 2, 2, .write = bochs_bios_write, }, /* 0x501 */ + { 0x8900, 1, 1, .write = bochs_bios_write, }, /* 0x8900 */ + PORTIO_END_OF_LIST(), +}; + static void *bochs_bios_init(void) { void *fw_cfg; @@ -574,12 +584,11 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; + PortioList *bochs_bios_port_list = g_new(PortioList, 1); - register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); - - register_ioport_write(0x501, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); + portio_list_init(bochs_bios_port_list, bochs_bios_portio_list, + NULL, "bochs-bios"); + portio_list_add(bochs_bios_port_list, get_system_io(), 0x0); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); @@ -967,6 +976,24 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } +static const MemoryRegionOps ioport80_io_ops = { + .write = ioport80_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + +static const MemoryRegionOps ioportF0_io_ops = { + .write = ioportF0_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, ISADevice **floppy, @@ -981,10 +1008,14 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, qemu_irq *a20_line; ISADevice *i8042, *port92, *vmmouse, *pit = NULL; qemu_irq *cpu_exit_irq; + MemoryRegion *ioport80_io = g_new(MemoryRegion, 1); + MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1); - register_ioport_write(0x80, 1, 1, ioport80_write, NULL); + memory_region_init_io(ioport80_io, &ioport80_io_ops, NULL, "ioport80", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io); - register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); + memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1); + memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io); /* * Check if an HPET shall be created. diff --git a/hw/pc_piix.c b/hw/pc_piix.c index aa3e7f4..19e342a 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -281,8 +281,8 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) } #endif -static QEMUMachine pc_machine_v1_3 = { - .name = "pc-1.3", +static QEMUMachine pc_machine_v1_4 = { + .name = "pc-1.4", .alias = "pc", .desc = "Standard PC", .init = pc_init_pci_1_3, @@ -290,7 +290,26 @@ static QEMUMachine pc_machine_v1_3 = { .is_default = 1, }; +#define PC_COMPAT_1_3 \ + {\ + .driver = "usb-tablet",\ + .property = "usb_version",\ + .value = stringify(1),\ + } + +static QEMUMachine pc_machine_v1_3 = { + .name = "pc-1.3", + .desc = "Standard PC", + .init = pc_init_pci_1_3, + .max_cpus = 255, + .compat_props = (GlobalProperty[]) { + PC_COMPAT_1_3, + { /* end of list */ } + }, +}; + #define PC_COMPAT_1_2 \ + PC_COMPAT_1_3,\ {\ .driver = "nec-usb-xhci",\ .property = "msi",\ @@ -626,6 +645,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_machine_v1_4); qemu_register_machine(&pc_machine_v1_3); qemu_register_machine(&pc_machine_v1_2); qemu_register_machine(&pc_machine_v1_1); diff --git a/hw/serial.c b/hw/serial.c index 60283ea..07a2a11 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -718,7 +718,7 @@ const MemoryRegionOps serial_io_ops = { }; SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr) + CharDriverState *chr, MemoryRegion *system_io) { SerialState *s; @@ -732,7 +732,7 @@ SerialState *serial_init(int base, qemu_irq irq, int baudbase, vmstate_register(NULL, base, &vmstate_serial, s); memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); - memory_region_add_subregion(get_system_io(), base, &s->io); + memory_region_add_subregion(system_io, base, &s->io); return s; } diff --git a/hw/serial.h b/hw/serial.h index f1e3c4a..ed1a5cd 100644 --- a/hw/serial.h +++ b/hw/serial.h @@ -89,7 +89,7 @@ void serial_set_frequency(SerialState *s, uint32_t frequency); /* legacy pre qom */ SerialState *serial_init(int base, qemu_irq irq, int baudbase, - CharDriverState *chr); + CharDriverState *chr, MemoryRegion *system_io); SerialState *serial_mm_init(MemoryRegion *address_space, hwaddr base, int it_shift, qemu_irq irq, int baudbase, @@ -197,6 +197,7 @@ struct USBEndpoint { enum USBDeviceFlags { USB_DEV_FLAG_FULL_PATH, + USB_DEV_FLAG_IS_HOST, }; /* definition of a USB device */ @@ -229,6 +230,7 @@ struct USBDevice { USBEndpoint ep_out[USB_MAX_ENDPOINTS]; QLIST_HEAD(, USBDescString) strings; + const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */ const USBDescDevice *device; int configuration; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index 55d0edd..8264c24 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -166,6 +166,9 @@ const char *usb_device_get_product_desc(USBDevice *dev) const USBDesc *usb_device_get_usb_desc(USBDevice *dev) { USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (dev->usb_desc) { + return dev->usb_desc; + } return klass->usb_desc; } diff --git a/hw/usb/core.c b/hw/usb/core.c index 52b5310..8e360d3 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -406,7 +406,11 @@ void usb_handle_packet(USBDevice *dev, USBPacket *p) if (QTAILQ_EMPTY(&p->ep->queue) || p->ep->pipeline) { usb_process_one(p); if (p->status == USB_RET_ASYNC) { + /* hcd drivers cannot handle async for isoc */ assert(p->ep->type != USB_ENDPOINT_XFER_ISOC); + /* using async for interrupt packets breaks migration */ + assert(p->ep->type != USB_ENDPOINT_XFER_INT || + (dev->flags & USB_DEV_FLAG_IS_HOST)); usb_packet_set_state(p, USB_PACKET_ASYNC); QTAILQ_INSERT_TAIL(&p->ep->queue, p, queue); } else if (p->status == USB_RET_ADD_TO_QUEUE) { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 55266b1..8749128 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -46,6 +46,7 @@ typedef struct USBHIDState { USBDevice dev; USBEndpoint *intr; HIDState hid; + uint32_t usb_version; } USBHIDState; enum { @@ -131,6 +132,36 @@ static const USBDescIface desc_iface_tablet = { }, }; +static const USBDescIface desc_iface_tablet2 = { + .bInterfaceNumber = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_HID, + .bInterfaceProtocol = 0x02, + .ndesc = 1, + .descs = (USBDescOther[]) { + { + /* HID descriptor */ + .data = (uint8_t[]) { + 0x09, /* u8 bLength */ + USB_DT_HID, /* u8 bDescriptorType */ + 0x01, 0x00, /* u16 HID_class */ + 0x00, /* u8 country_code */ + 0x01, /* u8 num_descriptors */ + USB_DT_REPORT, /* u8 type: Report */ + 74, 0, /* u16 len */ + }, + }, + }, + .eps = (USBDescEndpoint[]) { + { + .bEndpointAddress = USB_DIR_IN | 0x01, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = 8, + .bInterval = 4, /* 2 ^ (4-1) * 125 usecs = 1 ms */ + }, + }, +}; + static const USBDescIface desc_iface_keyboard = { .bInterfaceNumber = 0, .bNumEndpoints = 1, @@ -196,6 +227,23 @@ static const USBDescDevice desc_device_tablet = { }, }; +static const USBDescDevice desc_device_tablet2 = { + .bcdUSB = 0x0200, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { + { + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG_TABLET, + .bmAttributes = 0xa0, + .bMaxPower = 50, + .nif = 1, + .ifs = &desc_iface_tablet2, + }, + }, +}; + static const USBDescDevice desc_device_keyboard = { .bcdUSB = 0x0100, .bMaxPacketSize0 = 8, @@ -239,6 +287,20 @@ static const USBDesc desc_tablet = { .str = desc_strings, }; +static const USBDesc desc_tablet2 = { + .id = { + .idVendor = 0x0627, + .idProduct = 0x0001, + .bcdDevice = 0, + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT_TABLET, + .iSerialNumber = STR_SERIALNUMBER, + }, + .full = &desc_device_tablet, + .high = &desc_device_tablet2, + .str = desc_strings, +}; + static const USBDesc desc_keyboard = { .id = { .idVendor = 0x0627, @@ -508,6 +570,21 @@ static int usb_hid_initfn(USBDevice *dev, int kind) static int usb_tablet_initfn(USBDevice *dev) { + USBHIDState *us = DO_UPCAST(USBHIDState, dev, dev); + + switch (us->usb_version) { + case 1: + dev->usb_desc = &desc_tablet; + break; + case 2: + dev->usb_desc = &desc_tablet2; + break; + default: + error_report("Invalid usb version %d for usb-tabler (must be 1 or 2)", + us->usb_version); + return -1; + } + return usb_hid_initfn(dev, HID_TABLET); } @@ -562,8 +639,14 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hid_handle_control; uc->handle_data = usb_hid_handle_data; uc->handle_destroy = usb_hid_handle_destroy; + uc->handle_attach = usb_desc_attach; } +static Property usb_tablet_properties[] = { + DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), + DEFINE_PROP_END_OF_LIST(), +}; + static void usb_tablet_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -572,8 +655,8 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) usb_hid_class_initfn(klass, data); uc->init = usb_tablet_initfn; uc->product_desc = "QEMU USB Tablet"; - uc->usb_desc = &desc_tablet; dc->vmsd = &vmstate_usb_ptr; + dc->props = usb_tablet_properties; } static TypeInfo usb_tablet_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 9ee60dd..470fbbb 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -184,6 +184,7 @@ static void usb_hub_detach(USBPort *port1) port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + usb_wakeup(s->intr); } static void usb_hub_child_detach(USBPort *port1, USBDevice *child) @@ -363,6 +364,7 @@ static void usb_hub_handle_control(USBDevice *dev, USBPacket *p, port->wPortChange |= PORT_STAT_C_RESET; /* set enable bit */ port->wPortStatus |= PORT_STAT_ENABLE; + usb_wakeup(s->intr); } break; case PORT_POWER: diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 14d9e5a..30cb033 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -639,6 +639,8 @@ typedef struct USBNetState { unsigned int in_ptr, in_len; uint8_t in_buf[2048]; + USBEndpoint *intr; + char usbstring_mac[13]; NICState *nic; NICConf conf; @@ -851,6 +853,10 @@ static void *rndis_queue_response(USBNetState *s, unsigned int length) struct rndis_response *r = g_malloc0(sizeof(struct rndis_response) + length); + if (QTAILQ_EMPTY(&s->rndis_resp)) { + usb_wakeup(s->intr); + } + QTAILQ_INSERT_TAIL(&s->rndis_resp, r, entries); r->length = length; @@ -1349,6 +1355,7 @@ static int usb_net_initfn(USBDevice *dev) s->media_state = 0; /* NDIS_MEDIA_STATE_CONNECTED */; s->filter = 0; s->vendorid = 0x1234; + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); qemu_macaddr_default_if_unset(&s->conf.macaddr); s->nic = qemu_new_nic(&net_usbnet_info, &s->conf, diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 08b416d..f7342b0 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -43,6 +43,7 @@ typedef struct USBWacomState { USBDevice dev; + USBEndpoint *intr; QEMUPutMouseEntry *eh_entry; int dx, dy, dz, buttons_state; int x, y; @@ -137,6 +138,7 @@ static void usb_mouse_event(void *opaque, s->dz += dz1; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static void usb_wacom_event(void *opaque, @@ -150,6 +152,7 @@ static void usb_wacom_event(void *opaque, s->dz += dz; s->buttons_state = buttons_state; s->changed = 1; + usb_wakeup(s->intr); } static inline int int_clamp(int val, int vmin, int vmax) @@ -337,6 +340,7 @@ static int usb_wacom_initfn(USBDevice *dev) USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev); usb_desc_create_serial(dev); usb_desc_init(dev); + s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); s->changed = 1; return 0; } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 7df8e21..7536837 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -114,6 +114,7 @@ #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction #define MAX_QH 100 // Max allowable queue heads in a chain #define MIN_FR_PER_TICK 3 // Min frames to process when catching up +#define PERIODIC_ACTIVE 64 /* Internal periodic / asynchronous schedule state machine states */ @@ -738,6 +739,19 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], return 0; } +static void ehci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep) +{ + EHCIState *s = container_of(bus, EHCIState, bus); + uint32_t portsc = s->portsc[ep->dev->port->index]; + + if (portsc & PORTSC_POWNER) { + return; + } + + s->periodic_sched_active = PERIODIC_ACTIVE; + qemu_bh_schedule(s->async_bh); +} + static USBDevice *ehci_find_device(EHCIState *ehci, uint8_t addr) { USBDevice *dev; @@ -1188,9 +1202,10 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) trace_usb_ehci_packet_action(p->queue, p, "wakeup"); p->async = EHCI_ASYNC_FINISHED; - if (p->queue->async) { - qemu_bh_schedule(p->queue->ehci->async_bh); + if (!p->queue->async) { + s->periodic_sched_active = PERIODIC_ACTIVE; } + qemu_bh_schedule(s->async_bh); } static void ehci_execute_complete(EHCIQueue *q) @@ -1344,6 +1359,8 @@ static int ehci_process_itd(EHCIState *ehci, uint32_t i, len, pid, dir, devaddr, endp; uint32_t pg, off, ptr1, ptr2, max, mult; + ehci->periodic_sched_active = PERIODIC_ACTIVE; + dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION); devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR); endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP); @@ -2033,6 +2050,9 @@ static void ehci_advance_state(EHCIState *ehci, int async) case EST_WRITEBACK: assert(q != NULL); again = ehci_state_writeback(q); + if (!async) { + ehci->periodic_sched_active = PERIODIC_ACTIVE; + } break; default: @@ -2198,7 +2218,6 @@ static void ehci_frame_timer(void *opaque) if (ehci_periodic_enabled(ehci) || ehci->pstate != EST_INACTIVE) { need_timer++; - ehci->async_stepdown = 0; if (frames > ehci->maxframes) { skipped_frames = frames - ehci->maxframes; @@ -2222,18 +2241,25 @@ static void ehci_frame_timer(void *opaque) break; } } + if (ehci->periodic_sched_active) { + ehci->periodic_sched_active--; + } ehci_update_frindex(ehci, 1); ehci_advance_periodic_state(ehci); ehci->last_run_ns += FRAME_TIMER_NS; } } else { - if (ehci->async_stepdown < ehci->maxframes / 2) { - ehci->async_stepdown++; - } + ehci->periodic_sched_active = 0; ehci_update_frindex(ehci, frames); ehci->last_run_ns += FRAME_TIMER_NS * frames; } + if (ehci->periodic_sched_active) { + ehci->async_stepdown = 0; + } else if (ehci->async_stepdown < ehci->maxframes / 2) { + ehci->async_stepdown++; + } + /* Async is not inside loop since it executes everything it can once * called */ @@ -2301,6 +2327,7 @@ static USBPortOps ehci_port_ops = { static USBBusOps ehci_bus_ops = { .register_companion = ehci_register_companion, + .wakeup_endpoint = ehci_wakeup_endpoint, }; static int usb_ehci_post_load(void *opaque, int version_id) diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index d8078f4..772870b 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -311,6 +311,7 @@ struct EHCIState { uint64_t last_run_ns; uint32_t async_stepdown; + uint32_t periodic_sched_active; bool int_req_by_async; }; diff --git a/hw/usb/host-bsd.c b/hw/usb/host-bsd.c index 6473e8b..dae0009 100644 --- a/hw/usb/host-bsd.c +++ b/hw/usb/host-bsd.c @@ -292,6 +292,7 @@ static void usb_host_handle_destroy(USBDevice *opaque) static int usb_host_initfn(USBDevice *dev) { + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); return 0; } diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index aa77b77..bdafb6b 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1476,6 +1476,7 @@ static int usb_host_initfn(USBDevice *dev) { USBHostDevice *s = DO_UPCAST(USBHostDevice, dev, dev); + dev->flags |= (1 << USB_DEV_FLAG_IS_HOST); dev->auto_attach = 0; s->fd = -1; s->hub_fd = -1; diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 490c90f..9e7f645 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -1644,6 +1644,10 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, return; } + if (QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq)) { + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f)); + } + /* bufp_alloc also adds the packet to the ep queue */ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep); } else { diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 5016e95..57d16c0 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -354,7 +354,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) pm_smbus_init(&s->dev.qdev, &s->smb); memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io); - apm_init(&s->apm, NULL, s); + apm_init(dev, &s->apm, NULL, s); memory_region_init(&s->io, "vt82c686-pm", 64); memory_region_set_enabled(&s->io, false); diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c index baae02b..f2e3bf1 100644 --- a/hw/xilinx_axienet.c +++ b/hw/xilinx_axienet.c @@ -591,6 +591,10 @@ static void enet_write(void *opaque, hwaddr addr, s->maddr[s->fmi & 3][addr & 1] = value; break; + case R_IS: + s->regs[addr] &= ~value; + break; + case 0x8000 ... 0x83ff: s->ext_mtable[addr - 0x8000] = value; break; diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c index d20fc41..02c5850 100644 --- a/hw/xilinx_uartlite.c +++ b/hw/xilinx_uartlite.c @@ -97,6 +97,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size) s->rx_fifo_len--; uart_update_status(s); uart_update_irq(s); + qemu_chr_accept_input(s->chr); break; default: @@ -182,12 +183,8 @@ static void uart_rx(void *opaque, const uint8_t *buf, int size) static int uart_can_rx(void *opaque) { struct xlx_uartlite *s = opaque; - int r; - r = s->rx_fifo_len < sizeof(s->rx_fifo); - if (!r) - printf("cannot receive!\n"); - return r; + return s->rx_fifo_len < sizeof(s->rx_fifo); } static void uart_event(void *opaque, int event) diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h index 5356395..42d6855 100644 --- a/linux-user/arm/syscall_nr.h +++ b/linux-user/arm/syscall_nr.h @@ -182,8 +182,8 @@ #define TARGET_NR_rt_sigtimedwait (177) #define TARGET_NR_rt_sigqueueinfo (178) #define TARGET_NR_rt_sigsuspend (179) -#define TARGET_NR_pread (180) -#define TARGET_NR_pwrite (181) +#define TARGET_NR_pread64 (180) +#define TARGET_NR_pwrite64 (181) #define TARGET_NR_chown (182) #define TARGET_NR_getcwd (183) #define TARGET_NR_capget (184) diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h index 74abfca..f080305 100644 --- a/linux-user/i386/syscall_nr.h +++ b/linux-user/i386/syscall_nr.h @@ -182,8 +182,8 @@ #define TARGET_NR_rt_sigtimedwait 177 #define TARGET_NR_rt_sigqueueinfo 178 #define TARGET_NR_rt_sigsuspend 179 -#define TARGET_NR_pread 180 -#define TARGET_NR_pwrite 181 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 #define TARGET_NR_chown 182 #define TARGET_NR_getcwd 183 #define TARGET_NR_capget 184 diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h index f201f9f..061711c 100644 --- a/linux-user/sparc/syscall_nr.h +++ b/linux-user/sparc/syscall_nr.h @@ -62,8 +62,8 @@ #define TARGET_NR_getpagesize 64 /* Common */ #define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */ #define TARGET_NR_vfork 66 /* Common */ -#define TARGET_NR_pread 67 /* Linux Specific */ -#define TARGET_NR_pwrite 68 /* Linux Specific */ +#define TARGET_NR_pread64 67 /* Linux Specific */ +#define TARGET_NR_pwrite64 68 /* Linux Specific */ #define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */ #define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */ #define TARGET_NR_mmap 71 /* Common */ diff --git a/linux-user/strace.list b/linux-user/strace.list index af3c6a0..08f115d 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -972,9 +972,6 @@ #ifdef TARGET_NR_prctl { TARGET_NR_prctl, "prctl" , NULL, NULL, NULL }, #endif -#ifdef TARGET_NR_pread -{ TARGET_NR_pread, "pread" , NULL, NULL, NULL }, -#endif #ifdef TARGET_NR_pread64 { TARGET_NR_pread64, "pread64" , NULL, NULL, NULL }, #endif @@ -993,9 +990,6 @@ #ifdef TARGET_NR_putpmsg { TARGET_NR_putpmsg, "putpmsg" , NULL, NULL, NULL }, #endif -#ifdef TARGET_NR_pwrite -{ TARGET_NR_pwrite, "pwrite" , NULL, NULL, NULL }, -#endif #ifdef TARGET_NR_pwrite64 { TARGET_NR_pwrite64, "pwrite64" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e4291ed..31d5276 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7449,24 +7449,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, goto unimplemented; #endif #endif -#ifdef TARGET_NR_pread - case TARGET_NR_pread: - if (regpairs_aligned(cpu_env)) - arg4 = arg5; - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - goto efault; - ret = get_errno(pread(arg1, p, arg3, arg4)); - unlock_user(p, arg2, ret); - break; - case TARGET_NR_pwrite: - if (regpairs_aligned(cpu_env)) - arg4 = arg5; - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - goto efault; - ret = get_errno(pwrite(arg1, p, arg3, arg4)); - unlock_user(p, arg2, 0); - break; -#endif #ifdef TARGET_NR_pread64 case TARGET_NR_pread64: if (regpairs_aligned(cpu_env)) { diff --git a/linux-user/unicore32/syscall_nr.h b/linux-user/unicore32/syscall_nr.h index 9c72d84..486b8c4 100644 --- a/linux-user/unicore32/syscall_nr.h +++ b/linux-user/unicore32/syscall_nr.h @@ -187,8 +187,8 @@ #define TARGET_NR_rt_sigtimedwait 177 #define TARGET_NR_rt_sigqueueinfo 178 #define TARGET_NR_rt_sigsuspend 179 -#define TARGET_NR_pread 180 -#define TARGET_NR_pwrite 181 +#define TARGET_NR_pread64 180 +#define TARGET_NR_pwrite64 181 #define TARGET_NR_chown 182 #define TARGET_NR_getcwd 183 #define TARGET_NR_capget 184 diff --git a/qemu-config.c b/qemu-config.c index 10d1ba4..aa78fb9 100644 --- a/qemu-config.c +++ b/qemu-config.c @@ -417,54 +417,6 @@ static QemuOptsList qemu_trace_opts = { }, }; -static QemuOptsList qemu_cpudef_opts = { - .name = "cpudef", - .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head), - .desc = { - { - .name = "name", - .type = QEMU_OPT_STRING, - },{ - .name = "level", - .type = QEMU_OPT_NUMBER, - },{ - .name = "vendor", - .type = QEMU_OPT_STRING, - },{ - .name = "family", - .type = QEMU_OPT_NUMBER, - },{ - .name = "model", - .type = QEMU_OPT_NUMBER, - },{ - .name = "stepping", - .type = QEMU_OPT_NUMBER, - },{ - .name = "feature_edx", /* cpuid 0000_0001.edx */ - .type = QEMU_OPT_STRING, - },{ - .name = "feature_ecx", /* cpuid 0000_0001.ecx */ - .type = QEMU_OPT_STRING, - },{ - .name = "extfeature_edx", /* cpuid 8000_0001.edx */ - .type = QEMU_OPT_STRING, - },{ - .name = "extfeature_ecx", /* cpuid 8000_0001.ecx */ - .type = QEMU_OPT_STRING, - },{ - .name = "xlevel", - .type = QEMU_OPT_NUMBER, - },{ - .name = "model_id", - .type = QEMU_OPT_STRING, - },{ - .name = "vendor_override", - .type = QEMU_OPT_NUMBER, - }, - { /* end of list */ } - }, -}; - QemuOptsList qemu_spice_opts = { .name = "spice", .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), @@ -700,7 +652,6 @@ static QemuOptsList *vm_config_groups[32] = { &qemu_rtc_opts, &qemu_global_opts, &qemu_mon_opts, - &qemu_cpudef_opts, &qemu_trace_opts, &qemu_option_rom_opts, &qemu_machine_opts, diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 4045f78..71fe1a1 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -3410,11 +3410,11 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = ctx.pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = ctx.pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); @@ -3468,7 +3468,7 @@ static inline void gen_intermediate_code_internal(CPUAlphaState *env, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.pc - pc_start; tb->icount = num_insns; @@ -3551,5 +3551,5 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-arm/translate.c b/target-arm/translate.c index c42110a..3cf3604 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9838,12 +9838,12 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_pc[lj] = dc->pc; gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1); - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) @@ -9977,7 +9977,7 @@ done_generating: j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; tb->icount = num_insns; @@ -10043,6 +10043,6 @@ void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf, void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos) { - env->regs[15] = gen_opc_pc[pc_pos]; + env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos]; env->condexec_bits = gen_opc_condexec_bits[pc_pos]; } diff --git a/target-cris/translate.c b/target-cris/translate.c index 0b0e86d..60bdc24 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3301,16 +3301,16 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, if (lj < j) { lj++; while (lj < j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } if (dc->delayed_branch == 1) { - gen_opc_pc[lj] = dc->ppc | 1; + tcg_ctx.gen_opc_pc[lj] = dc->ppc | 1; } else { - gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_pc[lj] = dc->pc; } - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } /* Pretty disas. */ @@ -3439,7 +3439,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } else { tb->size = dc->pc - pc_start; @@ -3621,5 +3621,5 @@ CRISCPU *cpu_cris_init(const char *cpu_model) void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-i386/translate.c b/target-i386/translate.c index 8e676ba..f394ea6 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7988,12 +7988,12 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = pc_ptr; + tcg_ctx.gen_opc_pc[lj] = pc_ptr; gen_opc_cc_op[lj] = dc->cc_op; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); @@ -8037,7 +8037,7 @@ static inline void gen_intermediate_code_internal(CPUX86State *env, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } #ifdef DEBUG_DISAS @@ -8080,16 +8080,17 @@ void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb, int pc_pos) int i; qemu_log("RESTORE:\n"); for(i = 0;i <= pc_pos; i++) { - if (gen_opc_instr_start[i]) { - qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]); + if (tcg_ctx.gen_opc_instr_start[i]) { + qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, + tcg_ctx.gen_opc_pc[i]); } } qemu_log("pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", - pc_pos, gen_opc_pc[pc_pos] - tb->cs_base, + pc_pos, tcg_ctx.gen_opc_pc[pc_pos] - tb->cs_base, (uint32_t)tb->cs_base); } #endif - env->eip = gen_opc_pc[pc_pos] - tb->cs_base; + env->eip = tcg_ctx.gen_opc_pc[pc_pos] - tb->cs_base; cc_op = gen_opc_cc_op[pc_pos]; if (cc_op != CC_OP_DYNAMIC) env->cc_op = cc_op; diff --git a/target-lm32/translate.c b/target-lm32/translate.c index af98649..e131ad1 100644 --- a/target-lm32/translate.c +++ b/target-lm32/translate.c @@ -1051,12 +1051,12 @@ static void gen_intermediate_code_internal(CPULM32State *env, if (lj < j) { lj++; while (lj < j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } - gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } /* Pretty disas. */ @@ -1110,7 +1110,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } else { tb->size = dc->pc - pc_start; @@ -1172,7 +1172,7 @@ void cpu_dump_state(CPULM32State *env, FILE *f, fprintf_function cpu_fprintf, void restore_state_to_opc(CPULM32State *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } void lm32_translate_init(void) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index b13be48..11defc6 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3019,11 +3019,11 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); @@ -3078,7 +3078,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; tb->icount = num_insns; @@ -3121,5 +3121,5 @@ void cpu_dump_state(CPUM68KState *env, FILE *f, fprintf_function cpu_fprintf, void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c index cce4494..6ceff02 100644 --- a/target-microblaze/translate.c +++ b/target-microblaze/translate.c @@ -1788,11 +1788,11 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } /* Pretty disas. */ @@ -1902,7 +1902,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = dc->pc - pc_start; tb->icount = num_insns; @@ -2014,5 +2014,5 @@ MicroBlazeCPU *cpu_mb_init(const char *cpu_model) void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos) { - env->sregs[SR_PC] = gen_opc_pc[pc_pos]; + env->sregs[SR_PC] = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-mips/dsp_helper.c b/target-mips/dsp_helper.c index e7949c2..14daf91 100644 --- a/target-mips/dsp_helper.c +++ b/target-mips/dsp_helper.c @@ -3152,7 +3152,7 @@ target_ulong helper_##name(CPUMIPSState *env, target_ulong rs, \ \ filter = ((int32_t)0x01 << size) - 1; \ filter = filter << pos; \ - temprs = rs & filter; \ + temprs = (rs << pos) & filter; \ temprt = rt & ~filter; \ temp = temprs | temprt; \ \ @@ -3814,17 +3814,18 @@ void helper_shilo(target_ulong ac, target_ulong rs, CPUMIPSState *env) rs5_0 = rs & 0x3F; rs5_0 = (int8_t)(rs5_0 << 2) >> 2; - rs5_0 = MIPSDSP_ABS(rs5_0); + + if (unlikely(rs5_0 == 0)) { + return; + } + acc = (((uint64_t)env->active_tc.HI[ac] << 32) & MIPSDSP_LHI) | ((uint64_t)env->active_tc.LO[ac] & MIPSDSP_LLO); - if (rs5_0 == 0) { - temp = acc; + + if (rs5_0 > 0) { + temp = acc >> rs5_0; } else { - if (rs5_0 > 0) { - temp = acc >> rs5_0; - } else { - temp = acc << rs5_0; - } + temp = acc << -rs5_0; } env->active_tc.HI[ac] = (target_ulong)(int32_t)((temp & MIPSDSP_LHI) >> 32); diff --git a/target-mips/translate.c b/target-mips/translate.c index 71c55bc..65e6725 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15579,13 +15579,13 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = ctx.pc; + tcg_ctx.gen_opc_pc[lj] = ctx.pc; gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK; gen_opc_btarget[lj] = ctx.btarget; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); @@ -15662,7 +15662,7 @@ done_generating: j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.pc - pc_start; tb->icount = num_insns; @@ -16002,7 +16002,7 @@ void cpu_state_reset(CPUMIPSState *env) void restore_state_to_opc(CPUMIPSState *env, TranslationBlock *tb, int pc_pos) { - env->active_tc.PC = gen_opc_pc[pc_pos]; + env->active_tc.PC = tcg_ctx.gen_opc_pc[pc_pos]; env->hflags &= ~MIPS_HFLAG_BMASK; env->hflags |= gen_opc_hflags[pc_pos]; switch (env->hflags & MIPS_HFLAG_BMASK_BASE) { diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c index f14da7b..9ac999a 100644 --- a/target-openrisc/translate.c +++ b/target-openrisc/translate.c @@ -1707,12 +1707,12 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, if (k < j) { k++; while (k < j) { - gen_opc_instr_start[k++] = 0; + tcg_ctx.gen_opc_instr_start[k++] = 0; } } - gen_opc_pc[k] = dc->pc; - gen_opc_instr_start[k] = 1; - gen_opc_icount[k] = num_insns; + tcg_ctx.gen_opc_pc[k] = dc->pc; + tcg_ctx.gen_opc_instr_start[k] = 1; + tcg_ctx.gen_opc_icount[k] = num_insns; } if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { @@ -1787,7 +1787,7 @@ static inline void gen_intermediate_code_internal(OpenRISCCPU *cpu, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; k++; while (k <= j) { - gen_opc_instr_start[k++] = 0; + tcg_ctx.gen_opc_instr_start[k++] = 0; } } else { tb->size = dc->pc - pc_start; @@ -1832,5 +1832,5 @@ void cpu_dump_state(CPUOpenRISCState *env, FILE *f, void restore_state_to_opc(CPUOpenRISCState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 987b04e..653c2fd 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -9680,11 +9680,11 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } - gen_opc_pc[lj] = ctx.nip; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = ctx.nip; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } LOG_DISAS("----------------\n"); LOG_DISAS("nip=" TARGET_FMT_lx " super=%d ir=%d\n", @@ -9781,7 +9781,7 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } else { tb->size = ctx.nip - pc_start; tb->icount = num_insns; @@ -9810,5 +9810,5 @@ void gen_intermediate_code_pc (CPUPPCState *env, struct TranslationBlock *tb) void restore_state_to_opc(CPUPPCState *env, TranslationBlock *tb, int pc_pos) { - env->nip = gen_opc_pc[pc_pos]; + env->nip = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 993f207..787e3c6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -5160,13 +5160,13 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, if (lj < j) { lj++; while (lj < j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } - gen_opc_pc[lj] = dc.pc; + tcg_ctx.gen_opc_pc[lj] = dc.pc; gen_opc_cc_op[lj] = dc.cc_op; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); @@ -5212,7 +5212,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } else { tb->size = dc.pc - pc_start; @@ -5240,7 +5240,7 @@ void gen_intermediate_code_pc (CPUS390XState *env, struct TranslationBlock *tb) void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb, int pc_pos) { int cc_op; - env->psw.addr = gen_opc_pc[pc_pos]; + env->psw.addr = tcg_ctx.gen_opc_pc[pc_pos]; cc_op = gen_opc_cc_op[pc_pos]; if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) { env->cc_op = cc_op; diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 5497ded..86493e1 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -2003,12 +2003,12 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, if (ii < i) { ii++; while (ii < i) - gen_opc_instr_start[ii++] = 0; + tcg_ctx.gen_opc_instr_start[ii++] = 0; } - gen_opc_pc[ii] = ctx.pc; + tcg_ctx.gen_opc_pc[ii] = ctx.pc; gen_opc_hflags[ii] = ctx.flags; - gen_opc_instr_start[ii] = 1; - gen_opc_icount[ii] = num_insns; + tcg_ctx.gen_opc_instr_start[ii] = 1; + tcg_ctx.gen_opc_icount[ii] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); @@ -2061,7 +2061,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, i = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; ii++; while (ii <= i) - gen_opc_instr_start[ii++] = 0; + tcg_ctx.gen_opc_instr_start[ii++] = 0; } else { tb->size = ctx.pc - pc_start; tb->icount = num_insns; @@ -2088,6 +2088,6 @@ void gen_intermediate_code_pc(CPUSH4State * env, struct TranslationBlock *tb) void restore_state_to_opc(CPUSH4State *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; env->flags = gen_opc_hflags[pc_pos]; } diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 2ae8036..5859f2e 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -5283,11 +5283,11 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, if (lj < j) { lj++; while (lj < j) - gen_opc_instr_start[lj++] = 0; - gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_pc[lj] = dc->pc; gen_opc_npc[lj] = dc->npc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) @@ -5339,7 +5339,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; #if 0 log_page_dump(); #endif @@ -5478,7 +5478,7 @@ void gen_intermediate_code_init(CPUSPARCState *env) void restore_state_to_opc(CPUSPARCState *env, TranslationBlock *tb, int pc_pos) { target_ulong npc; - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; npc = gen_opc_npc[pc_pos]; if (npc == 1) { /* dynamic NPC: already stored */ diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c index 052bb45..3951758 100644 --- a/target-unicore32/translate.c +++ b/target-unicore32/translate.c @@ -2003,12 +2003,12 @@ static inline void gen_intermediate_code_internal(CPUUniCore32State *env, if (lj < j) { lj++; while (lj < j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } - gen_opc_pc[lj] = dc->pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = num_insns; + tcg_ctx.gen_opc_pc[lj] = dc->pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = num_insns; } if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { @@ -2117,7 +2117,7 @@ done_generating: j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf; lj++; while (lj <= j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } else { tb->size = dc->pc - pc_start; @@ -2203,5 +2203,5 @@ void cpu_dump_state(CPUUniCore32State *env, FILE *f, void restore_state_to_opc(CPUUniCore32State *env, TranslationBlock *tb, int pc_pos) { - env->regs[31] = gen_opc_pc[pc_pos]; + env->regs[31] = tcg_ctx.gen_opc_pc[pc_pos]; } diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 9d01983..035b07c 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -48,6 +48,9 @@ static void xtensa_cpu_reset(CPUState *s) XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; env->sregs[VECBASE] = env->config->vecbase; env->sregs[IBREAKENABLE] = 0; + env->sregs[CACHEATTR] = 0x22222222; + env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, + XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; env->pending_irq_level = 0; reset_mmu(env); diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 74e9888..08fd5bc 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -65,6 +65,7 @@ enum { XTENSA_OPTION_FP_COPROCESSOR, XTENSA_OPTION_MP_SYNCHRO, XTENSA_OPTION_CONDITIONAL_STORE, + XTENSA_OPTION_ATOMCTL, /* Interrupts and exceptions */ XTENSA_OPTION_EXCEPTION, @@ -93,6 +94,7 @@ enum { XTENSA_OPTION_REGION_PROTECTION, XTENSA_OPTION_REGION_TRANSLATION, XTENSA_OPTION_MMU, + XTENSA_OPTION_CACHEATTR, /* Other */ XTENSA_OPTION_WINDOWED_REGISTER, @@ -128,6 +130,8 @@ enum { ITLBCFG = 91, DTLBCFG = 92, IBREAKENABLE = 96, + CACHEATTR = 98, + ATOMCTL = 99, IBREAKA = 128, DBREAKA = 144, DBREAKC = 160, @@ -149,6 +153,7 @@ enum { ICOUNTLEVEL = 237, EXCVADDR = 238, CCOMPARE = 240, + MISC = 244, }; #define PS_INTLEVEL 0xf @@ -193,6 +198,14 @@ enum { #define REGION_PAGE_MASK 0xe0000000 +#define PAGE_CACHE_MASK 0x700 +#define PAGE_CACHE_SHIFT 8 +#define PAGE_CACHE_INVALID 0x000 +#define PAGE_CACHE_BYPASS 0x100 +#define PAGE_CACHE_WT 0x200 +#define PAGE_CACHE_WB 0x400 +#define PAGE_CACHE_ISOLATE 0x600 + enum { /* Static vectors */ EXC_RESET, @@ -404,6 +417,7 @@ void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); #define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) +#define XTENSA_OPTION_ALL (~(uint64_t)0) static inline bool xtensa_option_bits_enabled(const XtensaConfig *config, uint64_t opt) diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index d94bae2..200fb43 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -390,6 +390,7 @@ int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, static unsigned mmu_attr_to_access(uint32_t attr) { unsigned access = 0; + if (attr < 12) { access |= PAGE_READ; if (attr & 0x1) { @@ -398,8 +399,22 @@ static unsigned mmu_attr_to_access(uint32_t attr) if (attr & 0x2) { access |= PAGE_WRITE; } + + switch (attr & 0xc) { + case 0: + access |= PAGE_CACHE_BYPASS; + break; + + case 4: + access |= PAGE_CACHE_WB; + break; + + case 8: + access |= PAGE_CACHE_WT; + break; + } } else if (attr == 13) { - access |= PAGE_READ | PAGE_WRITE; + access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE; } return access; } @@ -410,14 +425,35 @@ static unsigned mmu_attr_to_access(uint32_t attr) */ static unsigned region_attr_to_access(uint32_t attr) { - unsigned access = 0; - if ((attr < 6 && attr != 3) || attr == 14) { - access |= PAGE_READ | PAGE_WRITE; - } - if (attr > 0 && attr < 6) { - access |= PAGE_EXEC; - } - return access; + static const unsigned access[16] = { + [0] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_WT, + [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, + [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, + [3] = PAGE_EXEC | PAGE_CACHE_WB, + [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, + [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, + [14] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE, + }; + + return access[attr & 0xf]; +} + +/*! + * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, A.2.14 The Cache Attribute Register + */ +static unsigned cacheattr_attr_to_access(uint32_t attr) +{ + static const unsigned access[16] = { + [0] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_WT, + [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, + [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, + [3] = PAGE_EXEC | PAGE_CACHE_WB, + [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, + [14] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE, + }; + + return access[attr & 0xf]; } static bool is_access_granted(unsigned access, int is_write) @@ -566,7 +602,8 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, } else { *paddr = vaddr; *page_size = TARGET_PAGE_SIZE; - *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + *access = cacheattr_attr_to_access( + env->sregs[CACHEATTR] >> ((vaddr & 0xe0000000) >> 27)); return 0; } } @@ -599,24 +636,34 @@ static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, xtensa_tlb_get_entry(env, dtlb, wi, ei); if (entry->asid) { + static const char * const cache_text[8] = { + [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass", + [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT", + [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB", + [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate", + }; unsigned access = attr_to_access(entry->attr); + unsigned cache_idx = (access & PAGE_CACHE_MASK) >> + PAGE_CACHE_SHIFT; if (print_header) { print_header = false; cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text); cpu_fprintf(f, - "\tVaddr Paddr ASID Attr RWX\n" - "\t---------- ---------- ---- ---- ---\n"); + "\tVaddr Paddr ASID Attr RWX Cache\n" + "\t---------- ---------- ---- ---- --- -------\n"); } cpu_fprintf(f, - "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c\n", + "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c %-7s\n", entry->vaddr, entry->paddr, entry->asid, entry->attr, (access & PAGE_READ) ? 'R' : '-', (access & PAGE_WRITE) ? 'W' : '-', - (access & PAGE_EXEC) ? 'X' : '-'); + (access & PAGE_EXEC) ? 'X' : '-', + cache_text[cache_idx] ? cache_text[cache_idx] : + "Invalid"); } } } diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h index 1163c09..5b4cd27 100644 --- a/target-xtensa/helper.h +++ b/target-xtensa/helper.h @@ -23,6 +23,7 @@ DEF_HELPER_3(waiti, void, env, i32, i32) DEF_HELPER_3(timer_irq, void, env, i32, i32) DEF_HELPER_2(advance_ccount, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) +DEF_HELPER_3(check_atomctl, void, env, i32, i32) DEF_HELPER_2(wsr_rasid, void, env, i32) DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index ae0c099..0e0f21d 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -415,6 +415,63 @@ void HELPER(check_interrupts)(CPUXtensaState *env) check_interrupts(env); } +/*! + * Check vaddr accessibility/cache attributes and raise an exception if + * specified by the ATOMCTL SR. + * + * Note: local memory exclusion is not implemented + */ +void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) +{ + uint32_t paddr, page_size, access; + uint32_t atomctl = env->sregs[ATOMCTL]; + int rc = xtensa_get_physical_addr(env, true, vaddr, 1, + xtensa_get_cring(env), &paddr, &page_size, &access); + + /* + * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions, + * see opcode description in the ISA + */ + if (rc == 0 && + (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) { + rc = STORE_PROHIBITED_CAUSE; + } + + if (rc) { + HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); + } + + /* + * When data cache is not configured use ATOMCTL bypass field. + * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL) + * under the Conditional Store Option. + */ + if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { + access = PAGE_CACHE_BYPASS; + } + + switch (access & PAGE_CACHE_MASK) { + case PAGE_CACHE_WB: + atomctl >>= 2; + case PAGE_CACHE_WT: + atomctl >>= 2; + case PAGE_CACHE_BYPASS: + if ((atomctl & 0x3) == 0) { + HELPER(exception_cause_vaddr)(env, pc, + LOAD_STORE_ERROR_CAUSE, vaddr); + } + break; + + case PAGE_CACHE_ISOLATE: + HELPER(exception_cause_vaddr)(env, pc, + LOAD_STORE_ERROR_CAUSE, vaddr); + break; + + default: + break; + } +} + void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v) { v = (v & 0xffffff00) | 0x1; diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h index e395053..dd4f51a 100644 --- a/target-xtensa/overlay_tool.h +++ b/target-xtensa/overlay_tool.h @@ -42,6 +42,10 @@ #define XCHAL_VECBASE_RESET_VADDR 0 #endif +#ifndef XCHAL_HW_MIN_VERSION +#define XCHAL_HW_MIN_VERSION 0 +#endif + #define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0) #define XTENSA_OPTIONS ( \ @@ -62,6 +66,8 @@ XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \ XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \ XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \ + XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \ + XTENSA_OPTION_ATOMCTL) | \ /* Interrupts and exceptions */ \ XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \ XCHAL_OPTION(XCHAL_HAVE_VECBASE, XTENSA_OPTION_RELOCATABLE_VECTOR) | \ @@ -85,9 +91,13 @@ XCHAL_OPTION(XCHAL_HAVE_XLT_CACHEATTR, \ XTENSA_OPTION_REGION_TRANSLATION) | \ XCHAL_OPTION(XCHAL_HAVE_PTP_MMU, XTENSA_OPTION_MMU) | \ + XCHAL_OPTION(XCHAL_HAVE_CACHEATTR, XTENSA_OPTION_CACHEATTR) | \ /* Other, TODO */ \ XCHAL_OPTION(XCHAL_HAVE_WINDOWED, XTENSA_OPTION_WINDOWED_REGISTER) | \ - XCHAL_OPTION(XCHAL_HAVE_DEBUG, XTENSA_OPTION_DEBUG)) + XCHAL_OPTION(XCHAL_HAVE_DEBUG, XTENSA_OPTION_DEBUG) |\ + XCHAL_OPTION(XCHAL_NUM_MISC_REGS > 0, XTENSA_OPTION_MISC_SR) | \ + XCHAL_OPTION(XCHAL_HAVE_THREADPTR, XTENSA_OPTION_THREAD_POINTER) | \ + XCHAL_OPTION(XCHAL_HAVE_PRID, XTENSA_OPTION_PROCESSOR_ID)) #ifndef XCHAL_WINDOW_OF4_VECOFS #define XCHAL_WINDOW_OF4_VECOFS 0x00000000 diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index e5a3f49..5d8762c 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -78,76 +78,117 @@ static TCGv_i32 cpu_UR[256]; #include "gen-icount.h" -static const char * const sregnames[256] = { - [LBEG] = "LBEG", - [LEND] = "LEND", - [LCOUNT] = "LCOUNT", - [SAR] = "SAR", - [BR] = "BR", - [LITBASE] = "LITBASE", - [SCOMPARE1] = "SCOMPARE1", - [ACCLO] = "ACCLO", - [ACCHI] = "ACCHI", - [MR] = "MR0", - [MR + 1] = "MR1", - [MR + 2] = "MR2", - [MR + 3] = "MR3", - [WINDOW_BASE] = "WINDOW_BASE", - [WINDOW_START] = "WINDOW_START", - [PTEVADDR] = "PTEVADDR", - [RASID] = "RASID", - [ITLBCFG] = "ITLBCFG", - [DTLBCFG] = "DTLBCFG", - [IBREAKENABLE] = "IBREAKENABLE", - [IBREAKA] = "IBREAKA0", - [IBREAKA + 1] = "IBREAKA1", - [DBREAKA] = "DBREAKA0", - [DBREAKA + 1] = "DBREAKA1", - [DBREAKC] = "DBREAKC0", - [DBREAKC + 1] = "DBREAKC1", - [EPC1] = "EPC1", - [EPC1 + 1] = "EPC2", - [EPC1 + 2] = "EPC3", - [EPC1 + 3] = "EPC4", - [EPC1 + 4] = "EPC5", - [EPC1 + 5] = "EPC6", - [EPC1 + 6] = "EPC7", - [DEPC] = "DEPC", - [EPS2] = "EPS2", - [EPS2 + 1] = "EPS3", - [EPS2 + 2] = "EPS4", - [EPS2 + 3] = "EPS5", - [EPS2 + 4] = "EPS6", - [EPS2 + 5] = "EPS7", - [EXCSAVE1] = "EXCSAVE1", - [EXCSAVE1 + 1] = "EXCSAVE2", - [EXCSAVE1 + 2] = "EXCSAVE3", - [EXCSAVE1 + 3] = "EXCSAVE4", - [EXCSAVE1 + 4] = "EXCSAVE5", - [EXCSAVE1 + 5] = "EXCSAVE6", - [EXCSAVE1 + 6] = "EXCSAVE7", - [CPENABLE] = "CPENABLE", - [INTSET] = "INTSET", - [INTCLEAR] = "INTCLEAR", - [INTENABLE] = "INTENABLE", - [PS] = "PS", - [VECBASE] = "VECBASE", - [EXCCAUSE] = "EXCCAUSE", - [DEBUGCAUSE] = "DEBUGCAUSE", - [CCOUNT] = "CCOUNT", - [PRID] = "PRID", - [ICOUNT] = "ICOUNT", - [ICOUNTLEVEL] = "ICOUNTLEVEL", - [EXCVADDR] = "EXCVADDR", - [CCOMPARE] = "CCOMPARE0", - [CCOMPARE + 1] = "CCOMPARE1", - [CCOMPARE + 2] = "CCOMPARE2", +typedef struct XtensaReg { + const char *name; + uint64_t opt_bits; + enum { + SR_R = 1, + SR_W = 2, + SR_X = 4, + SR_RW = 3, + SR_RWX = 7, + } access; +} XtensaReg; + +#define XTENSA_REG_ACCESS(regname, opt, acc) { \ + .name = (regname), \ + .opt_bits = XTENSA_OPTION_BIT(opt), \ + .access = (acc), \ + } + +#define XTENSA_REG(regname, opt) XTENSA_REG_ACCESS(regname, opt, SR_RWX) + +#define XTENSA_REG_BITS(regname, opt) { \ + .name = (regname), \ + .opt_bits = (opt), \ + .access = SR_RWX, \ + } + +static const XtensaReg sregnames[256] = { + [LBEG] = XTENSA_REG("LBEG", XTENSA_OPTION_LOOP), + [LEND] = XTENSA_REG("LEND", XTENSA_OPTION_LOOP), + [LCOUNT] = XTENSA_REG("LCOUNT", XTENSA_OPTION_LOOP), + [SAR] = XTENSA_REG_BITS("SAR", XTENSA_OPTION_ALL), + [BR] = XTENSA_REG("BR", XTENSA_OPTION_BOOLEAN), + [LITBASE] = XTENSA_REG("LITBASE", XTENSA_OPTION_EXTENDED_L32R), + [SCOMPARE1] = XTENSA_REG("SCOMPARE1", XTENSA_OPTION_CONDITIONAL_STORE), + [ACCLO] = XTENSA_REG("ACCLO", XTENSA_OPTION_MAC16), + [ACCHI] = XTENSA_REG("ACCHI", XTENSA_OPTION_MAC16), + [MR] = XTENSA_REG("MR0", XTENSA_OPTION_MAC16), + [MR + 1] = XTENSA_REG("MR1", XTENSA_OPTION_MAC16), + [MR + 2] = XTENSA_REG("MR2", XTENSA_OPTION_MAC16), + [MR + 3] = XTENSA_REG("MR3", XTENSA_OPTION_MAC16), + [WINDOW_BASE] = XTENSA_REG("WINDOW_BASE", XTENSA_OPTION_WINDOWED_REGISTER), + [WINDOW_START] = XTENSA_REG("WINDOW_START", + XTENSA_OPTION_WINDOWED_REGISTER), + [PTEVADDR] = XTENSA_REG("PTEVADDR", XTENSA_OPTION_MMU), + [RASID] = XTENSA_REG("RASID", XTENSA_OPTION_MMU), + [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU), + [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU), + [IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG), + [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR), + [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL), + [IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG), + [IBREAKA + 1] = XTENSA_REG("IBREAKA1", XTENSA_OPTION_DEBUG), + [DBREAKA] = XTENSA_REG("DBREAKA0", XTENSA_OPTION_DEBUG), + [DBREAKA + 1] = XTENSA_REG("DBREAKA1", XTENSA_OPTION_DEBUG), + [DBREAKC] = XTENSA_REG("DBREAKC0", XTENSA_OPTION_DEBUG), + [DBREAKC + 1] = XTENSA_REG("DBREAKC1", XTENSA_OPTION_DEBUG), + [EPC1] = XTENSA_REG("EPC1", XTENSA_OPTION_EXCEPTION), + [EPC1 + 1] = XTENSA_REG("EPC2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPC1 + 2] = XTENSA_REG("EPC3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPC1 + 3] = XTENSA_REG("EPC4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPC1 + 4] = XTENSA_REG("EPC5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPC1 + 5] = XTENSA_REG("EPC6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPC1 + 6] = XTENSA_REG("EPC7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [DEPC] = XTENSA_REG("DEPC", XTENSA_OPTION_EXCEPTION), + [EPS2] = XTENSA_REG("EPS2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPS2 + 1] = XTENSA_REG("EPS3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPS2 + 2] = XTENSA_REG("EPS4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPS2 + 3] = XTENSA_REG("EPS5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPS2 + 4] = XTENSA_REG("EPS6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EPS2 + 5] = XTENSA_REG("EPS7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1] = XTENSA_REG("EXCSAVE1", XTENSA_OPTION_EXCEPTION), + [EXCSAVE1 + 1] = XTENSA_REG("EXCSAVE2", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1 + 2] = XTENSA_REG("EXCSAVE3", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1 + 3] = XTENSA_REG("EXCSAVE4", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1 + 4] = XTENSA_REG("EXCSAVE5", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1 + 5] = XTENSA_REG("EXCSAVE6", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [EXCSAVE1 + 6] = XTENSA_REG("EXCSAVE7", + XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), + [CPENABLE] = XTENSA_REG("CPENABLE", XTENSA_OPTION_COPROCESSOR), + [INTSET] = XTENSA_REG_ACCESS("INTSET", XTENSA_OPTION_INTERRUPT, SR_RW), + [INTCLEAR] = XTENSA_REG_ACCESS("INTCLEAR", XTENSA_OPTION_INTERRUPT, SR_W), + [INTENABLE] = XTENSA_REG("INTENABLE", XTENSA_OPTION_INTERRUPT), + [PS] = XTENSA_REG_BITS("PS", XTENSA_OPTION_ALL), + [VECBASE] = XTENSA_REG("VECBASE", XTENSA_OPTION_RELOCATABLE_VECTOR), + [EXCCAUSE] = XTENSA_REG("EXCCAUSE", XTENSA_OPTION_EXCEPTION), + [DEBUGCAUSE] = XTENSA_REG_ACCESS("DEBUGCAUSE", XTENSA_OPTION_DEBUG, SR_R), + [CCOUNT] = XTENSA_REG("CCOUNT", XTENSA_OPTION_TIMER_INTERRUPT), + [PRID] = XTENSA_REG_ACCESS("PRID", XTENSA_OPTION_PROCESSOR_ID, SR_R), + [ICOUNT] = XTENSA_REG("ICOUNT", XTENSA_OPTION_DEBUG), + [ICOUNTLEVEL] = XTENSA_REG("ICOUNTLEVEL", XTENSA_OPTION_DEBUG), + [EXCVADDR] = XTENSA_REG("EXCVADDR", XTENSA_OPTION_EXCEPTION), + [CCOMPARE] = XTENSA_REG("CCOMPARE0", XTENSA_OPTION_TIMER_INTERRUPT), + [CCOMPARE + 1] = XTENSA_REG("CCOMPARE1", + XTENSA_OPTION_TIMER_INTERRUPT), + [CCOMPARE + 2] = XTENSA_REG("CCOMPARE2", + XTENSA_OPTION_TIMER_INTERRUPT), + [MISC] = XTENSA_REG("MISC0", XTENSA_OPTION_MISC_SR), + [MISC + 1] = XTENSA_REG("MISC1", XTENSA_OPTION_MISC_SR), + [MISC + 2] = XTENSA_REG("MISC2", XTENSA_OPTION_MISC_SR), + [MISC + 3] = XTENSA_REG("MISC3", XTENSA_OPTION_MISC_SR), }; -static const char * const uregnames[256] = { - [THREADPTR] = "THREADPTR", - [FCR] = "FCR", - [FSR] = "FSR", +static const XtensaReg uregnames[256] = { + [THREADPTR] = XTENSA_REG("THREADPTR", XTENSA_OPTION_THREAD_POINTER), + [FCR] = XTENSA_REG("FCR", XTENSA_OPTION_FP_COPROCESSOR), + [FSR] = XTENSA_REG("FSR", XTENSA_OPTION_FP_COPROCESSOR), }; void xtensa_translate_init(void) @@ -183,18 +224,18 @@ void xtensa_translate_init(void) } for (i = 0; i < 256; ++i) { - if (sregnames[i]) { + if (sregnames[i].name) { cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUXtensaState, sregs[i]), - sregnames[i]); + sregnames[i].name); } } for (i = 0; i < 256; ++i) { - if (uregnames[i]) { + if (uregnames[i].name) { cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUXtensaState, uregs[i]), - uregnames[i]); + uregnames[i].name); } } #define GEN_HELPER 2 @@ -450,6 +491,28 @@ static void gen_brcondi(DisasContext *dc, TCGCond cond, tcg_temp_free(tmp); } +static void gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) +{ + if (!xtensa_option_bits_enabled(dc->config, sregnames[sr].opt_bits)) { + if (sregnames[sr].name) { + qemu_log("SR %s is not configured\n", sregnames[sr].name); + } else { + qemu_log("SR %d is not implemented\n", sr); + } + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + } else if (!(sregnames[sr].access & access)) { + static const char * const access_text[] = { + [SR_R] = "rsr", + [SR_W] = "wsr", + [SR_X] = "xsr", + }; + assert(access < ARRAY_SIZE(access_text) && access_text[access]); + qemu_log("SR %s is not available for %s\n", sregnames[sr].name, + access_text[access]); + gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); + } +} + static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) { gen_advance_ccount(dc); @@ -471,14 +534,10 @@ static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) [PTEVADDR] = gen_rsr_ptevaddr, }; - if (sregnames[sr]) { - if (rsr_handler[sr]) { - rsr_handler[sr](dc, d, sr); - } else { - tcg_gen_mov_i32(d, cpu_SR[sr]); - } + if (rsr_handler[sr]) { + rsr_handler[sr](dc, d, sr); } else { - qemu_log("RSR %d not implemented, ", sr); + tcg_gen_mov_i32(d, cpu_SR[sr]); } } @@ -556,6 +615,11 @@ static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_jumpi_check_loop_end(dc, 0); } +static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f); +} + static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) { unsigned id = sr - IBREAKA; @@ -640,14 +704,6 @@ static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_jumpi_check_loop_end(dc, -1); } -static void gen_wsr_debugcause(DisasContext *dc, uint32_t sr, TCGv_i32 v) -{ -} - -static void gen_wsr_prid(DisasContext *dc, uint32_t sr, TCGv_i32 v) -{ -} - static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v) { if (dc->icount) { @@ -693,6 +749,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [ITLBCFG] = gen_wsr_tlbcfg, [DTLBCFG] = gen_wsr_tlbcfg, [IBREAKENABLE] = gen_wsr_ibreakenable, + [ATOMCTL] = gen_wsr_atomctl, [IBREAKA] = gen_wsr_ibreaka, [IBREAKA + 1] = gen_wsr_ibreaka, [DBREAKA] = gen_wsr_dbreaka, @@ -704,8 +761,6 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [INTCLEAR] = gen_wsr_intclear, [INTENABLE] = gen_wsr_intenable, [PS] = gen_wsr_ps, - [DEBUGCAUSE] = gen_wsr_debugcause, - [PRID] = gen_wsr_prid, [ICOUNT] = gen_wsr_icount, [ICOUNTLEVEL] = gen_wsr_icountlevel, [CCOMPARE] = gen_wsr_ccompare, @@ -713,14 +768,10 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [CCOMPARE + 2] = gen_wsr_ccompare, }; - if (sregnames[sr]) { - if (wsr_handler[sr]) { - wsr_handler[sr](dc, sr, s); - } else { - tcg_gen_mov_i32(cpu_SR[sr], s); - } + if (wsr_handler[sr]) { + wsr_handler[sr](dc, sr, s); } else { - qemu_log("WSR %d not implemented, ", sr); + tcg_gen_mov_i32(cpu_SR[sr], s); } } @@ -1352,12 +1403,14 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 1: /*ABS*/ { - int label = gen_new_label(); - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]); - tcg_gen_brcondi_i32( - TCG_COND_GE, cpu_R[RRR_R], 0, label); - tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); - gen_set_label(label); + 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; @@ -1431,6 +1484,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 6: /*XSR*/ { TCGv_i32 tmp = tcg_temp_new_i32(); + gen_check_sr(dc, RSR_SR, SR_X); if (RSR_SR >= 64) { gen_check_privilege(dc); } @@ -1439,9 +1493,6 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) gen_rsr(dc, cpu_R[RRR_T], RSR_SR); gen_wsr(dc, RSR_SR, tmp); tcg_temp_free(tmp); - if (!sregnames[RSR_SR]) { - TBD(); - } } break; @@ -1664,25 +1715,21 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 3: /*RST3*/ switch (OP2) { case 0: /*RSR*/ + gen_check_sr(dc, RSR_SR, SR_R); if (RSR_SR >= 64) { gen_check_privilege(dc); } gen_window_check1(dc, RRR_T); gen_rsr(dc, cpu_R[RRR_T], RSR_SR); - if (!sregnames[RSR_SR]) { - TBD(); - } break; case 1: /*WSR*/ + gen_check_sr(dc, RSR_SR, SR_W); if (RSR_SR >= 64) { gen_check_privilege(dc); } gen_window_check1(dc, RRR_T); gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); - if (!sregnames[RSR_SR]) { - TBD(); - } break; case 2: /*SEXTu*/ @@ -1710,22 +1757,20 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) { TCGv_i32 tmp1 = tcg_temp_new_i32(); TCGv_i32 tmp2 = tcg_temp_new_i32(); - int label = gen_new_label(); + 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_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp2, 0, label); tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31); - tcg_gen_xori_i32(cpu_R[RRR_R], tmp1, - 0xffffffff >> (25 - RRR_T)); - - gen_set_label(label); + 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; @@ -1742,19 +1787,9 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) TCG_COND_LEU, TCG_COND_GEU }; - int label = gen_new_label(); - - if (RRR_R != RRR_T) { - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - tcg_gen_brcond_i32(cond[OP2 - 4], - cpu_R[RRR_S], cpu_R[RRR_T], label); - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_T]); - } else { - tcg_gen_brcond_i32(cond[OP2 - 4], - cpu_R[RRR_T], cpu_R[RRR_S], label); - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - } - gen_set_label(label); + 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; @@ -1765,15 +1800,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) gen_window_check3(dc, RRR_R, RRR_S, RRR_T); { static const TCGCond cond[] = { - TCG_COND_NE, TCG_COND_EQ, + TCG_COND_NE, + TCG_COND_LT, TCG_COND_GE, - TCG_COND_LT }; - int label = gen_new_label(); - tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label); - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - gen_set_label(label); + 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; @@ -1782,16 +1818,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) HAS_OPTION(XTENSA_OPTION_BOOLEAN); gen_window_check2(dc, RRR_R, RRR_S); { - int label = gen_new_label(); + 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_brcondi_i32( - OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE, - tmp, 0, label); - tcg_gen_mov_i32(cpu_R[RRR_R], cpu_R[RRR_S]); - gen_set_label(label); + 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; @@ -1799,7 +1835,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) gen_window_check1(dc, RRR_R); { int st = (RRR_S << 4) + RRR_T; - if (uregnames[st]) { + if (uregnames[st].name) { tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]); } else { qemu_log("RUR %d not implemented, ", st); @@ -1810,7 +1846,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) case 15: /*WUR*/ gen_window_check1(dc, RRR_T); - if (uregnames[RSR_SR]) { + if (uregnames[RSR_SR].name) { gen_wur(RSR_SR, cpu_R[RRR_T]); } else { qemu_log("WUR %d not implemented, ", RSR_SR); @@ -2082,15 +2118,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) gen_check_cpenable(dc, 0); { static const TCGCond cond[] = { - TCG_COND_NE, TCG_COND_EQ, + TCG_COND_NE, + TCG_COND_LT, TCG_COND_GE, - TCG_COND_LT }; - int label = gen_new_label(); - tcg_gen_brcondi_i32(cond[OP2 - 8], cpu_R[RRR_T], 0, label); - tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_FR[RRR_S]); - gen_set_label(label); + 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; @@ -2099,16 +2136,16 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) HAS_OPTION(XTENSA_OPTION_BOOLEAN); gen_check_cpenable(dc, 0); { - int label = gen_new_label(); + 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_brcondi_i32( - OP2 & 1 ? TCG_COND_EQ : TCG_COND_NE, - tmp, 0, label); - tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_FR[RRR_S]); - gen_set_label(label); + 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; @@ -2317,10 +2354,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) int 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); + + gen_advance_ccount(dc); + 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); @@ -2328,6 +2370,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) tcg_gen_qemu_st32(tmp, addr, dc->cring); gen_set_label(label); + tcg_temp_free(tpc); tcg_temp_free(addr); tcg_temp_free(tmp); } @@ -2897,12 +2940,12 @@ static void gen_intermediate_code_internal( if (lj < j) { lj++; while (lj < j) { - gen_opc_instr_start[lj++] = 0; + tcg_ctx.gen_opc_instr_start[lj++] = 0; } } - gen_opc_pc[lj] = dc.pc; - gen_opc_instr_start[lj] = 1; - gen_opc_icount[lj] = insn_count; + tcg_ctx.gen_opc_pc[lj] = dc.pc; + tcg_ctx.gen_opc_instr_start[lj] = 1; + tcg_ctx.gen_opc_icount[lj] = insn_count; } if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { @@ -2986,8 +3029,8 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "PC=%08x\n\n", env->pc); for (i = j = 0; i < 256; ++i) { - if (sregnames[i]) { - cpu_fprintf(f, "%s=%08x%c", sregnames[i], env->sregs[i], + if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) { + cpu_fprintf(f, "%12s=%08x%c", sregnames[i].name, env->sregs[i], (j++ % 4) == 3 ? '\n' : ' '); } } @@ -2995,8 +3038,8 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); for (i = j = 0; i < 256; ++i) { - if (uregnames[i]) { - cpu_fprintf(f, "%s=%08x%c", uregnames[i], env->uregs[i], + if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) { + cpu_fprintf(f, "%s=%08x%c", uregnames[i].name, env->uregs[i], (j++ % 4) == 3 ? '\n' : ' '); } } @@ -3004,7 +3047,7 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); for (i = 0; i < 16; ++i) { - cpu_fprintf(f, "A%02d=%08x%c", i, env->regs[i], + cpu_fprintf(f, " A%02d=%08x%c", i, env->regs[i], (i % 4) == 3 ? '\n' : ' '); } @@ -3028,5 +3071,5 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf, void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, int pc_pos) { - env->pc = gen_opc_pc[pc_pos]; + env->pc = tcg_ctx.gen_opc_pc[pc_pos]; } @@ -455,6 +455,9 @@ struct TCGContext { uint16_t *gen_opc_ptr; TCGArg *gen_opparam_ptr; + target_ulong gen_opc_pc[OPC_BUF_SIZE]; + uint16_t gen_opc_icount[OPC_BUF_SIZE]; + uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(CONFIG_QEMU_LDST_OPTIMIZATION) && defined(CONFIG_SOFTMMU) /* labels info for qemu_ld/st IRs diff --git a/tests/tcg/mips/mips32-dsp/insv.c b/tests/tcg/mips/mips32-dsp/insv.c index 7e3b047..243b007 100644 --- a/tests/tcg/mips/mips32-dsp/insv.c +++ b/tests/tcg/mips/mips32-dsp/insv.c @@ -10,7 +10,7 @@ int main() dsp = 0x305; rt = 0x12345678; rs = 0x87654321; - result = 0x12345338; + result = 0x12345438; __asm ("wrdsp %2, 0x03\n\t" "insv %0, %1\n\t" diff --git a/tests/tcg/mips/mips32-dsp/shilo.c b/tests/tcg/mips/mips32-dsp/shilo.c index b686616..ce8ebc6 100644 --- a/tests/tcg/mips/mips32-dsp/shilo.c +++ b/tests/tcg/mips/mips32-dsp/shilo.c @@ -23,5 +23,23 @@ int main() assert(ach == resulth); assert(acl == resultl); + + ach = 0x1; + acl = 0x80000000; + + resulth = 0x3; + resultl = 0x0; + + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "shilo $ac1, -1\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/mips/mips32-dsp/shilov.c b/tests/tcg/mips/mips32-dsp/shilov.c index f186032..e1d6cea 100644 --- a/tests/tcg/mips/mips32-dsp/shilov.c +++ b/tests/tcg/mips/mips32-dsp/shilov.c @@ -25,5 +25,25 @@ int main() assert(ach == resulth); assert(acl == resultl); + + rs = 0xffffffff; + ach = 0x1; + acl = 0x80000000; + + resulth = 0x3; + resultl = 0x0; + + __asm + ("mthi %0, $ac1\n\t" + "mtlo %1, $ac1\n\t" + "shilov $ac1, %2\n\t" + "mfhi %0, $ac1\n\t" + "mflo %1, $ac1\n\t" + : "+r"(ach), "+r"(acl) + : "r"(rs) + ); + assert(ach == resulth); + assert(acl == resultl); + return 0; } diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile index 0ff0ccf..002fd87 100644 --- a/tests/tcg/xtensa/Makefile +++ b/tests/tcg/xtensa/Makefile @@ -42,9 +42,11 @@ endif TESTCASES += test_quo.tst TESTCASES += test_rem.tst TESTCASES += test_rst0.tst +TESTCASES += test_s32c1i.tst TESTCASES += test_sar.tst TESTCASES += test_sext.tst TESTCASES += test_shift.tst +TESTCASES += test_sr.tst TESTCASES += test_timer.tst TESTCASES += test_windowed.tst diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc index 23bf3e9..c9be1ce 100644 --- a/tests/tcg/xtensa/macros.inc +++ b/tests/tcg/xtensa/macros.inc @@ -1,7 +1,7 @@ .macro test_suite name .data status: .word result -result: .space 20 +result: .space 256 .text .global main .align 4 diff --git a/tests/tcg/xtensa/test_s32c1i.S b/tests/tcg/xtensa/test_s32c1i.S new file mode 100644 index 0000000..4536015 --- /dev/null +++ b/tests/tcg/xtensa/test_s32c1i.S @@ -0,0 +1,39 @@ +.include "macros.inc" + +test_suite s32c1i + +test s32c1i_nowrite + movi a2, 1f + movi a3, 1 + wsr a3, scompare1 + movi a1, 2 + s32c1i a1, a2, 0 + assert ne, a1, a3 + l32i a1, a2, 0 + assert eqi, a1, 3 + +.data +.align 4 +1: + .word 3 +.text +test_end + +test s32c1i_write + movi a2, 1f + movi a3, 3 + wsr a3, scompare1 + movi a1, 2 + s32c1i a1, a2, 0 + assert eq, a1, a3 + l32i a1, a2, 0 + assert eqi, a1, 2 + +.data +.align 4 +1: + .word 3 +.text +test_end + +test_suite_end diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S new file mode 100644 index 0000000..470c03d --- /dev/null +++ b/tests/tcg/xtensa/test_sr.S @@ -0,0 +1,90 @@ +.include "macros.inc" + +test_suite sr + +.macro sr_op sym, op_sym, op_byte, sr + .if \sym + \op_sym a4, \sr + .else + .byte 0x40, \sr, \op_byte + .endif +.endm + +.macro test_sr_op sym, mask, op, op_byte, sr + movi a4, 0 + .if (\mask) + set_vector kernel, 0 + sr_op \sym, \op, \op_byte, \sr + .else + set_vector kernel, 2f +1: + sr_op \sym, \op, \op_byte, \sr + test_fail +2: + reset_ps + rsr a2, exccause + assert eqi, a2, 0 + rsr a2, epc1 + movi a3, 1b + assert eq, a2, a3 + .endif +.endm + +.macro test_sr_mask sr, sym, mask +test \sr + test_sr_op \sym, \mask & 1, rsr, 0x03, \sr + test_sr_op \sym, \mask & 2, wsr, 0x13, \sr + test_sr_op \sym, \mask & 4, xsr, 0x61, \sr +test_end +.endm + +.macro test_sr sr, conf + test_sr_mask \sr, \conf, 7 +.endm + +test_sr acchi, 1 +test_sr acclo, 1 +test_sr_mask /*atomctl*/99, 0, 0 +test_sr_mask /*br*/4, 0, 0 +test_sr_mask /*cacheattr*/98, 0, 0 +test_sr ccompare0, 1 +test_sr ccount, 1 +test_sr cpenable, 1 +test_sr dbreaka0, 1 +test_sr dbreakc0, 1 +test_sr_mask debugcause, 1, 1 +test_sr depc, 1 +test_sr dtlbcfg, 1 +test_sr epc1, 1 +test_sr epc2, 1 +test_sr eps2, 1 +test_sr exccause, 1 +test_sr excsave1, 1 +test_sr excsave2, 1 +test_sr excvaddr, 1 +test_sr ibreaka0, 1 +test_sr ibreakenable, 1 +test_sr icount, 1 +test_sr icountlevel, 1 +test_sr_mask /*intclear*/227, 0, 2 +test_sr_mask /*interrupt*/226, 0, 3 +test_sr intenable, 1 +test_sr itlbcfg, 1 +test_sr lbeg, 1 +test_sr lcount, 1 +test_sr lend, 1 +test_sr litbase, 1 +test_sr m0, 1 +test_sr misc0, 1 +test_sr_mask /*prefctl*/40, 0, 0 +test_sr_mask /*prid*/235, 0, 1 +test_sr ps, 1 +test_sr ptevaddr, 1 +test_sr rasid, 1 +test_sr sar, 1 +test_sr scompare1, 1 +test_sr vecbase, 1 +test_sr windowbase, 1 +test_sr windowstart, 1 + +test_suite_end diff --git a/translate-all.c b/translate-all.c index d9c2e57..f22e3ee 100644 --- a/translate-all.c +++ b/translate-all.c @@ -33,10 +33,6 @@ /* code generation context */ TCGContext tcg_ctx; -target_ulong gen_opc_pc[OPC_BUF_SIZE]; -uint16_t gen_opc_icount[OPC_BUF_SIZE]; -uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; - void cpu_gen_init(void) { tcg_context_init(&tcg_ctx); @@ -146,9 +142,10 @@ int cpu_restore_state(TranslationBlock *tb, if (j < 0) return -1; /* now find start of instruction before */ - while (gen_opc_instr_start[j] == 0) + while (s->gen_opc_instr_start[j] == 0) { j--; - env->icount_decr.u16.low -= gen_opc_icount[j]; + } + env->icount_decr.u16.low -= s->gen_opc_icount[j]; restore_state_to_opc(env, tb, j); diff --git a/ui/curses.c b/ui/curses.c index b40b223..5dc0b2c 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -28,10 +28,6 @@ #include <termios.h> #endif -#ifdef __OpenBSD__ -#define resize_term resizeterm -#endif - #include "qemu-common.h" #include "console.h" #include "sysemu.h" |