From 5163f6e864760e038964f1e38ee065b241695f35 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 27 Feb 2010 10:50:32 +0100 Subject: Fix qemu -net user,hostfwd= example Signed-off-by: Aurelien Jarno (cherry picked from commit aa375206189b7de7c23ad9de66413fb7d4497940) --- qemu-options.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-options.hx b/qemu-options.hx index c22b99996..8de71d6ba 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -968,7 +968,7 @@ the guest, use the following: @example # on the host -qemu -net user,hostfwd=tcp:5555::23 [...] +qemu -net user,hostfwd=tcp::5555-:23 [...] telnet localhost 5555 @end example -- cgit v1.2.3 From 41a5bda61fcab457cbfe8aa5f55cf7aadd0067a9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 4 Feb 2010 14:31:50 +0100 Subject: fix undefined shifts by >32 This one is for 0.12 too. Signed-off-by: Paolo Bonzini Signed-off-by: Blue Swirl (cherry picked from commit 0dfbd514460045e3af1ed6805ab97ffedbbd1ab2) --- vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vl.c b/vl.c index 40b07fe93..2dbb6dbc1 100644 --- a/vl.c +++ b/vl.c @@ -2573,9 +2573,9 @@ static void numa_add(const char *optarg) fprintf(stderr, "only 63 CPUs in NUMA mode supported.\n"); } - value = (1 << (endvalue + 1)) - (1 << value); + value = (2ULL << endvalue) - (1ULL << value); } else { - value = 1 << value; + value = 1ULL << value; } } node_cpumask[nodenr] = value; -- cgit v1.2.3 From cc21d131e347673564ccc10f9d30c9995f4b664e Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 18 Jan 2010 12:15:01 +0100 Subject: qemu-char.c: drop debug printfs from qemu_chr_parse_compat Signed-off-by: Jan Kiszka Acked-by: Gerd Hoffmann Signed-off-by: Aurelien Jarno (cherry picked from commit 5bb599023a6478e86152a2e8bc2b21775261b9da) --- qemu-char.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/qemu-char.c b/qemu-char.c index 5a1b535bd..f00f90ad6 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2318,7 +2318,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { - fprintf(stderr, "udp #1\n"); goto fail; } } @@ -2329,7 +2328,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) { host[0] = 0; if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { - fprintf(stderr, "udp #2\n"); goto fail; } } @@ -2357,7 +2355,6 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) } fail: - fprintf(stderr, "%s: fail on \"%s\"\n", __FUNCTION__, filename); qemu_opts_del(opts); return NULL; } -- cgit v1.2.3 From 7d5625d5f7c1550a41774bed699c0d9b3feeedec Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 6 Mar 2010 18:33:53 +0100 Subject: target-i386: fix lddqu SSE instruction This instruction load data from memory to register and not the reverse. Signed-off-by: Aurelien Jarno (cherry picked from commit c22549204a6edc431e8e4358e61bd56386ff6957) --- target-i386/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 511a4eae9..4ab226f43 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3169,7 +3169,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); + gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); break; case 0x22b: /* movntss */ case 0x32b: /* movntsd */ -- cgit v1.2.3 From c248df6161e7cacaa37f3214323307b8cb29dd28 Mon Sep 17 00:00:00 2001 From: malc Date: Thu, 4 Mar 2010 15:09:26 +0300 Subject: target-i386: Fix long jumps/calls in long mode with REX.W set Signed-off-by: malc Signed-off-by: Aurelien Jarno (cherry picked from commit 41b1e61f51b05fd6ca060f901b822f83e0beb6b6) --- target-i386/translate.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 4ab226f43..0f7255d9d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4591,9 +4591,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* operand size for jumps is 64 bit */ ot = OT_QUAD; } else if (op == 3 || op == 5) { - /* for call calls, the operand is 16 or 32 bit, even - in long mode */ - ot = dflag ? OT_LONG : OT_WORD; + ot = dflag ? OT_LONG + (rex_w == 1) : OT_WORD; } else if (op == 6) { /* default push size is 64 bit */ ot = dflag ? OT_QUAD : OT_WORD; -- cgit v1.2.3 From b299b12b176792db8ff47c4d22fa62e4d64a0614 Mon Sep 17 00:00:00 2001 From: Ryan Harper Date: Tue, 23 Feb 2010 09:13:14 -0600 Subject: Fix segfault with ram_size > 4095M without kvm Currently, x86_64-softmmu qemu segfaults when trying to use > 4095M memsize. This patch adds a simple check and error message (much like the 2047 limit on 32-bit hosts) on ram_size in the control path after we determine we're not using kvm Upstream qemu-kvm is affected if using the -no-kvm option; this patch address the segfault there as well. Signed-off-by: Ryan Harper Signed-off-by: Aurelien Jarno --- vl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vl.c b/vl.c index 2dbb6dbc1..bb9c21ce8 100644 --- a/vl.c +++ b/vl.c @@ -5792,6 +5792,12 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "failed to initialize KVM\n"); exit(1); } + } else { + /* without kvm enabled, we can only support 4095 MB RAM */ + if (ram_size > (4095UL << 20)) { + fprintf(stderr, "qemu: without kvm support at most 4095 MB RAM can be simulated\n"); + exit(1); + } } if (qemu_init_main_loop()) { -- cgit v1.2.3 From d2df336c582d74650f4ccc3ef4e84ac86c2868fe Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sat, 6 Mar 2010 18:02:31 +0100 Subject: target-i386: fix SIB decoding with index = 4 A SIB byte with an index of 4 means "no scaled index", even if the scale value is not 0. In 64-bit mode, if REX.X is used, an index of 4 selects %r12. This is correctly handled by the computation of the index variable, which includes the index bits, and also the REX.X prefix: index = ((code >> 3) & 7) | REX_X(s); Thanks to Avi Kivity, Jamie Lokier and Malc for the analysis of the problem and the initial patch. Signed-off-by: Aurelien Jarno (cherry picked from commit b16f827bdf7444b8cd338b9ecb654b4752f47225) --- target-i386/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 0f7255d9d..a61db16ec 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2047,8 +2047,8 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ gen_op_movl_A0_im(disp); } } - /* XXX: index == 4 is always invalid */ - if (havesib && (index != 4 || scale != 0)) { + /* index == 4 means no index */ + if (havesib && (index != 4)) { #ifdef TARGET_X86_64 if (s->aflag == 2) { gen_op_addq_A0_reg_sN(scale, index); -- cgit v1.2.3 From c5f5dc5bad4cec580f10b31fcafd1dd5bd93c88f Mon Sep 17 00:00:00 2001 From: TeLeMan Date: Fri, 12 Mar 2010 19:38:06 +0800 Subject: target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 The commit c22549204a6edc431e8e4358e61bd56386ff6957 led movntps & movntdq to be translated incorrectly. Signed-off-by: TeLeMan Signed-off-by: Aurelien Jarno (cherry picked from commit 2e21e7491ff2af3628a97d4652e7adcc6961c2e9) --- target-i386/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-i386/translate.c b/target-i386/translate.c index a61db16ec..3de65bd1d 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -3165,6 +3165,11 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) case 0x1e7: /* movntdq */ case 0x02b: /* movntps */ case 0x12b: /* movntps */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg])); + break; case 0x3f0: /* lddqu */ if (mod == 3) goto illegal_op; -- cgit v1.2.3 From 30d061750d965f37e77ee5678e5b9b2e57bacb73 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 10 Mar 2010 17:30:29 +0100 Subject: fdc: fix drive property handling. Fix the floppy controller init wrappers to set the drive properties only in case the DriveInfo pointers passed in are non NULL. This allows to set the properties using -global. Signed-off-by: Gerd Hoffmann Signed-off-by: Aurelien Jarno (cherry picked from commit 995bf0ca57e52f4991d7f90c7eb2bbf7bc3f3c44) --- hw/fdc.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/fdc.c b/hw/fdc.c index 0579b0372..b29136552 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -1860,8 +1860,12 @@ fdctrl_t *fdctrl_init_isa(DriveInfo **fds) ISADevice *dev; dev = isa_create("isa-fdc"); - qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]); - qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]); + if (fds[0]) { + qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]); + } + if (fds[1]) { + qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]); + } if (qdev_init(&dev->qdev) < 0) return NULL; return &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state); @@ -1879,8 +1883,12 @@ fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann, sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev); fdctrl = &sys->state; fdctrl->dma_chann = dma_chann; /* FIXME */ - qdev_prop_set_drive(dev, "driveA", fds[0]); - qdev_prop_set_drive(dev, "driveB", fds[1]); + if (fds[0]) { + qdev_prop_set_drive(dev, "driveA", fds[0]); + } + if (fds[1]) { + qdev_prop_set_drive(dev, "driveB", fds[1]); + } qdev_init_nofail(dev); sysbus_connect_irq(&sys->busdev, 0, irq); sysbus_mmio_map(&sys->busdev, 0, mmio_base); @@ -1896,7 +1904,9 @@ fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base, fdctrl_t *fdctrl; dev = qdev_create(NULL, "SUNW,fdtwo"); - qdev_prop_set_drive(dev, "drive", fds[0]); + if (fds[0]) { + qdev_prop_set_drive(dev, "drive", fds[0]); + } qdev_init_nofail(dev); sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev); fdctrl = &sys->state; -- cgit v1.2.3 From 8ec131fb593dede3e2113490af77ee20a4e26faa Mon Sep 17 00:00:00 2001 From: Vagrant Cascadian Date: Sun, 14 Mar 2010 08:51:53 +0000 Subject: spelling typo (compatibilty) in hw/fw_cfg.c here's a trivial patch to fix the spelling of "compatibility": Signed-off-by: Vagrant Cascadian Signed-off-by: Blue Swirl (cherry picked from commit 66c80e75752e87a9479577fda1446a7623884f01) --- hw/fw_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index ea120ba55..c62bf522d 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -179,7 +179,7 @@ static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size) static void put_unused(QEMUFile *f, void *pv, size_t size) { - fprintf(stderr, "uint32_as_uint16 is only used for backward compatibilty.\n"); + fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n"); fprintf(stderr, "This functions shouldn't be called.\n"); } -- cgit v1.2.3 From 2a7996ce0ed1b1c0db686f60d0ded426698676e6 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sun, 7 Mar 2010 11:28:40 +0100 Subject: Don't set default monitor when there is a mux'ed one This fixes eg. "-nographic -serial mon:stdio [-serial ...]". Signed-off-by: Jan Kiszka Signed-off-by: Aurelien Jarno (cherry picked from commit 18141ed67f5ee8c7e8e3f8bffdb24d7b8cdbc270) --- vl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vl.c b/vl.c index bb9c21ce8..425bb4b6f 100644 --- a/vl.c +++ b/vl.c @@ -5368,6 +5368,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_serial: add_device_config(DEV_SERIAL, optarg); default_serial = 0; + if (strncmp(optarg, "mon:", 4) == 0) { + default_monitor = 0; + } break; case QEMU_OPTION_watchdog: if (watchdog) { @@ -5386,10 +5389,16 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_virtiocon: add_device_config(DEV_VIRTCON, optarg); default_virtcon = 0; + if (strncmp(optarg, "mon:", 4) == 0) { + default_monitor = 0; + } break; case QEMU_OPTION_parallel: add_device_config(DEV_PARALLEL, optarg); default_parallel = 0; + if (strncmp(optarg, "mon:", 4) == 0) { + default_monitor = 0; + } break; case QEMU_OPTION_loadvm: loadvm = optarg; -- cgit v1.2.3 From 6629fa647330f6d28ba843cda2c0700dc7d4c952 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Sun, 7 Mar 2010 11:28:48 +0100 Subject: Fix corner case in chardev udp: parameter The missing '@' broke 'udp::@:' parsing. Signed-off-by: Jan Kiszka Signed-off-by: Aurelien Jarno (cherry picked from commit 39324ca488ac8f7124b3698d28bf46b90d9acd84) --- qemu-char.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-char.c b/qemu-char.c index f00f90ad6..30f39caae 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2317,7 +2317,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) qemu_opt_set(opts, "backend", "udp"); if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) { host[0] = 0; - if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) { + if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) { goto fail; } } -- cgit v1.2.3 From 18a21890ff2b24bc7f0cdc3807e2fb65e014522b Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 13 Dec 2009 19:03:31 +0000 Subject: workaround for cmd646 bmdma register access while no dma is active This is a workaround only, and is a partial revert of a few changes to BMDMAState which removed pci_dev field on the way. - cmd646 pci_from_bm() expects bm->unit value to correspond with bm data being passed to callback as opaque pointer. This breaks when write to dma control register of second channel happens when no dma operation is in progress, so bm->unit is zero for second channel, and pci_from_bm() returns garbage pointer. Crash happens shortly after that while dereferencing that pointer. v0->v1: cleaned up dead code from pci_from_bm. Signed-off-by: Igor V. Kovalenko Signed-off-by: Blue Swirl (cherry picked from commit 90228ee395b71cdd64e6bc844e3d553eb9ef643f) --- hw/ide/cmd646.c | 7 ++----- hw/ide/internal.h | 1 + hw/ide/piix.c | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index e1e626e2a..835c98d72 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -70,11 +70,7 @@ static void ide_map(PCIDevice *pci_dev, int region_num, static PCIIDEState *pci_from_bm(BMDMAState *bm) { - if (bm->unit == 0) { - return container_of(bm, PCIIDEState, bmdma[0]); - } else { - return container_of(bm, PCIIDEState, bmdma[1]); - } + return bm->pci_dev; } static uint32_t bmdma_readb(void *opaque, uint32_t addr) @@ -145,6 +141,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, BMDMAState *bm = &d->bmdma[i]; d->bus[i].bmdma = bm; bm->bus = d->bus+i; + bm->pci_dev = d; qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 8869a0834..8615d1a1f 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -481,6 +481,7 @@ struct BMDMAState { uint8_t status; uint32_t addr; + struct PCIIDEState *pci_dev; IDEBus *bus; /* current transfer state */ uint32_t cur_addr; diff --git a/hw/ide/piix.c b/hw/ide/piix.c index de3648023..2776ac365 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -78,6 +78,7 @@ static void bmdma_map(PCIDevice *pci_dev, int region_num, BMDMAState *bm = &d->bmdma[i]; d->bus[i].bmdma = bm; bm->bus = d->bus+i; + bm->pci_dev = d; qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); -- cgit v1.2.3 From 5c6892078a2a9d3919a5b99942c9f0132e34080d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 5 Mar 2010 08:35:07 +0100 Subject: tcg/arm: correctly save/restore registers in prologue/epilogue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 6113d6d3169393c323ac4c82d756a850145a5e7a QEMU crashes on ARM hosts. This is not a bug of this commit, but a latent bug revealed by this commit. The TCG code is called through a procedure call using the prologue and epilogue code. This code does not save and restore enough registers. The "Procedure Call Standard for the ARM Architecture" says: A subroutine must preserve the contents of the registers r4-r8, r10,  r11 and SP (and r9 in PCS variants that designate r9 as v6). The current code only saves and restores r9 to r11, and misses r4 to r8. The patch fixes that by saving r4 to r12. Theoretically there is no need to save and restore r12, but an even number of registers have to be saved as per EABI. Signed-off-by: Aurelien Jarno (cherry picked from commit 4e17eae9f2ee49833698aae2753c5bb041510870) --- tcg/arm/tcg-target.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c index f8d626d02..81f533f73 100644 --- a/tcg/arm/tcg-target.c +++ b/tcg/arm/tcg-target.c @@ -1697,12 +1697,15 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, void tcg_target_qemu_prologue(TCGContext *s) { - /* stmdb sp!, { r9 - r11, lr } */ - tcg_out32(s, (COND_AL << 28) | 0x092d4e00); + /* Theoretically there is no need to save r12, but an + even number of registers to be saved as per EABI */ + + /* stmdb sp!, { r4 - r12, lr } */ + tcg_out32(s, (COND_AL << 28) | 0x092d5ff0); tcg_out_bx(s, COND_AL, TCG_REG_R0); tb_ret_addr = s->code_ptr; - /* ldmia sp!, { r9 - r11, pc } */ - tcg_out32(s, (COND_AL << 28) | 0x08bd8e00); + /* ldmia sp!, { r4 - r12, pc } */ + tcg_out32(s, (COND_AL << 28) | 0x08bd9ff0); } -- cgit v1.2.3 From 81b168a702ce7dd6d6504436d6c1f129ee44183e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 29 Mar 2010 02:09:23 +0200 Subject: tcg/mips: fix branch offset during retranslation Branch offsets should only be overwritten during relocation, to support partial retranslation. Signed-off-by: Aurelien Jarno (cherry picked from commit 6d8ff4d85ce2f3fc8a18dc8f077f73a4bd19a89a) --- tcg/mips/tcg-target.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 807b8fdfa..3ed9217e3 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -339,6 +339,17 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i tcg_out32(s, inst); } +/* + * Type branch + */ +static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs) +{ + /* We need to keep the offset unchanged for retranslation */ + uint16_t offset = (uint16_t)(*(uint32_t *) &s->code_ptr); + + tcg_out_opc_imm(s, opc, rt, rs, offset); +} + /* * Type sa */ @@ -469,42 +480,42 @@ static void tcg_out_brcond(TCGContext *s, int cond, int arg1, switch (cond) { case TCG_COND_EQ: - tcg_out_opc_imm(s, OPC_BEQ, arg1, arg2, 0); + tcg_out_opc_br(s, OPC_BEQ, arg1, arg2); break; case TCG_COND_NE: - tcg_out_opc_imm(s, OPC_BNE, arg1, arg2, 0); + tcg_out_opc_br(s, OPC_BNE, arg1, arg2); break; case TCG_COND_LT: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_LTU: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_GE: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_GEU: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_LE: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_LEU: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_GT: tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); break; case TCG_COND_GTU: tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); break; default: tcg_abort(); @@ -553,7 +564,7 @@ static void tcg_out_brcond2(TCGContext *s, int cond, int arg1, } label_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BNE, arg2, arg4, 0); + tcg_out_opc_br(s, OPC_BNE, arg2, arg4); tcg_out_nop(s); switch(cond) { @@ -670,20 +681,20 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, # if TARGET_LONG_BITS == 64 label3_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT); tcg_out_nop(s); tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, offsetof(CPUState, tlb_table[mem_index][0].addr_read) + addr_memh); label1_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT); tcg_out_nop(s); reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); # else label1_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT); tcg_out_nop(s); # endif @@ -725,7 +736,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, } label2_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO); tcg_out_nop(s); /* label1: fast path */ @@ -857,20 +868,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, # if TARGET_LONG_BITS == 64 label3_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_T0, TCG_REG_AT); tcg_out_nop(s); tcg_out_opc_imm(s, OPC_LW, TCG_REG_AT, TCG_REG_A0, offsetof(CPUState, tlb_table[mem_index][0].addr_write) + addr_memh); label1_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, addr_regh, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BEQ, addr_regh, TCG_REG_AT); tcg_out_nop(s); reloc_pc16(label3_ptr, (tcg_target_long) s->code_ptr); # else label1_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_T0, TCG_REG_AT); tcg_out_nop(s); # endif @@ -911,7 +922,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, tcg_out_nop(s); label2_ptr = s->code_ptr; - tcg_out_opc_imm(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO, 0); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_ZERO, TCG_REG_ZERO); tcg_out_nop(s); /* label1: fast path */ -- cgit v1.2.3 From 804b6ab08d82adcab05d64362be91c48a7467fd4 Mon Sep 17 00:00:00 2001 From: Paul Brook Date: Sun, 4 Apr 2010 21:48:31 +0100 Subject: UHCI spurious interrut fix Only raise an interrupt if the TD has actually completed. Signed-off-by: Paul Brook --- hw/usb-uhci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index dc52737ae..cfd77ebed 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -677,9 +677,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ ret = async->packet.len; - if (td->ctrl & TD_CTRL_IOC) - *int_mask |= 0x01; - if (td->ctrl & TD_CTRL_IOS) td->ctrl &= ~TD_CTRL_ACTIVE; @@ -693,6 +690,8 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ here. The docs are somewhat unclear, but win2k relies on this behavior. */ td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); + if (td->ctrl & TD_CTRL_IOC) + *int_mask |= 0x01; if (pid == USB_TOKEN_IN) { if (len > max_len) { @@ -750,6 +749,8 @@ out: if (err == 0) { td->ctrl &= ~TD_CTRL_ACTIVE; s->status |= UHCI_STS_USBERR; + if (td->ctrl & TD_CTRL_IOC) + *int_mask |= 0x01; uhci_update_irq(s); } } -- cgit v1.2.3 From c4c4b32b8112fd06508ca572f564198f1fa34b8e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 2 Feb 2010 19:39:11 +0100 Subject: sh7750: handle MMUCR TI bit When the MMUCR TI bit is set, all the UTLB and ITLB entries should be flushed. Signed-off-by: Aurelien Jarno (cherry picked from commit e781d1285fc3b81d689ba25360c6c272116387fa) --- hw/sh7750.c | 7 +++++-- target-sh4/cpu.h | 2 ++ target-sh4/helper.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/hw/sh7750.c b/hw/sh7750.c index 933bbc0c7..9c39f4b68 100644 --- a/hw/sh7750.c +++ b/hw/sh7750.c @@ -396,8 +396,11 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, portb_changed(s, temp); return; case SH7750_MMUCR_A7: - s->cpu->mmucr = mem_value; - return; + if (mem_value & MMUCR_TI) { + cpu_sh4_invalidate_tlb(s->cpu); + } + s->cpu->mmucr = mem_value & ~MMUCR_TI; + return; case SH7750_PTEH_A7: /* If asid changes, clear all registered tlb entries. */ if ((s->cpu->pteh & 0xff) != (mem_value & 0xff)) diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h index 366e7986e..015d59845 100644 --- a/target-sh4/cpu.h +++ b/target-sh4/cpu.h @@ -167,6 +167,7 @@ int cpu_sh4_handle_mmu_fault(CPUSH4State * env, target_ulong address, int rw, void do_interrupt(CPUSH4State * env); void sh4_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +void cpu_sh4_invalidate_tlb(CPUSH4State *s); void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value); @@ -222,6 +223,7 @@ enum { /* MMU control register */ #define MMUCR 0x1F000010 #define MMUCR_AT (1<<0) +#define MMUCR_TI (1<<2) #define MMUCR_SV (1<<8) #define MMUCR_URC_BITS (6) #define MMUCR_URC_OFFSET (10) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 088d36a5f..e7c494fb9 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -574,6 +574,24 @@ void cpu_load_tlb(CPUSH4State * env) entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); } + void cpu_sh4_invalidate_tlb(CPUSH4State *s) +{ + int i; + + /* UTLB */ + for (i = 0; i < UTLB_SIZE; i++) { + tlb_t * entry = &s->utlb[i]; + entry->v = 0; + } + /* ITLB */ + for (i = 0; i < UTLB_SIZE; i++) { + tlb_t * entry = &s->utlb[i]; + entry->v = 0; + } + + tlb_flush(s, 1); +} + void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, uint32_t mem_value) { -- cgit v1.2.3 From 36a013c956bec033f6261070671b569c95976194 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 1 Feb 2010 19:58:46 +0100 Subject: target-sh4: MMU: fix mem_idx computation The mem_idx is wrongly computed. As written in target-sh4/cpu.h, mode 0 corresponds to kernel mode (SR_MD = 1), while mode 1 corresponds to user mode (SR_MD = 0). Signed-off-by: Aurelien Jarno (cherry picked from commit 33b8f5546cc16eaa3d89fe133a9843c794b65d6c) --- target-sh4/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 895b978d3..7f9527a83 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1905,7 +1905,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, ctx.bstate = BS_NONE; ctx.sr = env->sr; ctx.fpscr = env->fpscr; - ctx.memidx = (env->sr & SR_MD) ? 1 : 0; + ctx.memidx = (env->sr & SR_MD) == 0 ? 1 : 0; /* We don't know if the delayed pc came from a dynamic or static branch, so assume it is a dynamic branch. */ ctx.delayed_pc = -1; /* use delayed pc from env pointer */ -- cgit v1.2.3 From 082a9fc2564b3f8177adc2c79a5fd47c34728d72 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 1 Feb 2010 20:07:06 +0100 Subject: target-sh4: MMU: fix ITLB priviledge check There is an ITLB access violation if SR_MD=0 (user mode) while the high bit of the protection key is 0 (priviledge mode). Signed-off-by: Aurelien Jarno (cherry picked from commit bc13ad29e6b7484ccd5e7ee0f5d0f966585eb4c9) --- target-sh4/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index e7c494fb9..21b76456a 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -377,7 +377,7 @@ static int get_mmu_address(CPUState * env, target_ulong * physical, n = find_itlb_entry(env, address, use_asid, 1); if (n >= 0) { matching = &env->itlb[n]; - if ((env->sr & SR_MD) & !(matching->pr & 2)) + if (!(env->sr & SR_MD) && !(matching->pr & 2)) n = MMU_ITLB_VIOLATION; else *prot = PAGE_READ; -- cgit v1.2.3 From 2039f70c235de7b7f6f41f682376260440fc3153 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Feb 2010 18:02:55 +0100 Subject: target-sh4: MMU: fix store queue addresses The store queues are located from 0xe0000000 to 0xe3ffffff. Signed-off-by: Aurelien Jarno (cherry picked from commit b1563142123593581895049568c5526b1e91da7b) --- target-sh4/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-sh4/helper.c b/target-sh4/helper.c index 21b76456a..29b681398 100644 --- a/target-sh4/helper.c +++ b/target-sh4/helper.c @@ -430,7 +430,7 @@ static int get_physical_address(CPUState * env, target_ulong * physical, if ((address >= 0x80000000 && address < 0xc0000000) || address >= 0xe0000000) { if (!(env->sr & SR_MD) - && (address < 0xe0000000 || address > 0xe4000000)) { + && (address < 0xe0000000 || address >= 0xe4000000)) { /* Unauthorized access in user mode (only store queues are available) */ fprintf(stderr, "Unauthorized access\n"); if (rw == 0) -- cgit v1.2.3 From 5eb089588ed3e54865fe596531e2375d0a5ab3f0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 6 Apr 2010 12:21:05 +0200 Subject: linux-user: switch default ppc64 CPU to 970fx from 970 Signed-off-by: Aurelien Jarno (cherry picked from commit f7177937a2c0db4c3bb42e3adfde937e9c0734a1) --- linux-user/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-user/main.c b/linux-user/main.c index e51539eff..802bd8852 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2684,7 +2684,7 @@ int main(int argc, char **argv, char **envp) #endif #elif defined(TARGET_PPC) #ifdef TARGET_PPC64 - cpu_model = "970"; + cpu_model = "970fx"; #else cpu_model = "750"; #endif -- cgit v1.2.3 From 9462695b64ef628e94d7f670feecdaa125ff5f52 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 24 Feb 2010 16:17:58 +0100 Subject: json-parser: Fix segfault on malformed input If the parser fails to parse the key in parse_pair, it will access a NULL pointer. A simple way to trigger this is sending {foo} via QMP. This patch turns the segfault into a syntax error reply. Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit d758d90fe1f74a46042fca665036a23b4d5fe87d) --- json-parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-parser.c b/json-parser.c index 2ab6f6c11..3497cd365 100644 --- a/json-parser.c +++ b/json-parser.c @@ -266,7 +266,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l peek = qlist_peek(working); key = parse_value(ctxt, &working, ap); - if (qobject_type(key) != QTYPE_QSTRING) { + if (!key || qobject_type(key) != QTYPE_QSTRING) { parse_error(ctxt, peek, "key is not a string in object"); goto out; } -- cgit v1.2.3 From de17c16e1f5e8fe9e69f9f0187c10f47c073d053 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 26 Jan 2010 14:49:08 +0100 Subject: block: avoid creating too large iovecs in multiwrite_merge If we go over the maximum number of iovecs support by syscall we get back EINVAL from the kernel which translate to I/O errors for the guest. Add a MAX_IOV defintion for platforms that don't have it. For now we use the same 1024 define that's used on Linux and various other platforms, but until the windows block backend implements some kind of vectored I/O it doesn't matter. Signed-off-by: Christoph Hellwig Signed-off-by: Anthony Liguori (cherry picked from commit e2a305fb13ff0f5cf6ff805555aaa90a5ed5954c) Signed-off-by: Kevin Wolf --- block.c | 4 ++++ qemu-common.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/block.c b/block.c index 97af3f577..9697dc9c3 100644 --- a/block.c +++ b/block.c @@ -1669,6 +1669,10 @@ static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs, merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]); } + if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 > IOV_MAX) { + merge = 0; + } + if (merge) { size_t size; QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov)); diff --git a/qemu-common.h b/qemu-common.h index d96060adb..a23afbcad 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -54,6 +54,10 @@ struct iovec { void *iov_base; size_t iov_len; }; +/* + * Use the same value as Linux for now. + */ +#define IOV_MAX 1024 #else #include #endif -- cgit v1.2.3 From 83ef70f24afed411d19bca42072c7a6477c6dbcc Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 23 Feb 2010 16:40:52 +0100 Subject: qcow2: Factor next_refcount_table_size out When the refcount table grows, it doesn't only grow by one entry but reserves some space for future refcount blocks. The algorithm to calculate the number of entries stays the same with the fixes, so factor it out before replacing the rest. As Juan suggested take the opportunity to simplify the code a bit. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori (cherry picked from commit 05121aedc41f87e44e41e9cef55f2e49ce7ba94e) --- block/qcow2-refcount.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index c2a5c0471..5dde80a74 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -123,6 +123,24 @@ static int get_refcount(BlockDriverState *bs, int64_t cluster_index) return be16_to_cpu(s->refcount_block_cache[block_index]); } +/* + * Rounds the refcount table size up to avoid growing the table for each single + * refcount block that is allocated. + */ +static unsigned int next_refcount_table_size(BDRVQcowState *s, + unsigned int min_size) +{ + unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1; + unsigned int refcount_table_clusters = + MAX(1, s->refcount_table_size >> (s->cluster_bits - 3)); + + while (min_clusters > refcount_table_clusters) { + refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2; + } + + return refcount_table_clusters << (s->cluster_bits - 3); +} + static int grow_refcount_table(BlockDriverState *bs, int min_size) { BDRVQcowState *s = bs->opaque; @@ -136,17 +154,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size) if (min_size <= s->refcount_table_size) return 0; /* compute new table size */ - refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3); - for(;;) { - if (refcount_table_clusters == 0) { - refcount_table_clusters = 1; - } else { - refcount_table_clusters = (refcount_table_clusters * 3 + 1) / 2; - } - new_table_size = refcount_table_clusters << (s->cluster_bits - 3); - if (min_size <= new_table_size) - break; - } + new_table_size = next_refcount_table_size(s, min_size); #ifdef DEBUG_ALLOC2 printf("grow_refcount_table from %d to %d\n", s->refcount_table_size, -- cgit v1.2.3 From fafc2e4b33220afd52b9e4bab1091b5861c8e5c4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 23 Feb 2010 16:40:53 +0100 Subject: qcow2: Rewrite alloc_refcount_block/grow_refcount_table The current implementation of alloc_refcount_block and grow_refcount_table has fundamental problems regarding error handling. There are some places where an I/O error means that the image is going to be corrupted. I have found that the only way to fix this is to completely rewrite the thing. In detail, the problem is that the refcount blocks itself are allocated using alloc_refcount_noref (to avoid endless recursion when updating the refcount of the new refcount block, which migh access just the same refcount block but its allocation is not yet completed...). Only at the end of the refcount allocation the refcount of the refcount block is increased. If an error happens in between, the refcount block is in use, but has a refcount of zero and will likely be overwritten later. The new approach is explained in comments in the code. The trick is basically to let new refcount blocks describe their own refcount, so their refcount will be automatically changed when they are hooked up in the refcount table. Signed-off-by: Kevin Wolf Signed-off-by: Anthony Liguori (cherry picked from commit 92dcb59fd4e1491afa0756ee9c2594869b487d23) --- block/qcow2-refcount.c | 310 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 222 insertions(+), 88 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 5dde80a74..5ebbcb63d 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -27,7 +27,7 @@ #include "block/qcow2.h" static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size); -static int update_refcount(BlockDriverState *bs, +static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, int64_t offset, int64_t length, int addend); @@ -141,114 +141,248 @@ static unsigned int next_refcount_table_size(BDRVQcowState *s, return refcount_table_clusters << (s->cluster_bits - 3); } -static int grow_refcount_table(BlockDriverState *bs, int min_size) + +/* Checks if two offsets are described by the same refcount block */ +static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a, + uint64_t offset_b) +{ + uint64_t block_a = offset_a >> (2 * s->cluster_bits - REFCOUNT_SHIFT); + uint64_t block_b = offset_b >> (2 * s->cluster_bits - REFCOUNT_SHIFT); + + return (block_a == block_b); +} + +/* + * Loads a refcount block. If it doesn't exist yet, it is allocated first + * (including growing the refcount table if needed). + * + * Returns the offset of the refcount block on success or -errno in error case + */ +static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) { BDRVQcowState *s = bs->opaque; - int new_table_size, new_table_size2, refcount_table_clusters, i, ret; - uint64_t *new_table; - int64_t table_offset; - uint8_t data[12]; - int old_table_size; - int64_t old_table_offset; + unsigned int refcount_table_index; + int ret; + + /* Find the refcount block for the given cluster */ + refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); + + if (refcount_table_index < s->refcount_table_size) { + + uint64_t refcount_block_offset = + s->refcount_table[refcount_table_index]; + + /* If it's already there, we're done */ + if (refcount_block_offset) { + if (refcount_block_offset != s->refcount_block_cache_offset) { + ret = load_refcount_block(bs, refcount_block_offset); + if (ret < 0) { + return ret; + } + } + return refcount_block_offset; + } + } + + /* + * If we came here, we need to allocate something. Something is at least + * a cluster for the new refcount block. It may also include a new refcount + * table if the old refcount table is too small. + * + * Note that allocating clusters here needs some special care: + * + * - We can't use the normal qcow2_alloc_clusters(), it would try to + * increase the refcount and very likely we would end up with an endless + * recursion. Instead we must place the refcount blocks in a way that + * they can describe them themselves. + * + * - We need to consider that at this point we are inside update_refcounts + * and doing the initial refcount increase. This means that some clusters + * have already been allocated by the caller, but their refcount isn't + * accurate yet. free_cluster_index tells us where this allocation ends + * as long as we don't overwrite it by freeing clusters. + * + * - alloc_clusters_noref and qcow2_free_clusters may load a different + * refcount block into the cache + */ + + if (cache_refcount_updates) { + ret = write_refcount_block(s); + if (ret < 0) { + return ret; + } + } + + /* Allocate the refcount block itself and mark it as used */ + uint64_t new_block = alloc_clusters_noref(bs, s->cluster_size); + memset(s->refcount_block_cache, 0, s->cluster_size); + s->refcount_block_cache_offset = new_block; - if (min_size <= s->refcount_table_size) - return 0; - /* compute new table size */ - new_table_size = next_refcount_table_size(s, min_size); #ifdef DEBUG_ALLOC2 - printf("grow_refcount_table from %d to %d\n", - s->refcount_table_size, - new_table_size); + fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64 + " at %" PRIx64 "\n", + refcount_table_index, cluster_index << s->cluster_bits, new_block); #endif - new_table_size2 = new_table_size * sizeof(uint64_t); - new_table = qemu_mallocz(new_table_size2); + + if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) { + /* The block describes itself, need to update the cache */ + int block_index = (new_block >> s->cluster_bits) & + ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); + s->refcount_block_cache[block_index] = cpu_to_be16(1); + } else { + /* Described somewhere else. This can recurse at most twice before we + * arrive at a block that describes itself. */ + ret = update_refcount(bs, new_block, s->cluster_size, 1); + if (ret < 0) { + goto fail_block; + } + } + + /* Now the new refcount block needs to be written to disk */ + ret = bdrv_pwrite(s->hd, new_block, s->refcount_block_cache, + s->cluster_size); + if (ret < 0) { + goto fail_block; + } + + /* If the refcount table is big enough, just hook the block up there */ + if (refcount_table_index < s->refcount_table_size) { + uint64_t data64 = cpu_to_be64(new_block); + ret = bdrv_pwrite(s->hd, + s->refcount_table_offset + refcount_table_index * sizeof(uint64_t), + &data64, sizeof(data64)); + if (ret < 0) { + goto fail_block; + } + + s->refcount_table[refcount_table_index] = new_block; + return new_block; + } + + /* + * If we come here, we need to grow the refcount table. Again, a new + * refcount table needs some space and we can't simply allocate to avoid + * endless recursion. + * + * Therefore let's grab new refcount blocks at the end of the image, which + * will describe themselves and the new refcount table. This way we can + * reference them only in the new table and do the switch to the new + * refcount table at once without producing an inconsistent state in + * between. + */ + /* Calculate the number of refcount blocks needed so far */ + uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT); + uint64_t blocks_used = (s->free_cluster_index + + refcount_block_clusters - 1) / refcount_block_clusters; + + /* And now we need at least one block more for the new metadata */ + uint64_t table_size = next_refcount_table_size(s, blocks_used + 1); + uint64_t last_table_size; + uint64_t blocks_clusters; + do { + uint64_t table_clusters = size_to_clusters(s, table_size); + blocks_clusters = 1 + + ((table_clusters + refcount_block_clusters - 1) + / refcount_block_clusters); + uint64_t meta_clusters = table_clusters + blocks_clusters; + + last_table_size = table_size; + table_size = next_refcount_table_size(s, blocks_used + + ((meta_clusters + refcount_block_clusters - 1) + / refcount_block_clusters)); + + } while (last_table_size != table_size); + +#ifdef DEBUG_ALLOC2 + fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n", + s->refcount_table_size, table_size); +#endif + + /* Create the new refcount table and blocks */ + uint64_t meta_offset = (blocks_used * refcount_block_clusters) * + s->cluster_size; + uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size; + uint16_t *new_blocks = qemu_mallocz(blocks_clusters * s->cluster_size); + uint64_t *new_table = qemu_mallocz(table_size * sizeof(uint64_t)); + + assert(meta_offset >= (s->free_cluster_index * s->cluster_size)); + + /* Fill the new refcount table */ memcpy(new_table, s->refcount_table, - s->refcount_table_size * sizeof(uint64_t)); - for(i = 0; i < s->refcount_table_size; i++) + s->refcount_table_size * sizeof(uint64_t)); + new_table[refcount_table_index] = new_block; + + int i; + for (i = 0; i < blocks_clusters; i++) { + new_table[blocks_used + i] = meta_offset + (i * s->cluster_size); + } + + /* Fill the refcount blocks */ + uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t)); + int block = 0; + for (i = 0; i < table_clusters + blocks_clusters; i++) { + new_blocks[block++] = cpu_to_be16(1); + } + + /* Write refcount blocks to disk */ + ret = bdrv_pwrite(s->hd, meta_offset, new_blocks, + blocks_clusters * s->cluster_size); + qemu_free(new_blocks); + if (ret < 0) { + goto fail_table; + } + + /* Write refcount table to disk */ + for(i = 0; i < table_size; i++) { cpu_to_be64s(&new_table[i]); - /* Note: we cannot update the refcount now to avoid recursion */ - table_offset = alloc_clusters_noref(bs, new_table_size2); - ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2); - if (ret != new_table_size2) - goto fail; - for(i = 0; i < s->refcount_table_size; i++) - be64_to_cpus(&new_table[i]); + } + + ret = bdrv_pwrite(s->hd, table_offset, new_table, + table_size * sizeof(uint64_t)); + if (ret < 0) { + goto fail_table; + } + for(i = 0; i < table_size; i++) { + cpu_to_be64s(&new_table[i]); + } + + /* Hook up the new refcount table in the qcow2 header */ + uint8_t data[12]; cpu_to_be64w((uint64_t*)data, table_offset); - cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters); + cpu_to_be32w((uint32_t*)(data + 8), table_clusters); ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset), - data, sizeof(data)); - if (ret != sizeof(data)) { - goto fail; + data, sizeof(data)); + if (ret < 0) { + goto fail_table; } + /* And switch it in memory */ + uint64_t old_table_offset = s->refcount_table_offset; + uint64_t old_table_size = s->refcount_table_size; + qemu_free(s->refcount_table); - old_table_offset = s->refcount_table_offset; - old_table_size = s->refcount_table_size; s->refcount_table = new_table; - s->refcount_table_size = new_table_size; + s->refcount_table_size = table_size; s->refcount_table_offset = table_offset; - update_refcount(bs, table_offset, new_table_size2, 1); + /* Free old table. Remember, we must not change free_cluster_index */ + uint64_t old_free_cluster_index = s->free_cluster_index; qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t)); - return 0; - fail: - qemu_free(new_table); - return ret < 0 ? ret : -EIO; -} - - -static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) -{ - BDRVQcowState *s = bs->opaque; - int64_t offset, refcount_block_offset; - unsigned int refcount_table_index; - int ret; - uint64_t data64; - int cache = cache_refcount_updates; + s->free_cluster_index = old_free_cluster_index; - /* Find L1 index and grow refcount table if needed */ - refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); - if (refcount_table_index >= s->refcount_table_size) { - ret = grow_refcount_table(bs, refcount_table_index + 1); - if (ret < 0) - return ret; + ret = load_refcount_block(bs, new_block); + if (ret < 0) { + goto fail_block; } - /* Load or allocate the refcount block */ - refcount_block_offset = s->refcount_table[refcount_table_index]; - if (!refcount_block_offset) { - if (cache_refcount_updates) { - write_refcount_block(s); - cache_refcount_updates = 0; - } - /* create a new refcount block */ - /* Note: we cannot update the refcount now to avoid recursion */ - offset = alloc_clusters_noref(bs, s->cluster_size); - memset(s->refcount_block_cache, 0, s->cluster_size); - ret = bdrv_pwrite(s->hd, offset, s->refcount_block_cache, s->cluster_size); - if (ret != s->cluster_size) - return -EINVAL; - s->refcount_table[refcount_table_index] = offset; - data64 = cpu_to_be64(offset); - ret = bdrv_pwrite(s->hd, s->refcount_table_offset + - refcount_table_index * sizeof(uint64_t), - &data64, sizeof(data64)); - if (ret != sizeof(data64)) - return -EINVAL; - - refcount_block_offset = offset; - s->refcount_block_cache_offset = offset; - update_refcount(bs, offset, s->cluster_size, 1); - cache_refcount_updates = cache; - } else { - if (refcount_block_offset != s->refcount_block_cache_offset) { - if (load_refcount_block(bs, refcount_block_offset) < 0) - return -EIO; - } - } + return new_block; - return refcount_block_offset; +fail_table: + qemu_free(new_table); +fail_block: + s->refcount_block_cache_offset = 0; + return ret; } #define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT) -- cgit v1.2.3 From 4f7cb969319be00ffce3dee6426d1b4ae95d2d83 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 10 Mar 2010 17:47:17 +0100 Subject: scsi-disk: fix buffer overflow In case s->version is shorter than 4 bytes we overflow the memcpy src buffer. Fix it by clearing the target buffer, then copy only the amount of bytes we actually have. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from 314b1811c15f4e982e4667d9b845aee4b5a63d91) Signed-off-by: Kevin Wolf --- hw/scsi-disk.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index b34fbaa67..a79201213 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -434,7 +434,9 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) memcpy(&outbuf[16], "QEMU HARDDISK ", 16); } memcpy(&outbuf[8], "QEMU ", 8); - memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4); + memset(&outbuf[32], 0, 4); + memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, + MIN(4, strlen(s->version ? s->version : QEMU_VERSION))); /* Identify device as SCSI-3 rev 1. Some later commands are also implemented. */ outbuf[2] = 3; -- cgit v1.2.3 From aba5288247add3fccc089f21ea8b41f48556c184 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 1 Apr 2010 22:48:44 +0200 Subject: block: Fix multiwrite error handling When two requests of the same multiwrite batch fail, the callback of all requests in that batch were called twice. This could have any kind of nasty effects, in my case it lead to use after free and eventually a segfault. Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit cb6d3ca07b8f62b47ef30c6a92caa3e8bd71248b) --- block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block.c b/block.c index 9697dc9c3..06e22a615 100644 --- a/block.c +++ b/block.c @@ -1617,7 +1617,7 @@ static void multiwrite_cb(void *opaque, int ret) { MultiwriteCB *mcb = opaque; - if (ret < 0) { + if (ret < 0 && !mcb->error) { mcb->error = ret; multiwrite_user_cb(mcb); } -- cgit v1.2.3 From ffac613ff988db0eed39f97ec0005eb6ffe2f638 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 6 Apr 2010 18:24:06 +0200 Subject: block: Fix error code in multiwrite for immediate failures Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit 0f0b604b00851f2c7160b4195136c1fd27418088) --- block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 06e22a615..d537d10b6 100644 --- a/block.c +++ b/block.c @@ -1758,10 +1758,10 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) // submitted yet. Otherwise we'll wait for the submitted AIOs to // complete and report the error in the callback. if (mcb->num_requests == 0) { - reqs[i].error = EIO; + reqs[i].error = -EIO; goto fail; } else { - mcb->error = EIO; + mcb->error = -EIO; break; } } else { -- cgit v1.2.3 From 4622317288507449ec7b9af344c265dd20c96b3a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 6 Apr 2010 18:24:07 +0200 Subject: block: Fix multiwrite memory leak in error case Previously multiwrite_user_cb was never called if a request in the multiwrite batch failed right away because it did set mcb->error immediately. Make it look more like a normal callback to fix this. Reported-by: Juan Quintela Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit 7eb58a6c556c3880e6712cbf6d24d681261c5095) --- block.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index d537d10b6..4f9a48b71 100644 --- a/block.c +++ b/block.c @@ -1761,7 +1761,8 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs) reqs[i].error = -EIO; goto fail; } else { - mcb->error = -EIO; + mcb->num_requests++; + multiwrite_cb(mcb, -EIO); break; } } else { -- cgit v1.2.3 From e00722122380b173eccfa246167241c8adf940c6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 6 Apr 2010 15:30:09 +0200 Subject: qcow2: Don't ignore immediate read/write failures Returning -EIO is far from optimal, but at least it's an error code. Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit 171e3d6b9997c98a97d0c525867f7cd9b640cadd) --- block/qcow2.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 4ae8f193d..f6f8980ed 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -467,8 +467,10 @@ static void qcow_aio_read_cb(void *opaque, int ret) acb->hd_aiocb = bdrv_aio_readv(s->hd, (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb); - if (acb->hd_aiocb == NULL) + if (acb->hd_aiocb == NULL) { + ret = -EIO; goto done; + } } return; @@ -620,8 +622,10 @@ static void qcow_aio_write_cb(void *opaque, int ret) (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->n, qcow_aio_write_cb, acb); - if (acb->hd_aiocb == NULL) + if (acb->hd_aiocb == NULL) { + ret = -EIO; goto done; + } return; -- cgit v1.2.3 From 0434349d6ac96d26cf067f58074b939d881b0911 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 6 Apr 2010 15:30:14 +0200 Subject: qcow2: Remove request from in-flight list after error If we complete a request with a failure we need to remove it from the list of requests that are in flight. If we don't do it, the next time the same AIOCB is used for a cluster allocation it will create a loop in the list and qemu will hang in an endless loop. Signed-off-by: Kevin Wolf Signed-off-by: Aurelien Jarno (cherry picked from commit c644db3d53c90ef569ff5a90e9f821b88e7123bb) --- block/qcow2-cluster.c | 1 + block/qcow2.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index b13b6935f..c7057b166 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -811,6 +811,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size); if (cluster_offset < 0) { + QLIST_REMOVE(m, next_in_flight); return cluster_offset; } diff --git a/block/qcow2.c b/block/qcow2.c index f6f8980ed..5d33d6c79 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -624,11 +624,15 @@ static void qcow_aio_write_cb(void *opaque, int ret) qcow_aio_write_cb, acb); if (acb->hd_aiocb == NULL) { ret = -EIO; - goto done; + goto fail; } return; +fail: + if (acb->l2meta.nb_clusters != 0) { + QLIST_REMOVE(&acb->l2meta, next_in_flight); + } done: if (acb->qiov->niov > 1) qemu_vfree(acb->orig_buf); -- cgit v1.2.3 From 69ff4e9dbde494b1e8752606b0820f04344caeb1 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Tue, 6 Apr 2010 19:22:07 -0300 Subject: net: remove broken net_set_boot_mask() boot device validation There are many problems with net_set_boot_mask(): 1) It is broken when using the device model instead of "-net nic". Example: $ qemu-system-x86_64 -device rtl8139,vlan=0,id=net0,mac=52:54:00:82:41:fd,bus=pci.0,addr=0x4 -net user,vlan=0,name=hostnet0 -vnc 0.0.0.0:0 -boot n Cannot boot from non-existent NIC $ 2) The mask was previously used to set which boot ROMs were supposed to be loaded, but this was changed long time ago. Now all ROM images are loaded, and SeaBIOS takes care of jumping to the right boot entry point depending on the boot settings. 3) Interpretation and validation of the boot parameter letters is done on the machine type code. Examples: PC accepts only a,b,c,d,n as valid boot device letters. mac99 accepts only a,b,c,d,e,f. As a side-effect of this change, qemu-kvm won't abort anymore if using "-boot n" on a machine with no network devices. Checking if the requested boot device is valid is now a task for the BIOS or the machine-type code. Signed-off-by: Eduardo Habkost Acked-by: Juan Quintela Signed-off-by: Aurelien Jarno (cherry-picked from da1fcfda59a6bcbdf58d49243fbced455f2bf78a) --- net.c | 20 -------------------- net.h | 1 - vl.c | 5 +---- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/net.c b/net.c index 029b0d79b..28b6b43a9 100644 --- a/net.c +++ b/net.c @@ -1187,26 +1187,6 @@ void net_host_device_remove(Monitor *mon, const QDict *qdict) qemu_del_vlan_client(vc); } -void net_set_boot_mask(int net_boot_mask) -{ - int i; - - /* Only the first four NICs may be bootable */ - net_boot_mask = net_boot_mask & 0xF; - - for (i = 0; i < nb_nics; i++) { - if (net_boot_mask & (1 << i)) { - nd_table[i].bootable = 1; - net_boot_mask &= ~(1 << i); - } - } - - if (net_boot_mask) { - fprintf(stderr, "Cannot boot from non-existent NIC\n"); - exit(1); - } -} - void do_info_network(Monitor *mon) { VLANState *vlan; diff --git a/net.h b/net.h index 673b3554d..209431dd0 100644 --- a/net.h +++ b/net.h @@ -163,7 +163,6 @@ int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); void net_check_clients(void); void net_cleanup(void); -void net_set_boot_mask(int boot_mask); void net_host_device_add(Monitor *mon, const QDict *qdict); void net_host_device_remove(Monitor *mon, const QDict *qdict); diff --git a/vl.c b/vl.c index 425bb4b6f..6b6e86d69 100644 --- a/vl.c +++ b/vl.c @@ -4851,7 +4851,7 @@ int main(int argc, char **argv, char **envp) const char *gdbstub_dev = NULL; uint32_t boot_devices_bitmap = 0; int i; - int snapshot, linux_boot, net_boot; + int snapshot, linux_boot; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ @@ -5850,9 +5850,6 @@ int main(int argc, char **argv, char **envp) exit(1); } - net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; - net_set_boot_mask(net_boot); - /* init the bluetooth world */ if (foreach_device_config(DEV_BT, bt_parse)) exit(1); -- cgit v1.2.3 From 09e96924ec55eb0f1288ac44b271261055ed0657 Mon Sep 17 00:00:00 2001 From: Chris Webb Date: Mon, 8 Mar 2010 14:34:49 +0000 Subject: Fix SIGFPE for vnc display of width/height = 1 During boot, the screen gets resized to height 1 and a mouse click at this point will cause a division by zero when calculating the absolute pointer position from the pixel (x, y). Return a click in the middle of the screen instead in this case. Signed-off-by: Chris Webb Signed-off-by: Anthony Liguori (cherry picked from commit cc39a92cbfc80c70d2b83708a4c9b309c3126ac3) --- vnc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vnc.c b/vnc.c index a1f9c9293..8566a4ba1 100644 --- a/vnc.c +++ b/vnc.c @@ -1421,8 +1421,10 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) dz = 1; if (vs->absolute) { - kbd_mouse_event(x * 0x7FFF / (ds_get_width(vs->ds) - 1), - y * 0x7FFF / (ds_get_height(vs->ds) - 1), + kbd_mouse_event(ds_get_width(vs->ds) > 1 ? + x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000, + ds_get_height(vs->ds) > 1 ? + y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000, dz, buttons); } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) { x -= 0x7FFF; -- cgit v1.2.3 From 9167a242db92fa49ba1f60fcc748fa07258f3819 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Wed, 3 Feb 2010 21:44:17 -0200 Subject: Fix incoming migration with iothread Do not allow the vcpus to execute if the vm is stopped. Fixes -incoming with CONFIG_IOTHREAD enabled. Signed-off-by: Marcelo Tosatti (cherry picked from commit c5f32c99c6855d466737daf1cd262e7e92062f87) --- vl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vl.c b/vl.c index 6b6e86d69..77677e801 100644 --- a/vl.c +++ b/vl.c @@ -3471,6 +3471,8 @@ static int cpu_can_run(CPUState *env) return 0; if (env->stopped) return 0; + if (!vm_running) + return 0; return 1; } -- cgit v1.2.3 From 1ce4fad939d2d54d6e45c109b17dfab6d03f1160 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 11 Apr 2010 23:59:39 +0200 Subject: sh_pci: fix memory and I/O access Since commit 8da3ff180974732fc4272cb4433fef85c1822961 ("MMIO callback interface changes"), the addresses passed to the I/O functions are an offset to the start of the area. As a consequence, there is no need to correct the address using the value of IOBR. This make possible the use of the default MMIO functions. Moreover the addresses are now remaped when the value if IOBR change. The memory area corresponds to the devices behing the PCI bus, it should not be mapped by the PCI controller. Remove the corresponding code. Signed-off-by: Aurelien Jarno (cherry-picked from commit 5ba9e9522cf572715ca1966b292f64fb78342e22) --- default-configs/sh4-softmmu.mak | 1 + default-configs/sh4eb-softmmu.mak | 1 + hw/sh_pci.c | 111 ++++++-------------------------------- 3 files changed, 17 insertions(+), 96 deletions(-) diff --git a/default-configs/sh4-softmmu.mak b/default-configs/sh4-softmmu.mak index 4f912eccd..a89f52b16 100644 --- a/default-configs/sh4-softmmu.mak +++ b/default-configs/sh4-softmmu.mak @@ -2,3 +2,4 @@ CONFIG_USB_OHCI=y CONFIG_PTIMER=y +CONFIG_ISA_MMIO=y diff --git a/default-configs/sh4eb-softmmu.mak b/default-configs/sh4eb-softmmu.mak index 93d0c76f2..762385be3 100644 --- a/default-configs/sh4eb-softmmu.mak +++ b/default-configs/sh4eb-softmmu.mak @@ -2,3 +2,4 @@ CONFIG_USB_OHCI=y CONFIG_PTIMER=y +CONFIG_ISA_MMIO=y diff --git a/hw/sh_pci.c b/hw/sh_pci.c index abe4c7568..441879a9d 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -47,10 +47,15 @@ static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val) pcic->par = val; break; case 0x1c4: - pcic->mbr = val; + pcic->mbr = val & 0xff000001; break; case 0x1c8: - pcic->iobr = val; + if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) { + cpu_register_physical_memory(pcic->iobr & 0xfffc0000, 0x40000, + IO_MEM_UNASSIGNED); + pcic->iobr = val & 0xfffc0001; + isa_mmio_init(pcic->iobr & 0xfffc0000, 0x40000); + } break; case 0x220: pci_data_write(pcic->bus, pcic->par, val, 4); @@ -66,89 +71,16 @@ static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr) return le32_to_cpup((uint32_t*)(pcic->dev->config + addr)); case 0x1c0: return pcic->par; + case 0x1c4: + return pcic->mbr; + case 0x1c8: + return pcic->iobr; case 0x220: return pci_data_read(pcic->bus, pcic->par, 4); } return 0; } -static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr, - uint32_t val, int size) -{ - pci_data_write(pcic->bus, addr + pcic->mbr, val, size); -} - -static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr, - int size) -{ - return pci_data_read(pcic->bus, addr + pcic->mbr, size); -} - -static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 1); -} - -static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 2); -} - -static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val) -{ - sh_pci_data_write(p, addr, val, 4); -} - -static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 1); -} - -static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 2); -} - -static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr) -{ - return sh_pci_mem_read(p, addr, 4); -} - -static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr) -{ - return addr + pcic->iobr; -} - -static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outb(sh_pci_addr2port(p, addr), val); -} - -static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outw(sh_pci_addr2port(p, addr), val); -} - -static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val) -{ - cpu_outl(sh_pci_addr2port(p, addr), val); -} - -static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr) -{ - return cpu_inb(sh_pci_addr2port(p, addr)); -} - -static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr) -{ - return cpu_inw(sh_pci_addr2port(p, addr)); -} - -static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr) -{ - return cpu_inl(sh_pci_addr2port(p, addr)); -} - typedef struct { CPUReadMemoryFunc * const r[3]; CPUWriteMemoryFunc * const w[3]; @@ -159,21 +91,11 @@ static MemOp sh_pci_reg = { { NULL, NULL, sh_pci_reg_write }, }; -static MemOp sh_pci_mem = { - { sh_pci_readb, sh_pci_readw, sh_pci_readl }, - { sh_pci_writeb, sh_pci_writew, sh_pci_writel }, -}; - -static MemOp sh_pci_iop = { - { sh_pci_inb, sh_pci_inw, sh_pci_inl }, - { sh_pci_outb, sh_pci_outw, sh_pci_outl }, -}; - PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, void *opaque, int devfn_min, int nirq) { SHPCIC *p; - int mem, reg, iop; + int reg; p = qemu_mallocz(sizeof(SHPCIC)); p->bus = pci_register_bus(NULL, "pci", @@ -182,14 +104,11 @@ PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq, p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice), -1, NULL, NULL); reg = cpu_register_io_memory(sh_pci_reg.r, sh_pci_reg.w, p); - iop = cpu_register_io_memory(sh_pci_iop.r, sh_pci_iop.w, p); - mem = cpu_register_io_memory(sh_pci_mem.r, sh_pci_mem.w, p); cpu_register_physical_memory(0x1e200000, 0x224, reg); - cpu_register_physical_memory(0x1e240000, 0x40000, iop); - cpu_register_physical_memory(0x1d000000, 0x1000000, mem); cpu_register_physical_memory(0xfe200000, 0x224, reg); - cpu_register_physical_memory(0xfe240000, 0x40000, iop); - cpu_register_physical_memory(0xfd000000, 0x1000000, mem); + + p->iobr = 0xfe240000; + isa_mmio_init(p->iobr, 0x40000); pci_config_set_vendor_id(p->dev->config, PCI_VENDOR_ID_HITACHI); pci_config_set_device_id(p->dev->config, PCI_DEVICE_ID_HITACHI_SH7751R); -- cgit v1.2.3 From d80e20a1c32bd1bd73cb6e435a01687211e3b3da Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Fri, 9 Apr 2010 17:28:40 +0200 Subject: tcp/mips: Change TCG_AREG0 (fp -> s0) Register fp (frame pointer) is a bad choice for compilations without optimisation, because the compiler makes heavy use of this register (so the resulting code crashes). Register s0 had been used for TCG_AREG1 in earlier releases, but was no longer used and is now free for TCG_AREG0. The resulting code works for compilations without optimisation (tested with qemu mips in qemu mips on x86 host). Signed-off-by: Stefan Weil Signed-off-by: Aurelien Jarno --- dyngen-exec.h | 6 +++--- tcg/mips/tcg-target.c | 5 +++-- tcg/mips/tcg-target.h | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/dyngen-exec.h b/dyngen-exec.h index 0353f36cd..3f1c43196 100644 --- a/dyngen-exec.h +++ b/dyngen-exec.h @@ -69,9 +69,9 @@ extern int printf(const char *, ...); #define AREG1 "r14" #define AREG2 "r15" #elif defined(__mips__) -#define AREG0 "fp" -#define AREG1 "s0" -#define AREG2 "s1" +#define AREG0 "s0" +#define AREG1 "s1" +#define AREG2 "fp" #elif defined(__sparc__) #ifdef CONFIG_SOLARIS #define AREG0 "g2" diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c index 3ed9217e3..79ba9a662 100644 --- a/tcg/mips/tcg-target.c +++ b/tcg/mips/tcg-target.c @@ -1273,7 +1273,9 @@ static const TCGTargetOpDef mips_op_defs[] = { }; static int tcg_target_callee_save_regs[] = { +#if 0 /* used for the global env (TCG_AREG0), so no need to save */ TCG_REG_S0, +#endif TCG_REG_S1, TCG_REG_S2, TCG_REG_S3, @@ -1282,8 +1284,7 @@ static int tcg_target_callee_save_regs[] = { TCG_REG_S6, TCG_REG_S7, TCG_REG_GP, - /* TCG_REG_FP, */ /* currently used for the global env, so np - need to save */ + TCG_REG_FP, TCG_REG_RA, /* should be last for ABI compliance */ }; diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h index 46760a50e..baae6d85c 100644 --- a/tcg/mips/tcg-target.h +++ b/tcg/mips/tcg-target.h @@ -92,9 +92,9 @@ enum { #undef TCG_TARGET_HAS_ext16u_i32 /* andi rt, rs, 0xffff */ /* Note: must be synced with dyngen-exec.h */ -#define TCG_AREG0 TCG_REG_FP -#define TCG_AREG1 TCG_REG_S0 -#define TCG_AREG2 TCG_REG_S1 +#define TCG_AREG0 TCG_REG_S0 +#define TCG_AREG1 TCG_REG_S1 +#define TCG_AREG2 TCG_REG_FP #include -- cgit v1.2.3 From a8c46d182c90873dce5a9eaf97a6c0413751edc7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jan 2010 17:08:00 +0100 Subject: lsi: use QTAILQ for lsi_queue Replace the funky array logic for queued commands with standard qemu list functions. Also rename lsi_queue to lsi_request. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from commit 042ec49dc52e54153942a089a46ae584152998fb) --- hw/lsi53c895a.c | 68 ++++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 014c85dbd..5c679ed66 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -173,11 +173,12 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) /* Flag set if this is a tagged command. */ #define LSI_TAG_VALID (1 << 16) -typedef struct { +typedef struct lsi_request { uint32_t tag; uint32_t pending; int out; -} lsi_queue; + QTAILQ_ENTRY(lsi_request) next; +} lsi_request; typedef struct { PCIDevice dev; @@ -205,9 +206,7 @@ typedef struct { uint32_t current_dma_len; int command_complete; uint8_t *dma_buf; - lsi_queue *queue; - int queue_len; - int active_commands; + QTAILQ_HEAD(, lsi_request) queue; uint32_t dsa; uint32_t temp; @@ -391,9 +390,9 @@ static void lsi_stop_script(LSIState *s) static void lsi_update_irq(LSIState *s) { - int i; int level; static int last_level; + lsi_request *p; /* It's unclear whether the DIP/SIP bits should be cleared when the Interrupt Status Registers are cleared or when istat0 is read. @@ -427,9 +426,9 @@ static void lsi_update_irq(LSIState *s) if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) { DPRINTF("Handled IRQs & disconnected, looking for pending " "processes\n"); - for (i = 0; i < s->active_commands; i++) { - if (s->queue[i].pending) { - lsi_reselect(s, s->queue[i].tag); + QTAILQ_FOREACH(p, &s->queue, next) { + if (p->pending) { + lsi_reselect(s, p->tag); break; } } @@ -563,14 +562,11 @@ static void lsi_do_dma(LSIState *s, int out) /* Add a command to the queue. */ static void lsi_queue_command(LSIState *s) { - lsi_queue *p; + lsi_request *p; DPRINTF("Queueing tag=0x%x\n", s->current_tag); - if (s->queue_len == s->active_commands) { - s->queue_len++; - s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue)); - } - p = &s->queue[s->active_commands++]; + p = qemu_mallocz(sizeof(*p)); + QTAILQ_INSERT_TAIL(&s->queue, p, next); p->tag = s->current_tag; p->pending = 0; p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO; @@ -590,17 +586,14 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data) /* Perform reselection to continue a command. */ static void lsi_reselect(LSIState *s, uint32_t tag) { - lsi_queue *p; - int n; + lsi_request *p; int id; - p = NULL; - for (n = 0; n < s->active_commands; n++) { - p = &s->queue[n]; + QTAILQ_FOREACH(p, &s->queue, next) { if (p->tag == tag) break; } - if (n == s->active_commands) { + if (p == NULL) { BADF("Reselected non-existant command tag=0x%x\n", tag); return; } @@ -624,10 +617,8 @@ static void lsi_reselect(LSIState *s, uint32_t tag) lsi_add_msg_byte(s, tag & 0xff); } - s->active_commands--; - if (n != s->active_commands) { - s->queue[n] = s->queue[s->active_commands]; - } + QTAILQ_REMOVE(&s->queue, p, next); + qemu_free(p); if (lsi_irq_on_rsl(s)) { lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); @@ -638,10 +629,9 @@ static void lsi_reselect(LSIState *s, uint32_t tag) the device was reselected, nonzero if the IO is deferred. */ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) { - lsi_queue *p; - int i; - for (i = 0; i < s->active_commands; i++) { - p = &s->queue[i]; + lsi_request *p; + + QTAILQ_FOREACH(p, &s->queue, next) { if (p->tag == tag) { if (p->pending) { BADF("Multiple IO pending for tag %d\n", tag); @@ -659,7 +649,7 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) lsi_reselect(s, tag); return 0; } else { - DPRINTF("Queueing IO tag=0x%x\n", tag); + DPRINTF("Queueing IO tag=0x%x\n", tag); p->pending = arg; return 1; } @@ -905,13 +895,15 @@ static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) static void lsi_wait_reselect(LSIState *s) { - int i; + lsi_request *p; + DPRINTF("Wait Reselect\n"); if (s->current_dma_len) BADF("Reselect with pending DMA\n"); - for (i = 0; i < s->active_commands; i++) { - if (s->queue[i].pending) { - lsi_reselect(s, s->queue[i].tag); + + QTAILQ_FOREACH(p, &s->queue, next) { + if (p->pending) { + lsi_reselect(s, p->tag); break; } } @@ -2008,7 +2000,7 @@ static void lsi_pre_save(void *opaque) assert(s->dma_buf == NULL); assert(s->current_dma_len == 0); - assert(s->active_commands == 0); + assert(QTAILQ_EMPTY(&s->queue)); } static const VMStateDescription vmstate_lsi_scsi = { @@ -2101,8 +2093,6 @@ static int lsi_scsi_uninit(PCIDevice *d) cpu_unregister_io_memory(s->mmio_io_addr); cpu_unregister_io_memory(s->ram_io_addr); - qemu_free(s->queue); - return 0; } @@ -2138,9 +2128,7 @@ static int lsi_scsi_init(PCIDevice *dev) PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc); pci_register_bar((struct PCIDevice *)s, 2, 0x2000, PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc); - s->queue = qemu_malloc(sizeof(lsi_queue)); - s->queue_len = 1; - s->active_commands = 0; + QTAILQ_INIT(&s->queue); lsi_soft_reset(s); -- cgit v1.2.3 From d40ba77ebf0097ff45e3d2ae6fc915560c626e91 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jan 2010 17:08:01 +0100 Subject: lsi: have lsi_request for the whole life time of the request. Right now lsi_request is allocated when a request is queued and released when a request is unqueued. With this patch applied the lsi_request is kept for the whole lifetime of the scsi request. Rationale: We can use it for per-request data then. The patch does that already for the request tag. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from commit af12ac9880eacdd79d49a11d5672df7170afb38f) --- hw/lsi53c895a.c | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 5c679ed66..83c9d542a 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -202,11 +202,12 @@ typedef struct { SCSIDevice *current_dev; int current_lun; /* The tag is a combination of the device ID and the SCSI tag. */ - uint32_t current_tag; + uint32_t select_tag; uint32_t current_dma_len; int command_complete; uint8_t *dma_buf; QTAILQ_HEAD(, lsi_request) queue; + lsi_request *current; uint32_t dsa; uint32_t temp; @@ -533,7 +534,7 @@ static void lsi_do_dma(LSIState *s, int out) if (s->dma_buf == NULL) { s->dma_buf = s->current_dev->info->get_buf(s->current_dev, - s->current_tag); + s->current->tag); } /* ??? Set SFBR to first data byte. */ @@ -547,10 +548,10 @@ static void lsi_do_dma(LSIState *s, int out) s->dma_buf = NULL; if (out) { /* Write the data. */ - s->current_dev->info->write_data(s->current_dev, s->current_tag); + s->current_dev->info->write_data(s->current_dev, s->current->tag); } else { /* Request any remaining data. */ - s->current_dev->info->read_data(s->current_dev, s->current_tag); + s->current_dev->info->read_data(s->current_dev, s->current->tag); } } else { s->dma_buf += count; @@ -562,12 +563,13 @@ static void lsi_do_dma(LSIState *s, int out) /* Add a command to the queue. */ static void lsi_queue_command(LSIState *s) { - lsi_request *p; + lsi_request *p = s->current; DPRINTF("Queueing tag=0x%x\n", s->current_tag); - p = qemu_mallocz(sizeof(*p)); - QTAILQ_INSERT_TAIL(&s->queue, p, next); - p->tag = s->current_tag; + assert(s->current != NULL); + QTAILQ_INSERT_TAIL(&s->queue, s->current, next); + s->current = NULL; + p->pending = 0; p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO; } @@ -597,6 +599,10 @@ static void lsi_reselect(LSIState *s, uint32_t tag) BADF("Reselected non-existant command tag=0x%x\n", tag); return; } + assert(s->current == NULL); + QTAILQ_REMOVE(&s->queue, p, next); + s->current = p; + id = (tag >> 8) & 0xf; s->ssid = id | 0x80; /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */ @@ -605,21 +611,17 @@ static void lsi_reselect(LSIState *s, uint32_t tag) } DPRINTF("Reselected target %d\n", id); s->current_dev = s->bus.devs[id]; - s->current_tag = tag; s->scntl1 |= LSI_SCNTL1_CON; lsi_set_phase(s, PHASE_MI); s->msg_action = p->out ? 2 : 3; s->current_dma_len = p->pending; s->dma_buf = NULL; lsi_add_msg_byte(s, 0x80); - if (s->current_tag & LSI_TAG_VALID) { + if (s->current->tag & LSI_TAG_VALID) { lsi_add_msg_byte(s, 0x20); lsi_add_msg_byte(s, tag & 0xff); } - QTAILQ_REMOVE(&s->queue, p, next); - qemu_free(p); - if (lsi_irq_on_rsl(s)) { lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); } @@ -677,11 +679,15 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, } else { lsi_set_phase(s, PHASE_ST); } + + qemu_free(s->current); + s->current = NULL; + lsi_resume_script(s); return; } - if (s->waiting == 1 || tag != s->current_tag || + if (s->waiting == 1 || tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_tag(s, tag, arg)) return; @@ -711,14 +717,19 @@ static void lsi_do_command(LSIState *s) cpu_physical_memory_read(s->dnad, buf, s->dbc); s->sfbr = buf[0]; s->command_complete = 0; - n = s->current_dev->info->send_command(s->current_dev, s->current_tag, buf, + + assert(s->current == NULL); + s->current = qemu_mallocz(sizeof(lsi_request)); + s->current->tag = s->select_tag; + + n = s->current_dev->info->send_command(s->current_dev, s->current->tag, buf, s->current_lun); if (n > 0) { lsi_set_phase(s, PHASE_DI); - s->current_dev->info->read_data(s->current_dev, s->current_tag); + s->current_dev->info->read_data(s->current_dev, s->current->tag); } else if (n < 0) { lsi_set_phase(s, PHASE_DO); - s->current_dev->info->write_data(s->current_dev, s->current_tag); + s->current_dev->info->write_data(s->current_dev, s->current->tag); } if (!s->command_complete) { @@ -841,16 +852,16 @@ static void lsi_do_msgout(LSIState *s) } break; case 0x20: /* SIMPLE queue */ - s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; DPRINTF("SIMPLE queue tag=0x%x\n", s->current_tag & 0xff); break; case 0x21: /* HEAD of queue */ BADF("HEAD queue not implemented\n"); - s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; break; case 0x22: /* ORDERED queue */ BADF("ORDERED queue not implemented\n"); - s->current_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; + s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID; break; default: if ((msg & 0x80) == 0) { @@ -1086,7 +1097,7 @@ again: it only applies in low-level mode (unimplemented). lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ s->current_dev = s->bus.devs[id]; - s->current_tag = id << 8; + s->select_tag = id << 8; s->scntl1 |= LSI_SCNTL1_CON; if (insn & (1 << 3)) { s->socl |= LSI_SOCL_ATN; -- cgit v1.2.3 From 5773685183ff412933865d323c1b6c0564d9b9c4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jan 2010 17:08:02 +0100 Subject: lsi: move current_dev into lsi_request Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from commit daa70311e0f7b37cd0ea3c4de0d163ccf1a36abe) --- hw/lsi53c895a.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 83c9d542a..4465e08f8 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -175,6 +175,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) typedef struct lsi_request { uint32_t tag; + SCSIDevice *dev; uint32_t pending; int out; QTAILQ_ENTRY(lsi_request) next; @@ -199,7 +200,7 @@ typedef struct { * 3 if a DMA operation is in progress. */ int waiting; SCSIBus bus; - SCSIDevice *current_dev; + SCSIDevice *select_dev; int current_lun; /* The tag is a combination of the device ID and the SCSI tag. */ uint32_t select_tag; @@ -533,8 +534,8 @@ static void lsi_do_dma(LSIState *s, int out) s->dbc -= count; if (s->dma_buf == NULL) { - s->dma_buf = s->current_dev->info->get_buf(s->current_dev, - s->current->tag); + s->dma_buf = s->current->dev->info->get_buf(s->current->dev, + s->current->tag); } /* ??? Set SFBR to first data byte. */ @@ -548,10 +549,10 @@ static void lsi_do_dma(LSIState *s, int out) s->dma_buf = NULL; if (out) { /* Write the data. */ - s->current_dev->info->write_data(s->current_dev, s->current->tag); + s->current->dev->info->write_data(s->current->dev, s->current->tag); } else { /* Request any remaining data. */ - s->current_dev->info->read_data(s->current_dev, s->current->tag); + s->current->dev->info->read_data(s->current->dev, s->current->tag); } } else { s->dma_buf += count; @@ -610,7 +611,6 @@ static void lsi_reselect(LSIState *s, uint32_t tag) s->sfbr = 1 << (id & 0x7); } DPRINTF("Reselected target %d\n", id); - s->current_dev = s->bus.devs[id]; s->scntl1 |= LSI_SCNTL1_CON; lsi_set_phase(s, PHASE_MI); s->msg_action = p->out ? 2 : 3; @@ -721,15 +721,16 @@ static void lsi_do_command(LSIState *s) assert(s->current == NULL); s->current = qemu_mallocz(sizeof(lsi_request)); s->current->tag = s->select_tag; + s->current->dev = s->select_dev; - n = s->current_dev->info->send_command(s->current_dev, s->current->tag, buf, - s->current_lun); + n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf, + s->current_lun); if (n > 0) { lsi_set_phase(s, PHASE_DI); - s->current_dev->info->read_data(s->current_dev, s->current->tag); + s->current->dev->info->read_data(s->current->dev, s->current->tag); } else if (n < 0) { lsi_set_phase(s, PHASE_DO); - s->current_dev->info->write_data(s->current_dev, s->current->tag); + s->current->dev->info->write_data(s->current->dev, s->current->tag); } if (!s->command_complete) { @@ -1096,7 +1097,7 @@ again: /* ??? Linux drivers compain when this is set. Maybe it only applies in low-level mode (unimplemented). lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ - s->current_dev = s->bus.devs[id]; + s->select_dev = s->bus.devs[id]; s->select_tag = id << 8; s->scntl1 |= LSI_SCNTL1_CON; if (insn & (1 << 3)) { -- cgit v1.2.3 From d89930374302722f78bd4337c167e7e8fd7a169a Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jan 2010 17:08:03 +0100 Subject: lsi: move dma_len+dma_buf into lsi_request Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from commit b96a0da06bd782ef290445479a6d4d0de00c2c23) --- hw/lsi53c895a.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 4465e08f8..c43ed2323 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -176,6 +176,8 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) typedef struct lsi_request { uint32_t tag; SCSIDevice *dev; + uint32_t dma_len; + uint8_t *dma_buf; uint32_t pending; int out; QTAILQ_ENTRY(lsi_request) next; @@ -204,9 +206,7 @@ typedef struct { int current_lun; /* The tag is a combination of the device ID and the SCSI tag. */ uint32_t select_tag; - uint32_t current_dma_len; int command_complete; - uint8_t *dma_buf; QTAILQ_HEAD(, lsi_request) queue; lsi_request *current; @@ -509,15 +509,16 @@ static void lsi_do_dma(LSIState *s, int out) uint32_t count; target_phys_addr_t addr; - if (!s->current_dma_len) { + assert(s->current); + if (!s->current->dma_len) { /* Wait until data is available. */ DPRINTF("DMA no data available\n"); return; } count = s->dbc; - if (count > s->current_dma_len) - count = s->current_dma_len; + if (count > s->current->dma_len) + count = s->current->dma_len; addr = s->dnad; /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */ @@ -533,20 +534,20 @@ static void lsi_do_dma(LSIState *s, int out) s->dnad += count; s->dbc -= count; - if (s->dma_buf == NULL) { - s->dma_buf = s->current->dev->info->get_buf(s->current->dev, - s->current->tag); + if (s->current->dma_buf == NULL) { + s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev, + s->current->tag); } /* ??? Set SFBR to first data byte. */ if (out) { - cpu_physical_memory_read(addr, s->dma_buf, count); + cpu_physical_memory_read(addr, s->current->dma_buf, count); } else { - cpu_physical_memory_write(addr, s->dma_buf, count); + cpu_physical_memory_write(addr, s->current->dma_buf, count); } - s->current_dma_len -= count; - if (s->current_dma_len == 0) { - s->dma_buf = NULL; + s->current->dma_len -= count; + if (s->current->dma_len == 0) { + s->current->dma_buf = NULL; if (out) { /* Write the data. */ s->current->dev->info->write_data(s->current->dev, s->current->tag); @@ -555,7 +556,7 @@ static void lsi_do_dma(LSIState *s, int out) s->current->dev->info->read_data(s->current->dev, s->current->tag); } } else { - s->dma_buf += count; + s->current->dma_buf += count; lsi_resume_script(s); } } @@ -568,6 +569,7 @@ static void lsi_queue_command(LSIState *s) DPRINTF("Queueing tag=0x%x\n", s->current_tag); assert(s->current != NULL); + assert(s->current->dma_len == 0); QTAILQ_INSERT_TAIL(&s->queue, s->current, next); s->current = NULL; @@ -614,8 +616,7 @@ static void lsi_reselect(LSIState *s, uint32_t tag) s->scntl1 |= LSI_SCNTL1_CON; lsi_set_phase(s, PHASE_MI); s->msg_action = p->out ? 2 : 3; - s->current_dma_len = p->pending; - s->dma_buf = NULL; + s->current->dma_len = p->pending; lsi_add_msg_byte(s, 0x80); if (s->current->tag & LSI_TAG_VALID) { lsi_add_msg_byte(s, 0x20); @@ -695,7 +696,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, /* host adapter (re)connected */ DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); - s->current_dma_len = arg; + s->current->dma_len = arg; s->command_complete = 1; if (!s->waiting) return; @@ -910,8 +911,6 @@ static void lsi_wait_reselect(LSIState *s) lsi_request *p; DPRINTF("Wait Reselect\n"); - if (s->current_dma_len) - BADF("Reselect with pending DMA\n"); QTAILQ_FOREACH(p, &s->queue, next) { if (p->pending) { @@ -919,7 +918,7 @@ static void lsi_wait_reselect(LSIState *s) break; } } - if (s->current_dma_len == 0) { + if (s->current == NULL) { s->waiting = 1; } } @@ -2010,8 +2009,10 @@ static void lsi_pre_save(void *opaque) { LSIState *s = opaque; - assert(s->dma_buf == NULL); - assert(s->current_dma_len == 0); + if (s->current) { + assert(s->current->dma_buf == NULL); + assert(s->current->dma_len == 0); + } assert(QTAILQ_EMPTY(&s->queue)); } -- cgit v1.2.3 From 3b4bef06969e42bdb929284ecff1dfb41d1b4aed Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 6 Jan 2010 17:08:04 +0100 Subject: lsi: pass lsi_request to lsi_reselect All callers of lsi_reselect have a lsi_request struct at hand anyway. So just pass it directly instead of having lsi_reselect search for it using the tag. Signed-off-by: Gerd Hoffmann Signed-off-by: Anthony Liguori (cherry picked from commit aa4d32c4742e62e09786bd1067a5b98239867e93) --- hw/lsi53c895a.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index c43ed2323..872106d1e 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -371,7 +371,7 @@ static int lsi_dma_64bit(LSIState *s) static uint8_t lsi_reg_readb(LSIState *s, int offset); static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); static void lsi_execute_script(LSIState *s); -static void lsi_reselect(LSIState *s, uint32_t tag); +static void lsi_reselect(LSIState *s, lsi_request *p); static inline uint32_t read_dword(LSIState *s, uint32_t addr) { @@ -430,7 +430,7 @@ static void lsi_update_irq(LSIState *s) "processes\n"); QTAILQ_FOREACH(p, &s->queue, next) { if (p->pending) { - lsi_reselect(s, p->tag); + lsi_reselect(s, p); break; } } @@ -589,24 +589,15 @@ static void lsi_add_msg_byte(LSIState *s, uint8_t data) } /* Perform reselection to continue a command. */ -static void lsi_reselect(LSIState *s, uint32_t tag) +static void lsi_reselect(LSIState *s, lsi_request *p) { - lsi_request *p; int id; - QTAILQ_FOREACH(p, &s->queue, next) { - if (p->tag == tag) - break; - } - if (p == NULL) { - BADF("Reselected non-existant command tag=0x%x\n", tag); - return; - } assert(s->current == NULL); QTAILQ_REMOVE(&s->queue, p, next); s->current = p; - id = (tag >> 8) & 0xf; + id = (p->tag >> 8) & 0xf; s->ssid = id | 0x80; /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */ if (!s->dcntl & LSI_DCNTL_COM) { @@ -620,7 +611,7 @@ static void lsi_reselect(LSIState *s, uint32_t tag) lsi_add_msg_byte(s, 0x80); if (s->current->tag & LSI_TAG_VALID) { lsi_add_msg_byte(s, 0x20); - lsi_add_msg_byte(s, tag & 0xff); + lsi_add_msg_byte(s, p->tag & 0xff); } if (lsi_irq_on_rsl(s)) { @@ -649,7 +640,7 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) && !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) { /* Reselect device. */ - lsi_reselect(s, tag); + lsi_reselect(s, p); return 0; } else { DPRINTF("Queueing IO tag=0x%x\n", tag); @@ -914,7 +905,7 @@ static void lsi_wait_reselect(LSIState *s) QTAILQ_FOREACH(p, &s->queue, next) { if (p->pending) { - lsi_reselect(s, p->tag); + lsi_reselect(s, p); break; } } -- cgit v1.2.3 From 3597c9c1d5722edf1ebcaf01ff1ea7c3b68ecb28 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 29 Mar 2010 15:42:57 +0200 Subject: lsi: fix segfault in lsi_command_complete Signed-off-by: Gerd Hoffmann Signed-off-by: Aurelien Jarno (cherry picked from commit 6ac08101f9de84be1fb7b45f87caed8ba8f3eb5a) --- hw/lsi53c895a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 872106d1e..e0ade1e54 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -679,7 +679,7 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, return; } - if (s->waiting == 1 || tag != s->current->tag || + if (s->waiting == 1 || !s->current || tag != s->current->tag || (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { if (lsi_queue_tag(s, tag, arg)) return; -- cgit v1.2.3 From 012d4869c1eb195e83f159ed7b2bced33f37f960 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 21 Apr 2010 20:35:45 +0100 Subject: block: Free iovec arrays allocated by multiwrite_merge() A new iovec array is allocated when creating a merged write request. This patch ensures that the iovec array is deleted in addition to its qiov owner. Reported-by: Leszek Urbanski Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf (cherry picked from commit 1e1ea48d42e011b9bdd0d689d184e7cac4617b66) --- block.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block.c b/block.c index 4f9a48b71..7326bfeee 100644 --- a/block.c +++ b/block.c @@ -1608,6 +1608,9 @@ static void multiwrite_user_cb(MultiwriteCB *mcb) for (i = 0; i < mcb->num_callbacks; i++) { mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error); + if (mcb->callbacks[i].free_qiov) { + qemu_iovec_destroy(mcb->callbacks[i].free_qiov); + } qemu_free(mcb->callbacks[i].free_qiov); qemu_vfree(mcb->callbacks[i].free_buf); } -- cgit v1.2.3 From b09ac1abe7691988d52082f9108cc8a18add9389 Mon Sep 17 00:00:00 2001 From: malc Date: Fri, 8 Jan 2010 11:26:27 +0300 Subject: oss: workaround for cases when OSS_GETVERSION is not defined Thanks to Juergen Lock. Signed-off-by: malc (cherry picked from commit e726fe7d60d46636c74c1c4a8fac7e4a05efb163) --- audio/ossaudio.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 4002f1467..4766aa725 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -240,7 +240,9 @@ static int oss_open (int in, struct oss_params *req, struct oss_params *obt, int *pfd) { int fd; +#ifdef OSS_GETVERSION int version; +#endif int oflags = conf.exclusive ? O_EXCL : 0; audio_buf_info abinfo; int fmt, freq, nchannels; @@ -281,6 +283,7 @@ static int oss_open (int in, struct oss_params *req, goto err; } +#ifdef OSS_GETVERSION if (ioctl (fd, OSS_GETVERSION, &version)) { oss_logerr2 (errno, typ, "Failed to get OSS version\n"); version = 0; @@ -289,9 +292,17 @@ static int oss_open (int in, struct oss_params *req, if (conf.debug) { dolog ("OSS version = %#x\n", version); } +#endif #ifdef SNDCTL_DSP_POLICY - if (conf.policy >= 0 && version >= 0x040000) { + if (conf.policy >= 0 +#ifdef OSS_GETVERSION + && version >= 0x040000 +#else + 0 +#endif + ) + { int policy = conf.policy; if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n", -- cgit v1.2.3 From 8f30db54d9de358146fe549315daebf66dad7a82 Mon Sep 17 00:00:00 2001 From: malc Date: Sat, 9 Jan 2010 00:28:40 +0300 Subject: oss: refactor code around policy setting This fixes a problem with a previous patch spotted by Juergen Lock, thanks to him again. Signed-off-by: malc (cherry picked from commit 78d9356d3caad95a74bc9cd65eea5fc7e050c35d) --- audio/ossaudio.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 4766aa725..fe6fb523b 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -38,6 +38,10 @@ #define AUDIO_CAP "oss" #include "audio_int.h" +#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY +#define USE_DSP_POLICY +#endif + typedef struct OSSVoiceOut { HWVoiceOut hw; void *pcm_buf; @@ -240,7 +244,7 @@ static int oss_open (int in, struct oss_params *req, struct oss_params *obt, int *pfd) { int fd; -#ifdef OSS_GETVERSION +#ifdef USE_DSP_POLICY int version; #endif int oflags = conf.exclusive ? O_EXCL : 0; @@ -283,7 +287,7 @@ static int oss_open (int in, struct oss_params *req, goto err; } -#ifdef OSS_GETVERSION +#ifdef USE_DSP_POLICY if (ioctl (fd, OSS_GETVERSION, &version)) { oss_logerr2 (errno, typ, "Failed to get OSS version\n"); version = 0; @@ -292,16 +296,8 @@ static int oss_open (int in, struct oss_params *req, if (conf.debug) { dolog ("OSS version = %#x\n", version); } -#endif -#ifdef SNDCTL_DSP_POLICY - if (conf.policy >= 0 -#ifdef OSS_GETVERSION - && version >= 0x040000 -#else - 0 -#endif - ) + if (conf.policy >= 0 && version >= 0x040000) { int policy = conf.policy; if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { @@ -868,7 +864,7 @@ static struct audio_option oss_options[] = { .valp = &conf.exclusive, .descr = "Open device in exclusive mode (vmix wont work)" }, -#ifdef SNDCTL_DSP_POLICY +#ifdef USE_DSP_POLICY { .name = "POLICY", .tag = AUD_OPT_INT, -- cgit v1.2.3 From 2a444947268503e5fa70297de398b813a8ee3b25 Mon Sep 17 00:00:00 2001 From: malc Date: Sat, 9 Jan 2010 17:54:07 +0300 Subject: oss: issue OSS_GETVERSION ioctl only when needed Signed-off-by: malc (cherry picked from commit 6d246526ce3c145b2831285def6983f5de6190d3) --- audio/ossaudio.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index fe6fb523b..79d1daa1c 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -244,9 +244,6 @@ static int oss_open (int in, struct oss_params *req, struct oss_params *obt, int *pfd) { int fd; -#ifdef USE_DSP_POLICY - int version; -#endif int oflags = conf.exclusive ? O_EXCL : 0; audio_buf_info abinfo; int fmt, freq, nchannels; @@ -288,22 +285,25 @@ static int oss_open (int in, struct oss_params *req, } #ifdef USE_DSP_POLICY - if (ioctl (fd, OSS_GETVERSION, &version)) { - oss_logerr2 (errno, typ, "Failed to get OSS version\n"); - version = 0; - } + if (conf.policy >= 0) { + int version; - if (conf.debug) { - dolog ("OSS version = %#x\n", version); - } + if (ioctl (fd, OSS_GETVERSION, &version)) { + oss_logerr2 (errno, typ, "Failed to get OSS version\n"); + version = 0; + } - if (conf.policy >= 0 && version >= 0x040000) - { - int policy = conf.policy; - if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { - oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n", - conf.policy); - goto err; + if (conf.debug) { + dolog ("OSS version = %#x\n", version); + } + + if (version >= 0x040000) { + int policy = conf.policy; + if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { + oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n", + conf.policy); + goto err; + } } } else -- cgit v1.2.3 From 2b8bdd5c7fc3f4de476b5c4d48ea702a220a7461 Mon Sep 17 00:00:00 2001 From: malc Date: Sat, 9 Jan 2010 18:06:54 +0300 Subject: oss: fix fragment setting Previous patch introduced subtle regression, in cases when OSS_GETVERSION fails the code wasn't falling back to SNDCTL_DSP_SETFRAGMENT. Signed-off-by: malc (cherry picked from commit 3d709fe73a77c40e263b3af6e650fd4b519c3562) --- audio/ossaudio.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index 79d1daa1c..ebf8b2397 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -247,6 +247,7 @@ static int oss_open (int in, struct oss_params *req, int oflags = conf.exclusive ? O_EXCL : 0; audio_buf_info abinfo; int fmt, freq, nchannels; + int setfragment = 1; const char *dspname = in ? conf.devpath_in : conf.devpath_out; const char *typ = in ? "ADC" : "DAC"; @@ -290,25 +291,27 @@ static int oss_open (int in, struct oss_params *req, if (ioctl (fd, OSS_GETVERSION, &version)) { oss_logerr2 (errno, typ, "Failed to get OSS version\n"); - version = 0; - } - - if (conf.debug) { - dolog ("OSS version = %#x\n", version); } + else { + if (conf.debug) { + dolog ("OSS version = %#x\n", version); + } - if (version >= 0x040000) { - int policy = conf.policy; - if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { - oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n", - conf.policy); - goto err; + if (version >= 0x040000) { + int policy = conf.policy; + if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { + oss_logerr2 (errno, typ, + "Failed to set timing policy to %d\n", + conf.policy); + goto err; + } + setfragment = 0; } } } - else #endif - { + + if (setfragment) { int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize); if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", -- cgit v1.2.3 From d04d7cf15854e92ad6d0414ae760334966534a68 Mon Sep 17 00:00:00 2001 From: Juergen Lock Date: Tue, 12 Jan 2010 23:48:04 +0100 Subject: Workaround for broken OSS_GETVERSION on FreeBSD, part two Turns out on those versions of FreeBSD (>= 7.x) that know OSS_GETVERSION the ioctl doesn't actually work yet (except in the Linuxolator), so if building on FreeBSD assume the sound drivers are new enough if the ioctl returns the errno it does currently on FreeBSD. (Rev 2 after private discussion with malc.) Signed-off-by: Juergen Lock Signed-off-by: malc (cherry picked from commit 72ff25e4e98d6dba9286d032b9ff5432553bbad5) --- audio/ossaudio.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/audio/ossaudio.c b/audio/ossaudio.c index ebf8b2397..42bffaeaf 100644 --- a/audio/ossaudio.c +++ b/audio/ossaudio.c @@ -240,6 +240,31 @@ static void oss_dump_info (struct oss_params *req, struct oss_params *obt) } #endif +#ifdef USE_DSP_POLICY +static int oss_get_version (int fd, int *version, const char *typ) +{ + if (ioctl (fd, OSS_GETVERSION, &version)) { +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + /* + * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION + * since 7.x, but currently only on the mixer device (or in + * the Linuxolator), and in the native version that part of + * the code is in fact never reached so the ioctl fails anyway. + * Until this is fixed, just check the errno and if its what + * FreeBSD's sound drivers return atm assume they are new enough. + */ + if (errno == EINVAL) { + *version = 0x040000; + return 0; + } +#endif + oss_logerr2 (errno, typ, "Failed to get OSS version\n"); + return -1; + } + return 0; +} +#endif + static int oss_open (int in, struct oss_params *req, struct oss_params *obt, int *pfd) { @@ -289,10 +314,7 @@ static int oss_open (int in, struct oss_params *req, if (conf.policy >= 0) { int version; - if (ioctl (fd, OSS_GETVERSION, &version)) { - oss_logerr2 (errno, typ, "Failed to get OSS version\n"); - } - else { + if (!oss_get_version (fd, &version, typ)) { if (conf.debug) { dolog ("OSS version = %#x\n", version); } -- cgit v1.2.3 From b04c3db504f35b57a2ce519313f3d49fcecf6cb3 Mon Sep 17 00:00:00 2001 From: Anthony Liguori Date: Tue, 4 May 2010 09:17:19 -0500 Subject: Update for 0.12.4 release Signed-off-by: Anthony Liguori --- Changelog | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ VERSION | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 67d0efd3a..4feb1867e 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,53 @@ +version 0.12.4 + - Workaround for broken OSS_GETVERSION on FreeBSD, part two (Juergen Lock) + - oss: fix fragment setting (malc) + - oss: issue OSS_GETVERSION ioctl only when needed (malc) + - oss: refactor code around policy setting (malc) + - oss: workaround for cases when OSS_GETVERSION is not defined (malc) + - block: Free iovec arrays allocated by multiwrite_merge() (Stefan Hajnoczi) + - lsi: fix segfault in lsi_command_complete (Gerd Hoffmann) + - lsi: pass lsi_request to lsi_reselect (Gerd Hoffmann) + - lsi: move dma_len+dma_buf into lsi_request (Gerd Hoffmann) + - lsi: move current_dev into lsi_request (Gerd Hoffmann) + - lsi: have lsi_request for the whole life time of the request. (Gerd Hoffmann) + - lsi: use QTAILQ for lsi_queue (Gerd Hoffmann) + - tcp/mips: Change TCG_AREG0 (fp -> s0) (Stefan Weil) + - sh_pci: fix memory and I/O access (Aurelien Jarno) + - Fix incoming migration with iothread (Marcelo Tosatti) + - Fix SIGFPE for vnc display of width/height = 1 (Chris Webb) + - net: remove broken net_set_boot_mask() boot device validation (Eduardo Habkost) + - qcow2: Remove request from in-flight list after error (Kevin Wolf) + - qcow2: Don't ignore immediate read/write failures (Kevin Wolf) + - block: Fix multiwrite memory leak in error case (Kevin Wolf) + - block: Fix error code in multiwrite for immediate failures (Kevin Wolf) + - block: Fix multiwrite error handling (Kevin Wolf) + - scsi-disk: fix buffer overflow (Gerd Hoffmann) + - qcow2: Rewrite alloc_refcount_block/grow_refcount_table (Kevin Wolf) + - qcow2: Factor next_refcount_table_size out (Kevin Wolf) + - block: avoid creating too large iovecs in multiwrite_merge (Christoph Hellwig) + - json-parser: Fix segfault on malformed input (Kevin Wolf) + - linux-user: switch default ppc64 CPU to 970fx from 970 (Aurelien Jarno) + - target-sh4: MMU: fix store queue addresses (Aurelien Jarno) + - target-sh4: MMU: fix ITLB priviledge check (Aurelien Jarno) + - target-sh4: MMU: fix mem_idx computation (Aurelien Jarno) + - sh7750: handle MMUCR TI bit (Aurelien Jarno) + - UHCI spurious interrut fix (Paul Brook) + - tcg/mips: fix branch offset during retranslation (Aurelien Jarno) + - tcg/arm: correctly save/restore registers in prologue/epilogue (Aurelien Jarno) + - workaround for cmd646 bmdma register access while no dma is active (Igor V. Kovalenko) + - Fix corner case in chardev udp: parameter (Jan Kiszka) + - Don't set default monitor when there is a mux'ed one (Jan Kiszka) + - spelling typo (compatibilty) in hw/fw_cfg.c (Vagrant Cascadian) + - fdc: fix drive property handling. (Gerd Hoffmann) + - target-i386: fix commit c22549204a6edc431e8e4358e61bd56386ff6957 (TeLeMan) + - target-i386: fix SIB decoding with index = 4 (Aurelien Jarno) + - Fix segfault with ram_size > 4095M without kvm (Ryan Harper) + - target-i386: Fix long jumps/calls in long mode with REX.W set (malc) + - target-i386: fix lddqu SSE instruction (Aurelien Jarno) + - qemu-char.c: drop debug printfs from qemu_chr_parse_compat (Jan Kiszka) + - fix undefined shifts by >32 (Paolo Bonzini) + - Fix qemu -net user,hostfwd= example (Aurelien Jarno) + version 0.12.3 - kvm: Fix eflags corruption in kvm mode (Jan Kiszka) - qcow2: Fix access after end of array (Kevin Wolf) diff --git a/VERSION b/VERSION index aa22d3ce3..e01e0ddd8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.12.3 +0.12.4 -- cgit v1.2.3