Compare commits

..

219 Commits

Author SHA1 Message Date
Gerd Hoffmann
316cb068bd gtk: avoid gd_widget_reparent with gtk 3.14+
gtk_widget_reparent is depricated in gtk 3.14, stop using it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-28 11:25:14 +01:00
Gerd Hoffmann
987fec54e1 gtk: drop gtk_widget_set_double_buffered call
Dunno why it is here.  Removing it seems to have no ill side effects.
It is depricated in 3.14+.  In some cases it has no effect since 3.10
according to the docs:

https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-set-double-buffered

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-28 11:25:14 +01:00
Jan Kiszka
3e9418e160 Revert "main-loop.c: Handle SIGINT, SIGHUP and SIGTERM synchronously"
This reverts commit 15124e1420. It breaks
debuggability of qemu and is no longer needed as the problem has
now been addressed in a different way.

Instead we provide a comment about why these signals must be
handled asynchronously.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>
[PMM: added comment]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-27 15:05:09 +00:00
Jan Kiszka
817ef04db2 Make qemu_shutdown_requested signal-safe
qemu_shutdown_requested may be interrupted by qemu_system_killed. If the
latter sets shutdown_requested after qemu_shutdown_requested has read it
but before it was cleared, the shutdown event is lost. Fix this by using
atomic_xchg.

This provides a different fix for the problem which commit 15124e142
attempts to deal with. That commit breaks use of ^C to drop into gdb,
and so this approach is better (and 15124e142 can be reverted).

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
[PMM: commit message tweak]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-27 14:09:27 +00:00
Peter Maydell
ff0d48768b MAINTAINERS: add myself under 'general project admin' section
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Stefan Weil <sw@weilnetz.de>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Acked-by: Kevin Wolf <kwolf@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Message-id: 1413405052-4527-1-git-send-email-peter.maydell@linaro.org
2014-10-24 14:30:18 +01:00
Leon Alrae
6f64091786 MAINTAINERS: add myself as MIPS guest cores co-maintainer
Add myself to the maintainer list for MIPS guest cores and update the status
from "Odd Fixes" to "Maintained".

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Acked-by: Aurelien Jarno <aurelien@aurel32.net>
Message-id: 1413459487-13658-1-git-send-email-leon.alrae@imgtec.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 14:28:18 +01:00
Leon Alrae
74dda9876b target-mips: add ULL suffix in bitswap to avoid compiler warning
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Message-id: 1413982829-27225-1-git-send-email-leon.alrae@imgtec.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 14:07:51 +01:00
Peter Maydell
71b7f54fdf Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20141024' into staging
target-arm queue:
 * remove pointless 'info pcmcia' and a lot of now-dead code
 * register ARM cpu reset handlers even if not using -kernel
 * update to libvixl 1.6
 * various minor code cleanups
 * support PSCI under TCG ('virt' machine can now be shut down,
   SMP configurations work)
 * correct the sense of the AArch64 DCZID DZP bit
 * report a valid L1Ip field in CTR_EL0 for CPU type "any"
 * correctly UNDEF writes to FPINST/FPINST2 from EL0
 * more preparatory code refactoring for EL2/EL3 support

# gpg: Signature made Fri 24 Oct 2014 12:35:52 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20141024: (23 commits)
  target-arm: A32: Emulate the SMC instruction
  target-arm: make arm_current_el() return EL3
  target-arm: rename arm_current_pl to arm_current_el
  target-arm: reject switching to monitor mode
  target-arm: add arm_is_secure() function
  target-arm: increase arrays of registers R13 & R14
  target-arm: correctly UNDEF writes to FPINST/FPINST2 from EL0
  target-arm: Report a valid L1Ip field in CTR_EL0 for CPU type "any"
  target-arm: Correct sense of the DCZID DZP bit
  arm/virt: enable PSCI emulation support for system emulation
  target-arm: add emulation of PSCI calls for system emulation
  target-arm: Add support for A32 and T32 HVC and SMC insns
  target-arm: Handle SMC/HVC undef-if-no-ELx in pre_* helpers
  target-arm: add missing PSCI constants needed for PSCI emulation
  target-arm: do not set do_interrupt handlers for ARM and AArch64 user modes
  target-arm: add powered off cpu state
  omap_gpmc.c: Remove duplicate assignment
  disas/libvixl/a64/instructions-a64.h: Remove unused constants
  arm_gic: remove unused parameter.
  disas/libvixl: Update to libvixl 1.6
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:40:29 +01:00
Fabian Aggeler
dbe9d16367 target-arm: A32: Emulate the SMC instruction
Implements SMC instruction in AArch32 using the A32 syndrome. When executing
SMC instruction from monitor CPU mode SCR.NS bit is reset.

Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Message-id: 1413910544-20150-7-git-send-email-greg.bellows@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:15 +01:00
Fabian Aggeler
592125f83a target-arm: make arm_current_el() return EL3
Make arm_current_el() return EL3 for secure PL1 and monitor mode.
Increase MMU modes since mmu_index is directly inferred from arm_
current_el(). Change assertion in arm_el_is_aa64() to allow EL3.

Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1413910544-20150-6-git-send-email-greg.bellows@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:14 +01:00
Greg Bellows
dcbff19bd0 target-arm: rename arm_current_pl to arm_current_el
Renamed the arm_current_pl CPU function to more accurately represent that it
returns the ARMv8 EL rather than ARMv7 PL.

Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1413910544-20150-5-git-send-email-greg.bellows@linaro.org
[PMM: fixed a minor merge resolution error in a couple of hunks]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:14 +01:00
Sergey Fedorov
027fc52704 target-arm: reject switching to monitor mode
Reject switching to monitor mode from non-secure state.

Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1413910544-20150-4-git-send-email-greg.bellows@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:14 +01:00
Fabian Aggeler
19e0fefa6f target-arm: add arm_is_secure() function
arm_is_secure() function allows to determine CPU security state
if the CPU implements Security Extensions/EL3.
arm_is_secure_below_el3() returns true if CPU is in secure state
below EL3.

Signed-off-by: Sergey Fedorov <s.fedorov@samsung.com>
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1413910544-20150-3-git-send-email-greg.bellows@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:14 +01:00
Fabian Aggeler
0b7d409d42 target-arm: increase arrays of registers R13 & R14
Increasing banked_r13 and banked_r14 to store LR_mon and SP_mon (bank
index 7).

Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1413910544-20150-2-git-send-email-greg.bellows@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:14 +01:00
Peter Maydell
23adb8618c target-arm: correctly UNDEF writes to FPINST/FPINST2 from EL0
The ARM ARM requires that the FPINST and FPINST2 VFP control
registers are not accessible to code at EL0. We were already
correctly implementing this for reads of these registers; add
the missing check for the write code path.

Reported-by: Laurent Desnogues <laurent.desnogues@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
Message-id: 1412967447-20931-1-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:14 +01:00
Peter Maydell
0e7b176ae0 target-arm: Report a valid L1Ip field in CTR_EL0 for CPU type "any"
For the CPU type "any" (only used with linux-user) we were reporting
the L1Ip field as 0b00, which is reserved. Change this field to 0b10
instead, indicating a VIPT icache as the comment describes.

Reported-by: Laurent Desnogues <laurent.desnogues@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
Message-id: 1412966807-20844-1-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:13 +01:00
Peter Maydell
14e5f10607 target-arm: Correct sense of the DCZID DZP bit
The DZP bit in the DCZID system register should be set if
the control bits which prohibit use of the DC ZVA instruction
have been set (it stands for Data Zero Prohibited). However
we had the sense of the test inverted; fix this so that the
bit reads correctly.

To avoid this regressing the behaviour of the user-mode
emulator, we must set the DZE bit in the SCTLR for that
config so that userspace continues to see DZP as zero (it
was getting the correct result by accident previously).

Reported-by: Christopher Covington <cov@codeaurora.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Christopher Covington <cov@codeaurora.org>
Message-id: 1412959792-20708-1-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:13 +01:00
Rob Herring
211b016915 arm/virt: enable PSCI emulation support for system emulation
Now that we have PSCI emulation, enable it for the virt platform.
This simplifies the virt machine a bit now that PSCI no longer
needs to be a KVM only feature.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-8-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:13 +01:00
Rob Herring
98128601ac target-arm: add emulation of PSCI calls for system emulation
Add support for handling PSCI calls in system emulation. Both version
0.1 and 0.2 of the PSCI spec are supported. Platforms can enable support
by setting the "psci-conduit" QOM property on the cpus to SMC or HVC
emulation and having a PSCI binding in their dtb.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-7-git-send-email-peter.maydell@linaro.org
[PMM: made system reset/off PSCI functions power down the CPU so
 we obey the PSCI API requirement never to return from them;
 rearranged how the code is plumbed into the exception system,
 so that we split "is this a valid call?" from "do the call"]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:13 +01:00
Peter Maydell
37e6456ef5 target-arm: Add support for A32 and T32 HVC and SMC insns
Add support for HVC and SMC instructions to the A32 and
T32 decoder. Using these for real exceptions to EL2 or EL3
is currently not supported (the do_interrupt routine does
not handle them) but we require the instruction support to
implement PSCI.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-6-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:13 +01:00
Peter Maydell
3940433843 target-arm: Handle SMC/HVC undef-if-no-ELx in pre_* helpers
SMC must UNDEF if EL3 is not implemented; similarly HVC UNDEFs
if EL2 is not implemented. Move the handling of this from
translate-a64.c into the pre_smc and pre_hvc helper functions.
This is necessary because use of these instructions for PSCI
takes precedence over this UNDEF case, and we can't tell if
this is a PSCI call until runtime.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-5-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:12 +01:00
Ard Biesheuvel
3df53cdf56 target-arm: add missing PSCI constants needed for PSCI emulation
This adds some PSCI function IDs and symbolic return codes that are needed
to implement PSCI emulation in TCG mode.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-4-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:12 +01:00
Rob Herring
0adf7d3cc3 target-arm: do not set do_interrupt handlers for ARM and AArch64 user modes
User mode emulation should never get interrupts and thus should not
use the system emulation exception handler function. Remove the reference,
and '#ifndef USER_MODE_ONLY' the function itself as well, so that we can add
system mode only functionality to it.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-3-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:12 +01:00
Rob Herring
543486db35 target-arm: add powered off cpu state
Add tracking of cpu power state in order to support powering off of
cores in system emuluation. The initial state is determined by the
start-powered-off QOM property.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412865028-17725-2-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:12 +01:00
Dr. David Alan Gilbert
635117e71f omap_gpmc.c: Remove duplicate assignment
This looks like an old merge error and should have no effect.
(Build tested only)

Found by Coccinelle using Julia Lawall's script:
https://lkml.org/lkml/2014/8/23/128

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-id: 1414055855-6688-1-git-send-email-dgilbert@redhat.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:12 +01:00
Chen Gang
94cc44a9e5 disas/libvixl/a64/instructions-a64.h: Remove unused constants
The instructions-a64.h header defines a number of floating point
constants whose initializers are function calls. gcc 5 will warn
if these constants are not used by the C or C++ file which includes
the header, because they imply a runtime cost. Since for the files
QEMU uses from libvixl we don't use these constants at all, just
remove them.

Upstream intend to fix these by shifting to an 'extern const' in
the header plus definition in a suitable source file, so we can
drop this patch when we sync with the upcoming libvixl 1.7.

The related compiling error:

    CXX   disas/arm-a64.o
  In file included from /upstream/qemu/disas/libvixl/a64/disasm-a64.h:32:0,
                   from disas/arm-a64.cc:20:
  disas/libvixl/a64/instructions-a64.h:98:13: error: 'vixl::kFP32PositiveInfinity' defined but not used [-Werror=unused-variable]
   const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
               ^
  disas/libvixl/a64/instructions-a64.h:99:13: error: 'vixl::kFP32NegativeInfinity' defined but not used [-Werror=unused-variable]
   const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
               ^
  disas/libvixl/a64/instructions-a64.h💯14: error: 'vixl::kFP64PositiveInfinity' defined but not used [-Werror=unused-variable]
   const double kFP64PositiveInfinity =
                ^
  disas/libvixl/a64/instructions-a64.h:102:14: error: 'vixl::kFP64NegativeInfinity' defined but not used [-Werror=unused-variable]
   const double kFP64NegativeInfinity =
                ^
  disas/libvixl/a64/instructions-a64.h:107:21: error: 'vixl::kFP64SignallingNaN' defined but not used [-Werror=unused-variable]
   static const double kFP64SignallingNaN =
                       ^
  disas/libvixl/a64/instructions-a64.h:109:20: error: 'vixl::kFP32SignallingNaN' defined but not used [-Werror=unused-variable]
   static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
                      ^
  disas/libvixl/a64/instructions-a64.h:112:21: error: 'vixl::kFP64QuietNaN' defined but not used [-Werror=unused-variable]
   static const double kFP64QuietNaN =
                       ^
  disas/libvixl/a64/instructions-a64.h:114:20: error: 'vixl::kFP32QuietNaN' defined but not used [-Werror=unused-variable]
   static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
                      ^
  disas/libvixl/a64/instructions-a64.h:117:21: error: 'vixl::kFP64DefaultNaN' defined but not used [-Werror=unused-variable]
   static const double kFP64DefaultNaN =
                       ^
  disas/libvixl/a64/instructions-a64.h:119:20: error: 'vixl::kFP32DefaultNaN' defined but not used [-Werror=unused-variable]
   static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
                      ^
  cc1plus: all warnings being treated as errors
  make: *** [disas/arm-a64.o] Error 1

Signed-off-by: Chen Gang <gang.chen.5i5j@gmail.com>
[PMM: Rewrote the commit message a little]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:12 +01:00
KONRAD Frederic
7b95a50858 arm_gic: remove unused parameter.
This removes num_irq parameter from gic_init_irqs_and_distributor as it is not
used.

Signed-off-by: KONRAD Frederic <fred.konrad@greensocs.com>
Message-id: 1412859651-15060-1-git-send-email-fred.konrad@greensocs.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:11 +01:00
Peter Maydell
6aea44fc2b disas/libvixl: Update to libvixl 1.6
Update our copy of libvixl to upstream 1.6. There are no
changes of any particular interest to QEMU, so this is simply
keeping up with current upstream.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1412091418-25744-1-git-send-email-peter.maydell@linaro.org
2014-10-24 12:19:11 +01:00
Ard Biesheuvel
c6faa758e3 hw/arm/boot: register cpu reset handlers if using -bios
Move the registering of CPU reset handlers to before the point where
we leave the function in the -bios (not -kernel) case, so CPU reset
works correctly with -bios as well.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:11 +01:00
Claudio Fontana
b32a950910 hw/arm/virt: mark timer in fdt as v8-compatible
check if the first cpu is an armv8 cpu, and if so, put
arm,armv8-timer in the compatible string list.

Note that due to this check, this patch moves the creation
of the timer fdt node to after the cpu creation loop.

Signed-off-by: Claudio Fontana <claudio.fontana@huawei.com>
Message-id: 1411736960-24206-1-git-send-email-hw.claudio@gmail.com
[PMM: updated to list arm,armv8-timer first]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:11 +01:00
Markus Armbruster
7797a73947 hmp: Remove "info pcmcia"
This command lists PCMCIA sockets and cards.  Only a few ARM boards
have sockets (akita, borzoi, connex, mainstone, spitz, terrier, tosa,
verdex, z2), the only card is the DSCM-1xxxx Hitachi Microdrive (qdev
"microdrive"), and it is only inserted during machine init, if ever.
So this command doesn't really tell anybody anything new so far.

Moreover, pcmcia_socket_unregister() has a use-after-free bug, flagged
by Coverity.  Has never been used, because there has never been code
to eject a PCMCIA card.

Not worth fixing & converting to QMP.  Remove it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Luiz Capitulino <lcapitulino@redhat.com>
Acked-by: Andreas Färber <afaerber@suse.de>
Message-id: 1411144812-22958-1-git-send-email-armbru@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 12:19:11 +01:00
Peter Maydell
8b135a288a Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches

# gpg: Signature made Thu 23 Oct 2014 18:56:05 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (32 commits)
  qemu-img: Print error if check failed
  block: char devices on FreeBSD are not behind a pager
  iotests: Add test for qcow2 L1 table update
  qcow2: Do not overflow when writing an L1 sector
  iotests: Add test for map commands
  qemu-io: Respect early image end for map
  block: Respect underlying file's EOF
  docs/qcow2: Limit refcount_order to [0, 6]
  docs/qcow2: Correct refcount_block_entries
  qcow2: Drop REFCOUNT_SHIFT
  iotests: Add test for potentially damaging repairs
  iotests: Fix test outputs
  qcow2: Clean up after refcount rebuild
  qcow2: Rebuild refcount structure during check
  qcow2: Do not perform potentially damaging repairs
  qcow2: Fix refcount blocks beyond image end
  qcow2: Reuse refcount table in calculate_refcounts()
  qcow2: Let inc_refcounts() resize the reftable
  qcow2: Let inc_refcounts() return -errno
  qcow2: Split fail code in L1 and L2 checks
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-24 11:33:46 +01:00
Kevin Wolf
d4db399b8b Merge remote-tracking branch 'mreitz/block' into queue-block
* mreitz/block:
  qemu-img: Print error if check failed
  block: char devices on FreeBSD are not behind a pager
2014-10-23 19:55:55 +02:00
Max Reitz
832390a5ed qemu-img: Print error if check failed
Currently, if bdrv_check() fails either by returning -errno or having
check_errors set, qemu-img check just exits with 1 after having told the
user that there were no errors on the image. This is bad.

Instead of printing the check result if there were internal errors which
were so bad that bdrv_check() could not even complete with 0 as a return
value, qemu-img check should inform the user about the error.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2014-10-23 19:42:07 +02:00
Peter Maydell
1430500bb8 Merge remote-tracking branch 'remotes/qmp-unstable/tags/for-upstream' into staging
QMP patches

# gpg: Signature made Thu 23 Oct 2014 16:05:52 BST using RSA key ID E24ED5A7
# gpg: Good signature from "Luiz Capitulino <lcapitulino@gmail.com>"

* remotes/qmp-unstable/tags/for-upstream:
  monitor: delete device_del_bus_completion
  monitor: add del completion for peripheral device
  qdev: add qdev_build_hotpluggable_device_list helper
  MAINTAINERS: add entry for qobject files
  dump: Turn some functions to void to make code cleaner
  dump: Propagate errors into qmp_dump_guest_memory()
  virtio-balloon: Tweak recent fix for integer overflow

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-23 17:05:15 +01:00
Roger Pau Monne
3cad83075c block: char devices on FreeBSD are not behind a pager
Introduce a new flag to mark devices that require requests to be aligned and
replace the usage of BDRV_O_NOCACHE and O_DIRECT with this flag when
appropriate.

If a character device is used as a backend on a FreeBSD host set this flag
unconditionally.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
2014-10-23 16:56:53 +02:00
Max Reitz
1b2dd0bee6 iotests: Add test for qcow2 L1 table update
Updating the L1 table should not result in random data being written.
This adds a test for that.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
a1391444fe qcow2: Do not overflow when writing an L1 sector
While writing an L1 table sector, qcow2_write_l1_entry() copies the
respective range from s->l1_table to the local "buf" array. The size of
s->l1_table does not have to be a multiple of L1_ENTRIES_PER_SECTOR;
thus, limit the index which is used for copying all entries to the L1
size.

Cc: qemu-stable@nongnu.org
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Peter Lieven <pl@kamp.de>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
925bb3238d iotests: Add test for map commands
Add a test for qemu-img map and qemu-io -c map on truncated files.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
4b25bbc4c2 qemu-io: Respect early image end for map
bdrv_is_allocated() may report zero clusters which most probably means
the image (file) is shorter than expected. Respect this case in order to
avoid an infinite loop.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
59c9a95fd2 block: Respect underlying file's EOF
When falling through to the underlying file in
bdrv_co_get_block_status(), if it returns that the query offset is
beyond the file end (by setting *pnum to 0), return the range to be
zero and do not let the number of sectors for which information could be
obtained be overwritten.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
7f75a07d50 docs/qcow2: Limit refcount_order to [0, 6]
Specify the upper limit of refcount_order to be 6 (that is,
refcount_bits = 64). Any larger value does not make much sense when all
offsets, sizes, cluster counts etc. "only" have a width of 64 bit as
well, and very large values would be very difficult to support.
Therefore, just cap it at the largest reasonable value.

Suggested-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
4b318d6ca6 docs/qcow2: Correct refcount_block_entries
A refblock entry may have a different size than 16 bits, it may even be
smaller than a byte. Correct the refcount_block_entries calculation
accordingly.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
17bd5f4727 qcow2: Drop REFCOUNT_SHIFT
With BDRVQcowState.refcount_block_bits, we don't need REFCOUNT_SHIFT
anymore.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:02 +02:00
Max Reitz
234764eed1 iotests: Add test for potentially damaging repairs
There are certain cases where repairing a qcow2 image might actually
damage it further (or rather, where repairing it has in fact damaged it
further with the old qcow2 check implementation). This should not
happen, so add a test for these cases.

Furthermore, the repair function now repairs refblocks beyond the image
end by resizing the image accordingly. Add several tests for this as
well.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
d26e6ec052 iotests: Fix test outputs
039, 060 and 061 all create images with referenced clusters having a
refcount of 0. Because previous commits changed handling of such errors,
these tests now have a different output. Fix it.

Furthermore, 060 created a refblock with a refcount greater than one
which now results in having to rebuild the refcount structure as well.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
791230d8bb qcow2: Clean up after refcount rebuild
Because the old refcount structure will be leaked after having rebuilt
it, we need to recalculate the refcounts and run a leak-fixing operation
afterwards (if leaks should be fixed at all).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
c7c0681bc8 qcow2: Rebuild refcount structure during check
The previous commit introduced the "rebuild" variable to qcow2's
implementation of the image consistency check. Now make use of this by
adding a function which creates a completely new refcount structure
based solely on the in-memory information gathered before.

The old refcount structure will be leaked, however. This leak will be
dealt with in a follow-up commit.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
f307b2558f qcow2: Do not perform potentially damaging repairs
If a referenced cluster has a refcount of 0, increasing its refcount may
result in clusters being allocated for the refcount structures. This may
overwrite the referenced cluster, therefore we cannot simply increase
the refcount then.

In such cases, we can either try to replicate all the refcount
operations solely for the check operation, basing the allocations on the
in-memory refcount table; or we can simply rebuild the whole refcount
structure based on the in-memory refcount table. Since the latter will
be much easier, do that.

To prepare for this, introduce a "rebuild" boolean which should be set
to true whenever a fix is rather dangerous or too complicated using the
current refcount structures. Another example for this is refcount blocks
being referenced more than once.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
001c158def qcow2: Fix refcount blocks beyond image end
If the qcow2 check function detects a refcount block located beyond the
image end, grow the image appropriately. This cannot break anything and
is the logical fix for such a case.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
9696df219a qcow2: Reuse refcount table in calculate_refcounts()
We will later call calculate_refcounts multiple times, so reuse the
refcount table if possible.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
641bb63cd6 qcow2: Let inc_refcounts() resize the reftable
Now that the refcount table can be passed around by reference, do that
for inc_refcounts() (and subsequently check_refcounts_l1() and
check_refcounts_l2()) and use it for resizing it when a cluster after
the image end is encountered.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
fef4d3d564 qcow2: Let inc_refcounts() return -errno
As of a future patch, inc_refcounts() will have to throw errors which
are generally signaled by returning -errno. Therefore, let it return an
integer which is either 0 for success or -errno and handle the -errno
case in all callers.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
ad27390c85 qcow2: Split fail code in L1 and L2 checks
Instead of printing out an error message, incrementing check_errors and
returning a fixed -errno, just do cleanups and return -ret, with ret set
by the code which threw the exception (jumped to the fail label).

Also, increment check_errors on error in check_refcounts_l2().

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
713d9675e0 qcow2: Use int64_t for in-memory reftable size
Use int64_t for the entry count of the in-memory refcount table
throughout the check functions.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
057a3fe57e qcow2: Pull check_refblocks() up
Pull check_refblocks() before calculate_refcounts() so we can drop its
static declaration.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
78fb328e85 qcow2: Use sizeof(**refcount_table)
When implementing variable refcounts, we want to be able to easily find
all the places in qemu which are tied to a certain refcount order.
Replace sizeof(uint16_t) in the check code by sizeof(**refcount_table)
so we can later find it more easily.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
6ca56bf5e9 qcow2: Split qcow2_check_refcounts()
Put the code for calculating the reference counts and comparing them
during qemu-img check into own functions.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
5b84106bd9 qcow2: Fix leaks in dirty images
When opening dirty images, qcow2's repair function should not only
repair errors but leaks as well.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
1d13d65466 qcow2: Calculate refcount block entry count
The size of a refblock entry is (in theory) variable; calculate
therefore the number of entries per refblock and the according bit shift
(1 << x == entry count) when opening an image.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
9ebd844805 block: Add qemu_{,try_}blockalign0()
These functions call their non-0-counterparts and then fill the
allocated buffer with 0 (if the allocation has been successful).

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Peter Lieven
c5f7c0af47 block: qemu-iotests change _supported_proto to file once more.
In preparation to possible automatic regression and performance
testing for the block layer I found that the iotests don't work
for all protocols anymore.

In commit 1f7bf7d0 I started to change supported protocols from
generic to file for various tests. Unfortunately, some tests
added in the meantime again carry generic protocol altough they
can only work with file because they require local file access.

The other way around for some tests that only support file I added
NFS protocol after confirming they work.

Signed-off-by: Peter Lieven <pl@kamp.de>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Max Reitz
e9082e4736 block/vdi: Use {DIV_,}ROUND_UP
There are macros for these operations, so make use of them.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Paolo Bonzini
8113fb5292 MAINTAINERS: add the image fuzzer to the block layer
More work for the block device maintainers!

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Kevin Wolf
292420918d MAINTAINERS: qemu-iotests belongs to the block layer
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Paolo Bonzini
558939c6c7 MAINTAINERS: add aio to block layer
AioContext falls under the block layer, mark it as such.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-23 15:34:01 +02:00
Zhu Guihua
e799157c76 monitor: delete device_del_bus_completion
device_del_bus_completion() that gathers devices from buses is unused; delete
it.

Signed-off-by: Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
Reviewed-by: Marcel Apfelbaum <marcel.a@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:04:05 -04:00
Zhu Guihua
6a1fa9f5a6 monitor: add del completion for peripheral device
Add peripheral_device_del_completion() to let peripheral device del completion
be possible.

Signed-off-by: Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
Reviewed-by: Marcel Apfelbaum <marcel.a@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:03:44 -04:00
Zhu Guihua
66e56b13ad qdev: add qdev_build_hotpluggable_device_list helper
For peripheral device del completion, add a function to build a list for
hotpluggable devices.

Signed-off-by: Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
Reviewed-by: Marcel Apfelbaum <marcel.a@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:02:51 -04:00
Luiz Capitulino
f3582ba41c MAINTAINERS: add entry for qobject files
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:01:29 -04:00
zhanghailiang
4c7e251ae6 dump: Turn some functions to void to make code cleaner
Functions shouldn't return an error code and an Error object at the same time.
Turn all these functions that returning Error object to void.
We also judge if a function success or fail by reference to the local_err.

Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:01:29 -04:00
zhanghailiang
37917da2d0 dump: Propagate errors into qmp_dump_guest_memory()
The code calls dump_error() on error, and even passes it a suitable
message.  However, the message is thrown away, and its callers pass
up only success/failure.  All qmp_dump_guest_memory() can do is set
a generic error.

Propagate the errors properly, so qmp_dump_guest_memory() can return
a more useful error.

Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:01:29 -04:00
Markus Armbruster
22644cd2c6 virtio-balloon: Tweak recent fix for integer overflow
Commit 1f9296b avoids "other kinds of overflow" by limiting the
polling interval to UINT_MAX.  The computations to protect are done in
64 bits.  This is indeed safe when unsigned is 32 bits, as it commonly
is.  It isn't when unsigned is 64 bits.  Purely theoretical; I'm not
aware of such a system.  Limit it to UINT32_MAX instead.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-10-23 09:01:29 -04:00
Peter Maydell
e40830afa1 Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2014-10-22-tag' into staging
qga: remove readdir_r usage and fix use-after-free

Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>

# gpg: Signature made Wed 22 Oct 2014 13:56:19 BST using RSA key ID F108B584
# gpg: Can't check signature: public key not found

* remotes/mdroth/tags/qga-pull-2014-10-22-tag:
  qga: Rewrite code where using readdir_r

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 21:42:33 +01:00
Peter Maydell
6de4e7fdf6 Merge remote-tracking branch 'remotes/bkoppelmann/tags/pull-tricore-20141021' into staging
TriCore ABS, ABSB, B, BIT, BO instructions added

# gpg: Signature made Tue 21 Oct 2014 17:47:32 BST using RSA key ID 6B69CA14
# gpg: Good signature from "Bastian Koppelmann <kbastian@mail.uni-paderborn.de>"

* remotes/bkoppelmann/tags/pull-tricore-20141021:
  target-tricore: Add instructions of BO opcode format
  target-tricore: Add instructions of BIT opcode format
  target-tricore: Add instructions of B opcode format
  target-tricore: Add instructions of ABS, ABSB opcode format
  target-tricore: Cleanup and Bugfixes

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 18:43:35 +01:00
Peter Maydell
60b6381ffb Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20141021' into staging
add missing s390x files to MAINTAINERS

# gpg: Signature made Tue 21 Oct 2014 11:57:12 BST using RSA key ID C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"

* remotes/cohuck/tags/s390x-20141021:
  s390x: sweep up unmaintained files

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 18:41:38 +01:00
Peter Maydell
8f4699d873 Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block patches

# gpg: Signature made Mon 20 Oct 2014 13:04:09 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (28 commits)
  block: Make device model's references to BlockBackend strong
  block: Lift device model API into BlockBackend
  blockdev: Convert qmp_eject(), qmp_change_blockdev() to BlockBackend
  block/qapi: Convert qmp_query_block() to BlockBackend
  blockdev: Fix blockdev-add not to create DriveInfo
  blockdev: Drop superfluous DriveInfo member id
  pc87312: Drop unused members of PC87312State
  ide: Complete conversion from BlockDriverState to BlockBackend
  hw: Convert from BlockDriverState to BlockBackend, mostly
  virtio-blk: Rename VirtIOBlkConf variables to conf
  virtio-blk: Drop redundant VirtIOBlock member conf
  block: Rename BlockDriverCompletionFunc to BlockCompletionFunc
  block: Rename BlockDriverAIOCB* to BlockAIOCB*
  block: Eliminate DriveInfo member bdrv, use blk_by_legacy_dinfo()
  block: Merge BlockBackend and BlockDriverState name spaces
  block: Eliminate BlockDriverState member device_name[]
  block: Eliminate bdrv_iterate(), use bdrv_next()
  blockdev: Eliminate drive_del()
  block: Make BlockBackend own its BlockDriverState
  block: Code motion to get rid of stubs/blockdev.c
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 16:39:49 +01:00
Peter Maydell
895b810c12 Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20141015-2' into staging
usb: add high speed mouse & keyboard configuration

* remotes/kraxel/tags/pull-usb-20141015-2:
  xhci: remove dead code
  usb-hid: Add high speed keyboard configuration
  usb-hid: Add high speed mouse configuration
  usb-hid: Move descriptor decision to usb-hid initfn

Conflicts:
	include/hw/i386/pc.h
[Fixed trivial merge conflict in the pc-2.1 property list]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 15:48:32 +01:00
Peter Maydell
19f3772995 Merge remote-tracking branch 'remotes/spice/tags/pull-spice-20141015-1' into staging
qxl: keep going if reaching guest bug on empty area

# gpg: Signature made Wed 15 Oct 2014 11:45:37 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/spice/tags/pull-spice-20141015-1:
  qxl: keep going if reaching guest bug on empty area

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 14:49:37 +01:00
Peter Maydell
4b4ce6c2b8 Merge remote-tracking branch 'remotes/kraxel/tags/pull-gtk-20141015-1' into staging
gtk: fix memory leak, add pause key support.

# gpg: Signature made Wed 15 Oct 2014 11:30:39 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-gtk-20141015-1:
  gtk: add support for the Pause key
  gtk.c: Fix memory leak in gd_set_keycode_type()

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 14:01:42 +01:00
zhanghailiang
e668d1b854 qga: Rewrite code where using readdir_r
If readdir_r fails, error_setg_errno will reference the freed
pointer *dirpath*.

Moreover, readdir_r may cause a buffer overflow, using readdir instead.

Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
2014-10-22 07:49:52 -05:00
Peter Maydell
ad089894a8 Merge remote-tracking branch 'remotes/kraxel/tags/pull-console-20141015-1' into staging
configure: Prepend pixman and ftd flags to overrule system-provided ones

# gpg: Signature made Wed 15 Oct 2014 11:21:13 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-console-20141015-1:
  configure: Prepend pixman and ftd flags to overrule system-provided ones

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 13:08:43 +01:00
Peter Maydell
31cc9514a5 Merge remote-tracking branch 'remotes/lalrae/tags/mips-20141015' into staging
* remotes/lalrae/tags/mips-20141015: (28 commits)
  target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX
  target-mips/dsp_helper.c: Add ifdef guards around various functions
  target-mips/translate.c: Add ifdef guard around check_mips64()
  target-mips/op_helper.c: Remove unused do_lbu() function
  target-mips/dsp_helper.c: Remove unused function get_DSPControl_24()
  target-mips: fix broken MIPS16 and microMIPS
  target-mips/translate.c: Update OPC_SYNCI
  target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA
  mips_malta: update malta's pseudo-bootloader - replace JR with JALR
  target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
  target-mips: do not allow Status.FR=0 mode in 64-bit FPU
  target-mips: add new Floating Point Comparison instructions
  target-mips: add new Floating Point instructions
  softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
  target-mips: add AUI, LSA and PCREL instruction families
  target-mips: add compact and CP1 branches
  target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
  target-mips: Status.UX/SX/KX enable 32-bit address wrapping
  target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6
  target-mips: redefine Integer Multiply and Divide instructions
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-22 12:06:47 +01:00
Peter Maydell
01a2050fa5 hw/i386/pc_q35.c: Avoid g_assert_cmpint() as it is not in glib 2.12
The function g_assert_cmpint() is not in glib 2.12, which is our current
minimum requirement. Rephrase the recently added assertion to avoid it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Gonglei <arei.gonglei@huawei.com>
2014-10-22 11:32:44 +01:00
Cornelia Huck
4277af19d9 s390x: sweep up unmaintained files
Several s390x/kvm/ccw related files don't have an entry in MAINTAINERS:
Sort them into the appropriate sections.

Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
2014-10-21 12:40:34 +02:00
Markus Armbruster
84ebe3755f block: Make device model's references to BlockBackend strong
Doesn't make a difference just yet, but it's the right thing to do.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:51 +02:00
Markus Armbruster
a7f53e26a6 block: Lift device model API into BlockBackend
Move device model attachment / detachment and the BlockDevOps device
model callbacks and their wrappers from BlockDriverState to
BlockBackend.

Wrapper calls in block.c change from

    bdrv_dev_FOO_cb(bs, ...)

to

    if (bs->blk) {
        bdrv_dev_FOO_cb(bs->blk, ...);
    }

No change, because both bdrv_dev_change_media_cb() and
bdrv_dev_resize_cb() do nothing when no device model is attached, and
a device model can be attached only when bs->blk.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
6007cdd448 blockdev: Convert qmp_eject(), qmp_change_blockdev() to BlockBackend
Much more command code needs conversion.  I'm converting these now
because they're using bdrv_dev_* functions, which I'm about to lift
into BlockBackend.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
d829a2115f block/qapi: Convert qmp_query_block() to BlockBackend
Much more command code needs conversion.  I start with this one
because it's using bdrv_dev_* functions, which I'm about to lift into
BlockBackend.

While there, give bdrv_query_info() internal linkage.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
26f8b3a847 blockdev: Fix blockdev-add not to create DriveInfo
blockdev_init() always creates a DriveInfo, but only drive_new() fills
it in.  qmp_blockdev_add() leaves it blank.  This results in a drive
with type = IF_IDE, bus = 0, unit = 0.  Screwed up in commit ee13ed1c.

Board initialization code looking for IDE drive (0,0) can pick up one
of these bogus drives.  The QMP command has to execute really early to
be visible.  Not sure how likely that is in practice.

Fix by creating DriveInfo in drive_new().  Block backends created by
blockdev-add don't get one.

Breaks the test for "has been created by qmp_blockdev_add()" in
blockdev_mark_auto_del() and do_drive_del(), because it changes the
value of dinfo && !dinfo->enable_auto_del from true to false.  Simply
test !dinfo instead.

Leaves DriveInfo member enable_auto_del unused.  Drop it.

A few places assume a block backend always has a DriveInfo.  Fix them
up.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
d3aeb1b7da blockdev: Drop superfluous DriveInfo member id
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
b8864be5f3 pc87312: Drop unused members of PC87312State
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
a987ee1f1b ide: Complete conversion from BlockDriverState to BlockBackend
Add a BlockBackend member to TrimAIOCB, so ide_issue_trim_cb() can use
blk_aio_discard() instead of bdrv_aio_discard().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:03:50 +02:00
Markus Armbruster
4be746345f hw: Convert from BlockDriverState to BlockBackend, mostly
Device models should access their block backends only through the
block-backend.h API.  Convert them, and drop direct includes of
inappropriate headers.

Just four uses of BlockDriverState are left:

* The Xen paravirtual block device backend (xen_disk.c) opens images
  itself when set up via xenbus, bypassing blockdev.c.  I figure it
  should go through qmp_blockdev_add() instead.

* Device model "usb-storage" prompts for keys.  No other device model
  does, and this one probably shouldn't do it, either.

* ide_issue_trim_cb() uses bdrv_aio_discard() instead of
  blk_aio_discard() because it fishes its backend out of a BlockAIOCB,
  which has only the BlockDriverState.

* PC87312State has an unused BlockDriverState[] member.

The next two commits take care of the latter two.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:02:25 +02:00
Markus Armbruster
2a30307f70 virtio-blk: Rename VirtIOBlkConf variables to conf
This is consistent with how VirtIOFOOConf variables are named
elsewhere, and makes blk available for BlockBackend variables.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 14:02:21 +02:00
Markus Armbruster
f75167313c virtio-blk: Drop redundant VirtIOBlock member conf
Commit 12c5674 turned it into a pointer to member blk.conf.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:48:28 +02:00
Markus Armbruster
097310b53e block: Rename BlockDriverCompletionFunc to BlockCompletionFunc
I'll use it with block backends shortly, and the name is going to fit
badly there.  It's a block layer thing anyway, not just a block driver
thing.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:27 +02:00
Markus Armbruster
7c84b1b831 block: Rename BlockDriverAIOCB* to BlockAIOCB*
I'll use BlockDriverAIOCB with block backends shortly, and the name is
going to fit badly there.  It's a block layer thing anyway, not just a
block driver thing.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:27 +02:00
Markus Armbruster
fa1d36df74 block: Eliminate DriveInfo member bdrv, use blk_by_legacy_dinfo()
The patch is big, but all it really does is replacing

    dinfo->bdrv

by

    blk_bs(blk_by_legacy_dinfo(dinfo))

The replacement is repetitive, but the conversion of device models to
BlockBackend is imminent, and will shorten it to just
blk_legacy_dinfo(dinfo).

Line wrapping muddies the waters a bit.  I also omit tests whether
dinfo->bdrv is null, because it never is.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:27 +02:00
Markus Armbruster
7f06d47eff block: Merge BlockBackend and BlockDriverState name spaces
BlockBackend's name space is separate only to keep the initial patches
simple.  Time to merge the two.

Retain bdrv_find() and bdrv_get_device_name() for now, to keep this
series manageable.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
bfb197e0d9 block: Eliminate BlockDriverState member device_name[]
device_name[] can become non-empty only in bdrv_new_root() and
bdrv_move_feature_fields().  The latter is used only to undo damage
done by bdrv_swap().  The former is called only by blk_new_with_bs().
Therefore, when a BlockDriverState's device_name[] is non-empty, then
it's been created with a BlockBackend, and vice versa.  Furthermore,
blk_new_with_bs() keeps the two names equal.

Therefore, device_name[] is redundant.  Eliminate it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
fea68bb6e9 block: Eliminate bdrv_iterate(), use bdrv_next()
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
b9fe8a7a12 blockdev: Eliminate drive_del()
drive_del() has become a trivial wrapper around blk_unref().  Get rid
of it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
9ba10c95a4 block: Make BlockBackend own its BlockDriverState
On BlockBackend destruction, unref its BlockDriverState.  Replaces the
callers' unrefs.

This turns the pointer from BlockBackend to BlockDriverState into a
strong reference, managed with bdrv_ref() / bdrv_unref().  The
back-pointer remains weak.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
8fb3c76c94 block: Code motion to get rid of stubs/blockdev.c
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
18e46a033d block: Connect BlockBackend and DriveInfo
Make the BlockBackend own the DriveInfo.  Change blockdev_init() to
return the BlockBackend instead of the DriveInfo.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
7e7d56d9e0 block: Connect BlockBackend to BlockDriverState
Convenience function blk_new_with_bs() creates a BlockBackend with its
BlockDriverState.  Callers have to unref both.  The commit after next
will relieve them of the need to unref the BlockDriverState.

Complication: due to the silly way drive_del works, we need a way to
hide a BlockBackend, just like bdrv_make_anon().  To emphasize its
"special" status, give the function a suitably off-putting name:
blk_hide_on_behalf_of_do_drive_del().  Unfortunately, hiding turns the
BlockBackend's name into the empty string.  Can't avoid that without
breaking the blk->bs->device_name equals blk->name invariant.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
26f54e9a3c block: New BlockBackend
A block device consists of a frontend device model and a backend.

A block backend has a tree of block drivers doing the actual work.
The tree is managed by the block layer.

We currently use a single abstraction BlockDriverState both for tree
nodes and the backend as a whole.  Drawbacks:

* Its API includes both stuff that makes sense only at the block
  backend level (root of the tree) and stuff that's only for use
  within the block layer.  This makes the API bigger and more complex
  than necessary.  Moreover, it's not obvious which interfaces are
  meant for device models, and which really aren't.

* Since device models keep a reference to their backend, the backend
  object can't just be destroyed.  But for media change, we need to
  replace the tree.  Our solution is to make the BlockDriverState
  generic, with actual driver state in a separate object, pointed to
  by member opaque.  That lets us replace the tree by deinitializing
  and reinitializing its root.  This special need of the root makes
  the data structure awkward everywhere in the tree.

The general plan is to separate the APIs into "block backend", for use
by device models, monitor and whatever other code dealing with block
backends, and "block driver", for use by the block layer and whatever
other code (if any) dealing with trees and tree nodes.

Code dealing with block backends, device models in particular, should
become completely oblivious of BlockDriverState.  This should let us
clean up both APIs, and the tree data structures.

This commit is a first step.  It creates a minimal "block backend"
API: type BlockBackend and functions to create, destroy and find them.

BlockBackend objects are created and destroyed exactly when root
BlockDriverState objects are created and destroyed.  "Root" in the
sense of "in bdrv_states".  They're not yet used for anything; that'll
come shortly.

A root BlockDriverState is created with bdrv_new_root(), so where to
create a BlockBackend is obvious.  Where these roots get destroyed
isn't always as obvious.

It is obvious in qemu-img.c, qemu-io.c and qemu-nbd.c, and in error
paths of blockdev_init(), blk_connect().  That leaves destruction of
objects successfully created by blockdev_init() and blk_connect().

blockdev_init() is used only by drive_new() and qmp_blockdev_add().
Objects created by the latter are currently indestructible (see commit
48f364d "blockdev: Refuse to drive_del something added with
blockdev-add" and commit 2d246f0 "blockdev: Introduce
DriveInfo.enable_auto_del").  Objects created by the former get
destroyed by drive_del().

Objects created by blk_connect() get destroyed by blk_disconnect().

BlockBackend is reference-counted.  Its reference count never exceeds
one so far, but that's going to change.

In drive_del(), the BB's reference count is surely one now.  The BDS's
reference count is greater than one when something else is holding a
reference, such as a block job.  In this case, the BB is destroyed
right away, but the BDS lives on until all extra references get
dropped.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Markus Armbruster
e4e9986b1c block: Split bdrv_new_root() off bdrv_new()
Creating an anonymous BDS can't fail.  Make that obvious.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Benoît Canet <benoit.canet@nodalink.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Max Reitz
ec0de76874 nbd: Fix filename generation
Export names may be used with nbd+unix, too, fix nbd_refresh_filename()
accordingly. Also, for nbd+tcp, the documented path schema is
"nbd://host[:port]/export", so use it. Furthermore, as can be seen from
that schema, the port is optional.

That makes six single cases for how the filename can be formatted; it is
not easy to generalize these cases without the resulting statement being
completely unreadable, thus there is simply one snprintf() per case.

Finally, taking the options from BDRVNBDState::socket_opts is wrong,
because those will not contain the export name. Just use
BlockDriverState::options instead.

Reported-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Tony Breeds
7c15903789 block/raw-posix: use seek_hole ahead of fiemap
try_fiemap() uses FIEMAP_FLAG_SYNC which has a significant performance
impact.

Prefer seek_hole() over fiemap() to avoid this impact where possible.
seek_hole is more widely used and, arguably, has potential to be
optimised in the kernel.

Reported-By: Michael Steffens <michael_steffens@posteo.de>
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Pádraig Brady <pbrady@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Tony Breeds
38c4d0aea3 block/raw-posix: Fix disk corruption in try_fiemap
Using fiemap without FIEMAP_FLAG_SYNC is a known corrupter.

Add the FIEMAP_FLAG_SYNC flag to the FS_IOC_FIEMAP ioctl.  This has
the downside of significantly reducing performance.

Reported-By: Michael Steffens <michael_steffens@posteo.de>
Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Pádraig Brady <pbrady@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Zhang Haoyu
d8bb71b622 qcow2: fix leak of Qcow2DiscardRegion in update_refcount_discard
When the Qcow2DiscardRegion is adjacent to another one referenced by "d",
free this Qcow2DiscardRegion metadata referenced by "p" after
it was removed from s->discards queue.

Signed-off-by: Zhang Haoyu <zhanghy@sangfor.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2014-10-20 13:41:26 +02:00
Bastian Koppelmann
3a16ecb063 target-tricore: Add instructions of BO opcode format
Add instructions of BO opcode format.
Add microcode generator functions gen_swap, gen_ldmst.
Add microcode generator functions gen_st/ld_preincr, which write back the address after the memory access.
Add helper for circular and bit reverse addr mode calculation.
Add sign extended bitmask for BO_OFF10 field.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
2014-10-20 12:25:07 +01:00
Bastian Koppelmann
b74f2b5bb3 target-tricore: Add instructions of BIT opcode format
Add instructions of BIT opcode format.
Add microcode generator functions gen_bit_1/2op to do 1/2 bit operations on the last bit.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
2014-10-20 12:25:07 +01:00
Bastian Koppelmann
f718b0bbfa target-tricore: Add instructions of B opcode format
Add instructions of B opcode format.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
2014-10-20 12:25:07 +01:00
Bastian Koppelmann
59543d4ee1 target-tricore: Add instructions of ABS, ABSB opcode format
Add instructions of ABS, ABSB opcode format.
Add microcode generator functions for ld/st of two 32bit reg as one 64bit value.
Add microcode generator functions for ldmst and swap.
Add helper ldlcx, lducx, stlcx and stucx.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
2014-10-20 12:25:07 +01:00
Bastian Koppelmann
030c58dfb7 target-tricore: Cleanup and Bugfixes
Move FCX loading of save_context_ to caller functions, for STLCX, STUCX insn to use those functions.
Move FCX storing of restore_context_ to caller functions, for LDLCX, LDUCX insn to use those functions.
Remove do_raise_exception function, which caused clang to emit a warning.
Fix: save_context_lower now saves a[11] instead of PSW.
Fix: MASK_OP_ABSB_BPOS starting at wrong offset.

Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
2014-10-20 12:25:06 +01:00
Gonglei
5f77ef69a1 glib: add compatibility interface for g_strcmp0()
This patch fixes compilation errors when building against glib < 2.16.0
due to the missing g_strcmp0() function.

Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Message-id: 1413457177-10132-1-git-send-email-arei.gonglei@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-16 23:02:31 +01:00
Peter Maydell
8a2c263624 Merge remote-tracking branch 'remotes/kraxel/tags/pull-vga-20141015-1' into staging
vga-pci: add qext region to mmio
vga: Remove unused arrays dmask4 and dmask16

# gpg: Signature made Wed 15 Oct 2014 10:12:06 BST using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-vga-20141015-1:
  hw/display/vga: Remove unused arrays dmask4 and dmask16
  vga-pci: add qext region to mmio

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-16 09:26:14 +01:00
Peter Maydell
605c690b1b Merge remote-tracking branch 'remotes/kraxel/tags/pull-bootindex-20141015-1' into staging
allow changing bootorder via monitor at runtime,
by making bootindex a writable qom property.

* remotes/kraxel/tags/pull-bootindex-20141015-1: (34 commits)
  bootindex: change fprintf to error_report
  bootindex: delete bootindex when device is removed
  bootindex: move calling add_boot_device_patch to bootindex setter function
  ide: add calling add_boot_device_patch in bootindex setter function
  nvma: ide: add bootindex to qom property
  usb-storage: add bootindex to qom property
  virtio-blk: alias bootindex property explicitly for virt-blk-pci/ccw/s390
  block: remove bootindex property from qdev to qom
  virtio-blk: add bootindex to qom property
  ide: add bootindex to qom property
  scsi: add bootindex to qom property
  isa-fdc: remove bootindexA/B property from qdev to qom
  redirect: remove bootindex property from qdev to qom
  vfio: remove bootindex property from qdev to qom
  pci-assign: remove bootindex property from qdev to qom
  host-libusb: remove bootindex property from qdev to qom
  virtio-net: alias bootindex property explicitly for virt-net-pci/ccw/s390
  net: remove bootindex property from qdev to qom
  usb-net: add bootindex to qom property
  vmxnet3: add bootindex to qom property
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-16 09:24:45 +01:00
Stefan Hajnoczi
89b516d8b9 glib: add compatibility interface for g_get_monotonic_time()
This patch fixes compilation errors when building against glib <2.28.0
due to the missing g_get_monotonic_time() function.

The compilation error in tests/libqos/virtio.c was introduced in commit
70556264a8 ("libqos: use microseconds
instead of iterations for virtio timeout").

Add a simple g_get_monotonic_time() implementation to glib-compat.h
based on code from vhost-user-test.c.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
[Igor: add G_TIME_SPAN_SECOND, include glib-compat.h in libqtest.h]
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-15 13:43:35 +01:00
Gerd Hoffmann
ac20e1bb0e xhci: remove dead code
Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 13:39:48 +02:00
Jan Vesely
b13ce07688 usb-hid: Add high speed keyboard configuration
Signed-off-by: Jan Vesely <jano.vesely@gmail.com>

[ kraxel: fixup compat property to apply to 2.1 & older ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 13:39:22 +02:00
Jan Vesely
58e4fee24a usb-hid: Add high speed mouse configuration
Signed-off-by: Jan Vesely <jano.vesely@gmail.com>

[ kraxel: fixup compat property to apply to 2.1 & older ]

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 13:38:09 +02:00
Peter Maydell
32d9c5613e Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20141015' into staging
migration/next for 20141015

# gpg: Signature made Wed 15 Oct 2014 09:21:54 BST using RSA key ID 5872D723
# gpg: Can't check signature: public key not found

* remotes/juanquintela/tags/migration/20141015:
  migration: catch unknown flag combinations in ram_load
  qemu-file: Move stdio implementation to qemu-file-stdio.c
  qemu-file: Move unix and socket implementations to qemu-file-unix.c
  qemu-file: Use qemu_file_is_writable() on stdio_fclose()
  qemu-file: Make qemu_file_is_writable() non-static
  qemu-file: Add copyright header to qemu-file.c
  vmstate: Allow dynamic allocation for VBUFFER during migration
  block/migration: Disable cache invalidate for incoming migration
  Tests: QEMUSizedBuffer/QEMUBuffer
  QEMUSizedBuffer based QEMUFile

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-15 11:55:54 +01:00
Jan Kiszka
50e1206069 configure: Prepend pixman and ftd flags to overrule system-provided ones
Other packages may provide includes for pixman as well if the host has a
devel package installed. So add ours to the front to unsure that the
right version is used.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 12:20:27 +02:00
Peter Maydell
9879232543 hw/display/vga: Remove unused arrays dmask4 and dmask16
Following cleanup of the vga device code in commit d2e043a804,
the arrays dmask4 and dmask16 are now unused. gcc doesn't warn
about this, but clang does; remove them.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 11:10:50 +02:00
Gerd Hoffmann
b5682aa4ca vga-pci: add qext region to mmio
Add a qemu extented register range to the standard vga mmio bar.
Right nowe there are two registers:  One readonly register returning the
size of the region (so we can easily add more registers there if needed)
and one endian control register, so guests (especially ppc) can flip
the framebuffer endianness as they need it.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
2014-10-15 11:08:35 +02:00
Marc-André Lureau
9e5a25f1c2 qxl: keep going if reaching guest bug on empty area
Xorg server hangs when using xfig and typing a text with space:
 #0  qxl_wait_for_io_command (qxl=<value optimized out>) at qxl_io.c:47
 #1  0x00007f826a49a299 in qxl_download_box (surface=0x221d030, x1=231, y1=259,
     x2=<value optimized out>, y2=<value optimized out>) at qxl_surface.c:143

       while (!(ram_header->int_pending & QXL_INTERRUPT_IO_CMD))
         usleep (1);

The QXL driver is calling QXL_IO_UPDATE_AREA with an empty area. This
is a guest bug. The call is async and no ack is sent back on guest
bug, so the X server will hang. The driver should be improved to avoid
this situation and also to abort on QXL_INTERRUPT_ERROR. This will be
a different patch series for the driver. However, it is simple enough
to keep qemu running on empty areas update, which is what this patch
provides.

https://bugzilla.redhat.com/show_bug.cgi?id=1151363

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 11:08:34 +02:00
Jan Vesely
ff326ffaeb usb-hid: Move descriptor decision to usb-hid initfn
Signed-off-by: Jan Vesely <jano.vesely@gmail.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 11:08:34 +02:00
Martin Decky
5c960521b8 gtk: add support for the Pause key
Special handing of the Pause key. Implemented in a similar way as in
ui/sdl.c.

Signed-off-by: Martin Decky <martin@decky.cz>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 11:08:32 +02:00
Chen Fan
84961407a5 gtk.c: Fix memory leak in gd_set_keycode_type()
this memory leak is introduced by the original
 commit 3158a3482b

 valgrind out showing:
 ==14553== 21,459 (72 direct, 21,387 indirect) bytes in 1 blocks are definitely
 lost in loss record 8,055 of 8,082
 ==14553==    at 0x4A06BC3: calloc (vg_replace_malloc.c:618)
 ==14553==    by 0x80DBFBC: XkbGetKeyboardByName (in /usr/lib64/libX11.so.6.3.0)
 ==14553==    by 0x40C704: gtk_display_init (gtk.c:1798)
 ==14553==    by 0x1AEDC1: main (vl.c:4480)

Signed-off-by: Chen Fan <chen.fan.fnst@cn.fujitsu.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-10-15 11:08:32 +02:00
Peter Maydell
88e6599669 Merge remote-tracking branch 'remotes/afaerber/tags/qom-devices-for-peter' into staging
QOM infrastructure fixes and device conversions

* GPIO conversion to QOM, continued
* Device property description support
* QTest cases for hotplug
* Hotplug handler conversion

# gpg: Signature made Wed 15 Oct 2014 04:05:17 BST using RSA key ID 3E7E013F
# gpg: Good signature from "Andreas Färber <afaerber@suse.de>"
# gpg:                 aka "Andreas Färber <afaerber@suse.com>"

* remotes/afaerber/tags/qom-devices-for-peter: (47 commits)
  qdev: Drop legacy_name from qdev properties
  qmp: Print descriptions of object properties
  qdev: Set the object property's description to the qdev property's.
  qom: Add description field in ObjectProperty struct
  qdev: Add description field in PropertyInfo struct
  qdev: device_del: Search for to be unplugged device in 'peripheral' container
  qdev: HotplugHandler: Add support for unplugging BUS-less devices
  qdev: Drop legacy hotplug fields/methods
  usb: Convert usb devices to hotplug handler API
  usb: Convert usb-ccid to hotplug handler API
  usb-storage: Drop not needed "allow_hotplug = 0"
  usb-bot: Drop not needed "allow_hotplug = 0"
  usb-bot: Mark device as non hotpluggable
  scsi: Cleanup not used anymore SCSIBusInfo{hotplug, hot_unplug} fields
  scsi: Convert virtio-scsi HBA to hotplug handler API
  scsi: Convert pvscsi HBA to hotplug handler API
  scsi: Set SCSI BUS itself as default HotplugHandler
  s390x: Convert virtio-ccw to hotplug handler API
  s390x: Convert s390-virtio to hotplug handler API
  s390x: Drop not used allow_hotplug in event-facility
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-10-15 08:12:53 +01:00
Gonglei
18b91a3e08 qdev: Drop legacy_name from qdev properties
The legacy_name is useless now, better help
information is provided by description field of property.

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Gonglei
07d09c58db qmp: Print descriptions of object properties
Add a new "description" field to DevicePropertyInfo.
The descriptions can serve as documentation in the code,
and they can be used to provide better help. For example:

$./qemu-system-x86_64 -device virtio-blk-pci,?

Before this patch:

virtio-blk-pci.iothread=link<iothread>
virtio-blk-pci.x-data-plane=bool
virtio-blk-pci.scsi=bool
virtio-blk-pci.config-wce=bool
virtio-blk-pci.serial=str
virtio-blk-pci.secs=uint32
virtio-blk-pci.heads=uint32
virtio-blk-pci.cyls=uint32
virtio-blk-pci.discard_granularity=uint32
virtio-blk-pci.bootindex=int32
virtio-blk-pci.opt_io_size=uint32
virtio-blk-pci.min_io_size=uint16
virtio-blk-pci.physical_block_size=uint16
virtio-blk-pci.logical_block_size=uint16
virtio-blk-pci.drive=str
virtio-blk-pci.virtio-backend=child<virtio-blk-device>
virtio-blk-pci.command_serr_enable=on/off
virtio-blk-pci.multifunction=on/off
virtio-blk-pci.rombar=uint32
virtio-blk-pci.romfile=str
virtio-blk-pci.addr=pci-devfn
virtio-blk-pci.event_idx=on/off
virtio-blk-pci.indirect_desc=on/off
virtio-blk-pci.vectors=uint32
virtio-blk-pci.ioeventfd=on/off
virtio-blk-pci.class=uint32

After:

virtio-blk-pci.iothread=link<iothread>
virtio-blk-pci.x-data-plane=bool (on/off)
virtio-blk-pci.scsi=bool (on/off)
virtio-blk-pci.config-wce=bool (on/off)
virtio-blk-pci.serial=str
virtio-blk-pci.secs=uint32
virtio-blk-pci.heads=uint32
virtio-blk-pci.cyls=uint32
virtio-blk-pci.discard_granularity=uint32
virtio-blk-pci.bootindex=int32
virtio-blk-pci.opt_io_size=uint32
virtio-blk-pci.min_io_size=uint16
virtio-blk-pci.physical_block_size=uint16 (A power of two between 512 and 32768)
virtio-blk-pci.logical_block_size=uint16 (A power of two between 512 and 32768)
virtio-blk-pci.drive=str (ID of a drive to use as a backend)
virtio-blk-pci.virtio-backend=child<virtio-blk-device>
virtio-blk-pci.command_serr_enable=bool (on/off)
virtio-blk-pci.multifunction=bool (on/off)
virtio-blk-pci.rombar=uint32
virtio-blk-pci.romfile=str
virtio-blk-pci.addr=int32 (Slot and optional function number, example: 06.0 or 06)
virtio-blk-pci.event_idx=bool (on/off)
virtio-blk-pci.indirect_desc=bool (on/off)
virtio-blk-pci.vectors=uint32
virtio-blk-pci.ioeventfd=bool (on/off)
virtio-blk-pci.class=uint32

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Gonglei
b8c9cd5c8c qdev: Set the object property's description to the qdev property's.
Set all static qdev properties' descriptions to object property's
description.

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Gonglei
8074264203 qom: Add description field in ObjectProperty struct
The descriptions can serve as documentation in the code,
and they can be used to provide better help.

Copy property descriptions when copying alias properties.

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Gonglei
51b2e8c331 qdev: Add description field in PropertyInfo struct
The descriptions can serve as documentation in the code,
and they can be used to provide better help.

Cc: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Igor Mammedov
b6cc36abb2 qdev: device_del: Search for to be unplugged device in 'peripheral' container
device_add puts every device with 'id' inside of 'peripheral'
container using id's value as the last component name.
Use it by replacing recursive search on sysbus with path
lookup in 'peripheral' container, which could handle both
BUS and BUS-less device cases.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:15 +02:00
Igor Mammedov
7716b8ca74 qdev: HotplugHandler: Add support for unplugging BUS-less devices
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
2d9a982f37 qdev: Drop legacy hotplug fields/methods
It removes not needed anymore BusState::allow_hotplug field and
DeviceClass::unplug callback.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
5f4d917376 usb: Convert usb devices to hotplug handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
138d587afb usb: Convert usb-ccid to hotplug handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
77de4a09c6 usb-storage: Drop not needed "allow_hotplug = 0"
Drop useless hack that disables hotplug on bus, after backend
storage was added to it, by setting "allow_hotplug = 0". Even
if bus is hotpluggable, it won't be possible to add another
SCSI device to bus since its realize will fail early with
error "no free target" in scsi_qdev_realize() method.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
af01492755 usb-bot: Drop not needed "allow_hotplug = 0"
Drop useless hack that disables hotplug on bus by setting
"allow_hotplug = 0". Even if bus is hotpluggable, It won't
be possible to add another SCSI device to bus since its
realization will fail early with error "no free target"
in scsi_qdev_realize() method.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
e9fd12aa0d usb-bot: Mark device as non hotpluggable
usb-bot creates SCSI bus and immediately makes it
non hotpluggable which was making not possible to
hotplug usb-bot since QEMU would abort at
bus_add_child(scsi-hd) time when usb-bot is
realized.

Mark usb-bot as not hotpluggable so that attempt
to hotplug it would error out even before it gets
to device initialization point.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
10bdcd5659 scsi: Cleanup not used anymore SCSIBusInfo{hotplug, hot_unplug} fields
SCSI subsytem was converted to hotplug handler API and
doesn't use SCSIBusInfo{hotplug, hot_unplug} fields and
related callbacks anymore.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
02206e5275 scsi: Convert virtio-scsi HBA to hotplug handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
91c8daad4b scsi: Convert pvscsi HBA to hotplug handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
bddd763a4e scsi: Set SCSI BUS itself as default HotplugHandler
That would allow to handle SCSI device unplug
on HBAs without dedicated hot(un)plug handlers
and avoid making such HBAs explicitly hotpluggable.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
277bc95ed3 s390x: Convert virtio-ccw to hotplug handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
e98f8c3622 s390x: Convert s390-virtio to hotplug handler API
Beside of conversion, patch drops present unplug
handling, effectively disabling hot-unplug of
s390-virtio devices.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:14 +02:00
Igor Mammedov
492bcf8f71 s390x: Drop not used allow_hotplug in event-facility
s390-sclp-event-facility creates s390-sclp-events-bus
and immediately sets its allow_hotplug field to 0,
which is NOP since it's already 0 by default.

Also since BUS is not hotpluggable, it's not possible
to call SCLP_EVENT{ DeviceClass::unplug } callback
from qdev_unplug() making this unreachable code,
so drop it as well.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
2f4f603517 virtio-mmio: Drop useless bus->allow_hotplug = 0
Bus by default is not hotpluggable.
virtio-mmio-bus and its parent types do not set allow_hotplug
anywhere explicitly, so remove not needed field access
and wrapper along with it.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
0ddef15b04 virtio-serial: Convert to hotplug-handler API
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
7f17a91715 virtio-pci: Drop BusState::allow_hotplug
virtio-pci-bus is an internal object of composite
virtio-pci device and it doesn't participate in
-device/device_add hotplug flow, and since it's
not required by bus_add_child() that BUS must
be hotpluggable to be able to add child at runtime,
it's possible to drop not needed 'allow_hotplug'
field.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
c32e36f6ab target-i386: ICC bus: Drop BusState::allow_hotplug
Since bus_add_child() no longer cares if BUS is hotpluggable
or not, there is no need in setting allow_hotplug field.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
e378acb404 qdev: Drop hotplug check from bus_add_child()
Check is too restrictive and does not allow
to add children to just created bus during hotplug
when the bus is part of composite device.

Removing check from bus_add_child() doesn't affect
devices creatable with device_add/del commands since
they have a similar builtin check and patch will
allow to create complex composite devices during
hotplug.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
431bbb26cb qdev: Add wrapper to set BUS as HotplugHandler
To be used for conversion of SCSI and USB devices,
and would allow to make every HBA/USB host switch
to HotplugHandler API without touching each controller
explicitly.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
014176f914 qdev: Add simple/generic unplug callback for HotplugHandler
It will be used in shallow conversion from legacy hotplug
mechanism and eventually replace all the uses of old mechanism
DeviceClass::unplug = qdev_simple_unplug_cb()

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
181a2c6323 qdev: HotplugHandler: Provide unplug callback
It is to be called for actual device removal and
will allow to separate request and removal handling
phases of x86-CPU devices and also it's a handler
to be called for synchronously removable devices.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
14d5a28fb6 qdev: HotplugHandler: Rename unplug callback to unplug_request
'HotplugHandler.unplug' callback is currently used as async
call to issue unplug request for device that implements it.
Renaming 'unplug' callback to 'unplug_request' should help to
avoid confusion about what callback does and would allow to
introduce 'unplug' callback that would perform actual device
removal when guest is ready for it.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
ce9835e00d qdev: do not allow to instantiate non hotpluggable device with device_add
It will allow explicitly mark device as not hotpluggable and
avoid its creation with following error at realize time
and destroying it afterwards anyway. Instead of it will
error out even before instance of device is created.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
39b888bd88 Access BusState::allow_hotplug using wraper qbus_is_hotpluggable()
It would allow to transparently switch detection whether Bus
is hotpluggable from allow_hotplug field to hotplug_handler
link and to drop allow_hotplug field once all users are
converted to hotplug handler API.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
49cec38591 tests: usb: usb-uas hotplug test
checks that it's possible to hotplug usb-uas HBA and
then if it's possible to hot(un)plug scsi-disk to it.
Thest basically covers hot(un)plug on dummy HBAs
without means of hot(un)plug notification of the guest.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
b6ca82feed tests: usb: usb-storage hotplug test
usb-storage is different from usual usb devices
in that it uses a child SCSI bus for underlying storage.
This commit verifies that the SCSI bus is hotpluggable, as
hotplug operation wouldn't succeed without it.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
b393768314 tests: usb: Generic usb device hotplug
use usb-tablet as a hotplugged usb device.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:13 +02:00
Igor Mammedov
fbd942c993 tests: usb: add port test to uhci unit test
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
b0354ec596 tests: usb: Move uhci port test code to libqos/usb.c
Move code necessary for testing uhci port into library
so it could be used by other USB tests.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
aaf3607051 tests: virtio-blk: Check if hot-plug/unplug works
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
9224709b7b tests: virtio-net: Check if hot-plug/unplug works
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
d1f3fc24f8 tests: virtio-rng: Check if hot-plug/unplug works
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
2f8b276720 libqos: Add qpci_plug_device_test() and qpci_unplug_acpi_device_test()
Functions will be used for testing hot(un)plug of PCI devices.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
823a9987c9 tests: virtio-serial: Check if hot-plug/unplug works
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Igor Mammedov
ac2c4946cc tests: virtio-scsi: Check if hot-plug/unplug works
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:12 +02:00
Gonglei
8ae9a9ef4e qom: Add error handler for object alias property
object_property_add_alias() is called at some
places at present. And its parameter errp may not NULL,
such as
 object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread",
                              &error_abort);
This patch add error handler for security.

Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:03:04 +02:00
Gonglei
3a53009fa0 qom: Add error handler for object_property_print()
Avoid the caller of object_property_print() leaking string
argument's memory, such as qdev_print_props() when
encounter errors.

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-15 05:02:55 +02:00
Peter Maydell
340fff722d target-mips: Remove unused gen_load_ACX, gen_store_ACX and cpu_ACX
Remove the functions gen_load_ACX and gen_store_ACX, which appear to have
been unused since they were first introduced many years ago. These functions
were the only places using the cpu_ACX[] array of TCG globals, so remove
that and its accompanying regnames_ACX[] as well.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:15 +01:00
Peter Maydell
31efecccce target-mips/dsp_helper.c: Add ifdef guards around various functions
Add ifdef TARGET_MIPS64 guards around various functions that are only
called from helpers for TARGET_MIPS64 CPUs; this avoids compiler
warnings when building other configs.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Peter Maydell
c7986fd6cd target-mips/translate.c: Add ifdef guard around check_mips64()
The function check_mips64() is only used if TARGET_MIPS64 is defined;
add an ifdef guard to its definition to avoid warnings about it being
unused in other configurations.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Peter Maydell
b808a1a812 target-mips/op_helper.c: Remove unused do_lbu() function
The do_lbu() function defined by the expansion of HELPER_LD() is
never used, so don't define it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Peter Maydell
3414e93eb7 target-mips/dsp_helper.c: Remove unused function get_DSPControl_24()
The function get_DSPControl_24() is unused; remove it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Yongbok Kim
b231c103af target-mips: fix broken MIPS16 and microMIPS
Commit 240ce26a broke MIPS16 and microMIPS support as it didn't
care those branches and jumps don't have delay slot in
MIPS16 and microMIPS.

This patch introduces a new argument delayslot_size to the
gen_compute_branch() indicating size of delay slot {0, 2, 4}.
And the information is used to call handle_delay_slot() forcingly
when no delay slot is required.

There are some microMIPS branch and jump instructions that requires
exact size of instruction in the delay slot. For indicating
these instructions, MIPS_HFLAG_BDS_STRICT flag is introduced.

Those fictional branch opcodes defined to support MIPS16 and
microMIPS are no longer needed.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Tested-by: Jonas Gorski <jogo@openwrt.org>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
[leon.alrae@imgtec.com: cosmetic changes]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Dongxue Zhang
a83bddd60d target-mips/translate.c: Update OPC_SYNCI
Update OPC_SYNCI with BS_STOP, in order to handle the instructions which saved
in the same TB of the store instruction.

Signed-off-by: Dongxue Zhang <elta.era@gmail.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
[leon.alrae@imgtec.com: update microMIPS SYNCI as well]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-14 13:29:14 +01:00
Leon Alrae
a773cc7970 target-mips: define a new generic CPU supporting MIPS64 Release 6 ISA
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
2014-10-14 13:28:52 +01:00
Leon Alrae
9fba150042 mips_malta: update malta's pseudo-bootloader - replace JR with JALR
JR has been removed in R6 and now this instruction will cause Reserved
Instruction Exception. Therefore use JALR with rd=0 which is equivalent to JR.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-14 13:28:52 +01:00
Yongbok Kim
0aefa33318 target-mips: remove JR, BLTZAL, BGEZAL and add NAL, BAL instructions
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-14 13:28:52 +01:00
Leon Alrae
ddc584bdb5 target-mips: do not allow Status.FR=0 mode in 64-bit FPU
Status.FR bit must be ignored on write and read as 1 when an implementation of
Release 6 of the Architecture in which a 64-bit floating point unit is
implemented.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
2014-10-14 13:28:52 +01:00
Yongbok Kim
3f4938833c target-mips: add new Floating Point Comparison instructions
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-14 13:28:52 +01:00
Leon Alrae
e7f16abbc5 target-mips: add new Floating Point instructions
In terms of encoding MIPS32R6 MIN.fmt, MAX.fmt, MINA.fmt, MAXA.fmt replaced
MIPS-3D RECIP1, RECIP2, RSQRT1, RSQRT2 instructions.

In R6 all Floating Point instructions are supposed to be IEEE-2008 compliant
i.e. FIR.HAS2008 always 1. However, QEMU softfloat for MIPS has not been
updated yet.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
2014-10-14 13:28:51 +01:00
Leon Alrae
2d31e0607d softfloat: add functions corresponding to IEEE-2008 min/maxNumMag
Add abs argument to the existing softfloat minmax() function and define
new float{32,64}_{min,max}nummag functions.

minnummag(x,y) returns x if |x| < |y|,
               returns y if |y| < |x|,
               otherwise minnum(x,y)

maxnummag(x,y) returns x if |x| > |y|,
               returns y if |y| > |x|,
               otherwise maxnum(x,y)

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-14 13:28:51 +01:00
Leon Alrae
d4ea6acdf6 target-mips: add AUI, LSA and PCREL instruction families
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Yongbok Kim <yongbok.kim@imgtec.com>
2014-10-14 13:26:54 +01:00
Peter Lieven
5b0e9dd46f migration: catch unknown flag combinations in ram_load
this patch extends commit db80fac by not only checking
for unknown flags, but also filtering out unknown flag
combinations.

Suggested-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Peter Lieven <pl@kamp.de>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 11:24:20 +02:00
Eduardo Habkost
c54d1c0670 qemu-file: Move stdio implementation to qemu-file-stdio.c
Separate the QEMUFile interface from the stdio-specific implementation,
to reduce dependencies from code using QEMUFile.

The code that is being moved is similar to the one that was on savevm.c before
it was moved in commit 093c455a8c, except for
some changes done by Markus, Juan, and myself. So, I am using the copyright and
license header from savevm.c, but CCing Juan and Markus so they can review the
copyright/license header.

Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 10:29:28 +02:00
Eduardo Habkost
bee223ba27 qemu-file: Move unix and socket implementations to qemu-file-unix.c
Separate the QEMUFile interface from the implementation, to reduce
dependencies from code using QEMUFile.

All the code that is being moved to the new file is exactly the same
code that was on savevm.c (moved by commit
093c455a8c), so I am using the copyright
and license header from savevm.c for the new file.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 10:29:28 +02:00
Eduardo Habkost
532bc727c3 qemu-file: Use qemu_file_is_writable() on stdio_fclose()
Use the existing function which checks if writev_buffer() or
put_buffer() are set, instead of duplicating it.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 10:28:12 +02:00
Eduardo Habkost
e68dd36596 qemu-file: Make qemu_file_is_writable() non-static
The QEMUFileStdio code will use qemu_file_is_writable() and will be
moved to a separate file.

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 10:28:12 +02:00
Eduardo Habkost
9a4ac51f72 qemu-file: Add copyright header to qemu-file.c
The person who created qemu-file.c (me, on commit
093c455a8c) didn't add a copyright/license
header to the file, even though the whole code was copied from savevm.c
(which had a copyright/license header).

To correct this, copy the copyright information and license from
savevm.c, that's where the original code came from.

Luckily, very few changes were made on qemu-file.c after it was created.
All the authors who touched the code are being CCed, so they can confirm
if they are OK with the copyright/license information being added.

Cc: Dr. David Alan Gilbert <dgilbert@redhat.com>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Juan Quintela <quintela@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 10:16:38 +02:00
Alexey Kardashevskiy
94ed706d53 vmstate: Allow dynamic allocation for VBUFFER during migration
This extends use of VMS_ALLOC flag from arrays to VBUFFER as well.

This defines VMSTATE_VBUFFER_ALLOC_UINT32 which makes use of VMS_ALLOC
and uses uint32_t type for a size.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 09:35:48 +02:00
Alexey Kardashevskiy
7ea2d269cb block/migration: Disable cache invalidate for incoming migration
When migrated using libvirt with "--copy-storage-all", at the end of
migration there is race between NBD mirroring task trying to do flush
and migration completion, both end up invalidating cache. Since qcow2
driver does not handle this situation very well, random crashes happen.

This disables the BDRV_O_INCOMING flag for the block device being migrated
once the cache has been invalidated.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

--

fixed parens by hand
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 09:35:21 +02:00
Dr. David Alan Gilbert
9935baca9b Tests: QEMUSizedBuffer/QEMUBuffer
Modify some of tests/test-vmstate.c to use the in memory file based
on QEMUSizedBuffer to provide basic testing of QEMUSizedBuffer and
the associated memory backed QEMUFile type.

Only some of the tests are changed so that the fd backed QEMUFile is
still tested.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 09:17:06 +02:00
Dr. David Alan Gilbert
deb22f9a44 QEMUSizedBuffer based QEMUFile
This is based on Stefan and Joel's patch that creates a QEMUFile that goes
to a memory buffer; from:

http://lists.gnu.org/archive/html/qemu-devel/2013-03/msg05036.html

Using the QEMUFile interface, this patch adds support functions for
operating on in-memory sized buffers that can be written to or read from.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Joel Schopp <jschopp@linux.vnet.ibm.com>

For fixes/tweeks I've done:
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
2014-10-14 09:17:06 +02:00
Peter Crosthwaite
688b057aec qdev: gpio: Register GPIO outputs as QOM links
Within the object that contains the GPIO output. This allows for
connecting GPIO outputs via setting of a Link property.

Also clear the link value to zero. This catch-alls the case
where a device improperly inits a gpio_out (malloc instead of
malloc0).

Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-13 16:39:27 +02:00
Peter Crosthwaite
a69bef1cf1 qdev: gpio: Register GPIO inputs as child objects
To the device that contains them. This will allow for referencing
a GPIO input from it's canonical path (exciting for dynamic machine
generation!)

Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-13 16:39:26 +02:00
Peter Crosthwaite
b235a71f52 qdev: gpio: Don't allow name share between I and O
Only allow a GPIO name to be one or the other. Inputs and outputs are
functionally different and should be in different namespaces. Prepares
support for the QOMification of IRQs as Links or Child objects.

The alternative is to munge names .e.g. with "-in" or "-out" suffixes
when giving QOM names. But that reduces clarity and if there are cases
out there where users want I and O with same name they can manually add
their own suffixes.

Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
2014-10-13 16:39:26 +02:00
Yongbok Kim
31837be3ee target-mips: add compact and CP1 branches
Introduce MIPS32R6 Compact Branch instructions which do not have delay slot -
they have forbidden slot instead. However, current implementation does not
support forbidden slot yet.

Add also BC1EQZ and BC1NEZ instructions.

Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
2014-10-13 12:38:25 +01:00
Yongbok Kim
15eacb9b52 target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions
Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com>
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:25 +01:00
Leon Alrae
01f7288579 target-mips: Status.UX/SX/KX enable 32-bit address wrapping
In R6 the special behaviour for data references is also specified for Kernel
and Supervisor mode. Therefore MIPS_HFLAG_UX is replaced by generic
MIPS_HFLAG_AWRAP indicating enabled 32-bit address wrapping.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:25 +01:00
Leon Alrae
4267d3e6e0 target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6
Also consider OPC_SPIM instruction as deleted in R6 because it is overlaping
with MIPS32R6 SDBBP.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:25 +01:00
Leon Alrae
b42ee5e1d9 target-mips: redefine Integer Multiply and Divide instructions
Use "R6_" prefix in front of all new Multiply / Divide instructions for
easier differentiation between R6 and preR6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
bf7910c6b1 target-mips: move PREF, CACHE, LLD and SCD instructions
The encoding of PREF, CACHE, LLD and SCD instruction changed in MIPS32R6.
Additionally, the hint codes in PREF instruction greater than or
equal to 24 generate Reserved Instruction Exception.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
fac5a07330 target-mips: signal RI Exception on DSP and Loongson instructions
Move DSP and Loongson instruction to *_legacy functions as they have been
removed in R6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
10dc65dbb8 target-mips: split decode_opc_special* into *_r6 and *_legacy
For better code readability and to avoid 'if' statements for all R6 and preR6
instructions whose opcodes are the same - decode_opc_special* functions are
split into functions with _r6 and _legacy suffixes.

*_r6 functions will contain instructions which were introduced in R6.
*_legacy functions will contain instructions which were removed in R6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
099e5b4d9f target-mips: extract decode_opc_special* from decode_opc
Creating separate decode functions for special, special2 and special3
instructions to ease adding new R6 instructions and removing legacy
instructions.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
4368b29a26 target-mips: move LL and SC instructions
The encoding of LL and SC instruction has changed in MIPS32 Release 6.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: James Hogan <james.hogan@imgtec.com>
2014-10-13 12:38:24 +01:00
Leon Alrae
b691d9d2a0 target-mips: add SELEQZ and SELNEZ instructions
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
Reviewed-by: James Hogan <james.hogan@imgtec.com>
2014-10-13 12:38:24 +01:00
Leon Alrae
fecd264695 target-mips: signal RI Exception on instructions removed in R6
Signal Reserved Instruction Exception on instructions that do not exist in R6.
In this commit the following groups of preR6 instructions are marked as deleted:
- Floating Point Paired Single
- Floating Point Compare
- conditional moves / branches on FPU conditions
- branch likelies
- unaligned loads / stores
- traps
- legacy accumulator instructions
- COP1X
- MIPS-3D

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
Leon Alrae
fa0d2f69e7 target-mips: define ISA_MIPS64R6
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
2014-10-13 12:38:24 +01:00
317 changed files with 12268 additions and 4867 deletions

View File

@@ -51,6 +51,7 @@ Descriptions of section entries:
General Project Administration
------------------------------
M: Anthony Liguori <aliguori@amazon.com>
M: Peter Maydell <peter.maydell@linaro.org>
Responsible Disclosure, Reporting Security Issues
------------------------------
@@ -100,7 +101,8 @@ F: hw/microblaze/
MIPS
M: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes
M: Leon Alrae <leon.alrae@imgtec.com>
S: Maintained
F: target-mips/
F: hw/mips/
@@ -198,7 +200,9 @@ M: Cornelia Huck <cornelia.huck@de.ibm.com>
M: Alexander Graf <agraf@suse.de>
S: Maintained
F: target-s390x/kvm.c
F: hw/intc/s390_flic.[hc]
F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h
X86
M: Marcelo Tosatti <mtosatti@redhat.com>
@@ -521,6 +525,8 @@ F: hw/s390x/s390-virtio-ccw.c
F: hw/s390x/css.[hc]
F: hw/s390x/sclp*.[hc]
F: hw/s390x/ipl*.[hc]
F: include/hw/s390x/
F: pc-bios/s390-ccw/
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
UniCore32 Machines
@@ -706,11 +712,15 @@ Block
M: Kevin Wolf <kwolf@redhat.com>
M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported
F: async.c
F: aio-*.c
F: block*
F: block/
F: hw/block/
F: qemu-img*
F: qemu-io*
F: tests/image-fuzzer/
F: tests/qemu-iotests/
T: git git://repo.or.cz/qemu/kevin.git block
T: git git://github.com/stefanha/qemu.git block
@@ -825,6 +835,12 @@ S: Supported
F: qapi-schema.json
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
QObject
M: Luiz Capitulino <lcapitulino@redhat.com>
S: Maintained
F: qobject/
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
QOM
M: Anthony Liguori <aliguori@amazon.com>
M: Andreas Färber <afaerber@suse.de>

View File

@@ -50,7 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration.o migration-tcp.o
common-obj-y += vmstate.o
common-obj-y += qemu-file.o
common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
common-obj-$(CONFIG_RDMA) += migration-rdma.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += block-migration.o

View File

@@ -1040,8 +1040,7 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
static int ram_load(QEMUFile *f, void *opaque, int version_id)
{
ram_addr_t addr;
int flags, ret = 0;
int flags = 0, ret = 0;
static uint64_t seq_iter;
seq_iter++;
@@ -1050,21 +1049,24 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
}
while (!ret) {
addr = qemu_get_be64(f);
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
ram_addr_t addr, total_ram_bytes;
void *host;
uint8_t ch;
addr = qemu_get_be64(f);
flags = addr & ~TARGET_PAGE_MASK;
addr &= TARGET_PAGE_MASK;
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
case RAM_SAVE_FLAG_MEM_SIZE:
/* Synchronize RAM block list */
char id[256];
ram_addr_t length;
ram_addr_t total_ram_bytes = addr;
while (total_ram_bytes) {
total_ram_bytes = addr;
while (!ret && total_ram_bytes) {
RAMBlock *block;
uint8_t len;
char id[256];
ram_addr_t length;
len = qemu_get_byte(f);
qemu_get_buffer(f, (uint8_t *)id, len);
@@ -1088,16 +1090,11 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
"accept migration", id);
ret = -EINVAL;
}
if (ret) {
break;
}
total_ram_bytes -= length;
}
} else if (flags & RAM_SAVE_FLAG_COMPRESS) {
void *host;
uint8_t ch;
break;
case RAM_SAVE_FLAG_COMPRESS:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
@@ -1107,9 +1104,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ch = qemu_get_byte(f);
ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
break;
case RAM_SAVE_FLAG_PAGE:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
@@ -1118,8 +1114,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
}
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
void *host = host_from_stream_offset(f, addr, flags);
break;
case RAM_SAVE_FLAG_XBZRLE:
host = host_from_stream_offset(f, addr, flags);
if (!host) {
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
ret = -EINVAL;
@@ -1132,17 +1129,22 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
break;
}
} else if (flags & RAM_SAVE_FLAG_HOOK) {
ram_control_load_hook(f, flags);
} else if (flags & RAM_SAVE_FLAG_EOS) {
break;
case RAM_SAVE_FLAG_EOS:
/* normal exit */
break;
} else {
error_report("Unknown migration flags: %#x", flags);
ret = -EINVAL;
break;
default:
if (flags & RAM_SAVE_FLAG_HOOK) {
ram_control_load_hook(f, flags);
} else {
error_report("Unknown combination of migration flags: %#x",
flags);
ret = -EINVAL;
}
}
if (!ret) {
ret = qemu_file_get_error(f);
}
ret = qemu_file_get_error(f);
}
DPRINTF("Completed load of VM with exit code %d seq iteration "

View File

@@ -14,7 +14,9 @@
*/
#include "qemu-common.h"
#include "block/block_int.h"
#include "block/block.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "hw/hw.h"
#include "qemu/queue.h"
#include "qemu/timer.h"
@@ -70,7 +72,7 @@ typedef struct BlkMigBlock {
int nr_sectors;
struct iovec iov;
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
BlockAIOCB *aiocb;
/* Protected by block migration lock. */
int ret;
@@ -130,9 +132,9 @@ static void blk_send(QEMUFile *f, BlkMigBlock * blk)
| flags);
/* device name */
len = strlen(blk->bmds->bs->device_name);
len = strlen(bdrv_get_device_name(blk->bmds->bs));
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
qemu_put_buffer(f, (uint8_t *)bdrv_get_device_name(blk->bmds->bs), len);
/* if a block is zero we need to flush here since the network
* bandwidth is now a lot higher than the storage device bandwidth.
@@ -343,12 +345,25 @@ static void unset_dirty_tracking(void)
}
}
static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
static void init_blk_migration(QEMUFile *f)
{
BlockDriverState *bs;
BlkMigDevState *bmds;
int64_t sectors;
if (!bdrv_is_read_only(bs)) {
block_mig_state.submitted = 0;
block_mig_state.read_done = 0;
block_mig_state.transferred = 0;
block_mig_state.total_sector_sum = 0;
block_mig_state.prev_progress = -1;
block_mig_state.bulk_completed = 0;
block_mig_state.zero_blocks = migrate_zero_blocks();
for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
if (bdrv_is_read_only(bs)) {
continue;
}
sectors = bdrv_nb_sectors(bs);
if (sectors <= 0) {
return;
@@ -369,28 +384,15 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
if (bmds->shared_base) {
DPRINTF("Start migration for %s with shared base image\n",
bs->device_name);
bdrv_get_device_name(bs));
} else {
DPRINTF("Start full migration for %s\n", bs->device_name);
DPRINTF("Start full migration for %s\n", bdrv_get_device_name(bs));
}
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
}
}
static void init_blk_migration(QEMUFile *f)
{
block_mig_state.submitted = 0;
block_mig_state.read_done = 0;
block_mig_state.transferred = 0;
block_mig_state.total_sector_sum = 0;
block_mig_state.prev_progress = -1;
block_mig_state.bulk_completed = 0;
block_mig_state.zero_blocks = migrate_zero_blocks();
bdrv_iterate(init_blk_migration_it, NULL);
}
/* Called with no lock taken. */
static int blk_mig_save_bulked_block(QEMUFile *f)

439
block.c
View File

@@ -28,8 +28,8 @@
#include "block/blockjob.h"
#include "qemu/module.h"
#include "qapi/qmp/qjson.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "sysemu/blockdev.h" /* FIXME layering violation */
#include "qemu/notify.h"
#include "block/coroutine.h"
#include "block/qapi.h"
@@ -58,15 +58,12 @@ struct BdrvDirtyBitmap {
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque);
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockCompletionFunc *cb, void *opaque);
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
@@ -79,14 +76,14 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags);
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BdrvRequestFlags flags,
BlockDriverCompletionFunc *cb,
void *opaque,
bool is_write);
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BdrvRequestFlags flags,
BlockCompletionFunc *cb,
void *opaque,
bool is_write);
static void coroutine_fn bdrv_co_do_rw(void *opaque);
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
@@ -335,35 +332,21 @@ void bdrv_register(BlockDriver *bdrv)
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
}
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
BlockDriverState *bdrv_new_root(void)
{
BlockDriverState *bs = bdrv_new();
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
return bs;
}
BlockDriverState *bdrv_new(void)
{
BlockDriverState *bs;
int i;
if (*device_name && !id_wellformed(device_name)) {
error_setg(errp, "Invalid device name");
return NULL;
}
if (bdrv_find(device_name)) {
error_setg(errp, "Device with id '%s' already exists",
device_name);
return NULL;
}
if (bdrv_find_node(device_name)) {
error_setg(errp,
"Device name '%s' conflicts with an existing node name",
device_name);
return NULL;
}
bs = g_new0(BlockDriverState, 1);
QLIST_INIT(&bs->dirty_bitmaps);
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
if (device_name[0] != '\0') {
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
}
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
QLIST_INIT(&bs->op_blockers[i]);
}
@@ -875,7 +858,7 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
}
/* takes care of avoiding namespaces collisions */
if (bdrv_find(node_name)) {
if (blk_by_name(node_name)) {
error_setg(errp, "node-name=%s is conflicting with a device id",
node_name);
return;
@@ -1159,7 +1142,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
} else if (backing_hd) {
error_setg(&bs->backing_blocker,
"device is used as backing hd of '%s'",
bs->device_name);
bdrv_get_device_name(bs));
}
bs->backing_hd = backing_hd;
@@ -1224,7 +1207,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
goto free_exit;
}
backing_hd = bdrv_new("", errp);
backing_hd = bdrv_new();
if (bs->backing_format[0] != '\0') {
back_drv = bdrv_find_format(bs->backing_format);
@@ -1353,7 +1336,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
qdict_put(snapshot_options, "file.filename",
qstring_from_str(tmp_filename));
bs_snapshot = bdrv_new("", &error_abort);
bs_snapshot = bdrv_new();
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
flags, bdrv_qcow2, &local_err);
@@ -1424,7 +1407,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
if (*pbs) {
bs = *pbs;
} else {
bs = bdrv_new("", &error_abort);
bs = bdrv_new();
}
/* NULL means an empty set of options */
@@ -1533,7 +1516,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
} else {
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
"support the option '%s'", drv->format_name,
bs->device_name, entry->key);
bdrv_get_device_name(bs), entry->key);
}
ret = -EINVAL;
@@ -1541,7 +1524,9 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
}
if (!bdrv_key_required(bs)) {
bdrv_dev_change_media_cb(bs, true);
if (bs->blk) {
blk_dev_change_media_cb(bs->blk, true);
}
} else if (!runstate_check(RUN_STATE_PRELAUNCH)
&& !runstate_check(RUN_STATE_INMIGRATE)
&& !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
@@ -1740,7 +1725,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
reopen_state->flags & BDRV_O_RDWR) {
error_set(errp, QERR_DEVICE_IS_READ_ONLY,
reopen_state->bs->device_name);
bdrv_get_device_name(reopen_state->bs));
goto error;
}
@@ -1767,7 +1752,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
/* It is currently mandatory to have a bdrv_reopen_prepare()
* handler for each supported drv. */
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
drv->format_name, reopen_state->bs->device_name,
drv->format_name, bdrv_get_device_name(reopen_state->bs),
"reopening of file");
ret = -1;
goto error;
@@ -1866,7 +1851,9 @@ void bdrv_close(BlockDriverState *bs)
}
}
bdrv_dev_change_media_cb(bs, false);
if (bs->blk) {
blk_dev_change_media_cb(bs->blk, false);
}
/*throttling disk I/O limits*/
if (bs->io_limits_enabled) {
@@ -1955,10 +1942,17 @@ void bdrv_drain_all(void)
Also, NULL terminate the device_name to prevent double remove */
void bdrv_make_anon(BlockDriverState *bs)
{
if (bs->device_name[0] != '\0') {
/*
* Take care to remove bs from bdrv_states only when it's actually
* in it. Note that bs->device_list.tqe_prev is initially null,
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
* resetting it to null on remove.
*/
if (bs->device_list.tqe_prev) {
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
bs->device_list.tqe_prev = NULL;
}
bs->device_name[0] = '\0';
if (bs->node_name[0] != '\0') {
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
}
@@ -1978,9 +1972,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
/* move some fields that need to stay attached to the device */
/* dev info */
bs_dest->dev_ops = bs_src->dev_ops;
bs_dest->dev_opaque = bs_src->dev_opaque;
bs_dest->dev = bs_src->dev;
bs_dest->guest_block_size = bs_src->guest_block_size;
bs_dest->copy_on_read = bs_src->copy_on_read;
@@ -2012,9 +2003,9 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
bs_dest->job = bs_src->job;
/* keep the same entry in bdrv_states */
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
bs_src->device_name);
bs_dest->device_list = bs_src->device_list;
bs_dest->blk = bs_src->blk;
memcpy(bs_dest->op_blockers, bs_src->op_blockers,
sizeof(bs_dest->op_blockers));
}
@@ -2027,7 +2018,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
* This will modify the BlockDriverState fields, and swap contents
* between bs_new and bs_old. Both bs_new and bs_old are modified.
*
* bs_new is required to be anonymous.
* bs_new must not be attached to a BlockBackend.
*
* This function does not create any image files.
*/
@@ -2046,11 +2037,10 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
}
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
assert(bs_new->device_name[0] == '\0');
/* bs_new must be unattached and shouldn't have anything fancy enabled */
assert(!bs_new->blk);
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
assert(bs_new->job == NULL);
assert(bs_new->dev == NULL);
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
@@ -2063,11 +2053,10 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
bdrv_move_feature_fields(bs_old, bs_new);
bdrv_move_feature_fields(bs_new, &tmp);
/* bs_new shouldn't be in bdrv_states even after the swap! */
assert(bs_new->device_name[0] == '\0');
/* bs_new must remain unattached */
assert(!bs_new->blk);
/* Check a few fields that should remain attached to the device */
assert(bs_new->dev == NULL);
assert(bs_new->job == NULL);
assert(bs_new->io_limits_enabled == false);
assert(!throttle_have_timer(&bs_new->throttle_state));
@@ -2091,7 +2080,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
* This will modify the BlockDriverState fields, and swap contents
* between bs_new and bs_top. Both bs_new and bs_top are modified.
*
* bs_new is required to be anonymous.
* bs_new must not be attached to a BlockBackend.
*
* This function does not create any image files.
*/
@@ -2106,7 +2095,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
static void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->dev);
assert(!bs->job);
assert(bdrv_op_blocker_is_empty(bs));
assert(!bs->refcnt);
@@ -2117,109 +2105,9 @@ static void bdrv_delete(BlockDriverState *bs)
/* remove from list, if necessary */
bdrv_make_anon(bs);
drive_info_del(drive_get_by_blockdev(bs));
g_free(bs);
}
int bdrv_attach_dev(BlockDriverState *bs, void *dev)
/* TODO change to DeviceState *dev when all users are qdevified */
{
if (bs->dev) {
return -EBUSY;
}
bs->dev = dev;
bdrv_iostatus_reset(bs);
/* We're expecting I/O from the device so bump up coroutine pool size */
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
return 0;
}
/* TODO qdevified devices don't use this, remove when devices are qdevified */
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
{
if (bdrv_attach_dev(bs, dev) < 0) {
abort();
}
}
void bdrv_detach_dev(BlockDriverState *bs, void *dev)
/* TODO change to DeviceState *dev when all users are qdevified */
{
assert(bs->dev == dev);
bs->dev = NULL;
bs->dev_ops = NULL;
bs->dev_opaque = NULL;
bs->guest_block_size = 512;
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
}
/* TODO change to return DeviceState * when all users are qdevified */
void *bdrv_get_attached_dev(BlockDriverState *bs)
{
return bs->dev;
}
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
void *opaque)
{
bs->dev_ops = ops;
bs->dev_opaque = opaque;
}
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
{
if (bs->dev_ops && bs->dev_ops->change_media_cb) {
bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
bs->dev_ops->change_media_cb(bs->dev_opaque, load);
if (tray_was_closed) {
/* tray open */
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
true, &error_abort);
}
if (load) {
/* tray close */
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
false, &error_abort);
}
}
}
bool bdrv_dev_has_removable_media(BlockDriverState *bs)
{
return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
}
void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
{
if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
}
}
bool bdrv_dev_is_tray_open(BlockDriverState *bs)
{
if (bs->dev_ops && bs->dev_ops->is_tray_open) {
return bs->dev_ops->is_tray_open(bs->dev_opaque);
}
return false;
}
static void bdrv_dev_resize_cb(BlockDriverState *bs)
{
if (bs->dev_ops && bs->dev_ops->resize_cb) {
bs->dev_ops->resize_cb(bs->dev_opaque);
}
}
bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
{
if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
return bs->dev_ops->is_medium_locked(bs->dev_opaque);
}
return false;
}
/*
* Run consistency checks on an image
*
@@ -3553,7 +3441,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
bdrv_dev_resize_cb(bs);
if (bs->blk) {
blk_dev_resize_cb(bs->blk);
}
}
return ret;
}
@@ -3754,8 +3644,10 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
bs->valid_key = 0;
} else if (!bs->valid_key) {
bs->valid_key = 1;
/* call the change callback now, we skipped it on open */
bdrv_dev_change_media_cb(bs, true);
if (bs->blk) {
/* call the change callback now, we skipped it on open */
blk_dev_change_media_cb(bs->blk, true);
}
}
return ret;
}
@@ -3803,16 +3695,12 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
}
/* This function is to find block backend bs */
/* TODO convert callers to blk_by_name(), then remove */
BlockDriverState *bdrv_find(const char *name)
{
BlockDriverState *bs;
BlockBackend *blk = blk_by_name(name);
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
if (!strcmp(name, bs->device_name)) {
return bs;
}
}
return NULL;
return blk ? blk_bs(blk) : NULL;
}
/* This function is to find a node in the bs graph */
@@ -3851,13 +3739,14 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
const char *node_name,
Error **errp)
{
BlockDriverState *bs = NULL;
BlockBackend *blk;
BlockDriverState *bs;
if (device) {
bs = bdrv_find(device);
blk = blk_by_name(device);
if (bs) {
return bs;
if (blk) {
return blk_bs(blk);
}
}
@@ -3894,18 +3783,10 @@ BlockDriverState *bdrv_next(BlockDriverState *bs)
return QTAILQ_NEXT(bs, device_list);
}
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)
/* TODO check what callers really want: bs->node_name or blk_name() */
const char *bdrv_get_device_name(const BlockDriverState *bs)
{
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
it(opaque, bs);
}
}
const char *bdrv_get_device_name(BlockDriverState *bs)
{
return bs->device_name;
return bs->blk ? blk_name(bs->blk) : "";
}
int bdrv_get_flags(BlockDriverState *bs)
@@ -4073,13 +3954,24 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
if (bs->file &&
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
(ret & BDRV_BLOCK_OFFSET_VALID)) {
int file_pnum;
ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
*pnum, pnum);
*pnum, &file_pnum);
if (ret2 >= 0) {
/* Ignore errors. This is just providing extra information, it
* is useful but not necessary.
*/
ret |= (ret2 & BDRV_BLOCK_ZERO);
if (!file_pnum) {
/* !file_pnum indicates an offset at or beyond the EOF; it is
* perfectly valid for the format block driver to point to such
* offsets, so catch it and mark everything as zero */
ret |= BDRV_BLOCK_ZERO;
} else {
/* Limit request to the range reported by the protocol driver */
*pnum = file_pnum;
ret |= (ret2 & BDRV_BLOCK_ZERO);
}
}
}
@@ -4432,9 +4324,9 @@ int bdrv_get_backing_file_depth(BlockDriverState *bs)
/**************************************************************/
/* async I/Os */
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
@@ -4442,9 +4334,9 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
cb, opaque, false);
}
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
@@ -4452,9 +4344,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
cb, opaque, true);
}
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque);
@@ -4469,7 +4361,7 @@ typedef struct MultiwriteCB {
int num_requests;
int num_callbacks;
struct {
BlockDriverCompletionFunc *cb;
BlockCompletionFunc *cb;
void *opaque;
QEMUIOVector *free_qiov;
} callbacks[];
@@ -4646,7 +4538,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
return 0;
}
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
void bdrv_aio_cancel(BlockAIOCB *acb)
{
qemu_aio_ref(acb);
bdrv_aio_cancel_async(acb);
@@ -4665,7 +4557,7 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb)
/* Async version of aio cancel. The caller is not blocked if the acb implements
* cancel_async, otherwise we do nothing and let the request normally complete.
* In either case the completion callback must be called. */
void bdrv_aio_cancel_async(BlockDriverAIOCB *acb)
void bdrv_aio_cancel_async(BlockAIOCB *acb)
{
if (acb->aiocb_info->cancel_async) {
acb->aiocb_info->cancel_async(acb);
@@ -4675,23 +4567,23 @@ void bdrv_aio_cancel_async(BlockDriverAIOCB *acb)
/**************************************************************/
/* async block device emulation */
typedef struct BlockDriverAIOCBSync {
BlockDriverAIOCB common;
typedef struct BlockAIOCBSync {
BlockAIOCB common;
QEMUBH *bh;
int ret;
/* vector translation state */
QEMUIOVector *qiov;
uint8_t *bounce;
int is_write;
} BlockDriverAIOCBSync;
} BlockAIOCBSync;
static const AIOCBInfo bdrv_em_aiocb_info = {
.aiocb_size = sizeof(BlockDriverAIOCBSync),
.aiocb_size = sizeof(BlockAIOCBSync),
};
static void bdrv_aio_bh_cb(void *opaque)
{
BlockDriverAIOCBSync *acb = opaque;
BlockAIOCBSync *acb = opaque;
if (!acb->is_write && acb->ret >= 0) {
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
@@ -4703,16 +4595,16 @@ static void bdrv_aio_bh_cb(void *opaque)
qemu_aio_unref(acb);
}
static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque,
int is_write)
static BlockAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque,
int is_write)
{
BlockDriverAIOCBSync *acb;
BlockAIOCBSync *acb;
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
acb->is_write = is_write;
@@ -4734,36 +4626,36 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
typedef struct BlockDriverAIOCBCoroutine {
BlockDriverAIOCB common;
typedef struct BlockAIOCBCoroutine {
BlockAIOCB common;
BlockRequest req;
bool is_write;
bool *done;
QEMUBH* bh;
} BlockDriverAIOCBCoroutine;
} BlockAIOCBCoroutine;
static const AIOCBInfo bdrv_em_co_aiocb_info = {
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
.aiocb_size = sizeof(BlockAIOCBCoroutine),
};
static void bdrv_co_em_bh(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockAIOCBCoroutine *acb = opaque;
acb->common.cb(acb->common.opaque, acb->req.error);
@@ -4774,7 +4666,7 @@ static void bdrv_co_em_bh(void *opaque)
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
static void coroutine_fn bdrv_co_do_rw(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockAIOCBCoroutine *acb = opaque;
BlockDriverState *bs = acb->common.bs;
if (!acb->is_write) {
@@ -4789,17 +4681,17 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
qemu_bh_schedule(acb->bh);
}
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BdrvRequestFlags flags,
BlockDriverCompletionFunc *cb,
void *opaque,
bool is_write)
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BdrvRequestFlags flags,
BlockCompletionFunc *cb,
void *opaque,
bool is_write)
{
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
BlockAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
acb->req.sector = sector_num;
@@ -4816,7 +4708,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockAIOCBCoroutine *acb = opaque;
BlockDriverState *bs = acb->common.bs;
acb->req.error = bdrv_co_flush(bs);
@@ -4824,13 +4716,13 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
qemu_bh_schedule(acb->bh);
}
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
trace_bdrv_aio_flush(bs, opaque);
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
BlockAIOCBCoroutine *acb;
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
@@ -4842,7 +4734,7 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
{
BlockDriverAIOCBCoroutine *acb = opaque;
BlockAIOCBCoroutine *acb = opaque;
BlockDriverState *bs = acb->common.bs;
acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
@@ -4850,12 +4742,12 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
qemu_bh_schedule(acb->bh);
}
BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
Coroutine *co;
BlockDriverAIOCBCoroutine *acb;
BlockAIOCBCoroutine *acb;
trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
@@ -4880,9 +4772,9 @@ void bdrv_init_with_whitelist(void)
}
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BlockDriverAIOCB *acb;
BlockAIOCB *acb;
acb = g_slice_alloc(aiocb_info->aiocb_size);
acb->aiocb_info = aiocb_info;
@@ -4895,13 +4787,13 @@ void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
void qemu_aio_ref(void *p)
{
BlockDriverAIOCB *acb = p;
BlockAIOCB *acb = p;
acb->refcnt++;
}
void qemu_aio_unref(void *p)
{
BlockDriverAIOCB *acb = p;
BlockAIOCB *acb = p;
assert(acb->refcnt > 0);
if (--acb->refcnt == 0) {
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
@@ -4931,7 +4823,7 @@ static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
BlockDriverAIOCB *acb;
BlockAIOCB *acb;
if (is_write) {
acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
@@ -4997,7 +4889,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
if (bs->drv->bdrv_co_flush_to_disk) {
ret = bs->drv->bdrv_co_flush_to_disk(bs);
} else if (bs->drv->bdrv_aio_flush) {
BlockDriverAIOCB *acb;
BlockAIOCB *acb;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
@@ -5043,6 +4935,11 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
return;
}
if (!(bs->open_flags & BDRV_O_INCOMING)) {
return;
}
bs->open_flags &= ~BDRV_O_INCOMING;
if (bs->drv->bdrv_invalidate_cache) {
bs->drv->bdrv_invalidate_cache(bs, &local_err);
} else if (bs->file) {
@@ -5078,19 +4975,6 @@ void bdrv_invalidate_cache_all(Error **errp)
}
}
void bdrv_clear_incoming_migration_all(void)
{
BlockDriverState *bs;
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
AioContext *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
bs->open_flags = bs->open_flags & ~(BDRV_O_INCOMING);
aio_context_release(aio_context);
}
}
int bdrv_flush(BlockDriverState *bs)
{
Coroutine *co;
@@ -5180,7 +5064,7 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
if (bs->drv->bdrv_co_discard) {
ret = bs->drv->bdrv_co_discard(bs, sector_num, num);
} else {
BlockDriverAIOCB *acb;
BlockAIOCB *acb;
CoroutineIOCompletion co = {
.coroutine = qemu_coroutine_self(),
};
@@ -5267,13 +5151,15 @@ int bdrv_media_changed(BlockDriverState *bs)
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
{
BlockDriver *drv = bs->drv;
const char *device_name;
if (drv && drv->bdrv_eject) {
drv->bdrv_eject(bs, eject_flag);
}
if (bs->device_name[0] != '\0') {
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
device_name = bdrv_get_device_name(bs);
if (device_name[0] != '\0') {
qapi_event_send_device_tray_moved(device_name,
eject_flag, &error_abort);
}
}
@@ -5304,9 +5190,9 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return -ENOTSUP;
}
BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
@@ -5325,6 +5211,11 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size)
return qemu_memalign(bdrv_opt_mem_align(bs), size);
}
void *qemu_blockalign0(BlockDriverState *bs, size_t size)
{
return memset(qemu_blockalign(bs, size), 0, size);
}
void *qemu_try_blockalign(BlockDriverState *bs, size_t size)
{
size_t align = bdrv_opt_mem_align(bs);
@@ -5338,6 +5229,17 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size)
return qemu_try_memalign(align, size);
}
void *qemu_try_blockalign0(BlockDriverState *bs, size_t size)
{
void *mem = qemu_try_blockalign(bs, size);
if (mem) {
memset(mem, 0, size);
}
return mem;
}
/*
* Check if all memory in this vector is sector aligned.
*/
@@ -5483,7 +5385,8 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
blocker = QLIST_FIRST(&bs->op_blockers[op]);
if (errp) {
error_setg(errp, "Device '%s' is busy: %s",
bs->device_name, error_get_pretty(blocker->reason));
bdrv_get_device_name(bs),
error_get_pretty(blocker->reason));
}
return true;
}

View File

@@ -5,7 +5,7 @@ block-obj-y += qed-check.o
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-$(CONFIG_QUORUM) += quorum.o
block-obj-y += parallels.o blkdebug.o blkverify.o
block-obj-y += snapshot.o qapi.o
block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
block-obj-$(CONFIG_POSIX) += raw-posix.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o

View File

@@ -86,7 +86,7 @@ typedef enum {
} ARCHIPCmd;
typedef struct ArchipelagoAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
struct BDRVArchipelagoState *s;
QEMUIOVector *qiov;
@@ -856,13 +856,13 @@ err_exit:
return ret;
}
static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque,
int op)
static BlockAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque,
int op)
{
ArchipelagoAIOCB *aio_cb;
BDRVArchipelagoState *s = bs->opaque;
@@ -894,17 +894,17 @@ err_exit:
return NULL;
}
static BlockDriverAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
static BlockAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
opaque, ARCHIP_OP_READ);
}
static BlockDriverAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
static BlockAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
opaque, ARCHIP_OP_WRITE);
@@ -1052,8 +1052,8 @@ static QemuOptsList qemu_archipelago_create_opts = {
}
};
static BlockDriverAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static BlockAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
return qemu_archipelago_aio_rw(bs, 0, NULL, 0, cb, opaque,
ARCHIP_OP_FLUSH);

View File

@@ -353,7 +353,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, MirrorSyncMode sync_mode,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb, void *opaque,
BlockCompletionFunc *cb, void *opaque,
Error **errp)
{
int64_t len;

View File

@@ -41,7 +41,7 @@ typedef struct BDRVBlkdebugState {
} BDRVBlkdebugState;
typedef struct BlkdebugAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
int ret;
} BlkdebugAIOCB;
@@ -463,8 +463,8 @@ static void error_callback_bh(void *opaque)
qemu_aio_unref(acb);
}
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
static BlockAIOCB *inject_error(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
{
BDRVBlkdebugState *s = bs->opaque;
int error = rule->options.inject.error;
@@ -489,9 +489,9 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
@@ -511,9 +511,9 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;
@@ -533,8 +533,8 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkdebugState *s = bs->opaque;
BlkdebugRule *rule = NULL;

View File

@@ -19,7 +19,7 @@ typedef struct {
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
struct BlkverifyAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
/* Request metadata */
@@ -165,7 +165,7 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque)
{
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
@@ -229,9 +229,9 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
}
}
static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkverifyState *s = bs->opaque;
BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
@@ -249,9 +249,9 @@ static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVBlkverifyState *s = bs->opaque;
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
@@ -264,9 +264,9 @@ static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb,
void *opaque)
{
BDRVBlkverifyState *s = bs->opaque;

631
block/block-backend.c Normal file
View File

@@ -0,0 +1,631 @@
/*
* QEMU Block backends
*
* Copyright (C) 2014 Red Hat, Inc.
*
* Authors:
* Markus Armbruster <armbru@redhat.com>,
*
* This work is licensed under the terms of the GNU LGPL, version 2.1
* or later. See the COPYING.LIB file in the top-level directory.
*/
#include "sysemu/block-backend.h"
#include "block/block_int.h"
#include "sysemu/blockdev.h"
#include "qapi-event.h"
/* Number of coroutines to reserve per attached device model */
#define COROUTINE_POOL_RESERVATION 64
struct BlockBackend {
char *name;
int refcnt;
BlockDriverState *bs;
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */
void *dev; /* attached device model, if any */
/* TODO change to DeviceState when all users are qdevified */
const BlockDevOps *dev_ops;
void *dev_opaque;
};
static void drive_info_del(DriveInfo *dinfo);
/* All the BlockBackends (except for hidden ones) */
static QTAILQ_HEAD(, BlockBackend) blk_backends =
QTAILQ_HEAD_INITIALIZER(blk_backends);
/*
* Create a new BlockBackend with @name, with a reference count of one.
* @name must not be null or empty.
* Fail if a BlockBackend with this name already exists.
* Store an error through @errp on failure, unless it's null.
* Return the new BlockBackend on success, null on failure.
*/
BlockBackend *blk_new(const char *name, Error **errp)
{
BlockBackend *blk;
assert(name && name[0]);
if (!id_wellformed(name)) {
error_setg(errp, "Invalid device name");
return NULL;
}
if (blk_by_name(name)) {
error_setg(errp, "Device with id '%s' already exists", name);
return NULL;
}
if (bdrv_find_node(name)) {
error_setg(errp,
"Device name '%s' conflicts with an existing node name",
name);
return NULL;
}
blk = g_new0(BlockBackend, 1);
blk->name = g_strdup(name);
blk->refcnt = 1;
QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
return blk;
}
/*
* Create a new BlockBackend with a new BlockDriverState attached.
* Otherwise just like blk_new(), which see.
*/
BlockBackend *blk_new_with_bs(const char *name, Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
blk = blk_new(name, errp);
if (!blk) {
return NULL;
}
bs = bdrv_new_root();
blk->bs = bs;
bs->blk = blk;
return blk;
}
static void blk_delete(BlockBackend *blk)
{
assert(!blk->refcnt);
assert(!blk->dev);
if (blk->bs) {
assert(blk->bs->blk == blk);
blk->bs->blk = NULL;
bdrv_unref(blk->bs);
blk->bs = NULL;
}
/* Avoid double-remove after blk_hide_on_behalf_of_do_drive_del() */
if (blk->name[0]) {
QTAILQ_REMOVE(&blk_backends, blk, link);
}
g_free(blk->name);
drive_info_del(blk->legacy_dinfo);
g_free(blk);
}
static void drive_info_del(DriveInfo *dinfo)
{
if (!dinfo) {
return;
}
qemu_opts_del(dinfo->opts);
g_free(dinfo->serial);
g_free(dinfo);
}
/*
* Increment @blk's reference count.
* @blk must not be null.
*/
void blk_ref(BlockBackend *blk)
{
blk->refcnt++;
}
/*
* Decrement @blk's reference count.
* If this drops it to zero, destroy @blk.
* For convenience, do nothing if @blk is null.
*/
void blk_unref(BlockBackend *blk)
{
if (blk) {
assert(blk->refcnt > 0);
if (!--blk->refcnt) {
blk_delete(blk);
}
}
}
/*
* Return the BlockBackend after @blk.
* If @blk is null, return the first one.
* Else, return @blk's next sibling, which may be null.
*
* To iterate over all BlockBackends, do
* for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
* ...
* }
*/
BlockBackend *blk_next(BlockBackend *blk)
{
return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends);
}
/*
* Return @blk's name, a non-null string.
* Wart: the name is empty iff @blk has been hidden with
* blk_hide_on_behalf_of_do_drive_del().
*/
const char *blk_name(BlockBackend *blk)
{
return blk->name;
}
/*
* Return the BlockBackend with name @name if it exists, else null.
* @name must not be null.
*/
BlockBackend *blk_by_name(const char *name)
{
BlockBackend *blk;
assert(name);
QTAILQ_FOREACH(blk, &blk_backends, link) {
if (!strcmp(name, blk->name)) {
return blk;
}
}
return NULL;
}
/*
* Return the BlockDriverState attached to @blk if any, else null.
*/
BlockDriverState *blk_bs(BlockBackend *blk)
{
return blk->bs;
}
/*
* Return @blk's DriveInfo if any, else null.
*/
DriveInfo *blk_legacy_dinfo(BlockBackend *blk)
{
return blk->legacy_dinfo;
}
/*
* Set @blk's DriveInfo to @dinfo, and return it.
* @blk must not have a DriveInfo set already.
* No other BlockBackend may have the same DriveInfo set.
*/
DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo)
{
assert(!blk->legacy_dinfo);
return blk->legacy_dinfo = dinfo;
}
/*
* Return the BlockBackend with DriveInfo @dinfo.
* It must exist.
*/
BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo)
{
BlockBackend *blk;
QTAILQ_FOREACH(blk, &blk_backends, link) {
if (blk->legacy_dinfo == dinfo) {
return blk;
}
}
abort();
}
/*
* Hide @blk.
* @blk must not have been hidden already.
* Make attached BlockDriverState, if any, anonymous.
* Once hidden, @blk is invisible to all functions that don't receive
* it as argument. For example, blk_by_name() won't return it.
* Strictly for use by do_drive_del().
* TODO get rid of it!
*/
void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
{
QTAILQ_REMOVE(&blk_backends, blk, link);
blk->name[0] = 0;
if (blk->bs) {
bdrv_make_anon(blk->bs);
}
}
/*
* Attach device model @dev to @blk.
* Return 0 on success, -EBUSY when a device model is attached already.
*/
int blk_attach_dev(BlockBackend *blk, void *dev)
/* TODO change to DeviceState *dev when all users are qdevified */
{
if (blk->dev) {
return -EBUSY;
}
blk_ref(blk);
blk->dev = dev;
bdrv_iostatus_reset(blk->bs);
/* We're expecting I/O from the device so bump up coroutine pool size */
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
return 0;
}
/*
* Attach device model @dev to @blk.
* @blk must not have a device model attached already.
* TODO qdevified devices don't use this, remove when devices are qdevified
*/
void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
{
if (blk_attach_dev(blk, dev) < 0) {
abort();
}
}
/*
* Detach device model @dev from @blk.
* @dev must be currently attached to @blk.
*/
void blk_detach_dev(BlockBackend *blk, void *dev)
/* TODO change to DeviceState *dev when all users are qdevified */
{
assert(blk->dev == dev);
blk->dev = NULL;
blk->dev_ops = NULL;
blk->dev_opaque = NULL;
bdrv_set_guest_block_size(blk->bs, 512);
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
blk_unref(blk);
}
/*
* Return the device model attached to @blk if any, else null.
*/
void *blk_get_attached_dev(BlockBackend *blk)
/* TODO change to return DeviceState * when all users are qdevified */
{
return blk->dev;
}
/*
* Set @blk's device model callbacks to @ops.
* @opaque is the opaque argument to pass to the callbacks.
* This is for use by device models.
*/
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
void *opaque)
{
blk->dev_ops = ops;
blk->dev_opaque = opaque;
}
/*
* Notify @blk's attached device model of media change.
* If @load is true, notify of media load.
* Else, notify of media eject.
* Also send DEVICE_TRAY_MOVED events as appropriate.
*/
void blk_dev_change_media_cb(BlockBackend *blk, bool load)
{
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
bool tray_was_closed = !blk_dev_is_tray_open(blk);
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
if (tray_was_closed) {
/* tray open */
qapi_event_send_device_tray_moved(blk_name(blk),
true, &error_abort);
}
if (load) {
/* tray close */
qapi_event_send_device_tray_moved(blk_name(blk),
false, &error_abort);
}
}
}
/*
* Does @blk's attached device model have removable media?
* %true if no device model is attached.
*/
bool blk_dev_has_removable_media(BlockBackend *blk)
{
return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
}
/*
* Notify @blk's attached device model of a media eject request.
* If @force is true, the medium is about to be yanked out forcefully.
*/
void blk_dev_eject_request(BlockBackend *blk, bool force)
{
if (blk->dev_ops && blk->dev_ops->eject_request_cb) {
blk->dev_ops->eject_request_cb(blk->dev_opaque, force);
}
}
/*
* Does @blk's attached device model have a tray, and is it open?
*/
bool blk_dev_is_tray_open(BlockBackend *blk)
{
if (blk->dev_ops && blk->dev_ops->is_tray_open) {
return blk->dev_ops->is_tray_open(blk->dev_opaque);
}
return false;
}
/*
* Does @blk's attached device model have the medium locked?
* %false if the device model has no such lock.
*/
bool blk_dev_is_medium_locked(BlockBackend *blk)
{
if (blk->dev_ops && blk->dev_ops->is_medium_locked) {
return blk->dev_ops->is_medium_locked(blk->dev_opaque);
}
return false;
}
/*
* Notify @blk's attached device model of a backend size change.
*/
void blk_dev_resize_cb(BlockBackend *blk)
{
if (blk->dev_ops && blk->dev_ops->resize_cb) {
blk->dev_ops->resize_cb(blk->dev_opaque);
}
}
void blk_iostatus_enable(BlockBackend *blk)
{
bdrv_iostatus_enable(blk->bs);
}
int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors)
{
return bdrv_read(blk->bs, sector_num, buf, nb_sectors);
}
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
int nb_sectors)
{
return bdrv_read_unthrottled(blk->bs, sector_num, buf, nb_sectors);
}
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
int nb_sectors)
{
return bdrv_write(blk->bs, sector_num, buf, nb_sectors);
}
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
int nb_sectors, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_write_zeroes(blk->bs, sector_num, nb_sectors, flags,
cb, opaque);
}
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
{
return bdrv_pread(blk->bs, offset, buf, count);
}
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count)
{
return bdrv_pwrite(blk->bs, offset, buf, count);
}
int64_t blk_getlength(BlockBackend *blk)
{
return bdrv_getlength(blk->bs);
}
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
{
bdrv_get_geometry(blk->bs, nb_sectors_ptr);
}
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_readv(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
}
BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_writev(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
}
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_flush(blk->bs, cb, opaque);
}
BlockAIOCB *blk_aio_discard(BlockBackend *blk,
int64_t sector_num, int nb_sectors,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_discard(blk->bs, sector_num, nb_sectors, cb, opaque);
}
void blk_aio_cancel(BlockAIOCB *acb)
{
bdrv_aio_cancel(acb);
}
void blk_aio_cancel_async(BlockAIOCB *acb)
{
bdrv_aio_cancel_async(acb);
}
int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
{
return bdrv_aio_multiwrite(blk->bs, reqs, num_reqs);
}
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{
return bdrv_ioctl(blk->bs, req, buf);
}
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
BlockCompletionFunc *cb, void *opaque)
{
return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
}
int blk_flush(BlockBackend *blk)
{
return bdrv_flush(blk->bs);
}
int blk_flush_all(void)
{
return bdrv_flush_all();
}
void blk_drain_all(void)
{
bdrv_drain_all();
}
BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read)
{
return bdrv_get_on_error(blk->bs, is_read);
}
BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
int error)
{
return bdrv_get_error_action(blk->bs, is_read, error);
}
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
bool is_read, int error)
{
bdrv_error_action(blk->bs, action, is_read, error);
}
int blk_is_read_only(BlockBackend *blk)
{
return bdrv_is_read_only(blk->bs);
}
int blk_is_sg(BlockBackend *blk)
{
return bdrv_is_sg(blk->bs);
}
int blk_enable_write_cache(BlockBackend *blk)
{
return bdrv_enable_write_cache(blk->bs);
}
void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
{
bdrv_set_enable_write_cache(blk->bs, wce);
}
int blk_is_inserted(BlockBackend *blk)
{
return bdrv_is_inserted(blk->bs);
}
void blk_lock_medium(BlockBackend *blk, bool locked)
{
bdrv_lock_medium(blk->bs, locked);
}
void blk_eject(BlockBackend *blk, bool eject_flag)
{
bdrv_eject(blk->bs, eject_flag);
}
int blk_get_flags(BlockBackend *blk)
{
return bdrv_get_flags(blk->bs);
}
void blk_set_guest_block_size(BlockBackend *blk, int align)
{
bdrv_set_guest_block_size(blk->bs, align);
}
void *blk_blockalign(BlockBackend *blk, size_t size)
{
return qemu_blockalign(blk ? blk->bs : NULL, size);
}
bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
{
return bdrv_op_is_blocked(blk->bs, op, errp);
}
void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason)
{
bdrv_op_unblock(blk->bs, op, reason);
}
void blk_op_block_all(BlockBackend *blk, Error *reason)
{
bdrv_op_block_all(blk->bs, reason);
}
void blk_op_unblock_all(BlockBackend *blk, Error *reason)
{
bdrv_op_unblock_all(blk->bs, reason);
}
AioContext *blk_get_aio_context(BlockBackend *blk)
{
return bdrv_get_aio_context(blk->bs);
}
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
{
bdrv_set_aio_context(blk->bs, new_context);
}
void blk_io_plug(BlockBackend *blk)
{
bdrv_io_plug(blk->bs);
}
void blk_io_unplug(BlockBackend *blk)
{
bdrv_io_unplug(blk->bs);
}
BlockAcctStats *blk_get_stats(BlockBackend *blk)
{
return bdrv_get_stats(blk->bs);
}
void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque)
{
return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque);
}

View File

@@ -182,7 +182,7 @@ static const BlockJobDriver commit_job_driver = {
void commit_start(BlockDriverState *bs, BlockDriverState *base,
BlockDriverState *top, int64_t speed,
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
BlockdevOnError on_error, BlockCompletionFunc *cb,
void *opaque, const char *backing_file_str, Error **errp)
{
CommitBlockJob *s;

View File

@@ -78,7 +78,7 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
struct BDRVCURLState;
typedef struct CURLAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
QEMUIOVector *qiov;
@@ -680,9 +680,9 @@ static void curl_readv_bh_cb(void *p)
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
}
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
CURLAIOCB *acb;

View File

@@ -80,7 +80,7 @@ typedef struct IscsiTask {
} IscsiTask;
typedef struct IscsiAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUIOVector *qiov;
QEMUBH *bh;
IscsiLun *iscsilun;
@@ -227,7 +227,7 @@ iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
}
static void
iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
iscsi_aio_cancel(BlockAIOCB *blockacb)
{
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
IscsiLun *iscsilun = acb->iscsilun;
@@ -663,9 +663,9 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
iscsi_schedule_bh(acb);
}
static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
@@ -1519,7 +1519,7 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
IscsiLun *iscsilun = NULL;
QDict *bs_options;
bs = bdrv_new("", &error_abort);
bs = bdrv_new();
/* Read out options */
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

View File

@@ -28,7 +28,7 @@
#define MAX_QUEUED_IO 128
struct qemu_laiocb {
BlockDriverAIOCB common;
BlockAIOCB common;
struct qemu_laio_state *ctx;
struct iocb iocb;
ssize_t ret;
@@ -146,7 +146,7 @@ static void qemu_laio_completion_cb(EventNotifier *e)
}
}
static void laio_cancel(BlockDriverAIOCB *blockacb)
static void laio_cancel(BlockAIOCB *blockacb)
{
struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
struct io_event event;
@@ -243,9 +243,9 @@ int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
return ret;
}
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
BlockCompletionFunc *cb, void *opaque, int type)
{
struct qemu_laio_state *s = aio_ctx;
struct qemu_laiocb *laiocb;

View File

@@ -567,7 +567,8 @@ static void mirror_complete(BlockJob *job, Error **errp)
return;
}
if (!s->synced) {
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
error_set(errp, QERR_BLOCK_JOB_NOT_READY,
bdrv_get_device_name(job->bs));
return;
}
@@ -612,7 +613,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
int64_t buf_size,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque, Error **errp,
const BlockJobDriver *driver,
bool is_none_mode, BlockDriverState *base)
@@ -672,7 +673,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
int64_t speed, int64_t granularity, int64_t buf_size,
MirrorSyncMode mode, BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque, Error **errp)
{
bool is_none_mode;
@@ -689,7 +690,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
int64_t speed,
BlockdevOnError on_error,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque, Error **errp)
{
int64_t length, base_length;

View File

@@ -342,30 +342,44 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
static void nbd_refresh_filename(BlockDriverState *bs)
{
BDRVNBDState *s = bs->opaque;
QDict *opts = qdict_new();
const char *path = qemu_opt_get(s->socket_opts, "path");
const char *host = qemu_opt_get(s->socket_opts, "host");
const char *port = qemu_opt_get(s->socket_opts, "port");
const char *export = qemu_opt_get(s->socket_opts, "export");
const char *path = qdict_get_try_str(bs->options, "path");
const char *host = qdict_get_try_str(bs->options, "host");
const char *port = qdict_get_try_str(bs->options, "port");
const char *export = qdict_get_try_str(bs->options, "export");
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
if (path && export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:///%s?socket=%s", export, path);
} else if (path && !export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix://?socket=%s", path);
} else if (!path && export && port) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s/%s", host, port, export);
} else if (!path && export && !port) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s/%s", host, export);
} else if (!path && !export && port) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s:%s", host, port);
} else if (!path && !export && !port) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd://%s", host);
}
if (path) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd+unix:%s", path);
qdict_put_obj(opts, "path", QOBJECT(qstring_from_str(path)));
} else if (export) {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd:%s:%s/%s", host, port, export);
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(port)));
qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
} else {
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
"nbd:%s:%s", host, port);
} else if (port) {
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(port)));
} else {
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
}
if (export) {
qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
}
bs->full_open_options = opts;

View File

@@ -78,7 +78,7 @@ static coroutine_fn int null_co_flush(BlockDriverState *bs)
}
typedef struct {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
} NullAIOCB;
@@ -94,9 +94,9 @@ static void null_bh_cb(void *opaque)
qemu_aio_unref(acb);
}
static inline BlockDriverAIOCB *null_aio_common(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
BlockCompletionFunc *cb,
void *opaque)
{
NullAIOCB *acb;
@@ -106,27 +106,27 @@ static inline BlockDriverAIOCB *null_aio_common(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *null_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return null_aio_common(bs, cb, opaque);
}
static BlockDriverAIOCB *null_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *null_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return null_aio_common(bs, cb, opaque);
}
static BlockDriverAIOCB *null_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb,
void *opaque)
{
return null_aio_common(bs, cb, opaque);
}

View File

@@ -28,6 +28,7 @@
#include "qapi-visit.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp/types.h"
#include "sysemu/block-backend.h"
#ifdef __linux__
#include <linux/fs.h>
#include <sys/ioctl.h>
@@ -264,22 +265,22 @@ void bdrv_query_image_info(BlockDriverState *bs,
}
/* @p_info will be set only on success. */
void bdrv_query_info(BlockDriverState *bs,
BlockInfo **p_info,
Error **errp)
static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
Error **errp)
{
BlockInfo *info = g_malloc0(sizeof(*info));
BlockDriverState *bs = blk_bs(blk);
BlockDriverState *bs0;
ImageInfo **p_image_info;
Error *local_err = NULL;
info->device = g_strdup(bs->device_name);
info->device = g_strdup(blk_name(blk));
info->type = g_strdup("unknown");
info->locked = bdrv_dev_is_medium_locked(bs);
info->removable = bdrv_dev_has_removable_media(bs);
info->locked = blk_dev_is_medium_locked(blk);
info->removable = blk_dev_has_removable_media(blk);
if (bdrv_dev_has_removable_media(bs)) {
if (blk_dev_has_removable_media(blk)) {
info->has_tray_open = true;
info->tray_open = bdrv_dev_is_tray_open(bs);
info->tray_open = blk_dev_is_tray_open(blk);
}
if (bdrv_iostatus_is_enabled(bs)) {
@@ -327,9 +328,9 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
s = g_malloc0(sizeof(*s));
if (bs->device_name[0]) {
if (bdrv_get_device_name(bs)[0]) {
s->has_device = true;
s->device = g_strdup(bs->device_name);
s->device = g_strdup(bdrv_get_device_name(bs));
}
s->stats = g_malloc0(sizeof(*s->stats));
@@ -360,12 +361,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
BlockInfoList *qmp_query_block(Error **errp)
{
BlockInfoList *head = NULL, **p_next = &head;
BlockDriverState *bs = NULL;
BlockBackend *blk;
Error *local_err = NULL;
while ((bs = bdrv_next(bs))) {
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
BlockInfoList *info = g_malloc0(sizeof(*info));
bdrv_query_info(bs, &info->value, &local_err);
bdrv_query_info(blk, &info->value, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto err;

View File

@@ -124,7 +124,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
header.version);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "qcow", version);
bdrv_get_device_name(bs), "qcow", version);
ret = -ENOTSUP;
goto fail;
}
@@ -231,7 +231,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
/* Disable migration when qcow images are used */
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"qcow", bs->device_name, "live migration");
"qcow", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
qemu_co_mutex_init(&s->lock);

View File

@@ -164,12 +164,14 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
{
BDRVQcowState *s = bs->opaque;
uint64_t buf[L1_ENTRIES_PER_SECTOR];
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
int l1_start_index;
int i, ret;
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
i++)
{
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
}

File diff suppressed because it is too large Load Diff

View File

@@ -206,8 +206,8 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bs->device_name, "qcow2",
msg);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bdrv_get_device_name(bs), "qcow2", msg);
}
static void report_unsupported_feature(BlockDriverState *bs,
@@ -698,6 +698,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
s->l2_size = 1 << s->l2_bits;
/* 2^(s->refcount_order - 3) is the refcount width in bytes */
s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3);
s->refcount_block_size = 1 << s->refcount_block_bits;
bs->total_sectors = header.size / 512;
s->csize_shift = (62 - (s->cluster_bits - 8));
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
@@ -907,7 +910,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
BdrvCheckResult result = {0};
ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS);
ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not repair dirty image");
goto fail;
@@ -1871,7 +1874,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
.l1_size = cpu_to_be32(0),
.refcount_table_offset = cpu_to_be64(cluster_size),
.refcount_table_clusters = cpu_to_be32(1),
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
.refcount_order = cpu_to_be32(4),
.header_length = cpu_to_be32(sizeof(*header)),
};

View File

@@ -59,8 +59,6 @@
/* The cluster reads as all zeros */
#define QCOW_OFLAG_ZERO (1ULL << 0)
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
#define MIN_CLUSTER_BITS 9
#define MAX_CLUSTER_BITS 21
@@ -223,6 +221,8 @@ typedef struct BDRVQcowState {
int l2_size;
int l1_size;
int l1_vm_state_index;
int refcount_block_bits;
int refcount_block_size;
int csize_shift;
int csize_mask;
uint64_t cluster_offset_mask;

View File

@@ -13,7 +13,7 @@
#include "qed.h"
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
void *gencb_alloc(size_t len, BlockCompletionFunc *cb, void *opaque)
{
GenericCB *gencb = g_malloc(len);
gencb->cb = cb;
@@ -24,7 +24,7 @@ void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
void gencb_complete(void *opaque, int ret)
{
GenericCB *gencb = opaque;
BlockDriverCompletionFunc *cb = gencb->cb;
BlockCompletionFunc *cb = gencb->cb;
void *user_opaque = gencb->opaque;
g_free(gencb);

View File

@@ -49,7 +49,7 @@ out:
}
static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
cb, opaque);
@@ -119,7 +119,7 @@ out:
*/
static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
unsigned int index, unsigned int n, bool flush,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
QEDWriteTableCB *write_table_cb;
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
@@ -180,7 +180,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
}
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
qed_write_table(s, s->header.l1_table_offset,
@@ -235,7 +235,7 @@ static void qed_read_l2_table_cb(void *opaque, int ret)
}
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
QEDReadL2TableCB *read_l2_table_cb;
@@ -275,7 +275,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n, bool flush,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
qed_write_table(s, request->l2_table->offset,

View File

@@ -130,7 +130,7 @@ static void qed_write_header_read_cb(void *opaque, int ret)
* This function only updates known header fields in-place and does not affect
* extra data after the QED header.
*/
static void qed_write_header(BDRVQEDState *s, BlockDriverCompletionFunc cb,
static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
void *opaque)
{
/* We must write full sectors for O_DIRECT but cannot necessarily generate
@@ -408,7 +408,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
snprintf(buf, sizeof(buf), "%" PRIx64,
s->header.features & ~QED_FEATURE_MASK);
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "QED", buf);
bdrv_get_device_name(bs), "QED", buf);
return -ENOTSUP;
}
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
@@ -759,7 +759,7 @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
QEMUIOVector *qiov,
QEMUIOVector **backing_qiov,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
uint64_t backing_length = 0;
size_t size;
@@ -851,7 +851,7 @@ static void qed_copy_from_backing_file_write(void *opaque, int ret)
*/
static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
uint64_t len, uint64_t offset,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque)
{
CopyFromBackingFileCB *copy_cb;
@@ -902,7 +902,7 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
static void qed_aio_complete_bh(void *opaque)
{
QEDAIOCB *acb = opaque;
BlockDriverCompletionFunc *cb = acb->common.cb;
BlockCompletionFunc *cb = acb->common.cb;
void *user_opaque = acb->common.opaque;
int ret = acb->bh_ret;
@@ -1064,7 +1064,7 @@ static void qed_aio_write_main(void *opaque, int ret)
BDRVQEDState *s = acb_to_s(acb);
uint64_t offset = acb->cur_cluster +
qed_offset_into_cluster(s, acb->cur_pos);
BlockDriverCompletionFunc *next_fn;
BlockCompletionFunc *next_fn;
trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
@@ -1164,7 +1164,7 @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
{
BDRVQEDState *s = acb_to_s(acb);
BlockDriverCompletionFunc *cb;
BlockCompletionFunc *cb;
/* Cancel timer when the first allocating request comes in */
if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
@@ -1365,11 +1365,11 @@ static void qed_aio_next_io(void *opaque, int ret)
io_fn, acb);
}
static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque, int flags)
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb,
void *opaque, int flags)
{
QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
@@ -1390,20 +1390,20 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
return &acb->common;
}
static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
opaque, QED_AIOCB_WRITE);
@@ -1431,7 +1431,7 @@ static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
int nb_sectors,
BdrvRequestFlags flags)
{
BlockDriverAIOCB *blockacb;
BlockAIOCB *blockacb;
BDRVQEDState *s = bs->opaque;
QEDWriteZeroesCB cb = { .done = false };
QEMUIOVector qiov;

View File

@@ -128,7 +128,7 @@ enum {
};
typedef struct QEDAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
int bh_ret; /* final return status for completion bh */
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
@@ -203,11 +203,11 @@ typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t l
* Generic callback for chaining async callbacks
*/
typedef struct {
BlockDriverCompletionFunc *cb;
BlockCompletionFunc *cb;
void *opaque;
} GenericCB;
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
void *gencb_alloc(size_t len, BlockCompletionFunc *cb, void *opaque);
void gencb_complete(void *opaque, int ret);
/**
@@ -230,16 +230,16 @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
*/
int qed_read_l1_table_sync(BDRVQEDState *s);
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
BlockDriverCompletionFunc *cb, void *opaque);
BlockCompletionFunc *cb, void *opaque);
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
unsigned int n);
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
uint64_t offset);
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
BlockDriverCompletionFunc *cb, void *opaque);
BlockCompletionFunc *cb, void *opaque);
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n, bool flush,
BlockDriverCompletionFunc *cb, void *opaque);
BlockCompletionFunc *cb, void *opaque);
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n, bool flush);

View File

@@ -92,7 +92,7 @@ typedef struct QuorumAIOCB QuorumAIOCB;
* $children_count QuorumChildRequest.
*/
typedef struct QuorumChildRequest {
BlockDriverAIOCB *aiocb;
BlockAIOCB *aiocb;
QEMUIOVector qiov;
uint8_t *buf;
int ret;
@@ -105,7 +105,7 @@ typedef struct QuorumChildRequest {
* used to do operations on each children and track overall progress.
*/
struct QuorumAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
/* Request metadata */
uint64_t sector_num;
@@ -130,7 +130,7 @@ struct QuorumAIOCB {
static bool quorum_vote(QuorumAIOCB *acb);
static void quorum_aio_cancel(BlockDriverAIOCB *blockacb)
static void quorum_aio_cancel(BlockAIOCB *blockacb)
{
QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common);
BDRVQuorumState *s = acb->common.bs->opaque;
@@ -186,7 +186,7 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
QEMUIOVector *qiov,
uint64_t sector_num,
int nb_sectors,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque)
{
QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque);
@@ -226,8 +226,8 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
static void quorum_report_failure(QuorumAIOCB *acb)
{
const char *reference = acb->common.bs->device_name[0] ?
acb->common.bs->device_name :
const char *reference = bdrv_get_device_name(acb->common.bs)[0] ?
bdrv_get_device_name(acb->common.bs) :
acb->common.bs->node_name;
qapi_event_send_quorum_failure(reference, acb->sector_num,
@@ -264,7 +264,7 @@ static void quorum_rewrite_aio_cb(void *opaque, int ret)
quorum_aio_finalize(acb);
}
static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb);
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb);
static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source)
{
@@ -640,7 +640,7 @@ free_exit:
return rewrite;
}
static BlockDriverAIOCB *read_quorum_children(QuorumAIOCB *acb)
static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
{
BDRVQuorumState *s = acb->common.bs->opaque;
int i;
@@ -659,7 +659,7 @@ static BlockDriverAIOCB *read_quorum_children(QuorumAIOCB *acb)
return &acb->common;
}
static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb)
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
{
BDRVQuorumState *s = acb->common.bs->opaque;
@@ -675,12 +675,12 @@ static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb)
return &acb->common;
}
static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
BDRVQuorumState *s = bs->opaque;
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
@@ -696,12 +696,12 @@ static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs,
return read_fifo_child(acb);
}
static BlockDriverAIOCB *quorum_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
BDRVQuorumState *s = bs->opaque;
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors,

View File

@@ -35,9 +35,9 @@
#ifdef CONFIG_LINUX_AIO
void *laio_init(void);
void laio_cleanup(void *s);
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
BlockCompletionFunc *cb, void *opaque, int type);
void laio_detach_aio_context(void *s, AioContext *old_context);
void laio_attach_aio_context(void *s, AioContext *new_context);
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
@@ -49,10 +49,10 @@ typedef struct QEMUWin32AIOState QEMUWin32AIOState;
QEMUWin32AIOState *win32_aio_init(void);
void win32_aio_cleanup(QEMUWin32AIOState *aio);
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
QEMUWin32AIOState *aio, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
BlockCompletionFunc *cb, void *opaque, int type);
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
AioContext *old_context);
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,

View File

@@ -150,6 +150,7 @@ typedef struct BDRVRawState {
bool has_discard:1;
bool has_write_zeroes:1;
bool discard_zeroes:1;
bool needs_alignment;
#ifdef CONFIG_FIEMAP
bool skip_fiemap;
#endif
@@ -230,7 +231,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
/* For /dev/sg devices the alignment is not really used.
With buffered I/O, we don't have any restrictions. */
if (bs->sg || !(s->open_flags & O_DIRECT)) {
if (bs->sg || !s->needs_alignment) {
bs->request_alignment = 1;
s->buf_align = 1;
return;
@@ -446,6 +447,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->has_discard = true;
s->has_write_zeroes = true;
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
s->needs_alignment = true;
}
if (fstat(s->fd, &st) < 0) {
error_setg_errno(errp, errno, "Could not stat file");
@@ -472,6 +476,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
}
#endif
}
#ifdef __FreeBSD__
if (S_ISCHR(st.st_mode)) {
/*
* The file is a char device (disk), which on FreeBSD isn't behind
* a pager, so force all requests to be aligned. This is needed
* so QEMU makes sure all IO operations on the device are aligned
* to sector size, or else FreeBSD will reject them with EINVAL.
*/
s->needs_alignment = true;
}
#endif
#ifdef CONFIG_XFS
if (platform_test_xfs_fd(s->fd)) {
@@ -1041,9 +1056,9 @@ static int paio_submit_co(BlockDriverState *bs, int fd,
return thread_pool_submit_co(pool, aio_worker, acb);
}
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
BlockCompletionFunc *cb, void *opaque, int type)
{
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
ThreadPool *pool;
@@ -1066,9 +1081,9 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
}
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
static BlockAIOCB *raw_aio_submit(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
BlockCompletionFunc *cb, void *opaque, int type)
{
BDRVRawState *s = bs->opaque;
@@ -1076,11 +1091,12 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
return NULL;
/*
* If O_DIRECT is used the buffer needs to be aligned on a sector
* boundary. Check if this is the case or tell the low-level
* driver that it needs to copy the buffer.
* Check if the underlying device requires requests to be aligned,
* and if the request we are trying to submit is aligned or not.
* If this is the case tell the low-level driver that it needs
* to copy the buffer.
*/
if ((bs->open_flags & BDRV_O_NOCACHE)) {
if (s->needs_alignment) {
if (!bdrv_qiov_is_aligned(bs, qiov)) {
type |= QEMU_AIO_MISALIGNED;
#ifdef CONFIG_LINUX_AIO
@@ -1125,24 +1141,24 @@ static void raw_aio_flush_io_queue(BlockDriverState *bs)
#endif
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
static BlockAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_READ);
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_WRITE);
}
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
@@ -1482,7 +1498,7 @@ static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
f.fm.fm_start = start;
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
f.fm.fm_flags = 0;
f.fm.fm_flags = FIEMAP_FLAG_SYNC;
f.fm.fm_extent_count = 1;
f.fm.fm_reserved = 0;
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
@@ -1571,9 +1587,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
start = sector_num * BDRV_SECTOR_SIZE;
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
ret = try_seek_hole(bs, start, &data, &hole, pnum);
if (ret < 0) {
ret = try_seek_hole(bs, start, &data, &hole, pnum);
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
if (ret < 0) {
/* Assume everything is allocated. */
data = 0;
@@ -1595,9 +1611,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
return ret;
}
static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
static coroutine_fn BlockAIOCB *raw_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
@@ -1935,9 +1951,9 @@ static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return ioctl(s->fd, req, buf);
}
static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
RawPosixAIOData *acb;
@@ -1976,9 +1992,9 @@ static int fd_open(BlockDriverState *bs)
#endif /* !linux && !FreeBSD */
static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
static coroutine_fn BlockAIOCB *hdev_aio_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;

View File

@@ -138,9 +138,9 @@ static int aio_worker(void *arg)
return ret;
}
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
BlockCompletionFunc *cb, void *opaque, int type)
{
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
ThreadPool *pool;
@@ -369,9 +369,9 @@ fail:
return ret;
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
static BlockAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
if (s->aio) {
@@ -383,9 +383,9 @@ static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
}
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
if (s->aio) {
@@ -397,8 +397,8 @@ static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
}
}
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);

View File

@@ -129,10 +129,10 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return bdrv_ioctl(bs->file, req, buf);
}
static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockCompletionFunc *cb,
void *opaque)
{
return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
}

View File

@@ -68,7 +68,7 @@ typedef enum {
} RBDAIOCmd;
typedef struct RBDAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUBH *bh;
int64_t ret;
QEMUIOVector *qiov;
@@ -589,13 +589,13 @@ static int rbd_aio_flush_wrapper(rbd_image_t image,
#endif
}
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque,
RBDAIOCmd cmd)
static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque,
RBDAIOCmd cmd)
{
RBDAIOCB *acb;
RADOSCB *rcb = NULL;
@@ -675,32 +675,32 @@ failed:
return NULL;
}
static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
RBD_AIO_READ);
}
static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
int64_t sector_num,
QEMUIOVector *qiov,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
RBD_AIO_WRITE);
}
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
BlockCompletionFunc *cb,
void *opaque)
{
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
}
@@ -876,11 +876,11 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
}
#ifdef LIBRBD_SUPPORTS_DISCARD
static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors,
BlockDriverCompletionFunc *cb,
void *opaque)
static BlockAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors,
BlockCompletionFunc *cb,
void *opaque)
{
return rbd_start_aio(bs, sector_num, NULL, nb_sectors, cb, opaque,
RBD_AIO_DISCARD);

View File

@@ -301,7 +301,7 @@ enum AIOCBState {
};
struct SheepdogAIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
QEMUIOVector *qiov;
@@ -473,7 +473,7 @@ static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
return true;
}
static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
static void sd_aio_cancel(BlockAIOCB *blockacb)
{
SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
BDRVSheepdogState *s = acb->common.bs->opaque;

View File

@@ -220,7 +220,7 @@ static const BlockJobDriver stream_job_driver = {
void stream_start(BlockDriverState *bs, BlockDriverState *base,
const char *backing_file_str, int64_t speed,
BlockdevOnError on_error,
BlockDriverCompletionFunc *cb,
BlockCompletionFunc *cb,
void *opaque, Error **errp)
{
StreamBlockJob *s;

View File

@@ -407,8 +407,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
We accept them but round the disk size to the next multiple of
SECTOR_SIZE. */
logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
header.disk_size += SECTOR_SIZE - 1;
header.disk_size &= ~(SECTOR_SIZE - 1);
header.disk_size = ROUND_UP(header.disk_size, SECTOR_SIZE);
}
if (header.signature != VDI_SIGNATURE) {
@@ -475,7 +474,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
s->header = header;
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
bmap_size = DIV_ROUND_UP(bmap_size, SECTOR_SIZE);
s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE);
if (s->bmap == NULL) {
ret = -ENOMEM;
@@ -490,7 +489,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
/* Disable migration when vdi images are used */
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vdi", bs->device_name, "live migration");
"vdi", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
return 0;
@@ -736,10 +735,10 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
/* We need enough blocks to store the given disk size,
so always round up. */
blocks = (bytes + block_size - 1) / block_size;
blocks = DIV_ROUND_UP(bytes, block_size);
bmap_size = blocks * sizeof(uint32_t);
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
bmap_size = ROUND_UP(bmap_size, SECTOR_SIZE);
memset(&header, 0, sizeof(header));
pstrcpy(header.text, sizeof(header.text), VDI_TEXT);

View File

@@ -1004,7 +1004,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
/* Disable migration when VHDX images are used */
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vhdx", bs->device_name, "live migration");
"vhdx", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
return 0;

View File

@@ -657,7 +657,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
le32_to_cpu(header.version));
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
bs->device_name, "vmdk", buf);
bdrv_get_device_name(bs), "vmdk", buf);
return -ENOTSUP;
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
/* VMware KB 2064959 explains that version 3 added support for
@@ -939,7 +939,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
/* Disable migration when VMDK images are used */
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vmdk", bs->device_name, "live migration");
"vmdk", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
g_free(buf);
return 0;

View File

@@ -320,7 +320,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
/* Disable migration when VHD images are used */
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vpc", bs->device_name, "live migration");
"vpc", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
return 0;

View File

@@ -1182,7 +1182,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
if (s->qcow) {
error_set(&s->migration_blocker,
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
"vvfat (rw)", bs->device_name, "live migration");
"vvfat (rw)", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
}
@@ -2939,7 +2939,7 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
unlink(s->qcow_filename);
#endif
bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
bdrv_set_backing_hd(s->bs, bdrv_new());
s->bs->backing_hd->drv = &vvfat_write_target;
s->bs->backing_hd->opaque = g_new(void *, 1);
*(void**)s->bs->backing_hd->opaque = s;

View File

@@ -44,7 +44,7 @@ struct QEMUWin32AIOState {
};
typedef struct QEMUWin32AIOCB {
BlockDriverAIOCB common;
BlockAIOCB common;
struct QEMUWin32AIOState *ctx;
int nbytes;
OVERLAPPED ov;
@@ -110,10 +110,10 @@ static const AIOCBInfo win32_aiocb_info = {
.aiocb_size = sizeof(QEMUWin32AIOCB),
};
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
QEMUWin32AIOState *aio, HANDLE hfile,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
BlockCompletionFunc *cb, void *opaque, int type)
{
struct QEMUWin32AIOCB *waiocb;
uint64_t offset = sector_num * 512;

View File

@@ -30,6 +30,7 @@
* THE SOFTWARE.
*/
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "block/blockjob.h"
@@ -46,8 +47,6 @@
#include "trace.h"
#include "sysemu/arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
[IF_IDE] = "ide",
@@ -85,13 +84,15 @@ static int if_max_devs[IF_COUNT] = {
*/
void override_max_devs(BlockInterfaceType type, int max_devs)
{
BlockBackend *blk;
DriveInfo *dinfo;
if (max_devs <= 0) {
return;
}
QTAILQ_FOREACH(dinfo, &drives, next) {
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
dinfo = blk_legacy_dinfo(blk);
if (dinfo->type == type) {
fprintf(stderr, "Cannot override units-per-bus property of"
" the %s interface, because a drive of that type has"
@@ -110,28 +111,27 @@ void override_max_devs(BlockInterfaceType type, int max_devs)
* automatic deletion, and generic qdev code calls blockdev_auto_del()
* when deletion is actually safe.
*/
void blockdev_mark_auto_del(BlockDriverState *bs)
void blockdev_mark_auto_del(BlockBackend *blk)
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
DriveInfo *dinfo = blk_legacy_dinfo(blk);
BlockDriverState *bs = blk_bs(blk);
if (dinfo && !dinfo->enable_auto_del) {
if (!dinfo) {
return;
}
if (bs->job) {
block_job_cancel(bs->job);
}
if (dinfo) {
dinfo->auto_del = 1;
}
dinfo->auto_del = 1;
}
void blockdev_auto_del(BlockDriverState *bs)
void blockdev_auto_del(BlockBackend *blk)
{
DriveInfo *dinfo = drive_get_by_blockdev(bs);
DriveInfo *dinfo = blk_legacy_dinfo(blk);
if (dinfo && dinfo->auto_del) {
drive_del(dinfo);
blk_unref(blk);
}
}
@@ -193,15 +193,15 @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
{
BlockBackend *blk;
DriveInfo *dinfo;
/* seek interface, bus and unit */
QTAILQ_FOREACH(dinfo, &drives, next) {
if (dinfo->type == type &&
dinfo->bus == bus &&
dinfo->unit == unit)
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
dinfo = blk_legacy_dinfo(blk);
if (dinfo && dinfo->type == type
&& dinfo->bus == bus && dinfo->unit == unit) {
return dinfo;
}
}
return NULL;
@@ -209,17 +209,19 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
bool drive_check_orphaned(void)
{
BlockBackend *blk;
DriveInfo *dinfo;
bool rs = false;
QTAILQ_FOREACH(dinfo, &drives, next) {
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
dinfo = blk_legacy_dinfo(blk);
/* If dinfo->bdrv->dev is NULL, it has no device attached. */
/* Unless this is a default drive, this may be an oversight. */
if (!dinfo->bdrv->dev && !dinfo->is_default &&
if (!blk_get_attached_dev(blk) && !dinfo->is_default &&
dinfo->type != IF_NONE) {
fprintf(stderr, "Warning: Orphaned drive without device: "
"id=%s,file=%s,if=%s,bus=%d,unit=%d\n",
dinfo->id, dinfo->bdrv->filename, if_name[dinfo->type],
blk_name(blk), blk_bs(blk)->filename, if_name[dinfo->type],
dinfo->bus, dinfo->unit);
rs = true;
}
@@ -238,13 +240,15 @@ DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
int drive_get_max_bus(BlockInterfaceType type)
{
int max_bus;
BlockBackend *blk;
DriveInfo *dinfo;
max_bus = -1;
QTAILQ_FOREACH(dinfo, &drives, next) {
if(dinfo->type == type &&
dinfo->bus > max_bus)
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
dinfo = blk_legacy_dinfo(blk);
if (dinfo && dinfo->type == type && dinfo->bus > max_bus) {
max_bus = dinfo->bus;
}
}
return max_bus;
}
@@ -259,40 +263,11 @@ DriveInfo *drive_get_next(BlockInterfaceType type)
return drive_get(type, 0, next_block_unit[type]++);
}
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
{
DriveInfo *dinfo;
QTAILQ_FOREACH(dinfo, &drives, next) {
if (dinfo->bdrv == bs) {
return dinfo;
}
}
return NULL;
}
static void bdrv_format_print(void *opaque, const char *name)
{
error_printf(" %s", name);
}
void drive_del(DriveInfo *dinfo)
{
bdrv_unref(dinfo->bdrv);
}
void drive_info_del(DriveInfo *dinfo)
{
if (!dinfo) {
return;
}
qemu_opts_del(dinfo->opts);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
g_free(dinfo);
}
typedef struct {
QEMUBH *bh;
BlockDriverState *bs;
@@ -360,15 +335,15 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
/* Takes the ownership of bs_opts */
static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
Error **errp)
static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
Error **errp)
{
const char *buf;
int ro = 0;
int bdrv_flags = 0;
int on_read_error, on_write_error;
BlockBackend *blk;
BlockDriverState *bs;
DriveInfo *dinfo;
ThrottleConfig cfg;
int snapshot = 0;
bool copy_on_read;
@@ -523,10 +498,11 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
}
/* init */
bs = bdrv_new(qemu_opts_id(opts), errp);
if (!bs) {
blk = blk_new_with_bs(qemu_opts_id(opts), errp);
if (!blk) {
goto early_err;
}
bs = blk_bs(blk);
bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
bs->read_only = ro;
bs->detect_zeroes = detect_zeroes;
@@ -539,18 +515,13 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
bdrv_set_io_limits(bs, &cfg);
}
dinfo = g_malloc0(sizeof(*dinfo));
dinfo->id = g_strdup(qemu_opts_id(opts));
dinfo->bdrv = bs;
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
if (!file || !*file) {
if (has_driver_specific_opts) {
file = NULL;
} else {
QDECREF(bs_opts);
qemu_opts_del(opts);
return dinfo;
return blk;
}
}
if (snapshot) {
@@ -571,11 +542,11 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
QINCREF(bs_opts);
ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
assert(bs == dinfo->bdrv);
assert(bs == blk_bs(blk));
if (ret < 0) {
error_setg(errp, "could not open disk image %s: %s",
file ?: dinfo->id, error_get_pretty(error));
file ?: blk_name(blk), error_get_pretty(error));
error_free(error);
goto err;
}
@@ -587,10 +558,10 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
QDECREF(bs_opts);
qemu_opts_del(opts);
return dinfo;
return blk;
err:
bdrv_unref(bs);
blk_unref(blk);
early_err:
qemu_opts_del(opts);
err_no_opts:
@@ -703,6 +674,7 @@ QemuOptsList qemu_legacy_drive_opts = {
DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
{
const char *value;
BlockBackend *blk;
DriveInfo *dinfo = NULL;
QDict *bs_opts;
QemuOpts *legacy_opts;
@@ -1000,9 +972,9 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
}
/* Actual block device init: Functionality shared with blockdev-add */
dinfo = blockdev_init(filename, bs_opts, &local_err);
blk = blockdev_init(filename, bs_opts, &local_err);
bs_opts = NULL;
if (dinfo == NULL) {
if (!blk) {
if (local_err) {
error_report("%s", error_get_pretty(local_err));
error_free(local_err);
@@ -1012,8 +984,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
assert(!local_err);
}
/* Set legacy DriveInfo fields */
dinfo->enable_auto_del = true;
/* Create legacy DriveInfo */
dinfo = g_malloc0(sizeof(*dinfo));
dinfo->opts = all_opts;
dinfo->cyls = cyls;
@@ -1025,9 +997,10 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
dinfo->bus = bus_id;
dinfo->unit = unit_id;
dinfo->devaddr = devaddr;
dinfo->serial = g_strdup(serial);
blk_set_legacy_dinfo(blk, dinfo);
switch(type) {
case IF_IDE:
case IF_SCSI:
@@ -1620,19 +1593,21 @@ exit:
}
static void eject_device(BlockDriverState *bs, int force, Error **errp)
static void eject_device(BlockBackend *blk, int force, Error **errp)
{
BlockDriverState *bs = blk_bs(blk);
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
return;
}
if (!bdrv_dev_has_removable_media(bs)) {
if (!blk_dev_has_removable_media(blk)) {
error_setg(errp, "Device '%s' is not removable",
bdrv_get_device_name(bs));
return;
}
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
bdrv_dev_eject_request(bs, force);
if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
blk_dev_eject_request(blk, force);
if (!force) {
error_setg(errp, "Device '%s' is locked",
bdrv_get_device_name(bs));
@@ -1645,15 +1620,15 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp)
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{
BlockDriverState *bs;
BlockBackend *blk;
bs = bdrv_find(device);
if (!bs) {
blk = blk_by_name(device);
if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
eject_device(bs, force, errp);
eject_device(blk, force, errp);
}
void qmp_block_passwd(bool has_device, const char *device,
@@ -1712,16 +1687,18 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
void qmp_change_blockdev(const char *device, const char *filename,
const char *format, Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
BlockDriver *drv = NULL;
int bdrv_flags;
Error *err = NULL;
bs = bdrv_find(device);
if (!bs) {
blk = blk_by_name(device);
if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
bs = blk_bs(blk);
if (format) {
drv = bdrv_find_whitelisted_format(format, bs->read_only);
@@ -1731,7 +1708,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
}
}
eject_device(bs, 0, &err);
eject_device(blk, 0, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -1829,19 +1806,19 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
BlockBackend *blk;
BlockDriverState *bs;
DriveInfo *dinfo;
AioContext *aio_context;
Error *local_err = NULL;
bs = bdrv_find(id);
if (!bs) {
blk = blk_by_name(id);
if (!blk) {
error_report("Device '%s' not found", id);
return -1;
}
bs = blk_bs(blk);
dinfo = drive_get_by_blockdev(bs);
if (dinfo && !dinfo->enable_auto_del) {
if (!blk_legacy_dinfo(blk)) {
error_report("Deleting device added with blockdev-add"
" is not supported");
return -1;
@@ -1867,14 +1844,13 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
* can be removed. If this is a drive with no device backing
* then we can just get rid of the block driver state right here.
*/
if (bdrv_get_attached_dev(bs)) {
bdrv_make_anon(bs);
if (blk_get_attached_dev(blk)) {
blk_hide_on_behalf_of_do_drive_del(blk);
/* Further I/O must not pause the guest */
bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT);
} else {
drive_del(dinfo);
blk_unref(blk);
}
aio_context_release(aio_context);
@@ -2566,7 +2542,7 @@ void qmp_change_backing_file(const char *device,
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
{
QmpOutputVisitor *ov = qmp_output_visitor_new();
DriveInfo *dinfo;
BlockBackend *blk;
QObject *obj;
QDict *qdict;
Error *local_err = NULL;
@@ -2604,14 +2580,14 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
qdict_flatten(qdict);
dinfo = blockdev_init(NULL, qdict, &local_err);
blk = blockdev_init(NULL, qdict, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto fail;
}
if (bdrv_key_required(dinfo->bdrv)) {
drive_del(dinfo);
if (bdrv_key_required(blk_bs(blk))) {
blk_unref(blk);
error_setg(errp, "blockdev-add doesn't support encrypted devices");
goto fail;
}
@@ -2620,26 +2596,21 @@ fail:
qmp_output_visitor_cleanup(ov);
}
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
{
BlockJobInfoList **prev = opaque;
BlockJob *job = bs->job;
if (job) {
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
elem->value = block_job_query(bs->job);
(*prev)->next = elem;
*prev = elem;
}
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{
/* Dummy is a fake list element for holding the head pointer */
BlockJobInfoList dummy = {};
BlockJobInfoList *prev = &dummy;
bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
return dummy.next;
BlockJobInfoList *head = NULL, **p_next = &head;
BlockDriverState *bs;
for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
if (bs->job) {
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
elem->value = block_job_query(bs->job);
*p_next = elem;
p_next = &elem->next;
}
}
return head;
}
QemuOptsList qemu_common_drive_opts = {

View File

@@ -36,7 +36,7 @@
#include "qapi-event.h"
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
int64_t speed, BlockDriverCompletionFunc *cb,
int64_t speed, BlockCompletionFunc *cb,
void *opaque, Error **errp)
{
BlockJob *job;
@@ -107,7 +107,8 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
void block_job_complete(BlockJob *job, Error **errp)
{
if (job->paused || job->cancelled || !job->driver->complete) {
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
error_set(errp, QERR_BLOCK_JOB_NOT_READY,
bdrv_get_device_name(job->bs));
return;
}
@@ -154,7 +155,7 @@ void block_job_iostatus_reset(BlockJob *job)
struct BlockCancelData {
BlockJob *job;
BlockDriverCompletionFunc *cb;
BlockCompletionFunc *cb;
void *opaque;
bool cancelled;
int ret;

6
configure vendored
View File

@@ -4211,9 +4211,9 @@ EOF
fi
fi
# add pixman flags after all config tests are done
QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags $fdt_cflags"
libs_softmmu="$libs_softmmu $pixman_libs"
# prepend pixman and ftd flags after all config tests are done
QEMU_CFLAGS="$pixman_cflags $fdt_cflags $QEMU_CFLAGS"
libs_softmmu="$pixman_libs $libs_softmmu"
echo "Install prefix $prefix"
echo "BIOS directory `eval echo $qemu_datadir`"

View File

@@ -24,6 +24,7 @@
#include "hw/hw.h"
#include "hw/boards.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "qemu/config-file.h"
#include "sysemu/sysemu.h"
@@ -76,6 +77,6 @@ void drive_hot_add(Monitor *mon, const QDict *qdict)
err:
if (dinfo) {
drive_del(dinfo);
blk_unref(blk_by_legacy_dinfo(dinfo));
}
}

View File

@@ -39,7 +39,7 @@ public:
~QEMUDisassembler() { }
protected:
void ProcessOutput(Instruction *instr) {
virtual void ProcessOutput(const Instruction *instr) {
fprintf(stream_, "%08" PRIx32 " %s",
instr->InstructionBits(), GetOutput());
}

View File

@@ -2,7 +2,7 @@
The code in this directory is a subset of libvixl:
https://github.com/armvixl/vixl
(specifically, it is the set of files needed for disassembly only,
taken from libvixl 1.5).
taken from libvixl 1.6).
Bugfixes should preferably be sent upstream initially.
The disassembler does not currently support the entire A64 instruction

View File

@@ -32,6 +32,7 @@
#include "globals.h"
#include "utils.h"
#include "code-buffer.h"
#include "a64/instructions-a64.h"
namespace vixl {
@@ -168,6 +169,11 @@ class CPURegister {
return type_ == kFPRegister;
}
bool IsW() const { return IsValidRegister() && Is32Bits(); }
bool IsX() const { return IsValidRegister() && Is64Bits(); }
bool IsS() const { return IsValidFPRegister() && Is32Bits(); }
bool IsD() const { return IsValidFPRegister() && Is64Bits(); }
const Register& W() const;
const Register& X() const;
const FPRegister& S() const;
@@ -191,12 +197,12 @@ class CPURegister {
class Register : public CPURegister {
public:
explicit Register() : CPURegister() {}
Register() : CPURegister() {}
inline explicit Register(const CPURegister& other)
: CPURegister(other.code(), other.size(), other.type()) {
VIXL_ASSERT(IsValidRegister());
}
explicit Register(unsigned code, unsigned size)
Register(unsigned code, unsigned size)
: CPURegister(code, size, kRegister) {}
bool IsValid() const {
@@ -536,7 +542,7 @@ class Operand {
class MemOperand {
public:
explicit MemOperand(Register base,
ptrdiff_t offset = 0,
int64_t offset = 0,
AddrMode addrmode = Offset);
explicit MemOperand(Register base,
Register regoffset,
@@ -552,7 +558,7 @@ class MemOperand {
const Register& base() const { return base_; }
const Register& regoffset() const { return regoffset_; }
ptrdiff_t offset() const { return offset_; }
int64_t offset() const { return offset_; }
AddrMode addrmode() const { return addrmode_; }
Shift shift() const { return shift_; }
Extend extend() const { return extend_; }
@@ -565,7 +571,7 @@ class MemOperand {
private:
Register base_;
Register regoffset_;
ptrdiff_t offset_;
int64_t offset_;
AddrMode addrmode_;
Shift shift_;
Extend extend_;
@@ -680,32 +686,80 @@ class Label {
};
// TODO: Obtain better values for these, based on real-world data.
const int kLiteralPoolCheckInterval = 4 * KBytes;
const int kRecommendedLiteralPoolRange = 2 * kLiteralPoolCheckInterval;
// A literal is a 32-bit or 64-bit piece of data stored in the instruction
// stream and loaded through a pc relative load. The same literal can be
// referred to by multiple instructions but a literal can only reside at one
// place in memory. A literal can be used by a load before or after being
// placed in memory.
//
// Internally an offset of 0 is associated with a literal which has been
// neither used nor placed. Then two possibilities arise:
// 1) the label is placed, the offset (stored as offset + 1) is used to
// resolve any subsequent load using the label.
// 2) the label is not placed and offset is the offset of the last load using
// the literal (stored as -offset -1). If multiple loads refer to this
// literal then the last load holds the offset of the preceding load and
// all loads form a chain. Once the offset is placed all the loads in the
// chain are resolved and future loads fall back to possibility 1.
class RawLiteral {
public:
RawLiteral() : size_(0), offset_(0), raw_value_(0) {}
size_t size() {
VIXL_STATIC_ASSERT(kDRegSizeInBytes == kXRegSizeInBytes);
VIXL_STATIC_ASSERT(kSRegSizeInBytes == kWRegSizeInBytes);
VIXL_ASSERT((size_ == kXRegSizeInBytes) || (size_ == kWRegSizeInBytes));
return size_;
}
uint64_t raw_value64() {
VIXL_ASSERT(size_ == kXRegSizeInBytes);
return raw_value_;
}
uint32_t raw_value32() {
VIXL_ASSERT(size_ == kWRegSizeInBytes);
VIXL_ASSERT(is_uint32(raw_value_) || is_int32(raw_value_));
return static_cast<uint32_t>(raw_value_);
}
bool IsUsed() { return offset_ < 0; }
bool IsPlaced() { return offset_ > 0; }
// Control whether a branch over the literal pool should also be emitted. This
// is needed if the literal pool has to be emitted in the middle of the JITted
// code.
enum LiteralPoolEmitOption {
JumpRequired,
NoJumpRequired
protected:
ptrdiff_t offset() {
VIXL_ASSERT(IsPlaced());
return offset_ - 1;
}
void set_offset(ptrdiff_t offset) {
VIXL_ASSERT(offset >= 0);
VIXL_ASSERT(IsWordAligned(offset));
VIXL_ASSERT(!IsPlaced());
offset_ = offset + 1;
}
ptrdiff_t last_use() {
VIXL_ASSERT(IsUsed());
return -offset_ - 1;
}
void set_last_use(ptrdiff_t offset) {
VIXL_ASSERT(offset >= 0);
VIXL_ASSERT(IsWordAligned(offset));
VIXL_ASSERT(!IsPlaced());
offset_ = -offset - 1;
}
size_t size_;
ptrdiff_t offset_;
uint64_t raw_value_;
friend class Assembler;
};
// Literal pool entry.
class Literal {
template <typename T>
class Literal : public RawLiteral {
public:
Literal(Instruction* pc, uint64_t imm, unsigned size)
: pc_(pc), value_(imm), size_(size) {}
private:
Instruction* pc_;
int64_t value_;
unsigned size_;
friend class Assembler;
explicit Literal(T value) {
size_ = sizeof(value);
memcpy(&raw_value_, &value, sizeof(value));
}
};
@@ -750,7 +804,9 @@ enum LoadStoreScalingOption {
// Assembler.
class Assembler {
public:
Assembler(byte* buffer, unsigned buffer_size,
Assembler(size_t capacity,
PositionIndependentCodeOption pic = PositionIndependentCode);
Assembler(byte* buffer, size_t capacity,
PositionIndependentCodeOption pic = PositionIndependentCode);
// The destructor asserts that one of the following is true:
@@ -763,9 +819,6 @@ class Assembler {
// Start generating code from the beginning of the buffer, discarding any code
// and data that has already been emitted into the buffer.
//
// In order to avoid any accidental transfer of state, Reset ASSERTs that the
// constant pool is not blocked.
void Reset();
// Finalize a code buffer of generated instructions. This function must be
@@ -776,13 +829,47 @@ class Assembler {
// Bind a label to the current PC.
void bind(Label* label);
// Bind a label to a specified offset from the start of the buffer.
void BindToOffset(Label* label, ptrdiff_t offset);
// Place a literal at the current PC.
void place(RawLiteral* literal);
ptrdiff_t CursorOffset() const {
return buffer_->CursorOffset();
}
ptrdiff_t BufferEndOffset() const {
return static_cast<ptrdiff_t>(buffer_->capacity());
}
// Return the address of an offset in the buffer.
template <typename T>
inline T GetOffsetAddress(ptrdiff_t offset) {
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
return buffer_->GetOffsetAddress<T>(offset);
}
// Return the address of a bound label.
template <typename T>
inline T GetLabelAddress(const Label * label) {
VIXL_ASSERT(label->IsBound());
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
VIXL_STATIC_ASSERT(sizeof(*buffer_) == 1);
return reinterpret_cast<T>(buffer_ + label->location());
return GetOffsetAddress<T>(label->location());
}
// Return the address of the cursor.
template <typename T>
inline T GetCursorAddress() {
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
return GetOffsetAddress<T>(CursorOffset());
}
// Return the address of the start of the buffer.
template <typename T>
inline T GetStartAddress() {
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
return GetOffsetAddress<T>(0);
}
// Instruction set functions.
@@ -1324,14 +1411,17 @@ class Assembler {
void stnp(const CPURegister& rt, const CPURegister& rt2,
const MemOperand& dst);
// Load literal to register.
void ldr(const Register& rt, uint64_t imm);
// Load integer or FP register from literal pool.
void ldr(const CPURegister& rt, RawLiteral* literal);
// Load double precision floating point literal to FP register.
void ldr(const FPRegister& ft, double imm);
// Load word with sign extension from literal pool.
void ldrsw(const Register& rt, RawLiteral* literal);
// Load single precision floating point literal to FP register.
void ldr(const FPRegister& ft, float imm);
// Load integer or FP register from pc + imm19 << 2.
void ldr(const CPURegister& rt, int imm19);
// Load word with sign extension from pc + imm19 << 2.
void ldrsw(const Register& rt, int imm19);
// Store exclusive byte.
void stxrb(const Register& rs, const Register& rt, const MemOperand& dst);
@@ -1618,25 +1708,26 @@ class Assembler {
inline void dci(Instr raw_inst) { Emit(raw_inst); }
// Emit 32 bits of data into the instruction stream.
inline void dc32(uint32_t data) { EmitData(&data, sizeof(data)); }
inline void dc32(uint32_t data) {
VIXL_ASSERT(buffer_monitor_ > 0);
buffer_->Emit32(data);
}
// Emit 64 bits of data into the instruction stream.
inline void dc64(uint64_t data) { EmitData(&data, sizeof(data)); }
inline void dc64(uint64_t data) {
VIXL_ASSERT(buffer_monitor_ > 0);
buffer_->Emit64(data);
}
// Copy a string into the instruction stream, including the terminating NULL
// character. The instruction pointer (pc_) is then aligned correctly for
// character. The instruction pointer is then aligned correctly for
// subsequent instructions.
void EmitStringData(const char * string) {
void EmitString(const char * string) {
VIXL_ASSERT(string != NULL);
VIXL_ASSERT(buffer_monitor_ > 0);
size_t len = strlen(string) + 1;
EmitData(string, len);
// Pad with NULL characters until pc_ is aligned.
const char pad[] = {'\0', '\0', '\0', '\0'};
VIXL_STATIC_ASSERT(sizeof(pad) == kInstructionSize);
Instruction* next_pc = AlignUp(pc_, kInstructionSize);
EmitData(&pad, next_pc - pc_);
buffer_->EmitString(string);
buffer_->Align();
}
// Code generation helpers.
@@ -1912,43 +2003,39 @@ class Assembler {
return scale << FPScale_offset;
}
// Size of the code generated in bytes
size_t SizeOfCodeGenerated() const {
VIXL_ASSERT((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_)));
return pc_ - buffer_;
}
// Size of the code generated since label to the current position.
size_t SizeOfCodeGeneratedSince(Label* label) const {
size_t pc_offset = SizeOfCodeGenerated();
VIXL_ASSERT(label->IsBound());
VIXL_ASSERT(pc_offset >= static_cast<size_t>(label->location()));
VIXL_ASSERT(pc_offset < buffer_size_);
return pc_offset - label->location();
return buffer_->OffsetFrom(label->location());
}
size_t BufferCapacity() const { return buffer_->capacity(); }
inline void BlockLiteralPool() {
literal_pool_monitor_++;
}
size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); }
inline void ReleaseLiteralPool() {
if (--literal_pool_monitor_ == 0) {
// Has the literal pool been blocked for too long?
VIXL_ASSERT(literals_.empty() ||
(pc_ < (literals_.back()->pc_ + kMaxLoadLiteralRange)));
void EnsureSpaceFor(size_t amount) {
if (buffer_->RemainingBytes() < amount) {
size_t capacity = buffer_->capacity();
size_t size = buffer_->CursorOffset();
do {
// TODO(all): refine.
capacity *= 2;
} while ((capacity - size) < amount);
buffer_->Grow(capacity);
}
}
inline bool IsLiteralPoolBlocked() {
return literal_pool_monitor_ != 0;
#ifdef DEBUG
void AcquireBuffer() {
VIXL_ASSERT(buffer_monitor_ >= 0);
buffer_monitor_++;
}
void CheckLiteralPool(LiteralPoolEmitOption option = JumpRequired);
void EmitLiteralPool(LiteralPoolEmitOption option = NoJumpRequired);
size_t LiteralPoolSize();
void ReleaseBuffer() {
buffer_monitor_--;
VIXL_ASSERT(buffer_monitor_ >= 0);
}
#endif
inline PositionIndependentCodeOption pic() {
return pic_;
@@ -1959,22 +2046,30 @@ class Assembler {
(pic() == PositionDependentCode);
}
protected:
inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const {
static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) {
return reg.Is64Bits() ? xzr : wzr;
}
protected:
void LoadStore(const CPURegister& rt,
const MemOperand& addr,
LoadStoreOp op,
LoadStoreScalingOption option = PreferScaledOffset);
static bool IsImmLSUnscaled(ptrdiff_t offset);
static bool IsImmLSScaled(ptrdiff_t offset, LSDataSize size);
static bool IsImmLSUnscaled(int64_t offset);
static bool IsImmLSScaled(int64_t offset, LSDataSize size);
void LoadStorePair(const CPURegister& rt,
const CPURegister& rt2,
const MemOperand& addr,
LoadStorePairOp op);
static bool IsImmLSPair(int64_t offset, LSDataSize size);
// TODO(all): The third parameter should be passed by reference but gcc 4.8.2
// reports a bogus uninitialised warning then.
void Logical(const Register& rd,
const Register& rn,
const Operand& operand,
const Operand operand,
LogicalOp op);
void LogicalImmediate(const Register& rd,
const Register& rn,
@@ -2035,6 +2130,7 @@ class Assembler {
const CPURegister& rt, const CPURegister& rt2);
static LoadStorePairNonTemporalOp StorePairNonTemporalOpFor(
const CPURegister& rt, const CPURegister& rt2);
static LoadLiteralOp LoadLiteralOpFor(const CPURegister& rt);
private:
@@ -2053,10 +2149,6 @@ class Assembler {
const Operand& operand,
FlagsUpdate S,
Instr op);
void LoadStorePair(const CPURegister& rt,
const CPURegister& rt2,
const MemOperand& addr,
LoadStorePairOp op);
void LoadStorePairNonTemporal(const CPURegister& rt,
const CPURegister& rt2,
const MemOperand& addr,
@@ -2088,8 +2180,6 @@ class Assembler {
const FPRegister& fa,
FPDataProcessing3SourceOp op);
void RecordLiteral(int64_t imm, unsigned size);
// Link the current (not-yet-emitted) instruction to the specified label, then
// return an offset to be encoded in the instruction. If the label is not yet
// bound, an offset of 0 is returned.
@@ -2098,79 +2188,102 @@ class Assembler {
ptrdiff_t LinkAndGetPageOffsetTo(Label * label);
// A common implementation for the LinkAndGet<Type>OffsetTo helpers.
template <int element_size>
template <int element_shift>
ptrdiff_t LinkAndGetOffsetTo(Label* label);
// Emit the instruction at pc_.
// Literal load offset are in words (32-bit).
ptrdiff_t LinkAndGetWordOffsetTo(RawLiteral* literal);
// Emit the instruction in buffer_.
void Emit(Instr instruction) {
VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize);
VIXL_ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_));
#ifdef DEBUG
finalized_ = false;
#endif
memcpy(pc_, &instruction, sizeof(instruction));
pc_ += sizeof(instruction);
CheckBufferSpace();
VIXL_ASSERT(buffer_monitor_ > 0);
buffer_->Emit32(instruction);
}
// Emit data inline in the instruction stream.
void EmitData(void const * data, unsigned size) {
VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
VIXL_ASSERT((pc_ + size) <= (buffer_ + buffer_size_));
#ifdef DEBUG
finalized_ = false;
#endif
// TODO: Record this 'instruction' as data, so that it can be disassembled
// correctly.
memcpy(pc_, data, size);
pc_ += size;
CheckBufferSpace();
}
inline void CheckBufferSpace() {
VIXL_ASSERT(pc_ < (buffer_ + buffer_size_));
if (pc_ > next_literal_pool_check_) {
CheckLiteralPool();
}
}
// The buffer into which code and relocation info are generated.
Instruction* buffer_;
// Buffer size, in bytes.
size_t buffer_size_;
Instruction* pc_;
std::list<Literal*> literals_;
Instruction* next_literal_pool_check_;
unsigned literal_pool_monitor_;
// Buffer where the code is emitted.
CodeBuffer* buffer_;
PositionIndependentCodeOption pic_;
friend class Label;
friend class BlockLiteralPoolScope;
#ifdef DEBUG
bool finalized_;
int64_t buffer_monitor_;
#endif
};
class BlockLiteralPoolScope {
// All Assembler emits MUST acquire/release the underlying code buffer. The
// helper scope below will do so and optionally ensure the buffer is big enough
// to receive the emit. It is possible to request the scope not to perform any
// checks (kNoCheck) if for example it is known in advance the buffer size is
// adequate or there is some other size checking mechanism in place.
class CodeBufferCheckScope {
public:
explicit BlockLiteralPoolScope(Assembler* assm) : assm_(assm) {
assm_->BlockLiteralPool();
// Tell whether or not the scope needs to ensure the associated CodeBuffer
// has enough space for the requested size.
enum CheckPolicy {
kNoCheck,
kCheck
};
// Tell whether or not the scope should assert the amount of code emitted
// within the scope is consistent with the requested amount.
enum AssertPolicy {
kNoAssert, // No assert required.
kExactSize, // The code emitted must be exactly size bytes.
kMaximumSize // The code emitted must be at most size bytes.
};
CodeBufferCheckScope(Assembler* assm,
size_t size,
CheckPolicy check_policy = kCheck,
AssertPolicy assert_policy = kMaximumSize)
: assm_(assm) {
if (check_policy == kCheck) assm->EnsureSpaceFor(size);
#ifdef DEBUG
assm->bind(&start_);
size_ = size;
assert_policy_ = assert_policy;
assm->AcquireBuffer();
#else
USE(assert_policy);
#endif
}
~BlockLiteralPoolScope() {
assm_->ReleaseLiteralPool();
// This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert).
explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) {
#ifdef DEBUG
size_ = 0;
assert_policy_ = kNoAssert;
assm->AcquireBuffer();
#endif
}
private:
~CodeBufferCheckScope() {
#ifdef DEBUG
assm_->ReleaseBuffer();
switch (assert_policy_) {
case kNoAssert: break;
case kExactSize:
VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) == size_);
break;
case kMaximumSize:
VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) <= size_);
break;
default:
VIXL_UNREACHABLE();
}
#endif
}
protected:
Assembler* assm_;
#ifdef DEBUG
Label start_;
size_t size_;
AssertPolicy assert_policy_;
#endif
};
} // namespace vixl
#endif // VIXL_A64_ASSEMBLER_A64_H_

View File

@@ -29,8 +29,8 @@
#include "a64/decoder-a64.h"
namespace vixl {
// Top-level instruction decode function.
void Decoder::Decode(Instruction *instr) {
void Decoder::DecodeInstruction(const Instruction *instr) {
if (instr->Bits(28, 27) == 0) {
VisitUnallocated(instr);
} else {
@@ -109,20 +109,17 @@ void Decoder::Decode(Instruction *instr) {
}
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
visitors_.remove(new_visitor);
visitors_.push_front(new_visitor);
visitors_.push_back(new_visitor);
}
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
visitors_.remove(new_visitor);
visitors_.push_back(new_visitor);
visitors_.push_front(new_visitor);
}
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
@@ -139,7 +136,6 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor) {
visitors_.remove(new_visitor);
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
if (*it == registered_visitor) {
@@ -160,7 +156,7 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
}
void Decoder::DecodePCRelAddressing(Instruction* instr) {
void Decoder::DecodePCRelAddressing(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x0);
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
// decode.
@@ -169,7 +165,7 @@ void Decoder::DecodePCRelAddressing(Instruction* instr) {
}
void Decoder::DecodeBranchSystemException(Instruction* instr) {
void Decoder::DecodeBranchSystemException(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
(instr->Bits(27, 24) == 0x5) ||
(instr->Bits(27, 24) == 0x6) ||
@@ -270,7 +266,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
}
void Decoder::DecodeLoadStore(Instruction* instr) {
void Decoder::DecodeLoadStore(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
(instr->Bits(27, 24) == 0x9) ||
(instr->Bits(27, 24) == 0xC) ||
@@ -388,7 +384,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
}
void Decoder::DecodeLogical(Instruction* instr) {
void Decoder::DecodeLogical(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
if (instr->Mask(0x80400000) == 0x00400000) {
@@ -407,7 +403,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
}
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
void Decoder::DecodeBitfieldExtract(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
if ((instr->Mask(0x80400000) == 0x80000000) ||
@@ -432,7 +428,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
}
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
void Decoder::DecodeAddSubImmediate(const Instruction* instr) {
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
if (instr->Bit(23) == 1) {
VisitUnallocated(instr);
@@ -442,7 +438,7 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
}
void Decoder::DecodeDataProcessing(Instruction* instr) {
void Decoder::DecodeDataProcessing(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
(instr->Bits(27, 24) == 0xB));
@@ -557,7 +553,7 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
}
void Decoder::DecodeFP(Instruction* instr) {
void Decoder::DecodeFP(const Instruction* instr) {
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
(instr->Bits(27, 24) == 0xF));
@@ -684,14 +680,14 @@ void Decoder::DecodeFP(Instruction* instr) {
}
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
void Decoder::DecodeAdvSIMDLoadStore(const Instruction* instr) {
// TODO: Implement Advanced SIMD load/store instruction decode.
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
VisitUnimplemented(instr);
}
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
void Decoder::DecodeAdvSIMDDataProcessing(const Instruction* instr) {
// TODO: Implement Advanced SIMD data processing instruction decode.
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
VisitUnimplemented(instr);
@@ -699,7 +695,7 @@ void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
#define DEFINE_VISITOR_CALLERS(A) \
void Decoder::Visit##A(Instruction *instr) { \
void Decoder::Visit##A(const Instruction *instr) { \
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
std::list<DecoderVisitor*>::iterator it; \
for (it = visitors_.begin(); it != visitors_.end(); it++) { \

View File

@@ -88,112 +88,152 @@ namespace vixl {
// must provide implementations for all of these functions.
class DecoderVisitor {
public:
#define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
VISITOR_LIST(DECLARE)
#undef DECLARE
enum VisitorConstness {
kConstVisitor,
kNonConstVisitor
};
explicit DecoderVisitor(VisitorConstness constness = kConstVisitor)
: constness_(constness) {}
virtual ~DecoderVisitor() {}
private:
// Visitors are registered in a list.
std::list<DecoderVisitor*> visitors_;
#define DECLARE(A) virtual void Visit##A(const Instruction* instr) = 0;
VISITOR_LIST(DECLARE)
#undef DECLARE
friend class Decoder;
bool IsConstVisitor() const { return constness_ == kConstVisitor; }
Instruction* MutableInstruction(const Instruction* instr) {
VIXL_ASSERT(!IsConstVisitor());
return const_cast<Instruction*>(instr);
}
private:
VisitorConstness constness_;
};
class Decoder: public DecoderVisitor {
class Decoder {
public:
Decoder() {}
// Top-level instruction decoder function. Decodes an instruction and calls
// the visitor functions registered with the Decoder class.
void Decode(Instruction *instr);
// Top-level wrappers around the actual decoding function.
void Decode(const Instruction* instr) {
std::list<DecoderVisitor*>::iterator it;
for (it = visitors_.begin(); it != visitors_.end(); it++) {
VIXL_ASSERT((*it)->IsConstVisitor());
}
DecodeInstruction(instr);
}
void Decode(Instruction* instr) {
DecodeInstruction(const_cast<const Instruction*>(instr));
}
// Register a new visitor class with the decoder.
// Decode() will call the corresponding visitor method from all registered
// visitor classes when decoding reaches the leaf node of the instruction
// decode tree.
// Visitors are called in the order.
// A visitor can only be registered once.
// Registering an already registered visitor will update its position.
// Visitors are called in order.
// A visitor can be registered multiple times.
//
// d.AppendVisitor(V1);
// d.AppendVisitor(V2);
// d.PrependVisitor(V2); // Move V2 at the start of the list.
// d.InsertVisitorBefore(V3, V2);
// d.AppendVisitor(V4);
// d.AppendVisitor(V4); // No effect.
// d.PrependVisitor(V2);
// d.AppendVisitor(V3);
//
// d.Decode(i);
//
// will call in order visitor methods in V3, V2, V1, V4.
// will call in order visitor methods in V2, V1, V2, V3.
void AppendVisitor(DecoderVisitor* visitor);
void PrependVisitor(DecoderVisitor* visitor);
// These helpers register `new_visitor` before or after the first instance of
// `registered_visiter` in the list.
// So if
// V1, V2, V1, V2
// are registered in this order in the decoder, calls to
// d.InsertVisitorAfter(V3, V1);
// d.InsertVisitorBefore(V4, V2);
// will yield the order
// V1, V3, V4, V2, V1, V2
//
// For more complex modifications of the order of registered visitors, one can
// directly access and modify the list of visitors via the `visitors()'
// accessor.
void InsertVisitorBefore(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
void InsertVisitorAfter(DecoderVisitor* new_visitor,
DecoderVisitor* registered_visitor);
// Remove a previously registered visitor class from the list of visitors
// stored by the decoder.
// Remove all instances of a previously registered visitor class from the list
// of visitors stored by the decoder.
void RemoveVisitor(DecoderVisitor* visitor);
#define DECLARE(A) void Visit##A(Instruction* instr);
#define DECLARE(A) void Visit##A(const Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
std::list<DecoderVisitor*>* visitors() { return &visitors_; }
private:
// Decodes an instruction and calls the visitor functions registered with the
// Decoder class.
void DecodeInstruction(const Instruction* instr);
// Decode the PC relative addressing instruction, and call the corresponding
// visitors.
// On entry, instruction bits 27:24 = 0x0.
void DecodePCRelAddressing(Instruction* instr);
void DecodePCRelAddressing(const Instruction* instr);
// Decode the add/subtract immediate instruction, and call the correspoding
// visitors.
// On entry, instruction bits 27:24 = 0x1.
void DecodeAddSubImmediate(Instruction* instr);
void DecodeAddSubImmediate(const Instruction* instr);
// Decode the branch, system command, and exception generation parts of
// the instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
void DecodeBranchSystemException(Instruction* instr);
void DecodeBranchSystemException(const Instruction* instr);
// Decode the load and store parts of the instruction tree, and call
// the corresponding visitors.
// On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
void DecodeLoadStore(Instruction* instr);
void DecodeLoadStore(const Instruction* instr);
// Decode the logical immediate and move wide immediate parts of the
// instruction tree, and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x2.
void DecodeLogical(Instruction* instr);
void DecodeLogical(const Instruction* instr);
// Decode the bitfield and extraction parts of the instruction tree,
// and call the corresponding visitors.
// On entry, instruction bits 27:24 = 0x3.
void DecodeBitfieldExtract(Instruction* instr);
void DecodeBitfieldExtract(const Instruction* instr);
// Decode the data processing parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
void DecodeDataProcessing(Instruction* instr);
void DecodeDataProcessing(const Instruction* instr);
// Decode the floating point parts of the instruction tree, and call the
// corresponding visitors.
// On entry, instruction bits 27:24 = {0xE, 0xF}.
void DecodeFP(Instruction* instr);
void DecodeFP(const Instruction* instr);
// Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
// and call the corresponding visitors.
// On entry, instruction bits 29:25 = 0x6.
void DecodeAdvSIMDLoadStore(Instruction* instr);
void DecodeAdvSIMDLoadStore(const Instruction* instr);
// Decode the Advanced SIMD (NEON) data processing part of the instruction
// tree, and call the corresponding visitors.
// On entry, instruction bits 27:25 = 0x7.
void DecodeAdvSIMDDataProcessing(Instruction* instr);
void DecodeAdvSIMDDataProcessing(const Instruction* instr);
private:
// Visitors are registered in a list.
std::list<DecoderVisitor*> visitors_;
};
} // namespace vixl
#endif // VIXL_A64_DECODER_A64_H_

View File

@@ -57,7 +57,7 @@ char* Disassembler::GetOutput() {
}
void Disassembler::VisitAddSubImmediate(Instruction* instr) {
void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
(instr->ImmAddSub() == 0) ? true : false;
@@ -102,7 +102,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
}
void Disassembler::VisitAddSubShifted(Instruction* instr) {
void Disassembler::VisitAddSubShifted(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -149,7 +149,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
}
void Disassembler::VisitAddSubExtended(Instruction* instr) {
void Disassembler::VisitAddSubExtended(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
const char *mnemonic = "";
Extend mode = static_cast<Extend>(instr->ExtendMode());
@@ -187,7 +187,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
}
void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
const char *form = "'Rd, 'Rn, 'Rm";
@@ -222,7 +222,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
}
void Disassembler::VisitLogicalImmediate(Instruction* instr) {
void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -294,7 +294,7 @@ bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
}
void Disassembler::VisitLogicalShifted(Instruction* instr) {
void Disassembler::VisitLogicalShifted(const Instruction* instr) {
bool rd_is_zr = RdIsZROrSP(instr);
bool rn_is_zr = RnIsZROrSP(instr);
const char *mnemonic = "";
@@ -345,7 +345,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
}
void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
@@ -360,7 +360,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
}
void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
@@ -375,7 +375,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
}
void Disassembler::VisitConditionalSelect(Instruction* instr) {
void Disassembler::VisitConditionalSelect(const Instruction* instr) {
bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
bool rn_is_rm = (instr->Rn() == instr->Rm());
const char *mnemonic = "";
@@ -428,7 +428,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
}
void Disassembler::VisitBitfield(Instruction* instr) {
void Disassembler::VisitBitfield(const Instruction* instr) {
unsigned s = instr->ImmS();
unsigned r = instr->ImmR();
unsigned rd_size_minus_1 =
@@ -506,7 +506,7 @@ void Disassembler::VisitBitfield(Instruction* instr) {
}
void Disassembler::VisitExtract(Instruction* instr) {
void Disassembler::VisitExtract(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
@@ -527,7 +527,7 @@ void Disassembler::VisitExtract(Instruction* instr) {
}
void Disassembler::VisitPCRelAddressing(Instruction* instr) {
void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
switch (instr->Mask(PCRelAddressingMask)) {
case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
@@ -536,7 +536,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) {
}
void Disassembler::VisitConditionalBranch(Instruction* instr) {
void Disassembler::VisitConditionalBranch(const Instruction* instr) {
switch (instr->Mask(ConditionalBranchMask)) {
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
default: VIXL_UNREACHABLE();
@@ -544,7 +544,8 @@ void Disassembler::VisitConditionalBranch(Instruction* instr) {
}
void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
void Disassembler::VisitUnconditionalBranchToRegister(
const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Xn";
@@ -564,7 +565,7 @@ void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
}
void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'BImmUncn";
@@ -577,7 +578,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
}
void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Rn";
@@ -598,7 +599,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
}
void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Rd, 'Rn, 'Rm";
@@ -619,7 +620,7 @@ void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
}
void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
bool ra_is_zr = RaIsZROrSP(instr);
const char *mnemonic = "";
const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
@@ -697,7 +698,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
}
void Disassembler::VisitCompareBranch(Instruction* instr) {
void Disassembler::VisitCompareBranch(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rt, 'BImmCmpa";
@@ -712,7 +713,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
}
void Disassembler::VisitTestBranch(Instruction* instr) {
void Disassembler::VisitTestBranch(const Instruction* instr) {
const char *mnemonic = "";
// If the top bit of the immediate is clear, the tested register is
// disassembled as Wt, otherwise Xt. As the top bit of the immediate is
@@ -729,7 +730,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
}
void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'IMoveImm";
@@ -768,7 +769,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
V(LDR_s, "ldr", "'St") \
V(LDR_d, "ldr", "'Dt")
void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePreIndex)";
@@ -782,7 +783,7 @@ void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
}
void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePostIndex)";
@@ -796,7 +797,7 @@ void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
}
void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStoreUnsignedOffset)";
@@ -811,7 +812,7 @@ void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
}
void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStoreRegisterOffset)";
@@ -826,7 +827,7 @@ void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
}
void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Wt, ['Xns'ILS]";
const char *form_x = "'Xt, ['Xns'ILS]";
@@ -857,7 +858,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
}
void Disassembler::VisitLoadLiteral(Instruction* instr) {
void Disassembler::VisitLoadLiteral(const Instruction* instr) {
const char *mnemonic = "ldr";
const char *form = "(LoadLiteral)";
@@ -866,6 +867,11 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
case LDRSW_x_lit: {
mnemonic = "ldrsw";
form = "'Xt, 'ILLiteral 'LValue";
break;
}
default: mnemonic = "unimplemented";
}
Format(instr, mnemonic, form);
@@ -883,7 +889,7 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
V(STP_d, "stp", "'Dt, 'Dt2", "8") \
V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairPostIndex)";
@@ -897,7 +903,7 @@ void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
}
void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairPreIndex)";
@@ -911,7 +917,7 @@ void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
}
void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(LoadStorePairOffset)";
@@ -925,7 +931,7 @@ void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
}
void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form;
@@ -944,7 +950,7 @@ void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
}
void Disassembler::VisitLoadStoreExclusive(Instruction* instr) {
void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form;
@@ -987,7 +993,7 @@ void Disassembler::VisitLoadStoreExclusive(Instruction* instr) {
}
void Disassembler::VisitFPCompare(Instruction* instr) {
void Disassembler::VisitFPCompare(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Fn, 'Fm";
const char *form_zero = "'Fn, #0.0";
@@ -1003,7 +1009,7 @@ void Disassembler::VisitFPCompare(Instruction* instr) {
}
void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
const char *mnemonic = "unmplemented";
const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
@@ -1018,7 +1024,7 @@ void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
}
void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
@@ -1031,7 +1037,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
}
void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'Fd, 'Fn";
@@ -1059,7 +1065,7 @@ void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
}
void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm";
@@ -1083,7 +1089,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
}
void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
@@ -1102,7 +1108,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
}
void Disassembler::VisitFPImmediate(Instruction* instr) {
void Disassembler::VisitFPImmediate(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "(FPImmediate)";
@@ -1115,7 +1121,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
}
void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "(FPIntegerConvert)";
const char *form_rf = "'Rd, 'Fn";
@@ -1171,7 +1177,7 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
}
void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
const char *mnemonic = "";
const char *form = "'Rd, 'Fn, 'IFPFBits";
const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
@@ -1199,7 +1205,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
}
void Disassembler::VisitSystem(Instruction* instr) {
void Disassembler::VisitSystem(const Instruction* instr) {
// Some system instructions hijack their Op and Cp fields to represent a
// range of immediates instead of indicating a different instruction. This
// makes the decoding tricky.
@@ -1267,7 +1273,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
}
void Disassembler::VisitException(Instruction* instr) {
void Disassembler::VisitException(const Instruction* instr) {
const char *mnemonic = "unimplemented";
const char *form = "'IDebug";
@@ -1286,22 +1292,75 @@ void Disassembler::VisitException(Instruction* instr) {
}
void Disassembler::VisitUnimplemented(Instruction* instr) {
void Disassembler::VisitUnimplemented(const Instruction* instr) {
Format(instr, "unimplemented", "(Unimplemented)");
}
void Disassembler::VisitUnallocated(Instruction* instr) {
void Disassembler::VisitUnallocated(const Instruction* instr) {
Format(instr, "unallocated", "(Unallocated)");
}
void Disassembler::ProcessOutput(Instruction* /*instr*/) {
void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
// The base disasm does nothing more than disassembling into a buffer.
}
void Disassembler::Format(Instruction* instr, const char* mnemonic,
void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
const CPURegister& reg) {
USE(instr);
VIXL_ASSERT(reg.IsValid());
char reg_char;
if (reg.IsRegister()) {
reg_char = reg.Is64Bits() ? 'x' : 'w';
} else {
VIXL_ASSERT(reg.IsFPRegister());
reg_char = reg.Is64Bits() ? 'd' : 's';
}
if (reg.IsFPRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
// A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
AppendToOutput("%c%d", reg_char, reg.code());
} else if (reg.Aliases(sp)) {
// Disassemble w31/x31 as stack pointer wsp/sp.
AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
} else {
// Disassemble w31/x31 as zero register wzr/xzr.
AppendToOutput("%czr", reg_char);
}
}
void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
int64_t offset) {
USE(instr);
char sign = (offset < 0) ? '-' : '+';
AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
}
void Disassembler::AppendAddressToOutput(const Instruction* instr,
const void* addr) {
USE(instr);
AppendToOutput("(addr %p)", addr);
}
void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
const void* addr) {
AppendAddressToOutput(instr, addr);
}
void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
const void* addr) {
AppendAddressToOutput(instr, addr);
}
void Disassembler::Format(const Instruction* instr, const char* mnemonic,
const char* format) {
VIXL_ASSERT(mnemonic != NULL);
ResetOutput();
@@ -1315,7 +1374,7 @@ void Disassembler::Format(Instruction* instr, const char* mnemonic,
}
void Disassembler::Substitute(Instruction* instr, const char* string) {
void Disassembler::Substitute(const Instruction* instr, const char* string) {
char chr = *string++;
while (chr != '\0') {
if (chr == '\'') {
@@ -1328,7 +1387,8 @@ void Disassembler::Substitute(Instruction* instr, const char* string) {
}
int Disassembler::SubstituteField(Instruction* instr, const char* format) {
int Disassembler::SubstituteField(const Instruction* instr,
const char* format) {
switch (format[0]) {
case 'R': // Register. X or W, selected by sf bit.
case 'F': // FP Register. S or D, selected by type field.
@@ -1354,7 +1414,7 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
}
int Disassembler::SubstituteRegisterField(Instruction* instr,
int Disassembler::SubstituteRegisterField(const Instruction* instr,
const char* format) {
unsigned reg_num = 0;
unsigned field_len = 2;
@@ -1381,34 +1441,47 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
field_len = 3;
}
char reg_type;
CPURegister::RegisterType reg_type;
unsigned reg_size;
if (format[0] == 'R') {
// Register type is R: use sf bit to choose X and W.
reg_type = instr->SixtyFourBits() ? 'x' : 'w';
reg_type = CPURegister::kRegister;
reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
} else if (format[0] == 'F') {
// Floating-point register: use type field to choose S or D.
reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
reg_type = CPURegister::kFPRegister;
reg_size = ((instr->FPType() & 1) == 0) ? kSRegSize : kDRegSize;
} else {
// Register type is specified. Make it lower case.
reg_type = format[0] + 0x20;
// The register type is specified.
switch (format[0]) {
case 'W':
reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
case 'X':
reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
case 'S':
reg_type = CPURegister::kFPRegister; reg_size = kSRegSize; break;
case 'D':
reg_type = CPURegister::kFPRegister; reg_size = kDRegSize; break;
default:
VIXL_UNREACHABLE();
reg_type = CPURegister::kRegister;
reg_size = kXRegSize;
}
}
if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
// A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
AppendToOutput("%c%d", reg_type, reg_num);
} else if (format[2] == 's') {
// Disassemble w31/x31 as stack pointer wsp/sp.
AppendToOutput("%s", (reg_type == 'w') ? "wsp" : "sp");
} else {
// Disassemble w31/x31 as zero register wzr/xzr.
AppendToOutput("%czr", reg_type);
if ((reg_type == CPURegister::kRegister) &&
(reg_num == kZeroRegCode) && (format[2] == 's')) {
reg_num = kSPRegInternalCode;
}
AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
return field_len;
}
int Disassembler::SubstituteImmediateField(Instruction* instr,
int Disassembler::SubstituteImmediateField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'I');
@@ -1458,8 +1531,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
}
case 'C': { // ICondB - Immediate Conditional Branch.
int64_t offset = instr->ImmCondBranch() << 2;
char sign = (offset >= 0) ? '+' : '-';
AppendToOutput("#%c0x%" PRIx64, sign, offset);
AppendPCRelativeOffsetToOutput(instr, offset);
return 6;
}
case 'A': { // IAddSub.
@@ -1522,7 +1594,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
}
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
const char* format) {
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
unsigned r = instr->ImmR();
@@ -1557,7 +1629,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
}
int Disassembler::SubstituteLiteralField(Instruction* instr,
int Disassembler::SubstituteLiteralField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
USE(format);
@@ -1565,16 +1637,21 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
switch (instr->Mask(LoadLiteralMask)) {
case LDR_w_lit:
case LDR_x_lit:
case LDRSW_x_lit:
case LDR_s_lit:
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
default: VIXL_UNREACHABLE();
case LDR_d_lit:
AppendDataAddressToOutput(instr, instr->LiteralAddress());
break;
default:
VIXL_UNREACHABLE();
}
return 6;
}
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
int Disassembler::SubstituteShiftField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'H');
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
@@ -1597,7 +1674,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
}
int Disassembler::SubstituteConditionField(Instruction* instr,
int Disassembler::SubstituteConditionField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'C');
const char* condition_code[] = { "eq", "ne", "hs", "lo",
@@ -1618,27 +1695,28 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
}
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
const char* format) {
VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
(strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
int64_t offset = instr->ImmPCRel();
Instruction * base = instr;
const Instruction * base = instr;
if (format[9] == 'P') {
offset *= kPageSize;
base = AlignDown(base, kPageSize);
}
char sign = (offset < 0) ? '-' : '+';
void * target = reinterpret_cast<void *>(base + offset);
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, std::abs(offset), target);
const void* target = reinterpret_cast<const void*>(base + offset);
AppendPCRelativeOffsetToOutput(instr, offset);
AppendToOutput(" ");
AppendAddressToOutput(instr, target);
return 13;
}
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
@@ -1655,19 +1733,18 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
default: VIXL_UNIMPLEMENTED();
}
offset <<= kInstructionSizeLog2;
char sign = '+';
if (offset < 0) {
offset = -offset;
sign = '-';
}
const void* target_address = reinterpret_cast<const void*>(instr + offset);
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
void * address = reinterpret_cast<void *>(instr + offset);
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, address);
AppendPCRelativeOffsetToOutput(instr, offset);
AppendToOutput(" ");
AppendCodeAddressToOutput(instr, target_address);
return 8;
}
int Disassembler::SubstituteExtendField(Instruction* instr,
int Disassembler::SubstituteExtendField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
VIXL_ASSERT(instr->ExtendMode() <= 7);
@@ -1694,7 +1771,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
}
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
@@ -1723,7 +1800,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
}
int Disassembler::SubstitutePrefetchField(Instruction* instr,
int Disassembler::SubstitutePrefetchField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'P');
USE(format);
@@ -1738,7 +1815,7 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
return 6;
}
int Disassembler::SubstituteBarrierField(Instruction* instr,
int Disassembler::SubstituteBarrierField(const Instruction* instr,
const char* format) {
VIXL_ASSERT(format[0] == 'M');
USE(format);
@@ -1770,7 +1847,7 @@ void Disassembler::AppendToOutput(const char* format, ...) {
}
void PrintDisassembler::ProcessOutput(Instruction* instr) {
void PrintDisassembler::ProcessOutput(const Instruction* instr) {
fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
reinterpret_cast<uint64_t>(instr),
instr->InstructionBits(),

View File

@@ -31,6 +31,7 @@
#include "utils.h"
#include "instructions-a64.h"
#include "decoder-a64.h"
#include "assembler-a64.h"
namespace vixl {
@@ -42,48 +43,83 @@ class Disassembler: public DecoderVisitor {
char* GetOutput();
// Declare all Visitor functions.
#define DECLARE(A) void Visit##A(Instruction* instr);
#define DECLARE(A) void Visit##A(const Instruction* instr);
VISITOR_LIST(DECLARE)
#undef DECLARE
protected:
virtual void ProcessOutput(Instruction* instr);
virtual void ProcessOutput(const Instruction* instr);
// Default output functions. The functions below implement a default way of
// printing elements in the disassembly. A sub-class can override these to
// customize the disassembly output.
// Prints the name of a register.
virtual void AppendRegisterNameToOutput(const Instruction* instr,
const CPURegister& reg);
// Prints a PC-relative offset. This is used for example when disassembling
// branches to immediate offsets.
virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr,
int64_t offset);
// Prints an address, in the general case. It can be code or data. This is
// used for example to print the target address of an ADR instruction.
virtual void AppendAddressToOutput(const Instruction* instr,
const void* addr);
// Prints the address of some code.
// This is used for example to print the target address of a branch to an
// immediate offset.
// A sub-class can for example override this method to lookup the address and
// print an appropriate name.
virtual void AppendCodeAddressToOutput(const Instruction* instr,
const void* addr);
// Prints the address of some data.
// This is used for example to print the source address of a load literal
// instruction.
virtual void AppendDataAddressToOutput(const Instruction* instr,
const void* addr);
private:
void Format(Instruction* instr, const char* mnemonic, const char* format);
void Substitute(Instruction* instr, const char* string);
int SubstituteField(Instruction* instr, const char* format);
int SubstituteRegisterField(Instruction* instr, const char* format);
int SubstituteImmediateField(Instruction* instr, const char* format);
int SubstituteLiteralField(Instruction* instr, const char* format);
int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
int SubstituteShiftField(Instruction* instr, const char* format);
int SubstituteExtendField(Instruction* instr, const char* format);
int SubstituteConditionField(Instruction* instr, const char* format);
int SubstitutePCRelAddressField(Instruction* instr, const char* format);
int SubstituteBranchTargetField(Instruction* instr, const char* format);
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
int SubstitutePrefetchField(Instruction* instr, const char* format);
int SubstituteBarrierField(Instruction* instr, const char* format);
void Format(
const Instruction* instr, const char* mnemonic, const char* format);
void Substitute(const Instruction* instr, const char* string);
int SubstituteField(const Instruction* instr, const char* format);
int SubstituteRegisterField(const Instruction* instr, const char* format);
int SubstituteImmediateField(const Instruction* instr, const char* format);
int SubstituteLiteralField(const Instruction* instr, const char* format);
int SubstituteBitfieldImmediateField(
const Instruction* instr, const char* format);
int SubstituteShiftField(const Instruction* instr, const char* format);
int SubstituteExtendField(const Instruction* instr, const char* format);
int SubstituteConditionField(const Instruction* instr, const char* format);
int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
int SubstituteBranchTargetField(const Instruction* instr, const char* format);
int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
int SubstitutePrefetchField(const Instruction* instr, const char* format);
int SubstituteBarrierField(const Instruction* instr, const char* format);
inline bool RdIsZROrSP(Instruction* instr) const {
inline bool RdIsZROrSP(const Instruction* instr) const {
return (instr->Rd() == kZeroRegCode);
}
inline bool RnIsZROrSP(Instruction* instr) const {
inline bool RnIsZROrSP(const Instruction* instr) const {
return (instr->Rn() == kZeroRegCode);
}
inline bool RmIsZROrSP(Instruction* instr) const {
inline bool RmIsZROrSP(const Instruction* instr) const {
return (instr->Rm() == kZeroRegCode);
}
inline bool RaIsZROrSP(Instruction* instr) const {
inline bool RaIsZROrSP(const Instruction* instr) const {
return (instr->Ra() == kZeroRegCode);
}
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
protected:
void ResetOutput();
void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
@@ -97,10 +133,10 @@ class Disassembler: public DecoderVisitor {
class PrintDisassembler: public Disassembler {
public:
explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
~PrintDisassembler() { }
virtual ~PrintDisassembler() { }
protected:
virtual void ProcessOutput(Instruction* instr);
virtual void ProcessOutput(const Instruction* instr);
private:
FILE *stream_;

View File

@@ -57,7 +57,7 @@ static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
// Logical immediates can't encode zero, so a return value of zero is used to
// indicate a failure case. Specifically, where the constraints on imm_s are
// not met.
uint64_t Instruction::ImmLogical() {
uint64_t Instruction::ImmLogical() const {
unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize;
int64_t n = BitN();
int64_t imm_s = ImmSetBits();
@@ -108,7 +108,7 @@ uint64_t Instruction::ImmLogical() {
}
float Instruction::ImmFP32() {
float Instruction::ImmFP32() const {
// ImmFP: abcdefgh (8 bits)
// Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
// where B is b ^ 1
@@ -122,7 +122,7 @@ float Instruction::ImmFP32() {
}
double Instruction::ImmFP64() {
double Instruction::ImmFP64() const {
// ImmFP: abcdefgh (8 bits)
// Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
// 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
@@ -148,8 +148,8 @@ LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
}
Instruction* Instruction::ImmPCOffsetTarget() {
Instruction * base = this;
const Instruction* Instruction::ImmPCOffsetTarget() const {
const Instruction * base = this;
ptrdiff_t offset;
if (IsPCRelAddressing()) {
// ADR and ADRP.
@@ -182,7 +182,7 @@ inline int Instruction::ImmBranch() const {
}
void Instruction::SetImmPCOffsetTarget(Instruction* target) {
void Instruction::SetImmPCOffsetTarget(const Instruction* target) {
if (IsPCRelAddressing()) {
SetPCRelImmTarget(target);
} else {
@@ -191,7 +191,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
}
void Instruction::SetPCRelImmTarget(Instruction* target) {
void Instruction::SetPCRelImmTarget(const Instruction* target) {
int32_t imm21;
if ((Mask(PCRelAddressingMask) == ADR)) {
imm21 = target - this;
@@ -207,7 +207,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
}
void Instruction::SetBranchImmTarget(Instruction* target) {
void Instruction::SetBranchImmTarget(const Instruction* target) {
VIXL_ASSERT(((target - this) & 3) == 0);
Instr branch_imm = 0;
uint32_t imm_mask = 0;
@@ -239,9 +239,9 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
}
void Instruction::SetImmLLiteral(Instruction* source) {
VIXL_ASSERT(((source - this) & 3) == 0);
int offset = (source - this) >> kLiteralEntrySizeLog2;
void Instruction::SetImmLLiteral(const Instruction* source) {
VIXL_ASSERT(IsWordAligned(source));
ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2;
Instr imm = Assembler::ImmLLiteral(offset);
Instr mask = ImmLLiteral_mask;

View File

@@ -44,6 +44,7 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes;
// This is the nominal page size (as used by the adrp instruction); the actual
// size of the memory pages allocated by the kernel is likely to differ.
const unsigned kPageSize = 4 * KBytes;
const unsigned kPageSizeLog2 = 12;
const unsigned kWRegSize = 32;
const unsigned kWRegSizeLog2 = 5;
@@ -95,30 +96,6 @@ const unsigned kDoubleExponentBits = 11;
const unsigned kFloatMantissaBits = 23;
const unsigned kFloatExponentBits = 8;
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
const double kFP64PositiveInfinity =
rawbits_to_double(UINT64_C(0x7ff0000000000000));
const double kFP64NegativeInfinity =
rawbits_to_double(UINT64_C(0xfff0000000000000));
// This value is a signalling NaN as both a double and as a float (taking the
// least-significant word).
static const double kFP64SignallingNaN =
rawbits_to_double(UINT64_C(0x7ff000007f800001));
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
// A similar value, but as a quiet NaN.
static const double kFP64QuietNaN =
rawbits_to_double(UINT64_C(0x7ff800007fc00001));
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
// The default NaN values (for FPCR.DN=1).
static const double kFP64DefaultNaN =
rawbits_to_double(UINT64_C(0x7ff8000000000000));
static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
enum LSDataSize {
LSByte = 0,
LSHalfword = 1,
@@ -201,9 +178,9 @@ class Instruction {
return signed_bitextract_32(width-1, 0, offset);
}
uint64_t ImmLogical();
float ImmFP32();
double ImmFP64();
uint64_t ImmLogical() const;
float ImmFP32() const;
double ImmFP64() const;
inline LSDataSize SizeLSPair() const {
return CalcLSPairDataSize(
@@ -311,46 +288,49 @@ class Instruction {
// Find the target of this instruction. 'this' may be a branch or a
// PC-relative addressing instruction.
Instruction* ImmPCOffsetTarget();
const Instruction* ImmPCOffsetTarget() const;
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
// a PC-relative addressing instruction.
void SetImmPCOffsetTarget(Instruction* target);
void SetImmPCOffsetTarget(const Instruction* target);
// Patch a literal load instruction to load from 'source'.
void SetImmLLiteral(Instruction* source);
void SetImmLLiteral(const Instruction* source);
inline uint8_t* LiteralAddress() {
inline uint8_t* LiteralAddress() const {
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
return reinterpret_cast<uint8_t*>(this) + offset;
const uint8_t* address = reinterpret_cast<const uint8_t*>(this) + offset;
// Note that the result is safely mutable only if the backing buffer is
// safely mutable.
return const_cast<uint8_t*>(address);
}
inline uint32_t Literal32() {
inline uint32_t Literal32() const {
uint32_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
inline uint64_t Literal64() {
inline uint64_t Literal64() const {
uint64_t literal;
memcpy(&literal, LiteralAddress(), sizeof(literal));
return literal;
}
inline float LiteralFP32() {
inline float LiteralFP32() const {
return rawbits_to_float(Literal32());
}
inline double LiteralFP64() {
inline double LiteralFP64() const {
return rawbits_to_double(Literal64());
}
inline Instruction* NextInstruction() {
inline const Instruction* NextInstruction() const {
return this + kInstructionSize;
}
inline Instruction* InstructionAtOffset(int64_t offset) {
inline const Instruction* InstructionAtOffset(int64_t offset) const {
VIXL_ASSERT(IsWordAligned(this + offset));
return this + offset;
}
@@ -359,11 +339,15 @@ class Instruction {
return reinterpret_cast<Instruction*>(src);
}
template<typename T> static inline const Instruction* CastConst(T src) {
return reinterpret_cast<const Instruction*>(src);
}
private:
inline int ImmBranch() const;
void SetPCRelImmTarget(Instruction* target);
void SetBranchImmTarget(Instruction* target);
void SetPCRelImmTarget(const Instruction* target);
void SetBranchImmTarget(const Instruction* target);
};
} // namespace vixl

113
disas/libvixl/code-buffer.h Normal file
View File

@@ -0,0 +1,113 @@
// Copyright 2014, ARM Limited
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of ARM Limited nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef VIXL_CODE_BUFFER_H
#define VIXL_CODE_BUFFER_H
#include <string.h>
#include "globals.h"
namespace vixl {
class CodeBuffer {
public:
explicit CodeBuffer(size_t capacity = 4 * KBytes);
CodeBuffer(void* buffer, size_t capacity);
~CodeBuffer();
void Reset();
ptrdiff_t OffsetFrom(ptrdiff_t offset) const {
ptrdiff_t cursor_offset = cursor_ - buffer_;
VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset));
return cursor_offset - offset;
}
ptrdiff_t CursorOffset() const {
return OffsetFrom(0);
}
template <typename T>
T GetOffsetAddress(ptrdiff_t offset) const {
VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_)));
return reinterpret_cast<T>(buffer_ + offset);
}
size_t RemainingBytes() const {
VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_)));
return (buffer_ + capacity_) - cursor_;
}
// A code buffer can emit:
// * 32-bit data: instruction and constant.
// * 64-bit data: constant.
// * string: debug info.
void Emit32(uint32_t data) { Emit(data); }
void Emit64(uint64_t data) { Emit(data); }
void EmitString(const char* string);
// Align to kInstructionSize.
void Align();
size_t capacity() const { return capacity_; }
bool IsManaged() const { return managed_; }
void Grow(size_t new_capacity);
bool IsDirty() const { return dirty_; }
void SetClean() { dirty_ = false; }
private:
template <typename T>
void Emit(T value) {
VIXL_ASSERT(RemainingBytes() >= sizeof(value));
dirty_ = true;
memcpy(cursor_, &value, sizeof(value));
cursor_ += sizeof(value);
}
// Backing store of the buffer.
byte* buffer_;
// If true the backing store is allocated and deallocated by the buffer. The
// backing store can then grow on demand. If false the backing store is
// provided by the user and cannot be resized internally.
bool managed_;
// Pointer to the next location to be written.
byte* cursor_;
// True if there has been any write since the buffer was created or cleaned.
bool dirty_;
// Capacity in bytes of the backing store.
size_t capacity_;
};
} // namespace vixl
#endif // VIXL_CODE_BUFFER_H

View File

@@ -134,4 +134,5 @@ uint64_t LowestSetBit(uint64_t value) {
bool IsPowerOf2(int64_t value) {
return (value != 0) && ((value & (value - 1)) == 0);
}
} // namespace vixl

View File

@@ -171,7 +171,7 @@ bool IsPowerOf2(int64_t value);
template<typename T>
bool IsWordAligned(T pointer) {
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
return ((intptr_t)(pointer) & 3) == 0;
}
// Increment a pointer until it has the specified alignment.
@@ -204,7 +204,6 @@ T AlignDown(T pointer, size_t alignment) {
return (T)(pointer_raw - align_step);
}
} // namespace vixl
#endif // VIXL_UTILS_H

View File

@@ -119,6 +119,8 @@ see <http://www.gnu.org/licenses/>. */
#define OP_SH_IMMEDIATE 0
#define OP_MASK_DELTA 0xffff
#define OP_SH_DELTA 0
#define OP_MASK_DELTA_R6 0x1ff
#define OP_SH_DELTA_R6 7
#define OP_MASK_FUNCT 0x3f
#define OP_SH_FUNCT 0
#define OP_MASK_SPEC 0x3f
@@ -405,6 +407,12 @@ struct mips_opcode
"+3" UDI immediate bits 6-20
"+4" UDI immediate bits 6-25
R6 immediates/displacements :
(adding suffix to 'o' to avoid adding new characters)
"+o" 9 bits immediate/displacement (shift = 7)
"+o1" 18 bits immediate/displacement (shift = 0)
"+o2" 19 bits immediate/displacement (shift = 0)
Other:
"()" parens surrounding optional value
"," separates operands
@@ -521,6 +529,8 @@ struct mips_opcode
#define INSN_ISA64 0x00000040
#define INSN_ISA32R2 0x00000080
#define INSN_ISA64R2 0x00000100
#define INSN_ISA32R6 0x00000200
#define INSN_ISA64R6 0x00000400
/* Masks used for MIPS-defined ASEs. */
#define INSN_ASE_MASK 0x0000f000
@@ -585,6 +595,8 @@ struct mips_opcode
#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2)
#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2)
#define ISA_MIPS32R6 (ISA_MIPS32R2 | INSN_ISA32R6)
#define ISA_MIPS64R6 (ISA_MIPS64R2 | INSN_ISA32R6 | INSN_ISA64R6)
/* CPU defines, use instead of hardcoding processor number. Keep this
in sync with bfd/archures.c in order for machine selection to work. */
@@ -1121,6 +1133,8 @@ extern const int bfd_mips16_num_opcodes;
#define I64 INSN_ISA64
#define I33 INSN_ISA32R2
#define I65 INSN_ISA64R2
#define I32R6 INSN_ISA32R6
#define I64R6 INSN_ISA64R6
/* MIPS64 MIPS-3D ASE support. */
#define I16 INSN_MIPS16
@@ -1209,6 +1223,146 @@ const struct mips_opcode mips_builtin_opcodes[] =
them first. The assemblers uses a hash table based on the
instruction name anyhow. */
/* name, args, match, mask, pinfo, membership */
{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6},
{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I64R6},
{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6},
{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6},
{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6},
{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6},
{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6},
{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6},
{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6},
{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6},
{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6},
{"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6},
{"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6},
{"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6},
{"dclo", "U,s", 0x00000053, 0xfc1f07ff, WR_d|RD_s, 0, I64R6},
{"sdbbp", "B", 0x0000000e, 0xfc00003f, TRAP, 0, I32R6},
{"mul", "d,s,t", 0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"muh", "d,s,t", 0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"mulu", "d,s,t", 0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"muhu", "d,s,t", 0x000000d9, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"div", "d,s,t", 0x0000009a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"mod", "d,s,t", 0x000000da, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"divu", "d,s,t", 0x0000009b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"modu", "d,s,t", 0x000000db, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"dmul", "d,s,t", 0x0000009c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"dmuh", "d,s,t", 0x000000dc, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"dmulu", "d,s,t", 0x0000009d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"dmuhu", "d,s,t", 0x000000dd, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"ddiv", "d,s,t", 0x0000009e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
{"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
{"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
{"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
{"scd", "t,o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
{"pref", "h,o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6},
{"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6},
{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"maddf.d", "D,S,T", 0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"msubf.s", "D,S,T", 0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"msubf.d", "D,S,T", 0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"max.s", "D,S,T", 0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"max.d", "D,S,T", 0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"maxa.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"maxa.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"rint.s", "D,S", 0x4600001a, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6},
{"rint.d", "D,S", 0x4620001a, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6},
{"class.s", "D,S", 0x4600001b, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6},
{"class.d", "D,S", 0x4620001b, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6},
{"min.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"min.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"mina.s", "D,S,T", 0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"mina.d", "D,S,T", 0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"sel.s", "D,S,T", 0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"sel.d", "D,S,T", 0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"seleqz.s", "D,S,T", 0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"seleqz.d", "D,S,T", 0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"selnez.s", "D,S,T", 0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
{"selnez.d", "D,S,T", 0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
{"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6},
{"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6},
{"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6},
{"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0, I64R6},
{"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0, I32R6},
{"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0, I32R6},
{"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0, I32R6},
{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6},
{"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0, I32R6},
{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6},
{"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bnezalc", "s,t,p", 0x60000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bnvc", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bnec", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"blezc", "s,t,p", 0x58000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bgezc", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bgec", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bgtzc", "s,t,p", 0x5c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bltzc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bltc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"blezalc", "s,t,p", 0x18000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bgezalc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bgeuc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
{"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
{"nal", "p", 0x04100000, 0xffff0000, WR_31, 0, I32R6},
{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, 0, I32R6},
{"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6},
{"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6},
{"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6},
{"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0, I32R6},
{"cmp.af.s", "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.un.s", "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.eq.s", "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.ueq.s", "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.lt.s", "D,S,T", 0x46800004, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.ult.s", "D,S,T", 0x46800005, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.le.s", "D,S,T", 0x46800006, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.ule.s", "D,S,T", 0x46800007, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.saf.s", "D,S,T", 0x46800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sun.s", "D,S,T", 0x46800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.seq.s", "D,S,T", 0x4680000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sueq.s", "D,S,T", 0x4680000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.slt.s", "D,S,T", 0x4680000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sult.s", "D,S,T", 0x4680000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sle.s", "D,S,T", 0x4680000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sule.s", "D,S,T", 0x4680000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.or.s", "D,S,T", 0x46800011, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.une.s", "D,S,T", 0x46800012, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.ne.s", "D,S,T", 0x46800013, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sor.s", "D,S,T", 0x46800019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sune.s", "D,S,T", 0x4680001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.sne.s", "D,S,T", 0x4680001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
{"cmp.af.d", "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.un.d", "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.eq.d", "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.ueq.d", "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.lt.d", "D,S,T", 0x46a00004, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.ult.d", "D,S,T", 0x46a00005, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.le.d", "D,S,T", 0x46a00006, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.ule.d", "D,S,T", 0x46a00007, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.saf.d", "D,S,T", 0x46a00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sun.d", "D,S,T", 0x46a00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.seq.d", "D,S,T", 0x46a0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sueq.d", "D,S,T", 0x46a0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.slt.d", "D,S,T", 0x46a0000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sult.d", "D,S,T", 0x46a0000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sle.d", "D,S,T", 0x46a0000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sule.d", "D,S,T", 0x46a0000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.or.d", "D,S,T", 0x46a00011, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.une.d", "D,S,T", 0x46a00012, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.ne.d", "D,S,T", 0x46a00013, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 },
{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 },
{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */
@@ -1753,6 +1907,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 },
{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 },
{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 },
{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6},
{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55},
{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 },
{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 },
@@ -3575,6 +3730,42 @@ print_insn_args (const char *d,
(*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
break;
case 'o':
switch (*(d+1)) {
case '1':
d++;
delta = l & ((1 << 18) - 1);
if (delta & 0x20000) {
delta |= ~0x1ffff;
}
break;
case '2':
d++;
delta = l & ((1 << 19) - 1);
if (delta & 0x40000) {
delta |= ~0x3ffff;
}
break;
default:
delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
if (delta & 0x8000) {
delta |= ~0xffff;
}
}
(*info->fprintf_func) (info->stream, "%d", delta);
break;
case 'p':
/* Sign extend the displacement with 26 bits. */
delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET;
if (delta & 0x2000000) {
delta |= ~0x3FFFFFF;
}
info->target = (delta << 2) + pc + INSNLEN;
(*info->print_address_func) (info->target, info);
break;
case 't': /* Coprocessor 0 reg name */
(*info->fprintf_func) (info->stream, "%s",
mips_cp0_names[(l >> OP_SH_RT) &
@@ -3726,7 +3917,8 @@ print_insn_args (const char *d,
case 'j': /* Same as i, but sign-extended. */
case 'o':
delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
if (delta & 0x8000)
delta |= ~0xffff;
(*info->fprintf_func) (info->stream, "%d",
@@ -4052,6 +4244,23 @@ print_insn_mips (bfd_vma memaddr,
&& strcmp (op->name, "jalx"))
continue;
if (strcmp(op->name, "bovc") == 0
|| strcmp(op->name, "bnvc") == 0) {
if (((word >> OP_SH_RS) & OP_MASK_RS) <
((word >> OP_SH_RT) & OP_MASK_RT)) {
continue;
}
}
if (strcmp(op->name, "bgezc") == 0
|| strcmp(op->name, "bltzc") == 0
|| strcmp(op->name, "bgezalc") == 0
|| strcmp(op->name, "bltzalc") == 0) {
if (((word >> OP_SH_RS) & OP_MASK_RS) !=
((word >> OP_SH_RT) & OP_MASK_RT)) {
continue;
}
}
/* Figure out instruction type and branch delay information. */
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
{

View File

@@ -7,6 +7,7 @@
* (GNU GPL), version 2 or later.
*/
#include "sysemu/block-backend.h"
#include "sysemu/dma.h"
#include "trace.h"
#include "qemu/range.h"
@@ -67,9 +68,9 @@ void qemu_sglist_destroy(QEMUSGList *qsg)
}
typedef struct {
BlockDriverAIOCB common;
BlockDriverState *bs;
BlockDriverAIOCB *acb;
BlockAIOCB common;
BlockBackend *blk;
BlockAIOCB *acb;
QEMUSGList *sg;
uint64_t sector_num;
DMADirection dir;
@@ -80,7 +81,7 @@ typedef struct {
DMAIOFunc *io_func;
} DMAAIOCB;
static void dma_bdrv_cb(void *opaque, int ret);
static void dma_blk_cb(void *opaque, int ret);
static void reschedule_dma(void *opaque)
{
@@ -88,7 +89,7 @@ static void reschedule_dma(void *opaque)
qemu_bh_delete(dbs->bh);
dbs->bh = NULL;
dma_bdrv_cb(dbs, 0);
dma_blk_cb(dbs, 0);
}
static void continue_after_map_failure(void *opaque)
@@ -99,7 +100,7 @@ static void continue_after_map_failure(void *opaque)
qemu_bh_schedule(dbs->bh);
}
static void dma_bdrv_unmap(DMAAIOCB *dbs)
static void dma_blk_unmap(DMAAIOCB *dbs)
{
int i;
@@ -115,7 +116,7 @@ static void dma_complete(DMAAIOCB *dbs, int ret)
{
trace_dma_complete(dbs, ret, dbs->common.cb);
dma_bdrv_unmap(dbs);
dma_blk_unmap(dbs);
if (dbs->common.cb) {
dbs->common.cb(dbs->common.opaque, ret);
}
@@ -127,13 +128,13 @@ static void dma_complete(DMAAIOCB *dbs, int ret)
qemu_aio_unref(dbs);
}
static void dma_bdrv_cb(void *opaque, int ret)
static void dma_blk_cb(void *opaque, int ret)
{
DMAAIOCB *dbs = (DMAAIOCB *)opaque;
dma_addr_t cur_addr, cur_len;
void *mem;
trace_dma_bdrv_cb(dbs, ret);
trace_dma_blk_cb(dbs, ret);
dbs->acb = NULL;
dbs->sector_num += dbs->iov.size / 512;
@@ -142,7 +143,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
dma_complete(dbs, ret);
return;
}
dma_bdrv_unmap(dbs);
dma_blk_unmap(dbs);
while (dbs->sg_cur_index < dbs->sg->nsg) {
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
@@ -168,19 +169,19 @@ static void dma_bdrv_cb(void *opaque, int ret)
qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK);
}
dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
dbs->iov.size / 512, dma_bdrv_cb, dbs);
dbs->acb = dbs->io_func(dbs->blk, dbs->sector_num, &dbs->iov,
dbs->iov.size / 512, dma_blk_cb, dbs);
assert(dbs->acb);
}
static void dma_aio_cancel(BlockDriverAIOCB *acb)
static void dma_aio_cancel(BlockAIOCB *acb)
{
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
trace_dma_aio_cancel(dbs);
if (dbs->acb) {
bdrv_aio_cancel_async(dbs->acb);
blk_aio_cancel_async(dbs->acb);
}
}
@@ -190,17 +191,17 @@ static const AIOCBInfo dma_aiocb_info = {
.cancel_async = dma_aio_cancel,
};
BlockDriverAIOCB *dma_bdrv_io(
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
BlockAIOCB *dma_blk_io(
BlockBackend *blk, QEMUSGList *sg, uint64_t sector_num,
DMAIOFunc *io_func, BlockCompletionFunc *cb,
void *opaque, DMADirection dir)
{
DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque);
DMAAIOCB *dbs = blk_aio_get(&dma_aiocb_info, blk, cb, opaque);
trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
trace_dma_blk_io(dbs, blk, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
dbs->acb = NULL;
dbs->bs = bs;
dbs->blk = blk;
dbs->sg = sg;
dbs->sector_num = sector_num;
dbs->sg_cur_index = 0;
@@ -209,25 +210,25 @@ BlockDriverAIOCB *dma_bdrv_io(
dbs->io_func = io_func;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
dma_bdrv_cb(dbs, 0);
dma_blk_cb(dbs, 0);
return &dbs->common;
}
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
BlockAIOCB *dma_blk_read(BlockBackend *blk,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque,
DMA_DIRECTION_FROM_DEVICE);
return dma_blk_io(blk, sg, sector, blk_aio_readv, cb, opaque,
DMA_DIRECTION_FROM_DEVICE);
}
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
BlockAIOCB *dma_blk_write(BlockBackend *blk,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque,
DMA_DIRECTION_TO_DEVICE);
return dma_blk_io(blk, sg, sector, blk_aio_writev, cb, opaque,
DMA_DIRECTION_TO_DEVICE);
}
@@ -262,8 +263,8 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg)
return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE);
}
void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie,
QEMUSGList *sg, enum BlockAcctType type)
{
block_acct_start(bdrv_get_stats(bs), cookie, sg->size, type);
block_acct_start(blk_get_stats(blk), cookie, sg->size, type);
}

View File

@@ -70,10 +70,10 @@ Rules support the following attributes:
once - (optional, default "off") only execute this action on the first
matching request
immediately - (optional, default "off") return a NULL BlockDriverAIOCB
pointer and fail without an errno instead. This exercises the
code path where BlockDriverAIOCB fails and the caller's
BlockDriverCompletionFunc is not invoked.
immediately - (optional, default "off") return a NULL BlockAIOCB
pointer and fail without an errno instead. This
exercises the code path where BlockAIOCB fails and the
caller's BlockCompletionFunc is not invoked.
Events
------

View File

@@ -110,6 +110,7 @@ in the description of a field.
in bits: refcount_bits = 1 << refcount_order). For version 2
images, the order is always assumed to be 4
(i.e. refcount_bits = 16).
This value may not exceed 6 (i.e. refcount_bits = 64).
100 - 103: header_length
Length of the header structure in bytes. For version 2
@@ -183,7 +184,7 @@ blocks and are exactly one cluster in size.
Given a offset into the image file, the refcount of its cluster can be obtained
as follows:
refcount_block_entries = (cluster_size / sizeof(uint16_t))
refcount_block_entries = (cluster_size * 8 / refcount_bits)
refcount_block_index = (offset / cluster_size) % refcount_block_entries
refcount_table_index = (offset / cluster_size) / refcount_block_entries

View File

@@ -70,3 +70,12 @@ Likewise applies to the pci variant only for obvious reasons.
0500 - 0515 : bochs dispi interface registers, mapped flat
without index/data ports. Use (index << 1)
as offset for (16bit) register access.
0600 - 0607 : qemu extended registers. qemu 2.2+ only.
The pci revision is 2 (or greater) when
these registers are present. The registers
are 32bit.
0600 : qemu extended register region size, in bytes.
0604 : framebuffer endianness register.
- 0xbebebebe indicates big endian.
- 0x1e1e1e1e indicates little endian.

383
dump.c
View File

@@ -81,9 +81,10 @@ static int dump_cleanup(DumpState *s)
return 0;
}
static void dump_error(DumpState *s, const char *reason)
static void dump_error(DumpState *s, const char *reason, Error **errp)
{
dump_cleanup(s);
error_setg(errp, "%s", reason);
}
static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
@@ -99,7 +100,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
return 0;
}
static int write_elf64_header(DumpState *s)
static void write_elf64_header(DumpState *s, Error **errp)
{
Elf64_Ehdr elf_header;
int ret;
@@ -126,14 +127,11 @@ static int write_elf64_header(DumpState *s)
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf header.\n");
return -1;
dump_error(s, "dump: failed to write elf header", errp);
}
return 0;
}
static int write_elf32_header(DumpState *s)
static void write_elf32_header(DumpState *s, Error **errp)
{
Elf32_Ehdr elf_header;
int ret;
@@ -160,16 +158,13 @@ static int write_elf32_header(DumpState *s)
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf header.\n");
return -1;
dump_error(s, "dump: failed to write elf header", errp);
}
return 0;
}
static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset,
hwaddr filesz)
static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset,
hwaddr filesz, Error **errp)
{
Elf64_Phdr phdr;
int ret;
@@ -186,16 +181,13 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n");
return -1;
dump_error(s, "dump: failed to write program header table", errp);
}
return 0;
}
static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset,
hwaddr filesz)
static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset,
hwaddr filesz, Error **errp)
{
Elf32_Phdr phdr;
int ret;
@@ -212,14 +204,11 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n");
return -1;
dump_error(s, "dump: failed to write program header table", errp);
}
return 0;
}
static int write_elf64_note(DumpState *s)
static void write_elf64_note(DumpState *s, Error **errp)
{
Elf64_Phdr phdr;
hwaddr begin = s->memory_offset - s->note_size;
@@ -235,11 +224,8 @@ static int write_elf64_note(DumpState *s)
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n");
return -1;
dump_error(s, "dump: failed to write program header table", errp);
}
return 0;
}
static inline int cpu_index(CPUState *cpu)
@@ -247,7 +233,8 @@ static inline int cpu_index(CPUState *cpu)
return cpu->cpu_index + 1;
}
static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
Error **errp)
{
CPUState *cpu;
int ret;
@@ -257,23 +244,21 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
id = cpu_index(cpu);
ret = cpu_write_elf64_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
dump_error(s, "dump: failed to write elf notes", errp);
return;
}
}
CPU_FOREACH(cpu) {
ret = cpu_write_elf64_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;
dump_error(s, "dump: failed to write CPU status", errp);
return;
}
}
return 0;
}
static int write_elf32_note(DumpState *s)
static void write_elf32_note(DumpState *s, Error **errp)
{
hwaddr begin = s->memory_offset - s->note_size;
Elf32_Phdr phdr;
@@ -289,14 +274,12 @@ static int write_elf32_note(DumpState *s)
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n");
return -1;
dump_error(s, "dump: failed to write program header table", errp);
}
return 0;
}
static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
Error **errp)
{
CPUState *cpu;
int ret;
@@ -306,23 +289,21 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
id = cpu_index(cpu);
ret = cpu_write_elf32_note(f, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
dump_error(s, "dump: failed to write elf notes", errp);
return;
}
}
CPU_FOREACH(cpu) {
ret = cpu_write_elf32_qemunote(f, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;
dump_error(s, "dump: failed to write CPU status", errp);
return;
}
}
return 0;
}
static int write_elf_section(DumpState *s, int type)
static void write_elf_section(DumpState *s, int type, Error **errp)
{
Elf32_Shdr shdr32;
Elf64_Shdr shdr64;
@@ -344,50 +325,44 @@ static int write_elf_section(DumpState *s, int type)
ret = fd_write_vmcore(&shdr, shdr_size, s);
if (ret < 0) {
dump_error(s, "dump: failed to write section header table.\n");
return -1;
dump_error(s, "dump: failed to write section header table", errp);
}
return 0;
}
static int write_data(DumpState *s, void *buf, int length)
static void write_data(DumpState *s, void *buf, int length, Error **errp)
{
int ret;
ret = fd_write_vmcore(buf, length, s);
if (ret < 0) {
dump_error(s, "dump: failed to save memory.\n");
return -1;
dump_error(s, "dump: failed to save memory", errp);
}
return 0;
}
/* write the memroy to vmcore. 1 page per I/O. */
static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
int64_t size)
/* write the memory to vmcore. 1 page per I/O. */
static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
int64_t size, Error **errp)
{
int64_t i;
int ret;
Error *local_err = NULL;
for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
TARGET_PAGE_SIZE);
if (ret < 0) {
return ret;
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
TARGET_PAGE_SIZE, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
if ((size % TARGET_PAGE_SIZE) != 0) {
ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
size % TARGET_PAGE_SIZE);
if (ret < 0) {
return ret;
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
size % TARGET_PAGE_SIZE, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
return 0;
}
/* get the memory's offset and size in the vmcore */
@@ -452,13 +427,13 @@ static void get_offset_range(hwaddr phys_addr,
}
}
static int write_elf_loads(DumpState *s)
static void write_elf_loads(DumpState *s, Error **errp)
{
hwaddr offset, filesz;
MemoryMapping *memory_mapping;
uint32_t phdr_index = 1;
int ret;
uint32_t max_index;
Error *local_err = NULL;
if (s->have_section) {
max_index = s->sh_info;
@@ -471,29 +446,28 @@ static int write_elf_loads(DumpState *s)
memory_mapping->length,
s, &offset, &filesz);
if (s->dump_info.d_class == ELFCLASS64) {
ret = write_elf64_load(s, memory_mapping, phdr_index++, offset,
filesz);
write_elf64_load(s, memory_mapping, phdr_index++, offset,
filesz, &local_err);
} else {
ret = write_elf32_load(s, memory_mapping, phdr_index++, offset,
filesz);
write_elf32_load(s, memory_mapping, phdr_index++, offset,
filesz, &local_err);
}
if (ret < 0) {
return -1;
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (phdr_index >= max_index) {
break;
}
}
return 0;
}
/* write elf header, PT_NOTE and elf note to vmcore. */
static int dump_begin(DumpState *s)
static void dump_begin(DumpState *s, Error **errp)
{
int ret;
Error *local_err = NULL;
/*
* the vmcore's format is:
@@ -521,69 +495,81 @@ static int dump_begin(DumpState *s)
/* write elf header to vmcore */
if (s->dump_info.d_class == ELFCLASS64) {
ret = write_elf64_header(s);
write_elf64_header(s, &local_err);
} else {
ret = write_elf32_header(s);
write_elf32_header(s, &local_err);
}
if (ret < 0) {
return -1;
if (local_err) {
error_propagate(errp, local_err);
return;
}
if (s->dump_info.d_class == ELFCLASS64) {
/* write PT_NOTE to vmcore */
if (write_elf64_note(s) < 0) {
return -1;
write_elf64_note(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/* write all PT_LOAD to vmcore */
if (write_elf_loads(s) < 0) {
return -1;
write_elf_loads(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/* write section to vmcore */
if (s->have_section) {
if (write_elf_section(s, 1) < 0) {
return -1;
write_elf_section(s, 1, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
/* write notes to vmcore */
if (write_elf64_notes(fd_write_vmcore, s) < 0) {
return -1;
write_elf64_notes(fd_write_vmcore, s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
} else {
/* write PT_NOTE to vmcore */
if (write_elf32_note(s) < 0) {
return -1;
write_elf32_note(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/* write all PT_LOAD to vmcore */
if (write_elf_loads(s) < 0) {
return -1;
write_elf_loads(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/* write section to vmcore */
if (s->have_section) {
if (write_elf_section(s, 0) < 0) {
return -1;
write_elf_section(s, 0, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
/* write notes to vmcore */
if (write_elf32_notes(fd_write_vmcore, s) < 0) {
return -1;
write_elf32_notes(fd_write_vmcore, s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
return 0;
}
/* write PT_LOAD to vmcore */
static int dump_completed(DumpState *s)
static void dump_completed(DumpState *s)
{
dump_cleanup(s);
return 0;
}
static int get_next_block(DumpState *s, GuestPhysBlock *block)
@@ -614,11 +600,12 @@ static int get_next_block(DumpState *s, GuestPhysBlock *block)
}
/* write all memory to vmcore */
static int dump_iterate(DumpState *s)
static void dump_iterate(DumpState *s, Error **errp)
{
GuestPhysBlock *block;
int64_t size;
int ret;
Error *local_err = NULL;
while (1) {
block = s->next_block;
@@ -630,34 +617,30 @@ static int dump_iterate(DumpState *s)
size -= block->target_end - (s->begin + s->length);
}
}
ret = write_memory(s, block, s->start, size);
if (ret == -1) {
return ret;
write_memory(s, block, s->start, size, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = get_next_block(s, block);
if (ret == 1) {
dump_completed(s);
return 0;
}
}
}
static int create_vmcore(DumpState *s)
static void create_vmcore(DumpState *s, Error **errp)
{
int ret;
Error *local_err = NULL;
ret = dump_begin(s);
if (ret < 0) {
return -1;
dump_begin(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = dump_iterate(s);
if (ret < 0) {
return -1;
}
return 0;
dump_iterate(s, errp);
}
static int write_start_flat_header(int fd)
@@ -738,9 +721,8 @@ static int buf_write_note(const void *buf, size_t size, void *opaque)
}
/* write common header, sub header and elf note to vmcore */
static int create_header32(DumpState *s)
static void create_header32(DumpState *s, Error **errp)
{
int ret = 0;
DiskDumpHeader32 *dh = NULL;
KdumpSubHeader32 *kh = NULL;
size_t size;
@@ -749,6 +731,7 @@ static int create_header32(DumpState *s)
uint32_t bitmap_blocks;
uint32_t status = 0;
uint64_t offset_note;
Error *local_err = NULL;
/* write common header, the version of kdump-compressed format is 6th */
size = sizeof(DiskDumpHeader32);
@@ -784,8 +767,7 @@ static int create_header32(DumpState *s)
dh->status = cpu_to_dump32(s, status);
if (write_buffer(s->fd, 0, dh, size) < 0) {
dump_error(s, "dump: failed to write disk dump header.\n");
ret = -1;
dump_error(s, "dump: failed to write disk dump header", errp);
goto out;
}
@@ -804,8 +786,7 @@ static int create_header32(DumpState *s)
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
dump_error(s, "dump: failed to write kdump sub header.\n");
ret = -1;
dump_error(s, "dump: failed to write kdump sub header", errp);
goto out;
}
@@ -814,15 +795,14 @@ static int create_header32(DumpState *s)
s->note_buf_offset = 0;
/* use s->note_buf to store notes temporarily */
if (write_elf32_notes(buf_write_note, s) < 0) {
ret = -1;
write_elf32_notes(buf_write_note, s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
if (write_buffer(s->fd, offset_note, s->note_buf,
s->note_size) < 0) {
dump_error(s, "dump: failed to write notes");
ret = -1;
dump_error(s, "dump: failed to write notes", errp);
goto out;
}
@@ -838,14 +818,11 @@ out:
g_free(dh);
g_free(kh);
g_free(s->note_buf);
return ret;
}
/* write common header, sub header and elf note to vmcore */
static int create_header64(DumpState *s)
static void create_header64(DumpState *s, Error **errp)
{
int ret = 0;
DiskDumpHeader64 *dh = NULL;
KdumpSubHeader64 *kh = NULL;
size_t size;
@@ -854,6 +831,7 @@ static int create_header64(DumpState *s)
uint32_t bitmap_blocks;
uint32_t status = 0;
uint64_t offset_note;
Error *local_err = NULL;
/* write common header, the version of kdump-compressed format is 6th */
size = sizeof(DiskDumpHeader64);
@@ -889,8 +867,7 @@ static int create_header64(DumpState *s)
dh->status = cpu_to_dump32(s, status);
if (write_buffer(s->fd, 0, dh, size) < 0) {
dump_error(s, "dump: failed to write disk dump header.\n");
ret = -1;
dump_error(s, "dump: failed to write disk dump header", errp);
goto out;
}
@@ -909,8 +886,7 @@ static int create_header64(DumpState *s)
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
block_size, kh, size) < 0) {
dump_error(s, "dump: failed to write kdump sub header.\n");
ret = -1;
dump_error(s, "dump: failed to write kdump sub header", errp);
goto out;
}
@@ -919,15 +895,15 @@ static int create_header64(DumpState *s)
s->note_buf_offset = 0;
/* use s->note_buf to store notes temporarily */
if (write_elf64_notes(buf_write_note, s) < 0) {
ret = -1;
write_elf64_notes(buf_write_note, s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
if (write_buffer(s->fd, offset_note, s->note_buf,
s->note_size) < 0) {
dump_error(s, "dump: failed to write notes");
ret = -1;
dump_error(s, "dump: failed to write notes", errp);
goto out;
}
@@ -943,16 +919,19 @@ out:
g_free(dh);
g_free(kh);
g_free(s->note_buf);
return ret;
}
static int write_dump_header(DumpState *s)
static void write_dump_header(DumpState *s, Error **errp)
{
Error *local_err = NULL;
if (s->dump_info.d_class == ELFCLASS32) {
return create_header32(s);
create_header32(s, &local_err);
} else {
return create_header64(s);
create_header64(s, &local_err);
}
if (local_err) {
error_propagate(errp, local_err);
}
}
@@ -1066,7 +1045,7 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
return true;
}
static int write_dump_bitmap(DumpState *s)
static void write_dump_bitmap(DumpState *s, Error **errp)
{
int ret = 0;
uint64_t last_pfn, pfn;
@@ -1087,8 +1066,7 @@ static int write_dump_bitmap(DumpState *s)
while (get_next_page(&block_iter, &pfn, NULL, s)) {
ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
if (ret < 0) {
dump_error(s, "dump: failed to set dump_bitmap.\n");
ret = -1;
dump_error(s, "dump: failed to set dump_bitmap", errp);
goto out;
}
@@ -1105,8 +1083,7 @@ static int write_dump_bitmap(DumpState *s)
ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
dump_bitmap_buf, s);
if (ret < 0) {
dump_error(s, "dump: failed to sync dump_bitmap.\n");
ret = -1;
dump_error(s, "dump: failed to sync dump_bitmap", errp);
goto out;
}
}
@@ -1116,8 +1093,6 @@ static int write_dump_bitmap(DumpState *s)
out:
g_free(dump_bitmap_buf);
return ret;
}
static void prepare_data_cache(DataCache *data_cache, DumpState *s,
@@ -1197,7 +1172,7 @@ static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
return buffer_is_zero(buf, page_size);
}
static int write_dump_pages(DumpState *s)
static void write_dump_pages(DumpState *s, Error **errp)
{
int ret = 0;
DataCache page_desc, page_data;
@@ -1241,7 +1216,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
g_free(buf);
if (ret < 0) {
dump_error(s, "dump: failed to write page data(zero page).\n");
dump_error(s, "dump: failed to write page data (zero page)", errp);
goto out;
}
@@ -1257,7 +1232,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
false);
if (ret < 0) {
dump_error(s, "dump: failed to write page desc.\n");
dump_error(s, "dump: failed to write page desc", errp);
goto out;
}
} else {
@@ -1282,7 +1257,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data.\n");
dump_error(s, "dump: failed to write page data", errp);
goto out;
}
#ifdef CONFIG_LZO
@@ -1295,7 +1270,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data.\n");
dump_error(s, "dump: failed to write page data", errp);
goto out;
}
#endif
@@ -1309,7 +1284,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_data, buf_out, size_out, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data.\n");
dump_error(s, "dump: failed to write page data", errp);
goto out;
}
#endif
@@ -1324,7 +1299,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
if (ret < 0) {
dump_error(s, "dump: failed to write page data.\n");
dump_error(s, "dump: failed to write page data", errp);
goto out;
}
}
@@ -1336,7 +1311,7 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
if (ret < 0) {
dump_error(s, "dump: failed to write page desc.\n");
dump_error(s, "dump: failed to write page desc", errp);
goto out;
}
}
@@ -1344,12 +1319,12 @@ static int write_dump_pages(DumpState *s)
ret = write_cache(&page_desc, NULL, 0, true);
if (ret < 0) {
dump_error(s, "dump: failed to sync cache for page_desc.\n");
dump_error(s, "dump: failed to sync cache for page_desc", errp);
goto out;
}
ret = write_cache(&page_data, NULL, 0, true);
if (ret < 0) {
dump_error(s, "dump: failed to sync cache for page_data.\n");
dump_error(s, "dump: failed to sync cache for page_data", errp);
goto out;
}
@@ -1362,13 +1337,12 @@ out:
#endif
g_free(buf_out);
return ret;
}
static int create_kdump_vmcore(DumpState *s)
static void create_kdump_vmcore(DumpState *s, Error **errp)
{
int ret;
Error *local_err = NULL;
/*
* the kdump-compressed format is:
@@ -1394,34 +1368,35 @@ static int create_kdump_vmcore(DumpState *s)
ret = write_start_flat_header(s->fd);
if (ret < 0) {
dump_error(s, "dump: failed to write start flat header.\n");
return -1;
dump_error(s, "dump: failed to write start flat header", errp);
return;
}
ret = write_dump_header(s);
if (ret < 0) {
return -1;
write_dump_header(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = write_dump_bitmap(s);
if (ret < 0) {
return -1;
write_dump_bitmap(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = write_dump_pages(s);
if (ret < 0) {
return -1;
write_dump_pages(s, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = write_end_flat_header(s->fd);
if (ret < 0) {
dump_error(s, "dump: failed to write end flat header.\n");
return -1;
dump_error(s, "dump: failed to write end flat header", errp);
return;
}
dump_completed(s);
return 0;
}
static ram_addr_t get_start_block(DumpState *s)
@@ -1460,9 +1435,9 @@ static void get_max_mapnr(DumpState *s)
s->max_mapnr = paddr_to_pfn(last_block->target_end);
}
static int dump_init(DumpState *s, int fd, bool has_format,
DumpGuestMemoryFormat format, bool paging, bool has_filter,
int64_t begin, int64_t length, Error **errp)
static void dump_init(DumpState *s, int fd, bool has_format,
DumpGuestMemoryFormat format, bool paging, bool has_filter,
int64_t begin, int64_t length, Error **errp)
{
CPUState *cpu;
int nr_cpus;
@@ -1567,7 +1542,7 @@ static int dump_init(DumpState *s, int fd, bool has_format,
s->flag_compress = 0;
}
return 0;
return;
}
if (s->has_filter) {
@@ -1616,11 +1591,10 @@ static int dump_init(DumpState *s, int fd, bool has_format,
}
}
return 0;
return;
cleanup:
dump_cleanup(s);
return -1;
}
void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
@@ -1631,7 +1605,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
const char *p;
int fd = -1;
DumpState *s;
int ret;
Error *local_err = NULL;
/*
* kdump-compressed format need the whole memory dumped, so paging or
@@ -1691,21 +1665,18 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
s = g_malloc0(sizeof(DumpState));
ret = dump_init(s, fd, has_format, format, paging, has_begin,
begin, length, errp);
if (ret < 0) {
dump_init(s, fd, has_format, format, paging, has_begin,
begin, length, &local_err);
if (local_err) {
g_free(s);
error_propagate(errp, local_err);
return;
}
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
if (create_kdump_vmcore(s) < 0) {
error_set(errp, QERR_IO_ERROR);
}
create_kdump_vmcore(s, errp);
} else {
if (create_vmcore(s) < 0) {
error_set(errp, QERR_IO_ERROR);
}
create_vmcore(s, errp);
}
g_free(s);

View File

@@ -7240,13 +7240,17 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
* minnum() and maxnum correspond to the IEEE 754-2008 minNum()
* and maxNum() operations. min() and max() are the typical min/max
* semantics provided by many CPUs which predate that specification.
*
* minnummag() and maxnummag() functions correspond to minNumMag()
* and minNumMag() from the IEEE-754 2008.
*/
#define MINMAX(s) \
static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
int ismin, int isieee STATUS_PARAM) \
int ismin, int isieee, \
int ismag STATUS_PARAM) \
{ \
flag aSign, bSign; \
uint ## s ## _t av, bv; \
uint ## s ## _t av, bv, aav, abv; \
a = float ## s ## _squash_input_denormal(a STATUS_VAR); \
b = float ## s ## _squash_input_denormal(b STATUS_VAR); \
if (float ## s ## _is_any_nan(a) || \
@@ -7266,6 +7270,17 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
bSign = extractFloat ## s ## Sign(b); \
av = float ## s ## _val(a); \
bv = float ## s ## _val(b); \
if (ismag) { \
aav = float ## s ## _abs(av); \
abv = float ## s ## _abs(bv); \
if (aav != abv) { \
if (ismin) { \
return (aav < abv) ? a : b; \
} else { \
return (aav < abv) ? b : a; \
} \
} \
} \
if (aSign != bSign) { \
if (ismin) { \
return aSign ? a : b; \
@@ -7283,22 +7298,32 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
\
float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 1, 0 STATUS_VAR); \
return float ## s ## _minmax(a, b, 1, 0, 0 STATUS_VAR); \
} \
\
float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 0, 0 STATUS_VAR); \
return float ## s ## _minmax(a, b, 0, 0, 0 STATUS_VAR); \
} \
\
float ## s float ## s ## _minnum(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 1, 1 STATUS_VAR); \
return float ## s ## _minmax(a, b, 1, 1, 0 STATUS_VAR); \
} \
\
float ## s float ## s ## _maxnum(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 0, 1 STATUS_VAR); \
return float ## s ## _minmax(a, b, 0, 1, 0 STATUS_VAR); \
} \
\
float ## s float ## s ## _minnummag(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 1, 1, 1 STATUS_VAR); \
} \
\
float ## s float ## s ## _maxnummag(float ## s a, float ## s b STATUS_PARAM) \
{ \
return float ## s ## _minmax(a, b, 0, 1, 1 STATUS_VAR); \
}
MINMAX(32)

View File

@@ -1748,8 +1748,6 @@ show information about active capturing
show list of VM snapshots
@item info status
show the current VM status (running|paused)
@item info pcmcia
show guest PCMCIA status
@item info mice
show which guest mouse is receiving events
@item info vnc

View File

@@ -354,8 +354,8 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
}
}
static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
@@ -615,7 +615,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
dc->cannot_instantiate_with_device_add_yet = true;
dc->hotpluggable = false;
hc->plug = piix4_device_plug_cb;
hc->unplug = piix4_device_unplug_cb;
hc->unplug_request = piix4_device_unplug_request_cb;
adevc->ospm_status = piix4_ospm_status;
}

View File

@@ -478,7 +478,7 @@ static void do_cpu_reset(void *opaque)
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
{
CPUState *cs = CPU(cpu);
CPUState *cs;
int kernel_size;
int initrd_size;
int is_linux = 0;
@@ -488,6 +488,15 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
int big_endian;
static const ARMInsnFixup *primary_loader;
/* CPU objects (unlike devices) are not automatically reset on system
* reset, so we must always register a handler to do so. If we're
* actually loading a kernel, the handler is also responsible for
* arranging that we start it correctly.
*/
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
}
/* Load the kernel. */
if (!info->kernel_filename) {
@@ -652,9 +661,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
}
info->is_linux = is_linux;
for (; cs; cs = CPU_NEXT(cs)) {
cpu = ARM_CPU(cs);
cpu->env.boot_info = info;
qemu_register_reset(do_cpu_reset, cpu);
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
ARM_CPU(cs)->env.boot_info = info;
}
}

View File

@@ -15,7 +15,7 @@
#include "strongarm.h"
#include "hw/arm/arm.h"
#include "hw/block/flash.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
static struct arm_boot_info collie_binfo = {
@@ -41,13 +41,13 @@ static void collie_init(MachineState *machine)
dinfo = drive_get(IF_PFLASH, 0, 0);
pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
(64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
dinfo = drive_get(IF_PFLASH, 0, 1);
pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
(64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
sysbus_create_simple("scoop", 0x40800000, NULL);

View File

@@ -40,7 +40,7 @@
#include "hw/block/flash.h"
#include "hw/devices.h"
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
@@ -71,7 +71,7 @@ static void connex_init(MachineState *machine)
be = 0;
#endif
if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
dinfo ? dinfo->bdrv : NULL,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
sector_len, connex_rom / sector_len,
2, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -109,7 +109,7 @@ static void verdex_init(MachineState *machine)
be = 0;
#endif
if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
dinfo ? dinfo->bdrv : NULL,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
sector_len, verdex_rom / sector_len,
2, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");

View File

@@ -24,7 +24,7 @@
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"

View File

@@ -18,7 +18,7 @@
#include "hw/devices.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
#include "sysemu/qtest.h"
@@ -149,9 +149,9 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
i ? "mainstone.flash1" : "mainstone.flash0",
MAINSTONE_FLASH,
dinfo->bdrv, sector_len,
MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
be)) {
blk_by_legacy_dinfo(dinfo),
sector_len, MAINSTONE_FLASH / sector_len,
4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
exit(1);
}

View File

@@ -18,11 +18,10 @@
#include "hw/char/serial.h"
#include "qemu/timer.h"
#include "hw/ptimer.h"
#include "block/block.h"
#include "hw/block/flash.h"
#include "ui/console.h"
#include "hw/i2c/i2c.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "ui/pixel_ops.h"
@@ -1632,7 +1631,9 @@ static void musicpal_init(MachineState *machine)
/* Register flash */
dinfo = drive_get(IF_PFLASH, 0, 0);
if (dinfo) {
flash_size = bdrv_getlength(dinfo->bdrv);
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
flash_size = blk_getlength(blk);
if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
flash_size != 32*1024*1024) {
fprintf(stderr, "Invalid flash image size\n");
@@ -1647,16 +1648,14 @@ static void musicpal_init(MachineState *machine)
#ifdef TARGET_WORDS_BIGENDIAN
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
"musicpal.flash", flash_size,
dinfo->bdrv, 0x10000,
(flash_size + 0xffff) >> 16,
blk, 0x10000, (flash_size + 0xffff) >> 16,
MP_FLASH_SIZE_MAX / flash_size,
2, 0x00BF, 0x236D, 0x0000, 0x0000,
0x5555, 0x2AAA, 1);
#else
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
"musicpal.flash", flash_size,
dinfo->bdrv, 0x10000,
(flash_size + 0xffff) >> 16,
blk, 0x10000, (flash_size + 0xffff) >> 16,
MP_FLASH_SIZE_MAX / flash_size,
2, 0x00BF, 0x236D, 0x0000, 0x0000,
0x5555, 0x2AAA, 0);

View File

@@ -31,7 +31,7 @@
#include "hw/hw.h"
#include "hw/bt.h"
#include "hw/loader.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
@@ -172,8 +172,9 @@ static void n8x0_nand_setup(struct n800_s *s)
qdev_prop_set_uint16(s->nand, "version_id", 0);
qdev_prop_set_int32(s->nand, "shift", 1);
dinfo = drive_get(IF_MTD, 0, 0);
if (dinfo && dinfo->bdrv) {
qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv);
if (dinfo) {
qdev_prop_set_drive_nofail(s->nand, "drive",
blk_by_legacy_dinfo(dinfo));
}
qdev_init_nofail(s->nand);
sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,

View File

@@ -21,6 +21,7 @@
#include "hw/arm/omap.h"
#include "sysemu/sysemu.h"
#include "hw/arm/soc_dma.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "qemu/range.h"
#include "hw/sysbus.h"
@@ -3978,7 +3979,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = omap_mmc_init(0xfffb7800, system_memory, dinfo->bdrv,
s->mmc = omap_mmc_init(0xfffb7800, system_memory,
blk_by_legacy_dinfo(dinfo),
qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
&s->drq[OMAP_DMA_MMC_TX],
omap_findclk(s, "mmc_ck"));

View File

@@ -18,6 +18,7 @@
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/hw.h"
#include "hw/arm/arm.h"
@@ -2461,7 +2462,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9),
blk_by_legacy_dinfo(dinfo),
qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
&s->drq[OMAP24XX_DMA_MMC1_TX],
omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));

View File

@@ -31,7 +31,7 @@
#include "hw/boards.h"
#include "hw/arm/arm.h"
#include "hw/block/flash.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "sysemu/qtest.h"
#include "exec/address-spaces.h"
@@ -154,8 +154,8 @@ static void sx1_init(MachineState *machine, const int version)
if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
"omap_sx1.flash0-1", flash_size,
dinfo->bdrv, sector_size,
flash_size / sector_size,
blk_by_legacy_dinfo(dinfo),
sector_size, flash_size / sector_size,
4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
fl_idx);
@@ -178,8 +178,8 @@ static void sx1_init(MachineState *machine, const int version)
if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
"omap_sx1.flash1-1", flash1_size,
dinfo->bdrv, sector_size,
flash1_size / sector_size,
blk_by_legacy_dinfo(dinfo),
sector_size, flash1_size / sector_size,
4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
fl_idx);

View File

@@ -14,6 +14,7 @@
#include "hw/i2c/i2c.h"
#include "hw/ssi.h"
#include "sysemu/char.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
static struct {
@@ -2085,7 +2086,8 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv,
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
blk_by_legacy_dinfo(dinfo),
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
@@ -2217,7 +2219,8 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
fprintf(stderr, "qemu: missing SecureDigital device\n");
exit(1);
}
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv,
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
blk_by_legacy_dinfo(dinfo),
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));

View File

@@ -16,7 +16,7 @@
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/error-report.h"

View File

@@ -22,10 +22,9 @@
#include "hw/devices.h"
#include "hw/arm/sharpsl.h"
#include "ui/console.h"
#include "block/block.h"
#include "audio/audio.h"
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"
@@ -170,7 +169,8 @@ static int sl_nand_init(SysBusDevice *dev)
s->ctl = 0;
nand = drive_get(IF_MTD, 0, 0);
s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
s->manf_id, s->chip_id);
memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40);
sysbus_init_mmio(dev, &s->iomem);

View File

@@ -17,11 +17,10 @@
#include "hw/devices.h"
#include "hw/arm/sharpsl.h"
#include "hw/pcmcia.h"
#include "block/block.h"
#include "hw/boards.h"
#include "hw/i2c/i2c.h"
#include "hw/ssi.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/sysbus.h"
#include "exec/address-spaces.h"

View File

@@ -15,7 +15,7 @@
#include "hw/pci/pci.h"
#include "hw/i2c/i2c.h"
#include "hw/boards.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "hw/block/flash.h"
@@ -338,7 +338,8 @@ static void versatile_init(MachineState *machine, int board_id)
dinfo = drive_get(IF_PFLASH, 0, 0);
if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
VERSATILE_FLASH_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
VERSATILE_FLASH_SECT_SIZE,
VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {

View File

@@ -30,7 +30,7 @@
#include "hw/boards.h"
#include "hw/loader.h"
#include "exec/address-spaces.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/block/flash.h"
#include "sysemu/device_tree.h"
#include "qemu/error-report.h"
@@ -491,7 +491,8 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
{
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
if (di && qdev_prop_set_drive(dev, "drive", di->bdrv)) {
if (di && qdev_prop_set_drive(dev, "drive",
blk_by_legacy_dinfo(di))) {
abort();
}

View File

@@ -33,6 +33,7 @@
#include "hw/arm/primecell.h"
#include "hw/devices.h"
#include "net/net.h"
#include "sysemu/block-backend.h"
#include "sysemu/device_tree.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
@@ -190,47 +191,48 @@ static void create_fdt(VirtBoardInfo *vbi)
static void fdt_add_psci_node(const VirtBoardInfo *vbi)
{
uint32_t cpu_suspend_fn;
uint32_t cpu_off_fn;
uint32_t cpu_on_fn;
uint32_t migrate_fn;
void *fdt = vbi->fdt;
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
/* No PSCI for TCG yet */
if (kvm_enabled()) {
uint32_t cpu_suspend_fn;
uint32_t cpu_off_fn;
uint32_t cpu_on_fn;
uint32_t migrate_fn;
qemu_fdt_add_subnode(fdt, "/psci");
if (armcpu->psci_version == 2) {
const char comp[] = "arm,psci-0.2\0arm,psci";
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
qemu_fdt_add_subnode(fdt, "/psci");
if (armcpu->psci_version == 2) {
const char comp[] = "arm,psci-0.2\0arm,psci";
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
} else {
cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
}
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
} else {
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
}
} else {
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
}
/* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer
* to the instruction that should be used to invoke PSCI functions.
* However, the device tree binding uses 'method' instead, so that is
* what we should use here.
*/
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
}
static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
@@ -239,14 +241,23 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
* but for the GIC implementation provided by both QEMU and KVM
* they are edge-triggered.
*/
ARMCPU *armcpu;
uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
qemu_fdt_add_subnode(vbi->fdt, "/timer");
qemu_fdt_setprop_string(vbi->fdt, "/timer",
"compatible", "arm,armv7-timer");
armcpu = ARM_CPU(qemu_get_cpu(0));
if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
const char compat[] = "arm,armv8-timer\0arm,armv7-timer";
qemu_fdt_setprop(vbi->fdt, "/timer", "compatible",
compat, sizeof(compat));
} else {
qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible",
"arm,armv7-timer");
}
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
@@ -450,7 +461,8 @@ static void create_one_flash(const char *name, hwaddr flashbase,
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
const uint64_t sectorlength = 256 * 1024;
if (dinfo && qdev_prop_set_drive(dev, "drive", dinfo->bdrv)) {
if (dinfo && qdev_prop_set_drive(dev, "drive",
blk_by_legacy_dinfo(dinfo))) {
abort();
}
@@ -537,23 +549,12 @@ static void machvirt_init(MachineState *machine)
vbi->smp_cpus = smp_cpus;
/*
* Only supported method of starting secondary CPUs is PSCI and
* PSCI is not yet supported with TCG, so limit smp_cpus to 1
* if we're not using KVM.
*/
if (!kvm_enabled() && smp_cpus > 1) {
error_report("mach-virt: must enable KVM to use multiple CPUs");
exit(1);
}
if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
error_report("mach-virt: cannot model more than 30GB RAM");
exit(1);
}
create_fdt(vbi);
fdt_add_timer_nodes(vbi);
for (n = 0; n < smp_cpus; n++) {
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
@@ -565,6 +566,9 @@ static void machvirt_init(MachineState *machine)
}
cpuobj = object_new(object_class_get_name(oc));
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
NULL);
/* Secondary CPUs start in PSCI powered-down state */
if (n > 0) {
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
@@ -577,6 +581,7 @@ static void machvirt_init(MachineState *machine)
object_property_set_bool(cpuobj, true, "realized", NULL);
}
fdt_add_timer_nodes(vbi);
fdt_add_cpu_nodes(vbi);
fdt_add_psci_node(vbi);

View File

@@ -22,7 +22,7 @@
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/block/flash.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/loader.h"
#include "hw/ssi.h"
#include "qemu/error-report.h"
@@ -164,7 +164,8 @@ static void zynq_init(MachineState *machine)
/* AMD */
pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE,
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
FLASH_SECTOR_SIZE,
FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
0);

View File

@@ -20,7 +20,7 @@
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "hw/block/flash.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "ui/console.h"
#include "audio/audio.h"
#include "exec/address-spaces.h"
@@ -336,9 +336,9 @@ static void z2_init(MachineState *machine)
if (!pflash_cfi01_register(Z2_FLASH_BASE,
NULL, "z2.flash0", Z2_FLASH_SIZE,
dinfo ? dinfo->bdrv : NULL, sector_len,
Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
be)) {
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
sector_len, Z2_FLASH_SIZE / sector_len,
4, 0, 0, 0, 0, be)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
exit(1);
}

View File

@@ -8,6 +8,7 @@
*/
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "qemu/error-report.h"
@@ -17,8 +18,10 @@ void blkconf_serial(BlockConf *conf, char **serial)
if (!*serial) {
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev(conf->bs);
*serial = g_strdup(dinfo->serial);
dinfo = blk_legacy_dinfo(conf->blk);
if (dinfo) {
*serial = g_strdup(dinfo->serial);
}
}
}
@@ -30,16 +33,18 @@ void blkconf_geometry(BlockConf *conf, int *ptrans,
if (!conf->cyls && !conf->heads && !conf->secs) {
/* try to fall back to value set with legacy -drive cyls=... */
dinfo = drive_get_by_blockdev(conf->bs);
conf->cyls = dinfo->cyls;
conf->heads = dinfo->heads;
conf->secs = dinfo->secs;
if (ptrans) {
*ptrans = dinfo->trans;
dinfo = blk_legacy_dinfo(conf->blk);
if (dinfo) {
conf->cyls = dinfo->cyls;
conf->heads = dinfo->heads;
conf->secs = dinfo->secs;
if (ptrans) {
*ptrans = dinfo->trans;
}
}
}
if (!conf->cyls && !conf->heads && !conf->secs) {
hd_geometry_guess(conf->bs,
hd_geometry_guess(conf->blk,
&conf->cyls, &conf->heads, &conf->secs,
ptrans);
} else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {

View File

@@ -17,7 +17,7 @@
#include "qemu/thread.h"
#include "qemu/error-report.h"
#include "hw/virtio/dataplane/vring.h"
#include "block/block.h"
#include "sysemu/block-backend.h"
#include "hw/virtio/virtio-blk.h"
#include "virtio-blk.h"
#include "block/aio.h"
@@ -30,7 +30,7 @@ struct VirtIOBlockDataPlane {
bool stopping;
bool disabled;
VirtIOBlkConf *blk;
VirtIOBlkConf *conf;
VirtIODevice *vdev;
Vring vring; /* virtqueue vring */
@@ -94,7 +94,7 @@ static void handle_notify(EventNotifier *e)
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
event_notifier_test_and_clear(&s->host_notifier);
bdrv_io_plug(s->blk->conf.bs);
blk_io_plug(s->conf->conf.blk);
for (;;) {
MultiReqBuffer mrb = {
.num_writes = 0,
@@ -120,7 +120,7 @@ static void handle_notify(EventNotifier *e)
virtio_blk_handle_request(req, &mrb);
}
virtio_submit_multiwrite(s->blk->conf.bs, &mrb);
virtio_submit_multiwrite(s->conf->conf.blk, &mrb);
if (likely(ret == -EAGAIN)) { /* vring emptied */
/* Re-enable guest->host notifies and stop processing the vring.
@@ -133,11 +133,11 @@ static void handle_notify(EventNotifier *e)
break;
}
}
bdrv_io_unplug(s->blk->conf.bs);
blk_io_unplug(s->conf->conf.blk);
}
/* Context: QEMU global mutex held */
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
Error **errp)
{
@@ -148,7 +148,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
*dataplane = NULL;
if (!blk->data_plane && !blk->iothread) {
if (!conf->data_plane && !conf->iothread) {
return;
}
@@ -163,7 +163,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
/* If dataplane is (re-)enabled while the guest is running there could be
* block jobs that can conflict.
*/
if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE,
&local_err)) {
error_setg(errp, "cannot start dataplane thread: %s",
error_get_pretty(local_err));
error_free(local_err);
@@ -172,10 +173,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
s = g_new0(VirtIOBlockDataPlane, 1);
s->vdev = vdev;
s->blk = blk;
s->conf = conf;
if (blk->iothread) {
s->iothread = blk->iothread;
if (conf->iothread) {
s->iothread = conf->iothread;
object_ref(OBJECT(s->iothread));
} else {
/* Create per-device IOThread if none specified. This is for
@@ -192,9 +193,9 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
error_setg(&s->blocker, "block device is in use by data plane");
bdrv_op_block_all(blk->conf.bs, s->blocker);
bdrv_op_unblock(blk->conf.bs, BLOCK_OP_TYPE_RESIZE, s->blocker);
bdrv_op_unblock(blk->conf.bs, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
blk_op_block_all(conf->conf.blk, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
*dataplane = s;
}
@@ -207,7 +208,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
}
virtio_blk_data_plane_stop(s);
bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
blk_op_unblock_all(s->conf->conf.blk, s->blocker);
error_free(s->blocker);
object_unref(OBJECT(s->iothread));
qemu_bh_delete(s->bh);
@@ -262,7 +263,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
s->started = true;
trace_virtio_blk_data_plane_start(s);
bdrv_set_aio_context(s->blk->conf.bs, s->ctx);
blk_set_aio_context(s->conf->conf.blk, s->ctx);
/* Kick right away to begin processing requests already in vring */
event_notifier_set(virtio_queue_get_host_notifier(vq));
@@ -308,7 +309,7 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
/* Drain and switch bs back to the QEMU main loop */
bdrv_set_aio_context(s->blk->conf.bs, qemu_get_aio_context());
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
aio_context_release(s->ctx);

View File

@@ -19,7 +19,7 @@
typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
Error **errp);
void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);

View File

@@ -33,6 +33,7 @@
#include "qemu/timer.h"
#include "hw/isa/isa.h"
#include "hw/sysbus.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
@@ -113,7 +114,7 @@ static const FDFormat fd_formats[] = {
{ FDRIVE_DRV_NONE, -1, -1, 0, 0, },
};
static void pick_geometry(BlockDriverState *bs, int *nb_heads,
static void pick_geometry(BlockBackend *blk, int *nb_heads,
int *max_track, int *last_sect,
FDriveType drive_in, FDriveType *drive,
FDriveRate *rate)
@@ -122,7 +123,7 @@ static void pick_geometry(BlockDriverState *bs, int *nb_heads,
uint64_t nb_sectors, size;
int i, first_match, match;
bdrv_get_geometry(bs, &nb_sectors);
blk_get_geometry(blk, &nb_sectors);
match = -1;
first_match = -1;
for (i = 0; ; i++) {
@@ -175,7 +176,7 @@ typedef enum FDiskFlags {
typedef struct FDrive {
FDCtrl *fdctrl;
BlockDriverState *bs;
BlockBackend *blk;
/* Drive status */
FDriveType drive;
uint8_t perpendicular; /* 2.88 MB access mode */
@@ -260,7 +261,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
#endif
drv->head = head;
if (drv->track != track) {
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
drv->media_changed = 0;
}
ret = 1;
@@ -269,7 +270,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
drv->sect = sect;
}
if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
ret = 2;
}
@@ -291,11 +292,11 @@ static void fd_revalidate(FDrive *drv)
FDriveRate rate;
FLOPPY_DPRINTF("revalidate\n");
if (drv->bs != NULL) {
ro = bdrv_is_read_only(drv->bs);
pick_geometry(drv->bs, &nb_heads, &max_track,
if (drv->blk != NULL) {
ro = blk_is_read_only(drv->blk);
pick_geometry(drv->blk, &nb_heads, &max_track,
&last_sect, drv->drive, &drive, &rate);
if (!bdrv_is_inserted(drv->bs)) {
if (!blk_is_inserted(drv->blk)) {
FLOPPY_DPRINTF("No disk in drive\n");
} else {
FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
@@ -665,7 +666,7 @@ static bool fdrive_media_changed_needed(void *opaque)
{
FDrive *drive = opaque;
return (drive->bs != NULL && drive->media_changed != 1);
return (drive->blk != NULL && drive->media_changed != 1);
}
static const VMStateDescription vmstate_fdrive_media_changed = {
@@ -910,8 +911,9 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
/* Initialise controller */
fdctrl->sra = 0;
fdctrl->srb = 0xc0;
if (!fdctrl->drives[1].bs)
if (!fdctrl->drives[1].blk) {
fdctrl->sra |= FD_SRA_nDRV2;
}
fdctrl->cur_drv = 0;
fdctrl->dor = FD_DOR_nRESET;
fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
@@ -1403,7 +1405,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
status2 = FD_SR2_SNS;
if (dma_len > fdctrl->data_len)
dma_len = fdctrl->data_len;
if (cur_drv->bs == NULL) {
if (cur_drv->blk == NULL) {
if (fdctrl->data_dir == FD_DIR_WRITE)
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
else
@@ -1424,8 +1426,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
if (fdctrl->data_dir != FD_DIR_WRITE ||
len < FD_SECTOR_LEN || rel_pos != 0) {
/* READ & SCAN commands and realign to a sector for WRITE */
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
fdctrl->fifo, 1) < 0) {
if (blk_read(cur_drv->blk, fd_sector(cur_drv),
fdctrl->fifo, 1) < 0) {
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
fd_sector(cur_drv));
/* Sure, image size is too small... */
@@ -1452,8 +1454,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
fdctrl->data_pos, len);
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
fdctrl->fifo, 1) < 0) {
if (blk_write(cur_drv->blk, fd_sector(cur_drv),
fdctrl->fifo, 1) < 0) {
FLOPPY_DPRINTF("error writing sector %d\n",
fd_sector(cur_drv));
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
@@ -1528,7 +1530,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
fd_sector(cur_drv));
return 0;
}
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
if (blk_read(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
< 0) {
FLOPPY_DPRINTF("error getting sector %d\n",
fd_sector(cur_drv));
/* Sure, image size is too small... */
@@ -1597,8 +1600,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
break;
}
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
if (cur_drv->bs == NULL ||
bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
if (cur_drv->blk == NULL ||
blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
} else {
@@ -1988,7 +1991,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
if (pos == FD_SECTOR_LEN - 1 ||
fdctrl->data_pos == fdctrl->data_len) {
cur_drv = get_cur_drv(fdctrl);
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
< 0) {
FLOPPY_DPRINTF("error writing sector %d\n",
fd_sector(cur_drv));
return;
@@ -2076,12 +2080,12 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
drive = &fdctrl->drives[i];
drive->fdctrl = fdctrl;
if (drive->bs) {
if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
if (drive->blk) {
if (blk_get_on_error(drive->blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
error_setg(errp, "fdc doesn't support drive option werror");
return;
}
if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
if (blk_get_on_error(drive->blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
error_setg(errp, "fdc doesn't support drive option rerror");
return;
}
@@ -2089,8 +2093,8 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
fd_init(drive);
fdctrl_change_cb(drive, 0);
if (drive->bs) {
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
if (drive->blk) {
blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
}
}
}
@@ -2107,10 +2111,10 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
dev = DEVICE(isadev);
if (fds[0]) {
qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0]));
}
if (fds[1]) {
qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1]));
}
qdev_init_nofail(dev);
@@ -2130,10 +2134,10 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
if (fds[0]) {
qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0]));
}
if (fds[1]) {
qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1]));
}
qdev_init_nofail(dev);
sbd = SYS_BUS_DEVICE(dev);
@@ -2149,7 +2153,7 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
dev = qdev_create(NULL, "SUNW,fdtwo");
if (fds[0]) {
qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(fds[0]));
}
qdev_init_nofail(dev);
sys = SYSBUS_FDC(dev);
@@ -2286,8 +2290,8 @@ static Property isa_fdc_properties[] = {
DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].blk),
DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].blk),
DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
0, true),
DEFINE_PROP_END_OF_LIST(),
@@ -2336,8 +2340,8 @@ static const VMStateDescription vmstate_sysbus_fdc ={
};
static Property sysbus_fdc_properties[] = {
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].blk),
DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].blk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2357,7 +2361,7 @@ static const TypeInfo sysbus_fdc_info = {
};
static Property sun4m_fdc_properties[] = {
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].blk),
DEFINE_PROP_END_OF_LIST(),
};

View File

@@ -30,7 +30,7 @@
* THE SOFTWARE.
*/
#include "block/block.h"
#include "sysemu/block-backend.h"
#include "hw/block/block.h"
#include "trace.h"
@@ -49,7 +49,7 @@ struct partition {
/* try to guess the disk logical geometry from the MSDOS partition table.
Return 0 if OK, -1 if could not guess */
static int guess_disk_lchs(BlockDriverState *bs,
static int guess_disk_lchs(BlockBackend *blk,
int *pcylinders, int *pheads, int *psectors)
{
uint8_t buf[BDRV_SECTOR_SIZE];
@@ -58,14 +58,14 @@ static int guess_disk_lchs(BlockDriverState *bs,
uint32_t nr_sects;
uint64_t nb_sectors;
bdrv_get_geometry(bs, &nb_sectors);
blk_get_geometry(blk, &nb_sectors);
/**
* The function will be invoked during startup not only in sync I/O mode,
* but also in async I/O mode. So the I/O throttling function has to
* be disabled temporarily here, not permanently.
*/
if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
if (blk_read_unthrottled(blk, 0, buf, 1) < 0) {
return -1;
}
/* test msdos magic */
@@ -90,20 +90,20 @@ static int guess_disk_lchs(BlockDriverState *bs,
*pheads = heads;
*psectors = sectors;
*pcylinders = cylinders;
trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
trace_hd_geometry_lchs_guess(blk, cylinders, heads, sectors);
return 0;
}
}
return -1;
}
static void guess_chs_for_size(BlockDriverState *bs,
static void guess_chs_for_size(BlockBackend *blk,
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
{
uint64_t nb_sectors;
int cylinders;
bdrv_get_geometry(bs, &nb_sectors);
blk_get_geometry(blk, &nb_sectors);
cylinders = nb_sectors / (16 * 63);
if (cylinders > 16383) {
@@ -116,21 +116,21 @@ static void guess_chs_for_size(BlockDriverState *bs,
*psecs = 63;
}
void hd_geometry_guess(BlockDriverState *bs,
void hd_geometry_guess(BlockBackend *blk,
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
int *ptrans)
{
int cylinders, heads, secs, translation;
if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
/* no LCHS guess: use a standard physical disk geometry */
guess_chs_for_size(bs, pcyls, pheads, psecs);
guess_chs_for_size(blk, pcyls, pheads, psecs);
translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
} else if (heads > 16) {
/* LCHS guess with heads > 16 means that a BIOS LBA
translation was active, so a standard physical disk
geometry is OK */
guess_chs_for_size(bs, pcyls, pheads, psecs);
guess_chs_for_size(blk, pcyls, pheads, psecs);
translation = *pcyls * *pheads <= 131072
? BIOS_ATA_TRANSLATION_LARGE
: BIOS_ATA_TRANSLATION_LBA;
@@ -146,7 +146,7 @@ void hd_geometry_guess(BlockDriverState *bs,
if (ptrans) {
*ptrans = translation;
}
trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation);
}
int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)

View File

@@ -22,6 +22,7 @@
*/
#include "hw/hw.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/ssi.h"
@@ -245,7 +246,7 @@ typedef struct Flash {
uint32_t r;
BlockDriverState *bdrv;
BlockBackend *blk;
uint8_t *storage;
uint32_t size;
@@ -279,7 +280,7 @@ typedef struct M25P80Class {
#define M25P80_GET_CLASS(obj) \
OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
static void bdrv_sync_complete(void *opaque, int ret)
static void blk_sync_complete(void *opaque, int ret)
{
/* do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required.
@@ -288,20 +289,20 @@ static void bdrv_sync_complete(void *opaque, int ret)
static void flash_sync_page(Flash *s, int page)
{
int bdrv_sector, nb_sectors;
int blk_sector, nb_sectors;
QEMUIOVector iov;
if (!s->bdrv || bdrv_is_read_only(s->bdrv)) {
if (!s->blk || blk_is_read_only(s->blk)) {
return;
}
bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
blk_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
qemu_iovec_init(&iov, 1);
qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE,
qemu_iovec_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE,
nb_sectors * BDRV_SECTOR_SIZE);
bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, bdrv_sync_complete,
NULL);
blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete,
NULL);
}
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
@@ -309,7 +310,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
int64_t start, end, nb_sectors;
QEMUIOVector iov;
if (!s->bdrv || bdrv_is_read_only(s->bdrv)) {
if (!s->blk || blk_is_read_only(s->blk)) {
return;
}
@@ -320,7 +321,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
qemu_iovec_init(&iov, 1);
qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
nb_sectors * BDRV_SECTOR_SIZE);
bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL);
blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL);
}
static void flash_erase(Flash *s, int offset, FlashCMD cmd)
@@ -620,17 +621,17 @@ static int m25p80_init(SSISlave *ss)
s->size = s->pi->sector_size * s->pi->n_sectors;
s->dirty_page = -1;
s->storage = qemu_blockalign(s->bdrv, s->size);
s->storage = blk_blockalign(s->blk, s->size);
dinfo = drive_get_next(IF_MTD);
if (dinfo && dinfo->bdrv) {
if (dinfo) {
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->bdrv = dinfo->bdrv;
s->blk = blk_by_legacy_dinfo(dinfo);
/* FIXME: Move to late init */
if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
BDRV_SECTOR_SIZE))) {
if (blk_read(s->blk, 0, s->storage,
DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) {
fprintf(stderr, "Failed to initialize SPI flash!\n");
return 1;
}

View File

@@ -20,7 +20,7 @@
# include "hw/hw.h"
# include "hw/block/flash.h"
# include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include "hw/qdev.h"
#include "qemu/error-report.h"
@@ -61,7 +61,7 @@ struct NANDFlashState {
int size, pages;
int page_shift, oob_shift, erase_shift, addr_shift;
uint8_t *storage;
BlockDriverState *bdrv;
BlockBackend *blk;
int mem_oob;
uint8_t cle, ale, ce, wp, gnd;
@@ -400,12 +400,12 @@ static void nand_realize(DeviceState *dev, Error **errp)
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
if (s->bdrv) {
if (bdrv_is_read_only(s->bdrv)) {
if (s->blk) {
if (blk_is_read_only(s->blk)) {
error_setg(errp, "Can't use a read-only drive");
return;
}
if (bdrv_getlength(s->bdrv) >=
if (blk_getlength(s->blk) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;
s->mem_oob = 0;
@@ -424,7 +424,7 @@ static void nand_realize(DeviceState *dev, Error **errp)
static Property nand_properties[] = {
DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
DEFINE_PROP_DRIVE("drive", NANDFlashState, blk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -624,7 +624,7 @@ uint32_t nand_getbuswidth(DeviceState *dev)
return s->buswidth << 3;
}
DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id)
{
DeviceState *dev;
@@ -634,8 +634,8 @@ DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
dev = DEVICE(object_new(TYPE_NAND));
qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
qdev_prop_set_uint8(dev, "chip_id", chip_id);
if (bdrv) {
qdev_prop_set_drive_nofail(dev, "drive", bdrv);
if (blk) {
qdev_prop_set_drive_nofail(dev, "drive", blk);
}
qdev_init_nofail(dev);
@@ -654,14 +654,14 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
if (PAGE(s->addr) >= s->pages)
return;
if (!s->bdrv) {
if (!s->blk) {
mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
s->offset, s->io, s->iolen);
} else if (s->mem_oob) {
sector = SECTOR(s->addr);
off = (s->addr & PAGE_MASK) + s->offset;
soff = SECTOR_OFFSET(s->addr);
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
@@ -673,21 +673,21 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
}
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
} else {
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
sector = off >> 9;
soff = off & 0x1ff;
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
return;
}
mem_and(iobuf + soff, s->io, s->iolen);
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
}
}
@@ -705,7 +705,7 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
return;
}
if (!s->bdrv) {
if (!s->blk) {
memset(s->storage + PAGE_START(addr),
0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
} else if (s->mem_oob) {
@@ -714,17 +714,17 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
i = SECTOR(addr);
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
for (; i < page; i ++)
if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) {
if (blk_write(s->blk, i, iobuf, 1) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
}
} else {
addr = PAGE_START(addr);
page = addr >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
if (blk_read(s->blk, page, iobuf, 1) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
if (blk_write(s->blk, page, iobuf, 1) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
@@ -732,18 +732,18 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
i = (addr & ~0x1ff) + 0x200;
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
i < addr; i += 0x200) {
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) {
if (blk_write(s->blk, i >> 9, iobuf, 1) < 0) {
printf("%s: write error in sector %" PRIu64 "\n",
__func__, i >> 9);
}
}
page = i >> 9;
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
if (blk_read(s->blk, page, iobuf, 1) < 0) {
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
}
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
if (blk_write(s->blk, page, iobuf, 1) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
}
}
@@ -756,9 +756,9 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
return;
}
if (s->bdrv) {
if (s->blk) {
if (s->mem_oob) {
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
if (blk_read(s->blk, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, SECTOR(addr));
}
@@ -767,8 +767,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
OOB_SIZE);
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
} else {
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
s->io, (PAGE_SECTORS + 2)) < 0) {
if (blk_read(s->blk, PAGE_START(addr) >> 9,
s->io, (PAGE_SECTORS + 2)) < 0) {
printf("%s: read error in sector %" PRIu64 "\n",
__func__, PAGE_START(addr) >> 9);
}

View File

@@ -26,6 +26,7 @@
#include <hw/pci/pci.h>
#include "sysemu/sysemu.h"
#include "qapi/visitor.h"
#include "sysemu/block-backend.h"
#include "nvme.h"
@@ -199,7 +200,7 @@ static void nvme_rw_cb(void *opaque, int ret)
NvmeCtrl *n = sq->ctrl;
NvmeCQueue *cq = n->cq[sq->cqid];
block_acct_done(bdrv_get_stats(n->conf.bs), &req->acct);
block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
if (!ret) {
req->status = NVME_SUCCESS;
} else {
@@ -233,11 +234,11 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
}
assert((nlb << data_shift) == req->qsg.size);
dma_acct_start(n->conf.bs, &req->acct, &req->qsg, is_write ?
BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
req->aiocb = is_write ?
dma_bdrv_write(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req) :
dma_bdrv_read(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req);
dma_blk_write(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req) :
dma_blk_read(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req);
return NVME_NO_COMPLETE;
}
@@ -290,7 +291,7 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
req = QTAILQ_FIRST(&sq->out_req_list);
assert(req->aiocb);
bdrv_aio_cancel(req->aiocb);
blk_aio_cancel(req->aiocb);
}
if (!nvme_check_cqid(n, sq->cqid)) {
cq = n->cq[sq->cqid];
@@ -565,7 +566,7 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
}
}
bdrv_flush(n->conf.bs);
blk_flush(n->conf.blk);
n->bar.cc = 0;
}
@@ -750,11 +751,11 @@ static int nvme_init(PCIDevice *pci_dev)
int64_t bs_size;
uint8_t *pci_conf;
if (!(n->conf.bs)) {
if (!n->conf.blk) {
return -1;
}
bs_size = bdrv_getlength(n->conf.bs);
bs_size = blk_getlength(n->conf.blk);
if (bs_size < 0) {
return -1;
}

View File

@@ -636,7 +636,7 @@ typedef struct NvmeAsyncEvent {
typedef struct NvmeRequest {
struct NvmeSQueue *sq;
BlockDriverAIOCB *aiocb;
BlockAIOCB *aiocb;
uint16_t status;
NvmeCqe cqe;
BlockAcctCookie acct;

View File

@@ -22,6 +22,7 @@
#include "hw/hw.h"
#include "hw/block/flash.h"
#include "hw/irq.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "exec/memory.h"
#include "exec/address-spaces.h"
@@ -49,8 +50,8 @@ typedef struct OneNANDState {
hwaddr base;
qemu_irq intr;
qemu_irq rdy;
BlockDriverState *bdrv;
BlockDriverState *bdrv_cur;
BlockBackend *blk;
BlockBackend *blk_cur;
uint8_t *image;
uint8_t *otp;
uint8_t *current;
@@ -213,7 +214,7 @@ static void onenand_reset(OneNANDState *s, int cold)
s->wpstatus = 0x0002;
s->cycle = 0;
s->otpmode = 0;
s->bdrv_cur = s->bdrv;
s->blk_cur = s->blk;
s->current = s->image;
s->secs_cur = s->secs;
@@ -221,7 +222,7 @@ static void onenand_reset(OneNANDState *s, int cold)
/* Lock the whole flash */
memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
if (s->blk_cur && blk_read(s->blk_cur, 0, s->boot[0], 8) < 0) {
hw_error("%s: Loading the BootRAM failed.\n", __func__);
}
}
@@ -237,10 +238,11 @@ static void onenand_system_reset(DeviceState *dev)
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
void *dest)
{
if (s->bdrv_cur)
return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
else if (sec + secn > s->secs_cur)
if (s->blk_cur) {
return blk_read(s->blk_cur, sec, dest, secn) < 0;
} else if (sec + secn > s->secs_cur) {
return 1;
}
memcpy(dest, s->current + (sec << 9), secn << 9);
@@ -256,9 +258,9 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
uint32_t size = (uint32_t)secn * 512;
const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0;
if (s->bdrv_cur) {
if (s->blk_cur) {
dp = g_malloc(size);
if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
if (!dp || blk_read(s->blk_cur, sec, dp, secn) < 0) {
result = 1;
}
} else {
@@ -273,11 +275,11 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
for (i = 0; i < size; i++) {
dp[i] &= sp[i];
}
if (s->bdrv_cur) {
result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
if (s->blk_cur) {
result = blk_write(s->blk_cur, sec, dp, secn) < 0;
}
}
if (dp && s->bdrv_cur) {
if (dp && s->blk_cur) {
g_free(dp);
}
}
@@ -290,14 +292,16 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
{
uint8_t buf[512];
if (s->bdrv_cur) {
if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
if (s->blk_cur) {
if (blk_read(s->blk_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) {
return 1;
}
memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
} else if (sec + secn > s->secs_cur)
} else if (sec + secn > s->secs_cur) {
return 1;
else
} else {
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
}
return 0;
}
@@ -309,11 +313,10 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
if (secn > 0) {
const uint8_t *sp = (const uint8_t *)src;
uint8_t *dp = 0, *dpp = 0;
if (s->bdrv_cur) {
if (s->blk_cur) {
dp = g_malloc(512);
if (!dp || bdrv_read(s->bdrv_cur,
s->secs_cur + (sec >> 5),
dp, 1) < 0) {
if (!dp
|| blk_read(s->blk_cur, s->secs_cur + (sec >> 5), dp, 1) < 0) {
result = 1;
} else {
dpp = dp + ((sec & 31) << 4);
@@ -330,9 +333,9 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
for (i = 0; i < (secn << 4); i++) {
dpp[i] &= sp[i];
}
if (s->bdrv_cur) {
result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
dp, 1) < 0;
if (s->blk_cur) {
result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5),
dp, 1) < 0;
}
}
g_free(dp);
@@ -354,16 +357,16 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num)
}
memset(blankbuf, 0xff, 512);
for (; num > 0; num--, sec++) {
if (s->bdrv_cur) {
if (s->blk_cur) {
int erasesec = s->secs_cur + (sec >> 5);
if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
if (blk_write(s->blk_cur, sec, blankbuf, 1) < 0) {
goto fail;
}
if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
if (blk_read(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
goto fail;
}
memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
if (blk_write(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
goto fail;
}
} else {
@@ -576,7 +579,7 @@ static void onenand_command(OneNANDState *s)
case 0x65: /* OTP Access */
s->intstatus |= ONEN_INT;
s->bdrv_cur = NULL;
s->blk_cur = NULL;
s->current = s->otp;
s->secs_cur = 1 << (BLOCK_SHIFT - 9);
s->addr[ONEN_BUF_BLOCK] = 0;
@@ -776,15 +779,15 @@ static int onenand_initfn(SysBusDevice *sbd)
? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
0x10000 << s->shift);
if (!s->bdrv) {
if (!s->blk) {
s->image = memset(g_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
} else {
if (bdrv_is_read_only(s->bdrv)) {
if (blk_is_read_only(s->blk)) {
error_report("Can't use a read-only drive");
return -1;
}
s->bdrv_cur = s->bdrv;
s->blk_cur = s->blk;
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
@@ -815,7 +818,7 @@ static Property onenand_properties[] = {
DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
DEFINE_PROP_END_OF_LIST(),
};

View File

@@ -38,7 +38,7 @@
#include "hw/hw.h"
#include "hw/block/flash.h"
#include "block/block.h"
#include "sysemu/block-backend.h"
#include "qemu/timer.h"
#include "qemu/bitops.h"
#include "exec/address-spaces.h"
@@ -69,7 +69,7 @@ struct pflash_t {
SysBusDevice parent_obj;
/*< public >*/
BlockDriverState *bs;
BlockBackend *blk;
uint32_t nb_blocs;
uint64_t sector_len;
uint8_t bank_width;
@@ -395,13 +395,13 @@ static void pflash_update(pflash_t *pfl, int offset,
int size)
{
int offset_end;
if (pfl->bs) {
if (pfl->blk) {
offset_end = offset + size;
/* round to sectors */
offset = offset >> 9;
offset_end = (offset_end + 511) >> 9;
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
offset_end - offset);
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
offset_end - offset);
}
}
@@ -784,9 +784,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->bs) {
if (pfl->blk) {
/* read the initial flash content */
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
ret = blk_read(pfl->blk, 0, pfl->storage, total_len >> 9);
if (ret < 0) {
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
@@ -795,8 +795,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
}
}
if (pfl->bs) {
pfl->ro = bdrv_is_read_only(pfl->bs);
if (pfl->blk) {
pfl->ro = blk_is_read_only(pfl->blk);
} else {
pfl->ro = 0;
}
@@ -898,7 +898,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
}
static Property pflash_cfi01_properties[] = {
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
/* num-blocks is the number of blocks actually visible to the guest,
* ie the total size of the device divided by the sector length.
* If we're emulating flash devices wired in parallel the actual
@@ -962,14 +962,14 @@ type_init(pflash_cfi01_register_types)
pflash_t *pflash_cfi01_register(hwaddr base,
DeviceState *qdev, const char *name,
hwaddr size,
BlockDriverState *bs,
BlockBackend *blk,
uint32_t sector_len, int nb_blocs,
int bank_width, uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3, int be)
{
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
abort();
}
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);

View File

@@ -38,7 +38,7 @@
#include "hw/hw.h"
#include "hw/block/flash.h"
#include "qemu/timer.h"
#include "block/block.h"
#include "sysemu/block-backend.h"
#include "exec/address-spaces.h"
#include "qemu/host-utils.h"
#include "hw/sysbus.h"
@@ -63,7 +63,7 @@ struct pflash_t {
SysBusDevice parent_obj;
/*< public >*/
BlockDriverState *bs;
BlockBackend *blk;
uint32_t sector_len;
uint32_t nb_blocs;
uint32_t chip_len;
@@ -249,13 +249,13 @@ static void pflash_update(pflash_t *pfl, int offset,
int size)
{
int offset_end;
if (pfl->bs) {
if (pfl->blk) {
offset_end = offset + size;
/* round to sectors */
offset = offset >> 9;
offset_end = (offset_end + 511) >> 9;
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
offset_end - offset);
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
offset_end - offset);
}
}
@@ -618,9 +618,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
pfl->chip_len = chip_len;
if (pfl->bs) {
if (pfl->blk) {
/* read the initial flash content */
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
ret = blk_read(pfl->blk, 0, pfl->storage, chip_len >> 9);
if (ret < 0) {
vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
error_setg(errp, "failed to read the initial flash content");
@@ -632,8 +632,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
pfl->rom_mode = 1;
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
if (pfl->bs) {
pfl->ro = bdrv_is_read_only(pfl->bs);
if (pfl->blk) {
pfl->ro = blk_is_read_only(pfl->blk);
} else {
pfl->ro = 0;
}
@@ -722,7 +722,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
}
static Property pflash_cfi02_properties[] = {
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
@@ -763,7 +763,7 @@ type_init(pflash_cfi02_register_types)
pflash_t *pflash_cfi02_register(hwaddr base,
DeviceState *qdev, const char *name,
hwaddr size,
BlockDriverState *bs, uint32_t sector_len,
BlockBackend *blk, uint32_t sector_len,
int nb_blocs, int nb_mappings, int width,
uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3,
@@ -772,7 +772,7 @@ pflash_t *pflash_cfi02_register(hwaddr base,
{
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
abort();
}
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);

View File

@@ -16,6 +16,7 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/block/block.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/virtio/virtio-blk.h"
#include "dataplane/virtio-blk.h"
@@ -64,7 +65,8 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
bool is_read)
{
BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
BlockErrorAction action = blk_get_error_action(req->dev->blk,
is_read, error);
VirtIOBlock *s = req->dev;
if (action == BLOCK_ERROR_ACTION_STOP) {
@@ -72,11 +74,11 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
s->rq = req;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
block_acct_done(bdrv_get_stats(s->bs), &req->acct);
block_acct_done(blk_get_stats(s->blk), &req->acct);
virtio_blk_free_request(req);
}
bdrv_error_action(s->bs, action, is_read, error);
blk_error_action(s->blk, action, is_read, error);
return action != BLOCK_ERROR_ACTION_IGNORE;
}
@@ -94,7 +96,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
}
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
virtio_blk_free_request(req);
}
@@ -109,7 +111,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
}
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
virtio_blk_free_request(req);
}
@@ -155,7 +157,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
*/
scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
if (!blk->blk.scsi) {
if (!blk->conf.scsi) {
status = VIRTIO_BLK_S_UNSUPP;
goto fail;
}
@@ -209,7 +211,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base;
hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len;
status = bdrv_ioctl(blk->bs, SG_IO, &hdr);
status = blk_ioctl(blk->blk, SG_IO, &hdr);
if (status) {
status = VIRTIO_BLK_S_UNSUPP;
goto fail;
@@ -255,7 +257,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
virtio_blk_free_request(req);
}
void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb)
{
int i, ret;
@@ -263,7 +265,7 @@ void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
return;
}
ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
ret = blk_aio_multiwrite(blk, mrb->blkreq, mrb->num_writes);
if (ret != 0) {
for (i = 0; i < mrb->num_writes; i++) {
if (mrb->blkreq[i].error) {
@@ -277,14 +279,14 @@ void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
{
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, 0,
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, 0,
BLOCK_ACCT_FLUSH);
/*
* Make sure all outstanding writes are posted to the backing device.
*/
virtio_submit_multiwrite(req->dev->bs, mrb);
bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
virtio_submit_multiwrite(req->dev->blk, mrb);
blk_aio_flush(req->dev->blk, virtio_blk_flush_complete, req);
}
static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
@@ -296,10 +298,10 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
if (sector & dev->sector_mask) {
return false;
}
if (size % dev->conf->logical_block_size) {
if (size % dev->conf.conf.logical_block_size) {
return false;
}
bdrv_get_geometry(dev->bs, &total_sectors);
blk_get_geometry(dev->blk, &total_sectors);
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
return false;
}
@@ -321,11 +323,11 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
return;
}
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
BLOCK_ACCT_WRITE);
if (mrb->num_writes == 32) {
virtio_submit_multiwrite(req->dev->bs, mrb);
virtio_submit_multiwrite(req->dev->blk, mrb);
}
blkreq = &mrb->blkreq[mrb->num_writes];
@@ -353,11 +355,11 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
return;
}
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
BLOCK_ACCT_READ);
bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
req->qiov.size / BDRV_SECTOR_SIZE,
virtio_blk_rw_complete, req);
blk_aio_readv(req->dev->blk, sector, &req->qiov,
req->qiov.size / BDRV_SECTOR_SIZE,
virtio_blk_rw_complete, req);
}
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
@@ -405,7 +407,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
* NB: per existing s/n string convention the string is
* terminated by '\0' only when shorter than buffer.
*/
const char *serial = s->blk.serial ? s->blk.serial : "";
const char *serial = s->conf.serial ? s->conf.serial : "";
size_t size = MIN(strlen(serial) + 1,
MIN(iov_size(in_iov, in_num),
VIRTIO_BLK_ID_BYTES));
@@ -445,7 +447,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
virtio_blk_handle_request(req, &mrb);
}
virtio_submit_multiwrite(s->bs, &mrb);
virtio_submit_multiwrite(s->blk, &mrb);
/*
* FIXME: Want to check for completions before returning to guest mode,
@@ -473,7 +475,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
req = next;
}
virtio_submit_multiwrite(s->bs, &mrb);
virtio_submit_multiwrite(s->blk, &mrb);
}
static void virtio_blk_dma_restart_cb(void *opaque, int running,
@@ -486,7 +488,7 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
}
if (!s->bh) {
s->bh = aio_bh_new(bdrv_get_aio_context(s->blk.conf.bs),
s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk),
virtio_blk_dma_restart_bh, s);
qemu_bh_schedule(s->bh);
}
@@ -504,8 +506,8 @@ static void virtio_blk_reset(VirtIODevice *vdev)
* This should cancel pending requests, but can't do nicely until there
* are per-device request lists.
*/
bdrv_drain_all();
bdrv_set_enable_write_cache(s->bs, s->original_wce);
blk_drain_all();
blk_set_enable_write_cache(s->blk, s->original_wce);
}
/* coalesce internal state, copy to pci i/o region 0
@@ -513,19 +515,20 @@ static void virtio_blk_reset(VirtIODevice *vdev)
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
{
VirtIOBlock *s = VIRTIO_BLK(vdev);
BlockConf *conf = &s->conf.conf;
struct virtio_blk_config blkcfg;
uint64_t capacity;
int blk_size = s->conf->logical_block_size;
int blk_size = conf->logical_block_size;
bdrv_get_geometry(s->bs, &capacity);
blk_get_geometry(s->blk, &capacity);
memset(&blkcfg, 0, sizeof(blkcfg));
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
virtio_stw_p(vdev, &blkcfg.cylinders, s->conf->cyls);
virtio_stw_p(vdev, &blkcfg.cylinders, conf->cyls);
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
virtio_stw_p(vdev, &blkcfg.min_io_size, s->conf->min_io_size / blk_size);
virtio_stw_p(vdev, &blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
blkcfg.heads = s->conf->heads;
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
virtio_stw_p(vdev, &blkcfg.opt_io_size, conf->opt_io_size / blk_size);
blkcfg.heads = conf->heads;
/*
* We must ensure that the block device capacity is a multiple of
* the logical block size. If that is not the case, let's use
@@ -537,15 +540,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
* divided by 512 - instead it is the amount of blk_size blocks
* per track (cylinder).
*/
if (bdrv_getlength(s->bs) / s->conf->heads / s->conf->secs % blk_size) {
blkcfg.sectors = s->conf->secs & ~s->sector_mask;
if (blk_getlength(s->blk) / conf->heads / conf->secs % blk_size) {
blkcfg.sectors = conf->secs & ~s->sector_mask;
} else {
blkcfg.sectors = s->conf->secs;
blkcfg.sectors = conf->secs;
}
blkcfg.size_max = 0;
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
blkcfg.physical_block_exp = get_physical_block_exp(conf);
blkcfg.alignment_offset = 0;
blkcfg.wce = bdrv_enable_write_cache(s->bs);
blkcfg.wce = blk_enable_write_cache(s->blk);
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}
@@ -556,9 +559,9 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
memcpy(&blkcfg, config, sizeof(blkcfg));
aio_context_acquire(bdrv_get_aio_context(s->bs));
bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
aio_context_release(bdrv_get_aio_context(s->bs));
aio_context_acquire(blk_get_aio_context(s->blk));
blk_set_enable_write_cache(s->blk, blkcfg.wce != 0);
aio_context_release(blk_get_aio_context(s->blk));
}
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
@@ -571,14 +574,15 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
features |= (1 << VIRTIO_BLK_F_SCSI);
if (s->blk.config_wce) {
if (s->conf.config_wce) {
features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
}
if (bdrv_enable_write_cache(s->bs))
if (blk_enable_write_cache(s->blk)) {
features |= (1 << VIRTIO_BLK_F_WCE);
if (bdrv_is_read_only(s->bs))
}
if (blk_is_read_only(s->blk)) {
features |= 1 << VIRTIO_BLK_F_RO;
}
return features;
}
@@ -612,13 +616,13 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
* Guest writes 1 to the WCE configuration field (writeback mode)
* Guest sets DRIVER_OK bit in status field
*
* s->bs would erroneously be placed in writethrough mode.
* s->blk would erroneously be placed in writethrough mode.
*/
if (!(features & (1 << VIRTIO_BLK_F_CONFIG_WCE))) {
aio_context_acquire(bdrv_get_aio_context(s->bs));
bdrv_set_enable_write_cache(s->bs,
!!(features & (1 << VIRTIO_BLK_F_WCE)));
aio_context_release(bdrv_get_aio_context(s->bs));
aio_context_acquire(blk_get_aio_context(s->blk));
blk_set_enable_write_cache(s->blk,
!!(features & (1 << VIRTIO_BLK_F_WCE)));
aio_context_release(blk_get_aio_context(s->blk));
}
}
@@ -707,8 +711,8 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data)
if (s->dataplane) {
return;
}
bdrv_drain_all(); /* complete in-flight non-dataplane requests */
virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->blk,
blk_drain_all(); /* complete in-flight non-dataplane requests */
virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->conf,
&s->dataplane, &err);
if (err != NULL) {
error_report("%s", error_get_pretty(err));
@@ -721,22 +725,22 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOBlock *s = VIRTIO_BLK(dev);
VirtIOBlkConf *blk = &(s->blk);
VirtIOBlkConf *conf = &s->conf;
Error *err = NULL;
static int virtio_blk_id;
if (!blk->conf.bs) {
if (!conf->conf.blk) {
error_setg(errp, "drive property not set");
return;
}
if (!bdrv_is_inserted(blk->conf.bs)) {
if (!blk_is_inserted(conf->conf.blk)) {
error_setg(errp, "Device needs media, but drive is empty");
return;
}
blkconf_serial(&blk->conf, &blk->serial);
s->original_wce = bdrv_enable_write_cache(blk->conf.bs);
blkconf_geometry(&blk->conf, NULL, 65535, 255, 255, &err);
blkconf_serial(&conf->conf, &conf->serial);
s->original_wce = blk_enable_write_cache(conf->conf.blk);
blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -745,14 +749,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
s->bs = blk->conf.bs;
s->conf = &blk->conf;
s->blk = conf->conf.blk;
s->rq = NULL;
s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
s->complete_request = virtio_blk_complete_request;
virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
if (err != NULL) {
error_propagate(errp, err);
virtio_cleanup(vdev);
@@ -764,10 +767,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
virtio_blk_save, virtio_blk_load, s);
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
bdrv_set_guest_block_size(s->bs, s->conf->logical_block_size);
blk_set_dev_ops(s->blk, &virtio_block_ops, s);
blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size);
bdrv_iostatus_enable(s->bs);
blk_iostatus_enable(s->blk);
}
static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
@@ -780,7 +783,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
s->dataplane = NULL;
qemu_del_vm_change_state_handler(s->change);
unregister_savevm(dev, "virtio-blk", s);
blockdev_mark_auto_del(s->bs);
blockdev_mark_auto_del(s->blk);
virtio_cleanup(vdev);
}
@@ -789,23 +792,23 @@ static void virtio_blk_instance_init(Object *obj)
VirtIOBlock *s = VIRTIO_BLK(obj);
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
(Object **)&s->blk.iothread,
(Object **)&s->conf.iothread,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
device_add_bootindex_property(obj, &s->blk.conf.bootindex,
device_add_bootindex_property(obj, &s->conf.conf.bootindex,
"bootindex", "/disk@0,0",
DEVICE(obj), NULL);
}
static Property virtio_blk_properties[] = {
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, blk.conf),
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, blk.conf),
DEFINE_PROP_STRING("serial", VirtIOBlock, blk.serial),
DEFINE_PROP_BIT("config-wce", VirtIOBlock, blk.config_wce, 0, true),
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
#ifdef __linux__
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, true),
#endif
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, conf.data_plane, 0, false),
DEFINE_PROP_END_OF_LIST(),
};

View File

@@ -39,6 +39,7 @@
#include "hw/xen/xen_backend.h"
#include "xen_blkif.h"
#include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
/* ------------------------------------------------------------- */
@@ -122,7 +123,7 @@ struct XenBlkDev {
/* qemu block driver */
DriveInfo *dinfo;
BlockDriverState *bs;
BlockBackend *blk;
QEMUBH *bh;
};
@@ -479,7 +480,7 @@ static void qemu_aio_complete(void *opaque, int ret)
if (ioreq->postsync) {
ioreq->postsync = 0;
ioreq->aio_inflight++;
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
return;
}
@@ -493,7 +494,7 @@ static void qemu_aio_complete(void *opaque, int ret)
break;
}
case BLKIF_OP_READ:
block_acct_done(bdrv_get_stats(ioreq->blkdev->bs), &ioreq->acct);
block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
break;
case BLKIF_OP_DISCARD:
default:
@@ -512,18 +513,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
ioreq->aio_inflight++;
if (ioreq->presync) {
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
return 0;
}
switch (ioreq->req.operation) {
case BLKIF_OP_READ:
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
ioreq->v.size, BLOCK_ACCT_READ);
ioreq->aio_inflight++;
bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq);
blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq);
break;
case BLKIF_OP_WRITE:
case BLKIF_OP_FLUSH_DISKCACHE:
@@ -531,18 +532,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
break;
}
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
ioreq->v.size, BLOCK_ACCT_WRITE);
ioreq->aio_inflight++;
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq);
blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE,
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
qemu_aio_complete, ioreq);
break;
case BLKIF_OP_DISCARD:
{
struct blkif_request_discard *discard_req = (void *)&ioreq->req;
ioreq->aio_inflight++;
bdrv_aio_discard(blkdev->bs,
blk_aio_discard(blkdev->blk,
discard_req->sector_number, discard_req->nr_sectors,
qemu_aio_complete, ioreq);
break;
@@ -854,44 +855,49 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->dinfo = drive_get(IF_XEN, 0, index);
if (!blkdev->dinfo) {
Error *local_err = NULL;
BlockBackend *blk;
BlockDriver *drv;
BlockDriverState *bs;
/* setup via xenbus -> create new block driver instance */
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
blkdev->bs = bdrv_new(blkdev->dev, NULL);
if (!blkdev->bs) {
blk = blk_new_with_bs(blkdev->dev, NULL);
if (!blk) {
return -1;
}
blkdev->blk = blk;
bs = blk_bs(blk);
drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly);
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
if (bdrv_open(&bs, blkdev->filename, NULL, NULL, qflags,
drv, &local_err) != 0) {
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
error_get_pretty(local_err));
error_free(local_err);
bdrv_unref(blkdev->bs);
blkdev->bs = NULL;
blk_unref(blk);
blkdev->blk = NULL;
return -1;
}
assert(bs == blk_bs(blk));
} else {
/* setup via qemu cmdline -> already setup for us */
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
blkdev->bs = blkdev->dinfo->bdrv;
if (bdrv_is_read_only(blkdev->bs) && !readonly) {
blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo);
if (blk_is_read_only(blkdev->blk) && !readonly) {
xen_be_printf(&blkdev->xendev, 0, "Unexpected read-only drive");
blkdev->bs = NULL;
blkdev->blk = NULL;
return -1;
}
/* blkdev->bs is not create by us, we get a reference
* so we can bdrv_unref() unconditionally */
bdrv_ref(blkdev->bs);
/* blkdev->blk is not create by us, we get a reference
* so we can blk_unref() unconditionally */
blk_ref(blkdev->blk);
}
bdrv_attach_dev_nofail(blkdev->bs, blkdev);
blkdev->file_size = bdrv_getlength(blkdev->bs);
blk_attach_dev_nofail(blkdev->blk, blkdev);
blkdev->file_size = blk_getlength(blkdev->blk);
if (blkdev->file_size < 0) {
xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
xen_be_printf(&blkdev->xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
(int)blkdev->file_size, strerror(-blkdev->file_size),
bdrv_get_format_name(blkdev->bs) ?: "-");
bdrv_get_format_name(blk_bs(blkdev->blk)) ?: "-");
blkdev->file_size = 0;
}
@@ -982,10 +988,10 @@ static void blk_disconnect(struct XenDevice *xendev)
{
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
if (blkdev->bs) {
bdrv_detach_dev(blkdev->bs, blkdev);
bdrv_unref(blkdev->bs);
blkdev->bs = NULL;
if (blkdev->blk) {
blk_detach_dev(blkdev->blk, blkdev);
blk_unref(blkdev->blk);
blkdev->blk = NULL;
}
xen_be_unbind_evtchn(&blkdev->xendev);
@@ -1001,7 +1007,7 @@ static int blk_free(struct XenDevice *xendev)
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
struct ioreq *ioreq;
if (blkdev->bs || blkdev->sring) {
if (blkdev->blk || blkdev->sring) {
blk_disconnect(xendev);
}

Some files were not shown because too many files have changed in this diff Show More