Compare commits

..

36 Commits

Author SHA1 Message Date
Anthony Liguori
8be3691a9a Update Changelog and VERSION for 0.11.0-rc1 release
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 16:35:28 -05:00
Anthony Liguori
355b84933d Move CLOCKLIBS and PTHREADLIBS out of CONFIG_LINUX_USER_ONLY
Otherwise, -lrt doesn't get added to the softmmu build.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 16:35:28 -05:00
Mark McLoughlin
ad6ee8fe97 Add a pc-0.11 machine type and make the pc type an alias
The pc-0.11 type allows users of qemu-0.11 to use a machine type which
they know will remain compatible when the upgrade to qemu-0.12.

Management tools may choose to canonicalize the 'pc' machine type to
'pc-0.11' so that if the 'pc' alias changes target in future versions
of qemu, the machine type used will remain compatible.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
9fc1babd95 Add machine type aliases
Add an 'alias' field to QEMUMachine and display it in the output of
'qemu -M ?' with an '(aliased to foo)' suffix.

Aliases can change targets in newer versions of qemu, so management tools
may choose canonicalize machine types to ensure that if a user chooses an
alias, that the actual machine type used will remain compatible in
future.

This is intended to mimic a symlink to a machine description file.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
413fb2412d Add support for fd=name to tap and socket networking
This allows a program to initialize a host networking device using a
file descriptor passed over a unix monitor socket.

The program must first pass the file descriptor using SCM_RIGHTS
ancillary data with the getfd monitor command. It then may do
"host_net_add tap fd=name" to use the named file descriptor.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
9bab7711ca Add monitor_get_fd() command for fetching named fds
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
dedd9ecaf9 Add getfd and closefd monitor commands
Add monitor commands to support passing file descriptors via
SCM_RIGHTS.

getfd assigns the passed file descriptor a name for use with other
monitor commands.

closefd allows passed file descriptors to be closed. If a monitor
command actually uses a named file descriptor, closefd will not be
required.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
f8f8e7e6dd Add SCM_RIGHTS support to unix socket character devices
If a file descriptor is passed via a message with SCM_RIGHTS ancillary
data on a unix socket, store the file descriptor for use in the
chr_read() handler. Close the file descriptor if it was not used.

The qemu_chr_get_msgfd() API provides access to the passed descriptor.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Mark McLoughlin
58cc6b7a5a Make tcp_chr_read() use recvmsg()
Split out tcp_chr_recv() out of tcp_chr_read() and implement it on
non-win32 using recvmsg(). This is needed for a subsequent patch
which implements SCM_RIGHTS support.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:47:09 -05:00
Filip Navara
583b6d0c04 tap-win32: Use correct headers.
Replace the usage of DDK headers with the SDK counterpart "winioctl.h".

Signed-off-by: Filip Navara <filip.navara@gmail.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:38:12 -05:00
Glauber Costa
1d600827f6 fix broken migration
While fixing migration with -S, commit
89befdd1a6 broke the rest of us. Poor
glommer, with a poor family, spare him his life from this monstruosity.

Since the unconditional vm_start, not autostart was the villain, I'm putting
back autostart. Let me know if you prefer other solutions, it doesn't really matter,
doesn't really matter to me.

Any way the wind blows...

Signed-off-by: Glauber Costa <glommer@redhat.com>
CC: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:38:12 -05:00
Ed Swierk
f833ef2133 slirp: Use monotonic clock if available (v2)
Calling gettimeofday() to compute a time interval can cause problems if
the system clock jumps forwards or backwards; replace updtime() with
qemu_get_clock(rt_clock), which calls clock_gettime(CLOCK_MONOTONIC) if
it is available.

Also remove some useless macros.

Signed-off-by: Ed Swierk <eswierk@aristanetworks.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:38:07 -05:00
Michael S. Tsirkin
8568d307a7 qemu: msix nit: clear msix_entries_nr on error
I don't think it's critical to do this, but it's
best to keep uninit and error recovery consistent.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:38:07 -05:00
Beth Kon
b87d79698d HPET fixes for reg writes
This patch addresses the problems found by Andriy Gapon:

- The code was incorrectly overwriting the high order 32
  bits of the timer and hpet config registers. This didn't show up
  in testing because linux and windows use hpet in legacy mode,
  where the high order 32 bits (advertising available interrupts)
  of the timer config register are ignored, and the high order 32
  bits of the hpet config register are reserved and unused.

- The mask for level-triggered interrupts was off by a bit. (hpet
  doesn't currently support level-triggered interrupts).

In addition, I removed some unused #defines, and corrected the ioapic
interrupt values advertised. I'd set this up early in hpet development
and never went back to correct it, and no bugs resulted since linux and
windows use hpet in legacy mode where available interrupts are ignored.

Signed-off-by: Beth Kon <eak@us.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-29 11:38:06 -05:00
Jan Kiszka
b0dc78730e slirp: Fix guestfwd for incoming data
Unless a virtual server address was explicitly defined (which is
impossible with the legacy -net channel format), guestfwd did not
properly forwarded host->guest packets. This patch fixes it.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:02 -05:00
Sebastian Herbszt
cc234b83c6 qemu-thread: use pthread_equal
Fixes

qemu-thread.c: In function `qemu_thread_equal':
qemu-thread.c:161: error: invalid operands to binary ==

Use of pthread_equal suggested by Filip Navara.

Signed-off-by: Sebastian Herbszt <herbszt@gmx.de>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:02 -05:00
Christoph Egger
96046435ba signrom.sh: portability fix
Attached patch makes signrom.sh working on NetBSD.
The output of the 'od' command leads to a syntax error
which breaks the build.

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:02 -05:00
Akkarit Sangpetch
ca95814efb qmu-img: fix qemu-img convert to generate a valid image when the source referenced a backing file
Make 'qemu-img convert' copies unallocated parts of the source image
when -B option was not specified.

Signed-off-by: Akkarit Sangpetch <asangpet@andrew.cmu.edu>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:01 -05:00
Kevin Wolf
e88802852d vmdk: Fix backing file handling
Instead of storing the backing file in its own BlockDriverState, VMDK uses the
BlockDriverState of the raw image file it opened. This is wrong and breaks
functions that access the backing file or protocols. This fix replaces all
occurrences of s->hd->backing_* with bs->backing_*.

This fixes qemu-iotests failure in 020 (Commit changes to backing file).

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:01 -05:00
Nolan
a57ac1d342 Add save/restore support to the LSI logic SCSI device model.
This patch requires "Handle BH's queued by AIO completions in
qemu_aio_flush()" to work reliably.  The combination of those two
patches survived 300+ migrations with heavy IO load running in the
guest.

Signed-off-by: Nolan Leake <nolan <at> sigbus.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:01 -05:00
Nolan
3f5cb28d9e Handle BH's queued by AIO completions in qemu_aio_flush()
Without this, the call to qemu_aio_flush during migration doesn't
actually flush all in-flight SCSI IOs.

Signed-off-by: Nolan Leake <nolan <at> sigbus.net>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:41:01 -05:00
Blue Swirl
dd500a9241 Fix most warnings (errors with -Werror) when debugging is enabled
I used the following command to enable debugging:
perl -p -i -e 's/^\/\/#define DEBUG/#define DEBUG/g' * */* */*/*

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:41:01 -05:00
Blue Swirl
b2b2d9dd2d Fix build with DEBUG_PCI in pci_host.h enabled
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:41:01 -05:00
Christoph Egger
b19bb78c2f isxdigit -> qemu_isxdigit
Hi!

Attached patch uses qemu_isxdigit() instead of isxdigit().
Fixes build warning on NetBSD.

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>

--
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Karl-Hammerschmidt-Str. 34, 85609 Dornach b. Muenchen
Geschaeftsfuehrer: Thomas M. McCoy, Giuliano Meroni
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
2009-07-22 15:40:55 -05:00
Christoph Egger
c3862e8d08 fix build warnings
Hi!

Attached patch fixes build warnings due to use of different pointer
signedness.

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>

--
---to satisfy European Law for business letters:
Advanced Micro Devices GmbH
Karl-Hammerschmidt-Str. 34, 85609 Dornach b. Muenchen
Geschaeftsfuehrer: Thomas M. McCoy, Giuliano Meroni
Sitz: Dornach, Gemeinde Aschheim, Landkreis Muenchen
Registergericht Muenchen, HRB Nr. 43632
2009-07-22 15:40:55 -05:00
Blue Swirl
0d0e17cf25 Suppress a Sparse warning
Move the export to a file used by both qdev.c and sysbus.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:55 -05:00
Blue Swirl
344a1d16f2 Sparc32: use hex for version numbers
0x10000000 looks better than 268435456.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:54 -05:00
Blue Swirl
462eb7f81e Sparc32: fix escc devices broken by ee6847d19b
The logic of Zilog makes channel B the first device and channel A the
second one.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:54 -05:00
Blue Swirl
8149632ad0 Sparc32: fix fdc io_base
On some Sparc32 machines, fdc is located above 4G limit, so uint32_t is not
appropriate type for io_base.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:54 -05:00
Blue Swirl
0412e2bab1 Fix sparc-softmmu breakage by ee6847d19b
Move the qdev_init(dev); call after the setting of d->size.
Thanks to Filip Navara.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:54 -05:00
Blue Swirl
e93d914384 Fix OpenBSD build
The header sys-queue.h must be #included early, otherwise at some point OS
queue macros will be used. On OpenBSD, those don't define TAILQ_FOREACH_SAFE.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
2009-07-22 15:40:54 -05:00
Paul Brook
22528739c9 ARM host fixes
Minor TCG cleanups and warning fixes for ARM hosts.

Signed-off-by: Paul Brook <paul@codesourcery.com>
2009-07-22 15:40:54 -05:00
Anthony Liguori
8fe7911401 Only allow -cpu host when KVM is enabled
-cpu host is not at all useful when using tcg.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:40:54 -05:00
Anthony Liguori
1eebab9835 Initialize cpuid variables
This causes a build break when !KVM.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-07-22 15:40:53 -05:00
malc
6f40c941bd Ignore -Waddress for alsaaudio.c
/usr/include/alsa/pcm.h contains:

#define snd_pcm_sw_params_alloca(ptr) do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(snd_pcm_sw_params_sizeof()); memset(*ptr, 0, snd_pcm_sw_params_sizeof()); } while (0)

The assert generates: "error: the address of 'sw_params' will always
evaluate as 'true'" which combined with -Werror prevents alsaaudio.o
from being built with certain versions of GCC.
2009-07-22 15:40:52 -05:00
Aurelien Jarno
3b72617c9a tcg: Fix tcg_gen_rotr_i64
Reported-by: Laurent Desnogues <laurent.desnogues@gmail.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2009-07-18 11:47:51 +02:00
783 changed files with 33167 additions and 64462 deletions

6
.gitignore vendored
View File

@@ -1,7 +1,4 @@
config-devices.*
config-all-devices.*
config-host.*
config-target.*
i386
*-softmmu
*-darwin-user
@@ -9,7 +6,6 @@ i386
*-bsd-user
libhw32
libhw64
libuser
qemu-doc.html
qemu-tech.html
qemu-doc.info
@@ -46,6 +42,4 @@ qemu-monitor.texi
patches
pc-bios/bios-pq/status
pc-bios/vgabios-pq/status
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
.stgit-*

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "roms/vgabios"]
path = roms/vgabios
url = ../vgabios.git
[submodule "roms/seabios"]
path = roms/seabios
url = ../seabios.git

153
Changelog
View File

@@ -1,76 +1,91 @@
version 0.12.1:
- loader: fix rom loading at address 0 (fixes target-arm) (Aurelien Jarno)
- loader: fix rom_copy (fixes multiboot) (Kevin Wolf)
version 0.11.0-rc1
- add machine aliasing support (Mark McLoughlin)
- add getfd/closefd monitor commands (Mark McLoughlin)
- use correct headers for tap-win32 (Filip Navara)
- fix live migration (Glauber Costa)
- slirp: use monotonic clock if available (Ed Swierk)
- clear msix_entries_nr on error (Michael Tsirkin)
- HPET: fix reg writes (Beth Kon)
- slirp: fix guestfwd for incoming data (Jan Kiszka)
- fix build of qemu-thread.c on win32 (Sebastian Herbszt)
- improve signrom.sh portability (Christoph Egger)
- fix qemu-img convert to copy unallocated parts of the image
(Akkarit Sangpetch)
- vmdk: fix backing file handling (Kevin Wolf)
- scsi: add save/restore support (Nolan Leake)
- fix live migration for SCSI (Nolan Leake)
- various sparc build fixes (Blue Swirl)
- fix OpenBSD build (Blue Swirl)
- only allow -cpu host when using KVM (Anthony Liguori)
- fix build breakage when !KVM (Anthony Liguori)
version 0.12.0:
version 0.10.6:
- e1000: ignore reset command (Kevin Wolf)
- fix VNC memory allocation (Stefan Weil)
- fix raw_pread_aligned return value (Christoph Hellwig)
- allow monitor interaction when using -incoming exec: (Chris Lalancette)
- fix -net socket,listen (Jan Kiszka)
- live migration: don't send gratuitous packets all at once (Gleb Natapov)
- serial: fix lost characters after sysrq (Jason Wessel)
- Fix prototype of zfree (Stefan Weil)
- Handle EINTR with exec: migration (Uri Lublin)
- Delete io-handler before closing fd after migration (Uri Lublin)
- Fix qemu_aio_flush (Andrea Arcangeli)
- lsi53c895a: Implement additional registers (Sebastian Herbszt)
- virtio-blk: fix warning (Gerd Hoffman)
- i386: fix cpu reset (Nitin Kamble)
- kvm: fix irq injection into full queue (Jan Kiszka)
- Prevent CD-ROM eject while device is locked (Mark McLoughlin)
- Fix screen dump with blank screen (Eduardo Habkost)
- Fix memory leak with cpu_unregister_map_client (Isaku Yamahata)
- Fix memory leak in SDL (Jan Kiszka)
- Fix build on OS X 10.4 (John Arbuckle)
- Fix leak of vlan clients after hot remove (Mark McLoughlin)
- Fix migration after hot remove with eepro100 (Mark McLoughlin)
- Don't start a VM after failed migration if stopped (Anthony Liguori)
- Fix live migration under heavy IO load (Glauber Costa)
- Honor -S on incoming migration (Paolo Bonzini)
- Reset HPET config register on reset (Beth Kon)
- Reset PS2 keyboard/mouse on reset (Dinesh Subraveti)
- Update to SeaBIOS 0.5.0
- e1000: fix device link status in Linux (Anthony Liguori)
- monitor: fix QMP for balloon command (Luiz Capitulino)
- QMP: Return an empty dict by default (Luiz Capitulino)
- QMP: Only handle converted commands (Luiz Capitulino)
- pci: support PCI based option rom loading (Gerd Hoffman/Anthony Liguori)
- Fix backcompat for hotplug of SCSI controllers (Daniel P. Berrange)
- fdc: fix migration from 0.11 (Juan Quintela)
- vmware-vga: fix segv on cursor resize. (Dave Airlie)
- vmware-vga: various fixes (Dave Airlie/Anthony Liguori)
- qdev: improve property error reporting. (Gerd Hoffmann)
- fix vga names in default_list (Gerd Hoffmann)
- usb-host: check mon before using it. (Gerd Hoffmann)
- usb-net: use qdev for -usbdevice (Gerd Hoffmann)
- monitor: Catch printing to non-existent monitor (Luiz Capitulino)
- Avoid permanently disabled QEMU monitor when UNIX migration fails (Daniel P. Berrange)
- Fix loading of ELF multiboot kernels (Kevin Wolf)
- qemu-io: Fix memory leak (Kevin Wolf)
- Fix thinko in linuxboot.S (Paolo Bonzini)
- target-i386: Fix evaluation of DR7 register (Jan Kiszka)
- vnc: hextile: do not generate ForegroundSpecified and SubrectsColoured tiles (Anthony Liguori)
- S390: Bail out without KVM (Alexander Graf)
- S390: Don't tell guest we're updating config space (Alexander Graf)
- target-s390: Fail on unknown instructions (Alexander Graf)
- osdep: Fix runtime failure on older Linux kernels (Andre Przywara)
- Fix a make -j race (Juergen Lock)
- target-alpha: Fix generic ctz64. (Richard Henderson)
- s390: Fix buggy assignment (Stefan Weil)
- target-mips: fix user-mode emulation startup (Nathan Froyd)
- target-i386: Update CPUID feature set for TCG (Andre Przywara)
- s390: fix build on 32 bit host (Michael S. Tsirkin)
version 0.10.5:
- kvm: trim unsupported cpu features from cpuid (Avi Kivity)
- kvm: provide a better error message for -smp > 1 (Mark McLoughlin)
- Remove initrd printfs (Richard Jones)
- Initial variables found by valgrind (Jean-Christophe Dubois)
- Fix -initrd with > 4GB guests (Glauber Costa)
- Fix busy loop on live migration for certain platforms (Uri Lublin)
- Remove GCC 3.x requirements from docs (Hollis Blanchard)
- ETRAX: fixes for kernel command line, ethernet address, bmi (Edgar Iglesias)
- CRIS: Fix bmi (Edgar Iglesias)
- Fix bounce buffer errors (Avi Kivity)
- Fix regression in -kernel (Anthony Liguori)
version 0.12.0-rc2:
version 0.10.4:
- Improve block range checks to remove integer overflow (Kevin Wolf)
- e1000: do not re-init PCI config space 0 (Amit Shah)
- fix AIO deletion race (Alex Graf)
- reset option roms on reboot (Glauber Costa)
- fix qcow2 corruption in cluster freeing (Gleb Natapov)
- Enable power button event generation (Gleb Natapov)
- v2: properly save kvm system time msr registers (Glauber Costa)
- convert more monitor commands to qmp (Luiz Capitulino)
- vnc: fix capslock tracking logic. (Gerd Hoffmann)
- QemuOpts: allow larger option values. (Gerd Hoffmann)
- scsi: fix drive hotplug. (Gerd Hoffmann)
- pci: don't hw_error() when no slot is available. (Gerd Hoffmann)
- pci: don't abort() when trying to hotplug with acpi off. (Gerd Hoffmann)
- allow default devices to be implemented in config file (Gerd Hoffman)
- vc: colorize chardev title line with blue background. (Gerd Hoffmann)
- chardev: make chardevs specified in config file work. (Gerd Hoffmann)
- qdev: also match bus name for global properties (Gerd Hoffmann)
- qdev: add command line option to set global defaults for properties. (Gerd Hoffmann)
- kvm: x86: Save/restore exception_index (Jan Kiszka)
- qdev: Replace device names containing whitespace (Markus Armbruster)
- fix rtc-td-hack on host without high-res timers (Gleb Natapov)
- virtio: verify features on load (Michael S. Tsirkin)
- vmware_vga: add rom file so that it boots. (Dave Airlie)
- Do not abort on qemu_malloc(0) in production builds (Anthony Liguori)
- Fix ARM userspace strex implementation. (Paul Brook)
- qemu: delete rule target on error (Michael S. Tsirkin)
- QMP: add human-readable description to error response (Markus Armbruster)
- convert more monitor commands to QError (Markus Armbruster)
- monitor: Fix double-prompt after "change vnc passwd BLA" (Markus Armbruster)
- monitor: do_cont(): Don't ask for passwords (Luiz Capitulino)
- monitor: Introduce 'block_passwd' command (Luiz Capitulino)
- pci: interrupt disable bit support (Michael S. Tsirkin)
- pci: interrupt status bit implementation (Michael S. Tsirkin)
- pci: prepare irq code for interrupt state (Michael S. Tsirkin)
- msix: function mask support (Michael S. Tsirkin)
- msix: macro rename for function mask support (Michael S. Tsirkin)
- cpuid: Fix multicore setup on Intel (Andre Przywara)
- kvm: x86: Fix initial kvm_has_msr_star (Jan Kiszka)
- Update OpenBIOS images to r640 (Aurelien Jarno)
version 0.10.3:
- fix AIO cancellations (Avi Kivity)
- fix live migration error path on incoming
- avoid SEGV on pci hotplug failure (Chris Wright)
- fix serial option in -drive
- support DDIM for option roms (Glauber Costa)
- avoid fork/exec on pre-2.6.27 kernels with KVM (Jan Kiszka)
- block-vpc: don't silently create smaller images than requested (Kevin Wolf)
- Fix non-ACPI timer interrupt routing (Beth Kon)
- hpet: fix emulation of HPET_TN_SETVAL (Jan Kiszka)
- kvm: fix cpuid initialization (Jan Kiszka)
- qcow2: fix corruption on little endian hosts (Kevin Wolf)
- avoid leaing memory on hot unplug (Mark McLoughlin)
- fix savevm/migration after hot unplug (Mark McLoughlin)
- Fix keyboard mapping on newer Xords with non-default keymaps (balrog)
- Make PCI config status register read-only (Anthony Liguori)
- Fix crash on resolution change -> screen dump -> vga redraw (Avi Kivity)
version 0.10.2:

View File

@@ -20,7 +20,6 @@ SH4 ?
CRIS Edgar E. Iglesias
Alpha ?
MicroBlaze Edgar E. Iglesias
S390 ?
Machines (sorted by CPU):
-------------------------
@@ -64,8 +63,6 @@ CRIS
Alpha
MicroBlaze
petalogix_s3adsp1800.c Edgar E. Iglesias
S390
s390-*.c Alexander Graf
Generic Subsystems:
-------------------
@@ -73,6 +70,7 @@ Generic Subsystems:
Dynamic translator Fabrice Bellard
Main loop Fabrice Bellard (new maintainer needed)
TCG Fabrice Bellard
kqemu interface Fabrice Bellard
IDE device ?
SCSI device Paul Brook
PCI layer ?

261
Makefile
View File

@@ -1,123 +1,88 @@
# Makefile for QEMU.
# This needs to be defined before rules.mak
GENERATED_HEADERS = config-host.h
ifneq ($(wildcard config-host.mak),)
# Put the all: rule here so that config-host.mak can contain dependencies.
all: build-all
include config-host.mak
include $(SRC_PATH)/rules.mak
config-host.mak: configure
@echo $@ is out-of-date, running configure
@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
else
config-host.mak:
@echo "Please call configure before running make!"
@exit 1
endif
# Don't try to regenerate Makefile or configure
# We don't generate any of them
Makefile: ;
configure: ;
.PHONY: all clean cscope distclean dvi html info install install-doc \
recurse-all speed tar tarbin test build-all
recurse-all speed tar tarbin test
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
LIBS+=-lz $(LIBS_TOOLS)
CPPFLAGS += -I. -I$(SRC_PATH) -MMD -MP -MT $@
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CPPFLAGS += -U_FORTIFY_SOURCE
LIBS=
ifdef CONFIG_STATIC
LDFLAGS += -static
endif
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8
else
DOCS=
endif
LIBS+=$(PTHREADLIBS)
LIBS+=$(CLOCKLIBS)
ifdef CONFIG_SOLARIS
LIBS+=-lsocket -lnsl -lresolv
endif
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
build-all: $(TOOLS) $(DOCS) roms recurse-all
config-host.mak: configure
ifneq ($(wildcard config-host.mak),)
@echo $@ is out-of-date, running configure
@sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
endif
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory)
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
$(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@")
%/config-devices.mak: default-configs/%.mak
$(call quiet-command,cat $< > $@.tmp, " GEN $@")
@if test -f $@ ; then \
echo "WARNING: $@ out of date." ;\
echo "Run \"make defconfig\" to regenerate." ; \
rm $@.tmp ; \
else \
mv $@.tmp $@ ; \
fi
defconfig:
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
-include config-all-devices.mak
build-all: $(DOCS) $(TOOLS) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
subdir-%: $(GENERATED_HEADERS)
subdir-%:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
$(filter %-softmmu,$(SUBDIR_RULES)): libqemu_common.a
$(filter %-user,$(SUBDIR_RULES)): libqemu_user.a
$(filter %-user,$(SUBDIR_RULES)): libuser.a
libuser.a: $(GENERATED_HEADERS)
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C libuser V="$(V)" TARGET_DIR="libuser/" all,)
ROMSUBDIR_RULES=$(patsubst %,romsubdir-%, $(ROMS))
romsubdir-%:
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C pc-bios/$* V="$(V)" TARGET_DIR="$*/",)
ALL_SUBDIRS=$(TARGET_DIRS) $(patsubst %,pc-bios/%, $(ROMS))
recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES)
#######################################################################
# QObject
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
qobject-obj-y += qerror.o
recurse-all: $(SUBDIR_RULES)
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
block-obj-y += nbd.o block.o aio.o aes.o osdep.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-y += nbd.o block.o aio.o aes.o
block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += cow.o qcow.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o
block-nested-y += parallels.o nbd.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
block-nested-$(CONFIG_POSIX) += raw-posix.o
ifdef CONFIG_WIN32
block-nested-y += raw-win32.o
else
ifdef CONFIG_AIO
block-obj-y += posix-aio-compat.o
endif
block-nested-y += raw-posix.o
endif
block-nested-$(CONFIG_CURL) += curl.o
block-obj-y += $(addprefix block/, $(block-nested-y))
net-obj-y = net.o
net-nested-y = queue.o checksum.o util.o
net-nested-y += socket.o
net-nested-y += dump.o
net-nested-$(CONFIG_POSIX) += tap.o
net-nested-$(CONFIG_LINUX) += tap-linux.o
net-nested-$(CONFIG_WIN32) += tap-win32.o
net-nested-$(CONFIG_BSD) += tap-bsd.o
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
net-nested-$(CONFIG_AIX) += tap-aix.o
net-nested-$(CONFIG_SLIRP) += slirp.o
net-nested-$(CONFIG_VDE) += vde.o
net-obj-y += $(addprefix net/, $(net-nested-y))
######################################################################
# libqemu_common.a: Target independent part of system emulation. The
# long term path is to suppress *all* target specific code in case of
@@ -125,46 +90,53 @@ net-obj-y += $(addprefix net/, $(net-nested-y))
# CPUs and machines.
obj-y = $(block-obj-y)
obj-y += $(net-obj-y)
obj-y += $(qobject-obj-y)
obj-y += readline.o console.o
obj-y += tcg-runtime.o host-utils.o
obj-y += irq.o ioport.o
obj-$(CONFIG_PTIMER) += ptimer.o
obj-$(CONFIG_MAX7310) += max7310.o
obj-$(CONFIG_WM8750) += wm8750.o
obj-$(CONFIG_TWL92230) += twl92230.o
obj-$(CONFIG_TSC2005) += tsc2005.o
obj-$(CONFIG_LM832X) += lm832x.o
obj-$(CONFIG_TMP105) += tmp105.o
obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
obj-$(CONFIG_SSD0303) += ssd0303.o
obj-$(CONFIG_SSD0323) += ssd0323.o
obj-$(CONFIG_ADS7846) += ads7846.o
obj-$(CONFIG_MAX111X) += max111x.o
obj-$(CONFIG_DS1338) += ds1338.o
obj-y += i2c.o smbus.o smbus_eeprom.o
obj-y += eeprom93xx.o
obj-y += irq.o ptimer.o
obj-y += i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
obj-y += ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
obj-y += tmp105.o lm832x.o eeprom93xx.o tsc2005.o
obj-y += scsi-disk.o cdrom.o
obj-y += scsi-generic.o scsi-bus.o
obj-y += scsi-generic.o
obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
obj-y += usb-serial.o usb-net.o usb-bus.o
obj-$(CONFIG_SSI) += ssi.o
obj-$(CONFIG_SSI_SD) += ssi-sd.o
obj-$(CONFIG_SD) += sd.o
obj-y += usb-serial.o usb-net.o
obj-y += sd.o ssi-sd.o
obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
obj-y += bt-hci-csr.o
obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
obj-y += qemu-char.o aio.o savevm.o
obj-y += buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
obj-y += qemu-char.o aio.o net-checksum.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o
obj-y += qemu-config.o block-migration.o
obj-y += qdev.o qdev-properties.o ssi.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
ifdef CONFIG_BRLAPI
LIBS+=-lbrlapi
endif
ifdef CONFIG_WIN32
obj-y += tap-win32.o
else
obj-y += migration-exec.o
endif
ifdef CONFIG_COREAUDIO
AUDIO_PT = y
endif
ifdef CONFIG_FMOD
audio/audio.o audio/fmodaudio.o: CPPFLAGS := -I$(CONFIG_FMOD_INC) $(CPPFLAGS)
endif
ifdef CONFIG_ESD
AUDIO_PT = y
AUDIO_PT_INT = y
endif
ifdef CONFIG_PA
AUDIO_PT = y
AUDIO_PT_INT = y
endif
ifdef AUDIO_PT
LDFLAGS += -pthread
endif
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
@@ -175,9 +147,7 @@ audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o
audio-obj-$(CONFIG_FMOD) += fmodaudio.o
audio-obj-$(CONFIG_ESD) += esdaudio.o
audio-obj-$(CONFIG_PA) += paaudio.o
audio-obj-$(CONFIG_WINWAVE) += winwaveaudio.o
audio-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o
audio-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o
audio-obj-$(AUDIO_PT_INT) += audio_pt_int.o
audio-obj-y += wavcapture.o
obj-y += $(addprefix audio/, $(audio-obj-y))
@@ -190,16 +160,22 @@ obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
obj-$(CONFIG_COCOA) += cocoa.o
obj-$(CONFIG_IOTHREAD) += qemu-thread.o
ifdef CONFIG_SLIRP
CPPFLAGS+=-I$(SRC_PATH)/slirp
endif
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
LIBS+=$(VDE_LIBS)
# xen backend driver support
obj-$(CONFIG_XEN) += xen_backend.o xen_devconfig.o
obj-$(CONFIG_XEN) += xen_console.o xenfb.o xen_disk.o xen_nic.o
QEMU_CFLAGS+=$(CURL_CFLAGS)
LIBS+=$(CURL_LIBS)
cocoa.o: cocoa.m
@@ -209,7 +185,7 @@ sdl_zoom.o: sdl_zoom.c sdl_zoom.h sdl_zoom_template.h
sdl.o: sdl.c keymaps.h sdl_keysym.h sdl_zoom.h
sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
sdl.o audio/sdlaudio.o sdl_zoom.o baum.o: CFLAGS += $(SDL_CFLAGS)
acl.o: acl.h acl.c
@@ -217,7 +193,7 @@ vnc.h: vnc-tls.h vnc-auth-vencrypt.h vnc-auth-sasl.h keymaps.h
vnc.o: vnc.c vnc.h vnc_keysym.h vnchextile.h d3des.c d3des.h acl.h
vnc.o: QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
vnc.o: CFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
vnc-tls.o: vnc-tls.c vnc.h
@@ -227,47 +203,46 @@ vnc-auth-sasl.o: vnc-auth-sasl.c vnc.h
curses.o: curses.c keymaps.h curses_keys.h
bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS)
bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS)
libqemu_common.a: $(obj-y)
#######################################################################
# user-obj-y is code used by qemu userspace emulation
user-obj-y = cutils.o cache-utils.o
libqemu_user.a: $(user-obj-y)
######################################################################
qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
qemu-img$(EXESUF): qemu-img.o qemu-tool.o tool-osdep.o $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o $(block-obj-y) $(qobject-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o tool-osdep.o $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o qemu-tool.o cmd.o $(block-obj-y) $(qobject-obj-y)
qemu-io$(EXESUF): qemu-io.o qemu-tool.o tool-osdep.o cmd.o $(block-obj-y)
qemu-img$(EXESUF) qemu-nbd$(EXESUF) qemu-io$(EXESUF): LIBS += -lz
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $@")
check-qint: check-qint.o qint.o qemu-malloc.o
check-qstring: check-qstring.o qstring.o qemu-malloc.o
check-qdict: check-qdict.o qdict.o qint.o qstring.o qbool.o qemu-malloc.o qlist.o
check-qlist: check-qlist.o qlist.o qint.o qemu-malloc.o
check-qfloat: check-qfloat.o qfloat.o qemu-malloc.o
check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o qemu-malloc.o
clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d
rm -f qemu-img-cmds.h
$(MAKE) -C tests clean
for d in $(ALL_SUBDIRS) libhw32 libhw64 libuser; do \
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
for d in $(TARGET_DIRS) $(ROMS) libhw32 libhw64; do \
$(MAKE) -C $$d $@ || exit 1 ; \
done
distclean: clean
rm -f config-host.mak config-host.h* config-host.ld $(DOCS) qemu-options.texi qemu-img-cmds.texi qemu-monitor.texi
rm -f config-all-devices.mak
rm -f roms/seabios/config.mak roms/vgabios/config.mak
rm -f config-host.mak config-host.h $(DOCS) qemu-options.texi qemu-img-cmds.texi
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
for d in $(TARGET_DIRS) libhw32 libhw64 libuser; do \
for d in $(TARGET_DIRS) libhw32 libhw64; do \
rm -rf $$d || exit 1 ; \
done
@@ -278,19 +253,22 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr
ifdef INSTALL_BLOBS
BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-e1000.bin pxe-i82559er.bin \
pxe-ne2k_pci.bin pxe-pcnet.bin \
pxe-rtl8139.bin pxe-virtio.bin \
pxe-ne2k_pci.bin pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin \
bamboo.dtb petalogix-s3adsp1800.dtb \
multiboot.bin linuxboot.bin
multiboot.bin
else
BLOBS=
endif
roms:
for d in $(ROMS); do \
$(MAKE) -C $$d || exit 1 ; \
done
install-doc: $(DOCS)
$(INSTALL_DIR) "$(DESTDIR)$(docdir)"
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
ifdef CONFIG_POSIX
ifndef CONFIG_WIN32
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
@@ -320,9 +298,8 @@ endif
test speed: all
$(MAKE) -C tests $@
.PHONY: TAGS
TAGS:
find "$(SRC_PATH)" -name '*.[hc]' -print0 | xargs -0 etags
etags *.[ch] tests/*.[ch] block/*.[ch] hw/*.[ch]
cscope:
rm -f ./cscope.*
@@ -392,7 +369,6 @@ tarbin:
$(bindir)/qemu-system-arm \
$(bindir)/qemu-system-cris \
$(bindir)/qemu-system-m68k \
$(bindir)/qemu-system-microblaze \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-system-mipsel \
$(bindir)/qemu-system-mips64 \
@@ -410,7 +386,6 @@ tarbin:
$(bindir)/qemu-armeb \
$(bindir)/qemu-cris \
$(bindir)/qemu-m68k \
$(bindir)/qemu-microblaze \
$(bindir)/qemu-mips \
$(bindir)/qemu-mipsel \
$(bindir)/qemu-ppc \
@@ -442,4 +417,4 @@ tarbin:
$(mandir)/man8/qemu-nbd.8
# Include automatically generated dependency files
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d net/*.d)
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d)

View File

@@ -1,44 +1,29 @@
# Makefile for qemu target independent devices.
include ../config-host.mak
include ../config-all-devices.mak
include config.mak
include ../config-host.mak
include $(SRC_PATH)/rules.mak
.PHONY: all
VPATH=$(SRC_PATH):$(SRC_PATH)/hw
QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
CPPFLAGS += -I. -I.. -I$(SRC_PATH) -MMD -MP -MT $@
CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CPPFLAGS+=-I$(SRC_PATH)/fpu
obj-y =
obj-y += loader.o
obj-y += virtio.o
obj-y += virtio.o virtio-pci.o
obj-y += fw_cfg.o
obj-y += watchdog.o
obj-$(CONFIG_ECC) += ecc.o
obj-$(CONFIG_NAND) += nand.o
obj-y += nand.o ecc.o
obj-$(CONFIG_M48T59) += m48t59.o
obj-$(CONFIG_ESCC) += escc.o
# PCI watchdog devices
obj-y += wdt_i6300esb.o
obj-y += msix.o
# PCI network cards
obj-y += ne2000.o
obj-$(CONFIG_SMC91C111) += smc91c111.o
obj-$(CONFIG_LAN9118) += lan9118.o
obj-y += m48t59.o escc.o
# SCSI layer
obj-y += lsi53c895a.o
obj-$(CONFIG_ESP) += esp.o
obj-y += lsi53c895a.o esp.o
obj-y += dma-helpers.o sysbus.o isa-bus.o
obj-$(CONFIG_QDEV_ADDR) += qdev-addr.o
obj-y += dma-helpers.o sysbus.o qdev-addr.o
all: $(HWLIB)
# Dummy command so that make thinks it has done something

View File

@@ -1,16 +1,11 @@
# -*- Mode: makefile -*-
# This needs to be defined before rules.mak
GENERATED_HEADERS = config-target.h
include ../config-host.mak
include config-devices.mak
include config-target.mak
include config.mak
include $(SRC_PATH)/rules.mak
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -MMD -MT $@ -MP -DNEED_CPU_H
#CFLAGS+=-Werror
LIBS=
ifdef CONFIG_USER_ONLY
# user emulator name
@@ -26,43 +21,135 @@ endif
PROGS=$(QEMU_PROG)
# cc-option
# Usage: CFLAGS+=$(call cc-option, $(CFLAGS), -falign-functions=0, -malign-functions=0)
cc-option = $(shell if $(CC) $(1) $(2) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi ;)
HELPER_CFLAGS=
ifeq ($(ARCH),i386)
HELPER_CFLAGS+=-fomit-frame-pointer
endif
ifeq ($(subst ppc64,ppc,$(ARCH))$(TARGET_BASE_ARCH),ppcppc)
translate.o: CFLAGS := $(CFLAGS) $(call cc-option, $(CFLAGS), -fno-unit-at-a-time,)
endif
ifeq ($(ARCH),sparc)
ifneq ($(CONFIG_SOLARIS),y)
HELPER_CFLAGS+=-ffixed-i0
endif
endif
ifeq ($(ARCH),alpha)
# Ensure there's only a single GP
CFLAGS+=-msmall-data
endif
ifeq ($(ARCH),ia64)
CFLAGS+=-mno-sdata
endif
CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
CPPFLAGS+=-U_FORTIFY_SOURCE
LIBS+=-lm
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
ifdef CONFIG_SOLARIS
LIBS+=-lsocket -lnsl -lresolv
ifdef NEEDS_LIBSUNMATH
LIBS+=-lsunmath
LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib
CFLAGS+=-I/opt/SUNWspro/prod/include/cc
endif
endif
kvm.o kvm-all.o: QEMU_CFLAGS+=$(KVM_CFLAGS)
config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
kvm.o: CFLAGS+=$(KVM_CFLAGS)
kvm-all.o: CFLAGS+=$(KVM_CFLAGS)
all: $(PROGS)
# Dummy command so that make thinks it has done something
@true
#########################################################
# cpu emulator library
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
libobj-y += tcg/tcg.o
libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
libobj-y = exec.o translate-all.o cpu-exec.o translate.o host-utils.o
libobj-$(CONFIG_KQEMU) += kqemu.o
# TCG code generator
libobj-y += tcg/tcg.o tcg/tcg-runtime.o
CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH)
ifeq ($(ARCH),sparc64)
CPPFLAGS+=-I$(SRC_PATH)/tcg/sparc
endif
ifdef CONFIG_SOFTFLOAT
libobj-y += fpu/softfloat.o
else
libobj-y += fpu/softfloat-native.o
endif
CPPFLAGS+=-I$(SRC_PATH)/fpu
libobj-y += op_helper.o helper.o
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ALPHA) += alpha_palcode.o
ifeq ($(TARGET_BASE_ARCH), arm)
libobj-y += neon_helper.o iwmmxt_helper.o
endif
ifeq ($(TARGET_BASE_ARCH), alpha)
libobj-y += alpha_palcode.o
endif
ifeq ($(TARGET_BASE_ARCH), cris)
libobj-y += cris-dis.o
ifndef CONFIG_USER_ONLY
libobj-y += mmu.o
endif
endif
# NOTE: the disassembler code is only needed for debugging
libobj-y += disas.o
libobj-$(CONFIG_ALPHA_DIS) += alpha-dis.o
libobj-$(CONFIG_ARM_DIS) += arm-dis.o
libobj-$(CONFIG_CRIS_DIS) += cris-dis.o
libobj-$(CONFIG_HPPA_DIS) += hppa-dis.o
libobj-$(CONFIG_I386_DIS) += i386-dis.o
libobj-$(CONFIG_M68K_DIS) += m68k-dis.o
libobj-$(CONFIG_MICROBLAZE_DIS) += microblaze-dis.o
libobj-$(CONFIG_MIPS_DIS) += mips-dis.o
libobj-$(CONFIG_PPC_DIS) += ppc-dis.o
libobj-$(CONFIG_S390_DIS) += s390-dis.o
libobj-$(CONFIG_SH4_DIS) += sh4-dis.o
libobj-$(CONFIG_SPARC_DIS) += sparc-dis.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
USE_I386_DIS=y
endif
ifeq ($(findstring x86_64, $(TARGET_ARCH) $(ARCH)),x86_64)
USE_I386_DIS=y
endif
libobj-$(USE_I386_DIS) += i386-dis.o
ifeq ($(findstring alpha, $(TARGET_ARCH) $(ARCH)),alpha)
libobj-y += alpha-dis.o
endif
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
libobj-y += ppc-dis.o
endif
ifeq ($(findstring microblaze, $(TARGET_BASE_ARCH) $(ARCH)),microblaze)
libobj-y += microblaze-dis.o
ifndef CONFIG_USER_ONLY
libobj-y += mmu.o
endif
endif
ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips)
libobj-y += mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
libobj-y += sparc-dis.o
endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
libobj-y += arm-dis.o
endif
ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
libobj-y += m68k-dis.o
endif
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
libobj-y += sh4-dis.o
endif
ifeq ($(findstring hppa, $(TARGET_BASE_ARCH) $(ARCH)),hppa)
libobj-y += hppa-dis.o
endif
ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390)
libobj-y += s390-dis.o
endif
# libqemu
@@ -76,11 +163,9 @@ tcg/tcg.o: cpu.h
# HELPER_CFLAGS is used for all the code compiled with static register
# variables
op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
op_helper.o: CFLAGS += $(HELPER_CFLAGS)
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
cpu-exec.o: CFLAGS += $(HELPER_CFLAGS)
#########################################################
# Linux user emulator target
@@ -88,35 +173,130 @@ signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS)
ifdef CONFIG_LINUX_USER
VPATH+=:$(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \
elfload.o linuxload.o uaccess.o gdbstub.o
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifeq ($(ARCH),i386)
ifdef TARGET_GPROF
USE_I386_LD=y
endif
ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
endif
endif
ifeq ($(ARCH),x86_64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),s390)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),sparc)
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
endif
ifeq ($(ARCH),sparc64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),alpha)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ia64)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),arm)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),m68k)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),mips)
ifeq ($(WORDS_BIGENDIAN),yes)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
endif
ifeq ($(ARCH),mips64)
ifeq ($(WORDS_BIGENDIAN),yes)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
endif
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
CFLAGS+=-p
endif
obj-y = main.o syscall.o strace.o mmap.o signal.o path.o thunk.o \
elfload.o linuxload.o uaccess.o envlist.o gdbstub.o gdbstub-xml.o \
ioport-user.o
obj-$(TARGET_HAS_BFLT) += flatload.o
ifdef TARGET_HAS_ELFLOAD32
elfload32.o: elfload.c
endif
obj-$(TARGET_HAS_ELFLOAD32) += elfload32.o
obj-$(TARGET_I386) += vm86.o
ifeq ($(TARGET_ARCH), i386)
obj-y += vm86.o
endif
obj-i386-y += ioport-user.o
nwfpe-obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o
nwfpe-obj-y := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o
nwfpe-obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o
obj-arm-y += $(addprefix nwfpe/, $(nwfpe-obj-y))
obj-arm-y += arm-semi.o
obj-m68k-y += m68k-sim.o m68k-semi.o
ARLIBS=../libuser/libuser.a libqemu.a
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
signal.o: CFLAGS += $(HELPER_CFLAGS)
ARLIBS=../libqemu_user.a libqemu.a
endif #CONFIG_LINUX_USER
LIBS+= $(PTHREADLIBS)
LIBS+= $(CLOCKLIBS)
#########################################################
# Darwin user emulator target
ifdef CONFIG_DARWIN_USER
VPATH+=:$(SRC_PATH)/darwin-user
QEMU_CFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
# Leave some space for the regular program loading zone
LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
@@ -124,11 +304,13 @@ LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
LIBS+=-lmx
obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \
gdbstub.o
gdbstub.o gdbstub-xml.o ioport-user.o
obj-i386-y += ioport-user.o
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
signal.o: CFLAGS += $(HELPER_CFLAGS)
ARLIBS=../libuser/libuser.a libqemu.a
ARLIBS=libqemu.a
endif #CONFIG_DARWIN_USER
@@ -138,28 +320,128 @@ endif #CONFIG_DARWIN_USER
ifdef CONFIG_BSD_USER
VPATH+=:$(SRC_PATH)/bsd-user
QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
CPPFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH)
obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \
gdbstub.o uaccess.o
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
obj-i386-y += ioport-user.o
ifeq ($(ARCH),i386)
ifdef TARGET_GPROF
USE_I386_LD=y
endif
ifdef CONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
LDFLAGS+=-Wl,-shared
endif
endif
ARLIBS=../libuser/libuser.a libqemu.a
ifeq ($(ARCH),x86_64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),s390)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),sparc)
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
endif
ifeq ($(ARCH),sparc64)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),alpha)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ia64)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),arm)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),m68k)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),mips)
ifeq ($(WORDS_BIGENDIAN),yes)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
endif
ifeq ($(ARCH),mips64)
ifeq ($(WORDS_BIGENDIAN),yes)
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
endif
obj-y = main.o bsdload.o elfload.o mmap.o path.o signal.o strace.o syscall.o \
gdbstub.o gdbstub-xml.o ioport-user.o
obj-y += uaccess.o
# Note: this is a workaround. The real fix is to avoid compiling
# cpu_signal_handler() in cpu-exec.c.
signal.o: CFLAGS += $(HELPER_CFLAGS)
ARLIBS=libqemu.a ../libqemu_user.a
endif #CONFIG_BSD_USER
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
ifndef CONFIG_USER_ONLY
obj-y = vl.o async.o monitor.o pci.o pci_host.o pcie_host.o machine.o gdbstub.o
obj-y = vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o \
gdbstub.o gdbstub-xml.o msix.o ioport.o
# virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o virtio-pci.o
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
ifdef CONFIG_ALSA
LIBS += -lasound
endif
ifdef CONFIG_ESD
LIBS += -lesd
endif
ifdef CONFIG_PA
LIBS += -lpulse-simple
endif
ifdef CONFIG_DSOUND
LIBS += -lole32 -ldxguid
endif
ifdef CONFIG_FMOD
LIBS += $(CONFIG_FMOD_LIB)
endif
ifdef CONFIG_OSS
LIBS += $(CONFIG_OSS_LIB)
endif
sound-obj-y =
sound-obj-$(CONFIG_SB16) += sb16.o
@@ -169,40 +451,59 @@ sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
sound-obj-$(CONFIG_CS4231A) += cs4231a.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
ifdef CONFIG_ADLIB
adlib.o fmopl.o: CFLAGS := ${CFLAGS} -DBUILD_Y8950=0
endif
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
ifdef CONFIG_VNC_TLS
CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
LIBS += $(CONFIG_VNC_TLS_LIBS)
endif
ifdef CONFIG_VNC_SASL
CPPFLAGS += $(CONFIG_VNC_SASL_CFLAGS)
LIBS += $(CONFIG_VNC_SASL_LIBS)
endif
ifdef CONFIG_BLUEZ
LIBS += $(CONFIG_BLUEZ_LIBS)
endif
# xen backend driver support
obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o
ifeq ($(CONFIG_XEN), y)
LIBS += $(XEN_LIBS)
endif
# USB layer
obj-$(CONFIG_USB_OHCI) += usb-ohci.o
obj-y += usb-ohci.o
# PCI network cards
obj-y += eepro100.o
obj-y += ne2000.o
obj-y += pcnet.o
obj-y += rtl8139.o
obj-y += e1000.o
# Generic watchdog support and some watchdog devices
obj-y += wdt_ib700.o wdt_i6300esb.o
# Hardware support
obj-i386-y = ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
obj-i386-y += pckbd.o $(sound-obj-y) dma.o
obj-i386-y += vga.o vga-pci.o vga-isa.o
obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o
obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += ne2000-isa.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o
ifeq ($(TARGET_BASE_ARCH), i386)
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
# shared objects
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
obj-ppc-y += ide/cmd646.o
obj-ppc-y += vga.o vga-pci.o $(sound-obj-y) dma.o openpic.o
obj-ppc-y = ppc.o ide.o vga.o $(sound-obj-y) dma.o openpic.o
# PREP target
obj-ppc-y += pckbd.o serial.o i8259.o i8254.o fdc.o mc146818rtc.o
obj-ppc-y += prep_pci.o ppc_prep.o ne2000-isa.o
obj-ppc-y += prep_pci.o ppc_prep.o
# Mac shared devices
obj-ppc-y += macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o
# OldWorld PowerMac
@@ -215,19 +516,29 @@ obj-ppc-y += ppc440.o ppc440_bamboo.o
# PowerPC E500 boards
obj-ppc-y += ppce500_pci.o ppce500_mpc8544ds.o
obj-ppc-$(CONFIG_KVM) += kvm_ppc.o
obj-ppc-$(CONFIG_FDT) += device_tree.o
ifeq ($(TARGET_BASE_ARCH), ppc)
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifdef FDT_LIBS
obj-ppc-y += device_tree.o
LIBS+= $(FDT_LIBS)
endif
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
obj-mips-y += vga-pci.o vga-isa.o vga-isa-mm.o
obj-mips-y += g364fb.o jazz_led.o dp8393x.o
obj-mips-y += ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/piix.o
obj-mips-y += gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
obj-mips-y += piix4.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
obj-mips-y += mipsnet.o ne2000-isa.o
obj-mips-y += ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
obj-mips-y += piix_pci.o parallel.o cirrus_vga.o pcspk.o $(sound-obj-y)
obj-mips-y += mipsnet.o
obj-mips-y += pflash_cfi01.o
obj-mips-y += vmware_vga.o
ifeq ($(TARGET_BASE_ARCH), mips)
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
obj-microblaze-y += microblaze_pic_cpu.o
@@ -238,7 +549,10 @@ obj-microblaze-y += xilinx_ethlite.o
obj-microblaze-y += pflash_cfi02.o
obj-microblaze-$(CONFIG_FDT) += device_tree.o
ifdef FDT_LIBS
obj-microblaze-y += device_tree.o
LIBS+= $(FDT_LIBS)
endif
# Boards
obj-cris-y = cris_pic_cpu.o etraxfs.o axis_dev88.o
@@ -253,68 +567,111 @@ obj-cris-y += etraxfs_ser.o
obj-cris-y += pflash_cfi02.o
ifeq ($(TARGET_ARCH), sparc64)
obj-sparc-y = sun4u.o pckbd.o apb_pci.o
obj-sparc-y += ide/core.o ide/qdev.o ide/pci.o ide/cmd646.o
obj-sparc-y += vga.o vga-pci.o
obj-sparc-y = sun4u.o ide.o pckbd.o vga.o apb_pci.o
obj-sparc-y += fdc.o mc146818rtc.o serial.o
obj-sparc-y += cirrus_vga.o parallel.o
else
obj-sparc-y = sun4m.o lance.o tcx.o iommu.o slavio_intctl.o
obj-sparc-y = sun4m.o tcx.o iommu.o slavio_intctl.o
obj-sparc-y += slavio_timer.o slavio_misc.o fdc.o sparc32_dma.o
obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
endif
obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y = integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o mpcore.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-arm-y += pflash_cfi01.o gumstix.o
obj-arm-y += zaurus.o ide/core.o ide/microdrive.o serial.o spitz.o tosa.o tc6393xb.o
obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
obj-arm-y += omap2.o omap_dss.o soc_dma.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += musicpal.o pflash_cfi02.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += musicpal.o pflash_cfi02.o
obj-arm-y += framebuffer.o
obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
obj-arm-y += syborg_virtio.o
ifeq ($(TARGET_BASE_ARCH), arm)
CPPFLAGS += -DHAS_AUDIO
endif
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
obj-sh4-y += ide/core.o ide/mmio.o
obj-sh4-y += ide.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
ifdef CONFIG_COCOA
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
ifdef CONFIG_COREAUDIO
COCOA_LIBS+=-framework CoreAudio
endif
endif
ifdef CONFIG_SLIRP
CPPFLAGS+=-I$(SRC_PATH)/slirp
endif
main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
# specific flags are needed for non soft mmu emulator
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
ifndef CONFIG_AIX
LIBS+=-lutil
endif
endif
endif
endif
ifdef TARGET_GPROF
vl.o: CFLAGS+=-p
LDFLAGS+=-p
endif
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
ifeq ($(ARCH),ia64)
LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
endif
# profiling code
ifdef TARGET_GPROF
LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
vl.o: CFLAGS+=$(SDL_CFLAGS)
vl.o: qemu-options.h
monitor.o: qemu-monitor.h
LIBS += $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS) $(CURL_LIBS)
ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
endif # CONFIG_SOFTMMU
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
endif # !CONFIG_USER_ONLY
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(ARLIBS)
$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y))
gdbstub-xml.c: $(TARGET_XML_FILES) feature_to_c.sh
ifeq ($(TARGET_XML_FILES),)
$(call quiet-command,rm -f $@ && echo > $@," GEN $(TARGET_DIR)$@")
else
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
endif
qemu-options.h: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
@@ -324,7 +681,7 @@ qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o
rm -f *.d */*.d tcg/*.o
rm -f qemu-options.h qemu-monitor.h gdbstub-xml.c
install: all

View File

@@ -1,27 +0,0 @@
# Makefile for qemu target independent user files.
include ../config-host.mak
include $(SRC_PATH)/rules.mak
.PHONY: all
VPATH=$(SRC_PATH)
QEMU_CFLAGS+=-I..
obj-y =
obj-y += envlist.o path.o
obj-y += tcg-runtime.o host-utils.o
obj-y += cutils.o cache-utils.o
all: libuser.a
# Dummy command so that make thinks it has done something
@true
libuser.a: $(obj-y)
clean:
rm -f *.o *.d *.a *~
# Include automatically generated dependency files
-include $(wildcard *.d */*.d)

View File

@@ -1,63 +0,0 @@
QEMU Monitor Protocol
=====================
Introduction
-------------
The QEMU Monitor Protocol (QMP) allows applications to communicate with
QEMU's Monitor.
QMP is JSON[1] based and has the following features:
- Lightweight, text-based, easy to parse data format
- Asynchronous events support
- Stability
For more information, please, refer to the following files:
o qmp-spec.txt QEMU Monitor Protocol current specification
o qmp-events.txt List of available asynchronous events
There are also two simple Python scripts available:
o qmp-shell A shell
o vm-info Show some information about the Virtual Machine
[1] http://www.json.org
Usage
-----
To enable QMP, QEMU has to be started in "control mode". There are
two ways of doing this, the simplest one is using the the '-qmp'
command-line option.
For example:
$ qemu [...] -qmp tcp:localhost:4444,server
Will start QEMU in control mode, waiting for a client TCP connection
on localhost port 4444.
It is also possible to use the '-mon' command-line option to have
more complex combinations. Please, refer to the QEMU's manpage for
more information.
Simple Testing
--------------
To manually test QMP one can connect with telnet and issue commands:
$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"QMP": {"capabilities": []}}
{ "execute": "query-version" }
{"return": {"qemu": "0.11.50", "package": ""}}
Contact
-------
http://www.linux-kvm.org/page/MonitorProtocol
Luiz Fernando N. Capitulino <lcapitulino@redhat.com>

View File

@@ -1,26 +0,0 @@
QEMU Monitor Protocol: Events
=============================
1 SHUTDOWN
-----------
Description: Issued when the Virtual Machine is powered down.
Data: None.
2 RESET
-------
Description: Issued when the Virtual Machine is reseted.
Data: None.
3 STOP
------
Description: Issued when the Virtual Machine is stopped.
Data: None.
4 DEBUG
-------
Description: Issued when the Virtual Machine enters debug mode.
Data: None.

View File

@@ -1,72 +0,0 @@
#!/usr/bin/python
#
# Simple QEMU shell on top of QMP
#
# Copyright (C) 2009 Red Hat Inc.
#
# Authors:
# Luiz Capitulino <lcapitulino@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2. See
# the COPYING file in the top-level directory.
#
# Usage:
#
# Start QEMU with:
#
# $ qemu [...] -monitor control,unix:./qmp,server
#
# Run the shell:
#
# $ qmp-shell ./qmp
#
# Commands have the following format:
#
# < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
#
# For example:
#
# (QEMU) info item=network
import qmp
import readline
from sys import argv,exit
def shell_help():
print 'bye exit from the shell'
def main():
if len(argv) != 2:
print 'qemu-shell <unix-socket>'
exit(1)
qemu = qmp.QEMUMonitorProtocol(argv[1])
qemu.connect()
print 'Connected!'
while True:
try:
cmd = raw_input('(QEMU) ')
except EOFError:
print
break
if cmd == '':
continue
elif cmd == 'bye':
break
elif cmd == 'help':
shell_help()
else:
try:
resp = qemu.send(cmd)
if resp == None:
print 'Disconnected'
break
print resp
except IndexError:
print '-> command format: <command-name> ',
print '[arg-name1=arg1] ... [arg-nameN=argN]'
if __name__ == '__main__':
main()

View File

@@ -1,203 +0,0 @@
QEMU Monitor Protocol Specification - Version 0.1
1. Introduction
===============
This document specifies the QEMU Monitor Protocol (QMP), a JSON-based protocol
which is available for applications to control QEMU at the machine-level.
To enable QMP support, QEMU has to be run in "control mode". This is done by
starting QEMU with the appropriate command-line options. Please, refer to the
QEMU manual page for more information.
2. Protocol Specification
=========================
This section details the protocol format. For the purpose of this document
"Client" is any application which is communicating with QEMU in control mode,
and "Server" is QEMU itself.
JSON data structures, when mentioned in this document, are always in the
following format:
json-DATA-STRUCTURE-NAME
Where DATA-STRUCTURE-NAME is any valid JSON data structure, as defined by
the JSON standard:
http://www.ietf.org/rfc/rfc4627.txt
For convenience, json-object members and json-array elements mentioned in
this document will be in a certain order. However, in real protocol usage
they can be in ANY order, thus no particular order should be assumed.
2.1 General Definitions
-----------------------
2.1.1 All interactions transmitted by the Server are json-objects, always
terminating with CRLF
2.1.2 All json-objects members are mandatory when not specified otherwise
2.2 Server Greeting
-------------------
Right when connected the Server will issue a greeting message, which signals
that the connection has been successfully established and that the Server is
waiting for commands.
The format is:
{ "QMP": { "capabilities": json-array } }
Where,
- The "capabilities" member specify the availability of features beyond the
baseline specification
2.3 Issuing Commands
--------------------
The format for command execution is:
{ "execute": json-string, "arguments": json-object, "id": json-value }
Where,
- The "execute" member identifies the command to be executed by the Server
- The "arguments" member is used to pass any arguments required for the
execution of the command, it is optional when no arguments are required
- The "id" member is a transaction identification associated with the
command execution, it is optional and will be part of the response if
provided
2.4 Commands Responses
----------------------
There are two possible responses which the Server will issue as the result
of a command execution: success or error.
2.4.1 success
-------------
The success response is issued when the command execution has finished
without errors.
The format is:
{ "return": json-object, "id": json-value }
Where,
- The "return" member contains the command returned data, which is defined
in a per-command basis or an empty json-object if the command does not
return data
- The "id" member contains the transaction identification associated
with the command execution (if issued by the Client)
2.4.2 error
-----------
The error response is issued when the command execution could not be
completed because of an error condition.
The format is:
{ "error": { "class": json-string, "data": json-object, "desc": json-string },
"id": json-value }
Where,
- The "class" member contains the error class name (eg. "ServiceUnavailable")
- The "data" member contains specific error data and is defined in a
per-command basis, it will be an empty json-object if the error has no data
- The "desc" member is a human-readable error message. Clients should
not attempt to parse this message.
- The "id" member contains the transaction identification associated with
the command execution (if issued by the Client)
NOTE: Some errors can occur before the Server is able to read the "id" member,
in these cases the "id" member will not be part of the error response, even
if provided by the client.
2.5 Asynchronous events
-----------------------
As a result of state changes, the Server may send messages unilaterally
to the Client at any time. They are called 'asynchronous events'.
The format is:
{ "event": json-string, "data": json-object,
"timestamp": { "seconds": json-number, "microseconds": json-number } }
Where,
- The "event" member contains the event's name
- The "data" member contains event specific data, which is defined in a
per-event basis, it is optional
- The "timestamp" member contains the exact time of when the event occurred
in the Server. It is a fixed json-object with time in seconds and
microseconds
For a listing of supported asynchronous events, please, refer to the
qmp-events.txt file.
3. QMP Examples
===============
This section provides some examples of real QMP usage, in all of them
'C' stands for 'Client' and 'S' stands for 'Server'.
3.1 Server greeting
-------------------
S: {"QMP": {"capabilities": []}}
3.2 Simple 'stop' execution
---------------------------
C: { "execute": "stop" }
S: {"return": {}}
3.3 KVM information
-------------------
C: { "execute": "query-kvm", "id": "example" }
S: {"return": {"enabled": true, "present": true}, "id": "example"}
3.4 Parsing error
------------------
C: { "execute": }
S: {"error": {"class": "JSONParsing", "desc": "Invalid JSON syntax", "data":
{}}}
3.5 Powerdown event
-------------------
S: {"timestamp": {"seconds": 1258551470, "microseconds": 802384}, "event":
"POWERDOWN"}
4. Compatibility Considerations
--------------------------------
In order to achieve maximum compatibility between versions, Clients must not
assume any particular:
- Size of json-objects or length of json-arrays
- Order of json-object members or json-array elements
- Amount of errors generated by a command, that is, new errors can be added
to any existing command in newer versions of the Server
Additionally, Clients should always:
- Check the capabilities json-array at connection time
- Check the availability of commands with 'query-commands' before issuing them
5. Recommendations to Client implementors
-----------------------------------------
5.1 The Server should be always started in pause mode, thus the Client is
able to perform any setup procedure without the risk of race conditions
and related problems

View File

@@ -1,72 +0,0 @@
# QEMU Monitor Protocol Python class
#
# Copyright (C) 2009 Red Hat Inc.
#
# Authors:
# Luiz Capitulino <lcapitulino@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2. See
# the COPYING file in the top-level directory.
import socket, json
class QMPError(Exception):
pass
class QMPConnectError(QMPError):
pass
class QEMUMonitorProtocol:
def connect(self):
self.sock.connect(self.filename)
data = self.__json_read()
if data == None:
raise QMPConnectError
if not data.has_key('QMP'):
raise QMPConnectError
return data['QMP']['capabilities']
def close(self):
self.sock.close()
def send_raw(self, line):
self.sock.send(str(line))
return self.__json_read()
def send(self, cmdline):
cmd = self.__build_cmd(cmdline)
self.__json_send(cmd)
resp = self.__json_read()
if resp == None:
return
elif resp.has_key('error'):
return resp['error']
else:
return resp['return']
def __build_cmd(self, cmdline):
cmdargs = cmdline.split()
qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
for arg in cmdargs[1:]:
opt = arg.split('=')
try:
value = int(opt[1])
except ValueError:
value = opt[1]
qmpcmd['arguments'][opt[0]] = value
return qmpcmd
def __json_send(self, cmd):
# XXX: We have to send any additional char, otherwise
# the Server won't read our input
self.sock.send(json.dumps(cmd) + ' ')
def __json_read(self):
try:
return json.loads(self.sock.recv(1024))
except ValueError:
return
def __init__(self, filename):
self.filename = filename
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

View File

@@ -1,32 +0,0 @@
#!/usr/bin/python
#
# Print Virtual Machine information
#
# Usage:
#
# Start QEMU with:
#
# $ qemu [...] -monitor control,unix:./qmp,server
#
# Run vm-info:
#
# $ vm-info ./qmp
#
# Luiz Capitulino <lcapitulino@redhat.com>
import qmp
from sys import argv,exit
def main():
if len(argv) != 2:
print 'vm-info <unix-socket>'
exit(1)
qemu = qmp.QEMUMonitorProtocol(argv[1])
qemu.connect()
for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]:
print cmd + ': ' + str(qemu.send('query-' + cmd))
if __name__ == '__main__':
main()

View File

@@ -1 +1 @@
0.12.1
0.10.91

22
acl.c
View File

@@ -27,7 +27,7 @@
#include "sysemu.h"
#include "acl.h"
#ifdef CONFIG_FNMATCH
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
@@ -64,7 +64,7 @@ qemu_acl *qemu_acl_init(const char *aclname)
acl->defaultDeny = 1;
acl->nentries = 0;
QTAILQ_INIT(&acl->entries);
TAILQ_INIT(&acl->entries);
acls = qemu_realloc(acls, sizeof(*acls) * (nacls +1));
acls[nacls] = acl;
@@ -78,8 +78,8 @@ int qemu_acl_party_is_allowed(qemu_acl *acl,
{
qemu_acl_entry *entry;
QTAILQ_FOREACH(entry, &acl->entries, next) {
#ifdef CONFIG_FNMATCH
TAILQ_FOREACH(entry, &acl->entries, next) {
#ifdef HAVE_FNMATCH_H
if (fnmatch(entry->match, party, 0) == 0)
return entry->deny ? 0 : 1;
#else
@@ -102,8 +102,8 @@ void qemu_acl_reset(qemu_acl *acl)
* of "open access" while the user re-initializes the
* access control list */
acl->defaultDeny = 1;
QTAILQ_FOREACH(entry, &acl->entries, next) {
QTAILQ_REMOVE(&acl->entries, entry, next);
TAILQ_FOREACH(entry, &acl->entries, next) {
TAILQ_REMOVE(&acl->entries, entry, next);
free(entry->match);
free(entry);
}
@@ -121,7 +121,7 @@ int qemu_acl_append(qemu_acl *acl,
entry->match = qemu_strdup(match);
entry->deny = deny;
QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
TAILQ_INSERT_TAIL(&acl->entries, entry, next);
acl->nentries++;
return acl->nentries;
@@ -147,10 +147,10 @@ int qemu_acl_insert(qemu_acl *acl,
entry->match = qemu_strdup(match);
entry->deny = deny;
QTAILQ_FOREACH(tmp, &acl->entries, next) {
TAILQ_FOREACH(tmp, &acl->entries, next) {
i++;
if (i == index) {
QTAILQ_INSERT_BEFORE(tmp, entry, next);
TAILQ_INSERT_BEFORE(tmp, entry, next);
acl->nentries++;
break;
}
@@ -165,10 +165,10 @@ int qemu_acl_remove(qemu_acl *acl,
qemu_acl_entry *entry;
int i = 0;
QTAILQ_FOREACH(entry, &acl->entries, next) {
TAILQ_FOREACH(entry, &acl->entries, next) {
i++;
if (strcmp(entry->match, match) == 0) {
QTAILQ_REMOVE(&acl->entries, entry, next);
TAILQ_REMOVE(&acl->entries, entry, next);
return i;
}
}

6
acl.h
View File

@@ -25,7 +25,7 @@
#ifndef __QEMU_ACL_H__
#define __QEMU_ACL_H__
#include "qemu-queue.h"
#include "sys-queue.h"
typedef struct qemu_acl_entry qemu_acl_entry;
typedef struct qemu_acl qemu_acl;
@@ -34,13 +34,13 @@ struct qemu_acl_entry {
char *match;
int deny;
QTAILQ_ENTRY(qemu_acl_entry) next;
TAILQ_ENTRY(qemu_acl_entry) next;
};
struct qemu_acl {
char *aclname;
unsigned int nentries;
QTAILQ_HEAD(,qemu_acl_entry) entries;
TAILQ_HEAD(,qemu_acl_entry) entries;
int defaultDeny;
};

52
aio.c
View File

@@ -13,13 +13,13 @@
#include "qemu-common.h"
#include "block.h"
#include "qemu-queue.h"
#include "sys-queue.h"
#include "qemu_socket.h"
typedef struct AioHandler AioHandler;
/* The list of registered AIO handlers */
static QLIST_HEAD(, AioHandler) aio_handlers;
static LIST_HEAD(, AioHandler) aio_handlers;
/* This is a simple lock used to protect the aio_handlers list. Specifically,
* it's used to ensure that no callbacks are removed while we're walking and
@@ -33,17 +33,16 @@ struct AioHandler
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
AioProcessQueue *io_process_queue;
int deleted;
void *opaque;
QLIST_ENTRY(AioHandler) node;
LIST_ENTRY(AioHandler) node;
};
static AioHandler *find_aio_handler(int fd)
{
AioHandler *node;
QLIST_FOREACH(node, &aio_handlers, node) {
LIST_FOREACH(node, &aio_handlers, node) {
if (node->fd == fd)
if (!node->deleted)
return node;
@@ -56,7 +55,6 @@ int qemu_aio_set_fd_handler(int fd,
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
AioProcessQueue *io_process_queue,
void *opaque)
{
AioHandler *node;
@@ -74,7 +72,7 @@ int qemu_aio_set_fd_handler(int fd,
* deleted because deleted nodes are only cleaned up after
* releasing the walking_handlers lock.
*/
QLIST_REMOVE(node, node);
LIST_REMOVE(node, node);
qemu_free(node);
}
}
@@ -83,13 +81,12 @@ int qemu_aio_set_fd_handler(int fd,
/* Alloc and insert if it's not already there */
node = qemu_mallocz(sizeof(AioHandler));
node->fd = fd;
QLIST_INSERT_HEAD(&aio_handlers, node, node);
LIST_INSERT_HEAD(&aio_handlers, node, node);
}
/* Update handler with latest information */
node->io_read = io_read;
node->io_write = io_write;
node->io_flush = io_flush;
node->io_process_queue = io_process_queue;
node->opaque = opaque;
}
@@ -112,32 +109,12 @@ void qemu_aio_flush(void)
*/
qemu_aio_wait();
QLIST_FOREACH(node, &aio_handlers, node) {
LIST_FOREACH(node, &aio_handlers, node) {
ret |= node->io_flush(node->opaque);
}
} while (qemu_bh_poll() || ret > 0);
}
int qemu_aio_process_queue(void)
{
AioHandler *node;
int ret = 0;
walking_handlers = 1;
QLIST_FOREACH(node, &aio_handlers, node) {
if (node->io_process_queue) {
if (node->io_process_queue(node->opaque)) {
ret = 1;
}
}
}
walking_handlers = 0;
return ret;
}
void qemu_aio_wait(void)
{
int ret;
@@ -145,13 +122,6 @@ void qemu_aio_wait(void)
if (qemu_bh_poll())
return;
/*
* If there are callbacks left that have been queued, we need to call then.
* Return afterwards to avoid waiting needlessly in select().
*/
if (qemu_aio_process_queue())
return;
do {
AioHandler *node;
fd_set rdfds, wrfds;
@@ -163,7 +133,7 @@ void qemu_aio_wait(void)
FD_ZERO(&wrfds);
/* fill fd sets */
QLIST_FOREACH(node, &aio_handlers, node) {
LIST_FOREACH(node, &aio_handlers, node) {
/* If there aren't pending AIO operations, don't invoke callbacks.
* Otherwise, if there are no AIO requests, qemu_aio_wait() would
* wait indefinitely.
@@ -198,7 +168,7 @@ void qemu_aio_wait(void)
/* we have to walk very carefully in case
* qemu_aio_set_fd_handler is called while we're walking */
node = QLIST_FIRST(&aio_handlers);
node = LIST_FIRST(&aio_handlers);
while (node) {
AioHandler *tmp;
@@ -214,10 +184,10 @@ void qemu_aio_wait(void)
}
tmp = node;
node = QLIST_NEXT(node, node);
node = LIST_NEXT(node, node);
if (tmp->deleted) {
QLIST_REMOVE(tmp, node);
LIST_REMOVE(tmp, node);
qemu_free(tmp);
}
}

View File

@@ -108,8 +108,8 @@ struct alpha_operand
string (the operand will be inserted in any case). If the
operand value is legal, *ERRMSG will be unchanged (most operands
can accept any value). */
unsigned (*insert) (unsigned instruction, int op,
const char **errmsg);
unsigned (*insert) PARAMS ((unsigned instruction, int op,
const char **errmsg));
/* Extraction function. This is used by the disassembler. To
extract this operand type from an instruction, check this field.
@@ -128,7 +128,7 @@ struct alpha_operand
non-zero if this operand type can not actually be extracted from
this operand (i.e., the instruction does not match). If the
operand is valid, *INVALID will not be changed. */
int (*extract) (unsigned instruction, int *invalid);
int (*extract) PARAMS ((unsigned instruction, int *invalid));
};
/* Elements in the table are retrieved by indexing with values from
@@ -158,7 +158,7 @@ extern const unsigned alpha_num_operands;
instructions which want their operands to look like "Ra,disp(Rb)". */
#define AXP_OPERAND_PARENS 02
/* Used in combination with PARENS, this suppresses the suppression of
/* Used in combination with PARENS, this supresses the supression of
the comma. This is used for "jmp Ra,(Rb),hint". */
#define AXP_OPERAND_COMMA 04
@@ -179,7 +179,7 @@ extern const unsigned alpha_num_operands;
a flags value of 0 can be treated as end-of-arguments. */
#define AXP_OPERAND_UNSIGNED 0200
/* Suppress overflow detection on this field. This is used for hints. */
/* Supress overflow detection on this field. This is used for hints. */
#define AXP_OPERAND_NOOVERFLOW 0400
/* Mask for optional argument default value. */
@@ -273,23 +273,23 @@ enum bfd_reloc_code_real {
/* Local insertion and extraction functions */
static unsigned insert_rba (unsigned, int, const char **);
static unsigned insert_rca (unsigned, int, const char **);
static unsigned insert_za (unsigned, int, const char **);
static unsigned insert_zb (unsigned, int, const char **);
static unsigned insert_zc (unsigned, int, const char **);
static unsigned insert_bdisp (unsigned, int, const char **);
static unsigned insert_jhint (unsigned, int, const char **);
static unsigned insert_ev6hwjhint (unsigned, int, const char **);
static unsigned insert_rba PARAMS((unsigned, int, const char **));
static unsigned insert_rca PARAMS((unsigned, int, const char **));
static unsigned insert_za PARAMS((unsigned, int, const char **));
static unsigned insert_zb PARAMS((unsigned, int, const char **));
static unsigned insert_zc PARAMS((unsigned, int, const char **));
static unsigned insert_bdisp PARAMS((unsigned, int, const char **));
static unsigned insert_jhint PARAMS((unsigned, int, const char **));
static unsigned insert_ev6hwjhint PARAMS((unsigned, int, const char **));
static int extract_rba (unsigned, int *);
static int extract_rca (unsigned, int *);
static int extract_za (unsigned, int *);
static int extract_zb (unsigned, int *);
static int extract_zc (unsigned, int *);
static int extract_bdisp (unsigned, int *);
static int extract_jhint (unsigned, int *);
static int extract_ev6hwjhint (unsigned, int *);
static int extract_rba PARAMS((unsigned, int *));
static int extract_rca PARAMS((unsigned, int *));
static int extract_za PARAMS((unsigned, int *));
static int extract_zb PARAMS((unsigned, int *));
static int extract_zc PARAMS((unsigned, int *));
static int extract_bdisp PARAMS((unsigned, int *));
static int extract_jhint PARAMS((unsigned, int *));
static int extract_ev6hwjhint PARAMS((unsigned, int *));
/* The operands table */
@@ -434,13 +434,18 @@ const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operand
/*ARGSUSED*/
static unsigned
insert_rba(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
insert_rba(insn, value, errmsg)
unsigned insn;
int value ATTRIBUTE_UNUSED;
const char **errmsg ATTRIBUTE_UNUSED;
{
return insn | (((insn >> 21) & 0x1f) << 16);
}
static int
extract_rba(unsigned insn, int *invalid)
extract_rba(insn, invalid)
unsigned insn;
int *invalid;
{
if (invalid != (int *) NULL
&& ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
@@ -453,13 +458,18 @@ extract_rba(unsigned insn, int *invalid)
/*ARGSUSED*/
static unsigned
insert_rca(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
insert_rca(insn, value, errmsg)
unsigned insn;
int value ATTRIBUTE_UNUSED;
const char **errmsg ATTRIBUTE_UNUSED;
{
return insn | ((insn >> 21) & 0x1f);
}
static int
extract_rca(unsigned insn, int *invalid)
extract_rca(insn, invalid)
unsigned insn;
int *invalid;
{
if (invalid != (int *) NULL
&& ((insn >> 21) & 0x1f) != (insn & 0x1f))
@@ -472,13 +482,18 @@ extract_rca(unsigned insn, int *invalid)
/*ARGSUSED*/
static unsigned
insert_za(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
insert_za(insn, value, errmsg)
unsigned insn;
int value ATTRIBUTE_UNUSED;
const char **errmsg ATTRIBUTE_UNUSED;
{
return insn | (31 << 21);
}
static int
extract_za(unsigned insn, int *invalid)
extract_za(insn, invalid)
unsigned insn;
int *invalid;
{
if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31)
*invalid = 1;
@@ -487,13 +502,18 @@ extract_za(unsigned insn, int *invalid)
/*ARGSUSED*/
static unsigned
insert_zb(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
insert_zb(insn, value, errmsg)
unsigned insn;
int value ATTRIBUTE_UNUSED;
const char **errmsg ATTRIBUTE_UNUSED;
{
return insn | (31 << 16);
}
static int
extract_zb(unsigned insn, int *invalid)
extract_zb(insn, invalid)
unsigned insn;
int *invalid;
{
if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31)
*invalid = 1;
@@ -502,13 +522,18 @@ extract_zb(unsigned insn, int *invalid)
/*ARGSUSED*/
static unsigned
insert_zc(unsigned insn, int value ATTRIBUTE_UNUSED, const char **errmsg ATTRIBUTE_UNUSED)
insert_zc(insn, value, errmsg)
unsigned insn;
int value ATTRIBUTE_UNUSED;
const char **errmsg ATTRIBUTE_UNUSED;
{
return insn | 31;
}
static int
extract_zc(unsigned insn, int *invalid)
extract_zc(insn, invalid)
unsigned insn;
int *invalid;
{
if (invalid != (int *) NULL && (insn & 0x1f) != 31)
*invalid = 1;
@@ -519,7 +544,10 @@ extract_zc(unsigned insn, int *invalid)
/* The displacement field of a Branch format insn. */
static unsigned
insert_bdisp(unsigned insn, int value, const char **errmsg)
insert_bdisp(insn, value, errmsg)
unsigned insn;
int value;
const char **errmsg;
{
if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("branch operand unaligned");
@@ -528,7 +556,9 @@ insert_bdisp(unsigned insn, int value, const char **errmsg)
/*ARGSUSED*/
static int
extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
extract_bdisp(insn, invalid)
unsigned insn;
int *invalid ATTRIBUTE_UNUSED;
{
return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000);
}
@@ -537,7 +567,10 @@ extract_bdisp(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
/* The hint field of a JMP/JSR insn. */
static unsigned
insert_jhint(unsigned insn, int value, const char **errmsg)
insert_jhint(insn, value, errmsg)
unsigned insn;
int value;
const char **errmsg;
{
if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("jump hint unaligned");
@@ -546,7 +579,9 @@ insert_jhint(unsigned insn, int value, const char **errmsg)
/*ARGSUSED*/
static int
extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
extract_jhint(insn, invalid)
unsigned insn;
int *invalid ATTRIBUTE_UNUSED;
{
return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000);
}
@@ -554,7 +589,10 @@ extract_jhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
/* The hint field of an EV6 HW_JMP/JSR insn. */
static unsigned
insert_ev6hwjhint(unsigned insn, int value, const char **errmsg)
insert_ev6hwjhint(insn, value, errmsg)
unsigned insn;
int value;
const char **errmsg;
{
if (errmsg != (const char **)NULL && (value & 3))
*errmsg = _("jump hint unaligned");
@@ -563,7 +601,9 @@ insert_ev6hwjhint(unsigned insn, int value, const char **errmsg)
/*ARGSUSED*/
static int
extract_ev6hwjhint(unsigned insn, int *invalid ATTRIBUTE_UNUSED)
extract_ev6hwjhint(insn, invalid)
unsigned insn;
int *invalid ATTRIBUTE_UNUSED;
{
return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000);
}
@@ -1764,7 +1804,9 @@ static const char * const vms_regnames[64] = {
/* Disassemble Alpha instructions. */
int
print_insn_alpha (bfd_vma memaddr, struct disassemble_info *info)
print_insn_alpha (memaddr, info)
bfd_vma memaddr;
struct disassemble_info *info;
{
static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
const char * const * regnames;

View File

@@ -2,6 +2,7 @@ OUTPUT_FORMAT("elf64-alpha", "elf64-alpha",
"elf64-alpha")
OUTPUT_ARCH(alpha)
ENTRY(__start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */

View File

@@ -23,6 +23,8 @@
for things we don't care about. */
#include "dis-asm.h"
#define FALSE 0
#define TRUE (!FALSE)
#define ATTRIBUTE_UNUSED __attribute__((unused))
#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
@@ -1529,7 +1531,7 @@ static unsigned int regname_selected = 1;
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
#define arm_regnames regnames[regname_selected].reg_names
static bfd_boolean force_thumb = false;
static bfd_boolean force_thumb = FALSE;
/* Current IT instruction state. This contains the same state as the IT
bits in the CPSR. */
@@ -1626,7 +1628,7 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream,
}
/* Print one coprocessor instruction on INFO->STREAM.
Return true if the instuction matched, false if this is not a
Return TRUE if the instuction matched, FALSE if this is not a
recognised coprocessor instruction. */
static bfd_boolean
@@ -2119,10 +2121,10 @@ print_insn_coprocessor (bfd_vma pc, struct disassemble_info *info, long given,
else
func (stream, "%c", *c);
}
return true;
return TRUE;
}
}
return false;
return FALSE;
}
static void
@@ -2216,7 +2218,7 @@ print_arm_address (bfd_vma pc, struct disassemble_info *info, long given)
}
/* Print one neon instruction on INFO->STREAM.
Return true if the instuction matched, false if this is not a
Return TRUE if the instuction matched, FALSE if this is not a
recognised neon instruction. */
static bfd_boolean
@@ -2242,7 +2244,7 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
else if ((given & 0xff000000) == 0xf9000000)
given ^= 0xf9000000 ^ 0xf4000000;
else
return false;
return FALSE;
}
for (insn = neon_opcodes; insn->assembler; insn++)
@@ -2332,34 +2334,34 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
{
int amask = (1 << size) - 1;
if ((idx_align & (1 << size)) != 0)
return false;
return FALSE;
if (size > 0)
{
if ((idx_align & amask) == amask)
align = 8 << size;
else if ((idx_align & amask) != 0)
return false;
return FALSE;
}
}
break;
case 2:
if (size == 2 && (idx_align & 2) != 0)
return false;
return FALSE;
align = (idx_align & 1) ? 16 << size : 0;
break;
case 3:
if ((size == 2 && (idx_align & 3) != 0)
|| (idx_align & 1) != 0)
return false;
return FALSE;
break;
case 4:
if (size == 2)
{
if ((idx_align & 3) == 3)
return false;
return FALSE;
align = (idx_align & 3) * 64;
}
else
@@ -2668,10 +2670,10 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
else
func (stream, "%c", *c);
}
return true;
return TRUE;
}
}
return false;
return FALSE;
}
/* Print one ARM instruction from PC on INFO->STREAM. */
@@ -2683,10 +2685,10 @@ print_insn_arm_internal (bfd_vma pc, struct disassemble_info *info, long given)
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
if (print_insn_coprocessor (pc, info, given, false))
if (print_insn_coprocessor (pc, info, given, FALSE))
return;
if (print_insn_neon (info, given, false))
if (print_insn_neon (info, given, FALSE))
return;
for (insn = arm_opcodes; insn->assembler; insn++)
@@ -3319,10 +3321,10 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
if (print_insn_coprocessor (pc, info, given, true))
if (print_insn_coprocessor (pc, info, given, TRUE))
return;
if (print_insn_neon (info, given, true))
if (print_insn_neon (info, given, TRUE))
return;
for (insn = thumb32_opcodes; insn->assembler; insn++)
@@ -3457,7 +3459,7 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
unsigned int op = (given & 0x00000f00) >> 8;
unsigned int i12 = (given & 0x00000fff);
unsigned int i8 = (given & 0x000000ff);
bfd_boolean writeback = false, postind = false;
bfd_boolean writeback = FALSE, postind = FALSE;
int offset = 0;
func (stream, "[%s", arm_regnames[Rn]);
@@ -3487,22 +3489,22 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
case 0xF: /* 8-bit + preindex with wb */
offset = i8;
writeback = true;
writeback = TRUE;
break;
case 0xD: /* 8-bit - preindex with wb */
offset = -i8;
writeback = true;
writeback = TRUE;
break;
case 0xB: /* 8-bit + postindex */
offset = i8;
postind = true;
postind = TRUE;
break;
case 0x9: /* 8-bit - postindex */
offset = -i8;
postind = true;
postind = TRUE;
break;
default:
@@ -3875,12 +3877,12 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
unsigned char b[4];
long given;
int status;
int is_thumb = false;
int is_data = false;
int is_thumb = FALSE;
int is_data = FALSE;
unsigned int size = 4;
void (*printer) (bfd_vma, struct disassemble_info *, long);
#if 0
bfd_boolean found = false;
bfd_boolean found = FALSE;
if (info->disassembler_options)
{
@@ -3903,7 +3905,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
if (pc <= last_mapping_addr)
last_mapping_sym = -1;
is_thumb = (last_type == MAP_THUMB);
found = false;
found = FALSE;
/* Start scanning at the start of the function, or wherever
we finished last time. */
n = info->symtab_pos + 1;
@@ -3921,7 +3923,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
&& get_sym_code_type (info, n, &type))
{
last_sym = n;
found = true;
found = TRUE;
}
}
@@ -3938,7 +3940,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
if (get_sym_code_type (info, n, &type))
{
last_sym = n;
found = true;
found = TRUE;
break;
}
}
@@ -4010,7 +4012,7 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info)
#endif
if (force_thumb)
is_thumb = true;
is_thumb = TRUE;
info->bytes_per_line = 4;

1
arm.ld
View File

@@ -2,6 +2,7 @@ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */

216
async.c
View File

@@ -1,216 +0,0 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu-common.h"
#include "qemu-aio.h"
/*
* An AsyncContext protects the callbacks of AIO requests and Bottom Halves
* against interfering with each other. A typical example is qcow2 that accepts
* asynchronous requests, but relies for manipulation of its metadata on
* synchronous bdrv_read/write that doesn't trigger any callbacks.
*
* However, these functions are often emulated using AIO which means that AIO
* callbacks must be run - but at the same time we must not run callbacks of
* other requests as they might start to modify metadata and corrupt the
* internal state of the caller of bdrv_read/write.
*
* To achieve the desired semantics we switch into a new AsyncContext.
* Callbacks must only be run if they belong to the current AsyncContext.
* Otherwise they need to be queued until their own context is active again.
* This is how you can make qemu_aio_wait() wait only for your own callbacks.
*
* The AsyncContexts form a stack. When you leave a AsyncContexts, you always
* return to the old ("parent") context.
*/
struct AsyncContext {
/* Consecutive number of the AsyncContext (position in the stack) */
int id;
/* Anchor of the list of Bottom Halves belonging to the context */
struct QEMUBH *first_bh;
/* Link to parent context */
struct AsyncContext *parent;
};
/* The currently active AsyncContext */
static struct AsyncContext *async_context = &(struct AsyncContext) { 0 };
/*
* Enter a new AsyncContext. Already scheduled Bottom Halves and AIO callbacks
* won't be called until this context is left again.
*/
void async_context_push(void)
{
struct AsyncContext *new = qemu_mallocz(sizeof(*new));
new->parent = async_context;
new->id = async_context->id + 1;
async_context = new;
}
/* Run queued AIO completions and destroy Bottom Half */
static void bh_run_aio_completions(void *opaque)
{
QEMUBH **bh = opaque;
qemu_bh_delete(*bh);
qemu_free(bh);
qemu_aio_process_queue();
}
/*
* Leave the currently active AsyncContext. All Bottom Halves belonging to the
* old context are executed before changing the context.
*/
void async_context_pop(void)
{
struct AsyncContext *old = async_context;
QEMUBH **bh;
/* Flush the bottom halves, we don't want to lose them */
while (qemu_bh_poll());
/* Switch back to the parent context */
async_context = async_context->parent;
qemu_free(old);
if (async_context == NULL) {
abort();
}
/* Schedule BH to run any queued AIO completions as soon as possible */
bh = qemu_malloc(sizeof(*bh));
*bh = qemu_bh_new(bh_run_aio_completions, bh);
qemu_bh_schedule(*bh);
}
/*
* Returns the ID of the currently active AsyncContext
*/
int get_async_context_id(void)
{
return async_context->id;
}
/***********************************************************/
/* bottom halves (can be seen as timers which expire ASAP) */
struct QEMUBH {
QEMUBHFunc *cb;
void *opaque;
int scheduled;
int idle;
int deleted;
QEMUBH *next;
};
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
{
QEMUBH *bh;
bh = qemu_mallocz(sizeof(QEMUBH));
bh->cb = cb;
bh->opaque = opaque;
bh->next = async_context->first_bh;
async_context->first_bh = bh;
return bh;
}
int qemu_bh_poll(void)
{
QEMUBH *bh, **bhp;
int ret;
ret = 0;
for (bh = async_context->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
if (!bh->idle)
ret = 1;
bh->idle = 0;
bh->cb(bh->opaque);
}
}
/* remove deleted bhs */
bhp = &async_context->first_bh;
while (*bhp) {
bh = *bhp;
if (bh->deleted) {
*bhp = bh->next;
qemu_free(bh);
} else
bhp = &bh->next;
}
return ret;
}
void qemu_bh_schedule_idle(QEMUBH *bh)
{
if (bh->scheduled)
return;
bh->scheduled = 1;
bh->idle = 1;
}
void qemu_bh_schedule(QEMUBH *bh)
{
if (bh->scheduled)
return;
bh->scheduled = 1;
bh->idle = 0;
/* stop the currently executing CPU to execute the BH ASAP */
qemu_notify_event();
}
void qemu_bh_cancel(QEMUBH *bh)
{
bh->scheduled = 0;
}
void qemu_bh_delete(QEMUBH *bh)
{
bh->scheduled = 0;
bh->deleted = 1;
}
void qemu_bh_update_timeout(int *timeout)
{
QEMUBH *bh;
for (bh = async_context->first_bh; bh; bh = bh->next) {
if (!bh->deleted && bh->scheduled) {
if (bh->idle) {
/* idle bottom halves will be polled at least
* every 10ms */
*timeout = MIN(10, *timeout);
} else {
/* non-idle bottom halves will be executed
* immediately */
*timeout = 0;
break;
}
}
}
}

View File

@@ -23,7 +23,6 @@
*/
#include <alsa/asoundlib.h>
#include "qemu-common.h"
#include "qemu-char.h"
#include "audio.h"
#if QEMU_GNUC_PREREQ(4, 3)
@@ -33,27 +32,16 @@
#define AUDIO_CAP "alsa"
#include "audio_int.h"
struct pollhlp {
snd_pcm_t *handle;
struct pollfd *pfds;
int count;
int mask;
};
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
int wpos;
int pending;
void *pcm_buf;
snd_pcm_t *handle;
struct pollhlp pollhlp;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
void *pcm_buf;
struct pollhlp pollhlp;
} ALSAVoiceIn;
static struct {
@@ -74,8 +62,7 @@ static struct {
int period_size_out_overridden;
int verbose;
} conf = {
.buffer_size_out = 4096,
.period_size_out = 1024,
.buffer_size_out = 1024,
.pcm_name_out = "default",
.pcm_name_in = "default",
};
@@ -127,23 +114,7 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
}
static void alsa_fini_poll (struct pollhlp *hlp)
{
int i;
struct pollfd *pfds = hlp->pfds;
if (pfds) {
for (i = 0; i < hlp->count; ++i) {
qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
}
qemu_free (pfds);
}
hlp->pfds = NULL;
hlp->count = 0;
hlp->handle = NULL;
}
static void alsa_anal_close1 (snd_pcm_t **handlep)
static void alsa_anal_close (snd_pcm_t **handlep)
{
int err = snd_pcm_close (*handlep);
if (err) {
@@ -152,163 +123,6 @@ static void alsa_anal_close1 (snd_pcm_t **handlep)
*handlep = NULL;
}
static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
{
alsa_fini_poll (hlp);
alsa_anal_close1 (handlep);
}
static int alsa_recover (snd_pcm_t *handle)
{
int err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Failed to prepare handle %p\n", handle);
return -1;
}
return 0;
}
static int alsa_resume (snd_pcm_t *handle)
{
int err = snd_pcm_resume (handle);
if (err < 0) {
alsa_logerr (err, "Failed to resume handle %p\n", handle);
return -1;
}
return 0;
}
static void alsa_poll_handler (void *opaque)
{
int err, count;
snd_pcm_state_t state;
struct pollhlp *hlp = opaque;
unsigned short revents;
count = poll (hlp->pfds, hlp->count, 0);
if (count < 0) {
dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
return;
}
if (!count) {
return;
}
/* XXX: ALSA example uses initial count, not the one returned by
poll, correct? */
err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
hlp->count, &revents);
if (err < 0) {
alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
return;
}
if (!(revents & hlp->mask)) {
if (conf.verbose) {
dolog ("revents = %d\n", revents);
}
return;
}
state = snd_pcm_state (hlp->handle);
switch (state) {
case SND_PCM_STATE_XRUN:
alsa_recover (hlp->handle);
break;
case SND_PCM_STATE_SUSPENDED:
alsa_resume (hlp->handle);
break;
case SND_PCM_STATE_PREPARED:
audio_run ("alsa run (prepared)");
break;
case SND_PCM_STATE_RUNNING:
audio_run ("alsa run (running)");
break;
default:
dolog ("Unexpected state %d\n", state);
}
}
static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
{
int i, count, err;
struct pollfd *pfds;
count = snd_pcm_poll_descriptors_count (handle);
if (count <= 0) {
dolog ("Could not initialize poll mode\n"
"Invalid number of poll descriptors %d\n", count);
return -1;
}
pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds));
if (!pfds) {
dolog ("Could not initialize poll mode\n");
return -1;
}
err = snd_pcm_poll_descriptors (handle, pfds, count);
if (err < 0) {
alsa_logerr (err, "Could not initialize poll mode\n"
"Could not obtain poll descriptors\n");
qemu_free (pfds);
return -1;
}
for (i = 0; i < count; ++i) {
if (pfds[i].events & POLLIN) {
err = qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler,
NULL, hlp);
}
if (pfds[i].events & POLLOUT) {
if (conf.verbose) {
dolog ("POLLOUT %d %d\n", i, pfds[i].fd);
}
err = qemu_set_fd_handler (pfds[i].fd, NULL,
alsa_poll_handler, hlp);
}
if (conf.verbose) {
dolog ("Set handler events=%#x index=%d fd=%d err=%d\n",
pfds[i].events, i, pfds[i].fd, err);
}
if (err) {
dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
pfds[i].events, i, pfds[i].fd, err);
while (i--) {
qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
}
qemu_free (pfds);
return -1;
}
}
hlp->pfds = pfds;
hlp->count = count;
hlp->handle = handle;
hlp->mask = mask;
return 0;
}
static int alsa_poll_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
}
static int alsa_poll_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
}
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
@@ -595,7 +409,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
if (((req->override_mask & 1) && (obt - req->period_size)))
if ((req->override_mask & 1) && (obt - req->period_size))
dolog ("Requested period %s %u was rejected, using %lu\n",
size_in_usec ? "time" : "size", req->period_size, obt);
}
@@ -675,10 +489,20 @@ static int alsa_open (int in, struct alsa_params_req *req,
return 0;
err:
alsa_anal_close1 (&handle);
alsa_anal_close (&handle);
return -1;
}
static int alsa_recover (snd_pcm_t *handle)
{
int err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Failed to prepare handle %p\n", handle);
return -1;
}
return 0;
}
static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
@@ -701,75 +525,20 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
return avail;
}
static void alsa_write_pending (ALSAVoiceOut *alsa)
{
HWVoiceOut *hw = &alsa->hw;
while (alsa->pending) {
int left_till_end_samples = hw->samples - alsa->wpos;
int len = audio_MIN (alsa->pending, left_till_end_samples);
char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift);
while (len) {
snd_pcm_sframes_t written;
written = snd_pcm_writei (alsa->handle, src, len);
if (written <= 0) {
switch (written) {
case 0:
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
return;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
return;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
continue;
case -ESTRPIPE:
/* stream is suspended and waiting for an
application recovery */
if (alsa_resume (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
return;
}
if (conf.verbose) {
dolog ("Resuming suspended output stream\n");
}
continue;
case -EAGAIN:
return;
default:
alsa_logerr (written, "Failed to write %d frames from %p\n",
len, src);
return;
}
}
alsa->wpos = (alsa->wpos + written) % hw->samples;
alsa->pending -= written;
len -= written;
}
}
}
static int alsa_run_out (HWVoiceOut *hw, int live)
static int alsa_run_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
int decr;
int rpos, live, decr;
int samples;
uint8_t *dst;
struct st_sample *src;
snd_pcm_sframes_t avail;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
avail = alsa_get_avail (alsa->handle);
if (avail < 0) {
dolog ("Could not get number of available playback frames\n");
@@ -777,9 +546,60 @@ static int alsa_run_out (HWVoiceOut *hw, int live)
}
decr = audio_MIN (live, avail);
decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending);
alsa->pending += decr;
alsa_write_pending (alsa);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int len = audio_MIN (samples, left_till_end_samples);
snd_pcm_sframes_t written;
src = hw->mix_buf + rpos;
dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
hw->clip (dst, src, len);
while (len) {
written = snd_pcm_writei (alsa->handle, dst, len);
if (written <= 0) {
switch (written) {
case 0:
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
goto exit;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
goto exit;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
continue;
case -EAGAIN:
goto exit;
default:
alsa_logerr (written, "Failed to write %d frames to %p\n",
len, dst);
goto exit;
}
}
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
dst = advance (dst, written << hw->info.shift);
src += written;
}
}
exit:
hw->rpos = rpos;
return decr;
}
@@ -788,7 +608,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
ldebug ("alsa_fini\n");
alsa_anal_close (&alsa->handle, &alsa->pollhlp);
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -830,7 +650,7 @@ static int alsa_init_out (HWVoiceOut *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close1 (&handle);
alsa_anal_close (&handle);
return -1;
}
@@ -866,21 +686,8 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_out (hw)) {
poll_mode = 0;
}
hw->poll_mode = poll_mode;
return alsa_voice_ctl (alsa->handle, "playback", 0);
}
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "playback", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
@@ -924,7 +731,7 @@ static int alsa_init_in (HWVoiceIn *hw, struct audsettings *as)
if (!alsa->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close1 (&handle);
alsa_anal_close (&handle);
return -1;
}
@@ -936,7 +743,7 @@ static void alsa_fini_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
alsa_anal_close (&alsa->handle, &alsa->pollhlp);
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
@@ -956,8 +763,8 @@ static int alsa_run_in (HWVoiceIn *hw)
int add;
int len;
} bufs[2] = {
{ .add = hw->wpos, .len = 0 },
{ .add = 0, .len = 0 }
{ hw->wpos, 0 },
{ 0, 0 }
};
snd_pcm_sframes_t avail;
snd_pcm_uframes_t read_samples = 0;
@@ -972,30 +779,8 @@ static int alsa_run_in (HWVoiceIn *hw)
return 0;
}
if (!avail) {
snd_pcm_state_t state;
state = snd_pcm_state (alsa->handle);
switch (state) {
case SND_PCM_STATE_PREPARED:
avail = hw->samples;
break;
case SND_PCM_STATE_SUSPENDED:
/* stream is suspended and waiting for an application recovery */
if (alsa_resume (alsa->handle)) {
dolog ("Failed to resume suspended input stream\n");
return 0;
}
if (conf.verbose) {
dolog ("Resuming suspended input stream\n");
}
break;
default:
if (conf.verbose) {
dolog ("No frames available and ALSA state is %d\n", state);
}
return 0;
}
if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
avail = hw->samples;
}
decr = audio_MIN (dead, avail);
@@ -1083,29 +868,11 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n");
if (poll_mode && alsa_poll_in (hw)) {
poll_mode = 0;
}
hw->poll_mode = poll_mode;
return alsa_voice_ctl (alsa->handle, "capture", 0);
}
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "capture", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
if (hw->poll_mode) {
hw->poll_mode = 0;
alsa_fini_poll (&alsa->pollhlp);
}
return alsa_voice_ctl (alsa->handle, "capture", 1);
}
@@ -1123,98 +890,63 @@ static void alsa_audio_fini (void *opaque)
}
static struct audio_option alsa_options[] = {
{
.name = "DAC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &conf.size_in_usec_out,
.descr = "DAC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "DAC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.period_size_out,
.descr = "DAC period size (0 to go with system default)",
.overriddenp = &conf.period_size_out_overridden
},
{
.name = "DAC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_size_out,
.descr = "DAC buffer size (0 to go with system default)",
.overriddenp = &conf.buffer_size_out_overridden
},
{
.name = "ADC_SIZE_IN_USEC",
.tag = AUD_OPT_BOOL,
.valp = &conf.size_in_usec_in,
.descr =
"ADC period/buffer size in microseconds (otherwise in frames)"
},
{
.name = "ADC_PERIOD_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.period_size_in,
.descr = "ADC period size (0 to go with system default)",
.overriddenp = &conf.period_size_in_overridden
},
{
.name = "ADC_BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_size_in,
.descr = "ADC buffer size (0 to go with system default)",
.overriddenp = &conf.buffer_size_in_overridden
},
{
.name = "THRESHOLD",
.tag = AUD_OPT_INT,
.valp = &conf.threshold,
.descr = "(undocumented)"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.pcm_name_out,
.descr = "DAC device name (for instance dmix)"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.pcm_name_in,
.descr = "ADC device name"
},
{
.name = "VERBOSE",
.tag = AUD_OPT_BOOL,
.valp = &conf.verbose,
.descr = "Behave in a more verbose way"
},
{ /* End of list */ }
{"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
"DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
{"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
"DAC period size (0 to go with system default)",
&conf.period_size_out_overridden, 0},
{"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
"DAC buffer size (0 to go with system default)",
&conf.buffer_size_out_overridden, 0},
{"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
"ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
{"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
"ADC period size (0 to go with system default)",
&conf.period_size_in_overridden, 0},
{"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
"ADC buffer size (0 to go with system default)",
&conf.buffer_size_in_overridden, 0},
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
"(undocumented)", NULL, 0},
{"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
"DAC device name (for instance dmix)", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
"ADC device name", NULL, 0},
{"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
"Behave in a more verbose way", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
.run_out = alsa_run_out,
.write = alsa_write,
.ctl_out = alsa_ctl_out,
alsa_init_out,
alsa_fini_out,
alsa_run_out,
alsa_write,
alsa_ctl_out,
.init_in = alsa_init_in,
.fini_in = alsa_fini_in,
.run_in = alsa_run_in,
.read = alsa_read,
.ctl_in = alsa_ctl_in,
alsa_init_in,
alsa_fini_in,
alsa_run_in,
alsa_read,
alsa_ctl_in
};
struct audio_driver alsa_audio_driver = {
.name = "alsa",
.descr = "ALSA http://www.alsa-project.org",
.options = alsa_options,
.init = alsa_audio_init,
.fini = alsa_audio_fini,
.pcm_ops = &alsa_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (ALSAVoiceOut),
.voice_size_in = sizeof (ALSAVoiceIn)
INIT_FIELD (name = ) "alsa",
INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org",
INIT_FIELD (options = ) alsa_options,
INIT_FIELD (init = ) alsa_audio_init,
INIT_FIELD (fini = ) alsa_audio_fini,
INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
};

View File

@@ -34,17 +34,11 @@
/* #define DEBUG_LIVE */
/* #define DEBUG_OUT */
/* #define DEBUG_CAPTURE */
/* #define DEBUG_POLL */
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
/* Order of CONFIG_AUDIO_DRIVERS is import.
The 1st one is the one used by default, that is the reason
that we generate the list.
*/
static struct audio_driver *drvtab[] = {
CONFIG_AUDIO_DRIVERS
AUDIO_DRIVERS
&no_audio_driver,
&wav_audio_driver
};
@@ -65,53 +59,66 @@ static struct {
} period;
int plive;
int log_to_monitor;
int try_poll_in;
int try_poll_out;
} conf = {
.fixed_out = { /* DAC fixed settings */
.enabled = 1,
.nb_voices = 1,
.greedy = 1,
.settings = {
.freq = 44100,
.nchannels = 2,
.fmt = AUD_FMT_S16,
.endianness = AUDIO_HOST_ENDIANNESS,
{ /* DAC fixed settings */
1, /* enabled */
1, /* nb_voices */
1, /* greedy */
{
44100, /* freq */
2, /* nchannels */
AUD_FMT_S16, /* fmt */
AUDIO_HOST_ENDIANNESS
}
},
.fixed_in = { /* ADC fixed settings */
.enabled = 1,
.nb_voices = 1,
.greedy = 1,
.settings = {
.freq = 44100,
.nchannels = 2,
.fmt = AUD_FMT_S16,
.endianness = AUDIO_HOST_ENDIANNESS,
{ /* ADC fixed settings */
1, /* enabled */
1, /* nb_voices */
1, /* greedy */
{
44100, /* freq */
2, /* nchannels */
AUD_FMT_S16, /* fmt */
AUDIO_HOST_ENDIANNESS
}
},
.period = { .hertz = 250 },
.plive = 0,
.log_to_monitor = 0,
.try_poll_in = 1,
.try_poll_out = 1,
{ 250 }, /* period */
0, /* plive */
0 /* log_to_monitor */
};
static AudioState glob_audio_state;
struct mixeng_volume nominal_volume = {
.mute = 0,
0,
#ifdef FLOAT_MIXENG
.r = 1.0,
.l = 1.0,
1.0,
1.0
#else
.r = 1ULL << 32,
.l = 1ULL << 32,
1ULL << 32,
1ULL << 32
#endif
};
/* http://www.df.lth.se/~john_e/gems/gem002d.html */
/* http://www.multi-platforms.com/Tips/PopCount.htm */
uint32_t popcount (uint32_t u)
{
u = ((u&0x55555555) + ((u>>1)&0x55555555));
u = ((u&0x33333333) + ((u>>2)&0x33333333));
u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
u = ( u&0x0000ffff) + (u>>16);
return u;
}
inline uint32_t lsbindex (uint32_t u)
{
return popcount ((u&-u)-1);
}
#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
#error No its not
#else
@@ -124,7 +131,7 @@ int audio_bug (const char *funcname, int cond)
if (!shown) {
shown = 1;
AUD_log (NULL, "Save all your work and restart without audio\n");
AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n");
AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n");
AUD_log (NULL, "I am sorry\n");
}
AUD_log (NULL, "Context:\n");
@@ -766,8 +773,8 @@ static void audio_detach_capture (HWVoiceOut *hw)
sw->rate = NULL;
}
QLIST_REMOVE (sw, entries);
QLIST_REMOVE (sc, entries);
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
if (was_active) {
/* We have removed soft voice from the capture:
@@ -811,8 +818,8 @@ static int audio_attach_capture (HWVoiceOut *hw)
qemu_free (sw);
return -1;
}
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
QLIST_INSERT_HEAD (&hw->cap_head, sc, entries);
LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
#ifdef DEBUG_CAPTURE
asprintf (&sw->name, "for %p %d,%d,%d",
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
@@ -851,28 +858,6 @@ int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
return live;
}
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending)
{
int left = hw->samples - pending;
int len = audio_MIN (left, live);
int clipped = 0;
while (len) {
struct st_sample *src = hw->mix_buf + hw->rpos;
uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift);
int samples_till_end_of_buf = hw->samples - hw->rpos;
int samples_to_clip = audio_MIN (len, samples_till_end_of_buf);
hw->clip (dst, src, samples_to_clip);
hw->rpos = (hw->rpos + samples_to_clip) % hw->samples;
len -= samples_to_clip;
clipped += samples_to_clip;
}
return clipped;
}
/*
* Soft voice (capture)
*/
@@ -969,17 +954,16 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
return m;
}
static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
{
int smin;
int nb_live1;
smin = audio_pcm_hw_find_min_out (hw, &nb_live1);
if (nb_live) {
*nb_live = nb_live1;
smin = audio_pcm_hw_find_min_out (hw, nb_live);
if (!*nb_live) {
return 0;
}
if (nb_live1) {
else {
int live = smin;
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
@@ -988,7 +972,19 @@ static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
}
return live;
}
return 0;
}
int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
{
int nb_live;
int live;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
return 0;
}
return live;
}
/*
@@ -1081,47 +1077,6 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
#undef DAC
#include "audio_template.h"
/*
* Timer
*/
static void audio_timer (void *opaque)
{
AudioState *s = opaque;
audio_run ("timer");
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
static int audio_is_timer_needed (void)
{
HWVoiceIn *hwi = NULL;
HWVoiceOut *hwo = NULL;
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
if (!hwo->poll_mode) return 1;
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
if (!hwi->poll_mode) return 1;
}
return 0;
}
static void audio_reset_timer (void)
{
AudioState *s = &glob_audio_state;
if (audio_is_timer_needed ()) {
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}
else {
qemu_del_timer (s->ts);
}
}
/*
* Public API
*/
int AUD_write (SWVoiceOut *sw, void *buf, int size)
{
int bytes;
@@ -1182,8 +1137,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out);
audio_reset_timer ();
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
}
}
}
@@ -1227,7 +1181,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (!hw->enabled) {
hw->enabled = 1;
if (s->vm_running) {
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in);
hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
}
}
sw->total_hw_samples_acquired = hw->total_samples_captured;
@@ -1346,7 +1300,7 @@ static void audio_run_out (AudioState *s)
int played;
int live, free, nb_live, cleanup_required, prev_rpos;
live = audio_pcm_hw_get_live_out (hw, &nb_live);
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!nb_live) {
live = 0;
}
@@ -1384,7 +1338,7 @@ static void audio_run_out (AudioState *s)
}
prev_rpos = hw->rpos;
played = hw->pcm_ops->run_out (hw, live);
played = hw->pcm_ops->run_out (hw);
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
hw->rpos, hw->samples, played);
@@ -1483,7 +1437,7 @@ static void audio_run_capture (AudioState *s)
HWVoiceOut *hw = &cap->hw;
SWVoiceOut *sw;
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
captured = live = audio_pcm_hw_get_live_out (hw);
rpos = hw->rpos;
while (live) {
int left = hw->samples - rpos;
@@ -1521,126 +1475,61 @@ static void audio_run_capture (AudioState *s)
}
}
void audio_run (const char *msg)
static void audio_timer (void *opaque)
{
AudioState *s = &glob_audio_state;
AudioState *s = opaque;
audio_run_out (s);
audio_run_in (s);
audio_run_capture (s);
#ifdef DEBUG_POLL
{
static double prevtime;
double currtime;
struct timeval tv;
if (gettimeofday (&tv, NULL)) {
perror ("audio_run: gettimeofday");
return;
}
currtime = tv.tv_sec + tv.tv_usec * 1e-6;
dolog ("Elapsed since last %s: %f\n", msg, currtime - prevtime);
prevtime = currtime;
}
#endif
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
static struct audio_option audio_options[] = {
/* DAC */
{
.name = "DAC_FIXED_SETTINGS",
.tag = AUD_OPT_BOOL,
.valp = &conf.fixed_out.enabled,
.descr = "Use fixed settings for host DAC"
},
{
.name = "DAC_FIXED_FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_out.settings.freq,
.descr = "Frequency for fixed host DAC"
},
{
.name = "DAC_FIXED_FMT",
.tag = AUD_OPT_FMT,
.valp = &conf.fixed_out.settings.fmt,
.descr = "Format for fixed host DAC"
},
{
.name = "DAC_FIXED_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_out.settings.nchannels,
.descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)"
},
{
.name = "DAC_VOICES",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_out.nb_voices,
.descr = "Number of voices for DAC"
},
{
.name = "DAC_TRY_POLL",
.tag = AUD_OPT_BOOL,
.valp = &conf.try_poll_out,
.descr = "Attempt using poll mode for DAC"
},
{"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
"Use fixed settings for host DAC", NULL, 0},
{"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
"Frequency for fixed host DAC", NULL, 0},
{"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
"Format for fixed host DAC", NULL, 0},
{"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
"Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
{"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
"Number of voices for DAC", NULL, 0},
/* ADC */
{
.name = "ADC_FIXED_SETTINGS",
.tag = AUD_OPT_BOOL,
.valp = &conf.fixed_in.enabled,
.descr = "Use fixed settings for host ADC"
},
{
.name = "ADC_FIXED_FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_in.settings.freq,
.descr = "Frequency for fixed host ADC"
},
{
.name = "ADC_FIXED_FMT",
.tag = AUD_OPT_FMT,
.valp = &conf.fixed_in.settings.fmt,
.descr = "Format for fixed host ADC"
},
{
.name = "ADC_FIXED_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_in.settings.nchannels,
.descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)"
},
{
.name = "ADC_VOICES",
.tag = AUD_OPT_INT,
.valp = &conf.fixed_in.nb_voices,
.descr = "Number of voices for ADC"
},
{
.name = "ADC_TRY_POLL",
.tag = AUD_OPT_BOOL,
.valp = &conf.try_poll_in,
.descr = "Attempt using poll mode for ADC"
},
{"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
"Use fixed settings for host ADC", NULL, 0},
{"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
"Frequency for fixed host ADC", NULL, 0},
{"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
"Format for fixed host ADC", NULL, 0},
{"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
"Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
{"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
"Number of voices for ADC", NULL, 0},
/* Misc */
{
.name = "TIMER_PERIOD",
.tag = AUD_OPT_INT,
.valp = &conf.period.hertz,
.descr = "Timer period in HZ (0 - use lowest possible)"
},
{
.name = "PLIVE",
.tag = AUD_OPT_BOOL,
.valp = &conf.plive,
.descr = "(undocumented)"
},
{
.name = "LOG_TO_MONITOR",
.tag = AUD_OPT_BOOL,
.valp = &conf.log_to_monitor,
.descr = "Print logging messages to monitor instead of stderr"
},
{ /* End of list */ }
{"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hertz,
"Timer period in HZ (0 - use lowest possible)", NULL, 0},
{"PLIVE", AUD_OPT_BOOL, &conf.plive,
"(undocumented)", NULL, 0},
{"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
"print logging messages to monitor instead of stderr", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static void audio_pp_nb_voices (const char *typ, int nb)
@@ -1743,13 +1632,12 @@ static void audio_vm_change_state_handler (void *opaque, int running,
s->vm_running = running;
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out);
hwo->pcm_ops->ctl_out (hwo, op);
}
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in);
hwi->pcm_ops->ctl_in (hwi, op);
}
audio_reset_timer ();
}
static void audio_atexit (void)
@@ -1784,31 +1672,38 @@ static void audio_atexit (void)
}
}
static const VMStateDescription vmstate_audio = {
.name = "audio",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
VMSTATE_END_OF_LIST()
static void audio_save (QEMUFile *f, void *opaque)
{
(void) f;
(void) opaque;
}
static int audio_load (QEMUFile *f, void *opaque, int version_id)
{
(void) f;
(void) opaque;
if (version_id != 1) {
return -EINVAL;
}
};
return 0;
}
static void audio_init (void)
{
size_t i;
int done = 0;
const char *drvname;
VMChangeStateEntry *e;
AudioState *s = &glob_audio_state;
if (s->drv) {
return;
}
QLIST_INIT (&s->hw_head_out);
QLIST_INIT (&s->hw_head_in);
QLIST_INIT (&s->cap_head);
LIST_INIT (&s->hw_head_out);
LIST_INIT (&s->hw_head_in);
LIST_INIT (&s->cap_head);
atexit (audio_atexit);
s->ts = qemu_new_timer (vm_clock, audio_timer, s);
@@ -1873,6 +1768,8 @@ static void audio_init (void)
}
}
VMChangeStateEntry *e;
if (conf.period.hertz <= 0) {
if (conf.period.hertz < 0) {
dolog ("warning: Timer period is negative - %d "
@@ -1881,8 +1778,7 @@ static void audio_init (void)
}
conf.period.ticks = 1;
} else {
conf.period.ticks =
muldiv64 (1, get_ticks_per_sec (), conf.period.hertz);
conf.period.ticks = ticks_per_sec / conf.period.hertz;
}
e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
@@ -1891,8 +1787,9 @@ static void audio_init (void)
"(Audio can continue looping even after stopping the VM)\n");
}
QLIST_INIT (&s->card_head);
vmstate_register (0, &vmstate_audio, s);
LIST_INIT (&s->card_head);
register_savevm ("audio", 0, 1, audio_save, audio_load, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
}
void AUD_register_card (const char *name, QEMUSoundCard *card)
@@ -1900,12 +1797,12 @@ void AUD_register_card (const char *name, QEMUSoundCard *card)
audio_init ();
card->name = qemu_strdup (name);
memset (&card->entries, 0, sizeof (card->entries));
QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
LIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries);
}
void AUD_remove_card (QEMUSoundCard *card)
{
QLIST_REMOVE (card, entries);
LIST_REMOVE (card, entries);
qemu_free (card->name);
}
@@ -1937,7 +1834,7 @@ CaptureVoiceOut *AUD_add_capture (
cap = audio_pcm_capture_find_specific (as);
if (cap) {
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
return cap;
}
else {
@@ -1952,8 +1849,8 @@ CaptureVoiceOut *AUD_add_capture (
}
hw = &cap->hw;
QLIST_INIT (&hw->sw_head);
QLIST_INIT (&cap->cb_head);
LIST_INIT (&hw->sw_head);
LIST_INIT (&cap->cb_head);
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
@@ -1981,8 +1878,8 @@ CaptureVoiceOut *AUD_add_capture (
[hw->info.swap_endianness]
[audio_bits_to_index (hw->info.bits)];
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
hw = NULL;
while ((hw = audio_pcm_hw_find_any_out (hw))) {
@@ -2008,7 +1905,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
if (cb->opaque == cb_opaque) {
cb->ops.destroy (cb_opaque);
QLIST_REMOVE (cb, entries);
LIST_REMOVE (cb, entries);
qemu_free (cb);
if (!cap->cb_head.lh_first) {
@@ -2025,12 +1922,12 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
st_rate_stop (sw->rate);
sw->rate = NULL;
}
QLIST_REMOVE (sw, entries);
QLIST_REMOVE (sc, entries);
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
sw = sw1;
}
QLIST_REMOVE (cap, entries);
LIST_REMOVE (cap, entries);
qemu_free (cap);
}
return;

View File

@@ -25,9 +25,9 @@
#define QEMU_AUDIO_H
#include "config-host.h"
#include "qemu-queue.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn) (void *opaque, int avail);
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
typedef enum {
AUD_FMT_U8,
@@ -38,7 +38,7 @@ typedef enum {
AUD_FMT_S32
} audfmt_e;
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
@@ -70,7 +70,7 @@ struct capture_ops {
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
QLIST_ENTRY (CaptureState) entries;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct SWVoiceOut SWVoiceOut;
@@ -79,7 +79,7 @@ typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
char *name;
QLIST_ENTRY (QEMUSoundCard) entries;
LIST_ENTRY (QEMUSoundCard) entries;
} QEMUSoundCard;
typedef struct QEMUAudioTimeStamp {
@@ -108,7 +108,7 @@ SWVoiceOut *AUD_open_out (
SWVoiceOut *sw,
const char *name,
void *callback_opaque,
audio_callback_fn callback_fn,
audio_callback_fn_t callback_fn,
struct audsettings *settings
);
@@ -129,7 +129,7 @@ SWVoiceIn *AUD_open_in (
SWVoiceIn *sw,
const char *name,
void *callback_opaque,
audio_callback_fn callback_fn,
audio_callback_fn_t callback_fn,
struct audsettings *settings
);
@@ -147,6 +147,9 @@ static inline void *advance (void *p, int incr)
return (d + incr);
}
uint32_t popcount (uint32_t u);
uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
__typeof (a) ta = a; \

View File

@@ -50,7 +50,7 @@ struct audio_option {
struct audio_callback {
void *opaque;
audio_callback_fn fn;
audio_callback_fn_t fn;
};
struct audio_pcm_info {
@@ -68,7 +68,6 @@ typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
int enabled;
int poll_mode;
int pending_disable;
struct audio_pcm_info info;
@@ -80,15 +79,14 @@ typedef struct HWVoiceOut {
struct st_sample *mix_buf;
int samples;
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceOut) entries;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
typedef struct HWVoiceIn {
int enabled;
int poll_mode;
struct audio_pcm_info info;
t_sample *conv;
@@ -100,9 +98,9 @@ typedef struct HWVoiceIn {
struct st_sample *conv_buf;
int samples;
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
struct audio_pcm_ops *pcm_ops;
QLIST_ENTRY (HWVoiceIn) entries;
LIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
struct SWVoiceOut {
@@ -119,7 +117,7 @@ struct SWVoiceOut {
char *name;
struct mixeng_volume vol;
struct audio_callback callback;
QLIST_ENTRY (SWVoiceOut) entries;
LIST_ENTRY (SWVoiceOut) entries;
};
struct SWVoiceIn {
@@ -135,7 +133,7 @@ struct SWVoiceIn {
char *name;
struct mixeng_volume vol;
struct audio_callback callback;
QLIST_ENTRY (SWVoiceIn) entries;
LIST_ENTRY (SWVoiceIn) entries;
};
struct audio_driver {
@@ -155,7 +153,7 @@ struct audio_driver {
struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, struct audsettings *as);
void (*fini_out)(HWVoiceOut *hw);
int (*run_out) (HWVoiceOut *hw, int live);
int (*run_out) (HWVoiceOut *hw);
int (*write) (SWVoiceOut *sw, void *buf, int size);
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
@@ -169,20 +167,20 @@ struct audio_pcm_ops {
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
QLIST_ENTRY (capture_callback) entries;
LIST_ENTRY (capture_callback) entries;
};
struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
QLIST_HEAD (cb_listhead, capture_callback) cb_head;
QLIST_ENTRY (CaptureVoiceOut) entries;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
QLIST_ENTRY (SWVoiceCap) entries;
LIST_ENTRY (SWVoiceCap) entries;
};
struct AudioState {
@@ -190,10 +188,10 @@ struct AudioState {
void *drv_opaque;
QEMUTimer *ts;
QLIST_HEAD (card_listhead, QEMUSoundCard) card_head;
QLIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
QLIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
QLIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
int nb_hw_voices_out;
int nb_hw_voices_in;
int vm_running;
@@ -209,7 +207,6 @@ extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern struct audio_driver esd_audio_driver;
extern struct audio_driver pa_audio_driver;
extern struct audio_driver winwave_audio_driver;
extern struct mixeng_volume nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
@@ -219,15 +216,12 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
int audio_pcm_hw_get_live_in (HWVoiceIn *hw);
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf,
int live, int pending);
int audio_pcm_hw_get_live_out (HWVoiceOut *hw);
int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live);
int audio_bug (const char *funcname, int cond);
void *audio_calloc (const char *funcname, int nmemb, size_t size);
void audio_run (const char *msg);
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
@@ -238,9 +232,11 @@ static inline int audio_ring_dist (int dst, int src, int len)
#if defined __GNUC__
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
#define INIT_FIELD(f) . f
#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m)))
#else
#define GCC_ATTR /**/
#define INIT_FIELD(f) /**/
#define GCC_FMT_ATTR(n, m)
#endif

View File

@@ -184,12 +184,12 @@ static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
{
QLIST_INSERT_HEAD (&hw->sw_head, sw, entries);
LIST_INSERT_HEAD (&hw->sw_head, sw, entries);
}
static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
{
QLIST_REMOVE (sw, entries);
LIST_REMOVE (sw, entries);
}
static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
@@ -201,7 +201,7 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
#ifdef DAC
audio_detach_capture (hw);
#endif
QLIST_REMOVE (hw, entries);
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
glue (hw->pcm_ops->fini_, TYPE) (hw);
@@ -267,9 +267,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
}
hw->pcm_ops = drv->pcm_ops;
QLIST_INIT (&hw->sw_head);
LIST_INIT (&hw->sw_head);
#ifdef DAC
QLIST_INIT (&hw->cap_head);
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
@@ -294,7 +294,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)
goto err1;
}
QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
#ifdef DAC
audio_attach_capture (hw);
@@ -402,7 +402,7 @@ SW *glue (AUD_open_, TYPE) (
SW *sw,
const char *name,
void *callback_opaque ,
audio_callback_fn callback_fn,
audio_callback_fn_t callback_fn,
struct audsettings *as
)
{
@@ -445,9 +445,9 @@ SW *glue (AUD_open_, TYPE) (
SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("New %s freq %d, bits %d, channels %d\n",
name,
as->freq,
(as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8,
as->nchannels);
freq,
(fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
nchannels);
#endif
if (live) {
@@ -485,30 +485,32 @@ SW *glue (AUD_open_, TYPE) (
}
}
sw->card = card;
sw->vol = nominal_volume;
sw->callback.fn = callback_fn;
sw->callback.opaque = callback_opaque;
if (sw) {
sw->card = card;
sw->vol = nominal_volume;
sw->callback.fn = callback_fn;
sw->callback.opaque = callback_opaque;
#ifdef DAC
if (live) {
int mixed =
(live << old_sw->info.shift)
* old_sw->info.bytes_per_second
/ sw->info.bytes_per_second;
if (live) {
int mixed =
(live << old_sw->info.shift)
* old_sw->info.bytes_per_second
/ sw->info.bytes_per_second;
#ifdef DEBUG_PLIVE
dolog ("Silence will be mixed %d\n", mixed);
dolog ("Silence will be mixed %d\n", mixed);
#endif
sw->total_hw_samples_mixed += mixed;
}
sw->total_hw_samples_mixed += mixed;
}
#endif
#ifdef DEBUG_AUDIO
dolog ("%s\n", name);
audio_pcm_print_info ("hw", &sw->hw->info);
audio_pcm_print_info ("sw", &sw->info);
dolog ("%s\n", name);
audio_pcm_print_info ("hw", &sw->hw->info);
audio_pcm_print_info ("sw", &sw->info);
#endif
}
return sw;
@@ -554,7 +556,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
return 0;
}
return muldiv64 (delta, sw->hw->info.freq, 1000000);
return (delta * sw->hw->info.freq) / 1000000;
}
#undef TYPE

View File

@@ -1,108 +0,0 @@
/* public domain */
#include "qemu-common.h"
#include "audio.h"
#define AUDIO_CAP "win-int"
#include <windows.h>
#include <mmsystem.h>
#include "audio.h"
#include "audio_int.h"
#include "audio_win_int.h"
int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as)
{
memset (wfx, 0, sizeof (*wfx));
wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->nChannels = as->nchannels;
wfx->nSamplesPerSec = as->freq;
wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
wfx->nBlockAlign = 1 << (as->nchannels == 2);
wfx->cbSize = 0;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
wfx->wBitsPerSample = 8;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
wfx->wBitsPerSample = 16;
wfx->nAvgBytesPerSec <<= 1;
wfx->nBlockAlign <<= 1;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
wfx->wBitsPerSample = 32;
wfx->nAvgBytesPerSec <<= 2;
wfx->nBlockAlign <<= 2;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", as->freq);
return -1;
}
return 0;
}
int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as)
{
if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
dolog ("Invalid wave format, tag is not PCM, but %d\n",
wfx->wFormatTag);
return -1;
}
if (!wfx->nSamplesPerSec) {
dolog ("Invalid wave format, frequency is zero\n");
return -1;
}
as->freq = wfx->nSamplesPerSec;
switch (wfx->nChannels) {
case 1:
as->nchannels = 1;
break;
case 2:
as->nchannels = 2;
break;
default:
dolog (
"Invalid wave format, number of channels is not 1 or 2, but %d\n",
wfx->nChannels
);
return -1;
}
switch (wfx->wBitsPerSample) {
case 8:
as->fmt = AUD_FMT_U8;
break;
case 16:
as->fmt = AUD_FMT_S16;
break;
case 32:
as->fmt = AUD_FMT_S32;
break;
default:
dolog ("Invalid wave format, bits per sample is not "
"8, 16 or 32, but %d\n",
wfx->wBitsPerSample);
return -1;
}
return 0;
}

View File

@@ -1,10 +0,0 @@
#ifndef AUDIO_WIN_INT_H
#define AUDIO_WIN_INT_H
int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as);
int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as);
#endif /* AUDIO_WIN_INT_H */

View File

@@ -190,15 +190,17 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
return 0;
}
static int coreaudio_run_out (HWVoiceOut *hw, int live)
static int coreaudio_run_out (HWVoiceOut *hw)
{
int decr;
int live, decr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (coreaudio_lock (core, "coreaudio_run_out")) {
return 0;
}
live = audio_pcm_hw_get_live_out (hw);
if (core->decr > live) {
ldebug ("core->decr %d live %d core->live %d\n",
core->decr,
@@ -511,39 +513,38 @@ static void coreaudio_audio_fini (void *opaque)
}
static struct audio_option coreaudio_options[] = {
{
.name = "BUFFER_SIZE",
.tag = AUD_OPT_INT,
.valp = &conf.buffer_frames,
.descr = "Size of the buffer in frames"
},
{
.name = "BUFFER_COUNT",
.tag = AUD_OPT_INT,
.valp = &conf.nbuffers,
.descr = "Number of buffers"
},
{ /* End of list */ }
{"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
"Size of the buffer in frames", NULL, 0},
{"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
"Number of buffers", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out,
.run_out = coreaudio_run_out,
.write = coreaudio_write,
.ctl_out = coreaudio_ctl_out
coreaudio_init_out,
coreaudio_fini_out,
coreaudio_run_out,
coreaudio_write,
coreaudio_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver coreaudio_audio_driver = {
.name = "coreaudio",
.descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
.options = coreaudio_options,
.init = coreaudio_audio_init,
.fini = coreaudio_audio_fini,
.pcm_ops = &coreaudio_pcm_ops,
.can_be_default = 1,
.max_voices_out = 1,
.max_voices_in = 0,
.voice_size_out = sizeof (coreaudioVoiceOut),
.voice_size_in = 0
INIT_FIELD (name = ) "coreaudio",
INIT_FIELD (descr = )
"CoreAudio http://developer.apple.com/audio/coreaudio.html",
INIT_FIELD (options = ) coreaudio_options,
INIT_FIELD (init = ) coreaudio_audio_init,
INIT_FIELD (fini = ) coreaudio_audio_fini,
INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
INIT_FIELD (voice_size_in = ) 0
};

View File

@@ -37,8 +37,6 @@
#include <objbase.h>
#include <dsound.h>
#include "audio_win_int.h"
/* #define DEBUG_DSOUND */
static struct {
@@ -51,16 +49,18 @@ static struct {
struct audsettings settings;
int latency_millis;
} conf = {
.lock_retries = 1,
.restore_retries = 1,
.getstatus_retries = 1,
.set_primary = 0,
.bufsize_in = 16384,
.bufsize_out = 16384,
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.latency_millis = 10
1,
1,
1,
0,
16384,
16384,
{
44100,
2,
AUD_FMT_S16
},
10
};
typedef struct {
@@ -306,6 +306,101 @@ static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
return -1;
}
static int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as)
{
memset (wfx, 0, sizeof (*wfx));
wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->nChannels = as->nchannels;
wfx->nSamplesPerSec = as->freq;
wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
wfx->nBlockAlign = 1 << (as->nchannels == 2);
wfx->cbSize = 0;
switch (as->fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
wfx->wBitsPerSample = 8;
break;
case AUD_FMT_S16:
case AUD_FMT_U16:
wfx->wBitsPerSample = 16;
wfx->nAvgBytesPerSec <<= 1;
wfx->nBlockAlign <<= 1;
break;
case AUD_FMT_S32:
case AUD_FMT_U32:
wfx->wBitsPerSample = 32;
wfx->nAvgBytesPerSec <<= 2;
wfx->nBlockAlign <<= 2;
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", as->freq);
return -1;
}
return 0;
}
static int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as)
{
if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
dolog ("Invalid wave format, tag is not PCM, but %d\n",
wfx->wFormatTag);
return -1;
}
if (!wfx->nSamplesPerSec) {
dolog ("Invalid wave format, frequency is zero\n");
return -1;
}
as->freq = wfx->nSamplesPerSec;
switch (wfx->nChannels) {
case 1:
as->nchannels = 1;
break;
case 2:
as->nchannels = 2;
break;
default:
dolog (
"Invalid wave format, number of channels is not 1 or 2, but %d\n",
wfx->nChannels
);
return -1;
}
switch (wfx->wBitsPerSample) {
case 8:
as->fmt = AUD_FMT_U8;
break;
case 16:
as->fmt = AUD_FMT_S16;
break;
case 32:
as->fmt = AUD_FMT_S32;
break;
default:
dolog ("Invalid wave format, bits per sample is not "
"8, 16 or 32, but %d\n",
wfx->wBitsPerSample);
return -1;
}
return 0;
}
#include "dsound_template.h"
#define DSBTYPE_IN
#include "dsound_template.h"
@@ -565,13 +660,13 @@ static int dsound_write (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
static int dsound_run_out (HWVoiceOut *hw, int live)
static int dsound_run_out (HWVoiceOut *hw)
{
int err;
HRESULT hr;
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
int len, hwshift;
int live, len, hwshift;
DWORD blen1, blen2;
DWORD len1, len2;
DWORD decr;
@@ -587,6 +682,8 @@ static int dsound_run_out (HWVoiceOut *hw, int live)
hwshift = hw->info.shift;
bufsize = hw->samples << hwshift;
live = audio_pcm_hw_get_live_out (hw);
hr = IDirectSoundBuffer_GetCurrentPosition (
dsb,
&ppos,
@@ -938,93 +1035,54 @@ static void *dsound_audio_init (void)
}
static struct audio_option dsound_options[] = {
{
.name = "LOCK_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.lock_retries,
.descr = "Number of times to attempt locking the buffer"
},
{
.name = "RESTOURE_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.restore_retries,
.descr = "Number of times to attempt restoring the buffer"
},
{
.name = "GETSTATUS_RETRIES",
.tag = AUD_OPT_INT,
.valp = &conf.getstatus_retries,
.descr = "Number of times to attempt getting status of the buffer"
},
{
.name = "SET_PRIMARY",
.tag = AUD_OPT_BOOL,
.valp = &conf.set_primary,
.descr = "Set the parameters of primary buffer"
},
{
.name = "LATENCY_MILLIS",
.tag = AUD_OPT_INT,
.valp = &conf.latency_millis,
.descr = "(undocumented)"
},
{
.name = "PRIMARY_FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.settings.freq,
.descr = "Primary buffer frequency"
},
{
.name = "PRIMARY_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.settings.nchannels,
.descr = "Primary buffer number of channels (1 - mono, 2 - stereo)"
},
{
.name = "PRIMARY_FMT",
.tag = AUD_OPT_FMT,
.valp = &conf.settings.fmt,
.descr = "Primary buffer format"
},
{
.name = "BUFSIZE_OUT",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize_out,
.descr = "(undocumented)"
},
{
.name = "BUFSIZE_IN",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize_in,
.descr = "(undocumented)"
},
{ /* End of list */ }
{"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
"Number of times to attempt locking the buffer", NULL, 0},
{"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
"Number of times to attempt restoring the buffer", NULL, 0},
{"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
"Number of times to attempt getting status of the buffer", NULL, 0},
{"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
"Set the parameters of primary buffer", NULL, 0},
{"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
"(undocumented)", NULL, 0},
{"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq,
"Primary buffer frequency", NULL, 0},
{"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
"Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
{"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt,
"Primary buffer format", NULL, 0},
{"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
"(undocumented)", NULL, 0},
{"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
"(undocumented)", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops dsound_pcm_ops = {
.init_out = dsound_init_out,
.fini_out = dsound_fini_out,
.run_out = dsound_run_out,
.write = dsound_write,
.ctl_out = dsound_ctl_out,
dsound_init_out,
dsound_fini_out,
dsound_run_out,
dsound_write,
dsound_ctl_out,
.init_in = dsound_init_in,
.fini_in = dsound_fini_in,
.run_in = dsound_run_in,
.read = dsound_read,
.ctl_in = dsound_ctl_in
dsound_init_in,
dsound_fini_in,
dsound_run_in,
dsound_read,
dsound_ctl_in
};
struct audio_driver dsound_audio_driver = {
.name = "dsound",
.descr = "DirectSound http://wikipedia.org/wiki/DirectSound",
.options = dsound_options,
.init = dsound_audio_init,
.fini = dsound_audio_fini,
.pcm_ops = &dsound_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = 1,
.voice_size_out = sizeof (DSoundVoiceOut),
.voice_size_in = sizeof (DSoundVoiceIn)
INIT_FIELD (name = ) "dsound",
INIT_FIELD (descr = )
"DirectSound http://wikipedia.org/wiki/DirectSound",
INIT_FIELD (options = ) dsound_options,
INIT_FIELD (init = ) dsound_audio_init,
INIT_FIELD (fini = ) dsound_audio_fini,
INIT_FIELD (pcm_ops = ) &dsound_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) 1,
INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn)
};

View File

@@ -58,8 +58,10 @@ static struct {
char *dac_host;
char *adc_host;
} conf = {
.samples = 1024,
.divisor = 2,
1024,
2,
NULL,
NULL
};
static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
@@ -131,7 +133,7 @@ static void *qesd_thread_out (void *arg)
int wsamples = written >> hw->info.shift;
int wbytes = wsamples << hw->info.shift;
if (wbytes != written) {
dolog ("warning: Misaligned write %d (requested %zd), "
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
@@ -158,15 +160,16 @@ static void *qesd_thread_out (void *arg)
return NULL;
}
static int qesd_run_out (HWVoiceOut *hw, int live)
static int qesd_run_out (HWVoiceOut *hw)
{
int decr;
int live, decr;
ESDVoiceOut *esd = (ESDVoiceOut *) hw;
if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
return 0;
}
live = audio_pcm_hw_get_live_out (hw);
decr = audio_MIN (live, esd->decr);
esd->decr -= decr;
esd->live = live - decr;
@@ -360,7 +363,7 @@ static void *qesd_thread_in (void *arg)
int rsamples = nread >> hw->info.shift;
int rbytes = rsamples << hw->info.shift;
if (rbytes != nread) {
dolog ("warning: Misaligned write %d (requested %zd), "
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
rbytes, nread, hw->info.align + 1);
}
@@ -548,57 +551,46 @@ static void qesd_audio_fini (void *opaque)
}
struct audio_option qesd_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.samples,
.descr = "buffer size in samples"
},
{
.name = "DIVISOR",
.tag = AUD_OPT_INT,
.valp = &conf.divisor,
.descr = "threshold divisor"
},
{
.name = "DAC_HOST",
.tag = AUD_OPT_STR,
.valp = &conf.dac_host,
.descr = "playback host"
},
{
.name = "ADC_HOST",
.tag = AUD_OPT_STR,
.valp = &conf.adc_host,
.descr = "capture host"
},
{ /* End of list */ }
{"SAMPLES", AUD_OPT_INT, &conf.samples,
"buffer size in samples", NULL, 0},
{"DIVISOR", AUD_OPT_INT, &conf.divisor,
"threshold divisor", NULL, 0},
{"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
"playback host", NULL, 0},
{"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
"capture host", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops qesd_pcm_ops = {
.init_out = qesd_init_out,
.fini_out = qesd_fini_out,
.run_out = qesd_run_out,
.write = qesd_write,
.ctl_out = qesd_ctl_out,
qesd_init_out,
qesd_fini_out,
qesd_run_out,
qesd_write,
qesd_ctl_out,
.init_in = qesd_init_in,
.fini_in = qesd_fini_in,
.run_in = qesd_run_in,
.read = qesd_read,
.ctl_in = qesd_ctl_in,
qesd_init_in,
qesd_fini_in,
qesd_run_in,
qesd_read,
qesd_ctl_in,
};
struct audio_driver esd_audio_driver = {
.name = "esd",
.descr = "http://en.wikipedia.org/wiki/Esound",
.options = qesd_options,
.init = qesd_audio_init,
.fini = qesd_audio_fini,
.pcm_ops = &qesd_pcm_ops,
.can_be_default = 0,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (ESDVoiceOut),
.voice_size_in = sizeof (ESDVoiceIn)
INIT_FIELD (name = ) "esd",
INIT_FIELD (descr = )
"http://en.wikipedia.org/wiki/Esound",
INIT_FIELD (options = ) qesd_options,
INIT_FIELD (init = ) qesd_audio_init,
INIT_FIELD (fini = ) qesd_audio_fini,
INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
INIT_FIELD (can_be_default = ) 0,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
};

View File

@@ -47,11 +47,16 @@ static struct {
int freq;
int nb_channels;
int bufsize;
int threshold;
int broken_adc;
} conf = {
.nb_samples = 2048 * 2,
.freq = 44100,
.nb_channels = 2,
NULL,
2048 * 2,
44100,
2,
0,
0,
0
};
static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
@@ -224,15 +229,24 @@ static int fmod_lock_sample (
return 0;
}
static int fmod_run_out (HWVoiceOut *hw, int live)
static int fmod_run_out (HWVoiceOut *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
int decr;
int live, decr;
void *p1 = 0, *p2 = 0;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1 = 0, len2 = 0;
int nb_live;
if (!hw->pending_disable) {
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!live) {
return 0;
}
if (!hw->pending_disable
&& nb_live
&& (conf.threshold && live <= conf.threshold)) {
ldebug ("live=%d nb_live=%d\n", live, nb_live);
return 0;
}
@@ -503,27 +517,27 @@ static struct {
const char *name;
int type;
} drvtab[] = {
{ .name = "none", .type = FSOUND_OUTPUT_NOSOUND },
{"none", FSOUND_OUTPUT_NOSOUND},
#ifdef _WIN32
{ .name = "winmm", .type = FSOUND_OUTPUT_WINMM },
{ .name = "dsound", .type = FSOUND_OUTPUT_DSOUND },
{ .name = "a3d", .type = FSOUND_OUTPUT_A3D },
{ .name = "asio", .type = FSOUND_OUTPUT_ASIO },
{"winmm", FSOUND_OUTPUT_WINMM},
{"dsound", FSOUND_OUTPUT_DSOUND},
{"a3d", FSOUND_OUTPUT_A3D},
{"asio", FSOUND_OUTPUT_ASIO},
#endif
#ifdef __linux__
{ .name = "oss", .type = FSOUND_OUTPUT_OSS },
{ .name = "alsa", .type = FSOUND_OUTPUT_ALSA },
{ .name = "esd", .type = FSOUND_OUTPUT_ESD },
{"oss", FSOUND_OUTPUT_OSS},
{"alsa", FSOUND_OUTPUT_ALSA},
{"esd", FSOUND_OUTPUT_ESD},
#endif
#ifdef __APPLE__
{ .name = "mac", .type = FSOUND_OUTPUT_MAC },
{"mac", FSOUND_OUTPUT_MAC},
#endif
#if 0
{ .name = "xbox", .type = FSOUND_OUTPUT_XBOX },
{ .name = "ps2", .type = FSOUND_OUTPUT_PS2 },
{ .name = "gcube", .type = FSOUND_OUTPUT_GC },
{"xbox", FSOUND_OUTPUT_XBOX},
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{ .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
{"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
@@ -625,63 +639,48 @@ static void fmod_audio_fini (void *opaque)
}
static struct audio_option fmod_options[] = {
{
.name = "DRV",
.tag = AUD_OPT_STR,
.valp = &conf.drvname,
.descr = "FMOD driver"
},
{
.name = "FREQ",
.tag = AUD_OPT_INT,
.valp = &conf.freq,
.descr = "Default frequency"
},
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.nb_samples,
.descr = "Buffer size in samples"
},
{
.name = "CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.nb_channels,
.descr = "Number of default channels (1 - mono, 2 - stereo)"
},
{
.name = "BUFSIZE",
.tag = AUD_OPT_INT,
.valp = &conf.bufsize,
.descr = "(undocumented)"
},
{ /* End of list */ }
{"DRV", AUD_OPT_STR, &conf.drvname,
"FMOD driver", NULL, 0},
{"FREQ", AUD_OPT_INT, &conf.freq,
"Default frequency", NULL, 0},
{"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
"Buffer size in samples", NULL, 0},
{"CHANNELS", AUD_OPT_INT, &conf.nb_channels,
"Number of default channels (1 - mono, 2 - stereo)", NULL, 0},
{"BUFSIZE", AUD_OPT_INT, &conf.bufsize,
"(undocumented)", NULL, 0},
#if 0
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
"(undocumented)"},
#endif
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops fmod_pcm_ops = {
.init_out = fmod_init_out,
.fini_out = fmod_fini_out,
.run_out = fmod_run_out,
.write = fmod_write,
.ctl_out = fmod_ctl_out,
fmod_init_out,
fmod_fini_out,
fmod_run_out,
fmod_write,
fmod_ctl_out,
.init_in = fmod_init_in,
.fini_in = fmod_fini_in,
.run_in = fmod_run_in,
.read = fmod_read,
.ctl_in = fmod_ctl_in
fmod_init_in,
fmod_fini_in,
fmod_run_in,
fmod_read,
fmod_ctl_in
};
struct audio_driver fmod_audio_driver = {
.name = "fmod",
.descr = "FMOD 3.xx http://www.fmod.org",
.options = fmod_options,
.init = fmod_audio_init,
.fini = fmod_audio_fini,
.pcm_ops = &fmod_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (FMODVoiceOut),
.voice_size_in = sizeof (FMODVoiceIn)
INIT_FIELD (name = ) "fmod",
INIT_FIELD (descr = ) "FMOD 3.xx http://www.fmod.org",
INIT_FIELD (options = ) fmod_options,
INIT_FIELD (init = ) fmod_audio_init,
INIT_FIELD (fini = ) fmod_audio_fini,
INIT_FIELD (pcm_ops = ) &fmod_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (FMODVoiceIn)
};

View File

@@ -27,7 +27,7 @@
#ifdef FLOAT_MIXENG
typedef float mixeng_real;
struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; };
struct st_sample { mixeng_real l; mixeng_real r; };
struct mixeng_sample { mixeng_real l; mixeng_real r; };
#else
struct mixeng_volume { int mute; int64_t r; int64_t l; };
struct st_sample { int64_t l; int64_t r; };

View File

@@ -38,17 +38,22 @@ typedef struct NoVoiceIn {
int64_t old_ticks;
} NoVoiceIn;
static int no_run_out (HWVoiceOut *hw, int live)
static int no_run_out (HWVoiceOut *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int decr, samples;
int live, decr, samples;
int64_t now;
int64_t ticks;
int64_t bytes;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
@@ -104,8 +109,7 @@ static int no_run_in (HWVoiceIn *hw)
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes =
muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
no->old_ticks = now;
bytes = audio_MIN (bytes, INT_MAX);
@@ -142,29 +146,29 @@ static void no_audio_fini (void *opaque)
}
static struct audio_pcm_ops no_pcm_ops = {
.init_out = no_init_out,
.fini_out = no_fini_out,
.run_out = no_run_out,
.write = no_write,
.ctl_out = no_ctl_out,
no_init_out,
no_fini_out,
no_run_out,
no_write,
no_ctl_out,
.init_in = no_init_in,
.fini_in = no_fini_in,
.run_in = no_run_in,
.read = no_read,
.ctl_in = no_ctl_in
no_init_in,
no_fini_in,
no_run_in,
no_read,
no_ctl_in
};
struct audio_driver no_audio_driver = {
.name = "none",
.descr = "Timer based audio emulation",
.options = NULL,
.init = no_audio_init,
.fini = no_audio_fini,
.pcm_ops = &no_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (NoVoiceOut),
.voice_size_in = sizeof (NoVoiceIn)
INIT_FIELD (name = ) "none",
INIT_FIELD (descr = ) "Timer based audio emulation",
INIT_FIELD (options = ) NULL,
INIT_FIELD (init = ) no_audio_init,
INIT_FIELD (fini = ) no_audio_fini,
INIT_FIELD (pcm_ops = ) &no_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn)
};

View File

@@ -31,8 +31,6 @@
#include <sys/soundcard.h>
#endif
#include "qemu-common.h"
#include "host-utils.h"
#include "qemu-char.h"
#include "audio.h"
#define AUDIO_CAP "oss"
@@ -42,11 +40,10 @@ typedef struct OSSVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
int fd;
int wpos;
int nfrags;
int fragsize;
int mmapped;
int pending;
int old_optr;
} OSSVoiceOut;
typedef struct OSSVoiceIn {
@@ -55,6 +52,7 @@ typedef struct OSSVoiceIn {
int fd;
int nfrags;
int fragsize;
int old_optr;
} OSSVoiceIn;
static struct {
@@ -64,17 +62,13 @@ static struct {
const char *devpath_out;
const char *devpath_in;
int debug;
int exclusive;
int policy;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.debug = 0,
.exclusive = 0,
.policy = 5
.debug = 0
};
struct oss_params {
@@ -116,42 +110,13 @@ static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
static void oss_anal_close (int *fdp)
{
int err;
qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
err = close (*fdp);
int err = close (*fdp);
if (err) {
oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
}
*fdp = -1;
}
static void oss_helper_poll_out (void *opaque)
{
(void) opaque;
audio_run ("oss_poll_out");
}
static void oss_helper_poll_in (void *opaque)
{
(void) opaque;
audio_run ("oss_poll_in");
}
static int oss_poll_out (HWVoiceOut *hw)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
return qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL);
}
static int oss_poll_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
return qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL);
}
static int oss_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
@@ -240,17 +205,13 @@ static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd)
{
int fd;
int version;
int oflags = conf.exclusive ? O_EXCL : 0;
int mmmmssss;
audio_buf_info abinfo;
int fmt, freq, nchannels;
const char *dspname = in ? conf.devpath_in : conf.devpath_out;
const char *typ = in ? "ADC" : "DAC";
/* Kludge needed to have working mmap on Linux */
oflags |= conf.try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY);
fd = open (dspname, oflags | O_NONBLOCK);
fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
if (-1 == fd) {
oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
return -1;
@@ -281,33 +242,11 @@ static int oss_open (int in, struct oss_params *req,
goto err;
}
if (ioctl (fd, OSS_GETVERSION, &version)) {
oss_logerr2 (errno, typ, "Failed to get OSS version\n");
version = 0;
}
if (conf.debug) {
dolog ("OSS version = %#x\n", version);
}
#ifdef SNDCTL_DSP_POLICY
if (conf.policy >= 0 && version >= 0x040000) {
int policy = conf.policy;
if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) {
oss_logerr2 (errno, typ, "Failed to set timing policy to %d\n",
conf.policy);
goto err;
}
}
else
#endif
{
int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
req->nfrags, req->fragsize);
goto err;
}
mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
req->nfrags, req->fragsize);
goto err;
}
if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
@@ -349,58 +288,26 @@ static int oss_open (int in, struct oss_params *req,
return -1;
}
static void oss_write_pending (OSSVoiceOut *oss)
{
HWVoiceOut *hw = &oss->hw;
if (oss->mmapped) {
return;
}
while (oss->pending) {
int samples_written;
ssize_t bytes_written;
int samples_till_end = hw->samples - oss->wpos;
int samples_to_write = audio_MIN (oss->pending, samples_till_end);
int bytes_to_write = samples_to_write << hw->info.shift;
void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift);
bytes_written = write (oss->fd, pcm, bytes_to_write);
if (bytes_written < 0) {
if (errno != EAGAIN) {
oss_logerr (errno, "failed to write %d bytes\n",
bytes_to_write);
}
break;
}
if (bytes_written & hw->info.align) {
dolog ("misaligned write asked for %d, but got %zd\n",
bytes_to_write, bytes_written);
return;
}
samples_written = bytes_written >> hw->info.shift;
oss->pending -= samples_written;
oss->wpos = (oss->wpos + samples_written) % hw->samples;
if (bytes_written - bytes_to_write) {
break;
}
}
}
static int oss_run_out (HWVoiceOut *hw, int live)
static int oss_run_out (HWVoiceOut *hw)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
int err, decr;
int err, rpos, live, decr;
int samples;
uint8_t *dst;
struct st_sample *src;
struct audio_buf_info abinfo;
struct count_info cntinfo;
int bufsize;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
bufsize = hw->samples << hw->info.shift;
if (oss->mmapped) {
int bytes, pos;
int bytes;
err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
if (err < 0) {
@@ -408,8 +315,20 @@ static int oss_run_out (HWVoiceOut *hw, int live)
return 0;
}
pos = hw->rpos << hw->info.shift;
bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize);
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64) {
dolog ("warning: Overrun\n");
}
return 0;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->info.shift, live);
}
else {
@@ -422,7 +341,7 @@ static int oss_run_out (HWVoiceOut *hw, int live)
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to av1474@comtv.ru\n",
"please report your OS/audio hw to malc@pulsesoft.com\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
@@ -442,10 +361,53 @@ static int oss_run_out (HWVoiceOut *hw, int live)
}
}
decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending);
oss->pending += decr;
oss_write_pending (oss);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = hw->mix_buf + rpos;
dst = advance (oss->pcm_buf, rpos << hw->info.shift);
hw->clip (dst, src, convert_samples);
if (!oss->mmapped) {
int written;
written = write (oss->fd, dst, convert_samples << hw->info.shift);
/* XXX: follow errno recommendations ? */
if (written == -1) {
oss_logerr (
errno,
"Failed to write %d bytes of audio data from %p\n",
convert_samples << hw->info.shift,
dst
);
continue;
}
if (written != convert_samples << hw->info.shift) {
int wsamples = written >> hw->info.shift;
int wbytes = wsamples << hw->info.shift;
if (wbytes != written) {
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
decr -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
if (oss->mmapped) {
oss->old_optr = cntinfo.ptr;
}
hw->rpos = rpos;
return decr;
}
@@ -519,7 +481,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (
NULL,
0,
hw->samples << hw->info.shift,
PROT_READ | PROT_WRITE,
MAP_SHARED,
@@ -529,8 +491,7 @@ static int oss_init_out (HWVoiceOut *hw, struct audsettings *as)
if (oss->pcm_buf == MAP_FAILED) {
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
hw->samples << hw->info.shift);
}
else {
} else {
int err;
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
@@ -585,48 +546,25 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
if (!oss->mmapped) {
return 0;
}
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
ldebug ("enabling voice\n");
if (poll_mode && oss_poll_out (hw)) {
poll_mode = 0;
}
hw->poll_mode = poll_mode;
if (!oss->mmapped) {
return 0;
}
audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
return -1;
}
ldebug ("enabling voice\n");
audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
return -1;
}
break;
case VOICE_DISABLE:
if (hw->poll_mode) {
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
hw->poll_mode = 0;
}
if (!oss->mmapped) {
return 0;
}
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
@@ -716,8 +654,8 @@ static int oss_run_in (HWVoiceIn *hw)
int add;
int len;
} bufs[2] = {
{ .add = hw->wpos, .len = 0 },
{ .add = 0, .len = 0 }
{ hw->wpos, 0 },
{ 0, 0 }
};
if (!dead) {
@@ -732,6 +670,7 @@ static int oss_run_in (HWVoiceIn *hw)
bufs[0].len = dead << hwshift;
}
for (i = 0; i < 2; ++i) {
ssize_t nread;
@@ -781,32 +720,8 @@ static int oss_read (SWVoiceIn *sw, void *buf, int size)
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && oss_poll_in (hw)) {
poll_mode = 0;
}
hw->poll_mode = poll_mode;
}
break;
case VOICE_DISABLE:
if (hw->poll_mode) {
hw->poll_mode = 0;
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
}
break;
}
(void) hw;
(void) cmd;
return 0;
}
@@ -821,83 +736,45 @@ static void oss_audio_fini (void *opaque)
}
static struct audio_option oss_options[] = {
{
.name = "FRAGSIZE",
.tag = AUD_OPT_INT,
.valp = &conf.fragsize,
.descr = "Fragment size in bytes"
},
{
.name = "NFRAGS",
.tag = AUD_OPT_INT,
.valp = &conf.nfrags,
.descr = "Number of fragments"
},
{
.name = "MMAP",
.tag = AUD_OPT_BOOL,
.valp = &conf.try_mmap,
.descr = "Try using memory mapped access"
},
{
.name = "DAC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.devpath_out,
.descr = "Path to DAC device"
},
{
.name = "ADC_DEV",
.tag = AUD_OPT_STR,
.valp = &conf.devpath_in,
.descr = "Path to ADC device"
},
{
.name = "EXCLUSIVE",
.tag = AUD_OPT_BOOL,
.valp = &conf.exclusive,
.descr = "Open device in exclusive mode (vmix wont work)"
},
#ifdef SNDCTL_DSP_POLICY
{
.name = "POLICY",
.tag = AUD_OPT_INT,
.valp = &conf.policy,
.descr = "Set the timing policy of the device, -1 to use fragment mode",
},
#endif
{
.name = "DEBUG",
.tag = AUD_OPT_BOOL,
.valp = &conf.debug,
.descr = "Turn on some debugging messages"
},
{ /* End of list */ }
{"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
"Fragment size in bytes", NULL, 0},
{"NFRAGS", AUD_OPT_INT, &conf.nfrags,
"Number of fragments", NULL, 0},
{"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
"Try using memory mapped access", NULL, 0},
{"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
"Path to DAC device", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
"Path to ADC device", NULL, 0},
{"DEBUG", AUD_OPT_BOOL, &conf.debug,
"Turn on some debugging messages", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
.run_out = oss_run_out,
.write = oss_write,
.ctl_out = oss_ctl_out,
oss_init_out,
oss_fini_out,
oss_run_out,
oss_write,
oss_ctl_out,
.init_in = oss_init_in,
.fini_in = oss_fini_in,
.run_in = oss_run_in,
.read = oss_read,
.ctl_in = oss_ctl_in
oss_init_in,
oss_fini_in,
oss_run_in,
oss_read,
oss_ctl_in
};
struct audio_driver oss_audio_driver = {
.name = "oss",
.descr = "OSS http://www.opensound.com",
.options = oss_options,
.init = oss_audio_init,
.fini = oss_audio_fini,
.pcm_ops = &oss_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (OSSVoiceOut),
.voice_size_in = sizeof (OSSVoiceIn)
INIT_FIELD (name = ) "oss",
INIT_FIELD (descr = ) "OSS http://www.opensound.com",
INIT_FIELD (options = ) oss_options,
INIT_FIELD (init = ) oss_audio_init,
INIT_FIELD (fini = ) oss_audio_fini,
INIT_FIELD (pcm_ops = ) &oss_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn)
};

View File

@@ -38,8 +38,11 @@ static struct {
char *sink;
char *source;
} conf = {
.samples = 1024,
.divisor = 2,
1024,
2,
NULL,
NULL,
NULL
};
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
@@ -120,15 +123,16 @@ static void *qpa_thread_out (void *arg)
return NULL;
}
static int qpa_run_out (HWVoiceOut *hw, int live)
static int qpa_run_out (HWVoiceOut *hw)
{
int decr;
int live, decr;
PAVoiceOut *pa = (PAVoiceOut *) hw;
if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
return 0;
}
live = audio_pcm_hw_get_live_out (hw);
decr = audio_MIN (live, pa->decr);
pa->decr -= decr;
pa->live = live - decr;
@@ -465,63 +469,47 @@ static void qpa_audio_fini (void *opaque)
}
struct audio_option qpa_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.samples,
.descr = "buffer size in samples"
},
{
.name = "DIVISOR",
.tag = AUD_OPT_INT,
.valp = &conf.divisor,
.descr = "threshold divisor"
},
{
.name = "SERVER",
.tag = AUD_OPT_STR,
.valp = &conf.server,
.descr = "server address"
},
{
.name = "SINK",
.tag = AUD_OPT_STR,
.valp = &conf.sink,
.descr = "sink device name"
},
{
.name = "SOURCE",
.tag = AUD_OPT_STR,
.valp = &conf.source,
.descr = "source device name"
},
{ /* End of list */ }
{"SAMPLES", AUD_OPT_INT, &conf.samples,
"buffer size in samples", NULL, 0},
{"DIVISOR", AUD_OPT_INT, &conf.divisor,
"threshold divisor", NULL, 0},
{"SERVER", AUD_OPT_STR, &conf.server,
"server address", NULL, 0},
{"SINK", AUD_OPT_STR, &conf.sink,
"sink device name", NULL, 0},
{"SOURCE", AUD_OPT_STR, &conf.source,
"source device name", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops qpa_pcm_ops = {
.init_out = qpa_init_out,
.fini_out = qpa_fini_out,
.run_out = qpa_run_out,
.write = qpa_write,
.ctl_out = qpa_ctl_out,
.init_in = qpa_init_in,
.fini_in = qpa_fini_in,
.run_in = qpa_run_in,
.read = qpa_read,
.ctl_in = qpa_ctl_in
qpa_init_out,
qpa_fini_out,
qpa_run_out,
qpa_write,
qpa_ctl_out,
qpa_init_in,
qpa_fini_in,
qpa_run_in,
qpa_read,
qpa_ctl_in
};
struct audio_driver pa_audio_driver = {
.name = "pa",
.descr = "http://www.pulseaudio.org/",
.options = qpa_options,
.init = qpa_audio_init,
.fini = qpa_audio_fini,
.pcm_ops = &qpa_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (PAVoiceOut),
.voice_size_in = sizeof (PAVoiceIn)
INIT_FIELD (name = ) "pa",
INIT_FIELD (descr = ) "http://www.pulseaudio.org/",
INIT_FIELD (options = ) qpa_options,
INIT_FIELD (init = ) qpa_audio_init,
INIT_FIELD (fini = ) qpa_audio_fini,
INIT_FIELD (pcm_ops = ) &qpa_pcm_ops,
INIT_FIELD (can_be_default = ) 0,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (PAVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (PAVoiceIn)
};

View File

@@ -41,14 +41,14 @@
typedef struct SDLVoiceOut {
HWVoiceOut hw;
int live;
int rpos;
int decr;
int pending;
} SDLVoiceOut;
static struct {
int nb_samples;
} conf = {
.nb_samples = 1024
1024
};
static struct SDLAudioState {
@@ -201,7 +201,7 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
}
#ifndef _WIN32
pthread_sigmask (SIG_SETMASK, &old, NULL);
pthread_sigmask (SIG_SETMASK, &old, 0);
#endif
return status;
}
@@ -225,10 +225,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
HWVoiceOut *hw = &sdl->hw;
int samples = len >> hw->info.shift;
if (sdl_lock (s, "sdl_callback")) {
return;
}
if (s->exit) {
return;
}
@@ -236,34 +232,49 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
while (samples) {
int to_mix, decr;
while (!sdl->pending) {
if (sdl_unlock (s, "sdl_callback")) {
return;
}
sdl_wait (s, "sdl_callback");
if (s->exit) {
return;
}
if (sdl_lock (s, "sdl_callback")) {
return;
}
sdl->pending += sdl->live;
sdl->live = 0;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s, "sdl_callback");
if (s->exit) {
return;
}
to_mix = audio_MIN (samples, sdl->pending);
decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0);
buf += decr << hw->info.shift;
samples -= decr;
sdl->decr += decr;
sdl->pending -= decr;
}
if (sdl_lock (s, "sdl_callback")) {
return;
}
if (sdl_unlock (s, "sdl_callback")) {
return;
if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
dolog ("sdl->live=%d hw->samples=%d\n",
sdl->live, hw->samples);
return;
}
if (!sdl->live) {
goto again;
}
/* dolog ("in callback live=%d\n", live); */
to_mix = audio_MIN (samples, sdl->live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
struct st_sample *src = hw->mix_buf + hw->rpos;
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
}
samples -= decr;
sdl->live -= decr;
sdl->decr += decr;
again:
if (sdl_unlock (s, "sdl_callback")) {
return;
}
}
/* dolog ("done len=%d\n", len); */
}
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
@@ -271,25 +282,36 @@ static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
return audio_pcm_sw_write (sw, buf, len);
}
static int sdl_run_out (HWVoiceOut *hw, int live)
static int sdl_run_out (HWVoiceOut *hw)
{
int decr;
int decr, live;
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
if (sdl_lock (s, "sdl_run_out")) {
if (sdl_lock (s, "sdl_callback")) {
return 0;
}
sdl->live = live;
decr = sdl->decr;
sdl->decr = 0;
live = audio_pcm_hw_get_live_out (hw);
if (sdl->decr > live) {
ldebug ("sdl->decr %d live %d sdl->live %d\n",
sdl->decr,
live,
sdl->live);
}
decr = audio_MIN (sdl->decr, live);
sdl->decr -= decr;
sdl->live = live - decr;
hw->rpos = sdl->rpos;
if (sdl->live > 0) {
sdl_unlock_and_post (s, "sdl_run_out");
sdl_unlock_and_post (s, "sdl_callback");
}
else {
sdl_unlock (s, "sdl_run_out");
sdl_unlock (s, "sdl_callback");
}
return decr;
}
@@ -398,33 +420,35 @@ static void sdl_audio_fini (void *opaque)
}
static struct audio_option sdl_options[] = {
{
.name = "SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.nb_samples,
.descr = "Size of SDL buffer in samples"
},
{ /* End of list */ }
{"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
"Size of SDL buffer in samples", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out,
.fini_out = sdl_fini_out,
.run_out = sdl_run_out,
.write = sdl_write_out,
.ctl_out = sdl_ctl_out,
sdl_init_out,
sdl_fini_out,
sdl_run_out,
sdl_write_out,
sdl_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver sdl_audio_driver = {
.name = "sdl",
.descr = "SDL http://www.libsdl.org",
.options = sdl_options,
.init = sdl_audio_init,
.fini = sdl_audio_fini,
.pcm_ops = &sdl_pcm_ops,
.can_be_default = 1,
.max_voices_out = 1,
.max_voices_in = 0,
.voice_size_out = sizeof (SDLVoiceOut),
.voice_size_in = 0
INIT_FIELD (name = ) "sdl",
INIT_FIELD (descr = ) "SDL http://www.libsdl.org",
INIT_FIELD (options = ) sdl_options,
INIT_FIELD (init = ) sdl_audio_init,
INIT_FIELD (fini = ) sdl_audio_fini,
INIT_FIELD (pcm_ops = ) &sdl_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
INIT_FIELD (voice_size_in = ) 0
};

View File

@@ -40,22 +40,24 @@ static struct {
struct audsettings settings;
const char *wav_path;
} conf = {
.settings.freq = 44100,
.settings.nchannels = 2,
.settings.fmt = AUD_FMT_S16,
.wav_path = "qemu.wav"
{
44100,
2,
AUD_FMT_S16,
0
},
"qemu.wav"
};
static int wav_run_out (HWVoiceOut *hw, int live)
static int wav_run_out (HWVoiceOut *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int rpos, decr, samples;
int rpos, live, decr, samples;
uint8_t *dst;
struct st_sample *src;
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - wav->old_ticks;
int64_t bytes =
muldiv64 (ticks, hw->info.bytes_per_second, get_ticks_per_sec ());
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
@@ -64,6 +66,11 @@ static int wav_run_out (HWVoiceOut *hw, int live)
samples = bytes >> hw->info.shift;
}
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
wav->old_ticks = now;
decr = audio_MIN (live, samples);
samples = decr;
@@ -212,51 +219,45 @@ static void wav_audio_fini (void *opaque)
}
static struct audio_option wav_options[] = {
{
.name = "FREQUENCY",
.tag = AUD_OPT_INT,
.valp = &conf.settings.freq,
.descr = "Frequency"
},
{
.name = "FORMAT",
.tag = AUD_OPT_FMT,
.valp = &conf.settings.fmt,
.descr = "Format"
},
{
.name = "DAC_FIXED_CHANNELS",
.tag = AUD_OPT_INT,
.valp = &conf.settings.nchannels,
.descr = "Number of channels (1 - mono, 2 - stereo)"
},
{
.name = "PATH",
.tag = AUD_OPT_STR,
.valp = &conf.wav_path,
.descr = "Path to wave file"
},
{ /* End of list */ }
{"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
"Frequency", NULL, 0},
{"FORMAT", AUD_OPT_FMT, &conf.settings.fmt,
"Format", NULL, 0},
{"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
"Number of channels (1 - mono, 2 - stereo)", NULL, 0},
{"PATH", AUD_OPT_STR, &conf.wav_path,
"Path to wave file", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
.run_out = wav_run_out,
.write = wav_write_out,
.ctl_out = wav_ctl_out,
wav_init_out,
wav_fini_out,
wav_run_out,
wav_write_out,
wav_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver wav_audio_driver = {
.name = "wav",
.descr = "WAV renderer http://wikipedia.org/wiki/WAV",
.options = wav_options,
.init = wav_audio_init,
.fini = wav_audio_fini,
.pcm_ops = &wav_pcm_ops,
.can_be_default = 0,
.max_voices_out = 1,
.max_voices_in = 0,
.voice_size_out = sizeof (WAVVoiceOut),
.voice_size_in = 0
INIT_FIELD (name = ) "wav",
INIT_FIELD (descr = )
"WAV renderer http://wikipedia.org/wiki/WAV",
INIT_FIELD (options = ) wav_options,
INIT_FIELD (init = ) wav_audio_init,
INIT_FIELD (fini = ) wav_audio_fini,
INIT_FIELD (pcm_ops = ) &wav_pcm_ops,
INIT_FIELD (can_be_default = ) 0,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
INIT_FIELD (voice_size_in = ) 0
};

View File

@@ -1,724 +0,0 @@
/* public domain */
#include "qemu-common.h"
#include "sysemu.h"
#include "audio.h"
#define AUDIO_CAP "winwave"
#include "audio_int.h"
#include <windows.h>
#include <mmsystem.h>
#include "audio_win_int.h"
static struct {
int dac_headers;
int dac_samples;
int adc_headers;
int adc_samples;
} conf = {
.dac_headers = 4,
.dac_samples = 1024,
.adc_headers = 4,
.adc_samples = 1024
};
typedef struct {
HWVoiceOut hw;
HWAVEOUT hwo;
WAVEHDR *hdrs;
HANDLE event;
void *pcm_buf;
int avail;
int pending;
int curhdr;
int paused;
CRITICAL_SECTION crit_sect;
} WaveVoiceOut;
typedef struct {
HWVoiceIn hw;
HWAVEIN hwi;
WAVEHDR *hdrs;
HANDLE event;
void *pcm_buf;
int curhdr;
int paused;
int rpos;
int avail;
CRITICAL_SECTION crit_sect;
} WaveVoiceIn;
static void winwave_log_mmresult (MMRESULT mr)
{
const char *str = "BUG";
switch (mr) {
case MMSYSERR_NOERROR:
str = "Success";
break;
case MMSYSERR_INVALHANDLE:
str = "Specified device handle is invalid";
break;
case MMSYSERR_BADDEVICEID:
str = "Specified device id is out of range";
break;
case MMSYSERR_NODRIVER:
str = "No device driver is present";
break;
case MMSYSERR_NOMEM:
str = "Unable to allocate or locl memory";
break;
case WAVERR_SYNC:
str = "Device is synchronous but waveOutOpen was called "
"without using the WINWAVE_ALLOWSYNC flag";
break;
case WAVERR_UNPREPARED:
str = "The data block pointed to by the pwh parameter "
"hasn't been prepared";
break;
case WAVERR_STILLPLAYING:
str = "There are still buffers in the queue";
break;
default:
dolog ("Reason: Unknown (MMRESULT %#x)\n", mr);
return;
}
dolog ("Reason: %s\n", str);
}
static void GCC_FMT_ATTR (2, 3) winwave_logerr (
MMRESULT mr,
const char *fmt,
...
)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (NULL, " failed\n");
winwave_log_mmresult (mr);
}
static void winwave_anal_close_out (WaveVoiceOut *wave)
{
MMRESULT mr;
mr = waveOutClose (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutClose");
}
wave->hwo = NULL;
}
static void CALLBACK winwave_callback_out (
HWAVEOUT hwo,
UINT msg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2
)
{
WaveVoiceOut *wave = (WaveVoiceOut *) dwInstance;
switch (msg) {
case WOM_DONE:
{
WAVEHDR *h = (WAVEHDR *) dwParam1;
if (!h->dwUser) {
h->dwUser = 1;
EnterCriticalSection (&wave->crit_sect);
{
wave->avail += conf.dac_samples;
}
LeaveCriticalSection (&wave->crit_sect);
if (wave->hw.poll_mode) {
if (!SetEvent (wave->event)) {
dolog ("DAC SetEvent failed %lx\n", GetLastError ());
}
}
}
}
break;
case WOM_CLOSE:
case WOM_OPEN:
break;
default:
dolog ("unknown wave out callback msg %x\n", msg);
}
}
static int winwave_init_out (HWVoiceOut *hw, struct audsettings *as)
{
int i;
int err;
MMRESULT mr;
WAVEFORMATEX wfx;
WaveVoiceOut *wave;
wave = (WaveVoiceOut *) hw;
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
goto err0;
}
mr = waveOutOpen (&wave->hwo, WAVE_MAPPER, &wfx,
(DWORD_PTR) winwave_callback_out,
(DWORD_PTR) wave, CALLBACK_FUNCTION);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutOpen");
goto err1;
}
wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
sizeof (*wave->hdrs));
if (!wave->hdrs) {
goto err2;
}
audio_pcm_init_info (&hw->info, as);
hw->samples = conf.dac_samples * conf.dac_headers;
wave->avail = hw->samples;
wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.dac_samples,
conf.dac_headers << hw->info.shift);
if (!wave->pcm_buf) {
goto err3;
}
for (i = 0; i < conf.dac_headers; ++i) {
WAVEHDR *h = &wave->hdrs[i];
h->dwUser = 0;
h->dwBufferLength = conf.dac_samples << hw->info.shift;
h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
h->dwFlags = 0;
mr = waveOutPrepareHeader (wave->hwo, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutPrepareHeader(%d)", i);
goto err4;
}
}
return 0;
err4:
qemu_free (wave->pcm_buf);
err3:
qemu_free (wave->hdrs);
err2:
winwave_anal_close_out (wave);
err1:
err0:
return -1;
}
static int winwave_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int winwave_run_out (HWVoiceOut *hw, int live)
{
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
int decr;
int doreset;
EnterCriticalSection (&wave->crit_sect);
{
decr = audio_MIN (live, wave->avail);
decr = audio_pcm_hw_clip_out (hw, wave->pcm_buf, decr, wave->pending);
wave->pending += decr;
wave->avail -= decr;
}
LeaveCriticalSection (&wave->crit_sect);
doreset = hw->poll_mode && (wave->pending >= conf.dac_samples);
if (doreset && !ResetEvent (wave->event)) {
dolog ("DAC ResetEvent failed %lx\n", GetLastError ());
}
while (wave->pending >= conf.dac_samples) {
MMRESULT mr;
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
mr = waveOutWrite (wave->hwo, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutWrite(%d)", wave->curhdr);
break;
}
wave->pending -= conf.dac_samples;
wave->curhdr = (wave->curhdr + 1) % conf.dac_headers;
}
return decr;
}
static void winwave_poll (void *opaque)
{
(void) opaque;
audio_run ("winwave_poll");
}
static void winwave_fini_out (HWVoiceOut *hw)
{
int i;
MMRESULT mr;
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
mr = waveOutReset (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutReset");
}
for (i = 0; i < conf.dac_headers; ++i) {
mr = waveOutUnprepareHeader (wave->hwo, &wave->hdrs[i],
sizeof (wave->hdrs[i]));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutUnprepareHeader(%d)", i);
}
}
winwave_anal_close_out (wave);
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
if (!CloseHandle (wave->event)) {
dolog ("DAC CloseHandle failed %lx\n", GetLastError ());
}
wave->event = NULL;
}
qemu_free (wave->pcm_buf);
wave->pcm_buf = NULL;
qemu_free (wave->hdrs);
wave->hdrs = NULL;
}
static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
MMRESULT mr;
WaveVoiceOut *wave = (WaveVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && !wave->event) {
wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
if (!wave->event) {
dolog ("DAC CreateEvent: %lx, poll mode will be disabled\n",
GetLastError ());
}
}
if (wave->event) {
int ret;
ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
hw->poll_mode = (ret == 0);
}
else {
hw->poll_mode = 0;
}
if (wave->paused) {
mr = waveOutRestart (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutRestart");
}
wave->paused = 0;
}
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
mr = waveOutPause (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveOutPause");
}
else {
wave->paused = 1;
}
}
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
}
return 0;
}
return -1;
}
static void winwave_anal_close_in (WaveVoiceIn *wave)
{
MMRESULT mr;
mr = waveInClose (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInClose");
}
wave->hwi = NULL;
}
static void CALLBACK winwave_callback_in (
HWAVEIN *hwi,
UINT msg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2
)
{
WaveVoiceIn *wave = (WaveVoiceIn *) dwInstance;
switch (msg) {
case WIM_DATA:
{
WAVEHDR *h = (WAVEHDR *) dwParam1;
if (!h->dwUser) {
h->dwUser = 1;
EnterCriticalSection (&wave->crit_sect);
{
wave->avail += conf.adc_samples;
}
LeaveCriticalSection (&wave->crit_sect);
if (wave->hw.poll_mode) {
if (!SetEvent (wave->event)) {
dolog ("ADC SetEvent failed %lx\n", GetLastError ());
}
}
}
}
break;
case WIM_CLOSE:
case WIM_OPEN:
break;
default:
dolog ("unknown wave in callback msg %x\n", msg);
}
}
static void winwave_add_buffers (WaveVoiceIn *wave, int samples)
{
int doreset;
doreset = wave->hw.poll_mode && (samples >= conf.adc_samples);
if (doreset && !ResetEvent (wave->event)) {
dolog ("ADC ResetEvent failed %lx\n", GetLastError ());
}
while (samples >= conf.adc_samples) {
MMRESULT mr;
WAVEHDR *h = &wave->hdrs[wave->curhdr];
h->dwUser = 0;
mr = waveInAddBuffer (wave->hwi, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInAddBuffer(%d)", wave->curhdr);
}
wave->curhdr = (wave->curhdr + 1) % conf.adc_headers;
samples -= conf.adc_samples;
}
}
static int winwave_init_in (HWVoiceIn *hw, struct audsettings *as)
{
int i;
int err;
MMRESULT mr;
WAVEFORMATEX wfx;
WaveVoiceIn *wave;
wave = (WaveVoiceIn *) hw;
InitializeCriticalSection (&wave->crit_sect);
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
goto err0;
}
mr = waveInOpen (&wave->hwi, WAVE_MAPPER, &wfx,
(DWORD_PTR) winwave_callback_in,
(DWORD_PTR) wave, CALLBACK_FUNCTION);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInOpen");
goto err1;
}
wave->hdrs = audio_calloc (AUDIO_FUNC, conf.dac_headers,
sizeof (*wave->hdrs));
if (!wave->hdrs) {
goto err2;
}
audio_pcm_init_info (&hw->info, as);
hw->samples = conf.adc_samples * conf.adc_headers;
wave->avail = 0;
wave->pcm_buf = audio_calloc (AUDIO_FUNC, conf.adc_samples,
conf.adc_headers << hw->info.shift);
if (!wave->pcm_buf) {
goto err3;
}
for (i = 0; i < conf.adc_headers; ++i) {
WAVEHDR *h = &wave->hdrs[i];
h->dwUser = 0;
h->dwBufferLength = conf.adc_samples << hw->info.shift;
h->lpData = advance (wave->pcm_buf, i * h->dwBufferLength);
h->dwFlags = 0;
mr = waveInPrepareHeader (wave->hwi, h, sizeof (*h));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInPrepareHeader(%d)", i);
goto err4;
}
}
wave->paused = 1;
winwave_add_buffers (wave, hw->samples);
return 0;
err4:
qemu_free (wave->pcm_buf);
err3:
qemu_free (wave->hdrs);
err2:
winwave_anal_close_in (wave);
err1:
err0:
return -1;
}
static void winwave_fini_in (HWVoiceIn *hw)
{
int i;
MMRESULT mr;
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
mr = waveInReset (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInReset");
}
for (i = 0; i < conf.adc_headers; ++i) {
mr = waveInUnprepareHeader (wave->hwi, &wave->hdrs[i],
sizeof (wave->hdrs[i]));
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInUnprepareHeader(%d)", i);
}
}
winwave_anal_close_in (wave);
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
if (!CloseHandle (wave->event)) {
dolog ("ADC CloseHandle failed %lx\n", GetLastError ());
}
wave->event = NULL;
}
qemu_free (wave->pcm_buf);
wave->pcm_buf = NULL;
qemu_free (wave->hdrs);
wave->hdrs = NULL;
}
static int winwave_run_in (HWVoiceIn *hw)
{
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int decr, ret;
if (!dead) {
return 0;
}
EnterCriticalSection (&wave->crit_sect);
{
decr = audio_MIN (dead, wave->avail);
wave->avail -= decr;
}
LeaveCriticalSection (&wave->crit_sect);
ret = decr;
while (decr) {
int left = hw->samples - hw->wpos;
int conv = audio_MIN (left, decr);
hw->conv (hw->conv_buf + hw->wpos,
advance (wave->pcm_buf, wave->rpos << hw->info.shift),
conv,
&nominal_volume);
wave->rpos = (wave->rpos + conv) % hw->samples;
hw->wpos = (hw->wpos + conv) % hw->samples;
decr -= conv;
}
winwave_add_buffers (wave, ret);
return ret;
}
static int winwave_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int winwave_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
MMRESULT mr;
WaveVoiceIn *wave = (WaveVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
{
va_list ap;
int poll_mode;
va_start (ap, cmd);
poll_mode = va_arg (ap, int);
va_end (ap);
if (poll_mode && !wave->event) {
wave->event = CreateEvent (NULL, TRUE, TRUE, NULL);
if (!wave->event) {
dolog ("ADC CreateEvent: %lx, poll mode will be disabled\n",
GetLastError ());
}
}
if (wave->event) {
int ret;
ret = qemu_add_wait_object (wave->event, winwave_poll, wave);
hw->poll_mode = (ret == 0);
}
else {
hw->poll_mode = 0;
}
if (wave->paused) {
mr = waveInStart (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInStart");
}
wave->paused = 0;
}
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
mr = waveInStop (wave->hwi);
if (mr != MMSYSERR_NOERROR) {
winwave_logerr (mr, "waveInStop");
}
else {
wave->paused = 1;
}
}
if (wave->event) {
qemu_del_wait_object (wave->event, winwave_poll, wave);
}
return 0;
}
return 0;
}
static void *winwave_audio_init (void)
{
return &conf;
}
static void winwave_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option winwave_options[] = {
{
.name = "DAC_HEADERS",
.tag = AUD_OPT_INT,
.valp = &conf.dac_headers,
.descr = "DAC number of headers",
},
{
.name = "DAC_SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.dac_samples,
.descr = "DAC number of samples per header",
},
{
.name = "ADC_HEADERS",
.tag = AUD_OPT_INT,
.valp = &conf.adc_headers,
.descr = "ADC number of headers",
},
{
.name = "ADC_SAMPLES",
.tag = AUD_OPT_INT,
.valp = &conf.adc_samples,
.descr = "ADC number of samples per header",
},
{ /* End of list */ }
};
static struct audio_pcm_ops winwave_pcm_ops = {
.init_out = winwave_init_out,
.fini_out = winwave_fini_out,
.run_out = winwave_run_out,
.write = winwave_write,
.ctl_out = winwave_ctl_out,
.init_in = winwave_init_in,
.fini_in = winwave_fini_in,
.run_in = winwave_run_in,
.read = winwave_read,
.ctl_in = winwave_ctl_in
};
struct audio_driver winwave_audio_driver = {
.name = "winwave",
.descr = "Windows Waveform Audio http://msdn.microsoft.com",
.options = winwave_options,
.init = winwave_audio_init,
.fini = winwave_audio_fini,
.pcm_ops = &winwave_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX,
.max_voices_in = INT_MAX,
.voice_size_out = sizeof (WaveVoiceOut),
.voice_size_in = sizeof (WaveVoiceIn)
};

View File

@@ -1,541 +0,0 @@
/*
* QEMU live block migration
*
* Copyright IBM, Corp. 2009
*
* Authors:
* Liran Schour <lirans@il.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "qemu-common.h"
#include "block_int.h"
#include "hw/hw.h"
#include "qemu-queue.h"
#include "monitor.h"
#include "block-migration.h"
#include <assert.h>
#define BLOCK_SIZE (BDRV_SECTORS_PER_DIRTY_CHUNK << BDRV_SECTOR_BITS)
#define BLK_MIG_FLAG_DEVICE_BLOCK 0x01
#define BLK_MIG_FLAG_EOS 0x02
#define BLK_MIG_FLAG_PROGRESS 0x04
#define MAX_IS_ALLOCATED_SEARCH 65536
#define MAX_BLOCKS_READ 10000
#define BLOCKS_READ_CHANGE 100
#define INITIAL_BLOCKS_READ 100
//#define DEBUG_BLK_MIGRATION
#ifdef DEBUG_BLK_MIGRATION
#define dprintf(fmt, ...) \
do { printf("blk_migration: " fmt, ## __VA_ARGS__); } while (0)
#else
#define dprintf(fmt, ...) \
do { } while (0)
#endif
typedef struct BlkMigDevState {
BlockDriverState *bs;
int bulk_completed;
int shared_base;
int64_t cur_sector;
int64_t completed_sectors;
int64_t total_sectors;
int64_t dirty;
QSIMPLEQ_ENTRY(BlkMigDevState) entry;
} BlkMigDevState;
typedef struct BlkMigBlock {
uint8_t *buf;
BlkMigDevState *bmds;
int64_t sector;
struct iovec iov;
QEMUIOVector qiov;
BlockDriverAIOCB *aiocb;
int ret;
QSIMPLEQ_ENTRY(BlkMigBlock) entry;
} BlkMigBlock;
typedef struct BlkMigState {
int blk_enable;
int shared_base;
QSIMPLEQ_HEAD(bmds_list, BlkMigDevState) bmds_list;
QSIMPLEQ_HEAD(blk_list, BlkMigBlock) blk_list;
int submitted;
int read_done;
int transferred;
int64_t total_sector_sum;
int prev_progress;
} BlkMigState;
static BlkMigState block_mig_state;
static void blk_send(QEMUFile *f, BlkMigBlock * blk)
{
int len;
/* sector number and flags */
qemu_put_be64(f, (blk->sector << BDRV_SECTOR_BITS)
| BLK_MIG_FLAG_DEVICE_BLOCK);
/* device name */
len = strlen(blk->bmds->bs->device_name);
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
qemu_put_buffer(f, blk->buf, BLOCK_SIZE);
}
int blk_mig_active(void)
{
return !QSIMPLEQ_EMPTY(&block_mig_state.bmds_list);
}
uint64_t blk_mig_bytes_transferred(void)
{
BlkMigDevState *bmds;
uint64_t sum = 0;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
sum += bmds->completed_sectors;
}
return sum << BDRV_SECTOR_BITS;
}
uint64_t blk_mig_bytes_remaining(void)
{
return blk_mig_bytes_total() - blk_mig_bytes_transferred();
}
uint64_t blk_mig_bytes_total(void)
{
BlkMigDevState *bmds;
uint64_t sum = 0;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
sum += bmds->total_sectors;
}
return sum << BDRV_SECTOR_BITS;
}
static void blk_mig_read_cb(void *opaque, int ret)
{
BlkMigBlock *blk = opaque;
blk->ret = ret;
QSIMPLEQ_INSERT_TAIL(&block_mig_state.blk_list, blk, entry);
block_mig_state.submitted--;
block_mig_state.read_done++;
assert(block_mig_state.submitted >= 0);
}
static int mig_save_device_bulk(Monitor *mon, QEMUFile *f,
BlkMigDevState *bmds, int is_async)
{
int64_t total_sectors = bmds->total_sectors;
int64_t cur_sector = bmds->cur_sector;
BlockDriverState *bs = bmds->bs;
BlkMigBlock *blk;
int nr_sectors;
if (bmds->shared_base) {
while (cur_sector < total_sectors &&
!bdrv_is_allocated(bs, cur_sector, MAX_IS_ALLOCATED_SEARCH,
&nr_sectors)) {
cur_sector += nr_sectors;
}
}
if (cur_sector >= total_sectors) {
bmds->cur_sector = bmds->completed_sectors = total_sectors;
return 1;
}
bmds->completed_sectors = cur_sector;
cur_sector &= ~((int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK - 1);
/* we are going to transfer a full block even if it is not allocated */
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
if (total_sectors - cur_sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
nr_sectors = total_sectors - cur_sector;
}
blk = qemu_malloc(sizeof(BlkMigBlock));
blk->buf = qemu_malloc(BLOCK_SIZE);
blk->bmds = bmds;
blk->sector = cur_sector;
if (is_async) {
blk->iov.iov_base = blk->buf;
blk->iov.iov_len = nr_sectors * BDRV_SECTOR_SIZE;
qemu_iovec_init_external(&blk->qiov, &blk->iov, 1);
blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
nr_sectors, blk_mig_read_cb, blk);
if (!blk->aiocb) {
goto error;
}
block_mig_state.submitted++;
} else {
if (bdrv_read(bs, cur_sector, blk->buf, nr_sectors) < 0) {
goto error;
}
blk_send(f, blk);
qemu_free(blk->buf);
qemu_free(blk);
}
bdrv_reset_dirty(bs, cur_sector, nr_sectors);
bmds->cur_sector = cur_sector + nr_sectors;
return (bmds->cur_sector >= total_sectors);
error:
monitor_printf(mon, "Error reading sector %" PRId64 "\n", cur_sector);
qemu_file_set_error(f);
qemu_free(blk->buf);
qemu_free(blk);
return 0;
}
static void set_dirty_tracking(int enable)
{
BlkMigDevState *bmds;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
bdrv_set_dirty_tracking(bmds->bs, enable);
}
}
static void init_blk_migration(Monitor *mon, QEMUFile *f)
{
BlkMigDevState *bmds;
BlockDriverState *bs;
int64_t sectors;
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;
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
if (bs->type == BDRV_TYPE_HD) {
sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
if (sectors == 0) {
continue;
}
bmds = qemu_mallocz(sizeof(BlkMigDevState));
bmds->bs = bs;
bmds->bulk_completed = 0;
bmds->total_sectors = sectors;
bmds->completed_sectors = 0;
bmds->shared_base = block_mig_state.shared_base;
block_mig_state.total_sector_sum += sectors;
if (bmds->shared_base) {
monitor_printf(mon, "Start migration for %s with shared base "
"image\n",
bs->device_name);
} else {
monitor_printf(mon, "Start full migration for %s\n",
bs->device_name);
}
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
}
}
}
static int blk_mig_save_bulked_block(Monitor *mon, QEMUFile *f, int is_async)
{
int64_t completed_sector_sum = 0;
BlkMigDevState *bmds;
int progress;
int ret = 0;
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
if (bmds->bulk_completed == 0) {
if (mig_save_device_bulk(mon, f, bmds, is_async) == 1) {
/* completed bulk section for this device */
bmds->bulk_completed = 1;
}
completed_sector_sum += bmds->completed_sectors;
ret = 1;
break;
} else {
completed_sector_sum += bmds->completed_sectors;
}
}
progress = completed_sector_sum * 100 / block_mig_state.total_sector_sum;
if (progress != block_mig_state.prev_progress) {
block_mig_state.prev_progress = progress;
qemu_put_be64(f, (progress << BDRV_SECTOR_BITS)
| BLK_MIG_FLAG_PROGRESS);
monitor_printf(mon, "Completed %d %%\r", progress);
monitor_flush(mon);
}
return ret;
}
#define MAX_NUM_BLOCKS 4
static void blk_mig_save_dirty_blocks(Monitor *mon, QEMUFile *f)
{
BlkMigDevState *bmds;
BlkMigBlock blk;
int64_t sector;
blk.buf = qemu_malloc(BLOCK_SIZE);
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
for (sector = 0; sector < bmds->cur_sector;) {
if (bdrv_get_dirty(bmds->bs, sector)) {
if (bdrv_read(bmds->bs, sector, blk.buf,
BDRV_SECTORS_PER_DIRTY_CHUNK) < 0) {
monitor_printf(mon, "Error reading sector %" PRId64 "\n",
sector);
qemu_file_set_error(f);
qemu_free(blk.buf);
return;
}
blk.bmds = bmds;
blk.sector = sector;
blk_send(f, &blk);
bdrv_reset_dirty(bmds->bs, sector,
BDRV_SECTORS_PER_DIRTY_CHUNK);
}
sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
}
}
qemu_free(blk.buf);
}
static void flush_blks(QEMUFile* f)
{
BlkMigBlock *blk;
dprintf("%s Enter submitted %d read_done %d transferred %d\n",
__FUNCTION__, block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
if (qemu_file_rate_limit(f)) {
break;
}
if (blk->ret < 0) {
qemu_file_set_error(f);
break;
}
blk_send(f, blk);
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
qemu_free(blk->buf);
qemu_free(blk);
block_mig_state.read_done--;
block_mig_state.transferred++;
assert(block_mig_state.read_done >= 0);
}
dprintf("%s Exit submitted %d read_done %d transferred %d\n", __FUNCTION__,
block_mig_state.submitted, block_mig_state.read_done,
block_mig_state.transferred);
}
static int is_stage2_completed(void)
{
BlkMigDevState *bmds;
if (block_mig_state.submitted > 0) {
return 0;
}
QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
if (bmds->bulk_completed == 0) {
return 0;
}
}
return 1;
}
static void blk_mig_cleanup(Monitor *mon)
{
BlkMigDevState *bmds;
BlkMigBlock *blk;
while ((bmds = QSIMPLEQ_FIRST(&block_mig_state.bmds_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.bmds_list, entry);
qemu_free(bmds);
}
while ((blk = QSIMPLEQ_FIRST(&block_mig_state.blk_list)) != NULL) {
QSIMPLEQ_REMOVE_HEAD(&block_mig_state.blk_list, entry);
qemu_free(blk->buf);
qemu_free(blk);
}
set_dirty_tracking(0);
monitor_printf(mon, "\n");
}
static int block_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
{
dprintf("Enter save live stage %d submitted %d transferred %d\n",
stage, block_mig_state.submitted, block_mig_state.transferred);
if (stage < 0) {
blk_mig_cleanup(mon);
return 0;
}
if (block_mig_state.blk_enable != 1) {
/* no need to migrate storage */
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return 1;
}
if (stage == 1) {
init_blk_migration(mon, f);
/* start track dirty blocks */
set_dirty_tracking(1);
}
flush_blks(f);
if (qemu_file_has_error(f)) {
blk_mig_cleanup(mon);
return 0;
}
/* control the rate of transfer */
while ((block_mig_state.submitted +
block_mig_state.read_done) * BLOCK_SIZE <
qemu_file_get_rate_limit(f)) {
if (blk_mig_save_bulked_block(mon, f, 1) == 0) {
/* no more bulk blocks for now */
break;
}
}
flush_blks(f);
if (qemu_file_has_error(f)) {
blk_mig_cleanup(mon);
return 0;
}
if (stage == 3) {
while (blk_mig_save_bulked_block(mon, f, 0) != 0) {
/* empty */
}
blk_mig_save_dirty_blocks(mon, f);
blk_mig_cleanup(mon);
/* report completion */
qemu_put_be64(f, (100 << BDRV_SECTOR_BITS) | BLK_MIG_FLAG_PROGRESS);
if (qemu_file_has_error(f)) {
return 0;
}
monitor_printf(mon, "Block migration completed\n");
}
qemu_put_be64(f, BLK_MIG_FLAG_EOS);
return ((stage == 2) && is_stage2_completed());
}
static int block_load(QEMUFile *f, void *opaque, int version_id)
{
static int banner_printed;
int len, flags;
char device_name[256];
int64_t addr;
BlockDriverState *bs;
uint8_t *buf;
do {
addr = qemu_get_be64(f);
flags = addr & ~BDRV_SECTOR_MASK;
addr >>= BDRV_SECTOR_BITS;
if (flags & BLK_MIG_FLAG_DEVICE_BLOCK) {
/* get device name */
len = qemu_get_byte(f);
qemu_get_buffer(f, (uint8_t *)device_name, len);
device_name[len] = '\0';
bs = bdrv_find(device_name);
if (!bs) {
fprintf(stderr, "Error unknown block device %s\n",
device_name);
return -EINVAL;
}
buf = qemu_malloc(BLOCK_SIZE);
qemu_get_buffer(f, buf, BLOCK_SIZE);
bdrv_write(bs, addr, buf, BDRV_SECTORS_PER_DIRTY_CHUNK);
qemu_free(buf);
} else if (flags & BLK_MIG_FLAG_PROGRESS) {
if (!banner_printed) {
printf("Receiving block device images\n");
banner_printed = 1;
}
printf("Completed %d %%%c", (int)addr,
(addr == 100) ? '\n' : '\r');
fflush(stdout);
} else if (!(flags & BLK_MIG_FLAG_EOS)) {
fprintf(stderr, "Unknown flags\n");
return -EINVAL;
}
if (qemu_file_has_error(f)) {
return -EIO;
}
} while (!(flags & BLK_MIG_FLAG_EOS));
return 0;
}
static void block_set_params(int blk_enable, int shared_base, void *opaque)
{
block_mig_state.blk_enable = blk_enable;
block_mig_state.shared_base = shared_base;
/* shared base means that blk_enable = 1 */
block_mig_state.blk_enable |= shared_base;
}
void blk_mig_init(void)
{
QSIMPLEQ_INIT(&block_mig_state.bmds_list);
QSIMPLEQ_INIT(&block_mig_state.blk_list);
register_savevm_live("block", 0, 1, block_set_params, block_save_live,
NULL, block_load, &block_mig_state);
}

View File

@@ -1,23 +0,0 @@
/*
* QEMU live block migration
*
* Copyright IBM, Corp. 2009
*
* Authors:
* Liran Schour <lirans@il.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#ifndef BLOCK_MIGRATION_H
#define BLOCK_MIGRATION_H
void blk_mig_init(void);
int blk_mig_active(void);
uint64_t blk_mig_bytes_transferred(void);
uint64_t blk_mig_bytes_remaining(void);
uint64_t blk_mig_bytes_total(void);
#endif /* BLOCK_MIGRATION_H */

652
block.c
View File

@@ -22,17 +22,20 @@
* THE SOFTWARE.
*/
#include "config-host.h"
#ifdef HOST_BSD
/* include native header before sys-queue.h */
#include <sys/queue.h>
#endif
#include "qemu-common.h"
#include "monitor.h"
#include "block_int.h"
#include "module.h"
#include "qemu-objects.h"
#ifdef CONFIG_BSD
#ifdef HOST_BSD
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
#ifndef __DragonFly__
#include <sys/disk.h>
#endif
@@ -42,14 +45,15 @@
#include <windows.h>
#endif
#define SECTOR_BITS 9
#define SECTOR_SIZE (1 << SECTOR_BITS)
static BlockDriverAIOCB *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,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
@@ -59,9 +63,6 @@ BlockDriverState *bdrv_first;
static BlockDriver *first_drv;
/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;
int path_is_absolute(const char *path)
{
const char *p;
@@ -137,10 +138,6 @@ void bdrv_register(BlockDriver *bdrv)
bdrv->bdrv_read = bdrv_read_em;
bdrv->bdrv_write = bdrv_write_em;
}
if (!bdrv->bdrv_aio_flush)
bdrv->bdrv_aio_flush = bdrv_aio_flush_em;
bdrv->next = first_drv;
first_drv = bdrv;
}
@@ -172,30 +169,6 @@ BlockDriver *bdrv_find_format(const char *format_name)
return NULL;
}
static int bdrv_is_whitelisted(BlockDriver *drv)
{
static const char *whitelist[] = {
CONFIG_BDRV_WHITELIST
};
const char **p;
if (!whitelist[0])
return 1; /* no whitelist, anything goes */
for (p = whitelist; *p; p++) {
if (!strcmp(drv->format_name, *p)) {
return 1;
}
}
return 0;
}
BlockDriver *bdrv_find_whitelisted_format(const char *format_name)
{
BlockDriver *drv = bdrv_find_format(format_name);
return drv && bdrv_is_whitelisted(drv) ? drv : NULL;
}
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options)
{
@@ -356,10 +329,11 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags)
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv)
{
int ret, open_flags, try_rw;
int ret, open_flags;
char tmp_filename[PATH_MAX];
char backing_filename[PATH_MAX];
bs->read_only = 0;
bs->is_temporary = 0;
bs->encrypted = 0;
bs->valid_key = 0;
@@ -383,7 +357,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
bdrv_delete(bs1);
return ret;
}
total_size = bdrv_getlength(bs1) >> BDRV_SECTOR_BITS;
total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
if (bs1->drv && bs1->drv->protocol_name)
is_protocol = 1;
@@ -434,28 +408,13 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
}
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
/*
* Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
* write cache to the guest. We do need the fdatasync to flush
* out transactions for block allocations, and we maybe have a
* volatile write cache in our backing device to deal with.
*/
if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
bs->enable_write_cache = 1;
/* Note: for compatibility, we open disk image files as RDWR, and
RDONLY as fallback */
try_rw = !bs->read_only || bs->is_temporary;
if (!(flags & BDRV_O_FILE))
open_flags = (try_rw ? BDRV_O_RDWR : 0) |
(flags & (BDRV_O_CACHE_MASK|BDRV_O_NATIVE_AIO));
open_flags = BDRV_O_RDWR | (flags & BDRV_O_CACHE_MASK);
else
open_flags = flags & ~(BDRV_O_FILE | BDRV_O_SNAPSHOT);
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv))
ret = -ENOTSUP;
else
ret = drv->bdrv_open(bs, filename, open_flags);
ret = drv->bdrv_open(bs, filename, open_flags);
if ((ret == -EACCES || ret == -EPERM) && !(flags & BDRV_O_FILE)) {
ret = drv->bdrv_open(bs, filename, open_flags & ~BDRV_O_RDWR);
bs->read_only = 1;
@@ -470,7 +429,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
return ret;
}
if (drv->bdrv_getlength) {
bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
bs->total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
}
#ifndef _WIN32
if (bs->is_temporary) {
@@ -481,8 +440,6 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
/* if there is a backing file, use it */
BlockDriver *back_drv = NULL;
bs->backing_hd = bdrv_new("");
/* pass on read_only property to the backing_hd */
bs->backing_hd->read_only = bs->read_only;
path_combine(backing_filename, sizeof(backing_filename),
filename, bs->backing_file);
if (bs->backing_format[0] != '\0')
@@ -573,7 +530,7 @@ int bdrv_commit(BlockDriverState *bs)
return -ENOTSUP;
}
total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
total_sectors = bdrv_getlength(bs) >> SECTOR_BITS;
for (i = 0; i < total_sectors;) {
if (drv->bdrv_is_allocated(bs, i, 65536, &n)) {
for(j = 0; j < n; j++) {
@@ -639,28 +596,6 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
return drv->bdrv_read(bs, sector_num, buf, nb_sectors);
}
static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int dirty)
{
int64_t start, end;
unsigned long val, idx, bit;
start = sector_num / BDRV_SECTORS_PER_DIRTY_CHUNK;
end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
for (; start <= end; start++) {
idx = start / (sizeof(unsigned long) * 8);
bit = start % (sizeof(unsigned long) * 8);
val = bs->dirty_bitmap[idx];
if (dirty) {
val |= 1 << bit;
} else {
val &= ~(1 << bit);
}
bs->dirty_bitmap[idx] = val;
}
}
/* Return < 0 if error. Important errors are:
-EIO generic I/O error (may happen for all errors)
-ENOMEDIUM No media inserted.
@@ -678,30 +613,26 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
return drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
int bdrv_pread(BlockDriverState *bs, int64_t offset,
void *buf, int count1)
{
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
uint8_t tmp_buf[SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
count = count1;
/* first read to align to sector start */
len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
if (len > count)
len = count;
sector_num = offset >> BDRV_SECTOR_BITS;
sector_num = offset >> SECTOR_BITS;
if (len > 0) {
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
memcpy(buf, tmp_buf + (offset & (SECTOR_SIZE - 1)), len);
count -= len;
if (count == 0)
return count1;
@@ -710,12 +641,12 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
}
/* read the sectors "in place" */
nb_sectors = count >> BDRV_SECTOR_BITS;
nb_sectors = count >> SECTOR_BITS;
if (nb_sectors > 0) {
if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
return -EIO;
sector_num += nb_sectors;
len = nb_sectors << BDRV_SECTOR_BITS;
len = nb_sectors << SECTOR_BITS;
buf += len;
count -= len;
}
@@ -732,20 +663,20 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
const void *buf, int count1)
{
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
uint8_t tmp_buf[SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
count = count1;
/* first write to align to sector start */
len = (BDRV_SECTOR_SIZE - offset) & (BDRV_SECTOR_SIZE - 1);
len = (SECTOR_SIZE - offset) & (SECTOR_SIZE - 1);
if (len > count)
len = count;
sector_num = offset >> BDRV_SECTOR_BITS;
sector_num = offset >> SECTOR_BITS;
if (len > 0) {
if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
memcpy(tmp_buf + (offset & (SECTOR_SIZE - 1)), buf, len);
if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
return -EIO;
count -= len;
@@ -756,12 +687,12 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
}
/* write the sectors "in place" */
nb_sectors = count >> BDRV_SECTOR_BITS;
nb_sectors = count >> SECTOR_BITS;
if (nb_sectors > 0) {
if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
return -EIO;
sector_num += nb_sectors;
len = nb_sectors << BDRV_SECTOR_BITS;
len = nb_sectors << SECTOR_BITS;
buf += len;
count -= len;
}
@@ -787,8 +718,6 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
return -ENOMEDIUM;
if (!drv->bdrv_truncate)
return -ENOTSUP;
if (bs->read_only)
return -EACCES;
return drv->bdrv_truncate(bs, offset);
}
@@ -802,7 +731,7 @@ int64_t bdrv_getlength(BlockDriverState *bs)
return -ENOMEDIUM;
if (!drv->bdrv_getlength) {
/* legacy mode */
return bs->total_sectors * BDRV_SECTOR_SIZE;
return bs->total_sectors * SECTOR_SIZE;
}
return drv->bdrv_getlength(bs);
}
@@ -815,7 +744,7 @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
if (length < 0)
length = 0;
else
length = length >> BDRV_SECTOR_BITS;
length = length >> SECTOR_BITS;
*nb_sectors_ptr = length;
}
@@ -983,23 +912,11 @@ int bdrv_is_read_only(BlockDriverState *bs)
return bs->read_only;
}
int bdrv_set_read_only(BlockDriverState *bs, int read_only)
{
int ret = bs->read_only;
bs->read_only = read_only;
return ret;
}
int bdrv_is_sg(BlockDriverState *bs)
{
return bs->sg;
}
int bdrv_enable_write_cache(BlockDriverState *bs)
{
return bs->enable_write_cache;
}
/* XXX: no longer used */
void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
@@ -1140,203 +1057,61 @@ int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
return bs->drv->bdrv_is_allocated(bs, sector_num, nb_sectors, pnum);
}
static void bdrv_print_dict(QObject *obj, void *opaque)
void bdrv_info(Monitor *mon)
{
QDict *bs_dict;
Monitor *mon = opaque;
bs_dict = qobject_to_qdict(obj);
monitor_printf(mon, "%s: type=%s removable=%d",
qdict_get_str(bs_dict, "device"),
qdict_get_str(bs_dict, "type"),
qdict_get_bool(bs_dict, "removable"));
if (qdict_get_bool(bs_dict, "removable")) {
monitor_printf(mon, " locked=%d", qdict_get_bool(bs_dict, "locked"));
}
if (qdict_haskey(bs_dict, "inserted")) {
QDict *qdict = qobject_to_qdict(qdict_get(bs_dict, "inserted"));
monitor_printf(mon, " file=");
monitor_print_filename(mon, qdict_get_str(qdict, "file"));
if (qdict_haskey(qdict, "backing_file")) {
monitor_printf(mon, " backing_file=");
monitor_print_filename(mon, qdict_get_str(qdict, "backing_file"));
}
monitor_printf(mon, " ro=%d drv=%s encrypted=%d",
qdict_get_bool(qdict, "ro"),
qdict_get_str(qdict, "drv"),
qdict_get_bool(qdict, "encrypted"));
} else {
monitor_printf(mon, " [not inserted]");
}
monitor_printf(mon, "\n");
}
void bdrv_info_print(Monitor *mon, const QObject *data)
{
qlist_iter(qobject_to_qlist(data), bdrv_print_dict, mon);
}
/**
* bdrv_info(): Block devices information
*
* Each block device information is stored in a QDict and the
* returned QObject is a QList of all devices.
*
* The QDict contains the following:
*
* - "device": device name
* - "type": device type
* - "removable": true if the device is removable, false otherwise
* - "locked": true if the device is locked, false otherwise
* - "inserted": only present if the device is inserted, it is a QDict
* containing the following:
* - "file": device file name
* - "ro": true if read-only, false otherwise
* - "drv": driver format name
* - "backing_file": backing file name if one is used
* - "encrypted": true if encrypted, false otherwise
*
* Example:
*
* [ { "device": "ide0-hd0", "type": "hd", "removable": false, "locked": false,
* "inserted": { "file": "/tmp/foobar", "ro": false, "drv": "qcow2" } },
* { "device": "floppy0", "type": "floppy", "removable": true,
* "locked": false } ]
*/
void bdrv_info(Monitor *mon, QObject **ret_data)
{
QList *bs_list;
BlockDriverState *bs;
bs_list = qlist_new();
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
QObject *bs_obj;
const char *type = "unknown";
monitor_printf(mon, "%s:", bs->device_name);
monitor_printf(mon, " type=");
switch(bs->type) {
case BDRV_TYPE_HD:
type = "hd";
monitor_printf(mon, "hd");
break;
case BDRV_TYPE_CDROM:
type = "cdrom";
monitor_printf(mon, "cdrom");
break;
case BDRV_TYPE_FLOPPY:
type = "floppy";
monitor_printf(mon, "floppy");
break;
}
bs_obj = qobject_from_jsonf("{ 'device': %s, 'type': %s, "
"'removable': %i, 'locked': %i }",
bs->device_name, type, bs->removable,
bs->locked);
assert(bs_obj != NULL);
if (bs->drv) {
QObject *obj;
QDict *bs_dict = qobject_to_qdict(bs_obj);
obj = qobject_from_jsonf("{ 'file': %s, 'ro': %i, 'drv': %s, "
"'encrypted': %i }",
bs->filename, bs->read_only,
bs->drv->format_name,
bdrv_is_encrypted(bs));
assert(obj != NULL);
if (bs->backing_file[0] != '\0') {
QDict *qdict = qobject_to_qdict(obj);
qdict_put(qdict, "backing_file",
qstring_from_str(bs->backing_file));
}
qdict_put_obj(bs_dict, "inserted", obj);
monitor_printf(mon, " removable=%d", bs->removable);
if (bs->removable) {
monitor_printf(mon, " locked=%d", bs->locked);
}
qlist_append_obj(bs_list, bs_obj);
if (bs->drv) {
monitor_printf(mon, " file=");
monitor_print_filename(mon, bs->filename);
if (bs->backing_file[0] != '\0') {
monitor_printf(mon, " backing_file=");
monitor_print_filename(mon, bs->backing_file);
}
monitor_printf(mon, " ro=%d", bs->read_only);
monitor_printf(mon, " drv=%s", bs->drv->format_name);
monitor_printf(mon, " encrypted=%d", bdrv_is_encrypted(bs));
} else {
monitor_printf(mon, " [not inserted]");
}
monitor_printf(mon, "\n");
}
*ret_data = QOBJECT(bs_list);
}
static void bdrv_stats_iter(QObject *data, void *opaque)
/* The "info blockstats" command. */
void bdrv_info_stats(Monitor *mon)
{
QDict *qdict;
Monitor *mon = opaque;
qdict = qobject_to_qdict(data);
monitor_printf(mon, "%s:", qdict_get_str(qdict, "device"));
qdict = qobject_to_qdict(qdict_get(qdict, "stats"));
monitor_printf(mon, " rd_bytes=%" PRId64
" wr_bytes=%" PRId64
" rd_operations=%" PRId64
" wr_operations=%" PRId64
"\n",
qdict_get_int(qdict, "rd_bytes"),
qdict_get_int(qdict, "wr_bytes"),
qdict_get_int(qdict, "rd_operations"),
qdict_get_int(qdict, "wr_operations"));
}
void bdrv_stats_print(Monitor *mon, const QObject *data)
{
qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon);
}
/**
* bdrv_info_stats(): show block device statistics
*
* Each device statistic information is stored in a QDict and
* the returned QObject is a QList of all devices.
*
* The QDict contains the following:
*
* - "device": device name
* - "stats": A QDict with the statistics information, it contains:
* - "rd_bytes": bytes read
* - "wr_bytes": bytes written
* - "rd_operations": read operations
* - "wr_operations": write operations
*
* Example:
*
* [ { "device": "ide0-hd0",
* "stats": { "rd_bytes": 512,
* "wr_bytes": 0,
* "rd_operations": 1,
* "wr_operations": 0 } },
* { "device": "ide1-cd0",
* "stats": { "rd_bytes": 0,
* "wr_bytes": 0,
* "rd_operations": 0,
* "wr_operations": 0 } } ]
*/
void bdrv_info_stats(Monitor *mon, QObject **ret_data)
{
QObject *obj;
QList *devices;
BlockDriverState *bs;
devices = qlist_new();
for (bs = bdrv_first; bs != NULL; bs = bs->next) {
obj = qobject_from_jsonf("{ 'device': %s, 'stats': {"
"'rd_bytes': %" PRId64 ","
"'wr_bytes': %" PRId64 ","
"'rd_operations': %" PRId64 ","
"'wr_operations': %" PRId64
"} }",
bs->device_name,
bs->rd_bytes, bs->wr_bytes,
bs->rd_ops, bs->wr_ops);
assert(obj != NULL);
qlist_append_obj(devices, obj);
monitor_printf(mon, "%s:"
" rd_bytes=%" PRIu64
" wr_bytes=%" PRIu64
" rd_operations=%" PRIu64
" wr_operations=%" PRIu64
"\n",
bs->device_name,
bs->rd_bytes, bs->wr_bytes,
bs->rd_ops, bs->wr_ops);
}
*ret_data = QOBJECT(devices);
}
const char *bdrv_get_encrypted_filename(BlockDriverState *bs)
@@ -1369,11 +1144,6 @@ int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
return -ENOTSUP;
if (bdrv_check_request(bs, sector_num, nb_sectors))
return -EIO;
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
}
@@ -1550,7 +1320,7 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
if (ret) {
/* Update stats even though technically transfer has not happened. */
bs->rd_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
bs->rd_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
bs->rd_ops ++;
}
@@ -1571,220 +1341,18 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
if (bdrv_check_request(bs, sector_num, nb_sectors))
return NULL;
if (bs->dirty_bitmap) {
set_dirty_bitmap(bs, sector_num, nb_sectors, 1);
}
ret = drv->bdrv_aio_writev(bs, sector_num, qiov, nb_sectors,
cb, opaque);
if (ret) {
/* Update stats even though technically transfer has not happened. */
bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE;
bs->wr_bytes += (unsigned) nb_sectors * SECTOR_SIZE;
bs->wr_ops ++;
}
return ret;
}
typedef struct MultiwriteCB {
int error;
int num_requests;
int num_callbacks;
struct {
BlockDriverCompletionFunc *cb;
void *opaque;
QEMUIOVector *free_qiov;
void *free_buf;
} callbacks[];
} MultiwriteCB;
static void multiwrite_user_cb(MultiwriteCB *mcb)
{
int i;
for (i = 0; i < mcb->num_callbacks; i++) {
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
qemu_free(mcb->callbacks[i].free_qiov);
qemu_free(mcb->callbacks[i].free_buf);
}
}
static void multiwrite_cb(void *opaque, int ret)
{
MultiwriteCB *mcb = opaque;
if (ret < 0) {
mcb->error = ret;
multiwrite_user_cb(mcb);
}
mcb->num_requests--;
if (mcb->num_requests == 0) {
if (mcb->error == 0) {
multiwrite_user_cb(mcb);
}
qemu_free(mcb);
}
}
static int multiwrite_req_compare(const void *a, const void *b)
{
return (((BlockRequest*) a)->sector - ((BlockRequest*) b)->sector);
}
/*
* Takes a bunch of requests and tries to merge them. Returns the number of
* requests that remain after merging.
*/
static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
int num_reqs, MultiwriteCB *mcb)
{
int i, outidx;
// Sort requests by start sector
qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
// Check if adjacent requests touch the same clusters. If so, combine them,
// filling up gaps with zero sectors.
outidx = 0;
for (i = 1; i < num_reqs; i++) {
int merge = 0;
int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
// This handles the cases that are valid for all block drivers, namely
// exactly sequential writes and overlapping writes.
if (reqs[i].sector <= oldreq_last) {
merge = 1;
}
// The block driver may decide that it makes sense to combine requests
// even if there is a gap of some sectors between them. In this case,
// the gap is filled with zeros (therefore only applicable for yet
// unused space in format like qcow2).
if (!merge && bs->drv->bdrv_merge_requests) {
merge = bs->drv->bdrv_merge_requests(bs, &reqs[outidx], &reqs[i]);
}
if (merge) {
size_t size;
QEMUIOVector *qiov = qemu_mallocz(sizeof(*qiov));
qemu_iovec_init(qiov,
reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
// Add the first request to the merged one. If the requests are
// overlapping, drop the last sectors of the first request.
size = (reqs[i].sector - reqs[outidx].sector) << 9;
qemu_iovec_concat(qiov, reqs[outidx].qiov, size);
// We might need to add some zeros between the two requests
if (reqs[i].sector > oldreq_last) {
size_t zero_bytes = (reqs[i].sector - oldreq_last) << 9;
uint8_t *buf = qemu_blockalign(bs, zero_bytes);
memset(buf, 0, zero_bytes);
qemu_iovec_add(qiov, buf, zero_bytes);
mcb->callbacks[i].free_buf = buf;
}
// Add the second request
qemu_iovec_concat(qiov, reqs[i].qiov, reqs[i].qiov->size);
reqs[outidx].nb_sectors += reqs[i].nb_sectors;
reqs[outidx].qiov = qiov;
mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
} else {
outidx++;
reqs[outidx].sector = reqs[i].sector;
reqs[outidx].nb_sectors = reqs[i].nb_sectors;
reqs[outidx].qiov = reqs[i].qiov;
}
}
return outidx + 1;
}
/*
* Submit multiple AIO write requests at once.
*
* On success, the function returns 0 and all requests in the reqs array have
* been submitted. In error case this function returns -1, and any of the
* requests may or may not be submitted yet. In particular, this means that the
* callback will be called for some of the requests, for others it won't. The
* caller must check the error field of the BlockRequest to wait for the right
* callbacks (if error != 0, no callback will be called).
*
* The implementation may modify the contents of the reqs array, e.g. to merge
* requests. However, the fields opaque and error are left unmodified as they
* are used to signal failure for a single request to the caller.
*/
int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
{
BlockDriverAIOCB *acb;
MultiwriteCB *mcb;
int i;
if (num_reqs == 0) {
return 0;
}
// Create MultiwriteCB structure
mcb = qemu_mallocz(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
mcb->num_requests = 0;
mcb->num_callbacks = num_reqs;
for (i = 0; i < num_reqs; i++) {
mcb->callbacks[i].cb = reqs[i].cb;
mcb->callbacks[i].opaque = reqs[i].opaque;
}
// Check for mergable requests
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
// Run the aio requests
for (i = 0; i < num_reqs; i++) {
acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
reqs[i].nb_sectors, multiwrite_cb, mcb);
if (acb == NULL) {
// We can only fail the whole thing if no request has been
// submitted yet. Otherwise we'll wait for the submitted AIOs to
// complete and report the error in the callback.
if (mcb->num_requests == 0) {
reqs[i].error = EIO;
goto fail;
} else {
mcb->error = EIO;
break;
}
} else {
mcb->num_requests++;
}
}
return 0;
fail:
free(mcb);
return -1;
}
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriver *drv = bs->drv;
if (!drv)
return NULL;
/*
* Note that unlike bdrv_flush the driver is reponsible for flushing a
* backing image if it exists.
*/
return drv->bdrv_aio_flush(bs, cb, opaque);
}
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
{
acb->pool->cancel(acb);
@@ -1875,25 +1443,6 @@ static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
static BlockDriverAIOCB *bdrv_aio_flush_em(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BlockDriverAIOCBSync *acb;
acb = qemu_aio_get(&bdrv_em_aio_pool, bs, cb, opaque);
acb->is_write = 1; /* don't bounce in the completion hadler */
acb->qiov = NULL;
acb->bounce = NULL;
acb->ret = 0;
if (!acb->bh)
acb->bh = qemu_bh_new(bdrv_aio_bh_cb, acb);
bdrv_flush(bs);
qemu_bh_schedule(acb->bh);
return &acb->common;
}
/**************************************************************/
/* sync block device emulation */
@@ -1912,26 +1461,19 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
struct iovec iov;
QEMUIOVector qiov;
async_context_push();
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * 512;
qemu_iovec_init_external(&qiov, &iov, 1);
acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
bdrv_rw_em_cb, &async_ret);
if (acb == NULL) {
async_ret = -1;
goto fail;
}
if (acb == NULL)
return -1;
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
fail:
async_context_pop();
return async_ret;
}
@@ -1943,24 +1485,17 @@ static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
struct iovec iov;
QEMUIOVector qiov;
async_context_push();
async_ret = NOT_DONE;
iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * 512;
qemu_iovec_init_external(&qiov, &iov, 1);
acb = bdrv_aio_writev(bs, sector_num, &qiov, nb_sectors,
bdrv_rw_em_cb, &async_ret);
if (acb == NULL) {
async_ret = -1;
goto fail;
}
if (acb == NULL)
return -1;
while (async_ret == NOT_DONE) {
qemu_aio_wait();
}
fail:
async_context_pop();
return async_ret;
}
@@ -1969,12 +1504,6 @@ void bdrv_init(void)
module_call_init(MODULE_INIT_BLOCK);
}
void bdrv_init_with_whitelist(void)
{
use_bdrv_whitelist = 1;
bdrv_init();
}
void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
@@ -2105,48 +1634,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
return NULL;
}
void *qemu_blockalign(BlockDriverState *bs, size_t size)
{
return qemu_memalign((bs && bs->buffer_alignment) ? bs->buffer_alignment : 512, size);
}
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
{
int64_t bitmap_size;
if (enable) {
if (!bs->dirty_bitmap) {
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
bs->dirty_bitmap = qemu_mallocz(bitmap_size);
}
} else {
if (bs->dirty_bitmap) {
qemu_free(bs->dirty_bitmap);
bs->dirty_bitmap = NULL;
}
}
}
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
if (bs->dirty_bitmap &&
(sector << BDRV_SECTOR_BITS) < bdrv_getlength(bs)) {
return bs->dirty_bitmap[chunk / (sizeof(unsigned long) * 8)] &
(1 << (chunk % (sizeof(unsigned long) * 8)));
} else {
return 0;
}
}
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors)
{
set_dirty_bitmap(bs, cur_sector, nr_sectors, 0);
}

42
block.h
View File

@@ -4,7 +4,6 @@
#include "qemu-aio.h"
#include "qemu-common.h"
#include "qemu-option.h"
#include "qobject.h"
/* block.c */
typedef struct BlockDriver BlockDriver;
@@ -38,23 +37,14 @@ typedef struct QEMUSnapshotInfo {
bdrv_file_open()) */
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB)
#define BDRV_SECTOR_BITS 9
#define BDRV_SECTOR_SIZE (1 << BDRV_SECTOR_BITS)
#define BDRV_SECTOR_MASK ~(BDRV_SECTOR_SIZE - 1);
void bdrv_info_print(Monitor *mon, const QObject *data);
void bdrv_info(Monitor *mon, QObject **ret_data);
void bdrv_stats_print(Monitor *mon, const QObject *data);
void bdrv_info_stats(Monitor *mon, QObject **ret_data);
void bdrv_info(Monitor *mon);
void bdrv_info_stats(Monitor *mon);
void bdrv_init(void);
void bdrv_init_with_whitelist(void);
BlockDriver *bdrv_find_format(const char *format_name);
BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options);
int bdrv_create2(BlockDriver *drv,
@@ -87,33 +77,15 @@ void bdrv_register(BlockDriver *bdrv);
/* async block I/O */
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
int sector_num);
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
typedef struct BlockRequest {
/* Fields to be filled by multiwrite caller */
int64_t sector;
int nb_sectors;
QEMUIOVector *qiov;
BlockDriverCompletionFunc *cb;
void *opaque;
/* Filled by multiwrite implementation */
int error;
} BlockRequest;
int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs,
int num_reqs);
/* sg packet commands */
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
@@ -146,9 +118,7 @@ int bdrv_get_type_hint(BlockDriverState *bs);
int bdrv_get_translation_hint(BlockDriverState *bs);
int bdrv_is_removable(BlockDriverState *bs);
int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_set_read_only(BlockDriverState *bs, int read_only);
int bdrv_is_sg(BlockDriverState *bs);
int bdrv_enable_write_cache(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_media_changed(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
@@ -195,10 +165,4 @@ int bdrv_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
int bdrv_load_vmstate(BlockDriverState *bs, uint8_t *buf,
int64_t pos, int size);
#define BDRV_SECTORS_PER_DIRTY_CHUNK 2048
void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable);
int bdrv_get_dirty(BlockDriverState *bs, int64_t sector);
void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
int nr_sectors);
#endif

View File

@@ -258,7 +258,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options)
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
qemu_fdatasync(s->fd);
fsync(s->fd);
}
static QEMUOptionParameter cow_create_options[] = {

View File

@@ -83,17 +83,17 @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
dprintf("CURL (AIO): Sock action %d on fd %d\n", action, fd);
switch (action) {
case CURL_POLL_IN:
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, NULL, s);
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, NULL, s);
break;
case CURL_POLL_OUT:
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, NULL, s);
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, NULL, s);
break;
case CURL_POLL_INOUT:
qemu_aio_set_fd_handler(fd, curl_multi_do,
curl_multi_do, NULL, NULL, s);
curl_multi_do, NULL, s);
break;
case CURL_POLL_REMOVE:
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
break;
}
@@ -269,7 +269,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
return NULL;
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, curl_read_cb);
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
@@ -358,11 +358,11 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
// Get file size
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_size_cb);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, curl_size_cb);
if (curl_easy_perform(state->curl))
goto out;
curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, curl_read_cb);
curl_easy_setopt(state->curl, CURLOPT_NOBODY, 0);
if (d)
s->len = (size_t)d;

View File

@@ -119,8 +119,7 @@ fail:
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
{
BDRVParallelsState *s = bs->opaque;
uint32_t index, offset;
uint64_t position;
uint32_t index, offset, position;
index = sector_num / s->tracks;
offset = sector_num % s->tracks;
@@ -129,7 +128,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
return -1;
position = (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
position = (s->catalog_bitmap[index] + offset) * 512;
// fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n",
// sector_num, index, offset, s->catalog_bitmap[index], position);

View File

@@ -39,9 +39,6 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
new_l1_size = s->l1_size;
if (min_size <= new_l1_size)
return 0;
if (new_l1_size == 0) {
new_l1_size = 1;
}
while (min_size > new_l1_size) {
new_l1_size = (new_l1_size * 3 + 1) / 2;
}
@@ -267,7 +264,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
return 0;
for (i = start; i < start + nb_clusters; i++)
if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
if (offset + i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
break;
return (i - start);
@@ -398,11 +395,10 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num)
{
BDRVQcowState *s = bs->opaque;
unsigned int l1_index, l2_index;
int l1_index, l2_index;
uint64_t l2_offset, *l2_table, cluster_offset;
int l1_bits, c;
unsigned int index_in_cluster, nb_clusters;
uint64_t nb_available, nb_needed;
int index_in_cluster, nb_available, nb_needed, nb_clusters;
index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
nb_needed = *num + index_in_cluster;
@@ -413,7 +409,7 @@ uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
* the end of the l1 entry
*/
nb_available = (1ULL << l1_bits) - (offset & ((1ULL << l1_bits) - 1));
nb_available = (1 << l1_bits) - (offset & ((1 << l1_bits) - 1));
/* compute the number of available sectors */
@@ -487,9 +483,8 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
int *new_l2_index)
{
BDRVQcowState *s = bs->opaque;
unsigned int l1_index, l2_index;
int l1_index, l2_index, ret;
uint64_t l2_offset, *l2_table;
int ret;
/* seek the the l2 offset in the l1 table */
@@ -688,8 +683,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
uint64_t l2_offset, *l2_table, cluster_offset;
unsigned int nb_clusters, i = 0;
QCowL2Meta *old_alloc;
int nb_clusters, i = 0;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
if (ret == 0)
@@ -738,44 +732,6 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
}
nb_clusters = i;
/*
* Check if there already is an AIO write request in flight which allocates
* the same cluster. In this case we need to wait until the previous
* request has completed and updated the L2 table accordingly.
*/
QLIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
uint64_t end_offset = offset + nb_clusters * s->cluster_size;
uint64_t old_offset = old_alloc->offset;
uint64_t old_end_offset = old_alloc->offset +
old_alloc->nb_clusters * s->cluster_size;
if (end_offset < old_offset || offset > old_end_offset) {
/* No intersection */
} else {
if (offset < old_offset) {
/* Stop at the start of a running allocation */
nb_clusters = (old_offset - offset) >> s->cluster_bits;
} else {
nb_clusters = 0;
}
if (nb_clusters == 0) {
/* Set dependency and wait for a callback */
m->depends_on = old_alloc;
m->nb_clusters = 0;
*num = 0;
return 0;
}
}
}
if (!nb_clusters) {
abort();
}
QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
/* allocate a new cluster */
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);

View File

@@ -182,6 +182,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
return 0;
fail:
qcow2_free_clusters(bs, table_offset, new_table_size2);
qemu_free(new_table);
return -EIO;
}
@@ -191,8 +192,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index)
{
BDRVQcowState *s = bs->opaque;
int64_t offset, refcount_block_offset;
unsigned int refcount_table_index;
int ret;
int ret, refcount_table_index;
uint64_t data64;
int cache = cache_refcount_updates;
@@ -513,11 +513,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
l1_size2 = l1_size * sizeof(uint64_t);
l1_allocated = 0;
if (l1_table_offset != s->l1_table_offset) {
if (l1_size2 != 0) {
l1_table = qemu_mallocz(align_offset(l1_size2, 512));
} else {
l1_table = NULL;
}
l1_table = qemu_mallocz(align_offset(l1_size2, 512));
l1_allocated = 1;
if (bdrv_pread(s->hd, l1_table_offset,
l1_table, l1_size2) != l1_size2)
@@ -773,16 +769,12 @@ static int check_refcounts_l1(BlockDriverState *bs,
l1_table_offset, l1_size2);
/* Read L1 table entries from disk */
if (l1_size2 == 0) {
l1_table = NULL;
} else {
l1_table = qemu_malloc(l1_size2);
if (bdrv_pread(s->hd, l1_table_offset,
l1_table, l1_size2) != l1_size2)
goto fail;
for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
}
l1_table = qemu_malloc(l1_size2);
if (bdrv_pread(s->hd, l1_table_offset,
l1_table, l1_size2) != l1_size2)
goto fail;
for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
/* Do the actual checks */
for(i = 0; i < l1_size; i++) {

View File

@@ -266,12 +266,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
sn->l1_size = s->l1_size;
if (s->l1_size != 0) {
l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
} else {
l1_table = NULL;
}
l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
for(i = 0; i < s->l1_size; i++) {
l1_table[i] = cpu_to_be64(s->l1_table[i]);
}

View File

@@ -124,12 +124,12 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset,
#ifdef DEBUG_EXT
printf("Qcow2: Got format extension %s\n", bs->backing_format);
#endif
offset = ((offset + ext.len + 7) & ~7);
offset += ((ext.len + 7) & ~7);
break;
default:
/* unknown magic -- just skip it */
offset = ((offset + ext.len + 7) & ~7);
offset += ((ext.len + 7) & ~7);
break;
}
}
@@ -166,7 +166,8 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
goto fail;
if (header.cluster_bits < MIN_CLUSTER_BITS ||
if (header.size <= 1 ||
header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS)
goto fail;
if (header.crypt_method > QCOW_CRYPT_AES)
@@ -199,15 +200,13 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
if (s->l1_size < s->l1_vm_state_index)
goto fail;
s->l1_table_offset = header.l1_table_offset;
if (s->l1_size > 0) {
s->l1_table = qemu_mallocz(
align_offset(s->l1_size * sizeof(uint64_t), 512));
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
s->l1_table = qemu_mallocz(
align_offset(s->l1_size * sizeof(uint64_t), 512));
if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
s->l1_size * sizeof(uint64_t))
goto fail;
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
@@ -220,8 +219,6 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags)
if (qcow2_refcount_init(bs) < 0)
goto fail;
QLIST_INIT(&s->cluster_allocs);
/* read qcow2 extensions */
if (header.backing_file_offset)
ext_end = header.backing_file_offset;
@@ -341,7 +338,6 @@ typedef struct QCowAIOCB {
QEMUIOVector hd_qiov;
QEMUBH *bh;
QCowL2Meta l2meta;
QLIST_ENTRY(QCowAIOCB) next_depend;
} QCowAIOCB;
static void qcow_aio_cancel(BlockDriverAIOCB *blockacb)
@@ -504,7 +500,6 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->n = 0;
acb->cluster_offset = 0;
acb->l2meta.nb_clusters = 0;
QLIST_INIT(&acb->l2meta.dependent_requests);
return acb;
}
@@ -522,33 +517,6 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
return &acb->common;
}
static void qcow_aio_write_cb(void *opaque, int ret);
static void run_dependent_requests(QCowL2Meta *m)
{
QCowAIOCB *req;
QCowAIOCB *next;
/* Take the request off the list of running requests */
if (m->nb_clusters != 0) {
QLIST_REMOVE(m, next_in_flight);
}
/*
* Restart all dependent requests.
* Can't use QLIST_FOREACH here - the next link might not be the same
* any more after the callback (request could depend on a different
* request now)
*/
for (req = m->dependent_requests.lh_first; req != NULL; req = next) {
next = req->next_depend.le_next;
qcow_aio_write_cb(req, 0);
}
/* Empty the list for the next part of the request */
QLIST_INIT(&m->dependent_requests);
}
static void qcow_aio_write_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
@@ -560,15 +528,14 @@ static void qcow_aio_write_cb(void *opaque, int ret)
acb->hd_aiocb = NULL;
if (ret >= 0) {
ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta);
}
run_dependent_requests(&acb->l2meta);
if (ret < 0)
goto done;
if (qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta) < 0) {
qcow2_free_any_clusters(bs, acb->cluster_offset, acb->l2meta.nb_clusters);
goto done;
}
acb->nb_sectors -= acb->n;
acb->sector_num += acb->n;
acb->buf += acb->n * 512;
@@ -588,14 +555,6 @@ static void qcow_aio_write_cb(void *opaque, int ret)
acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
index_in_cluster,
n_end, &acb->n, &acb->l2meta);
/* Need to wait for another request? If so, we are done for now. */
if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) {
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
acb, next_depend);
return;
}
if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
ret = -EIO;
goto done;
@@ -679,66 +638,13 @@ static int get_bits_from_size(size_t size)
return res;
}
static int preallocate(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint64_t cluster_offset = 0;
uint64_t nb_sectors;
uint64_t offset;
int num;
QCowL2Meta meta;
nb_sectors = bdrv_getlength(bs) >> 9;
offset = 0;
QLIST_INIT(&meta.dependent_requests);
while (nb_sectors) {
num = MIN(nb_sectors, INT_MAX >> 9);
cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
&meta);
if (cluster_offset == 0) {
return -1;
}
if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) {
qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters);
return -1;
}
/* There are no dependent requests, but we need to remove our request
* from the list of in-flight requests */
run_dependent_requests(&meta);
/* TODO Preallocate data if requested */
nb_sectors -= num;
offset += num << 9;
}
/*
* It is expected that the image file is large enough to actually contain
* all of the allocated clusters (otherwise we get failing reads after
* EOF). Extend the image to the last allocated sector.
*/
if (cluster_offset != 0) {
uint8_t buf[512];
memset(buf, 0, 512);
bdrv_write(s->hd, (cluster_offset >> 9) + num - 1, buf, 1);
}
return 0;
}
static int qcow_create2(const char *filename, int64_t total_size,
const char *backing_file, const char *backing_format,
int flags, size_t cluster_size, int prealloc)
int flags, size_t cluster_size)
{
int fd, header_size, backing_filename_len, l1_size, i, shift, l2_bits;
int ref_clusters, backing_format_len = 0;
int rounded_ext_bf_len = 0;
QCowHeader header;
uint64_t tmp, offset;
QCowCreateState s1, *s = &s1;
@@ -760,9 +666,8 @@ static int qcow_create2(const char *filename, int64_t total_size,
if (backing_format) {
ext_bf.magic = QCOW_EXT_MAGIC_BACKING_FORMAT;
backing_format_len = strlen(backing_format);
ext_bf.len = backing_format_len;
rounded_ext_bf_len = (sizeof(ext_bf) + ext_bf.len + 7) & ~7;
header_size += rounded_ext_bf_len;
ext_bf.len = (backing_format_len + 7) & ~7;
header_size += ((sizeof(ext_bf) + ext_bf.len + 7) & ~7);
}
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_file);
@@ -830,15 +735,15 @@ static int qcow_create2(const char *filename, int64_t total_size,
if (backing_file) {
if (backing_format_len) {
char zero[16];
int padding = rounded_ext_bf_len - (ext_bf.len + sizeof(ext_bf));
int d = ext_bf.len - backing_format_len;
memset(zero, 0, sizeof(zero));
cpu_to_be32s(&ext_bf.magic);
cpu_to_be32s(&ext_bf.len);
write(fd, &ext_bf, sizeof(ext_bf));
write(fd, backing_format, backing_format_len);
if (padding > 0) {
write(fd, zero, padding);
if (d>0) {
write(fd, zero, d);
}
}
write(fd, backing_file, backing_filename_len);
@@ -857,16 +762,6 @@ static int qcow_create2(const char *filename, int64_t total_size,
qemu_free(s->refcount_table);
qemu_free(s->refcount_block);
close(fd);
/* Preallocate metadata */
if (prealloc) {
BlockDriverState *bs;
bs = bdrv_new("");
bdrv_open(bs, filename, BDRV_O_CACHE_WB);
preallocate(bs);
bdrv_close(bs);
}
return 0;
}
@@ -877,7 +772,6 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
uint64_t sectors = 0;
int flags = 0;
size_t cluster_size = 65536;
int prealloc = 0;
/* Read out options */
while (options && options->name) {
@@ -893,28 +787,12 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
if (options->value.n) {
cluster_size = options->value.n;
}
} else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
if (!options->value.s || !strcmp(options->value.s, "off")) {
prealloc = 0;
} else if (!strcmp(options->value.s, "metadata")) {
prealloc = 1;
} else {
fprintf(stderr, "Invalid preallocation mode: '%s'\n",
options->value.s);
return -EINVAL;
}
}
options++;
}
if (backing_file && prealloc) {
fprintf(stderr, "Backing file and preallocation cannot be used at "
"the same time\n");
return -EINVAL;
}
return qcow_create2(filename, sectors, backing_file, backing_fmt, flags,
cluster_size, prealloc);
cluster_size);
}
static int qcow_make_empty(BlockDriverState *bs)
@@ -1104,11 +982,6 @@ static QEMUOptionParameter qcow_create_options[] = {
.type = OPT_SIZE,
.help = "qcow2 cluster size"
},
{
.name = BLOCK_OPT_PREALLOC,
.type = OPT_STRING,
.help = "Preallocation mode (allowed values: off, metadata)"
},
{ NULL }
};

View File

@@ -47,7 +47,7 @@
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
#define MIN_CLUSTER_BITS 9
#define MAX_CLUSTER_BITS 21
#define MAX_CLUSTER_BITS 16
#define L2_CACHE_SIZE 16
@@ -98,7 +98,6 @@ typedef struct BDRVQcowState {
uint8_t *cluster_cache;
uint8_t *cluster_data;
uint64_t cluster_cache_offset;
QLIST_HEAD(QCowClusterAlloc, QCowL2Meta) cluster_allocs;
uint64_t *refcount_table;
uint64_t refcount_table_offset;
@@ -129,8 +128,6 @@ typedef struct QCowCreateState {
int64_t refcount_block_offset;
} QCowCreateState;
struct QCowAIOCB;
/* XXX This could be private for qcow2-cluster.c */
typedef struct QCowL2Meta
{
@@ -138,10 +135,6 @@ typedef struct QCowL2Meta
int n_start;
int nb_available;
int nb_clusters;
struct QCowL2Meta *depends_on;
QLIST_HEAD(QCowAioDependencies, QCowAIOCB) dependent_requests;
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)

View File

@@ -1,43 +0,0 @@
/*
* QEMU Posix block I/O backend AIO support
*
* Copyright IBM, Corp. 2008
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#ifndef QEMU_RAW_POSIX_AIO_H
#define QEMU_RAW_POSIX_AIO_H
/* AIO request types */
#define QEMU_AIO_READ 0x0001
#define QEMU_AIO_WRITE 0x0002
#define QEMU_AIO_IOCTL 0x0004
#define QEMU_AIO_FLUSH 0x0008
#define QEMU_AIO_TYPE_MASK \
(QEMU_AIO_READ|QEMU_AIO_WRITE|QEMU_AIO_IOCTL|QEMU_AIO_FLUSH)
/* AIO flags */
#define QEMU_AIO_MISALIGNED 0x1000
/* posix-aio-compat.c - thread pool based implementation */
int paio_init(void);
BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque);
/* linux-aio.c - Linux native implementation */
void *laio_init(void);
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type);
#endif /* QEMU_RAW_POSIX_AIO_H */

View File

@@ -27,7 +27,9 @@
#include "qemu-log.h"
#include "block_int.h"
#include "module.h"
#include "block/raw-posix-aio.h"
#ifdef CONFIG_AIO
#include "posix-aio-compat.h"
#endif
#ifdef CONFIG_COCOA
#include <paths.h>
@@ -51,7 +53,7 @@
#include <linux/cdrom.h>
#include <linux/fd.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
#include <signal.h>
#include <sys/disk.h>
#include <sys/cdio.h>
@@ -113,18 +115,16 @@ typedef struct BDRVRawState {
int64_t fd_error_time;
int fd_got_error;
int fd_media_changed;
#endif
#ifdef CONFIG_LINUX_AIO
int use_aio;
void *aio_ctx;
#endif
uint8_t* aligned_buf;
} BDRVRawState;
static int posix_aio_init(void);
static int fd_open(BlockDriverState *bs);
static int64_t raw_getlength(BlockDriverState *bs);
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#if defined(__FreeBSD__)
static int cdrom_reopen(BlockDriverState *bs);
#endif
@@ -134,6 +134,8 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
BDRVRawState *s = bs->opaque;
int fd, ret;
posix_aio_init();
s->lseek_err_cnt = 0;
s->open_flags = open_flags | O_BINARY;
@@ -153,7 +155,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
s->open_flags |= O_DSYNC;
s->fd = -1;
fd = qemu_open(filename, s->open_flags, 0644);
fd = open(filename, s->open_flags, 0644);
if (fd < 0) {
ret = -errno;
if (ret == -EROFS)
@@ -162,44 +164,15 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
}
s->fd = fd;
s->aligned_buf = NULL;
if ((bdrv_flags & BDRV_O_NOCACHE)) {
s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE);
if (s->aligned_buf == NULL) {
goto out_close;
ret = -errno;
close(fd);
return ret;
}
}
#ifdef CONFIG_LINUX_AIO
if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
(BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
/* We're falling back to POSIX AIO in some cases */
paio_init();
s->aio_ctx = laio_init();
if (!s->aio_ctx) {
goto out_free_buf;
}
s->use_aio = 1;
} else
#endif
{
if (paio_init() < 0) {
goto out_free_buf;
}
#ifdef CONFIG_LINUX_AIO
s->use_aio = 0;
#endif
}
return 0;
out_free_buf:
qemu_vfree(s->aligned_buf);
out_close:
close(fd);
return -errno;
}
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
@@ -516,77 +489,249 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
return ret;
}
/*
* Check if all memory in this vector is sector aligned.
*/
static int qiov_is_aligned(QEMUIOVector *qiov)
{
int i;
#ifdef CONFIG_AIO
/***********************************************************/
/* Unix AIO using POSIX AIO */
for (i = 0; i < qiov->niov; i++) {
if ((uintptr_t) qiov->iov[i].iov_base % 512) {
return 0;
}
typedef struct RawAIOCB {
BlockDriverAIOCB common;
struct qemu_paiocb aiocb;
struct RawAIOCB *next;
int ret;
} RawAIOCB;
typedef struct PosixAioState
{
int rfd, wfd;
RawAIOCB *first_aio;
} PosixAioState;
static void posix_aio_read(void *opaque)
{
PosixAioState *s = opaque;
RawAIOCB *acb, **pacb;
int ret;
ssize_t len;
/* read all bytes from signal pipe */
for (;;) {
char bytes[16];
len = read(s->rfd, bytes, sizeof(bytes));
if (len == -1 && errno == EINTR)
continue; /* try again */
if (len == sizeof(bytes))
continue; /* more to read */
break;
}
return 1;
for(;;) {
pacb = &s->first_aio;
for(;;) {
acb = *pacb;
if (!acb)
goto the_end;
ret = qemu_paio_error(&acb->aiocb);
if (ret == ECANCELED) {
/* remove the request */
*pacb = acb->next;
qemu_aio_release(acb);
} else if (ret != EINPROGRESS) {
/* end of aio */
if (ret == 0) {
ret = qemu_paio_return(&acb->aiocb);
if (ret == acb->aiocb.aio_nbytes)
ret = 0;
else
ret = -EINVAL;
} else {
ret = -ret;
}
/* remove the request */
*pacb = acb->next;
/* call the callback */
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
break;
} else {
pacb = &acb->next;
}
}
}
the_end: ;
}
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int type)
static int posix_aio_flush(void *opaque)
{
PosixAioState *s = opaque;
return !!s->first_aio;
}
static PosixAioState *posix_aio_state;
static void aio_signal_handler(int signum)
{
if (posix_aio_state) {
char byte = 0;
write(posix_aio_state->wfd, &byte, sizeof(byte));
}
qemu_service_io();
}
static int posix_aio_init(void)
{
struct sigaction act;
PosixAioState *s;
int fds[2];
struct qemu_paioinit ai;
if (posix_aio_state)
return 0;
s = qemu_malloc(sizeof(PosixAioState));
sigfillset(&act.sa_mask);
act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
act.sa_handler = aio_signal_handler;
sigaction(SIGUSR2, &act, NULL);
s->first_aio = NULL;
if (pipe(fds) == -1) {
fprintf(stderr, "failed to create pipe\n");
return -errno;
}
s->rfd = fds[0];
s->wfd = fds[1];
fcntl(s->rfd, F_SETFL, O_NONBLOCK);
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
memset(&ai, 0, sizeof(ai));
ai.aio_threads = 64;
ai.aio_num = 64;
qemu_paio_init(&ai);
posix_aio_state = s;
return 0;
}
static void raw_aio_remove(RawAIOCB *acb)
{
RawAIOCB **pacb;
/* remove the callback from the queue */
pacb = &posix_aio_state->first_aio;
for(;;) {
if (*pacb == NULL) {
fprintf(stderr, "raw_aio_remove: aio request not found!\n");
break;
} else if (*pacb == acb) {
*pacb = acb->next;
qemu_aio_release(acb);
break;
}
pacb = &(*pacb)->next;
}
}
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
{
int ret;
RawAIOCB *acb = (RawAIOCB *)blockacb;
ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
if (ret == QEMU_PAIO_NOTCANCELED) {
/* fail safe: if the aio could not be canceled, we wait for
it */
while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
}
raw_aio_remove(acb);
}
static AIOPool raw_aio_pool = {
.aiocb_size = sizeof(RawAIOCB),
.cancel = raw_aio_cancel,
};
static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
RawAIOCB *acb;
if (fd_open(bs) < 0)
return NULL;
acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->aiocb.aio_fildes = s->fd;
acb->aiocb.ev_signo = SIGUSR2;
acb->aiocb.aio_iov = qiov->iov;
acb->aiocb.aio_niov = qiov->niov;
acb->aiocb.aio_nbytes = nb_sectors * 512;
acb->aiocb.aio_offset = sector_num * 512;
acb->aiocb.aio_flags = 0;
/*
* If O_DIRECT is used the buffer needs to be aligned on a sector
* boundary. Check if this is the case or telll the low-level
* driver that it needs to copy the buffer.
* boundary. Tell the low level code to ensure that in case it's
* not done yet.
*/
if (s->aligned_buf) {
if (!qiov_is_aligned(qiov)) {
type |= QEMU_AIO_MISALIGNED;
#ifdef CONFIG_LINUX_AIO
} else if (s->use_aio) {
return laio_submit(bs, s->aio_ctx, s->fd, sector_num, qiov,
nb_sectors, cb, opaque, type);
#endif
}
}
if (s->aligned_buf)
acb->aiocb.aio_flags |= QEMU_AIO_SECTOR_ALIGNED;
return paio_submit(bs, s->fd, sector_num, qiov, nb_sectors,
cb, opaque, type);
acb->next = posix_aio_state->first_aio;
posix_aio_state->first_aio = acb;
return acb;
}
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_READ);
RawAIOCB *acb;
acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
if (!acb)
return NULL;
if (qemu_paio_read(&acb->aiocb) < 0) {
raw_aio_remove(acb);
return NULL;
}
return &acb->common;
}
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
cb, opaque, QEMU_AIO_WRITE);
}
RawAIOCB *acb;
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
if (fd_open(bs) < 0)
acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
if (!acb)
return NULL;
return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
if (qemu_paio_write(&acb->aiocb) < 0) {
raw_aio_remove(acb);
return NULL;
}
return &acb->common;
}
#else /* CONFIG_AIO */
static int posix_aio_init(void)
{
return 0;
}
#endif /* CONFIG_AIO */
static void raw_close(BlockDriverState *bs)
{
@@ -634,9 +779,9 @@ static int64_t raw_getlength(BlockDriverState *bs)
BDRVRawState *s = bs->opaque;
int fd = s->fd;
int64_t size;
#ifdef CONFIG_BSD
#ifdef HOST_BSD
struct stat sb;
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
int reopened = 0;
#endif
#endif
@@ -650,8 +795,8 @@ static int64_t raw_getlength(BlockDriverState *bs)
if (ret < 0)
return ret;
#ifdef CONFIG_BSD
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef HOST_BSD
#ifdef __FreeBSD__
again:
#endif
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
@@ -672,7 +817,7 @@ again:
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
switch(s->type) {
case FTYPE_CD:
/* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
@@ -737,7 +882,7 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
qemu_fdatasync(s->fd);
fsync(s->fd);
}
@@ -761,9 +906,10 @@ static BlockDriver bdrv_raw = {
.bdrv_create = raw_create,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
#endif
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
@@ -880,7 +1026,7 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
#endif
s->type = FTYPE_FILE;
#if defined(__linux__)
#if defined(__linux__) && defined(CONFIG_AIO)
if (strstart(filename, "/dev/sg", NULL)) {
bs->sg = 1;
}
@@ -946,18 +1092,40 @@ static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return ioctl(s->fd, req, buf);
}
#ifdef CONFIG_AIO
static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
unsigned long int req, void *buf,
BlockDriverCompletionFunc *cb, void *opaque)
{
BDRVRawState *s = bs->opaque;
RawAIOCB *acb;
if (fd_open(bs) < 0)
return NULL;
return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
if (!acb)
return NULL;
acb->aiocb.aio_fildes = s->fd;
acb->aiocb.ev_signo = SIGUSR2;
acb->aiocb.aio_offset = 0;
acb->aiocb.aio_flags = 0;
acb->next = posix_aio_state->first_aio;
posix_aio_state->first_aio = acb;
acb->aiocb.aio_ioctl_buf = buf;
acb->aiocb.aio_ioctl_cmd = req;
if (qemu_paio_ioctl(&acb->aiocb) < 0) {
raw_aio_remove(acb);
return NULL;
}
return &acb->common;
}
#endif
#elif defined(__FreeBSD__)
static int fd_open(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
@@ -1007,19 +1175,18 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
}
static BlockDriver bdrv_host_device = {
.format_name = "host_device",
.instance_size = sizeof(BDRVRawState),
.bdrv_probe_device = hdev_probe_device,
.bdrv_open = hdev_open,
.bdrv_close = raw_close,
.format_name = "host_device",
.instance_size = sizeof(BDRVRawState),
.bdrv_probe_device = hdev_probe_device,
.bdrv_open = hdev_open,
.bdrv_close = raw_close,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.no_zero_init = 1,
.bdrv_flush = raw_flush,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
#endif
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1028,8 +1195,10 @@ static BlockDriver bdrv_host_device = {
/* generic scsi device */
#ifdef __linux__
.bdrv_ioctl = hdev_ioctl,
#ifdef CONFIG_AIO
.bdrv_aio_ioctl = hdev_aio_ioctl,
#endif
#endif
};
#ifdef __linux__
@@ -1038,6 +1207,8 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
BDRVRawState *s = bs->opaque;
int ret;
posix_aio_init();
s->type = FTYPE_FD;
/* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
@@ -1110,13 +1281,12 @@ static BlockDriver bdrv_host_floppy = {
.bdrv_open = floppy_open,
.bdrv_close = raw_close,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.no_zero_init = 1,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
#endif
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1193,13 +1363,12 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.no_zero_init = 1,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
#endif
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1212,11 +1381,13 @@ static BlockDriver bdrv_host_cdrom = {
/* generic scsi device */
.bdrv_ioctl = hdev_ioctl,
#ifdef CONFIG_AIO
.bdrv_aio_ioctl = hdev_aio_ioctl,
#endif
};
#endif /* __linux__ */
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
@@ -1315,13 +1486,12 @@ static BlockDriver bdrv_host_cdrom = {
.bdrv_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_create = hdev_create,
.create_options = raw_create_options,
.no_zero_init = 1,
.bdrv_flush = raw_flush,
#ifdef CONFIG_AIO
.bdrv_aio_readv = raw_aio_readv,
.bdrv_aio_writev = raw_aio_writev,
.bdrv_aio_flush = raw_aio_flush,
#endif
.bdrv_read = raw_read,
.bdrv_write = raw_write,
@@ -1346,7 +1516,7 @@ static void bdrv_raw_init(void)
bdrv_register(&bdrv_host_floppy);
bdrv_register(&bdrv_host_cdrom);
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
bdrv_register(&bdrv_host_cdrom);
#endif
}

View File

@@ -1,956 +0,0 @@
/*
* Block driver for the Virtual Disk Image (VDI) format
*
* Copyright (c) 2009 Stefan Weil
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) version 3 or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Reference:
* http://forums.virtualbox.org/viewtopic.php?t=8046
*
* This driver supports create / read / write operations on VDI images.
*
* Todo (see also TODO in code):
*
* Some features like snapshots are still missing.
*
* Deallocation of zero-filled blocks and shrinking images are missing, too
* (might be added to common block layer).
*
* Allocation of blocks could be optimized (less writes to block map and
* header).
*
* Read and write of adjacents blocks could be done in one operation
* (current code uses one operation per block (1 MiB).
*
* The code is not thread safe (missing locks for changes in header and
* block table, no problem with current QEMU).
*
* Hints:
*
* Blocks (VDI documentation) correspond to clusters (QEMU).
* QEMU's backing files could be implemented using VDI snapshot files (TODO).
* VDI snapshot files may also contain the complete machine state.
* Maybe this machine state can be converted to QEMU PC machine snapshot data.
*
* The driver keeps a block cache (little endian entries) in memory.
* For the standard block size (1 MiB), a 1 TiB disk will use 4 MiB RAM,
* so this seems to be reasonable.
*/
#include "qemu-common.h"
#include "block_int.h"
#include "module.h"
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#else
/* TODO: move uuid emulation to some central place in QEMU. */
#include "sysemu.h" /* UUID_FMT */
typedef unsigned char uuid_t[16];
void uuid_generate(uuid_t out);
int uuid_is_null(const uuid_t uu);
void uuid_unparse(const uuid_t uu, char *out);
#endif
/* Code configuration options. */
/* Enable debug messages. */
//~ #define CONFIG_VDI_DEBUG
/* Support write operations on VDI images. */
#define CONFIG_VDI_WRITE
/* Support non-standard block (cluster) size. This is untested.
* Maybe it will be needed for very large images.
*/
//~ #define CONFIG_VDI_BLOCK_SIZE
/* Support static (fixed, pre-allocated) images. */
#define CONFIG_VDI_STATIC_IMAGE
/* Command line option for static images. */
#define BLOCK_OPT_STATIC "static"
#define KiB 1024
#define MiB (KiB * KiB)
#define SECTOR_SIZE 512
#if defined(CONFIG_VDI_DEBUG)
#define logout(fmt, ...) \
fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
#else
#define logout(fmt, ...) ((void)0)
#endif
/* Image signature. */
#define VDI_SIGNATURE 0xbeda107f
/* Image version. */
#define VDI_VERSION_1_1 0x00010001
/* Image type. */
#define VDI_TYPE_DYNAMIC 1
#define VDI_TYPE_STATIC 2
/* Innotek / SUN images use these strings in header.text:
* "<<< innotek VirtualBox Disk Image >>>\n"
* "<<< Sun xVM VirtualBox Disk Image >>>\n"
* "<<< Sun VirtualBox Disk Image >>>\n"
* The value does not matter, so QEMU created images use a different text.
*/
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
/* Unallocated blocks use this index (no need to convert endianess). */
#define VDI_UNALLOCATED UINT32_MAX
#if !defined(CONFIG_UUID)
void uuid_generate(uuid_t out)
{
memset(out, 0, sizeof(out));
}
int uuid_is_null(const uuid_t uu)
{
uuid_t null_uuid = { 0 };
return memcmp(uu, null_uuid, sizeof(uu)) == 0;
}
void uuid_unparse(const uuid_t uu, char *out)
{
snprintf(out, 37, UUID_FMT,
uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
}
#endif
typedef struct {
BlockDriverAIOCB common;
int64_t sector_num;
QEMUIOVector *qiov;
uint8_t *buf;
/* Total number of sectors. */
int nb_sectors;
/* Number of sectors for current AIO. */
int n_sectors;
/* New allocated block map entry. */
uint32_t bmap_first;
uint32_t bmap_last;
/* Buffer for new allocated block. */
void *block_buffer;
void *orig_buf;
int header_modified;
BlockDriverAIOCB *hd_aiocb;
struct iovec hd_iov;
QEMUIOVector hd_qiov;
QEMUBH *bh;
} VdiAIOCB;
typedef struct {
char text[0x40];
uint32_t signature;
uint32_t version;
uint32_t header_size;
uint32_t image_type;
uint32_t image_flags;
char description[256];
uint32_t offset_bmap;
uint32_t offset_data;
uint32_t cylinders; /* disk geometry, unused here */
uint32_t heads; /* disk geometry, unused here */
uint32_t sectors; /* disk geometry, unused here */
uint32_t sector_size;
uint32_t unused1;
uint64_t disk_size;
uint32_t block_size;
uint32_t block_extra; /* unused here */
uint32_t blocks_in_image;
uint32_t blocks_allocated;
uuid_t uuid_image;
uuid_t uuid_last_snap;
uuid_t uuid_link;
uuid_t uuid_parent;
uint64_t unused2[7];
} VdiHeader;
typedef struct {
BlockDriverState *hd;
/* The block map entries are little endian (even in memory). */
uint32_t *bmap;
/* Size of block (bytes). */
uint32_t block_size;
/* Size of block (sectors). */
uint32_t block_sectors;
/* First sector of block map. */
uint32_t bmap_sector;
/* VDI header (converted to host endianess). */
VdiHeader header;
} BDRVVdiState;
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
* format (network byte order, standard, see RFC 4122) and vice versa.
*/
static void uuid_convert(uuid_t uuid)
{
bswap32s((uint32_t *)&uuid[0]);
bswap16s((uint16_t *)&uuid[4]);
bswap16s((uint16_t *)&uuid[6]);
}
static void vdi_header_to_cpu(VdiHeader *header)
{
le32_to_cpus(&header->signature);
le32_to_cpus(&header->version);
le32_to_cpus(&header->header_size);
le32_to_cpus(&header->image_type);
le32_to_cpus(&header->image_flags);
le32_to_cpus(&header->offset_bmap);
le32_to_cpus(&header->offset_data);
le32_to_cpus(&header->cylinders);
le32_to_cpus(&header->heads);
le32_to_cpus(&header->sectors);
le32_to_cpus(&header->sector_size);
le64_to_cpus(&header->disk_size);
le32_to_cpus(&header->block_size);
le32_to_cpus(&header->block_extra);
le32_to_cpus(&header->blocks_in_image);
le32_to_cpus(&header->blocks_allocated);
uuid_convert(header->uuid_image);
uuid_convert(header->uuid_last_snap);
uuid_convert(header->uuid_link);
uuid_convert(header->uuid_parent);
}
static void vdi_header_to_le(VdiHeader *header)
{
cpu_to_le32s(&header->signature);
cpu_to_le32s(&header->version);
cpu_to_le32s(&header->header_size);
cpu_to_le32s(&header->image_type);
cpu_to_le32s(&header->image_flags);
cpu_to_le32s(&header->offset_bmap);
cpu_to_le32s(&header->offset_data);
cpu_to_le32s(&header->cylinders);
cpu_to_le32s(&header->heads);
cpu_to_le32s(&header->sectors);
cpu_to_le32s(&header->sector_size);
cpu_to_le64s(&header->disk_size);
cpu_to_le32s(&header->block_size);
cpu_to_le32s(&header->block_extra);
cpu_to_le32s(&header->blocks_in_image);
cpu_to_le32s(&header->blocks_allocated);
cpu_to_le32s(&header->blocks_allocated);
uuid_convert(header->uuid_image);
uuid_convert(header->uuid_last_snap);
uuid_convert(header->uuid_link);
uuid_convert(header->uuid_parent);
}
#if defined(CONFIG_VDI_DEBUG)
static void vdi_header_print(VdiHeader *header)
{
char uuid[37];
logout("text %s", header->text);
logout("signature 0x%04x\n", header->signature);
logout("header size 0x%04x\n", header->header_size);
logout("image type 0x%04x\n", header->image_type);
logout("image flags 0x%04x\n", header->image_flags);
logout("description %s\n", header->description);
logout("offset bmap 0x%04x\n", header->offset_bmap);
logout("offset data 0x%04x\n", header->offset_data);
logout("cylinders 0x%04x\n", header->cylinders);
logout("heads 0x%04x\n", header->heads);
logout("sectors 0x%04x\n", header->sectors);
logout("sector size 0x%04x\n", header->sector_size);
logout("image size 0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
header->disk_size, header->disk_size / MiB);
logout("block size 0x%04x\n", header->block_size);
logout("block extra 0x%04x\n", header->block_extra);
logout("blocks tot. 0x%04x\n", header->blocks_in_image);
logout("blocks all. 0x%04x\n", header->blocks_allocated);
uuid_unparse(header->uuid_image, uuid);
logout("uuid image %s\n", uuid);
uuid_unparse(header->uuid_last_snap, uuid);
logout("uuid snap %s\n", uuid);
uuid_unparse(header->uuid_link, uuid);
logout("uuid link %s\n", uuid);
uuid_unparse(header->uuid_parent, uuid);
logout("uuid parent %s\n", uuid);
}
#endif
static int vdi_check(BlockDriverState *bs)
{
/* TODO: additional checks possible. */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
int n_errors = 0;
uint32_t blocks_allocated = 0;
uint32_t block;
uint32_t *bmap;
logout("\n");
bmap = qemu_malloc(s->header.blocks_in_image * sizeof(uint32_t));
memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
/* Check block map and value of blocks_allocated. */
for (block = 0; block < s->header.blocks_in_image; block++) {
uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
if (bmap_entry != VDI_UNALLOCATED) {
if (bmap_entry < s->header.blocks_in_image) {
blocks_allocated++;
if (bmap[bmap_entry] == VDI_UNALLOCATED) {
bmap[bmap_entry] = bmap_entry;
} else {
fprintf(stderr, "ERROR: block index %" PRIu32
" also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
}
} else {
fprintf(stderr, "ERROR: block index %" PRIu32
" too large, is %" PRIu32 "\n", block, bmap_entry);
n_errors++;
}
}
}
if (blocks_allocated != s->header.blocks_allocated) {
fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
", should be %" PRIu32 "\n",
blocks_allocated, s->header.blocks_allocated);
n_errors++;
}
qemu_free(bmap);
return n_errors;
}
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
{
/* TODO: vdi_get_info would be needed for machine snapshots.
vm_state_offset is still missing. */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
logout("\n");
bdi->cluster_size = s->block_size;
bdi->vm_state_offset = 0;
return 0;
}
static int vdi_make_empty(BlockDriverState *bs)
{
/* TODO: missing code. */
logout("\n");
/* The return value for missing code must be 0, see block.c. */
return 0;
}
static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const VdiHeader *header = (const VdiHeader *)buf;
int result = 0;
logout("\n");
if (buf_size < sizeof(*header)) {
/* Header too small, no VDI. */
} else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
result = 100;
}
if (result == 0) {
logout("no vdi image\n");
} else {
logout("%s", header->text);
}
return result;
}
static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVdiState *s = bs->opaque;
VdiHeader header;
size_t bmap_size;
int ret;
logout("\n");
ret = bdrv_file_open(&s->hd, filename, flags);
if (ret < 0) {
return ret;
}
if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) {
goto fail;
}
vdi_header_to_cpu(&header);
#if defined(CONFIG_VDI_DEBUG)
vdi_header_print(&header);
#endif
if (header.version != VDI_VERSION_1_1) {
logout("unsupported version %u.%u\n",
header.version >> 16, header.version & 0xffff);
goto fail;
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
/* We only support block maps which start on a sector boundary. */
logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
goto fail;
} else if (header.offset_data % SECTOR_SIZE != 0) {
/* We only support data blocks which start on a sector boundary. */
logout("unsupported data offset 0x%x B\n", header.offset_data);
goto fail;
} else if (header.sector_size != SECTOR_SIZE) {
logout("unsupported sector size %u B\n", header.sector_size);
goto fail;
} else if (header.block_size != 1 * MiB) {
logout("unsupported block size %u B\n", header.block_size);
goto fail;
} else if (header.disk_size !=
(uint64_t)header.blocks_in_image * header.block_size) {
logout("unexpected block number %u B\n", header.blocks_in_image);
goto fail;
} else if (!uuid_is_null(header.uuid_link)) {
logout("link uuid != 0, unsupported\n");
goto fail;
} else if (!uuid_is_null(header.uuid_parent)) {
logout("parent uuid != 0, unsupported\n");
goto fail;
}
bs->total_sectors = header.disk_size / SECTOR_SIZE;
s->block_size = header.block_size;
s->block_sectors = header.block_size / SECTOR_SIZE;
s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
s->header = header;
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
goto fail_free_bmap;
}
return 0;
fail_free_bmap:
qemu_free(s->bmap);
fail:
bdrv_delete(s->hd);
return -1;
}
static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum)
{
/* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
size_t bmap_index = sector_num / s->block_sectors;
size_t sector_in_block = sector_num % s->block_sectors;
int n_sectors = s->block_sectors - sector_in_block;
uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
if (n_sectors > nb_sectors) {
n_sectors = nb_sectors;
}
*pnum = n_sectors;
return bmap_entry != VDI_UNALLOCATED;
}
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
{
/* TODO: This code is untested. How can I get it executed? */
VdiAIOCB *acb = (VdiAIOCB *)blockacb;
logout("\n");
if (acb->hd_aiocb) {
bdrv_aio_cancel(acb->hd_aiocb);
}
qemu_aio_release(acb);
}
static AIOPool vdi_aio_pool = {
.aiocb_size = sizeof(VdiAIOCB),
.cancel = vdi_aio_cancel,
};
static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque, int is_write)
{
VdiAIOCB *acb;
logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
acb = qemu_aio_get(&vdi_aio_pool, bs, cb, opaque);
if (acb) {
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
if (qiov->niov > 1) {
acb->buf = qemu_blockalign(bs, qiov->size);
acb->orig_buf = acb->buf;
if (is_write) {
qemu_iovec_to_buffer(qiov, acb->buf);
}
} else {
acb->buf = (uint8_t *)qiov->iov->iov_base;
}
acb->nb_sectors = nb_sectors;
acb->n_sectors = 0;
acb->bmap_first = VDI_UNALLOCATED;
acb->bmap_last = VDI_UNALLOCATED;
acb->block_buffer = NULL;
acb->header_modified = 0;
}
return acb;
}
static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
{
logout("\n");
if (acb->bh) {
return -EIO;
}
acb->bh = qemu_bh_new(cb, acb);
if (!acb->bh) {
return -EIO;
}
qemu_bh_schedule(acb->bh);
return 0;
}
static void vdi_aio_read_cb(void *opaque, int ret);
static void vdi_aio_read_bh(void *opaque)
{
VdiAIOCB *acb = opaque;
logout("\n");
qemu_bh_delete(acb->bh);
acb->bh = NULL;
vdi_aio_read_cb(opaque, 0);
}
static void vdi_aio_read_cb(void *opaque, int ret)
{
VdiAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
logout("%u sectors read\n", acb->n_sectors);
acb->hd_aiocb = NULL;
if (ret < 0) {
goto done;
}
acb->nb_sectors -= acb->n_sectors;
if (acb->nb_sectors == 0) {
/* request completed */
ret = 0;
goto done;
}
acb->sector_num += acb->n_sectors;
acb->buf += acb->n_sectors * SECTOR_SIZE;
block_index = acb->sector_num / s->block_sectors;
sector_in_block = acb->sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
if (n_sectors > acb->nb_sectors) {
n_sectors = acb->nb_sectors;
}
logout("will read %u sectors starting at sector %" PRIu64 "\n",
n_sectors, acb->sector_num);
/* prepare next AIO request */
acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (bmap_entry == VDI_UNALLOCATED) {
/* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
if (ret < 0) {
goto done;
}
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(s->hd, offset, &acb->hd_qiov,
n_sectors, vdi_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
}
}
return;
done:
if (acb->qiov->niov > 1) {
qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
qemu_vfree(acb->orig_buf);
}
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
}
static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb) {
return NULL;
}
vdi_aio_read_cb(acb, 0);
return &acb->common;
}
static void vdi_aio_write_cb(void *opaque, int ret)
{
VdiAIOCB *acb = opaque;
BlockDriverState *bs = acb->common.bs;
BDRVVdiState *s = bs->opaque;
uint32_t bmap_entry;
uint32_t block_index;
uint32_t sector_in_block;
uint32_t n_sectors;
acb->hd_aiocb = NULL;
if (ret < 0) {
goto done;
}
acb->nb_sectors -= acb->n_sectors;
acb->sector_num += acb->n_sectors;
acb->buf += acb->n_sectors * SECTOR_SIZE;
if (acb->nb_sectors == 0) {
logout("finished data write\n");
acb->n_sectors = 0;
if (acb->header_modified) {
VdiHeader *header = acb->block_buffer;
logout("now writing modified header\n");
assert(acb->bmap_first != VDI_UNALLOCATED);
*header = s->header;
vdi_header_to_le(header);
acb->header_modified = 0;
acb->hd_iov.iov_base = acb->block_buffer;
acb->hd_iov.iov_len = SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1,
vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
}
return;
} else if (acb->bmap_first != VDI_UNALLOCATED) {
/* One or more new blocks were allocated. */
uint64_t offset;
uint32_t bmap_first;
uint32_t bmap_last;
qemu_free(acb->block_buffer);
acb->block_buffer = NULL;
bmap_first = acb->bmap_first;
bmap_last = acb->bmap_last;
logout("now writing modified block map entry %u...%u\n",
bmap_first, bmap_last);
/* Write modified sectors from block map. */
bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
n_sectors = bmap_last - bmap_first + 1;
offset = s->bmap_sector + bmap_first;
acb->bmap_first = VDI_UNALLOCATED;
acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
bmap_first * SECTOR_SIZE);
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first);
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
n_sectors, vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
}
return;
}
ret = 0;
goto done;
}
logout("%u sectors written\n", acb->n_sectors);
block_index = acb->sector_num / s->block_sectors;
sector_in_block = acb->sector_num % s->block_sectors;
n_sectors = s->block_sectors - sector_in_block;
if (n_sectors > acb->nb_sectors) {
n_sectors = acb->nb_sectors;
}
logout("will write %u sectors starting at sector %" PRIu64 "\n",
n_sectors, acb->sector_num);
/* prepare next AIO request */
acb->n_sectors = n_sectors;
bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (bmap_entry == VDI_UNALLOCATED) {
/* Allocate new block and write to it. */
uint64_t offset;
uint8_t *block;
bmap_entry = s->header.blocks_allocated;
s->bmap[block_index] = cpu_to_le32(bmap_entry);
s->header.blocks_allocated++;
offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors;
block = acb->block_buffer;
if (block == NULL) {
block = qemu_mallocz(s->block_size);
acb->block_buffer = block;
acb->bmap_first = block_index;
assert(!acb->header_modified);
acb->header_modified = 1;
}
acb->bmap_last = block_index;
memcpy(block + sector_in_block * SECTOR_SIZE,
acb->buf, n_sectors * SECTOR_SIZE);
acb->hd_iov.iov_base = (void *)block;
acb->hd_iov.iov_len = s->block_size;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset,
&acb->hd_qiov, s->block_sectors,
vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
}
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
n_sectors, vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
}
}
return;
done:
if (acb->qiov->niov > 1) {
qemu_vfree(acb->orig_buf);
}
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
}
static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb) {
return NULL;
}
vdi_aio_write_cb(acb, 0);
return &acb->common;
}
static int vdi_create(const char *filename, QEMUOptionParameter *options)
{
int fd;
int result = 0;
uint64_t bytes = 0;
uint32_t blocks;
size_t block_size = 1 * MiB;
uint32_t image_type = VDI_TYPE_DYNAMIC;
VdiHeader header;
size_t i;
size_t bmap_size;
uint32_t *bmap;
logout("\n");
/* Read out options. */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
bytes = options->value.n;
#if defined(CONFIG_VDI_BLOCK_SIZE)
} else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
if (options->value.n) {
/* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
block_size = options->value.n;
}
#endif
#if defined(CONFIG_VDI_STATIC_IMAGE)
} else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
if (options->value.n) {
image_type = VDI_TYPE_STATIC;
}
#endif
}
options++;
}
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0) {
return -errno;
}
blocks = bytes / block_size;
bmap_size = blocks * sizeof(uint32_t);
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
memset(&header, 0, sizeof(header));
pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
header.signature = VDI_SIGNATURE;
header.version = VDI_VERSION_1_1;
header.header_size = 0x180;
header.image_type = image_type;
header.offset_bmap = 0x200;
header.offset_data = 0x200 + bmap_size;
header.sector_size = SECTOR_SIZE;
header.disk_size = bytes;
header.block_size = block_size;
header.blocks_in_image = blocks;
if (image_type == VDI_TYPE_STATIC) {
header.blocks_allocated = blocks;
}
uuid_generate(header.uuid_image);
uuid_generate(header.uuid_last_snap);
/* There is no need to set header.uuid_link or header.uuid_parent here. */
#if defined(CONFIG_VDI_DEBUG)
vdi_header_print(&header);
#endif
vdi_header_to_le(&header);
if (write(fd, &header, sizeof(header)) < 0) {
result = -errno;
}
bmap = (uint32_t *)qemu_mallocz(bmap_size);
for (i = 0; i < blocks; i++) {
if (image_type == VDI_TYPE_STATIC) {
bmap[i] = i;
} else {
bmap[i] = VDI_UNALLOCATED;
}
}
if (write(fd, bmap, bmap_size) < 0) {
result = -errno;
}
qemu_free(bmap);
if (image_type == VDI_TYPE_STATIC) {
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
result = -errno;
}
}
if (close(fd) < 0) {
result = -errno;
}
return result;
}
static void vdi_close(BlockDriverState *bs)
{
BDRVVdiState *s = bs->opaque;
logout("\n");
bdrv_delete(s->hd);
}
static void vdi_flush(BlockDriverState *bs)
{
BDRVVdiState *s = bs->opaque;
logout("\n");
bdrv_flush(s->hd);
}
static QEMUOptionParameter vdi_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
.help = "Virtual disk size"
},
#if defined(CONFIG_VDI_BLOCK_SIZE)
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
.help = "VDI cluster (block) size"
},
#endif
#if defined(CONFIG_VDI_STATIC_IMAGE)
{
.name = BLOCK_OPT_STATIC,
.type = OPT_FLAG,
.help = "VDI static (pre-allocated) image"
},
#endif
/* TODO: An additional option to set UUID values might be useful. */
{ NULL }
};
static BlockDriver bdrv_vdi = {
.format_name = "vdi",
.instance_size = sizeof(BDRVVdiState),
.bdrv_probe = vdi_probe,
.bdrv_open = vdi_open,
.bdrv_close = vdi_close,
.bdrv_create = vdi_create,
.bdrv_flush = vdi_flush,
.bdrv_is_allocated = vdi_is_allocated,
.bdrv_make_empty = vdi_make_empty,
.bdrv_aio_readv = vdi_aio_readv,
#if defined(CONFIG_VDI_WRITE)
.bdrv_aio_writev = vdi_aio_writev,
#endif
.bdrv_get_info = vdi_get_info,
.create_options = vdi_create_options,
.bdrv_check = vdi_check,
};
static void bdrv_vdi_init(void)
{
logout("\n");
bdrv_register(&bdrv_vdi);
}
block_init(bdrv_vdi_init);

View File

@@ -1,5 +1,5 @@
/*
* Block driver for Connectix / Microsoft Virtual PC images
* Block driver for Conectix/Microsoft Virtual PC images
*
* Copyright (c) 2005 Alex Beregszaszi
* Copyright (c) 2009 Kevin Wolf <kwolf@suse.de>
@@ -511,10 +511,10 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
// Prepare the Hard Disk Footer
memset(buf, 0, 1024);
memcpy(footer->creator, "conectix", 8);
strncpy(footer->creator, "conectix", 8);
// TODO Check if "qemu" creator_app is ok for VPC
memcpy(footer->creator_app, "qemu", 4);
memcpy(footer->creator_os, "Wi2k", 4);
strncpy(footer->creator_app, "qemu", 4);
strncpy(footer->creator_os, "Wi2k", 4);
footer->features = be32_to_cpu(0x02);
footer->version = be32_to_cpu(0x00010000);
@@ -563,7 +563,7 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
// Prepare the Dynamic Disk Header
memset(buf, 0, 1024);
memcpy(dyndisk_header->magic, "cxsparse", 8);
strncpy(dyndisk_header->magic, "cxsparse", 8);
dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
dyndisk_header->table_offset = be64_to_cpu(3 * 512);

View File

@@ -379,7 +379,7 @@ static void init_mbr(BDRVVVFATState* s)
{
/* TODO: if the files mbr.img and bootsect.img exist, use them */
mbr_t* real_mbr=(mbr_t*)s->first_sectors;
partition_t* partition = &(real_mbr->partition[0]);
partition_t* partition=&(real_mbr->partition[0]);
int lba;
memset(s->first_sectors,0,512);
@@ -526,7 +526,7 @@ static uint16_t fat_datetime(time_t time,int return_time) {
t=localtime(&time); /* this is not thread safe */
#else
struct tm t1;
t = &t1;
t=&t1;
localtime_r(&time,t);
#endif
if(return_time)

View File

@@ -37,7 +37,6 @@
#define BLOCK_OPT_BACKING_FILE "backing_file"
#define BLOCK_OPT_BACKING_FMT "backing_fmt"
#define BLOCK_OPT_CLUSTER_SIZE "cluster_size"
#define BLOCK_OPT_PREALLOC "preallocation"
typedef struct AIOPool {
void (*cancel)(BlockDriverAIOCB *acb);
@@ -69,14 +68,6 @@ struct BlockDriver {
BlockDriverAIOCB *(*bdrv_aio_writev)(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque);
int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
int num_reqs);
int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
BlockRequest *b);
const char *protocol_name;
int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
@@ -117,9 +108,6 @@ struct BlockDriver {
/* Returns number of errors in image, -errno for internal errors */
int (*bdrv_check)(BlockDriverState* bs);
/* Set if newly created images are not guaranteed to contain only zeros */
int no_zero_init;
struct BlockDriver *next;
};
@@ -163,15 +151,11 @@ struct BlockDriverState {
/* the memory alignment required for the buffers handled by this driver */
int buffer_alignment;
/* do we need to tell the quest if we have a volatile write cache? */
int enable_write_cache;
/* NOTE: the following infos are only hints for real hardware
drivers. They are not used by the block driver */
int cyls, heads, secs, translation;
int type;
char device_name[32];
unsigned long *dirty_bitmap;
BlockDriverState *next;
void *private;
};

View File

@@ -163,7 +163,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
bprm.page[i] = NULL;
bprm.page[i] = 0;
retval = open(filename, O_RDONLY);
if (retval < 0)
return retval;

View File

@@ -126,9 +126,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
regs->rax = 0;
regs->rsp = infop->start_stack;
regs->rip = infop->entry;
if (bsd_type == target_freebsd) {
regs->rdi = infop->start_stack;
}
}
#else
@@ -252,13 +249,8 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#else
if (personality(infop->personality) == PER_LINUX32)
regs->u_regs[14] = infop->start_stack - 16 * 4;
else {
else
regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
if (bsd_type == target_freebsd) {
regs->u_regs[8] = infop->start_stack;
regs->u_regs[11] = infop->start_stack;
}
}
#endif
}
@@ -553,6 +545,8 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
memcpy(to, from, n);
}
extern unsigned long x86_stack_size;
static int load_aout_interp(void * exptr, int interp_fd);
#ifdef BSWAP_NEEDED
@@ -1020,7 +1014,7 @@ static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
key.st_value = orig_addr;
sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
if (sym != NULL) {
if (sym != 0) {
return s->disas_strtab + sym->st_name;
}
@@ -1115,10 +1109,10 @@ static void load_symbols(struct elfhdr *hdr, int fd)
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
s->lookup_symbol = lookup_symbolxx;
#else
s->disas_symtab.elf64 = syms;
s->lookup_symbol = (lookup_symbol_t)lookup_symbolxx;
s->lookup_symbol = lookup_symbolxx;
#endif
s->next = syminfos;
syminfos = s;
@@ -1254,7 +1248,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
#if 0
printf("Using ELF interpreter %s\n", path(elf_interpreter));
printf("Using ELF interpreter %s\n", elf_interpreter);
#endif
if (retval >= 0) {
retval = open(path(elf_interpreter), O_RDONLY);
@@ -1276,7 +1270,7 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
}
if (retval >= 0) {
interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
interp_elf_ex = *((struct elfhdr *) bprm->buf); /* elf exec-header */
interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
}
if (retval < 0) {
perror("load_elf_binary3");
@@ -1345,29 +1339,6 @@ int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
info->mmap = 0;
elf_entry = (abi_ulong) elf_ex.e_entry;
#if defined(CONFIG_USE_GUEST_BASE)
/*
* In case where user has not explicitly set the guest_base, we
* probe here that should we set it automatically.
*/
if (!have_guest_base) {
/*
* Go through ELF program header table and find out whether
* any of the segments drop below our current mmap_min_addr and
* in that case set guest_base to corresponding address.
*/
for (i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum;
i++, elf_ppnt++) {
if (elf_ppnt->p_type != PT_LOAD)
continue;
if (HOST_PAGE_ALIGN(elf_ppnt->p_vaddr) < mmap_min_addr) {
guest_base = HOST_PAGE_ALIGN(mmap_min_addr);
break;
}
}
}
#endif /* CONFIG_USE_GUEST_BASE */
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
info->rss = 0;

View File

@@ -39,7 +39,6 @@
{ TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
{ TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
{ TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },

View File

@@ -143,19 +143,5 @@ struct target_vm86plus_struct {
struct target_vm86plus_info_struct vm86plus;
};
/* FreeBSD sysarch(2) */
#define TARGET_FREEBSD_I386_GET_LDT 0
#define TARGET_FREEBSD_I386_SET_LDT 1
/* I386_IOPL */
#define TARGET_FREEBSD_I386_GET_IOPERM 3
#define TARGET_FREEBSD_I386_SET_IOPERM 4
/* xxxxx */
#define TARGET_FREEBSD_I386_VM86 6
#define TARGET_FREEBSD_I386_GET_FSBASE 7
#define TARGET_FREEBSD_I386_SET_FSBASE 8
#define TARGET_FREEBSD_I386_GET_GSBASE 9
#define TARGET_FREEBSD_I386_SET_GSBASE 10
#define UNAME_MACHINE "i386"

View File

@@ -31,22 +31,13 @@
/* For tb_lock */
#include "exec-all.h"
#include "envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
int singlestep;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long mmap_min_addr;
unsigned long guest_base;
int have_guest_base;
#endif
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
extern char **environ;
enum BSDType bsd_type;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
@@ -169,7 +160,7 @@ static void set_idt(int n, unsigned int dpl)
}
#endif
void cpu_loop(CPUX86State *env)
void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
{
int trapnr;
abi_ulong pc;
@@ -180,90 +171,27 @@ void cpu_loop(CPUX86State *env)
switch(trapnr) {
case 0x80:
/* syscall from int $0x80 */
if (bsd_type == target_freebsd) {
abi_ulong params = (abi_ulong) env->regs[R_ESP] +
sizeof(int32_t);
int32_t syscall_nr = env->regs[R_EAX];
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
get_user_s32(syscall_nr, params);
params += sizeof(int32_t);
} else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
get_user_s32(syscall_nr, params);
params += sizeof(int64_t);
}
get_user_s32(arg1, params);
params += sizeof(int32_t);
get_user_s32(arg2, params);
params += sizeof(int32_t);
get_user_s32(arg3, params);
params += sizeof(int32_t);
get_user_s32(arg4, params);
params += sizeof(int32_t);
get_user_s32(arg5, params);
params += sizeof(int32_t);
get_user_s32(arg6, params);
params += sizeof(int32_t);
get_user_s32(arg7, params);
params += sizeof(int32_t);
get_user_s32(arg8, params);
env->regs[R_EAX] = do_freebsd_syscall(env,
syscall_nr,
arg1,
arg2,
arg3,
arg4,
arg5,
arg6,
arg7,
arg8);
} else { //if (bsd_type == target_openbsd)
env->regs[R_EAX] = do_openbsd_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
}
if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
env->regs[R_EAX] = -env->regs[R_EAX];
env->eflags |= CC_C;
} else {
env->eflags &= ~CC_C;
}
env->regs[R_EAX] = do_openbsd_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
break;
#ifndef TARGET_ABI32
case EXCP_SYSCALL:
/* syscall from syscall intruction */
if (bsd_type == target_freebsd)
env->regs[R_EAX] = do_freebsd_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[R_ECX],
env->regs[8],
env->regs[9], 0, 0);
else { //if (bsd_type == target_openbsd)
env->regs[R_EAX] = do_openbsd_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9]);
}
/* linux syscall from syscall intruction */
env->regs[R_EAX] = do_openbsd_syscall(env,
env->regs[R_EAX],
env->regs[R_EDI],
env->regs[R_ESI],
env->regs[R_EDX],
env->regs[10],
env->regs[8],
env->regs[9]);
env->eip = env->exception_next_eip;
if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
env->regs[R_EAX] = -env->regs[R_EAX];
env->eflags |= CC_C;
} else {
env->eflags &= ~CC_C;
}
break;
#endif
#if 0
@@ -510,7 +438,7 @@ static void flush_windows(CPUSPARCState *env)
#endif
}
void cpu_loop(CPUSPARCState *env)
void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
{
int trapnr, ret, syscall_nr;
//target_siginfo_t info;
@@ -522,10 +450,6 @@ void cpu_loop(CPUSPARCState *env)
#ifndef TARGET_SPARC64
case 0x80:
#else
/* FreeBSD uses 0x141 for syscalls too */
case 0x141:
if (bsd_type != target_freebsd)
goto badtrap;
case 0x100:
#endif
syscall_nr = env->gregs[1];
@@ -533,7 +457,7 @@ void cpu_loop(CPUSPARCState *env)
ret = do_freebsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5], 0, 0);
env->regwptr[4], env->regwptr[5]);
else if (bsd_type == target_netbsd)
ret = do_netbsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
@@ -550,7 +474,6 @@ void cpu_loop(CPUSPARCState *env)
env->regwptr[4], env->regwptr[5]);
}
if ((unsigned int)ret >= (unsigned int)(-515)) {
ret = -ret;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
#else
@@ -656,9 +579,6 @@ void cpu_loop(CPUSPARCState *env)
}
break;
default:
#ifdef TARGET_SPARC64
badtrap:
#endif
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
exit (1);
@@ -682,11 +602,6 @@ static void usage(void)
"-s size set the stack size in bytes (default=%ld)\n"
"-cpu model select CPU (-cpu ? for list)\n"
"-drop-ld-preload drop LD_PRELOAD for target process\n"
"-E var=value sets/modifies targets environment variable(s)\n"
"-U var unsets targets environment variable(s)\n"
#if defined(CONFIG_USE_GUEST_BASE)
"-B address set guest_base address to address\n"
#endif
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
@@ -698,12 +613,6 @@ static void usage(void)
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
" 'strace' program. Enable by setting to any value.\n"
"You can use -E and -U options to set/unset environment variables\n"
"for target process. It is possible to provide several variables\n"
"by repeating the option. For example:\n"
" -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
"Note that if you provide several changes to single variable\n"
"last change will stay in effect.\n"
,
TARGET_ARCH,
interp_prefix,
@@ -738,9 +647,9 @@ int main(int argc, char **argv)
int optind;
const char *r;
int gdbstub_port = 0;
char **target_environ, **wrk;
envlist_t *envlist = NULL;
bsd_type = target_openbsd;
int drop_ld_preload = 0, environ_count = 0;
char **target_environ, **wrk, **dst;
enum BSDType bsd_type = target_openbsd;
if (argc <= 1)
usage();
@@ -748,16 +657,6 @@ int main(int argc, char **argv)
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
exit(1);
}
/* add current environment into the list */
for (wrk = environ; *wrk != NULL; wrk++) {
(void) envlist_setenv(envlist, *wrk);
}
cpu_model = NULL;
optind = 1;
for(;;) {
@@ -787,14 +686,6 @@ int main(int argc, char **argv)
exit(1);
}
cpu_set_log(mask);
} else if (!strcmp(r, "E")) {
r = argv[optind++];
if (envlist_setenv(envlist, r) != 0)
usage();
} else if (!strcmp(r, "U")) {
r = argv[optind++];
if (envlist_unsetenv(envlist, r) != 0)
usage();
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
@@ -826,13 +717,8 @@ int main(int argc, char **argv)
#endif
exit(1);
}
#if defined(CONFIG_USE_GUEST_BASE)
} else if (!strcmp(r, "B")) {
guest_base = strtol(argv[optind++], NULL, 0);
have_guest_base = 1;
#endif
} else if (!strcmp(r, "drop-ld-preload")) {
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
drop_ld_preload = 1;
} else if (!strcmp(r, "bsd")) {
if (!strcasecmp(argv[optind], "freebsd")) {
bsd_type = target_freebsd;
@@ -891,46 +777,25 @@ int main(int argc, char **argv)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
cpu_reset(env);
#endif
thread_env = env;
if (getenv("QEMU_STRACE")) {
do_strace = 1;
}
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
wrk = environ;
while (*(wrk++))
environ_count++;
#if defined(CONFIG_USE_GUEST_BASE)
/*
* Now that page sizes are configured in cpu_init() we can do
* proper page alignment for guest_base.
*/
guest_base = HOST_PAGE_ALIGN(guest_base);
/*
* Read in mmap_min_addr kernel parameter. This value is used
* When loading the ELF image to determine whether guest_base
* is needed.
*
* When user has explicitly set the quest base, we skip this
* test.
*/
if (!have_guest_base) {
FILE *fp;
if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
unsigned long tmp;
if (fscanf(fp, "%lu", &tmp) == 1) {
mmap_min_addr = tmp;
qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
}
fclose(fp);
}
target_environ = malloc((environ_count + 1) * sizeof(char *));
if (!target_environ)
abort();
for (wrk = environ, dst = target_environ; *wrk; wrk++) {
if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
continue;
*(dst++) = strdup(*wrk);
}
#endif /* CONFIG_USE_GUEST_BASE */
*dst = NULL; /* NULL terminate target_environ */
if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
@@ -944,9 +809,6 @@ int main(int argc, char **argv)
free(target_environ);
if (qemu_log_enabled()) {
#if defined(CONFIG_USE_GUEST_BASE)
qemu_log("guest_base 0x%lx\n", guest_base);
#endif
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
@@ -1108,7 +970,7 @@ int main(int argc, char **argv)
gdbserver_start (gdbstub_port);
gdb_handlesig(env, 0);
}
cpu_loop(env);
cpu_loop(env, bsd_type);
/* never exits */
return 0;
}

View File

@@ -30,7 +30,7 @@
//#define DEBUG_MMAP
#if defined(CONFIG_USE_NPTL)
#if defined(USE_NPTL)
pthread_mutex_t mmap_mutex;
static int __thread mmap_lock_count;

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "qemu.h"
#include "qemu-common.h"
struct pathelem
@@ -155,7 +156,7 @@ const char *path(const char *name)
{
/* Only do absolute paths: quick and dirty, but should mostly be OK.
Could do relative by tracking cwd. */
if (!base || !name || name[0] != '/')
if (!base || name[0] != '/')
return name;
return follow_path(base, name) ?: name;

View File

@@ -18,14 +18,13 @@ enum BSDType {
target_netbsd,
target_openbsd,
};
extern enum BSDType bsd_type;
#include "syscall_defs.h"
#include "syscall.h"
#include "target_signal.h"
#include "gdbstub.h"
#if defined(CONFIG_USE_NPTL)
#if defined(USE_NPTL)
#define THREAD __thread
#else
#define THREAD
@@ -85,9 +84,6 @@ typedef struct TaskState {
void init_task_state(TaskState *ts);
extern const char *qemu_uname_release;
#if defined(CONFIG_USE_GUEST_BASE)
extern unsigned long mmap_min_addr;
#endif
/* ??? See if we can avoid exposing so much of the loader internals. */
/*
@@ -131,8 +127,7 @@ abi_long do_brk(abi_ulong new_brk);
void syscall_init(void);
abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8);
abi_long arg5, abi_long arg6);
abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6);
@@ -141,7 +136,9 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg5, abi_long arg6);
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
extern THREAD CPUState *thread_env;
void cpu_loop(CPUState *env);
void cpu_loop(CPUState *env, enum BSDType bsd_type);
void init_paths(const char *prefix);
const char *path(const char *pathname);
char *target_strerror(int err);
int get_osversion(void);
void fork_start(void);
@@ -191,14 +188,11 @@ void mmap_lock(void);
void mmap_unlock(void);
void cpu_list_lock(void);
void cpu_list_unlock(void);
#if defined(CONFIG_USE_NPTL)
#if defined(USE_NPTL)
void mmap_fork_start(void);
void mmap_fork_end(int child);
#endif
/* main.c */
extern unsigned long x86_stack_size;
/* user access */
#define VERIFY_READ 0
@@ -388,7 +382,7 @@ static inline void *lock_user_string(abi_ulong guest_addr)
#define unlock_user_struct(host_ptr, guest_addr, copy) \
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
#if defined(CONFIG_USE_NPTL)
#if defined(USE_NPTL)
#include <pthread.h>
#endif

View File

@@ -36,7 +36,7 @@ print_execve(const struct syscallname *name,
unlock_user(s, arg1, 0);
for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(abi_ulong)) {
abi_ulong *arg_ptr, arg_addr;
abi_ulong *arg_ptr, arg_addr, s_addr;
arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(abi_ulong), 1);
if (!arg_ptr)
@@ -47,7 +47,7 @@ print_execve(const struct syscallname *name,
break;
if ((s = lock_user_string(arg_addr))) {
gemu_log("\"%s\",", s);
unlock_user(s, arg_addr, 0);
unlock_user(s, s_addr, 0);
}
}

View File

@@ -29,8 +29,6 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <signal.h>
#include <utime.h>
@@ -42,283 +40,20 @@
static abi_ulong target_brk;
static abi_ulong target_original_brk;
static inline abi_long get_errno(abi_long ret)
{
if (ret == -1)
/* XXX need to translate host -> target errnos here */
return -(errno);
else
return ret;
}
#define get_errno(x) (x)
#define target_to_host_bitmask(x, tbl) (x)
static inline int is_error(abi_long ret)
{
return (abi_ulong)ret >= (abi_ulong)(-4096);
}
void target_set_brk(abi_ulong new_brk)
{
target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
}
/* do_obreak() must return target errnos. */
static abi_long do_obreak(abi_ulong new_brk)
{
abi_ulong brk_page;
abi_long mapped_addr;
int new_alloc_size;
if (!new_brk)
return 0;
if (new_brk < target_original_brk)
return -TARGET_EINVAL;
brk_page = HOST_PAGE_ALIGN(target_brk);
/* If the new brk is less than this, set it and we're done... */
if (new_brk < brk_page) {
target_brk = new_brk;
return 0;
}
/* We need to allocate more memory after the brk... */
new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
if (!is_error(mapped_addr))
target_brk = new_brk;
else
return mapped_addr;
return 0;
}
#if defined(TARGET_I386)
static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
{
abi_long ret = 0;
abi_ulong val;
int idx;
switch(op) {
#ifdef TARGET_ABI32
case TARGET_FREEBSD_I386_SET_GSBASE:
case TARGET_FREEBSD_I386_SET_FSBASE:
if (op == TARGET_FREEBSD_I386_SET_GSBASE)
#else
case TARGET_FREEBSD_AMD64_SET_GSBASE:
case TARGET_FREEBSD_AMD64_SET_FSBASE:
if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
#endif
idx = R_GS;
else
idx = R_FS;
if (get_user(val, parms, abi_ulong))
return -TARGET_EFAULT;
cpu_x86_load_seg(env, idx, 0);
env->segs[idx].base = val;
break;
#ifdef TARGET_ABI32
case TARGET_FREEBSD_I386_GET_GSBASE:
case TARGET_FREEBSD_I386_GET_FSBASE:
if (op == TARGET_FREEBSD_I386_GET_GSBASE)
#else
case TARGET_FREEBSD_AMD64_GET_GSBASE:
case TARGET_FREEBSD_AMD64_GET_FSBASE:
if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
#endif
idx = R_GS;
else
idx = R_FS;
val = env->segs[idx].base;
if (put_user(val, parms, abi_ulong))
return -TARGET_EFAULT;
break;
/* XXX handle the others... */
default:
ret = -TARGET_EINVAL;
break;
}
return ret;
}
#endif
#ifdef TARGET_SPARC
static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
{
/* XXX handle
* TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
* TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
*/
return -TARGET_EINVAL;
}
#endif
#ifdef __FreeBSD__
/*
* XXX this uses the undocumented oidfmt interface to find the kind of
* a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
* (this is mostly copied from src/sbin/sysctl/sysctl.c)
*/
static int
oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
{
int qoid[CTL_MAXNAME+2];
uint8_t buf[BUFSIZ];
int i;
size_t j;
qoid[0] = 0;
qoid[1] = 4;
memcpy(qoid + 2, oid, len * sizeof(int));
j = sizeof(buf);
i = sysctl(qoid, len + 2, buf, &j, 0, 0);
if (i)
return i;
if (kind)
*kind = *(uint32_t *)buf;
if (fmt)
strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
return (0);
}
/*
* try and convert sysctl return data for the target.
* XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
*/
static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
{
switch (kind & CTLTYPE) {
case CTLTYPE_INT:
case CTLTYPE_UINT:
*(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
break;
#ifdef TARGET_ABI32
case CTLTYPE_LONG:
case CTLTYPE_ULONG:
*(uint32_t *)holdp = tswap32(*(long *)holdp);
break;
#else
case CTLTYPE_LONG:
*(uint64_t *)holdp = tswap64(*(long *)holdp);
case CTLTYPE_ULONG:
*(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
break;
#endif
case CTLTYPE_QUAD:
*(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
break;
case CTLTYPE_STRING:
break;
default:
/* XXX unhandled */
return -1;
}
return 0;
}
/* XXX this needs to be emulated on non-FreeBSD hosts... */
static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
{
abi_long ret;
void *hnamep, *holdp, *hnewp = NULL;
size_t holdlen;
abi_ulong oldlen = 0;
int32_t *snamep = qemu_malloc(sizeof(int32_t) * namelen), *p, *q, i;
uint32_t kind = 0;
if (oldlenp)
get_user_ual(oldlen, oldlenp);
if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
return -TARGET_EFAULT;
if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
return -TARGET_EFAULT;
if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
return -TARGET_EFAULT;
holdlen = oldlen;
for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
*q++ = tswap32(*p);
oidfmt(snamep, namelen, NULL, &kind);
/* XXX swap hnewp */
ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
if (!ret)
sysctl_oldcvt(holdp, holdlen, kind);
put_user_ual(holdlen, oldlenp);
unlock_user(hnamep, namep, 0);
unlock_user(holdp, oldp, holdlen);
if (hnewp)
unlock_user(hnewp, newp, 0);
qemu_free(snamep);
return ret;
}
#endif
/* FIXME
* lock_iovec()/unlock_iovec() have a return code of 0 for success where
* other lock functions have a return code of 0 for failure.
*/
static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
int count, int copy)
{
struct target_iovec *target_vec;
abi_ulong base;
int i;
target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
if (!target_vec)
return -TARGET_EFAULT;
for(i = 0;i < count; i++) {
base = tswapl(target_vec[i].iov_base);
vec[i].iov_len = tswapl(target_vec[i].iov_len);
if (vec[i].iov_len != 0) {
vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
/* Don't check lock_user return value. We must call writev even
if a element has invalid base address. */
} else {
/* zero length pointer is ignored */
vec[i].iov_base = NULL;
}
}
unlock_user (target_vec, target_addr, 0);
return 0;
}
static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
int count, int copy)
{
struct target_iovec *target_vec;
abi_ulong base;
int i;
target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
if (!target_vec)
return -TARGET_EFAULT;
for(i = 0;i < count; i++) {
if (target_vec[i].iov_base) {
base = tswapl(target_vec[i].iov_base);
unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
}
}
unlock_user (target_vec, target_addr, 0);
return 0;
}
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7,
abi_long arg8)
abi_long arg5, abi_long arg6)
{
abi_long ret;
void *p;
@@ -331,7 +66,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
switch(num) {
case TARGET_FREEBSD_NR_exit:
#ifdef TARGET_GPROF
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
@@ -351,18 +86,6 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(write(arg1, p, arg3));
unlock_user(p, arg2, 0);
break;
case TARGET_FREEBSD_NR_writev:
{
int count = arg3;
struct iovec *vec;
vec = alloca(count * sizeof(struct iovec));
if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
goto efault;
ret = get_errno(writev(arg1, vec, count));
unlock_iovec(vec, arg2, count, 0);
}
break;
case TARGET_FREEBSD_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
@@ -380,23 +103,12 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_FREEBSD_NR_mprotect:
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
case TARGET_FREEBSD_NR_break:
ret = do_obreak(arg1);
break;
#ifdef __FreeBSD__
case TARGET_FREEBSD_NR___sysctl:
ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
case TARGET_FREEBSD_NR_sysarch:
ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
break;
case TARGET_FREEBSD_NR_syscall:
case TARGET_FREEBSD_NR___syscall:
ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
break;
default:
ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
break;
}
fail:
@@ -426,7 +138,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
switch(num) {
case TARGET_NETBSD_NR_exit:
#ifdef TARGET_GPROF
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);
@@ -498,7 +210,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
switch(num) {
case TARGET_OPENBSD_NR_exit:
#ifdef TARGET_GPROF
#ifdef HAVE_GPROF
_mcleanup();
#endif
gdb_exit(cpu_env, arg1);

View File

@@ -106,9 +106,3 @@
#include "freebsd/syscall_nr.h"
#include "netbsd/syscall_nr.h"
#include "openbsd/syscall_nr.h"
struct target_iovec {
abi_long iov_base; /* Starting address */
abi_long iov_len; /* Number of bytes */
};

View File

@@ -90,24 +90,6 @@ struct target_msqid64_ds {
abi_ulong __unused5;
};
/* FreeBSD sysarch(2) */
#define TARGET_FREEBSD_I386_GET_LDT 0
#define TARGET_FREEBSD_I386_SET_LDT 1
/* I386_IOPL */
#define TARGET_FREEBSD_I386_GET_IOPERM 3
#define TARGET_FREEBSD_I386_SET_IOPERM 4
/* xxxxx */
#define TARGET_FREEBSD_I386_GET_FSBASE 7
#define TARGET_FREEBSD_I386_SET_FSBASE 8
#define TARGET_FREEBSD_I386_GET_GSBASE 9
#define TARGET_FREEBSD_I386_SET_GSBASE 10
#define TARGET_FREEBSD_AMD64_GET_FSBASE 128
#define TARGET_FREEBSD_AMD64_SET_FSBASE 129
#define TARGET_FREEBSD_AMD64_GET_GSBASE 130
#define TARGET_FREEBSD_AMD64_SET_GSBASE 131
#define UNAME_MACHINE "x86_64"
#define TARGET_ARCH_SET_GS 0x1001

12
bswap.h
View File

@@ -5,13 +5,13 @@
#include <inttypes.h>
#ifdef CONFIG_MACHINE_BSWAP_H
#ifdef HAVE_MACHINE_BSWAP_H
#include <sys/endian.h>
#include <sys/types.h>
#include <machine/bswap.h>
#else
#ifdef CONFIG_BYTESWAP_H
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
@@ -47,7 +47,7 @@
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif /* !CONFIG_BYTESWAP_H */
#endif /* !HAVE_BYTESWAP_H */
static inline uint16_t bswap16(uint16_t x)
{
@@ -64,7 +64,7 @@ static inline uint64_t bswap64(uint64_t x)
return bswap_64(x);
}
#endif /* ! CONFIG_MACHINE_BSWAP_H */
#endif /* ! HAVE_MACHINE_BSWAP_H */
static inline void bswap16s(uint16_t *s)
{
@@ -81,7 +81,7 @@ static inline void bswap64s(uint64_t *s)
*s = bswap64(*s);
}
#if defined(HOST_WORDS_BIGENDIAN)
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
@@ -203,7 +203,7 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
#endif
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu

View File

@@ -52,7 +52,7 @@ static void buffered_append(QEMUFileBuffered *s,
if (size > (s->buffer_capacity - s->buffer_size)) {
void *tmp;
dprintf("increasing buffer capacity from %zu by %zu\n",
dprintf("increasing buffer capacity from %ld by %ld\n",
s->buffer_capacity, size + 1024);
s->buffer_capacity += size + 1024;
@@ -79,7 +79,7 @@ static void buffered_flush(QEMUFileBuffered *s)
return;
}
dprintf("flushing %zu byte(s) of data\n", s->buffer_size);
dprintf("flushing %ld byte(s) of data\n", s->buffer_size);
while (offset < s->buffer_size) {
ssize_t ret;
@@ -93,16 +93,16 @@ static void buffered_flush(QEMUFileBuffered *s)
}
if (ret <= 0) {
dprintf("error flushing data, %zd\n", ret);
dprintf("error flushing data, %ld\n", ret);
s->has_error = 1;
break;
} else {
dprintf("flushed %zd byte(s)\n", ret);
dprintf("flushed %ld byte(s)\n", ret);
offset += ret;
}
}
dprintf("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
dprintf("flushed %ld of %ld byte(s)\n", offset, s->buffer_size);
memmove(s->buffer, s->buffer + offset, s->buffer_size - offset);
s->buffer_size -= offset;
}
@@ -145,7 +145,7 @@ static int buffered_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, in
break;
}
dprintf("put %zd byte(s)\n", ret);
dprintf("put %ld byte(s)\n", ret);
offset += ret;
s->bytes_xfer += ret;
}
@@ -211,13 +211,6 @@ out:
return s->xfer_limit;
}
static size_t buffered_get_rate_limit(void *opaque)
{
QEMUFileBuffered *s = opaque;
return s->xfer_limit;
}
static void buffered_rate_tick(void *opaque)
{
QEMUFileBuffered *s = opaque;
@@ -258,8 +251,7 @@ QEMUFile *qemu_fopen_ops_buffered(void *opaque,
s->file = qemu_fopen_ops(s, buffered_put_buffer, NULL,
buffered_close, buffered_rate_limit,
buffered_set_rate_limit,
buffered_get_rate_limit);
buffered_set_rate_limit);
s->timer = qemu_new_timer(rt_clock, buffered_rate_tick, s);

View File

@@ -1,367 +0,0 @@
/*
* QDict unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*/
#include <check.h>
#include "qint.h"
#include "qdict.h"
#include "qstring.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
START_TEST(qdict_new_test)
{
QDict *qdict;
qdict = qdict_new();
fail_unless(qdict != NULL);
fail_unless(qdict_size(qdict) == 0);
fail_unless(qdict->base.refcnt == 1);
fail_unless(qobject_type(QOBJECT(qdict)) == QTYPE_QDICT);
// destroy doesn't exit yet
free(qdict);
}
END_TEST
START_TEST(qdict_put_obj_test)
{
QInt *qi;
QDict *qdict;
QDictEntry *ent;
const int num = 42;
qdict = qdict_new();
// key "" will have tdb hash 12345
qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
fail_unless(qdict_size(qdict) == 1);
ent = QLIST_FIRST(&qdict->table[12345 % QDICT_HASH_SIZE]);
qi = qobject_to_qint(ent->value);
fail_unless(qint_get_int(qi) == num);
// destroy doesn't exit yet
QDECREF(qi);
qemu_free(ent->key);
qemu_free(ent);
qemu_free(qdict);
}
END_TEST
START_TEST(qdict_destroy_simple_test)
{
QDict *qdict;
qdict = qdict_new();
qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
QDECREF(qdict);
}
END_TEST
static QDict *tests_dict = NULL;
static void qdict_setup(void)
{
tests_dict = qdict_new();
fail_unless(tests_dict != NULL);
}
static void qdict_teardown(void)
{
QDECREF(tests_dict);
tests_dict = NULL;
}
START_TEST(qdict_get_test)
{
QInt *qi;
QObject *obj;
const int value = -42;
const char *key = "test";
qdict_put(tests_dict, key, qint_from_int(value));
obj = qdict_get(tests_dict, key);
fail_unless(obj != NULL);
qi = qobject_to_qint(obj);
fail_unless(qint_get_int(qi) == value);
}
END_TEST
START_TEST(qdict_get_int_test)
{
int ret;
const int value = 100;
const char *key = "int";
qdict_put(tests_dict, key, qint_from_int(value));
ret = qdict_get_int(tests_dict, key);
fail_unless(ret == value);
}
END_TEST
START_TEST(qdict_get_try_int_test)
{
int ret;
const int value = 100;
const char *key = "int";
qdict_put(tests_dict, key, qint_from_int(value));
ret = qdict_get_try_int(tests_dict, key, 0);
fail_unless(ret == value);
}
END_TEST
START_TEST(qdict_get_str_test)
{
const char *p;
const char *key = "key";
const char *str = "string";
qdict_put(tests_dict, key, qstring_from_str(str));
p = qdict_get_str(tests_dict, key);
fail_unless(p != NULL);
fail_unless(strcmp(p, str) == 0);
}
END_TEST
START_TEST(qdict_get_try_str_test)
{
const char *p;
const char *key = "key";
const char *str = "string";
qdict_put(tests_dict, key, qstring_from_str(str));
p = qdict_get_try_str(tests_dict, key);
fail_unless(p != NULL);
fail_unless(strcmp(p, str) == 0);
}
END_TEST
START_TEST(qdict_haskey_not_test)
{
fail_unless(qdict_haskey(tests_dict, "test") == 0);
}
END_TEST
START_TEST(qdict_haskey_test)
{
const char *key = "test";
qdict_put(tests_dict, key, qint_from_int(0));
fail_unless(qdict_haskey(tests_dict, key) == 1);
}
END_TEST
START_TEST(qdict_del_test)
{
const char *key = "key test";
qdict_put(tests_dict, key, qstring_from_str("foo"));
fail_unless(qdict_size(tests_dict) == 1);
qdict_del(tests_dict, key);
fail_unless(qdict_size(tests_dict) == 0);
fail_unless(qdict_haskey(tests_dict, key) == 0);
}
END_TEST
START_TEST(qobject_to_qdict_test)
{
fail_unless(qobject_to_qdict(QOBJECT(tests_dict)) == tests_dict);
}
END_TEST
/*
* Errors test-cases
*/
START_TEST(qdict_put_exists_test)
{
int value;
const char *key = "exists";
qdict_put(tests_dict, key, qint_from_int(1));
qdict_put(tests_dict, key, qint_from_int(2));
value = qdict_get_int(tests_dict, key);
fail_unless(value == 2);
fail_unless(qdict_size(tests_dict) == 1);
}
END_TEST
START_TEST(qdict_get_not_exists_test)
{
fail_unless(qdict_get(tests_dict, "foo") == NULL);
}
END_TEST
/*
* Stress test-case
*
* This is a lot big for a unit-test, but there is no other place
* to have it.
*/
static void remove_dots(char *string)
{
char *p = strchr(string, ':');
if (p)
*p = '\0';
}
static QString *read_line(FILE *file, char *key)
{
char value[128];
if (fscanf(file, "%s%s", key, value) == EOF)
return NULL;
remove_dots(key);
return qstring_from_str(value);
}
#define reset_file(file) fseek(file, 0L, SEEK_SET)
START_TEST(qdict_stress_test)
{
size_t lines;
char key[128];
FILE *test_file;
QDict *qdict;
QString *value;
const char *test_file_path = "qdict-test-data.txt";
test_file = fopen(test_file_path, "r");
fail_unless(test_file != NULL);
// Create the dict
qdict = qdict_new();
fail_unless(qdict != NULL);
// Add everything from the test file
for (lines = 0;; lines++) {
value = read_line(test_file, key);
if (!value)
break;
qdict_put(qdict, key, value);
}
fail_unless(qdict_size(qdict) == lines);
// Check if everything is really in there
reset_file(test_file);
for (;;) {
const char *str1, *str2;
value = read_line(test_file, key);
if (!value)
break;
str1 = qstring_get_str(value);
str2 = qdict_get_str(qdict, key);
fail_unless(str2 != NULL);
fail_unless(strcmp(str1, str2) == 0);
QDECREF(value);
}
// Delete everything
reset_file(test_file);
for (;;) {
value = read_line(test_file, key);
if (!value)
break;
qdict_del(qdict, key);
QDECREF(value);
fail_unless(qdict_haskey(qdict, key) == 0);
}
fclose(test_file);
fail_unless(qdict_size(qdict) == 0);
QDECREF(qdict);
}
END_TEST
static Suite *qdict_suite(void)
{
Suite *s;
TCase *qdict_public_tcase;
TCase *qdict_public2_tcase;
TCase *qdict_stress_tcase;
TCase *qdict_errors_tcase;
s = suite_create("QDict test-suite");
qdict_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qdict_public_tcase);
tcase_add_test(qdict_public_tcase, qdict_new_test);
tcase_add_test(qdict_public_tcase, qdict_put_obj_test);
tcase_add_test(qdict_public_tcase, qdict_destroy_simple_test);
/* Continue, but now with fixtures */
qdict_public2_tcase = tcase_create("Public Interface (2)");
suite_add_tcase(s, qdict_public2_tcase);
tcase_add_checked_fixture(qdict_public2_tcase, qdict_setup, qdict_teardown);
tcase_add_test(qdict_public2_tcase, qdict_get_test);
tcase_add_test(qdict_public2_tcase, qdict_get_int_test);
tcase_add_test(qdict_public2_tcase, qdict_get_try_int_test);
tcase_add_test(qdict_public2_tcase, qdict_get_str_test);
tcase_add_test(qdict_public2_tcase, qdict_get_try_str_test);
tcase_add_test(qdict_public2_tcase, qdict_haskey_not_test);
tcase_add_test(qdict_public2_tcase, qdict_haskey_test);
tcase_add_test(qdict_public2_tcase, qdict_del_test);
tcase_add_test(qdict_public2_tcase, qobject_to_qdict_test);
qdict_errors_tcase = tcase_create("Errors");
suite_add_tcase(s, qdict_errors_tcase);
tcase_add_checked_fixture(qdict_errors_tcase, qdict_setup, qdict_teardown);
tcase_add_test(qdict_errors_tcase, qdict_put_exists_test);
tcase_add_test(qdict_errors_tcase, qdict_get_not_exists_test);
/* The Big one */
qdict_stress_tcase = tcase_create("Stress Test");
suite_add_tcase(s, qdict_stress_tcase);
tcase_add_test(qdict_stress_tcase, qdict_stress_test);
return s;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = qdict_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,81 +0,0 @@
/*
* QFloat unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* Copyright IBM, Corp. 2009
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.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 <check.h>
#include "qfloat.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
START_TEST(qfloat_from_double_test)
{
QFloat *qf;
const double value = -42.23423;
qf = qfloat_from_double(value);
fail_unless(qf != NULL);
fail_unless(qf->value == value);
fail_unless(qf->base.refcnt == 1);
fail_unless(qobject_type(QOBJECT(qf)) == QTYPE_QFLOAT);
// destroy doesn't exit yet
qemu_free(qf);
}
END_TEST
START_TEST(qfloat_destroy_test)
{
QFloat *qf = qfloat_from_double(0.0);
QDECREF(qf);
}
END_TEST
static Suite *qfloat_suite(void)
{
Suite *s;
TCase *qfloat_public_tcase;
s = suite_create("QFloat test-suite");
qfloat_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qfloat_public_tcase);
tcase_add_test(qfloat_public_tcase, qfloat_from_double_test);
tcase_add_test(qfloat_public_tcase, qfloat_destroy_test);
return s;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = qfloat_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,110 +0,0 @@
/*
* QInt unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*/
#include <check.h>
#include "qint.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
START_TEST(qint_from_int_test)
{
QInt *qi;
const int value = -42;
qi = qint_from_int(value);
fail_unless(qi != NULL);
fail_unless(qi->value == value);
fail_unless(qi->base.refcnt == 1);
fail_unless(qobject_type(QOBJECT(qi)) == QTYPE_QINT);
// destroy doesn't exit yet
qemu_free(qi);
}
END_TEST
START_TEST(qint_destroy_test)
{
QInt *qi = qint_from_int(0);
QDECREF(qi);
}
END_TEST
START_TEST(qint_from_int64_test)
{
QInt *qi;
const int64_t value = 0x1234567890abcdefLL;
qi = qint_from_int(value);
fail_unless((int64_t) qi->value == value);
QDECREF(qi);
}
END_TEST
START_TEST(qint_get_int_test)
{
QInt *qi;
const int value = 123456;
qi = qint_from_int(value);
fail_unless(qint_get_int(qi) == value);
QDECREF(qi);
}
END_TEST
START_TEST(qobject_to_qint_test)
{
QInt *qi;
qi = qint_from_int(0);
fail_unless(qobject_to_qint(QOBJECT(qi)) == qi);
QDECREF(qi);
}
END_TEST
static Suite *qint_suite(void)
{
Suite *s;
TCase *qint_public_tcase;
s = suite_create("QInt test-suite");
qint_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qint_public_tcase);
tcase_add_test(qint_public_tcase, qint_from_int_test);
tcase_add_test(qint_public_tcase, qint_destroy_test);
tcase_add_test(qint_public_tcase, qint_from_int64_test);
tcase_add_test(qint_public_tcase, qint_get_int_test);
tcase_add_test(qint_public_tcase, qobject_to_qint_test);
return s;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = qint_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,687 +0,0 @@
/*
* Copyright IBM, Corp. 2009
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.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 <check.h>
#include <stdbool.h>
#include "qstring.h"
#include "qint.h"
#include "qdict.h"
#include "qlist.h"
#include "qfloat.h"
#include "qbool.h"
#include "qjson.h"
#include "qemu-common.h"
START_TEST(escaped_string)
{
int i;
struct {
const char *encoded;
const char *decoded;
int skip;
} test_cases[] = {
{ "\"\\\"\"", "\"" },
{ "\"hello world \\\"embedded string\\\"\"",
"hello world \"embedded string\"" },
{ "\"hello world\\nwith new line\"", "hello world\nwith new line" },
{ "\"single byte utf-8 \\u0020\"", "single byte utf-8 ", .skip = 1 },
{ "\"double byte utf-8 \\u00A2\"", "double byte utf-8 \xc2\xa2" },
{ "\"triple byte utf-8 \\u20AC\"", "triple byte utf-8 \xe2\x82\xac" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
if (test_cases[i].skip == 0) {
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
qobject_decref(obj);
}
QDECREF(str);
}
}
END_TEST
START_TEST(simple_string)
{
int i;
struct {
const char *encoded;
const char *decoded;
} test_cases[] = {
{ "\"hello world\"", "hello world" },
{ "\"the quick brown fox jumped over the fence\"",
"the quick brown fox jumped over the fence" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
qobject_decref(obj);
QDECREF(str);
}
}
END_TEST
START_TEST(single_quote_string)
{
int i;
struct {
const char *encoded;
const char *decoded;
} test_cases[] = {
{ "'hello world'", "hello world" },
{ "'the quick brown fox \\' jumped over the fence'",
"the quick brown fox ' jumped over the fence" },
{}
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
}
}
END_TEST
START_TEST(vararg_string)
{
int i;
struct {
const char *decoded;
} test_cases[] = {
{ "hello world" },
{ "the quick brown fox jumped over the fence" },
{}
};
for (i = 0; test_cases[i].decoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_jsonf("%s", test_cases[i].decoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
QDECREF(str);
}
}
END_TEST
START_TEST(simple_number)
{
int i;
struct {
const char *encoded;
int64_t decoded;
int skip;
} test_cases[] = {
{ "0", 0 },
{ "1234", 1234 },
{ "1", 1 },
{ "-32", -32 },
{ "-0", 0, .skip = 1 },
{ },
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QInt *qint;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
fail_unless(qint_get_int(qint) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
QString *str;
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
QDECREF(str);
}
QDECREF(qint);
}
}
END_TEST
START_TEST(float_number)
{
int i;
struct {
const char *encoded;
double decoded;
int skip;
} test_cases[] = {
{ "32.43", 32.43 },
{ "0.222", 0.222 },
{ "-32.12313", -32.12313 },
{ "-32.20e-10", -32.20e-10, .skip = 1 },
{ },
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QFloat *qfloat;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
qfloat = qobject_to_qfloat(obj);
fail_unless(qfloat_get_double(qfloat) == test_cases[i].decoded);
if (test_cases[i].skip == 0) {
QString *str;
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
QDECREF(str);
}
QDECREF(qfloat);
}
}
END_TEST
START_TEST(vararg_number)
{
QObject *obj;
QInt *qint;
QFloat *qfloat;
int value = 0x2342;
int64_t value64 = 0x2342342343LL;
double valuef = 2.323423423;
obj = qobject_from_jsonf("%d", value);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
fail_unless(qint_get_int(qint) == value);
QDECREF(qint);
obj = qobject_from_jsonf("%" PRId64, value64);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QINT);
qint = qobject_to_qint(obj);
fail_unless(qint_get_int(qint) == value64);
QDECREF(qint);
obj = qobject_from_jsonf("%f", valuef);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QFLOAT);
qfloat = qobject_to_qfloat(obj);
fail_unless(qfloat_get_double(qfloat) == valuef);
QDECREF(qfloat);
}
END_TEST
START_TEST(keyword_literal)
{
QObject *obj;
QBool *qbool;
QString *str;
obj = qobject_from_json("true");
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
fail_unless(qbool_get_int(qbool) != 0);
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), "true") == 0);
QDECREF(str);
QDECREF(qbool);
obj = qobject_from_json("false");
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
fail_unless(qbool_get_int(qbool) == 0);
str = qobject_to_json(obj);
fail_unless(strcmp(qstring_get_str(str), "false") == 0);
QDECREF(str);
QDECREF(qbool);
obj = qobject_from_jsonf("%i", false);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
fail_unless(qbool_get_int(qbool) == 0);
QDECREF(qbool);
obj = qobject_from_jsonf("%i", true);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QBOOL);
qbool = qobject_to_qbool(obj);
fail_unless(qbool_get_int(qbool) != 0);
QDECREF(qbool);
}
END_TEST
typedef struct LiteralQDictEntry LiteralQDictEntry;
typedef struct LiteralQObject LiteralQObject;
struct LiteralQObject
{
int type;
union {
int64_t qint;
const char *qstr;
LiteralQDictEntry *qdict;
LiteralQObject *qlist;
} value;
};
struct LiteralQDictEntry
{
const char *key;
LiteralQObject value;
};
#define QLIT_QINT(val) (LiteralQObject){.type = QTYPE_QINT, .value.qint = (val)}
#define QLIT_QSTR(val) (LiteralQObject){.type = QTYPE_QSTRING, .value.qstr = (val)}
#define QLIT_QDICT(val) (LiteralQObject){.type = QTYPE_QDICT, .value.qdict = (val)}
#define QLIT_QLIST(val) (LiteralQObject){.type = QTYPE_QLIST, .value.qlist = (val)}
typedef struct QListCompareHelper
{
int index;
LiteralQObject *objs;
int result;
} QListCompareHelper;
static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs);
static void compare_helper(QObject *obj, void *opaque)
{
QListCompareHelper *helper = opaque;
if (helper->result == 0) {
return;
}
if (helper->objs[helper->index].type == QTYPE_NONE) {
helper->result = 0;
return;
}
helper->result = compare_litqobj_to_qobj(&helper->objs[helper->index++], obj);
}
static int compare_litqobj_to_qobj(LiteralQObject *lhs, QObject *rhs)
{
if (lhs->type != qobject_type(rhs)) {
return 0;
}
switch (lhs->type) {
case QTYPE_QINT:
return lhs->value.qint == qint_get_int(qobject_to_qint(rhs));
case QTYPE_QSTRING:
return (strcmp(lhs->value.qstr, qstring_get_str(qobject_to_qstring(rhs))) == 0);
case QTYPE_QDICT: {
int i;
for (i = 0; lhs->value.qdict[i].key; i++) {
QObject *obj = qdict_get(qobject_to_qdict(rhs), lhs->value.qdict[i].key);
if (!compare_litqobj_to_qobj(&lhs->value.qdict[i].value, obj)) {
return 0;
}
}
return 1;
}
case QTYPE_QLIST: {
QListCompareHelper helper;
helper.index = 0;
helper.objs = lhs->value.qlist;
helper.result = 1;
qlist_iter(qobject_to_qlist(rhs), compare_helper, &helper);
return helper.result;
}
default:
break;
}
return 0;
}
START_TEST(simple_dict)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = "{\"foo\": 42, \"bar\": \"hello world\"}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ "foo", QLIT_QINT(42) },
{ "bar", QLIT_QSTR("hello world") },
{ }
})),
}, {
.encoded = "{}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ }
})),
}, {
.encoded = "{\"foo\": 43}",
.decoded = QLIT_QDICT(((LiteralQDictEntry[]){
{ "foo", QLIT_QINT(43) },
{ }
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QDICT);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QDICT);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
END_TEST
START_TEST(simple_list)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = "[43,42]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = "[43]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
{ }
})),
},
{
.encoded = "[]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
{ }
})),
},
{
.encoded = "[{}]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QDICT(((LiteralQDictEntry[]){
{},
})),
{},
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QLIST);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QLIST);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
END_TEST
START_TEST(simple_whitespace)
{
int i;
struct {
const char *encoded;
LiteralQObject decoded;
} test_cases[] = {
{
.encoded = " [ 43 , 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = " [ 43 , { 'h' : 'b' }, [ ], 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QDICT(((LiteralQDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ }})),
QLIT_QLIST(((LiteralQObject[]){
{ }})),
QLIT_QINT(42),
{ }
})),
},
{
.encoded = " [ 43 , { 'h' : 'b' , 'a' : 32 }, [ ], 42 ]",
.decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(43),
QLIT_QDICT(((LiteralQDictEntry[]){
{ "h", QLIT_QSTR("b") },
{ "a", QLIT_QINT(32) },
{ }})),
QLIT_QLIST(((LiteralQObject[]){
{ }})),
QLIT_QINT(42),
{ }
})),
},
{ }
};
for (i = 0; test_cases[i].encoded; i++) {
QObject *obj;
QString *str;
obj = qobject_from_json(test_cases[i].encoded);
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QLIST);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
str = qobject_to_json(obj);
qobject_decref(obj);
obj = qobject_from_json(qstring_get_str(str));
fail_unless(obj != NULL);
fail_unless(qobject_type(obj) == QTYPE_QLIST);
fail_unless(compare_litqobj_to_qobj(&test_cases[i].decoded, obj) == 1);
qobject_decref(obj);
QDECREF(str);
}
}
END_TEST
START_TEST(simple_varargs)
{
QObject *embedded_obj;
QObject *obj;
LiteralQObject decoded = QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(1),
QLIT_QINT(2),
QLIT_QLIST(((LiteralQObject[]){
QLIT_QINT(32),
QLIT_QINT(42),
{}})),
{}}));
embedded_obj = qobject_from_json("[32, 42]");
fail_unless(embedded_obj != NULL);
obj = qobject_from_jsonf("[%d, 2, %p]", 1, embedded_obj);
fail_unless(obj != NULL);
fail_unless(compare_litqobj_to_qobj(&decoded, obj) == 1);
qobject_decref(obj);
}
END_TEST
static Suite *qjson_suite(void)
{
Suite *suite;
TCase *string_literals, *number_literals, *keyword_literals;
TCase *dicts, *lists, *whitespace, *varargs;
string_literals = tcase_create("String Literals");
tcase_add_test(string_literals, simple_string);
tcase_add_test(string_literals, escaped_string);
tcase_add_test(string_literals, single_quote_string);
tcase_add_test(string_literals, vararg_string);
number_literals = tcase_create("Number Literals");
tcase_add_test(number_literals, simple_number);
tcase_add_test(number_literals, float_number);
tcase_add_test(number_literals, vararg_number);
keyword_literals = tcase_create("Keywords");
tcase_add_test(keyword_literals, keyword_literal);
dicts = tcase_create("Objects");
tcase_add_test(dicts, simple_dict);
lists = tcase_create("Lists");
tcase_add_test(lists, simple_list);
whitespace = tcase_create("Whitespace");
tcase_add_test(whitespace, simple_whitespace);
varargs = tcase_create("Varargs");
tcase_add_test(varargs, simple_varargs);
suite = suite_create("QJSON test-suite");
suite_add_tcase(suite, string_literals);
suite_add_tcase(suite, number_literals);
suite_add_tcase(suite, keyword_literals);
suite_add_tcase(suite, dicts);
suite_add_tcase(suite, lists);
suite_add_tcase(suite, whitespace);
suite_add_tcase(suite, varargs);
return suite;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = qjson_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,153 +0,0 @@
/*
* QList unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#include <check.h>
#include "qint.h"
#include "qlist.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
START_TEST(qlist_new_test)
{
QList *qlist;
qlist = qlist_new();
fail_unless(qlist != NULL);
fail_unless(qlist->base.refcnt == 1);
fail_unless(qobject_type(QOBJECT(qlist)) == QTYPE_QLIST);
// destroy doesn't exist yet
qemu_free(qlist);
}
END_TEST
START_TEST(qlist_append_test)
{
QInt *qi;
QList *qlist;
QListEntry *entry;
qi = qint_from_int(42);
qlist = qlist_new();
qlist_append(qlist, qi);
entry = QTAILQ_FIRST(&qlist->head);
fail_unless(entry != NULL);
fail_unless(entry->value == QOBJECT(qi));
// destroy doesn't exist yet
QDECREF(qi);
qemu_free(entry);
qemu_free(qlist);
}
END_TEST
START_TEST(qobject_to_qlist_test)
{
QList *qlist;
qlist = qlist_new();
fail_unless(qobject_to_qlist(QOBJECT(qlist)) == qlist);
// destroy doesn't exist yet
qemu_free(qlist);
}
END_TEST
START_TEST(qlist_destroy_test)
{
int i;
QList *qlist;
qlist = qlist_new();
for (i = 0; i < 42; i++)
qlist_append(qlist, qint_from_int(i));
QDECREF(qlist);
}
END_TEST
static int iter_called;
static const int iter_max = 42;
static void iter_func(QObject *obj, void *opaque)
{
QInt *qi;
fail_unless(opaque == NULL);
qi = qobject_to_qint(obj);
fail_unless(qi != NULL);
fail_unless((qint_get_int(qi) >= 0) && (qint_get_int(qi) <= iter_max));
iter_called++;
}
START_TEST(qlist_iter_test)
{
int i;
QList *qlist;
qlist = qlist_new();
for (i = 0; i < iter_max; i++)
qlist_append(qlist, qint_from_int(i));
iter_called = 0;
qlist_iter(qlist, iter_func, NULL);
fail_unless(iter_called == iter_max);
QDECREF(qlist);
}
END_TEST
static Suite *QList_suite(void)
{
Suite *s;
TCase *qlist_public_tcase;
s = suite_create("QList suite");
qlist_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qlist_public_tcase);
tcase_add_test(qlist_public_tcase, qlist_new_test);
tcase_add_test(qlist_public_tcase, qlist_append_test);
tcase_add_test(qlist_public_tcase, qobject_to_qlist_test);
tcase_add_test(qlist_public_tcase, qlist_destroy_test);
tcase_add_test(qlist_public_tcase, qlist_iter_test);
return s;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = QList_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,131 +0,0 @@
/*
* QString unit-tests.
*
* Copyright (C) 2009 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
*/
#include <check.h>
#include "qstring.h"
#include "qemu-common.h"
/*
* Public Interface test-cases
*
* (with some violations to access 'private' data)
*/
START_TEST(qstring_from_str_test)
{
QString *qstring;
const char *str = "QEMU";
qstring = qstring_from_str(str);
fail_unless(qstring != NULL);
fail_unless(qstring->base.refcnt == 1);
fail_unless(strcmp(str, qstring->string) == 0);
fail_unless(qobject_type(QOBJECT(qstring)) == QTYPE_QSTRING);
// destroy doesn't exit yet
qemu_free(qstring->string);
qemu_free(qstring);
}
END_TEST
START_TEST(qstring_destroy_test)
{
QString *qstring = qstring_from_str("destroy test");
QDECREF(qstring);
}
END_TEST
START_TEST(qstring_get_str_test)
{
QString *qstring;
const char *ret_str;
const char *str = "QEMU/KVM";
qstring = qstring_from_str(str);
ret_str = qstring_get_str(qstring);
fail_unless(strcmp(ret_str, str) == 0);
QDECREF(qstring);
}
END_TEST
START_TEST(qstring_append_chr_test)
{
int i;
QString *qstring;
const char *str = "qstring append char unit-test";
qstring = qstring_new();
for (i = 0; str[i]; i++)
qstring_append_chr(qstring, str[i]);
fail_unless(strcmp(str, qstring_get_str(qstring)) == 0);
QDECREF(qstring);
}
END_TEST
START_TEST(qstring_from_substr_test)
{
QString *qs;
qs = qstring_from_substr("virtualization", 3, 9);
fail_unless(qs != NULL);
fail_unless(strcmp(qstring_get_str(qs), "tualiza") == 0);
QDECREF(qs);
}
END_TEST
START_TEST(qobject_to_qstring_test)
{
QString *qstring;
qstring = qstring_from_str("foo");
fail_unless(qobject_to_qstring(QOBJECT(qstring)) == qstring);
QDECREF(qstring);
}
END_TEST
static Suite *qstring_suite(void)
{
Suite *s;
TCase *qstring_public_tcase;
s = suite_create("QString test-suite");
qstring_public_tcase = tcase_create("Public Interface");
suite_add_tcase(s, qstring_public_tcase);
tcase_add_test(qstring_public_tcase, qstring_from_str_test);
tcase_add_test(qstring_public_tcase, qstring_destroy_test);
tcase_add_test(qstring_public_tcase, qstring_get_str_test);
tcase_add_test(qstring_public_tcase, qstring_append_chr_test);
tcase_add_test(qstring_public_tcase, qstring_from_substr_test);
tcase_add_test(qstring_public_tcase, qobject_to_qstring_test);
return s;
}
int main(void)
{
int nf;
Suite *s;
SRunner *sr;
s = qstring_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}

26
cmd.c
View File

@@ -20,13 +20,13 @@
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/time.h>
#include <getopt.h>
#include "cmd.h"
#define _(x) x /* not gettext support yet */
extern int optind;
/* from libxcmd/command.c */
cmdinfo_t *cmdtab;
@@ -283,26 +283,6 @@ fetchline(void)
}
#endif
static char *qemu_strsep(char **input, const char *delim)
{
char *result = *input;
if (result != NULL) {
char *p = result;
for (p = result; *p != '\0'; p++) {
if (strchr(delim, *p)) {
break;
}
}
if (*p == '\0') {
*input = NULL;
} else {
*p = '\0';
*input = p + 1;
}
}
return result;
}
char **
breakline(
char *input,
@@ -312,7 +292,7 @@ breakline(
char *p;
char **rval = calloc(sizeof(char *), 1);
while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
while (rval && (p = strsep(&input, " ")) != NULL) {
if (!*p)
continue;
c++;

View File

@@ -1,2 +0,0 @@
#include "config-host.h"
#include "config-target.h"

1907
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -307,7 +307,7 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
#define PAT(x) x
#else
#define PAT(x) cbswap_32(x)
@@ -1317,31 +1317,16 @@ void console_color_init(DisplayState *ds)
static int n_text_consoles;
static CharDriverState *text_consoles[128];
static QemuOpts *text_console_opts[128];
static char *text_console_strs[128];
static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
{
TextConsole *s;
unsigned width;
unsigned height;
static int color_inited;
width = qemu_opt_get_number(opts, "width", 0);
if (width == 0)
width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
height = qemu_opt_get_number(opts, "height", 0);
if (height == 0)
height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
if (width == 0 || height == 0) {
s = new_console(ds, TEXT_CONSOLE);
width = ds_get_width(s->ds);
height = ds_get_height(s->ds);
} else {
s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
}
s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
if (!s) {
free(chr);
return;
@@ -1365,6 +1350,23 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt
s->total_height = DEFAULT_BACKSCROLL;
s->x = 0;
s->y = 0;
width = ds_get_width(s->ds);
height = ds_get_height(s->ds);
if (p != NULL) {
width = strtoul(p, (char **)&p, 10);
if (*p == 'C') {
p++;
width *= FONT_WIDTH;
}
if (*p == 'x') {
p++;
height = strtoul(p, (char **)&p, 10);
if (*p == 'C') {
p++;
height *= FONT_HEIGHT;
}
}
}
s->g_width = width;
s->g_height = height;
@@ -1384,22 +1386,12 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
if (chr->label) {
char msg[128];
int len;
s->t_attrib.bgcol = COLOR_BLUE;
len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
console_puts(chr, (uint8_t*)msg, len);
s->t_attrib = s->t_attrib_default;
}
qemu_chr_generic_open(chr);
qemu_chr_reset(chr);
if (chr->init)
chr->init(chr);
}
CharDriverState *text_console_init(QemuOpts *opts)
CharDriverState *text_console_init(const char *p)
{
CharDriverState *chr;
@@ -1410,7 +1402,7 @@ CharDriverState *text_console_init(QemuOpts *opts)
exit(1);
}
text_consoles[n_text_consoles] = chr;
text_console_opts[n_text_consoles] = opts;
text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
n_text_consoles++;
return chr;
@@ -1421,9 +1413,8 @@ void text_consoles_set_display(DisplayState *ds)
int i;
for (i = 0; i < n_text_consoles; i++) {
text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
qemu_opts_del(text_console_opts[i]);
text_console_opts[i] = NULL;
text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
qemu_free(text_console_strs[i]);
}
n_text_consoles = 0;
@@ -1568,7 +1559,7 @@ DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
surface->height = height;
surface->linesize = width * 4;
surface->pf = qemu_default_pixelformat(32);
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
#else
surface->flags = QEMU_ALLOCATED_FLAG;
@@ -1589,7 +1580,7 @@ DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
else
surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
#else
surface->flags = QEMU_ALLOCATED_FLAG;
@@ -1607,7 +1598,7 @@ DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
surface->height = height;
surface->linesize = linesize;
surface->pf = qemu_default_pixelformat(bpp);
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
surface->flags = QEMU_BIG_ENDIAN_FLAG;
#endif
surface->data = data;

View File

@@ -2,7 +2,6 @@
#define CONSOLE_H
#include "qemu-char.h"
#include "qdict.h"
/* keyboard/mouse support */
@@ -44,9 +43,8 @@ struct MouseTransformInfo {
int a[7];
};
void do_info_mice_print(Monitor *mon, const QObject *data);
void do_info_mice(Monitor *mon, QObject **ret_data);
void do_mouse_set(Monitor *mon, const QDict *qdict);
void do_info_mice(Monitor *mon);
void do_mouse_set(Monitor *mon, int index);
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
constants) */
@@ -304,7 +302,7 @@ void vga_hw_text_update(console_ch_t *chardata);
int is_graphic_console(void);
int is_fixedsize_console(void);
CharDriverState *text_console_init(QemuOpts *opts);
CharDriverState *text_console_init(const char *p);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
void console_color_init(DisplayState *ds);
@@ -323,8 +321,7 @@ void vnc_display_init(DisplayState *ds);
void vnc_display_close(DisplayState *ds);
int vnc_display_open(DisplayState *ds, const char *display);
int vnc_display_password(DisplayState *ds, const char *password);
void do_info_vnc_print(Monitor *mon, const QObject *data);
void do_info_vnc(Monitor *mon, QObject **ret_data);
void do_info_vnc(Monitor *mon);
char *vnc_display_local_addr(DisplayState *ds);
/* curses.c */

View File

@@ -27,7 +27,7 @@
* WORDS_ALIGNED : if defined, the host cpu can only make word aligned
* memory accesses.
*
* HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and
* WORDS_BIGENDIAN : if defined, the host cpu is big endian and
* otherwise little endian.
*
* (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
@@ -37,7 +37,7 @@
#include "softfloat.h"
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
@@ -123,7 +123,7 @@ typedef union {
endian ! */
typedef union {
float64 d;
#if defined(HOST_WORDS_BIGENDIAN) \
#if defined(WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
struct {
uint32_t upper;
@@ -141,7 +141,7 @@ typedef union {
#ifdef TARGET_SPARC
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN) \
#if defined(WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
struct {
uint32_t upmost;
@@ -221,7 +221,7 @@ static inline void stb_p(void *ptr, int v)
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
/* conservative code for little endian unaligned accesses */
static inline int lduw_le_p(const void *ptr)
@@ -398,7 +398,7 @@ static inline void stfq_le_p(void *ptr, float64 v)
}
#endif
#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
static inline int lduw_be_p(const void *ptr)
{
@@ -624,13 +624,8 @@ static inline void stfq_be_p(void *ptr, float64 v)
/* On some host systems the guest address space is reserved on the host.
* This allows the guest address space to be offset to a convenient location.
*/
#if defined(CONFIG_USE_GUEST_BASE)
extern unsigned long guest_base;
extern int have_guest_base;
#define GUEST_BASE guest_base
#else
#define GUEST_BASE 0ul
#endif
//#define GUEST_BASE 0x20000000
#define GUEST_BASE 0
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
@@ -873,6 +868,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
#define VGA_DIRTY_FLAG 0x01
#define CODE_DIRTY_FLAG 0x02
#define KQEMU_DIRTY_FLAG 0x04
#define MIGRATION_DIRTY_FLAG 0x08
/* read dirty bit (return 0 or 1) */
@@ -1017,33 +1013,24 @@ static inline int64_t cpu_get_real_ticks (void)
#endif
}
#elif (defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)
/*
* binutils wants to use rdhwr only on mips32r2
* but as linux kernel emulate it, it's fine
* to use it.
*
*/
#define MIPS_RDHWR(rd, value) { \
__asm__ __volatile__ ( \
".set push\n\t" \
".set mips32r2\n\t" \
"rdhwr %0, "rd"\n\t" \
".set pop" \
: "=r" (value)); \
}
#elif defined(__mips__)
static inline int64_t cpu_get_real_ticks(void)
{
/* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */
#if __mips_isa_rev >= 2
uint32_t count;
static uint32_t cyc_per_count = 0;
if (!cyc_per_count)
MIPS_RDHWR("$3", cyc_per_count);
__asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count));
MIPS_RDHWR("$2", count);
__asm__ __volatile__("rdhwr %1, $2" : "=r" (count));
return (int64_t)(count * cyc_per_count);
#else
/* FIXME */
static int64_t ticks = 0;
return ticks++;
#endif
}
#else
@@ -1064,9 +1051,14 @@ static inline int64_t profile_getclock(void)
return cpu_get_real_ticks();
}
extern int64_t kqemu_time, kqemu_time_start;
extern int64_t qemu_time, qemu_time_start;
extern int64_t tlb_flush_time;
extern int64_t kqemu_exec_count;
extern int64_t dev_time;
extern int64_t kqemu_ret_int_count;
extern int64_t kqemu_ret_excp_count;
extern int64_t kqemu_ret_intr_count;
#endif
void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,

View File

@@ -10,7 +10,12 @@
#include "bswap.h"
/* address in the RAM (different from a physical address) */
#ifdef CONFIG_KQEMU
/* FIXME: This is wrong. */
typedef uint32_t ram_addr_t;
#else
typedef unsigned long ram_addr_t;
#endif
/* memory API */
@@ -36,8 +41,8 @@ void *qemu_get_ram_ptr(ram_addr_t addr);
/* This should not be used by devices. */
ram_addr_t qemu_ram_addr_from_host(void *ptr);
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write,
int cpu_register_io_memory(CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
void *opaque);
void cpu_unregister_io_memory(int table_address);

View File

@@ -28,7 +28,7 @@
#include <inttypes.h>
#include <signal.h>
#include "osdep.h"
#include "qemu-queue.h"
#include "sys-queue.h"
#include "targphys.h"
#ifndef TARGET_LONG_BITS
@@ -106,7 +106,7 @@ typedef struct CPUTLBEntry {
sizeof(target_phys_addr_t))];
} CPUTLBEntry;
#ifdef HOST_WORDS_BIGENDIAN
#ifdef WORDS_BIGENDIAN
typedef struct icount_decr_u16 {
uint16_t high;
uint16_t low;
@@ -124,14 +124,14 @@ struct KVMState;
typedef struct CPUBreakpoint {
target_ulong pc;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUBreakpoint) entry;
TAILQ_ENTRY(CPUBreakpoint) entry;
} CPUBreakpoint;
typedef struct CPUWatchpoint {
target_ulong vaddr;
target_ulong len_mask;
int flags; /* BP_* */
QTAILQ_ENTRY(CPUWatchpoint) entry;
TAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint;
#define CPU_TEMP_BUF_NLONGS 128
@@ -169,10 +169,10 @@ typedef struct CPUWatchpoint {
\
/* from this point: preserved by CPU reset */ \
/* ice debug support */ \
QTAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
TAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
int singlestep_enabled; \
\
QTAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
TAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
CPUWatchpoint *watchpoint_hit; \
\
struct GDBRegisterState *gdb_regs; \
@@ -185,8 +185,6 @@ typedef struct CPUWatchpoint {
int cpu_index; /* CPU index (informative) */ \
uint32_t host_tid; /* host thread ID */ \
int numa_node; /* NUMA node this cpu is belonging to */ \
int nr_cores; /* number of cores within this CPU package */ \
int nr_threads;/* number of threads within this CPU */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
/* user data */ \
void *opaque; \

View File

@@ -38,7 +38,7 @@
#endif
#endif
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
#if defined(__sparc__) && !defined(HOST_SOLARIS)
// Work around ugly bugs in glibc that mangle global register contents
#undef env
#define env cpu_single_env
@@ -46,7 +46,7 @@
int tb_invalidated_flag;
//#define CONFIG_DEBUG_EXEC
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
int qemu_cpu_has_work(CPUState *env)
@@ -202,7 +202,7 @@ static void cpu_handle_debug_exception(CPUState *env)
CPUWatchpoint *wp;
if (!env->watchpoint_hit)
QTAILQ_FOREACH(wp, &env->watchpoints, entry)
TAILQ_FOREACH(wp, &env->watchpoints, entry)
wp->flags &= ~BP_WATCHPOINT_HIT;
if (debug_excp_handler)
@@ -249,7 +249,6 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X)
/* XXXXX */
#else
#error unsupported target CPU
@@ -259,7 +258,7 @@ int cpu_exec(CPUState *env1)
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
env = cpu_single_env;
#define env cpu_single_env
@@ -322,6 +321,31 @@ int cpu_exec(CPUState *env1)
}
env->exception_index = -1;
}
#ifdef CONFIG_KQEMU
if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) {
int ret;
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
ret = kqemu_cpu_exec(env);
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
if (ret == 1) {
/* exception */
longjmp(env->jmp_env, 1);
} else if (ret == 2) {
/* softmmu execution needed */
} else {
if (env->interrupt_request != 0 || env->exit_request != 0) {
/* hardware interrupt will be executed just after */
} else {
/* otherwise, we restart */
longjmp(env->jmp_env, 1);
}
}
}
#endif
if (kvm_enabled()) {
kvm_cpu_exec(env);
@@ -390,7 +414,7 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
env = cpu_single_env;
#define env cpu_single_env
@@ -417,7 +441,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_PPC)
#if 0
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
cpu_reset(env);
cpu_ppc_reset(env);
}
#endif
if (interrupt_request & CPU_INTERRUPT_HARD) {
@@ -461,6 +485,9 @@ int cpu_exec(CPUState *env1)
env->exception_index = env->interrupt_index;
do_interrupt(env);
env->interrupt_index = 0;
#if !defined(CONFIG_USER_ONLY)
cpu_check_irqs(env);
#endif
next_tb = 0;
}
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
@@ -541,7 +568,7 @@ int cpu_exec(CPUState *env1)
env->exception_index = EXCP_INTERRUPT;
cpu_loop_exit();
}
#ifdef CONFIG_DEBUG_EXEC
#ifdef DEBUG_EXEC
if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
/* restore flags in standard format */
regs_to_env();
@@ -587,7 +614,7 @@ int cpu_exec(CPUState *env1)
next_tb = 0;
tb_invalidated_flag = 0;
}
#ifdef CONFIG_DEBUG_EXEC
#ifdef DEBUG_EXEC
qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
(long)tb->tc_ptr, tb->pc,
lookup_symbol(tb->pc));
@@ -596,7 +623,11 @@ int cpu_exec(CPUState *env1)
spans two pages, we cannot safely do a direct
jump. */
{
if (next_tb != 0 && tb->page_addr[1] == -1) {
if (next_tb != 0 &&
#ifdef CONFIG_KQEMU
(env->kqemu_enabled != 2) &&
#endif
tb->page_addr[1] == -1) {
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
}
}
@@ -613,7 +644,7 @@ int cpu_exec(CPUState *env1)
while (env->current_tb) {
tc_ptr = tb->tc_ptr;
/* execute the generated code */
#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#undef env
env = cpu_single_env;
#define env cpu_single_env
@@ -650,6 +681,13 @@ int cpu_exec(CPUState *env1)
}
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
#if defined(CONFIG_KQEMU)
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
if (kqemu_is_ok(env) &&
(cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
cpu_loop_exit();
}
#endif
} /* for(;;) */
} else {
env_to_regs();
@@ -674,7 +712,6 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_SH4)
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X)
/* XXXXX */
#else
#error unsupported target CPU
@@ -748,10 +785,6 @@ void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
#if !defined(CONFIG_SOFTMMU)
#if defined(TARGET_I386)
#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
#else
#define EXCEPTION_ACTION cpu_loop_exit()
#endif
/* 'pc' is the host PC at which the exception was raised. 'address' is
the effective address of the memory exception. 'is_write' is 1 if a
@@ -776,7 +809,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
}
/* see if it is an MMU fault */
ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
ret = cpu_x86_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
@@ -788,16 +821,423 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
EXCEPTION_ACTION;
if (ret == 1) {
#if 0
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(env->exception_index, env->error_code);
} else {
/* activate soft MMU for this block */
env->hflags |= HF_SOFTMMU_MASK;
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#elif defined(TARGET_ARM)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_arm_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#elif defined(TARGET_SPARC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#elif defined(TARGET_M68K)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_m68k_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#elif defined (TARGET_MIPS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_mips_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
env->PC, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#elif defined (TARGET_MICROBLAZE)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
env->PC, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#elif defined (TARGET_SH4)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_sh4_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#elif defined (TARGET_ALPHA)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_alpha_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#elif defined (TARGET_CRIS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_cris_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
cpu_loop_exit();
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif
#if defined(__i386__)
#if defined(__APPLE__)
@@ -807,20 +1247,6 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
# define MASK_sig(context) ((context)->uc_sigmask)
#elif defined (__NetBSD__)
# include <ucontext.h>
# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
# define MASK_sig(context) ((context)->uc_sigmask)
#elif defined (__FreeBSD__) || defined(__DragonFly__)
# include <ucontext.h>
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
# define MASK_sig(context) ((context)->uc_sigmask)
#elif defined(__OpenBSD__)
# define EIP_sig(context) ((context)->sc_eip)
# define TRAP_sig(context) ((context)->sc_trapno)
@@ -837,9 +1263,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
ucontext_t *uc = puc;
#elif defined(__OpenBSD__)
#if defined(__OpenBSD__)
struct sigcontext *uc = puc;
#else
struct ucontext *uc = puc;
@@ -873,13 +1297,6 @@ int cpu_signal_handler(int host_signum, void *pinfo,
#define TRAP_sig(context) ((context)->sc_trapno)
#define ERROR_sig(context) ((context)->sc_err)
#define MASK_sig(context) ((context)->sc_mask)
#elif defined (__FreeBSD__) || defined(__DragonFly__)
#include <ucontext.h>
#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
#define MASK_sig(context) ((context)->uc_sigmask)
#else
#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
@@ -892,7 +1309,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
{
siginfo_t *info = pinfo;
unsigned long pc;
#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
#ifdef __NetBSD__
ucontext_t *uc = puc;
#elif defined(__OpenBSD__)
struct sigcontext *uc = puc;
@@ -1018,7 +1435,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
siginfo_t *info = pinfo;
int is_write;
uint32_t insn;
#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
#if !defined(__arch64__) || defined(HOST_SOLARIS)
uint32_t *regs = (uint32_t *)(info + 1);
void *sigmask = (regs + 20);
/* XXX: is there a standard glibc define ? */

View File

@@ -1,38 +1,11 @@
#!/bin/sh
echo "/* Automatically generated by create_config - do not modify */"
echo "/* Automatically generated by configure - do not modify */"
echo "#include \"../config-host.h\""
while read line; do
case $line in
VERSION=*) # configuration
version=${line#*=}
echo "#define QEMU_VERSION \"$version\""
;;
PKGVERSION=*) # configuration
pkgversion=${line#*=}
echo "#define QEMU_PKGVERSION \"$pkgversion\""
;;
ARCH=*) # configuration
arch=${line#*=}
arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
echo "#define HOST_$arch_name 1"
;;
CONFIG_AUDIO_DRIVERS=*)
drivers=${line#*=}
echo "#define CONFIG_AUDIO_DRIVERS \\"
for drv in $drivers; do
echo " &${drv}_audio_driver,\\"
done
echo ""
;;
CONFIG_BDRV_WHITELIST=*)
echo "#define CONFIG_BDRV_WHITELIST \\"
for drv in ${line#*=}; do
echo " \"${drv}\",\\"
done
echo " NULL"
;;
CONFIG_*=y) # configuration
name=${line%=*}
echo "#define $name 1"
@@ -42,29 +15,11 @@ case $line in
value=${line#*=}
echo "#define $name $value"
;;
ARCH=*) # configuration
arch=${line#*=}
arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
echo "#define HOST_$arch_name 1"
;;
HOST_USB=*)
# do nothing
;;
HOST_CC=*)
# do nothing
;;
HOST_*=y) # configuration
name=${line%=*}
echo "#define $name 1"
;;
HOST_*=*) # configuration
name=${line%=*}
value=${line#*=}
echo "#define $name $value"
;;
TARGET_ARCH=*) # configuration
target_arch=${line#*=}
arch_name=`echo $target_arch | tr '[:lower:]' '[:upper:]'`
echo "#define TARGET_ARCH \"$target_arch\""
echo "#define TARGET_$arch_name 1"
;;
TARGET_BASE_ARCH=*) # configuration
target_base_arch=${line#*=}
@@ -82,9 +37,6 @@ case $line in
TARGET_ARCH2=*)
# do nothing
;;
TARGET_DIRS=*)
# do nothing
;;
TARGET_*=y) # configuration
name=${line%=*}
echo "#define $name 1"
@@ -94,6 +46,10 @@ case $line in
value=${line#*=}
echo "#define $name $value"
;;
USE_NPTL=y) # configuration
name=${line%=*}
echo "#define $name 1"
;;
esac
done # read

View File

@@ -26,6 +26,8 @@
void *qemu_malloc(size_t len); /* can't include qemu-common.h here */
#define FALSE 0
#define TRUE 1
#define CONST_STRNEQ(STR1,STR2) (strncmp ((STR1), (STR2), sizeof (STR2) - 1) == 0)
/* cris-opc.c -- Table of opcodes for the CRIS processor.
@@ -1318,7 +1320,7 @@ cris_parse_disassembler_options (disassemble_info *info,
info->private_data = calloc (1, sizeof (struct cris_disasm_data));
disdata = (struct cris_disasm_data *) info->private_data;
if (disdata == NULL)
return false;
return FALSE;
/* Default true. */
disdata->trace_case
@@ -1326,7 +1328,7 @@ cris_parse_disassembler_options (disassemble_info *info,
|| (strcmp (info->disassembler_options, "nocase") != 0));
disdata->distype = distype;
return true;
return TRUE;
}
static const struct cris_spec_reg *
@@ -2777,7 +2779,7 @@ print_insn_cris_with_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_v0_v10))
return -1;
return print_insn_cris_generic (vma, info, true);
return print_insn_cris_generic (vma, info, TRUE);
}
#endif
/* Disassemble, prefixing register names with `$'. CRIS v32. */
@@ -2789,7 +2791,7 @@ print_insn_crisv32_with_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_v32))
return -1;
return print_insn_cris_generic (vma, info, true);
return print_insn_cris_generic (vma, info, TRUE);
}
#if 0
@@ -2803,7 +2805,7 @@ print_insn_crisv10_v32_with_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
return -1;
return print_insn_cris_generic (vma, info, true);
return print_insn_cris_generic (vma, info, TRUE);
}
/* Disassemble, no prefixes on register names. CRIS v0..v10. */
@@ -2815,7 +2817,7 @@ print_insn_cris_without_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_v0_v10))
return -1;
return print_insn_cris_generic (vma, info, false);
return print_insn_cris_generic (vma, info, FALSE);
}
/* Disassemble, no prefixes on register names. CRIS v32. */
@@ -2827,7 +2829,7 @@ print_insn_crisv32_without_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_v32))
return -1;
return print_insn_cris_generic (vma, info, false);
return print_insn_cris_generic (vma, info, FALSE);
}
/* Disassemble, no prefixes on register names.
@@ -2840,7 +2842,7 @@ print_insn_crisv10_v32_without_register_prefix (bfd_vma vma,
if (info->private_data == NULL
&& !cris_parse_disassembler_options (info, cris_dis_common_v10_v32))
return -1;
return print_insn_cris_generic (vma, info, false);
return print_insn_cris_generic (vma, info, FALSE);
}
#endif

View File

@@ -158,7 +158,7 @@ static void curses_cursor_position(DisplayState *ds, int x, int y)
#include "curses_keys.h"
static kbd_layout_t *kbd_layout = NULL;
static kbd_layout_t *kbd_layout = 0;
static int keycode2keysym[CURSES_KEYS];
static void curses_refresh(DisplayState *ds)
@@ -368,4 +368,7 @@ void curses_display_init(DisplayState *ds, int full_screen)
ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
invalidate = 1;
/* Standard VGA initial text mode dimensions */
curses_resize(ds);
}

View File

@@ -479,5 +479,5 @@ static const name2keysym_t name2keysym[] = {
{ "F20", 0x11c },
{ "Escape", 27 },
{ NULL, 0 },
{ 0, 0 },
};

View File

@@ -115,22 +115,6 @@ int qemu_fls(int i)
return 32 - clz32(i);
}
/*
* Make sure data goes on disk, but if possible do not bother to
* write out the inode just for timestamp updates.
*
* Unfortunately even in 2009 many operating systems do not support
* fdatasync and have to fall back to fsync.
*/
int qemu_fdatasync(int fd)
{
#ifdef CONFIG_FDATASYNC
return fdatasync(fd);
#else
return fsync(fd);
#endif
}
/* io vectors */
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
@@ -167,31 +151,6 @@ void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
++qiov->niov;
}
/*
* Copies iovecs from src to the end dst until src is completely copied or the
* total size of the copied iovec reaches size. The size of the last copied
* iovec is changed in order to fit the specified total size if it isn't a
* perfect fit already.
*/
void qemu_iovec_concat(QEMUIOVector *dst, QEMUIOVector *src, size_t size)
{
int i;
size_t done;
assert(dst->nalloc != -1);
done = 0;
for (i = 0; (i < src->niov) && (done != size); i++) {
if (done + src->iov[i].iov_len > size) {
qemu_iovec_add(dst, src->iov[i].iov_base, size - done);
break;
} else {
qemu_iovec_add(dst, src->iov[i].iov_base, src->iov[i].iov_len);
}
done += src->iov[i].iov_len;
}
}
void qemu_iovec_destroy(QEMUIOVector *qiov)
{
assert(qiov->nalloc != -1);

View File

@@ -156,7 +156,7 @@ void cpu_loop(CPUPPCState *env)
/* To deal with multiple qemu header version as host for the darwin-user code */
# define DAR SPR_DAR
#endif
EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
env->spr[SPR_DAR]);
/* Handle this via the gdb */
gdb_handlesig (env, SIGSEGV);
@@ -165,7 +165,7 @@ void cpu_loop(CPUPPCState *env)
queue_signal(info.si_signo, &info);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx "\n",
EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
env->spr[SPR_DAR]);
/* Handle this via the gdb */
gdb_handlesig (env, SIGSEGV);
@@ -846,7 +846,6 @@ int main(int argc, char **argv)
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
cpu_reset(env);
printf("Starting %s with qemu\n----------------\n", filename);

View File

@@ -60,13 +60,13 @@
#define dh_retvar_decl0_void void
#define dh_retvar_decl0_i32 TCGv_i32 retval
#define dh_retvar_decl0_i64 TCGv_i64 retval
#define dh_retvar_decl0_ptr TCGv_ptr retval
#define dh_retvar_decl0_ptr TCGv_iptr retval
#define dh_retvar_decl0(t) glue(dh_retvar_decl0_, dh_alias(t))
#define dh_retvar_decl_void
#define dh_retvar_decl_i32 TCGv_i32 retval,
#define dh_retvar_decl_i64 TCGv_i64 retval,
#define dh_retvar_decl_ptr TCGv_ptr retval,
#define dh_retvar_decl_ptr TCGv_iptr retval,
#define dh_retvar_decl(t) glue(dh_retvar_decl_, dh_alias(t))
#define dh_retvar_void TCG_CALL_DUMMY_ARG

View File

@@ -1 +0,0 @@
# Default configuration for alpha-linux-user

View File

@@ -1,3 +0,0 @@
# Default configuration for arm-linux-user
CONFIG_GDBSTUB_XML=y

View File

@@ -1,25 +0,0 @@
# Default configuration for arm-softmmu
CONFIG_GDBSTUB_XML=y
CONFIG_USB_OHCI=y
CONFIG_ISA_MMIO=y
CONFIG_NAND=y
CONFIG_ECC=y
CONFIG_PTIMER=y
CONFIG_SD=y
CONFIG_MAX7310=y
CONFIG_WM8750=y
CONFIG_TWL92230=y
CONFIG_TSC2005=y
CONFIG_LM832X=y
CONFIG_TMP105=y
CONFIG_STELLARIS_INPUT=y
CONFIG_SD0303=y
CONFIG_SD0323=y
CONFIG_ADS7846=y
CONFIG_MAX111X=y
CONFIG_SSI=y
CONFIG_SSI_SD=y
CONFIG_LAN9118=y
CONFIG_SMC91C111=y
CONFIG_DS1338=y

View File

@@ -1,3 +0,0 @@
# Default configuration for armeb-linux-user
CONFIG_GDBSTUB_XML=y

View File

@@ -1 +0,0 @@
# Default configuration for cris-linux-user

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